Remove Atom feeds and old URLs in the form of GET /:username/updates/:id (#11247)
				
					
				
			This commit is contained in:
		| @@ -31,13 +31,6 @@ class AccountsController < ApplicationController | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       format.atom do | ||||
|         mark_cacheable! | ||||
|  | ||||
|         @entries = @account.stream_entries.where(hidden: false).with_includes.paginate_by_max_id(PAGE_SIZE, params[:max_id], params[:since_id]) | ||||
|         render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.feed(@account, @entries.reject { |entry| entry.status.nil? })) | ||||
|       end | ||||
|  | ||||
|       format.rss do | ||||
|         mark_cacheable! | ||||
|  | ||||
|   | ||||
| @@ -33,12 +33,10 @@ class StatusesController < ApplicationController | ||||
|  | ||||
|         set_ancestors | ||||
|         set_descendants | ||||
|  | ||||
|         render 'stream_entries/show' | ||||
|       end | ||||
|  | ||||
|       format.json do | ||||
|         render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do | ||||
|         render_cached_json(['activitypub', 'note', @status], content_type: 'application/activity+json', public: @status.distributable?) do | ||||
|           ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::NoteSerializer, adapter: ActivityPub::Adapter) | ||||
|         end | ||||
|       end | ||||
| @@ -46,7 +44,7 @@ class StatusesController < ApplicationController | ||||
|   end | ||||
|  | ||||
|   def activity | ||||
|     render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: !@stream_entry.hidden?) do | ||||
|     render_cached_json(['activitypub', 'activity', @status], content_type: 'application/activity+json', public: @status.distributable?) do | ||||
|       ActiveModelSerializers::SerializableResource.new(@status, serializer: ActivityPub::ActivitySerializer, adapter: ActivityPub::Adapter) | ||||
|     end | ||||
|   end | ||||
| @@ -58,7 +56,7 @@ class StatusesController < ApplicationController | ||||
|     response.headers['X-Frame-Options'] = 'ALLOWALL' | ||||
|     @autoplay = ActiveModel::Type::Boolean.new.cast(params[:autoplay]) | ||||
|  | ||||
|     render 'stream_entries/embed', layout: 'embedded' | ||||
|     render layout: 'embedded' | ||||
|   end | ||||
|  | ||||
|   def replies | ||||
| @@ -92,11 +90,20 @@ class StatusesController < ApplicationController | ||||
|  | ||||
|   def create_descendant_thread(starting_depth, statuses) | ||||
|     depth = starting_depth + statuses.size | ||||
|  | ||||
|     if depth < DESCENDANTS_DEPTH_LIMIT | ||||
|       { statuses: statuses, starting_depth: starting_depth } | ||||
|       { | ||||
|         statuses: statuses, | ||||
|         starting_depth: starting_depth, | ||||
|       } | ||||
|     else | ||||
|       next_status = statuses.pop | ||||
|       { statuses: statuses, starting_depth: starting_depth, next_status: next_status } | ||||
|  | ||||
|       { | ||||
|         statuses: statuses, | ||||
|         starting_depth: starting_depth, | ||||
|         next_status: next_status, | ||||
|       } | ||||
|     end | ||||
|   end | ||||
|  | ||||
| @@ -164,22 +171,13 @@ class StatusesController < ApplicationController | ||||
|   end | ||||
|  | ||||
|   def set_link_headers | ||||
|     response.headers['Link'] = LinkHeader.new( | ||||
|       [ | ||||
|         [account_stream_entry_url(@account, @status.stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]], | ||||
|         [ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]], | ||||
|       ] | ||||
|     ) | ||||
|     response.headers['Link'] = LinkHeader.new([[ActivityPub::TagManager.instance.uri_for(@status), [%w(rel alternate), %w(type application/activity+json)]]]) | ||||
|   end | ||||
|  | ||||
|   def set_status | ||||
|     @status       = @account.statuses.find(params[:id]) | ||||
|     @stream_entry = @status.stream_entry | ||||
|     @type         = @stream_entry.activity_type.downcase | ||||
|  | ||||
|     @status = @account.statuses.find(params[:id]) | ||||
|     authorize @status, :show? | ||||
|   rescue Mastodon::NotPermittedError | ||||
|     # Reraise in order to get a 404 | ||||
|     raise ActiveRecord::RecordNotFound | ||||
|   end | ||||
|  | ||||
| @@ -192,7 +190,7 @@ class StatusesController < ApplicationController | ||||
|   end | ||||
|  | ||||
|   def redirect_to_original | ||||
|     redirect_to ::TagManager.instance.url_for(@status.reblog) if @status.reblog? | ||||
|     redirect_to ActivityPub::TagManager.instance.url_for(@status.reblog) if @status.reblog? | ||||
|   end | ||||
|  | ||||
|   def set_referrer_policy_header | ||||
|   | ||||
| @@ -1,64 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| class StreamEntriesController < ApplicationController | ||||
|   include Authorization | ||||
|   include SignatureVerification | ||||
|  | ||||
|   layout 'public' | ||||
|  | ||||
|   before_action :set_account | ||||
|   before_action :set_stream_entry | ||||
|   before_action :set_link_headers | ||||
|   before_action :check_account_suspension | ||||
|   before_action :set_cache_headers | ||||
|  | ||||
|   def show | ||||
|     respond_to do |format| | ||||
|       format.html do | ||||
|         expires_in 5.minutes, public: true unless @stream_entry.hidden? | ||||
|  | ||||
|         redirect_to short_account_status_url(params[:account_username], @stream_entry.activity) | ||||
|       end | ||||
|  | ||||
|       format.atom do | ||||
|         expires_in 3.minutes, public: true unless @stream_entry.hidden? | ||||
|  | ||||
|         render xml: OStatus::AtomSerializer.render(OStatus::AtomSerializer.new.entry(@stream_entry, true)) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def embed | ||||
|     redirect_to embed_short_account_status_url(@account, @stream_entry.activity), status: 301 | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def set_account | ||||
|     @account = Account.find_local!(params[:account_username]) | ||||
|   end | ||||
|  | ||||
|   def set_link_headers | ||||
|     response.headers['Link'] = LinkHeader.new( | ||||
|       [ | ||||
|         [account_stream_entry_url(@account, @stream_entry, format: 'atom'), [%w(rel alternate), %w(type application/atom+xml)]], | ||||
|         [ActivityPub::TagManager.instance.uri_for(@stream_entry.activity), [%w(rel alternate), %w(type application/activity+json)]], | ||||
|       ] | ||||
|     ) | ||||
|   end | ||||
|  | ||||
|   def set_stream_entry | ||||
|     @stream_entry = @account.stream_entries.where(activity_type: 'Status').find(params[:id]) | ||||
|     @type         = 'status' | ||||
|  | ||||
|     raise ActiveRecord::RecordNotFound if @stream_entry.activity.nil? | ||||
|     authorize @stream_entry.activity, :show? if @stream_entry.hidden? | ||||
|   rescue Mastodon::NotPermittedError | ||||
|     # Reraise in order to get a 404 | ||||
|     raise ActiveRecord::RecordNotFound | ||||
|   end | ||||
|  | ||||
|   def check_account_suspension | ||||
|     gone if @account.suspended? | ||||
|   end | ||||
| end | ||||
| @@ -89,7 +89,7 @@ module Admin::ActionLogsHelper | ||||
|     when 'DomainBlock', 'EmailDomainBlock' | ||||
|       link_to record.domain, "https://#{record.domain}" | ||||
|     when 'Status' | ||||
|       link_to record.account.acct, TagManager.instance.url_for(record) | ||||
|       link_to record.account.acct, ActivityPub::TagManager.instance.url_for(record) | ||||
|     when 'AccountWarning' | ||||
|       link_to record.target_account.acct, admin_account_path(record.target_account_id) | ||||
|     end | ||||
|   | ||||
| @@ -21,7 +21,7 @@ module HomeHelper | ||||
|                         end | ||||
|                     end | ||||
|                   else | ||||
|                     link_to(path || TagManager.instance.url_for(account), class: 'account__display-name') do | ||||
|                     link_to(path || ActivityPub::TagManager.instance.url_for(account), class: 'account__display-name') do | ||||
|                       content_tag(:div, class: 'account__avatar-wrapper') do | ||||
|                         content_tag(:div, '', class: 'account__avatar', style: "width: #{size}px; height: #{size}px; background-size: #{size}px #{size}px; background-image: url(#{full_asset_url(current_account&.user&.setting_auto_play_gif ? account.avatar_original_url : account.avatar_static_url)})") | ||||
|                       end + | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module StreamEntriesHelper | ||||
| module StatusesHelper | ||||
|   EMBEDDED_CONTROLLER = 'statuses' | ||||
|   EMBEDDED_ACTION = 'embed' | ||||
| 
 | ||||
| @@ -109,11 +109,13 @@ module StreamEntriesHelper | ||||
| 
 | ||||
|   def status_text_summary(status) | ||||
|     return if status.spoiler_text.blank? | ||||
| 
 | ||||
|     I18n.t('statuses.content_warning', warning: status.spoiler_text) | ||||
|   end | ||||
| 
 | ||||
|   def poll_summary(status) | ||||
|     return unless status.preloadable_poll | ||||
| 
 | ||||
|     status.preloadable_poll.options.map { |o| "[ ] #{o}" }.join("\n") | ||||
|   end | ||||
| 
 | ||||
| @@ -13,7 +13,7 @@ | ||||
| @import 'mastodon/widgets'; | ||||
| @import 'mastodon/forms'; | ||||
| @import 'mastodon/accounts'; | ||||
| @import 'mastodon/stream_entries'; | ||||
| @import 'mastodon/statuses'; | ||||
| @import 'mastodon/boost'; | ||||
| @import 'mastodon/components'; | ||||
| @import 'mastodon/polls'; | ||||
|   | ||||
| @@ -295,6 +295,6 @@ class Formatter | ||||
|   end | ||||
|  | ||||
|   def mention_html(account) | ||||
|     "<span class=\"h-card\"><a href=\"#{encode(TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(account.username)}</span></a></span>" | ||||
|     "<span class=\"h-card\"><a href=\"#{encode(ActivityPub::TagManager.instance.url_for(account))}\" class=\"u-url mention\">@<span>#{encode(account.username)}</span></a></span>" | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -1,376 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| class OStatus::AtomSerializer | ||||
|   include RoutingHelper | ||||
|   include ActionView::Helpers::SanitizeHelper | ||||
|  | ||||
|   class << self | ||||
|     def render(element) | ||||
|       document = Ox::Document.new(version: '1.0') | ||||
|       document << element | ||||
|       ('<?xml version="1.0"?>' + Ox.dump(element, effort: :tolerant)).force_encoding('UTF-8') | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def author(account) | ||||
|     author = Ox::Element.new('author') | ||||
|  | ||||
|     uri = OStatus::TagManager.instance.uri_for(account) | ||||
|  | ||||
|     append_element(author, 'id', uri) | ||||
|     append_element(author, 'activity:object-type', OStatus::TagManager::TYPES[:person]) | ||||
|     append_element(author, 'uri', uri) | ||||
|     append_element(author, 'name', account.username) | ||||
|     append_element(author, 'email', account.local? ? account.local_username_and_domain : account.acct) | ||||
|     append_element(author, 'summary', Formatter.instance.simplified_format(account).to_str, type: :html) if account.note? | ||||
|     append_element(author, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account)) | ||||
|     append_element(author, 'link', nil, rel: :avatar, type: account.avatar_content_type, 'media:width': 120, 'media:height': 120, href: full_asset_url(account.avatar.url(:original))) if account.avatar? | ||||
|     append_element(author, 'link', nil, rel: :header, type: account.header_content_type, 'media:width': 700, 'media:height': 335, href: full_asset_url(account.header.url(:original))) if account.header? | ||||
|     account.emojis.each do |emoji| | ||||
|       append_element(author, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode) | ||||
|     end | ||||
|     append_element(author, 'poco:preferredUsername', account.username) | ||||
|     append_element(author, 'poco:displayName', account.display_name) if account.display_name? | ||||
|     append_element(author, 'poco:note', account.local? ? account.note : strip_tags(account.note)) if account.note? | ||||
|     append_element(author, 'mastodon:scope', account.locked? ? :private : :public) | ||||
|  | ||||
|     author | ||||
|   end | ||||
|  | ||||
|   def feed(account, stream_entries) | ||||
|     feed = Ox::Element.new('feed') | ||||
|  | ||||
|     add_namespaces(feed) | ||||
|  | ||||
|     append_element(feed, 'id', account_url(account, format: 'atom')) | ||||
|     append_element(feed, 'title', account.display_name.presence || account.username) | ||||
|     append_element(feed, 'subtitle', account.note) | ||||
|     append_element(feed, 'updated', account.updated_at.iso8601) | ||||
|     append_element(feed, 'logo', full_asset_url(account.avatar.url(:original))) | ||||
|  | ||||
|     feed << author(account) | ||||
|  | ||||
|     append_element(feed, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(account)) | ||||
|     append_element(feed, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_url(account, format: 'atom')) | ||||
|     append_element(feed, 'link', nil, rel: :next, type: 'application/atom+xml', href: account_url(account, format: 'atom', max_id: stream_entries.last.id)) if stream_entries.size == 20 | ||||
|  | ||||
|     stream_entries.each do |stream_entry| | ||||
|       feed << entry(stream_entry) | ||||
|     end | ||||
|  | ||||
|     feed | ||||
|   end | ||||
|  | ||||
|   def entry(stream_entry, root = false) | ||||
|     entry = Ox::Element.new('entry') | ||||
|  | ||||
|     add_namespaces(entry) if root | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.uri_for(stream_entry.status)) | ||||
|     append_element(entry, 'published', stream_entry.created_at.iso8601) | ||||
|     append_element(entry, 'updated', stream_entry.updated_at.iso8601) | ||||
|     append_element(entry, 'title', stream_entry&.status&.title || "#{stream_entry.account.acct} deleted status") | ||||
|  | ||||
|     entry << author(stream_entry.account) if root | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[stream_entry.object_type]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[stream_entry.verb]) | ||||
|  | ||||
|     entry << object(stream_entry.target) if stream_entry.targeted? | ||||
|  | ||||
|     if stream_entry.status.nil? | ||||
|       append_element(entry, 'content', 'Deleted status') | ||||
|     elsif stream_entry.status.destroyed? | ||||
|       append_element(entry, 'content', 'Deleted status') | ||||
|       append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(stream_entry.status)) if stream_entry.account.local? | ||||
|     else | ||||
|       serialize_status_attributes(entry, stream_entry.status) | ||||
|     end | ||||
|  | ||||
|     append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(stream_entry.status)) | ||||
|     append_element(entry, 'link', nil, rel: :self, type: 'application/atom+xml', href: account_stream_entry_url(stream_entry.account, stream_entry, format: 'atom')) | ||||
|     append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(stream_entry.thread), href: ::TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded? | ||||
|     append_element(entry, 'ostatus:conversation', nil, ref: conversation_uri(stream_entry.status.conversation)) unless stream_entry&.status&.conversation_id.nil? | ||||
|  | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def object(status) | ||||
|     object = Ox::Element.new('activity:object') | ||||
|  | ||||
|     append_element(object, 'id', OStatus::TagManager.instance.uri_for(status)) | ||||
|     append_element(object, 'published', status.created_at.iso8601) | ||||
|     append_element(object, 'updated', status.updated_at.iso8601) | ||||
|     append_element(object, 'title', status.title) | ||||
|  | ||||
|     object << author(status.account) | ||||
|  | ||||
|     append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[status.object_type]) | ||||
|     append_element(object, 'activity:verb', OStatus::TagManager::VERBS[status.verb]) | ||||
|  | ||||
|     serialize_status_attributes(object, status) | ||||
|  | ||||
|     append_element(object, 'link', nil, rel: :alternate, type: 'text/html', href: ::TagManager.instance.url_for(status)) | ||||
|     append_element(object, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(status.thread), href: ::TagManager.instance.url_for(status.thread)) unless status.thread.nil? | ||||
|     append_element(object, 'ostatus:conversation', nil, ref: conversation_uri(status.conversation)) unless status.conversation_id.nil? | ||||
|  | ||||
|     object | ||||
|   end | ||||
|  | ||||
|   def follow_salmon(follow) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     description = "#{follow.account.acct} started following #{follow.target_account.acct}" | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow.created_at, follow.id, 'Follow')) | ||||
|     append_element(entry, 'title', description) | ||||
|     append_element(entry, 'content', description, type: :html) | ||||
|  | ||||
|     entry << author(follow.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:follow]) | ||||
|  | ||||
|     object = author(follow.target_account) | ||||
|     object.value = 'activity:object' | ||||
|  | ||||
|     entry << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def follow_request_salmon(follow_request) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(follow_request.created_at, follow_request.id, 'FollowRequest')) | ||||
|     append_element(entry, 'title', "#{follow_request.account.acct} requested to follow #{follow_request.target_account.acct}") | ||||
|  | ||||
|     entry << author(follow_request.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:request_friend]) | ||||
|  | ||||
|     object = author(follow_request.target_account) | ||||
|     object.value = 'activity:object' | ||||
|  | ||||
|     entry << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def authorize_follow_request_salmon(follow_request) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest')) | ||||
|     append_element(entry, 'title', "#{follow_request.target_account.acct} authorizes follow request by #{follow_request.account.acct}") | ||||
|  | ||||
|     entry << author(follow_request.target_account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:authorize]) | ||||
|  | ||||
|     object = Ox::Element.new('activity:object') | ||||
|     object << author(follow_request.account) | ||||
|  | ||||
|     append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend]) | ||||
|  | ||||
|     inner_object = author(follow_request.target_account) | ||||
|     inner_object.value = 'activity:object' | ||||
|  | ||||
|     object << inner_object | ||||
|     entry  << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def reject_follow_request_salmon(follow_request) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow_request.id, 'FollowRequest')) | ||||
|     append_element(entry, 'title', "#{follow_request.target_account.acct} rejects follow request by #{follow_request.account.acct}") | ||||
|  | ||||
|     entry << author(follow_request.target_account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:reject]) | ||||
|  | ||||
|     object = Ox::Element.new('activity:object') | ||||
|     object << author(follow_request.account) | ||||
|  | ||||
|     append_element(object, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(object, 'activity:verb', OStatus::TagManager::VERBS[:request_friend]) | ||||
|  | ||||
|     inner_object = author(follow_request.target_account) | ||||
|     inner_object.value = 'activity:object' | ||||
|  | ||||
|     object << inner_object | ||||
|     entry  << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def unfollow_salmon(follow) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     description = "#{follow.account.acct} is no longer following #{follow.target_account.acct}" | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, follow.id, 'Follow')) | ||||
|     append_element(entry, 'title', description) | ||||
|     append_element(entry, 'content', description, type: :html) | ||||
|  | ||||
|     entry << author(follow.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfollow]) | ||||
|  | ||||
|     object = author(follow.target_account) | ||||
|     object.value = 'activity:object' | ||||
|  | ||||
|     entry << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def block_salmon(block) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     description = "#{block.account.acct} no longer wishes to interact with #{block.target_account.acct}" | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block')) | ||||
|     append_element(entry, 'title', description) | ||||
|  | ||||
|     entry << author(block.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:block]) | ||||
|  | ||||
|     object = author(block.target_account) | ||||
|     object.value = 'activity:object' | ||||
|  | ||||
|     entry << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def unblock_salmon(block) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     description = "#{block.account.acct} no longer blocks #{block.target_account.acct}" | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, block.id, 'Block')) | ||||
|     append_element(entry, 'title', description) | ||||
|  | ||||
|     entry << author(block.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unblock]) | ||||
|  | ||||
|     object = author(block.target_account) | ||||
|     object.value = 'activity:object' | ||||
|  | ||||
|     entry << object | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def favourite_salmon(favourite) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     description = "#{favourite.account.acct} favourited a status by #{favourite.status.account.acct}" | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(favourite.created_at, favourite.id, 'Favourite')) | ||||
|     append_element(entry, 'title', description) | ||||
|     append_element(entry, 'content', description, type: :html) | ||||
|  | ||||
|     entry << author(favourite.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:favorite]) | ||||
|  | ||||
|     entry << object(favourite.status) | ||||
|  | ||||
|     append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status)) | ||||
|  | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   def unfavourite_salmon(favourite) | ||||
|     entry = Ox::Element.new('entry') | ||||
|     add_namespaces(entry) | ||||
|  | ||||
|     description = "#{favourite.account.acct} no longer favourites a status by #{favourite.status.account.acct}" | ||||
|  | ||||
|     append_element(entry, 'id', OStatus::TagManager.instance.unique_tag(Time.now.utc, favourite.id, 'Favourite')) | ||||
|     append_element(entry, 'title', description) | ||||
|     append_element(entry, 'content', description, type: :html) | ||||
|  | ||||
|     entry << author(favourite.account) | ||||
|  | ||||
|     append_element(entry, 'activity:object-type', OStatus::TagManager::TYPES[:activity]) | ||||
|     append_element(entry, 'activity:verb', OStatus::TagManager::VERBS[:unfavorite]) | ||||
|  | ||||
|     entry << object(favourite.status) | ||||
|  | ||||
|     append_element(entry, 'thr:in-reply-to', nil, ref: OStatus::TagManager.instance.uri_for(favourite.status), href: ::TagManager.instance.url_for(favourite.status)) | ||||
|  | ||||
|     entry | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def append_element(parent, name, content = nil, **attributes) | ||||
|     element = Ox::Element.new(name) | ||||
|     attributes.each { |k, v| element[k] = sanitize_str(v) } | ||||
|     element << sanitize_str(content) unless content.nil? | ||||
|     parent  << element | ||||
|   end | ||||
|  | ||||
|   def sanitize_str(raw_str) | ||||
|     raw_str.to_s | ||||
|   end | ||||
|  | ||||
|   def conversation_uri(conversation) | ||||
|     return conversation.uri if conversation.uri? | ||||
|     OStatus::TagManager.instance.unique_tag(conversation.created_at, conversation.id, 'Conversation') | ||||
|   end | ||||
|  | ||||
|   def add_namespaces(parent) | ||||
|     parent['xmlns']          = OStatus::TagManager::XMLNS | ||||
|     parent['xmlns:thr']      = OStatus::TagManager::THR_XMLNS | ||||
|     parent['xmlns:activity'] = OStatus::TagManager::AS_XMLNS | ||||
|     parent['xmlns:poco']     = OStatus::TagManager::POCO_XMLNS | ||||
|     parent['xmlns:media']    = OStatus::TagManager::MEDIA_XMLNS | ||||
|     parent['xmlns:ostatus']  = OStatus::TagManager::OS_XMLNS | ||||
|     parent['xmlns:mastodon'] = OStatus::TagManager::MTDN_XMLNS | ||||
|   end | ||||
|  | ||||
|   def serialize_status_attributes(entry, status) | ||||
|     append_element(entry, 'link', nil, rel: :alternate, type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(status)) if status.account.local? | ||||
|  | ||||
|     append_element(entry, 'summary', status.spoiler_text, 'xml:lang': status.language) if status.spoiler_text? | ||||
|     append_element(entry, 'content', Formatter.instance.format(status, inline_poll_options: true).to_str || '.', type: 'html', 'xml:lang': status.language) | ||||
|  | ||||
|     status.active_mentions.sort_by(&:id).each do |mentioned| | ||||
|       append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:person], href: OStatus::TagManager.instance.uri_for(mentioned.account)) | ||||
|     end | ||||
|  | ||||
|     append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': OStatus::TagManager::TYPES[:collection], href: OStatus::TagManager::COLLECTIONS[:public]) if status.public_visibility? | ||||
|  | ||||
|     status.tags.each do |tag| | ||||
|       append_element(entry, 'category', nil, term: tag.name) | ||||
|     end | ||||
|  | ||||
|     status.media_attachments.each do |media| | ||||
|       append_element(entry, 'link', nil, rel: :enclosure, type: media.file_content_type, length: media.file_file_size, href: full_asset_url(media.file.url(:original, false))) | ||||
|     end | ||||
|  | ||||
|     append_element(entry, 'category', nil, term: 'nsfw') if status.sensitive? && status.media_attachments.any? | ||||
|     append_element(entry, 'mastodon:scope', status.visibility) | ||||
|  | ||||
|     status.emojis.each do |emoji| | ||||
|       append_element(entry, 'link', nil, rel: :emoji, href: full_asset_url(emoji.image.url), name: emoji.shortcode) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -13,8 +13,6 @@ class StatusFinder | ||||
|     raise ActiveRecord::RecordNotFound unless TagManager.instance.local_url?(url) | ||||
|  | ||||
|     case recognized_params[:controller] | ||||
|     when 'stream_entries' | ||||
|       StreamEntry.find(recognized_params[:id]).status | ||||
|     when 'statuses' | ||||
|       Status.find(recognized_params[:id]) | ||||
|     else | ||||
|   | ||||
| @@ -33,15 +33,4 @@ class TagManager | ||||
|     domain = uri.host + (uri.port ? ":#{uri.port}" : '') | ||||
|     TagManager.instance.web_domain?(domain) | ||||
|   end | ||||
|  | ||||
|   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 | ||||
|       short_account_status_url(target.account, target) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| class AdminMailer < ApplicationMailer | ||||
|   layout 'plain_mailer' | ||||
|  | ||||
|   helper :stream_entries | ||||
|   helper :statuses | ||||
|  | ||||
|   def new_report(recipient, report) | ||||
|     @report   = report | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| class NotificationMailer < ApplicationMailer | ||||
|   helper :stream_entries | ||||
|   helper :statuses | ||||
|  | ||||
|   add_template_helper RoutingHelper | ||||
|  | ||||
|   | ||||
| @@ -11,7 +11,6 @@ module AccountAssociations | ||||
|     has_many :identity_proofs, class_name: 'AccountIdentityProof', dependent: :destroy, inverse_of: :account | ||||
|  | ||||
|     # Timelines | ||||
|     has_many :stream_entries, inverse_of: :account, dependent: :destroy | ||||
|     has_many :statuses, inverse_of: :account, dependent: :destroy | ||||
|     has_many :favourites, inverse_of: :account, dependent: :destroy | ||||
|     has_many :mentions, inverse_of: :account, dependent: :destroy | ||||
|   | ||||
| @@ -1,43 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| module Streamable | ||||
|   extend ActiveSupport::Concern | ||||
|  | ||||
|   included do | ||||
|     has_one :stream_entry, as: :activity | ||||
|  | ||||
|     after_create do | ||||
|       account.stream_entries.create!(activity: self, hidden: hidden?) if needs_stream_entry? | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   def title | ||||
|     super | ||||
|   end | ||||
|  | ||||
|   def content | ||||
|     title | ||||
|   end | ||||
|  | ||||
|   def target | ||||
|     super | ||||
|   end | ||||
|  | ||||
|   def object_type | ||||
|     :activity | ||||
|   end | ||||
|  | ||||
|   def thread | ||||
|     super | ||||
|   end | ||||
|  | ||||
|   def hidden? | ||||
|     false | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def needs_stream_entry? | ||||
|     account.local? | ||||
|   end | ||||
| end | ||||
| @@ -1,57 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| class RemoteProfile | ||||
|   include ActiveModel::Model | ||||
|  | ||||
|   attr_reader :document | ||||
|  | ||||
|   def initialize(body) | ||||
|     @document = Nokogiri::XML.parse(body, nil, 'utf-8') | ||||
|   end | ||||
|  | ||||
|   def root | ||||
|     @root ||= document.at_xpath('/atom:feed|/atom:entry', atom: OStatus::TagManager::XMLNS) | ||||
|   end | ||||
|  | ||||
|   def author | ||||
|     @author ||= root.at_xpath('./atom:author|./dfrn:owner', atom: OStatus::TagManager::XMLNS, dfrn: OStatus::TagManager::DFRN_XMLNS) | ||||
|   end | ||||
|  | ||||
|   def hub_link | ||||
|     @hub_link ||= link_href_from_xml(root, 'hub') | ||||
|   end | ||||
|  | ||||
|   def display_name | ||||
|     @display_name ||= author.at_xpath('./poco:displayName', poco: OStatus::TagManager::POCO_XMLNS)&.content | ||||
|   end | ||||
|  | ||||
|   def note | ||||
|     @note ||= author.at_xpath('./atom:summary|./poco:note', atom: OStatus::TagManager::XMLNS, poco: OStatus::TagManager::POCO_XMLNS)&.content | ||||
|   end | ||||
|  | ||||
|   def scope | ||||
|     @scope ||= author.at_xpath('./mastodon:scope', mastodon: OStatus::TagManager::MTDN_XMLNS)&.content | ||||
|   end | ||||
|  | ||||
|   def avatar | ||||
|     @avatar ||= link_href_from_xml(author, 'avatar') | ||||
|   end | ||||
|  | ||||
|   def header | ||||
|     @header ||= link_href_from_xml(author, 'header') | ||||
|   end | ||||
|  | ||||
|   def emojis | ||||
|     @emojis ||= author.xpath('./xmlns:link[@rel="emoji"]', xmlns: OStatus::TagManager::XMLNS) | ||||
|   end | ||||
|  | ||||
|   def locked? | ||||
|     scope == 'private' | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def link_href_from_xml(xml, type) | ||||
|     xml.at_xpath(%(./atom:link[@rel="#{type}"]/@href), atom: OStatus::TagManager::XMLNS)&.content | ||||
|   end | ||||
| end | ||||
| @@ -28,7 +28,6 @@ class Status < ApplicationRecord | ||||
|   before_destroy :unlink_from_conversations | ||||
|  | ||||
|   include Paginable | ||||
|   include Streamable | ||||
|   include Cacheable | ||||
|   include StatusThreadingConcern | ||||
|  | ||||
| @@ -61,7 +60,6 @@ class Status < ApplicationRecord | ||||
|   has_and_belongs_to_many :preview_cards | ||||
|  | ||||
|   has_one :notification, as: :activity, dependent: :destroy | ||||
|   has_one :stream_entry, as: :activity, inverse_of: :status | ||||
|   has_one :status_stat, inverse_of: :status | ||||
|   has_one :poll, inverse_of: :status, dependent: :destroy | ||||
|  | ||||
| @@ -106,13 +104,11 @@ class Status < ApplicationRecord | ||||
|                    :status_stat, | ||||
|                    :tags, | ||||
|                    :preview_cards, | ||||
|                    :stream_entry, | ||||
|                    :preloadable_poll, | ||||
|                    account: :account_stat, | ||||
|                    active_mentions: { account: :account_stat }, | ||||
|                    reblog: [ | ||||
|                      :application, | ||||
|                      :stream_entry, | ||||
|                      :tags, | ||||
|                      :preview_cards, | ||||
|                      :media_attachments, | ||||
|   | ||||
| @@ -1,59 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
| # == Schema Information | ||||
| # | ||||
| # Table name: stream_entries | ||||
| # | ||||
| #  id            :bigint(8)        not null, primary key | ||||
| #  activity_id   :bigint(8) | ||||
| #  activity_type :string | ||||
| #  created_at    :datetime         not null | ||||
| #  updated_at    :datetime         not null | ||||
| #  hidden        :boolean          default(FALSE), not null | ||||
| #  account_id    :bigint(8) | ||||
| # | ||||
|  | ||||
| class StreamEntry < ApplicationRecord | ||||
|   include Paginable | ||||
|  | ||||
|   belongs_to :account, inverse_of: :stream_entries | ||||
|   belongs_to :activity, polymorphic: true | ||||
|   belongs_to :status, foreign_type: 'Status', foreign_key: 'activity_id', inverse_of: :stream_entry | ||||
|  | ||||
|   validates :account, :activity, presence: true | ||||
|  | ||||
|   STATUS_INCLUDES = [:account, :stream_entry, :conversation, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :conversation, :media_attachments, :tags, mentions: :account], thread: [:stream_entry, :account]].freeze | ||||
|  | ||||
|   default_scope { where(activity_type: 'Status') } | ||||
|   scope :recent, -> { reorder(id: :desc) } | ||||
|   scope :with_includes, -> { includes(:account, status: STATUS_INCLUDES) } | ||||
|  | ||||
|   delegate :target, :title, :content, :thread, | ||||
|            to: :status, | ||||
|            allow_nil: true | ||||
|  | ||||
|   def object_type | ||||
|     orphaned? || targeted? ? :activity : status.object_type | ||||
|   end | ||||
|  | ||||
|   def verb | ||||
|     orphaned? ? :delete : status.verb | ||||
|   end | ||||
|  | ||||
|   def targeted? | ||||
|     [:follow, :request_friend, :authorize, :reject, :unfollow, :block, :unblock, :share, :favorite].include? verb | ||||
|   end | ||||
|  | ||||
|   def threaded? | ||||
|     (verb == :favorite || object_type == :comment) && !thread.nil? | ||||
|   end | ||||
|  | ||||
|   def mentions | ||||
|     orphaned? ? [] : status.active_mentions.map(&:account) | ||||
|   end | ||||
|  | ||||
|   private | ||||
|  | ||||
|   def orphaned? | ||||
|     status.nil? | ||||
|   end | ||||
| end | ||||
| @@ -29,7 +29,7 @@ class REST::AccountSerializer < ActiveModel::Serializer | ||||
|   end | ||||
|  | ||||
|   def url | ||||
|     TagManager.instance.url_for(object) | ||||
|     ActivityPub::TagManager.instance.url_for(object) | ||||
|   end | ||||
|  | ||||
|   def avatar | ||||
|   | ||||
| @@ -58,7 +58,7 @@ class REST::StatusSerializer < ActiveModel::Serializer | ||||
|   end | ||||
|  | ||||
|   def uri | ||||
|     OStatus::TagManager.instance.uri_for(object) | ||||
|     ActivityPub::TagManager.instance.uri_for(object) | ||||
|   end | ||||
|  | ||||
|   def content | ||||
| @@ -66,7 +66,7 @@ class REST::StatusSerializer < ActiveModel::Serializer | ||||
|   end | ||||
|  | ||||
|   def url | ||||
|     TagManager.instance.url_for(object) | ||||
|     ActivityPub::TagManager.instance.url_for(object) | ||||
|   end | ||||
|  | ||||
|   def favourited | ||||
| @@ -132,7 +132,7 @@ class REST::StatusSerializer < ActiveModel::Serializer | ||||
|     end | ||||
|  | ||||
|     def url | ||||
|       TagManager.instance.url_for(object.account) | ||||
|       ActivityPub::TagManager.instance.url_for(object.account) | ||||
|     end | ||||
|  | ||||
|     def acct | ||||
|   | ||||
| @@ -2,7 +2,7 @@ | ||||
|  | ||||
| class RSS::AccountSerializer | ||||
|   include ActionView::Helpers::NumberHelper | ||||
|   include StreamEntriesHelper | ||||
|   include StatusesHelper | ||||
|   include RoutingHelper | ||||
|  | ||||
|   def render(account, statuses) | ||||
| @@ -10,7 +10,7 @@ class RSS::AccountSerializer | ||||
|  | ||||
|     builder.title("#{display_name(account)} (@#{account.local_username_and_domain})") | ||||
|            .description(account_description(account)) | ||||
|            .link(TagManager.instance.url_for(account)) | ||||
|            .link(ActivityPub::TagManager.instance.url_for(account)) | ||||
|            .logo(full_pack_url('media/images/logo.svg')) | ||||
|            .accent_color('2b90d9') | ||||
|  | ||||
| @@ -20,7 +20,7 @@ class RSS::AccountSerializer | ||||
|     statuses.each do |status| | ||||
|       builder.item do |item| | ||||
|         item.title(status.title) | ||||
|             .link(TagManager.instance.url_for(status)) | ||||
|             .link(ActivityPub::TagManager.instance.url_for(status)) | ||||
|             .pub_date(status.created_at) | ||||
|             .description(status.spoiler_text.presence || Formatter.instance.format(status, inline_poll_options: true).to_str) | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
| class RSS::TagSerializer | ||||
|   include ActionView::Helpers::NumberHelper | ||||
|   include ActionView::Helpers::SanitizeHelper | ||||
|   include StreamEntriesHelper | ||||
|   include StatusesHelper | ||||
|   include RoutingHelper | ||||
|  | ||||
|   def render(tag, statuses) | ||||
| @@ -18,7 +18,7 @@ class RSS::TagSerializer | ||||
|     statuses.each do |status| | ||||
|       builder.item do |item| | ||||
|         item.title(status.title) | ||||
|             .link(TagManager.instance.url_for(status)) | ||||
|             .link(ActivityPub::TagManager.instance.url_for(status)) | ||||
|             .pub_date(status.created_at) | ||||
|             .description(status.spoiler_text.presence || Formatter.instance.format(status).to_str) | ||||
|  | ||||
|   | ||||
| @@ -12,7 +12,7 @@ class BatchedRemoveStatusService < BaseService | ||||
|   # @param [Hash] options | ||||
|   # @option [Boolean] :skip_side_effects | ||||
|   def call(statuses, **options) | ||||
|     statuses = Status.where(id: statuses.map(&:id)).includes(:account, :stream_entry).flat_map { |status| [status] + status.reblogs.includes(:account, :stream_entry).to_a } | ||||
|     statuses = Status.where(id: statuses.map(&:id)).includes(:account).flat_map { |status| [status] + status.reblogs.includes(:account).to_a } | ||||
|  | ||||
|     @mentions = statuses.each_with_object({}) { |s, h| h[s.id] = s.active_mentions.includes(:account).to_a } | ||||
|     @tags     = statuses.each_with_object({}) { |s, h| h[s.id] = s.tags.pluck(:name) } | ||||
|   | ||||
| @@ -84,7 +84,7 @@ class FetchLinkCardService < BaseService | ||||
|  | ||||
|   def mention_link?(a) | ||||
|     @status.mentions.any? do |mention| | ||||
|       a['href'] == TagManager.instance.url_for(mention.account) | ||||
|       a['href'] == ActivityPub::TagManager.instance.url_for(mention.account) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   | ||||
| @@ -40,7 +40,7 @@ class ProcessMentionsService < BaseService | ||||
|   private | ||||
|  | ||||
|   def mention_undeliverable?(mentioned_account) | ||||
|     mentioned_account.nil? || (!mentioned_account.local? && mentioned_account.ostatus? && @status.stream_entry.hidden?) | ||||
|     mentioned_account.nil? || (!mentioned_account.local? && mentioned_account.ostatus?) | ||||
|   end | ||||
|  | ||||
|   def create_notification(mention) | ||||
|   | ||||
| @@ -5,14 +5,13 @@ class RemoveStatusService < BaseService | ||||
|   include Payloadable | ||||
|  | ||||
|   def call(status, **options) | ||||
|     @payload      = Oj.dump(event: :delete, payload: status.id.to_s) | ||||
|     @status       = status | ||||
|     @account      = status.account | ||||
|     @tags         = status.tags.pluck(:name).to_a | ||||
|     @mentions     = status.active_mentions.includes(:account).to_a | ||||
|     @reblogs      = status.reblogs.includes(:account).to_a | ||||
|     @stream_entry = status.stream_entry | ||||
|     @options      = options | ||||
|     @payload  = Oj.dump(event: :delete, payload: status.id.to_s) | ||||
|     @status   = status | ||||
|     @account  = status.account | ||||
|     @tags     = status.tags.pluck(:name).to_a | ||||
|     @mentions = status.active_mentions.includes(:account).to_a | ||||
|     @reblogs  = status.reblogs.includes(:account).to_a | ||||
|     @options  = options | ||||
|  | ||||
|     RedisLock.acquire(lock_options) do |lock| | ||||
|       if lock.acquired? | ||||
|   | ||||
| @@ -73,10 +73,7 @@ class ResolveURLService < BaseService | ||||
|  | ||||
|     return unless recognized_params[:action] == 'show' | ||||
|  | ||||
|     if recognized_params[:controller] == 'stream_entries' | ||||
|       status = StreamEntry.find_by(id: recognized_params[:id])&.status | ||||
|       check_local_status(status) | ||||
|     elsif recognized_params[:controller] == 'statuses' | ||||
|     if recognized_params[:controller] == 'statuses' | ||||
|       status = Status.find_by(id: recognized_params[:id]) | ||||
|       check_local_status(status) | ||||
|     elsif recognized_params[:controller] == 'accounts' | ||||
|   | ||||
| @@ -24,7 +24,6 @@ class SuspendAccountService < BaseService | ||||
|     report_notes | ||||
|     scheduled_statuses | ||||
|     status_pins | ||||
|     stream_entries | ||||
|     subscriptions | ||||
|   ).freeze | ||||
|  | ||||
|   | ||||
| @@ -3,10 +3,10 @@ | ||||
| .moved-account-widget | ||||
|   .moved-account-widget__message | ||||
|     = fa_icon 'suitcase' | ||||
|     = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), TagManager.instance.url_for(moved_to_account), class: 'mention')) | ||||
|     = t('accounts.moved_html', name: content_tag(:bdi, content_tag(:strong, display_name(account, custom_emojify: true), class: :emojify)), new_profile_link: link_to(content_tag(:strong, safe_join(['@', content_tag(:span, moved_to_account.acct)])), ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'mention')) | ||||
|  | ||||
|   .moved-account-widget__card | ||||
|     = link_to TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do | ||||
|     = link_to ActivityPub::TagManager.instance.url_for(moved_to_account), class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'me noopener' do | ||||
|       .detailed-status__display-avatar | ||||
|         .account__avatar-overlay | ||||
|           .account__avatar-overlay-base{ style: "background-image: url('#{moved_to_account.avatar.url(:original)}')" } | ||||
|   | ||||
| @@ -39,12 +39,12 @@ | ||||
|       - else | ||||
|         .activity-stream.activity-stream--under-tabs | ||||
|           - if params[:page].to_i.zero? | ||||
|             = render partial: 'stream_entries/status', collection: @pinned_statuses, as: :status, locals: { pinned: true } | ||||
|             = render partial: 'statuses/status', collection: @pinned_statuses, as: :status, locals: { pinned: true } | ||||
|  | ||||
|           - if @newer_url | ||||
|             .entry= link_to_more @newer_url | ||||
|  | ||||
|           = render partial: 'stream_entries/status', collection: @statuses, as: :status | ||||
|           = render partial: 'statuses/status', collection: @statuses, as: :status | ||||
|  | ||||
|           - if @older_url | ||||
|             .entry= link_to_more @older_url | ||||
|   | ||||
| @@ -19,4 +19,4 @@ | ||||
|       = table_link_to 'times', t('admin.accounts.reject'), reject_admin_account_path(account.id), method: :post, data: { confirm: t('admin.accounts.are_you_sure') } if can?(:reject, account.user) | ||||
|     - else | ||||
|       = table_link_to 'circle', t('admin.accounts.web'), web_path("accounts/#{account.id}") | ||||
|       = table_link_to 'globe', t('admin.accounts.public'), TagManager.instance.url_for(account) | ||||
|       = table_link_to 'globe', t('admin.accounts.public'), ActivityPub::TagManager.instance.url_for(account) | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
|         = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif, media: status.proper.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } | ||||
|  | ||||
|     .detailed-status__meta | ||||
|       = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do | ||||
|       = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime', target: stream_link_target, rel: 'noopener' do | ||||
|         %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) | ||||
|       · | ||||
|       - if status.reblog? | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) | ||||
| - account_url = local_assigns[:admin] ? admin_account_path(account.id) : ActivityPub::TagManager.instance.url_for(account) | ||||
|  | ||||
| .card.h-card | ||||
|   = link_to account_url, target: '_blank', rel: 'noopener' do | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| .post-follow-actions | ||||
|   %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@resource.id}"), class: 'button button--block' | ||||
|   %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@resource), class: 'button button--block' | ||||
|   %div= link_to t('authorize_follow.post_follow.return'), ActivityPub::TagManager.instance.url_for(@resource), class: 'button button--block' | ||||
|   %div= t('authorize_follow.post_follow.close') | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  | ||||
|     .public-layout | ||||
|       .activity-stream.activity-stream--highlighted | ||||
|         = render 'stream_entries/status', status: @status | ||||
|         = render 'statuses/status', status: @status | ||||
|  | ||||
|   = simple_form_for @remote_follow, as: :remote_follow, url: remote_interaction_path(@status) do |f| | ||||
|     = render 'shared/error_messages', object: @remote_follow | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|       = image_tag account.avatar.url(:original), alt: '', width: 48, height: 48, class: 'avatar' | ||||
|  | ||||
|     %span.display-name | ||||
|       - account_url = local_assigns[:admin] ? admin_account_path(account.id) : TagManager.instance.url_for(account) | ||||
|       - account_url = local_assigns[:admin] ? admin_account_path(account.id) : ActivityPub::TagManager.instance.url_for(account) | ||||
|       = link_to account_url, class: 'detailed-status__display-name p-author h-card', target: '_blank', rel: 'noopener' do | ||||
|         %strong.emojify= display_name(account, custom_emojify: true) | ||||
|         %span @#{account.acct} | ||||
|   | ||||
| @@ -1,4 +1,4 @@ | ||||
| .post-follow-actions | ||||
|   %div= link_to t('authorize_follow.post_follow.web'), web_url("accounts/#{@account.id}"), class: 'button button--block' | ||||
|   %div= link_to t('authorize_follow.post_follow.return'), TagManager.instance.url_for(@account), class: 'button button--block' | ||||
|   %div= link_to t('authorize_follow.post_follow.return'), ActivityPub::TagManager.instance.url_for(@account), class: 'button button--block' | ||||
|   %div= t('authorize_follow.post_follow.close') | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| .detailed-status.detailed-status--flex | ||||
|   .p-author.h-card | ||||
|     = link_to TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do | ||||
|     = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'detailed-status__display-name u-url', target: stream_link_target, rel: 'noopener' do | ||||
|       .detailed-status__display-avatar | ||||
|         - if current_account&.user&.setting_auto_play_gif || autoplay | ||||
|           = image_tag status.account.avatar_original_url, width: 48, height: 48, alt: '', class: 'account__avatar u-photo' | ||||
| @@ -24,23 +24,23 @@ | ||||
|       = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) | ||||
|       - if status.preloadable_poll | ||||
|         = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do | ||||
|           = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } | ||||
|           = render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } | ||||
| 
 | ||||
|   - if !status.media_attachments.empty? | ||||
|     - if status.media_attachments.first.audio_or_video? | ||||
|       - video = status.media_attachments.first | ||||
|       = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 670, height: 380, detailed: true, inline: true, alt: video.description do | ||||
|         = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } | ||||
|         = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } | ||||
|     - else | ||||
|       = react_component :media_gallery, height: 380, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, standalone: true, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, 'reduceMotion': current_account&.user&.setting_reduce_motion, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do | ||||
|         = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } | ||||
|         = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } | ||||
|   - elsif status.preview_card | ||||
|     = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json | ||||
| 
 | ||||
|   .detailed-status__meta | ||||
|     %data.dt-published{ value: status.created_at.to_time.iso8601 } | ||||
| 
 | ||||
|     = link_to TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener' do | ||||
|     = link_to ActivityPub::TagManager.instance.url_for(status), class: 'detailed-status__datetime u-url u-uid', target: stream_link_target, rel: 'noopener' do | ||||
|       %time.formatted{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) | ||||
|     · | ||||
|     - if status.application && @account.user&.setting_show_application | ||||
| @@ -1,11 +1,11 @@ | ||||
| .status | ||||
|   .status__info | ||||
|     = link_to TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do | ||||
|     = link_to ActivityPub::TagManager.instance.url_for(status), class: 'status__relative-time u-url u-uid', target: stream_link_target, rel: 'noopener' do | ||||
|       %time.time-ago{ datetime: status.created_at.iso8601, title: l(status.created_at) }= l(status.created_at) | ||||
|     %data.dt-published{ value: status.created_at.to_time.iso8601 } | ||||
| 
 | ||||
|     .p-author.h-card | ||||
|       = link_to TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do | ||||
|       = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do | ||||
|         .status__avatar | ||||
|           %div | ||||
|             - if current_account&.user&.setting_auto_play_gif || autoplay | ||||
| @@ -28,16 +28,16 @@ | ||||
|       = Formatter.instance.format(status, custom_emojify: true, autoplay: autoplay) | ||||
|       - if status.preloadable_poll | ||||
|         = react_component :poll, disabled: true, poll: ActiveModelSerializers::SerializableResource.new(status.preloadable_poll, serializer: REST::PollSerializer, scope: current_user, scope_name: :current_user).as_json do | ||||
|           = render partial: 'stream_entries/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } | ||||
|           = render partial: 'statuses/poll', locals: { status: status, poll: status.preloadable_poll, autoplay: autoplay } | ||||
| 
 | ||||
|   - if !status.media_attachments.empty? | ||||
|     - if status.media_attachments.first.audio_or_video? | ||||
|       - video = status.media_attachments.first | ||||
|       = react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description do | ||||
|         = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } | ||||
|         = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } | ||||
|     - else | ||||
|       = react_component :media_gallery, height: 343, sensitive: !current_account&.user&.show_all_media? && status.sensitive? || current_account&.user&.hide_all_media?, 'autoPlayGif': current_account&.user&.setting_auto_play_gif || autoplay, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json } do | ||||
|         = render partial: 'stream_entries/attachment_list', locals: { attachments: status.media_attachments } | ||||
|         = render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments } | ||||
|   - elsif status.preview_card | ||||
|     = react_component :card, 'maxDescription': 160, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json | ||||
| 
 | ||||
| @@ -17,9 +17,9 @@ | ||||
| - if status.reply? && include_threads | ||||
|   - if @next_ancestor | ||||
|     .entry{ class: entry_classes } | ||||
|       = link_to_more TagManager.instance.url_for(@next_ancestor) | ||||
|       = link_to_more ActivityPub::TagManager.instance.url_for(@next_ancestor) | ||||
| 
 | ||||
|   = render partial: 'stream_entries/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay | ||||
|   = render partial: 'statuses/status', collection: @ancestors, as: :status, locals: { is_predecessor: true, direct_reply_id: status.in_reply_to_id }, autoplay: autoplay | ||||
| 
 | ||||
| .entry{ class: entry_classes } | ||||
| 
 | ||||
| @@ -28,7 +28,7 @@ | ||||
|       .status__prepend-icon-wrapper | ||||
|         %i.status__prepend-icon.fa.fa-fw.fa-retweet | ||||
|       %span | ||||
|         = link_to TagManager.instance.url_for(status.account), class: 'status__display-name muted' do | ||||
|         = link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name muted' do | ||||
|           %bdi | ||||
|             %strong.emojify= display_name(status.account, custom_emojify: true) | ||||
|         = t('stream_entries.reblogged') | ||||
| @@ -39,18 +39,18 @@ | ||||
|       %span | ||||
|         = t('stream_entries.pinned') | ||||
| 
 | ||||
|   = render (centered ? 'stream_entries/detailed_status' : 'stream_entries/simple_status'), status: status.proper, autoplay: autoplay | ||||
|   = render (centered ? 'statuses/detailed_status' : 'statuses/simple_status'), status: status.proper, autoplay: autoplay | ||||
| 
 | ||||
| - if include_threads | ||||
|   - if @since_descendant_thread_id | ||||
|     .entry{ class: entry_classes } | ||||
|       = link_to_more short_account_status_url(status.account.username, status, max_descendant_thread_id: @since_descendant_thread_id + 1) | ||||
|   - @descendant_threads.each do |thread| | ||||
|     = render partial: 'stream_entries/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay | ||||
|     = render partial: 'statuses/status', collection: thread[:statuses], as: :status, locals: { is_successor: true, parent_id: status.id }, autoplay: autoplay | ||||
| 
 | ||||
|     - if thread[:next_status] | ||||
|       .entry{ class: entry_classes } | ||||
|         = link_to_more TagManager.instance.url_for(thread[:next_status]) | ||||
|         = link_to_more ActivityPub::TagManager.instance.url_for(thread[:next_status]) | ||||
|   - if @next_descendant_thread | ||||
|     .entry{ class: entry_classes } | ||||
|       = link_to_more short_account_status_url(status.account.username, status, since_descendant_thread_id: @max_descendant_thread_id - 1) | ||||
							
								
								
									
										3
									
								
								app/views/statuses/embed.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/views/statuses/embed.html.haml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| - cache @status do | ||||
|   .activity-stream.activity-stream--headless | ||||
|     = render 'status', status: @status, centered: true, autoplay: @autoplay | ||||
							
								
								
									
										24
									
								
								app/views/statuses/show.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								app/views/statuses/show.html.haml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| - content_for :page_title do | ||||
|   = t('statuses.title', name: display_name(@account), quote: truncate(@status.spoiler_text.presence || @status.text, length: 50, omission: '…', escape: false)) | ||||
|  | ||||
| - content_for :header_tags do | ||||
|   - if @account.user&.setting_noindex | ||||
|     %meta{ name: 'robots', content: 'noindex' }/ | ||||
|  | ||||
|   %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: short_account_status_url(@account, @status), format: 'json') }/ | ||||
|   %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@status) }/ | ||||
|  | ||||
|   = opengraph 'og:site_name', site_title | ||||
|   = opengraph 'og:type', 'article' | ||||
|   = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})" | ||||
|   = opengraph 'og:url', short_account_status_url(@account, @status) | ||||
|  | ||||
|   = render 'og_description', activity: @status | ||||
|   = render 'og_image', activity: @status, account: @account | ||||
|  | ||||
| .grid | ||||
|   .column-0 | ||||
|     .activity-stream.h-entry | ||||
|       = render partial: 'status', locals: { status: @status, include_threads: true } | ||||
|   .column-1 | ||||
|     = render 'application/sidebar' | ||||
| @@ -1,3 +0,0 @@ | ||||
| - cache @stream_entry.activity do | ||||
|   .activity-stream.activity-stream--headless | ||||
|     = render "stream_entries/#{@type}", @type.to_sym => @stream_entry.activity, centered: true, autoplay: @autoplay | ||||
| @@ -1,25 +0,0 @@ | ||||
| - content_for :page_title do | ||||
|   = t('statuses.title', name: display_name(@account), quote: truncate(@stream_entry.activity.spoiler_text.presence || @stream_entry.activity.text, length: 50, omission: '…', escape: false)) | ||||
|  | ||||
| - content_for :header_tags do | ||||
|   - if @account.user&.setting_noindex | ||||
|     %meta{ name: 'robots', content: 'noindex' }/ | ||||
|  | ||||
|   %link{ rel: 'alternate', type: 'application/atom+xml', href: account_stream_entry_url(@account, @stream_entry, format: 'atom') }/ | ||||
|   %link{ rel: 'alternate', type: 'application/json+oembed', href: api_oembed_url(url: account_stream_entry_url(@account, @stream_entry), format: 'json') }/ | ||||
|   %link{ rel: 'alternate', type: 'application/activity+json', href: ActivityPub::TagManager.instance.uri_for(@stream_entry.activity) }/ | ||||
|  | ||||
|   = opengraph 'og:site_name', site_title | ||||
|   = opengraph 'og:type', 'article' | ||||
|   = opengraph 'og:title', "#{display_name(@account)} (@#{@account.local_username_and_domain})" | ||||
|   = opengraph 'og:url', short_account_status_url(@account, @stream_entry.activity) | ||||
|  | ||||
|   = render 'stream_entries/og_description', activity: @stream_entry.activity | ||||
|   = render 'stream_entries/og_image', activity: @stream_entry.activity, account: @account | ||||
|  | ||||
| .grid | ||||
|   .column-0 | ||||
|     .activity-stream.h-entry | ||||
|       = render partial: "stream_entries/#{@type}", locals: { @type.to_sym => @stream_entry.activity, include_threads: true } | ||||
|   .column-1 | ||||
|     = render 'application/sidebar' | ||||
| @@ -45,12 +45,6 @@ Rails.application.routes.draw do | ||||
|   get '/authorize_follow', to: redirect { |_, request| "/authorize_interaction?#{request.params.to_query}" } | ||||
|  | ||||
|   resources :accounts, path: 'users', only: [:show], param: :username do | ||||
|     resources :stream_entries, path: 'updates', only: [:show] do | ||||
|       member do | ||||
|         get :embed | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     get :remote_follow,  to: 'remote_follow#new' | ||||
|     post :remote_follow, to: 'remote_follow#create' | ||||
|  | ||||
|   | ||||
							
								
								
									
										13
									
								
								db/post_migrate/20190706233204_drop_stream_entries.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								db/post_migrate/20190706233204_drop_stream_entries.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| class DropStreamEntries < ActiveRecord::Migration[5.2] | ||||
|   disable_ddl_transaction! | ||||
|  | ||||
|   def up | ||||
|     drop_table :stream_entries | ||||
|   end | ||||
|  | ||||
|   def down | ||||
|     raise ActiveRecord::IrreversibleMigration | ||||
|   end | ||||
| end | ||||
							
								
								
									
										14
									
								
								db/schema.rb
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								db/schema.rb
									
									
									
									
									
								
							| @@ -10,7 +10,7 @@ | ||||
| # | ||||
| # It's strongly recommended that you check this file into your version control system. | ||||
|  | ||||
| ActiveRecord::Schema.define(version: 2019_06_27_222826) do | ||||
| ActiveRecord::Schema.define(version: 2019_07_06_233204) do | ||||
|  | ||||
|   # These are extensions that must be enabled in order to support this database | ||||
|   enable_extension "plpgsql" | ||||
| @@ -647,17 +647,6 @@ ActiveRecord::Schema.define(version: 2019_06_27_222826) do | ||||
|     t.index ["tag_id", "status_id"], name: "index_statuses_tags_on_tag_id_and_status_id", unique: true | ||||
|   end | ||||
|  | ||||
|   create_table "stream_entries", force: :cascade do |t| | ||||
|     t.bigint "activity_id" | ||||
|     t.string "activity_type" | ||||
|     t.datetime "created_at", null: false | ||||
|     t.datetime "updated_at", null: false | ||||
|     t.boolean "hidden", default: false, null: false | ||||
|     t.bigint "account_id" | ||||
|     t.index ["account_id", "activity_type", "id"], name: "index_stream_entries_on_account_id_and_activity_type_and_id" | ||||
|     t.index ["activity_id", "activity_type"], name: "index_stream_entries_on_activity_id_and_activity_type" | ||||
|   end | ||||
|  | ||||
|   create_table "subscriptions", force: :cascade do |t| | ||||
|     t.string "callback_url", default: "", null: false | ||||
|     t.string "secret" | ||||
| @@ -831,7 +820,6 @@ ActiveRecord::Schema.define(version: 2019_06_27_222826) do | ||||
|   add_foreign_key "statuses", "statuses", column: "reblog_of_id", on_delete: :cascade | ||||
|   add_foreign_key "statuses_tags", "statuses", on_delete: :cascade | ||||
|   add_foreign_key "statuses_tags", "tags", name: "fk_3081861e21", on_delete: :cascade | ||||
|   add_foreign_key "stream_entries", "accounts", name: "fk_5659b17554", on_delete: :cascade | ||||
|   add_foreign_key "subscriptions", "accounts", name: "fk_9847d1cbb5", on_delete: :cascade | ||||
|   add_foreign_key "tombstones", "accounts", on_delete: :cascade | ||||
|   add_foreign_key "user_invite_requests", "users", on_delete: :cascade | ||||
|   | ||||
| @@ -48,37 +48,6 @@ RSpec.describe AccountsController, type: :controller do | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'atom' do | ||||
|       let(:format) { 'atom' } | ||||
|       let(:content_type) { 'application/atom+xml' } | ||||
|  | ||||
|       shared_examples 'responsed streams' do | ||||
|         it 'assigns @entries' do | ||||
|           entries = assigns(:entries).to_a | ||||
|           expect(entries.size).to eq expected_statuses.size | ||||
|           entries.each.zip(expected_statuses.each) do |entry, expected_status| | ||||
|             expect(entry.status).to eq expected_status | ||||
|           end | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       include_examples 'responses' | ||||
|  | ||||
|       context 'without max_id nor since_id' do | ||||
|         let(:expected_statuses) { [status7, status6, status5, status4, status3, status2, status1] } | ||||
|  | ||||
|         include_examples 'responsed streams' | ||||
|       end | ||||
|  | ||||
|       context 'with max_id and since_id' do | ||||
|         let(:max_id) { status4.stream_entry.id } | ||||
|         let(:since_id) { status1.stream_entry.id } | ||||
|         let(:expected_statuses) { [status3, status2] } | ||||
|  | ||||
|         include_examples 'responsed streams' | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'activitystreams2' do | ||||
|       let(:format) { 'json' } | ||||
|       let(:content_type) { 'application/activity+json' } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ RSpec.describe Api::OEmbedController, type: :controller do | ||||
|   describe 'GET #show' do | ||||
|     before do | ||||
|       request.host = Rails.configuration.x.local_domain | ||||
|       get :show, params: { url: account_stream_entry_url(alice, status.stream_entry) }, format: :json | ||||
|       get :show, params: { url: short_account_status_url(alice, status) }, format: :json | ||||
|     end | ||||
|  | ||||
|     it 'returns http success' do | ||||
|   | ||||
| @@ -360,9 +360,5 @@ describe ApplicationController, type: :controller do | ||||
|     context 'Status' do | ||||
|       include_examples 'cacheable', :status, Status | ||||
|     end | ||||
|  | ||||
|     context 'StreamEntry' do | ||||
|       include_examples 'receives :with_includes', :stream_entry, StreamEntry | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -55,18 +55,6 @@ describe StatusesController do | ||||
|         expect(assigns(:status)).to eq status | ||||
|       end | ||||
|  | ||||
|       it 'assigns @stream_entry' do | ||||
|         status = Fabricate(:status) | ||||
|         get :show, params: { account_username: status.account.username, id: status.id } | ||||
|         expect(assigns(:stream_entry)).to eq status.stream_entry | ||||
|       end | ||||
|  | ||||
|       it 'assigns @type' do | ||||
|         status = Fabricate(:status) | ||||
|         get :show, params: { account_username: status.account.username, id: status.id } | ||||
|         expect(assigns(:type)).to eq 'status' | ||||
|       end | ||||
|  | ||||
|       it 'assigns @ancestors for ancestors of the status if it is a reply' do | ||||
|         ancestor = Fabricate(:status) | ||||
|         status = Fabricate(:status, in_reply_to_id: ancestor.id) | ||||
| @@ -135,10 +123,10 @@ describe StatusesController do | ||||
|         expect(response).to have_http_status(200) | ||||
|       end | ||||
|  | ||||
|       it 'renders stream_entries/show' do | ||||
|       it 'renders statuses/show' do | ||||
|         status = Fabricate(:status) | ||||
|         get :show, params: { account_username: status.account.username, id: status.id } | ||||
|         expect(response).to render_template 'stream_entries/show' | ||||
|         expect(response).to render_template 'statuses/show' | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|   | ||||
| @@ -1,95 +0,0 @@ | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe StreamEntriesController, type: :controller do | ||||
|   render_views | ||||
|  | ||||
|   shared_examples 'before_action' do |route| | ||||
|     context 'when account is not suspended and stream_entry is available' do | ||||
|       it 'assigns instance variables' do | ||||
|         status = Fabricate(:status) | ||||
|  | ||||
|         get route, params: { account_username: status.account.username, id: status.stream_entry.id } | ||||
|  | ||||
|         expect(assigns(:account)).to eq status.account | ||||
|         expect(assigns(:stream_entry)).to eq status.stream_entry | ||||
|         expect(assigns(:type)).to eq 'status' | ||||
|       end | ||||
|  | ||||
|       it 'sets Link headers' do | ||||
|         alice = Fabricate(:account, username: 'alice') | ||||
|         status = Fabricate(:status, account: alice) | ||||
|  | ||||
|         get route, params: { account_username: alice.username, id: status.stream_entry.id } | ||||
|  | ||||
|         expect(response.headers['Link'].to_s).to eq "<http://test.host/users/alice/updates/#{status.stream_entry.id}.atom>; rel=\"alternate\"; type=\"application/atom+xml\", <https://cb6e6126.ngrok.io/users/alice/statuses/#{status.id}>; rel=\"alternate\"; type=\"application/activity+json\"" | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'when account is suspended' do | ||||
|       it 'returns http status 410' do | ||||
|         account = Fabricate(:account, suspended: true) | ||||
|         status = Fabricate(:status, account: account) | ||||
|  | ||||
|         get route, params: { account_username: account.username, id: status.stream_entry.id } | ||||
|  | ||||
|         expect(response).to have_http_status(410) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'when activity is nil' do | ||||
|       it 'raises ActiveRecord::RecordNotFound' do | ||||
|         account = Fabricate(:account) | ||||
|         stream_entry = Fabricate.build(:stream_entry, account: account, activity: nil, activity_type: 'Status') | ||||
|         stream_entry.save!(validate: false) | ||||
|  | ||||
|         get route, params: { account_username: account.username, id: stream_entry.id } | ||||
|  | ||||
|         expect(response).to have_http_status(404) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'when it is hidden and it is not permitted' do | ||||
|       it 'raises ActiveRecord::RecordNotFound' do | ||||
|         status = Fabricate(:status) | ||||
|         user = Fabricate(:user) | ||||
|         status.account.block!(user.account) | ||||
|         status.stream_entry.update!(hidden: true) | ||||
|  | ||||
|         sign_in(user) | ||||
|         get route, params: { account_username: status.account.username, id: status.stream_entry.id } | ||||
|  | ||||
|         expect(response).to have_http_status(404) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe 'GET #show' do | ||||
|     include_examples 'before_action', :show | ||||
|  | ||||
|     it 'redirects to status page' do | ||||
|       status = Fabricate(:status) | ||||
|  | ||||
|       get :show, params: { account_username: status.account.username, id: status.stream_entry.id } | ||||
|  | ||||
|       expect(response).to redirect_to(short_account_status_url(status.account, status)) | ||||
|     end | ||||
|  | ||||
|     it 'returns http success with Atom' do | ||||
|       status = Fabricate(:status) | ||||
|       get :show, params: { account_username: status.account.username, id: status.stream_entry.id }, format: 'atom' | ||||
|       expect(response).to have_http_status(200) | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe 'GET #embed' do | ||||
|     include_examples 'before_action', :embed | ||||
|  | ||||
|     it 'redirects to new embed page' do | ||||
|       status = Fabricate(:status) | ||||
|  | ||||
|       get :embed, params: { account_username: status.account.username, id: status.stream_entry.id } | ||||
|  | ||||
|       expect(response).to redirect_to(embed_short_account_status_url(status.account, status)) | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -1,5 +0,0 @@ | ||||
| Fabricator(:stream_entry) do | ||||
|   account | ||||
|   activity { Fabricate(:status) } | ||||
|   hidden { [true, false].sample } | ||||
| end | ||||
| @@ -3,7 +3,7 @@ | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe Admin::AccountModerationNotesHelper, type: :helper do | ||||
|   include StreamEntriesHelper | ||||
|   include StatusesHelper | ||||
|  | ||||
|   describe '#admin_account_link_to' do | ||||
|     context 'account is nil' do | ||||
|   | ||||
| @@ -1,6 +1,6 @@ | ||||
| require 'rails_helper' | ||||
| 
 | ||||
| RSpec.describe StreamEntriesHelper, type: :helper do | ||||
| RSpec.describe StatusesHelper, type: :helper do | ||||
|   describe '#display_name' do | ||||
|     it 'uses the display name when it exists' do | ||||
|       account = Account.new(display_name: "Display", username: "Username") | ||||
| @@ -70,13 +70,13 @@ RSpec.describe StreamEntriesHelper, type: :helper do | ||||
|   end | ||||
| 
 | ||||
|   def set_not_embedded_view | ||||
|     params[:controller] = "not_#{StreamEntriesHelper::EMBEDDED_CONTROLLER}" | ||||
|     params[:action] = "not_#{StreamEntriesHelper::EMBEDDED_ACTION}" | ||||
|     params[:controller] = "not_#{StatusesHelper::EMBEDDED_CONTROLLER}" | ||||
|     params[:action] = "not_#{StatusesHelper::EMBEDDED_ACTION}" | ||||
|   end | ||||
| 
 | ||||
|   def set_embedded_view | ||||
|     params[:controller] = StreamEntriesHelper::EMBEDDED_CONTROLLER | ||||
|     params[:action] = StreamEntriesHelper::EMBEDDED_ACTION | ||||
|     params[:controller] = StatusesHelper::EMBEDDED_CONTROLLER | ||||
|     params[:action] = StatusesHelper::EMBEDDED_ACTION | ||||
|   end | ||||
| 
 | ||||
|   describe '#style_classes' do | ||||
| @@ -143,12 +143,6 @@ RSpec.describe ActivityPub::TagManager do | ||||
|       expect(subject.uri_to_resource(OStatus::TagManager.instance.uri_for(status), Status)).to eq status | ||||
|     end | ||||
|  | ||||
|     it 'returns the local status for OStatus StreamEntry URL' do | ||||
|       status = Fabricate(:status) | ||||
|       stream_entry_url = account_stream_entry_url(status.account, status.stream_entry) | ||||
|       expect(subject.uri_to_resource(stream_entry_url, Status)).to eq status | ||||
|     end | ||||
|  | ||||
|     it 'returns the remote status by matching URI without fragment part' do | ||||
|       status = Fabricate(:status, uri: 'https://example.com/123') | ||||
|       expect(subject.uri_to_resource('https://example.com/123#456', Status)).to eq status | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -25,15 +25,6 @@ describe StatusFinder do | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'with a stream entry url' do | ||||
|       let(:stream_entry) { Fabricate(:stream_entry) } | ||||
|       let(:url) { account_stream_entry_url(stream_entry.account, stream_entry) } | ||||
|  | ||||
|       it 'finds the stream entry' do | ||||
|         expect(subject.status).to eq(stream_entry.status) | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'with a remote url even if id exists on local' do | ||||
|       let(:status) { Fabricate(:status) } | ||||
|       let(:url) { "https://example.com/users/test/statuses/#{status.id}" } | ||||
|   | ||||
| @@ -119,46 +119,4 @@ RSpec.describe TagManager do | ||||
|       expect(TagManager.instance.same_acct?('username', 'incorrect@Cb6E6126.nGrOk.Io')).to eq false | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#url_for' do | ||||
|     let(:alice) { Fabricate(:account, username: 'alice') } | ||||
|  | ||||
|     subject { TagManager.instance.url_for(target) } | ||||
|  | ||||
|     context 'activity object' do | ||||
|       let(:target) { Fabricate(:status, account: alice, reblog: Fabricate(:status)).stream_entry } | ||||
|  | ||||
|       it 'returns the unique tag for status' do | ||||
|         expect(target.object_type).to eq :activity | ||||
|         is_expected.to eq "https://cb6e6126.ngrok.io/@alice/#{target.id}" | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'comment object' do | ||||
|       let(:target) { Fabricate(:status, account: alice, reply: true) } | ||||
|  | ||||
|       it 'returns the unique tag for status' do | ||||
|         expect(target.object_type).to eq :comment | ||||
|         is_expected.to eq "https://cb6e6126.ngrok.io/@alice/#{target.id}" | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'note object' do | ||||
|       let(:target) { Fabricate(:status, account: alice, reply: false, thread: nil) } | ||||
|  | ||||
|       it 'returns the unique tag for status' do | ||||
|         expect(target.object_type).to eq :note | ||||
|         is_expected.to eq "https://cb6e6126.ngrok.io/@alice/#{target.id}" | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'person object' do | ||||
|       let(:target) { alice } | ||||
|  | ||||
|       it 'returns the URL for account' do | ||||
|         expect(target.object_type).to eq :person | ||||
|         is_expected.to eq 'https://cb6e6126.ngrok.io/@alice' | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
|   | ||||
| @@ -1,63 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe Streamable do | ||||
|   class Parent | ||||
|     def title; end | ||||
|  | ||||
|     def target; end | ||||
|  | ||||
|     def thread; end | ||||
|  | ||||
|     def self.has_one(*); end | ||||
|  | ||||
|     def self.after_create; end | ||||
|   end | ||||
|  | ||||
|   class Child < Parent | ||||
|     include Streamable | ||||
|   end | ||||
|  | ||||
|   child = Child.new | ||||
|  | ||||
|   describe '#title' do | ||||
|     it 'calls Parent#title' do | ||||
|       expect_any_instance_of(Parent).to receive(:title) | ||||
|       child.title | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#content' do | ||||
|     it 'calls #title' do | ||||
|       expect_any_instance_of(Parent).to receive(:title) | ||||
|       child.content | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#target' do | ||||
|     it 'calls Parent#target' do | ||||
|       expect_any_instance_of(Parent).to receive(:target) | ||||
|       child.target | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#object_type' do | ||||
|     it 'returns :activity' do | ||||
|       expect(child.object_type).to eq :activity | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#thread' do | ||||
|     it 'calls Parent#thread' do | ||||
|       expect_any_instance_of(Parent).to receive(:thread) | ||||
|       child.thread | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#hidden?' do | ||||
|     it 'returns false' do | ||||
|       expect(child.hidden?).to be false | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -1,143 +0,0 @@ | ||||
| # frozen_string_literal: true | ||||
|  | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe RemoteProfile do | ||||
|   let(:remote_profile) { RemoteProfile.new(body) } | ||||
|   let(:body) do | ||||
|     <<-XML | ||||
|       <feed xmlns="http://www.w3.org/2005/Atom"> | ||||
|       <author>John</author> | ||||
|     XML | ||||
|   end | ||||
|  | ||||
|   describe '.initialize' do | ||||
|     it 'calls Nokogiri::XML.parse' do | ||||
|       expect(Nokogiri::XML).to receive(:parse).with(body, nil, 'utf-8') | ||||
|       RemoteProfile.new(body) | ||||
|     end | ||||
|  | ||||
|     it 'sets document' do | ||||
|       remote_profile = RemoteProfile.new(body) | ||||
|       expect(remote_profile).not_to be nil | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#root' do | ||||
|     let(:document) { remote_profile.document } | ||||
|  | ||||
|     it 'callse document.at_xpath' do | ||||
|       expect(document).to receive(:at_xpath).with( | ||||
|         '/atom:feed|/atom:entry', | ||||
|         atom: OStatus::TagManager::XMLNS | ||||
|       ) | ||||
|  | ||||
|       remote_profile.root | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#author' do | ||||
|     let(:root) { remote_profile.root } | ||||
|  | ||||
|     it 'calls root.at_xpath' do | ||||
|       expect(root).to receive(:at_xpath).with( | ||||
|         './atom:author|./dfrn:owner', | ||||
|         atom: OStatus::TagManager::XMLNS, | ||||
|         dfrn: OStatus::TagManager::DFRN_XMLNS | ||||
|       ) | ||||
|  | ||||
|       remote_profile.author | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#hub_link' do | ||||
|     let(:root) { remote_profile.root } | ||||
|  | ||||
|     it 'calls #link_href_from_xml' do | ||||
|       expect(remote_profile).to receive(:link_href_from_xml).with(root, 'hub') | ||||
|       remote_profile.hub_link | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#display_name' do | ||||
|     let(:author) { remote_profile.author } | ||||
|  | ||||
|     it 'calls author.at_xpath.content' do | ||||
|       expect(author).to receive_message_chain(:at_xpath, :content).with( | ||||
|         './poco:displayName', | ||||
|         poco: OStatus::TagManager::POCO_XMLNS | ||||
|       ).with(no_args) | ||||
|  | ||||
|       remote_profile.display_name | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#note' do | ||||
|     let(:author) { remote_profile.author } | ||||
|  | ||||
|     it 'calls author.at_xpath.content' do | ||||
|       expect(author).to receive_message_chain(:at_xpath, :content).with( | ||||
|         './atom:summary|./poco:note', | ||||
|         atom: OStatus::TagManager::XMLNS, | ||||
|         poco: OStatus::TagManager::POCO_XMLNS | ||||
|       ).with(no_args) | ||||
|  | ||||
|       remote_profile.note | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#scope' do | ||||
|     let(:author) { remote_profile.author } | ||||
|  | ||||
|     it 'calls author.at_xpath.content' do | ||||
|       expect(author).to receive_message_chain(:at_xpath, :content).with( | ||||
|         './mastodon:scope', | ||||
|         mastodon: OStatus::TagManager::MTDN_XMLNS | ||||
|       ).with(no_args) | ||||
|  | ||||
|       remote_profile.scope | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#avatar' do | ||||
|     let(:author) { remote_profile.author } | ||||
|  | ||||
|     it 'calls #link_href_from_xml' do | ||||
|       expect(remote_profile).to receive(:link_href_from_xml).with(author, 'avatar') | ||||
|       remote_profile.avatar | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#header' do | ||||
|     let(:author) { remote_profile.author } | ||||
|  | ||||
|     it 'calls #link_href_from_xml' do | ||||
|       expect(remote_profile).to receive(:link_href_from_xml).with(author, 'header') | ||||
|       remote_profile.header | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#locked?' do | ||||
|     before do | ||||
|       allow(remote_profile).to receive(:scope).and_return(scope) | ||||
|     end | ||||
|  | ||||
|     subject { remote_profile.locked? } | ||||
|  | ||||
|     context 'scope is private' do | ||||
|       let(:scope) { 'private' } | ||||
|  | ||||
|       it 'returns true' do | ||||
|         is_expected.to be true | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'scope is not private' do | ||||
|       let(:scope) { 'public' } | ||||
|  | ||||
|       it 'returns false' do | ||||
|         is_expected.to be false | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -1,192 +0,0 @@ | ||||
| require 'rails_helper' | ||||
|  | ||||
| RSpec.describe StreamEntry, type: :model do | ||||
|   let(:alice)     { Fabricate(:account, username: 'alice') } | ||||
|   let(:bob)       { Fabricate(:account, username: 'bob') } | ||||
|   let(:status)    { Fabricate(:status, account: alice) } | ||||
|   let(:reblog)    { Fabricate(:status, account: bob, reblog: status) } | ||||
|   let(:reply)     { Fabricate(:status, account: bob, thread: status) } | ||||
|   let(:stream_entry) { Fabricate(:stream_entry, activity: activity) } | ||||
|   let(:activity)     { reblog } | ||||
|  | ||||
|   describe '#object_type' do | ||||
|     before do | ||||
|       allow(stream_entry).to receive(:orphaned?).and_return(orphaned) | ||||
|       allow(stream_entry).to receive(:targeted?).and_return(targeted) | ||||
|     end | ||||
|  | ||||
|     subject { stream_entry.object_type } | ||||
|  | ||||
|     context 'orphaned? is true' do | ||||
|       let(:orphaned) { true } | ||||
|       let(:targeted) { false } | ||||
|  | ||||
|       it 'returns :activity' do | ||||
|         is_expected.to be :activity | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'targeted? is true' do | ||||
|       let(:orphaned) { false } | ||||
|       let(:targeted) { true } | ||||
|  | ||||
|       it 'returns :activity' do | ||||
|         is_expected.to be :activity | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'orphaned? and targeted? are false' do | ||||
|       let(:orphaned) { false } | ||||
|       let(:targeted) { false } | ||||
|  | ||||
|       context 'activity is reblog' do | ||||
|         let(:activity) { reblog } | ||||
|  | ||||
|         it 'returns :note' do | ||||
|           is_expected.to be :note | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       context 'activity is reply' do | ||||
|         let(:activity) { reply } | ||||
|  | ||||
|         it 'returns :comment' do | ||||
|           is_expected.to be :comment | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#verb' do | ||||
|     before do | ||||
|       allow(stream_entry).to receive(:orphaned?).and_return(orphaned) | ||||
|     end | ||||
|  | ||||
|     subject { stream_entry.verb } | ||||
|  | ||||
|     context 'orphaned? is true' do | ||||
|       let(:orphaned) { true } | ||||
|  | ||||
|       it 'returns :delete' do | ||||
|         is_expected.to be :delete | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'orphaned? is false' do | ||||
|       let(:orphaned) { false } | ||||
|  | ||||
|       context 'activity is reblog' do | ||||
|         let(:activity) { reblog } | ||||
|  | ||||
|         it 'returns :share' do | ||||
|           is_expected.to be :share | ||||
|         end | ||||
|       end | ||||
|  | ||||
|       context 'activity is reply' do | ||||
|         let(:activity) { reply } | ||||
|  | ||||
|         it 'returns :post' do | ||||
|           is_expected.to be :post | ||||
|         end | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#mentions' do | ||||
|     before do | ||||
|       allow(stream_entry).to receive(:orphaned?).and_return(orphaned) | ||||
|     end | ||||
|  | ||||
|     subject { stream_entry.mentions } | ||||
|  | ||||
|     context 'orphaned? is true' do | ||||
|       let(:orphaned) { true } | ||||
|  | ||||
|       it 'returns []' do | ||||
|         is_expected.to eq [] | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'orphaned? is false' do | ||||
|       before do | ||||
|         reblog.mentions << Fabricate(:mention, account: alice) | ||||
|         reblog.mentions << Fabricate(:mention, account: bob) | ||||
|       end | ||||
|  | ||||
|       let(:orphaned) { false } | ||||
|  | ||||
|       it 'returns [Account] includes alice and bob' do | ||||
|         is_expected.to eq [alice, bob] | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#targeted?' do | ||||
|     it 'returns true for a reblog' do | ||||
|       expect(reblog.stream_entry.targeted?).to be true | ||||
|     end | ||||
|  | ||||
|     it 'returns false otherwise' do | ||||
|       expect(status.stream_entry.targeted?).to be false | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe '#threaded?' do | ||||
|     it 'returns true for a reply' do | ||||
|       expect(reply.stream_entry.threaded?).to be true | ||||
|     end | ||||
|  | ||||
|     it 'returns false otherwise' do | ||||
|       expect(status.stream_entry.threaded?).to be false | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   describe 'delegated methods' do | ||||
|     context 'with a nil status' do | ||||
|       subject { described_class.new(status: nil) } | ||||
|  | ||||
|       it 'returns nil for target' do | ||||
|         expect(subject.target).to be_nil | ||||
|       end | ||||
|  | ||||
|       it 'returns nil for title' do | ||||
|         expect(subject.title).to be_nil | ||||
|       end | ||||
|  | ||||
|       it 'returns nil for content' do | ||||
|         expect(subject.content).to be_nil | ||||
|       end | ||||
|  | ||||
|       it 'returns nil for thread' do | ||||
|         expect(subject.thread).to be_nil | ||||
|       end | ||||
|     end | ||||
|  | ||||
|     context 'with a real status' do | ||||
|       let(:original) { Fabricate(:status, text: 'Test status') } | ||||
|       let(:status) { Fabricate(:status, reblog: original, thread: original) } | ||||
|       subject { described_class.new(status: status) } | ||||
|  | ||||
|       it 'delegates target' do | ||||
|         expect(status.target).not_to be_nil | ||||
|         expect(subject.target).to eq(status.target) | ||||
|       end | ||||
|  | ||||
|       it 'delegates title' do | ||||
|         expect(status.title).not_to be_nil | ||||
|         expect(subject.title).to eq(status.title) | ||||
|       end | ||||
|  | ||||
|       it 'delegates content' do | ||||
|         expect(status.content).not_to be_nil | ||||
|         expect(subject.content).to eq(status.content) | ||||
|       end | ||||
|  | ||||
|       it 'delegates thread' do | ||||
|         expect(status.thread).not_to be_nil | ||||
|         expect(subject.thread).to eq(status.thread) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| end | ||||
| @@ -15,8 +15,8 @@ RSpec.describe ProcessMentionsService, type: :service do | ||||
|       subject.call(status) | ||||
|     end | ||||
|  | ||||
|     it 'creates a mention' do | ||||
|       expect(remote_user.mentions.where(status: status).count).to eq 1 | ||||
|     it 'does not create a mention' do | ||||
|       expect(remote_user.mentions.where(status: status).count).to eq 0 | ||||
|     end | ||||
|   end | ||||
|  | ||||
|   | ||||
| @@ -27,14 +27,13 @@ RSpec.describe SuspendAccountService, type: :service do | ||||
|         [ | ||||
|           account.statuses, | ||||
|           account.media_attachments, | ||||
|           account.stream_entries, | ||||
|           account.notifications, | ||||
|           account.favourites, | ||||
|           account.active_relationships, | ||||
|           account.passive_relationships, | ||||
|           account.subscriptions | ||||
|         ].map(&:count) | ||||
|       }.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0]) | ||||
|       }.from([1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0]) | ||||
|     end | ||||
|  | ||||
|     it 'sends a delete actor activity to all known inboxes' do | ||||
| @@ -70,14 +69,13 @@ RSpec.describe SuspendAccountService, type: :service do | ||||
|         [ | ||||
|           remote_bob.statuses, | ||||
|           remote_bob.media_attachments, | ||||
|           remote_bob.stream_entries, | ||||
|           remote_bob.notifications, | ||||
|           remote_bob.favourites, | ||||
|           remote_bob.active_relationships, | ||||
|           remote_bob.passive_relationships, | ||||
|           remote_bob.subscriptions | ||||
|         ].map(&:count) | ||||
|       }.from([1, 1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0, 0]) | ||||
|       }.from([1, 1, 1, 1, 1, 1, 1]).to([0, 0, 0, 0, 0, 0, 0]) | ||||
|     end | ||||
|  | ||||
|     it 'sends a reject follow to follwer inboxes' do | ||||
|   | ||||
| @@ -2,10 +2,9 @@ | ||||
| 
 | ||||
| require 'rails_helper' | ||||
| 
 | ||||
| describe 'stream_entries/show.html.haml', without_verify_partial_doubles: true do | ||||
| describe 'statuses/show.html.haml', without_verify_partial_doubles: true do | ||||
|   before do | ||||
|     double(:api_oembed_url => '') | ||||
|     double(:account_stream_entry_url => '') | ||||
|     allow(view).to receive(:show_landing_strip?).and_return(true) | ||||
|     allow(view).to receive(:site_title).and_return('example site') | ||||
|     allow(view).to receive(:site_hostname).and_return('example.com') | ||||
| @@ -23,9 +22,7 @@ describe 'stream_entries/show.html.haml', without_verify_partial_doubles: true d | ||||
|     reply  =  Fabricate(:status, account: bob, thread: status, text: 'Hello Alice') | ||||
| 
 | ||||
|     assign(:status, status) | ||||
|     assign(:stream_entry, status.stream_entry) | ||||
|     assign(:account, alice) | ||||
|     assign(:type, status.stream_entry.activity_type.downcase) | ||||
|     assign(:descendant_threads, []) | ||||
| 
 | ||||
|     render | ||||
| @@ -46,11 +43,9 @@ describe 'stream_entries/show.html.haml', without_verify_partial_doubles: true d | ||||
|     comment =  Fabricate(:status, account: carl, thread: reply, text: 'Hello Bob') | ||||
| 
 | ||||
|     assign(:status, reply) | ||||
|     assign(:stream_entry, reply.stream_entry) | ||||
|     assign(:account, alice) | ||||
|     assign(:type, reply.stream_entry.activity_type.downcase) | ||||
|     assign(:ancestors, reply.stream_entry.activity.ancestors(1, bob)) | ||||
|     assign(:descendant_threads, [{ statuses: reply.stream_entry.activity.descendants(1) }]) | ||||
|     assign(:ancestors, reply.ancestors(1, bob)) | ||||
|     assign(:descendant_threads, [{ statuses: reply.descendants(1) }]) | ||||
| 
 | ||||
|     render | ||||
| 
 | ||||
| @@ -71,9 +66,7 @@ describe 'stream_entries/show.html.haml', without_verify_partial_doubles: true d | ||||
|     status  =  Fabricate(:status, account: alice, text: 'Hello World') | ||||
| 
 | ||||
|     assign(:status, status) | ||||
|     assign(:stream_entry, status.stream_entry) | ||||
|     assign(:account, alice) | ||||
|     assign(:type, status.stream_entry.activity_type.downcase) | ||||
|     assign(:descendant_threads, []) | ||||
| 
 | ||||
|     render | ||||
		Reference in New Issue
	
	Block a user