# frozen_string_literal: true require 'singleton' class ActivityPub::TagManager include Singleton include RoutingHelper CONTEXT = 'https://www.w3.org/ns/activitystreams' COLLECTIONS = { public: 'https://www.w3.org/ns/activitystreams#Public', }.freeze def url_for(target) return target.url if target.respond_to?(:local?) && !target.local? case target.object_type when :person short_account_url(target) when :note, :comment, :activity return activity_account_status_url(target.account, target) if target.reblog? short_account_status_url(target.account, target) end end def uri_for(target) return target.uri if target.respond_to?(:local?) && !target.local? case target.object_type when :person account_url(target) when :note, :comment, :activity return activity_account_status_url(target.account, target) if target.reblog? account_status_url(target.account, target) when :emoji emoji_url(target) end end def generate_uri_for(_target) URI.join(root_url, 'payloads', SecureRandom.uuid) end def activity_uri_for(target) raise ArgumentError, 'target must be a local activity' unless %i(note comment activity).include?(target.object_type) && target.local? activity_account_status_url(target.account, target) end # Primary audience of a status # Public statuses go out to primarily the public collection # Unlisted and private statuses go out primarily to the followers collection # Others go out only to the people they mention def to(status) case status.visibility when 'public' [COLLECTIONS[:public]] when 'unlisted', 'private' [account_followers_url(status.account)] when 'direct' status.mentions.map { |mention| uri_for(mention.account) } end end # Secondary audience of a status # Public statuses go out to followers as well # Unlisted statuses go to the public as well # Both of those and private statuses also go to the people mentioned in them # Direct ones don't have a secondary audience def cc(status) cc = [] cc << uri_for(status.reblog.account) if status.reblog? case status.visibility when 'public' cc << account_followers_url(status.account) when 'unlisted' cc << COLLECTIONS[:public] end cc.concat(status.mentions.map { |mention| uri_for(mention.account) }) unless status.direct_visibility? cc end def local_uri?(uri) uri = Addressable::URI.parse(uri) host = uri.normalized_host host = "#{host}:#{uri.port}" if uri.port !host.nil? && (::TagManager.instance.local_domain?(host) || ::TagManager.instance.web_domain?(host)) end def uri_to_local_id(uri, param = :id) path_params = Rails.application.routes.recognize_path(uri) path_params[param] end def uri_to_resource(uri, klass) if local_uri?(uri) case klass.name when 'Account' klass.find_local(uri_to_local_id(uri, :username)) else StatusFinder.new(uri).status end elsif OStatus::TagManager.instance.local_id?(uri) klass.find_by(id: OStatus::TagManager.instance.unique_tag_to_local_id(uri, klass.to_s)) else klass.find_by(uri: uri.split('#').first) end rescue ActiveRecord::RecordNotFound nil end end