From f7e35d90db3a08dbb4e4104f513e5817e18659b9 Mon Sep 17 00:00:00 2001 From: Drew DeVault Date: Tue, 4 Apr 2017 20:16:14 -0400 Subject: Remote follow improvements This stores the @username@instance you provide in your session and reuses it the next time you remote follow someone from this instance. --- app/controllers/remote_follow_controller.rb | 3 +++ 1 file changed, 3 insertions(+) (limited to 'app/controllers') diff --git a/app/controllers/remote_follow_controller.rb b/app/controllers/remote_follow_controller.rb index 7d4bfe6ce..1e3f786ec 100644 --- a/app/controllers/remote_follow_controller.rb +++ b/app/controllers/remote_follow_controller.rb @@ -8,6 +8,7 @@ class RemoteFollowController < ApplicationController def new @remote_follow = RemoteFollow.new + @remote_follow.acct = session[:remote_follow] if session.key?(:remote_follow) end def create @@ -22,6 +23,8 @@ class RemoteFollowController < ApplicationController render(:new) && return end + session[:remote_follow] = @remote_follow.acct + redirect_to Addressable::Template.new(redirect_url_link.template).expand(uri: "#{@account.username}@#{Rails.configuration.x.local_domain}").to_s else render :new -- cgit From 6d6a429af8fe4bd92ed497f401676353fdc603e0 Mon Sep 17 00:00:00 2001 From: Eugen Date: Fri, 7 Apr 2017 05:56:56 +0200 Subject: Rewrite Atom generation from stream entries to use Ox instead of Nokogiri (#1124) * Rewrite Atom generation from stream entries to use Ox instead of Nokogiri::Builder StreamEntry is now limited to only statuses, which allows some optimization. Removed extra queries on AccountsController#show. AtomSerializer instead of AtomBuilderHelper used in AccountsController#show, StreamEntriesController#show, StreamEntryRenderer and PubSubHubbub::DistributionWorker PubSubHubbub::DistributionWorker moves n+1 DomainBlock query to PubSubHubbub::DeliveryWorker instead. All Salmon slaps that aren't based on StreamEntry still use AtomBuilderHelper and Nokogiri * All Salmon slaps now use Ox instead of Nokogiri. No touch from status on account --- Gemfile | 1 + Gemfile.lock | 2 + app/controllers/accounts_controller.rb | 3 +- app/controllers/stream_entries_controller.rb | 4 +- app/lib/atom_serializer.rb | 348 ++++++++++++++++++++++++ app/lib/tag_manager.rb | 2 + app/models/stream_entry.rb | 28 +- app/services/after_block_service.rb | 18 +- app/services/authorize_follow_service.rb | 27 +- app/services/block_service.rb | 18 +- app/services/concerns/stream_entry_renderer.rb | 3 +- app/services/favourite_service.rb | 22 +- app/services/follow_service.rb | 44 +-- app/services/reject_follow_service.rb | 27 +- app/services/unblock_service.rb | 18 +- app/services/unfavourite_service.rb | 22 +- app/services/unfollow_service.rb | 21 +- app/views/accounts/show.atom.ruby | 27 -- app/views/stream_entries/show.atom.ruby | 9 - app/workers/pubsubhubbub/delivery_worker.rb | 3 + app/workers/pubsubhubbub/distribution_worker.rb | 8 +- 21 files changed, 393 insertions(+), 262 deletions(-) create mode 100644 app/lib/atom_serializer.rb delete mode 100644 app/views/accounts/show.atom.ruby delete mode 100644 app/views/stream_entries/show.atom.ruby (limited to 'app/controllers') diff --git a/Gemfile b/Gemfile index b5705e9d1..65bd5eb49 100644 --- a/Gemfile +++ b/Gemfile @@ -34,6 +34,7 @@ gem 'doorkeeper' gem 'rabl' gem 'rqrcode' gem 'twitter-text' +gem 'ox' gem 'oj' gem 'hiredis' gem 'redis', '~>3.2', require: ['redis', 'redis/connection/hiredis'] diff --git a/Gemfile.lock b/Gemfile.lock index 408d85ade..f2a199931 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -240,6 +240,7 @@ GEM addressable (~> 2.4) http (~> 2.0) nokogiri (~> 1.6) + ox (2.4.11) paperclip (5.1.0) activemodel (>= 4.2.0) activesupport (>= 4.2.0) @@ -482,6 +483,7 @@ DEPENDENCIES nokogiri oj ostatus2 + ox paperclip (~> 5.1) paperclip-av-transcoder pg diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index dc1aeb5ea..619c04be2 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -16,7 +16,8 @@ class AccountsController < ApplicationController end format.atom do - @entries = @account.stream_entries.order('id desc').where(activity_type: 'Status').where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) + @entries = @account.stream_entries.order('id desc').where(hidden: false).with_includes.paginate_by_max_id(20, params[:max_id], params[:since_id]) + render xml: AtomSerializer.render(AtomSerializer.new.feed(@account, @entries.to_a)) end format.activitystreams2 diff --git a/app/controllers/stream_entries_controller.rb b/app/controllers/stream_entries_controller.rb index de38b3602..469a8c33e 100644 --- a/app/controllers/stream_entries_controller.rb +++ b/app/controllers/stream_entries_controller.rb @@ -19,7 +19,9 @@ class StreamEntriesController < ApplicationController end end - format.atom + format.atom do + render xml: AtomSerializer.render(AtomSerializer.new.entry(@stream_entry, true)) + end end end diff --git a/app/lib/atom_serializer.rb b/app/lib/atom_serializer.rb new file mode 100644 index 000000000..21f485c2d --- /dev/null +++ b/app/lib/atom_serializer.rb @@ -0,0 +1,348 @@ +# frozen_string_literal: true + +class AtomSerializer + include RoutingHelper + + class << self + def render(element) + document = Ox::Document.new(version: '1.0') + document << element + "#{Ox.dump(element)}" + end + end + + def author(account) + author = Ox::Element.new('author') + + uri = TagManager.instance.uri_for(account) + + append_element(author, 'id', uri) + append_element(author, 'activity:object-type', TagManager::TYPES[:person]) + append_element(author, 'uri', uri) + append_element(author, 'name', account.username) + append_element(author, 'email', account.local? ? "#{account.acct}@#{Rails.configuration.x.local_domain}" : account.acct) + append_element(author, 'summary', 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))) + 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))) + append_element(author, 'poco:preferredUsername', account.username) + append_element(author, 'poco:displayName', account.display_name) unless account.display_name.blank? + append_element(author, 'poco:note', Formatter.instance.simplified_format(account).to_str) unless account.note.blank? + 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) + 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 + append_element(feed, 'link', nil, rel: :hub, href: api_push_url) + append_element(feed, 'link', nil, rel: :salmon, href: api_salmon_url(account.id)) + + 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', TagManager.instance.unique_tag(stream_entry.created_at, stream_entry.activity_id, stream_entry.activity_type)) + 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) + append_element(entry, 'activity:object-type', TagManager::TYPES[stream_entry.object_type]) + append_element(entry, 'activity:verb', TagManager::VERBS[stream_entry.verb]) + + entry << object(stream_entry.target) if stream_entry.targeted? + + serialize_status_attributes(entry, stream_entry.status) unless stream_entry.status.nil? + + append_element(entry, 'link', nil, rel: :alternate, type: 'text/html', href: account_stream_entry_url(stream_entry.account, stream_entry)) + 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: TagManager.instance.uri_for(stream_entry.thread), href: TagManager.instance.url_for(stream_entry.thread)) if stream_entry.threaded? + + entry + end + + def object(status) + object = Ox::Element.new('activity:object') + + append_element(object, 'id', 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', TagManager::TYPES[status.object_type]) + append_element(object, 'activity:verb', 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: TagManager.instance.uri_for(status.thread), href: TagManager.instance.url_for(status.thread)) if status.reply? + + 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', TagManager::VERBS[:authorize]) + + object = Ox::Element.new('activity:object') + object << author(follow_request.account) + + append_element(object, 'activity:object-type', TagManager::TYPES[:activity]) + append_element(object, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', TagManager::VERBS[:reject]) + + object = Ox::Element.new('activity:object') + object << author(follow_request.account) + + append_element(object, 'activity:object-type', TagManager::TYPES[:activity]) + append_element(object, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', TagManager::VERBS[:favorite]) + + entry << object(favourite.status) + + append_element(entry, 'thr:in-reply-to', nil, ref: 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', 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', TagManager::TYPES[:activity]) + append_element(entry, 'activity:verb', TagManager::VERBS[:unfavorite]) + + entry << object(favourite.status) + + append_element(entry, 'thr:in-reply-to', nil, ref: 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] = v.to_s } + element << content.to_s unless content.nil? + parent << element + end + + def add_namespaces(parent) + parent['xmlns'] = TagManager::XMLNS + parent['xmlns:thr'] = TagManager::THR_XMLNS + parent['xmlns:activity'] = TagManager::AS_XMLNS + parent['xmlns:poco'] = TagManager::POCO_XMLNS + parent['xmlns:media'] = TagManager::MEDIA_XMLNS + parent['xmlns:ostatus'] = TagManager::OS_XMLNS + parent['xmlns:mastodon'] = TagManager::MTDN_XMLNS + end + + def serialize_status_attributes(entry, status) + append_element(entry, 'summary', status.spoiler_text) unless status.spoiler_text.blank? + append_element(entry, 'content', Formatter.instance.format(status.reblog? ? status.reblog : status).to_str, type: 'html') + + status.mentions.each do |mentioned| + append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': TagManager::TYPES[:person], href: TagManager.instance.uri_for(mentioned.account)) + end + + append_element(entry, 'link', nil, rel: :mentioned, 'ostatus:object-type': TagManager::TYPES[:collection], href: TagManager::COLLECTIONS[:public]) if status.public_visibility? + + status.tags.each do |tag| + append_element(entry, 'category', nil, term: tag.name) + end + + append_element(entry, 'category', nil, term: 'nsfw') if status.sensitive? + + 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, 'mastodon:scope', status.visibility) + end +end diff --git a/app/lib/tag_manager.rb b/app/lib/tag_manager.rb index 2a5e7a409..07b2fb91e 100644 --- a/app/lib/tag_manager.rb +++ b/app/lib/tag_manager.rb @@ -78,6 +78,8 @@ class TagManager case target.object_type when :person account_url(target) + when :note, :comment, :activity + unique_tag(target.created_at, target.id, 'Status') else unique_tag(target.stream_entry.created_at, target.stream_entry.activity_id, target.stream_entry.activity_type) end diff --git a/app/models/stream_entry.rb b/app/models/stream_entry.rb index ae7ae446e..8aff5ae06 100644 --- a/app/models/stream_entry.rb +++ b/app/models/stream_entry.rb @@ -5,25 +5,21 @@ class StreamEntry < ApplicationRecord 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, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, mentions: :account], thread: [:stream_entry, :account]].freeze + STATUS_INCLUDES = [:account, :stream_entry, :media_attachments, :tags, mentions: :account, reblog: [:stream_entry, :account, :media_attachments, :tags, mentions: :account], thread: [:stream_entry, :account]].freeze + default_scope { where(activity_type: 'Status') } scope :with_includes, -> { includes(:account, status: STATUS_INCLUDES) } def object_type - if orphaned? - :activity - else - targeted? ? :activity : activity.object_type - end + orphaned? || targeted? ? :activity : status.object_type end def verb - orphaned? ? :delete : activity.verb + orphaned? ? :delete : status.verb end def targeted? @@ -31,15 +27,15 @@ class StreamEntry < ApplicationRecord end def target - orphaned? ? nil : activity.target + orphaned? ? nil : status.target end def title - orphaned? ? nil : activity.title + orphaned? ? nil : status.title end def content - orphaned? ? nil : activity.content + orphaned? ? nil : status.content end def threaded? @@ -47,20 +43,16 @@ class StreamEntry < ApplicationRecord end def thread - orphaned? ? nil : activity.thread + orphaned? ? nil : status.thread end def mentions - activity.respond_to?(:mentions) ? activity.mentions.map(&:account) : [] - end - - def activity - !new_record? ? send(activity_type.underscore) || super : super + orphaned? ? [] : status.mentions.map(&:account) end private def orphaned? - activity.nil? + status.nil? end end diff --git a/app/services/after_block_service.rb b/app/services/after_block_service.rb index 8c6197f2c..0f478bcb7 100644 --- a/app/services/after_block_service.rb +++ b/app/services/after_block_service.rb @@ -9,20 +9,20 @@ class AfterBlockService < BaseService private def clear_timelines(account, target_account) - mentions_key = FeedManager.instance.key(:mentions, account.id) - home_key = FeedManager.instance.key(:home, account.id) + home_key = FeedManager.instance.key(:home, account.id) - target_account.statuses.select('id').find_each do |status| - redis.zrem(mentions_key, status.id) - redis.zrem(home_key, status.id) + redis.pipelined do + target_account.statuses.select('id').find_each do |status| + redis.zrem(home_key, status.id) + end end end def clear_notifications(account, target_account) - Notification.where(account: account).joins(:follow).where(activity_type: 'Follow', follows: { account_id: target_account.id }).destroy_all - Notification.where(account: account).joins(mention: :status).where(activity_type: 'Mention', statuses: { account_id: target_account.id }).destroy_all - Notification.where(account: account).joins(:favourite).where(activity_type: 'Favourite', favourites: { account_id: target_account.id }).destroy_all - Notification.where(account: account).joins(:status).where(activity_type: 'Status', statuses: { account_id: target_account.id }).destroy_all + Notification.where(account: account).joins(:follow).where(activity_type: 'Follow', follows: { account_id: target_account.id }).delete_all + Notification.where(account: account).joins(mention: :status).where(activity_type: 'Mention', statuses: { account_id: target_account.id }).delete_all + Notification.where(account: account).joins(:favourite).where(activity_type: 'Favourite', favourites: { account_id: target_account.id }).delete_all + Notification.where(account: account).joins(:status).where(activity_type: 'Status', statuses: { account_id: target_account.id }).delete_all end def redis diff --git a/app/services/authorize_follow_service.rb b/app/services/authorize_follow_service.rb index ac465bdb2..97c76bee1 100644 --- a/app/services/authorize_follow_service.rb +++ b/app/services/authorize_follow_service.rb @@ -10,31 +10,6 @@ class AuthorizeFollowService < BaseService private def build_xml(follow_request) - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, Time.now.utc, follow_request.id, 'FollowRequest' - title xml, "#{follow_request.target_account.acct} authorizes follow request by #{follow_request.account.acct}" - - author(xml) do - include_author xml, follow_request.target_account - end - - object_type xml, :activity - verb xml, :authorize - - target(xml) do - author(xml) do - include_author xml, follow_request.account - end - - object_type xml, :activity - verb xml, :request_friend - - target(xml) do - include_author xml, follow_request.target_account - end - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.authorize_follow_request_salmon(follow_request)) end end diff --git a/app/services/block_service.rb b/app/services/block_service.rb index bd914d8be..d59b47afb 100644 --- a/app/services/block_service.rb +++ b/app/services/block_service.rb @@ -18,22 +18,6 @@ class BlockService < BaseService private def build_xml(block) - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, block.created_at, block.id, 'Block' - title xml, "#{block.account.acct} no longer wishes to interact with #{block.target_account.acct}" - - author(xml) do - include_author xml, block.account - end - - object_type xml, :activity - verb xml, :block - - target(xml) do - include_author xml, block.target_account - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.block_salmon(block)) end end diff --git a/app/services/concerns/stream_entry_renderer.rb b/app/services/concerns/stream_entry_renderer.rb index a4255daea..ef176d8a6 100644 --- a/app/services/concerns/stream_entry_renderer.rb +++ b/app/services/concerns/stream_entry_renderer.rb @@ -2,7 +2,6 @@ module StreamEntryRenderer def stream_entry_to_xml(stream_entry) - renderer = StreamEntriesController.renderer.new(method: 'get', http_host: Rails.configuration.x.local_domain, https: Rails.configuration.x.use_https) - renderer.render(:show, assigns: { stream_entry: stream_entry }, formats: [:atom]) + AtomSerializer.render(AtomSerializer.new.entry(stream_entry, true)) end end diff --git a/app/services/favourite_service.rb b/app/services/favourite_service.rb index 5cc96403c..e92aada64 100644 --- a/app/services/favourite_service.rb +++ b/app/services/favourite_service.rb @@ -22,26 +22,6 @@ class FavouriteService < BaseService private def build_xml(favourite) - description = "#{favourite.account.acct} favourited a status by #{favourite.status.account.acct}" - - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, favourite.created_at, favourite.id, 'Favourite' - title xml, description - content xml, description - - author(xml) do - include_author xml, favourite.account - end - - object_type xml, :activity - verb xml, :favorite - in_reply_to xml, TagManager.instance.uri_for(favourite.status), TagManager.instance.url_for(favourite.status) - - target(xml) do - include_target xml, favourite.status - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.favourite_salmon(favourite)) end end diff --git a/app/services/follow_service.rb b/app/services/follow_service.rb index 17b3b2542..844f5282d 100644 --- a/app/services/follow_service.rb +++ b/app/services/follow_service.rb @@ -10,7 +10,7 @@ class FollowService < BaseService target_account = FollowRemoteAccountService.new.call(uri) raise ActiveRecord::RecordNotFound if target_account.nil? || target_account.id == source_account.id || target_account.suspended? - raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) + raise Mastodon::NotPermittedError if target_account.blocking?(source_account) || source_account.blocking?(target_account) if target_account.locked? request_follow(source_account, target_account) @@ -55,48 +55,10 @@ class FollowService < BaseService end def build_follow_request_xml(follow_request) - description = "#{follow_request.account.acct} requested to follow #{follow_request.target_account.acct}" - - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, follow_request.created_at, follow_request.id, 'FollowRequest' - title xml, description - content xml, description - - author(xml) do - include_author xml, follow_request.account - end - - object_type xml, :activity - verb xml, :request_friend - - target(xml) do - include_author xml, follow_request.target_account - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.follow_request_salmon(follow_request)) end def build_follow_xml(follow) - description = "#{follow.account.acct} started following #{follow.target_account.acct}" - - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, follow.created_at, follow.id, 'Follow' - title xml, description - content xml, description - - author(xml) do - include_author xml, follow.account - end - - object_type xml, :activity - verb xml, :follow - - target(xml) do - include_author xml, follow.target_account - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.follow_salmon(follow)) end end diff --git a/app/services/reject_follow_service.rb b/app/services/reject_follow_service.rb index 1b03d62e6..675007938 100644 --- a/app/services/reject_follow_service.rb +++ b/app/services/reject_follow_service.rb @@ -10,31 +10,6 @@ class RejectFollowService < BaseService private def build_xml(follow_request) - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, Time.now.utc, follow_request.id, 'FollowRequest' - title xml, "#{follow_request.target_account.acct} rejects follow request by #{follow_request.account.acct}" - - author(xml) do - include_author xml, follow_request.target_account - end - - object_type xml, :activity - verb xml, :reject - - target(xml) do - author(xml) do - include_author xml, follow_request.account - end - - object_type xml, :activity - verb xml, :request_friend - - target(xml) do - include_author xml, follow_request.target_account - end - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.reject_follow_request_salmon(follow_request)) end end diff --git a/app/services/unblock_service.rb b/app/services/unblock_service.rb index c4f789f74..3a3fd2d8c 100644 --- a/app/services/unblock_service.rb +++ b/app/services/unblock_service.rb @@ -11,22 +11,6 @@ class UnblockService < BaseService private def build_xml(block) - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, Time.now.utc, block.id, 'Block' - title xml, "#{block.account.acct} no longer blocks #{block.target_account.acct}" - - author(xml) do - include_author xml, block.account - end - - object_type xml, :activity - verb xml, :unblock - - target(xml) do - include_author xml, block.target_account - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.unblock_salmon(block)) end end diff --git a/app/services/unfavourite_service.rb b/app/services/unfavourite_service.rb index 5f0ba4254..a32e87bff 100644 --- a/app/services/unfavourite_service.rb +++ b/app/services/unfavourite_service.rb @@ -13,26 +13,6 @@ class UnfavouriteService < BaseService private def build_xml(favourite) - description = "#{favourite.account.acct} no longer favourites a status by #{favourite.status.account.acct}" - - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, Time.now.utc, favourite.id, 'Favourite' - title xml, description - content xml, description - - author(xml) do - include_author xml, favourite.account - end - - object_type xml, :activity - verb xml, :unfavorite - in_reply_to xml, TagManager.instance.uri_for(favourite.status), TagManager.instance.url_for(favourite.status) - - target(xml) do - include_target xml, favourite.status - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.unfavourite_salmon(favourite)) end end diff --git a/app/services/unfollow_service.rb b/app/services/unfollow_service.rb index 3440da364..244c9b529 100644 --- a/app/services/unfollow_service.rb +++ b/app/services/unfollow_service.rb @@ -13,25 +13,6 @@ class UnfollowService < BaseService private def build_xml(follow) - description = "#{follow.account.acct} is no longer following #{follow.target_account.acct}" - - Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - unique_id xml, Time.now.utc, follow.id, 'Follow' - title xml, description - content xml, description - - author(xml) do - include_author xml, follow.account - end - - object_type xml, :activity - verb xml, :unfollow - - target(xml) do - include_author xml, follow.target_account - end - end - end.to_xml + AtomSerializer.render(AtomSerializer.new.unfollow_salmon(follow)) end end diff --git a/app/views/accounts/show.atom.ruby b/app/views/accounts/show.atom.ruby deleted file mode 100644 index e15021178..000000000 --- a/app/views/accounts/show.atom.ruby +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -Nokogiri::XML::Builder.new do |xml| - feed(xml) do - simple_id xml, account_url(@account, format: 'atom') - title xml, @account.display_name - subtitle xml, @account.note - updated_at xml, stream_updated_at - logo xml, full_asset_url(@account.avatar.url(:original)) - - author(xml) do - include_author xml, @account - end - - link_alternate xml, TagManager.instance.url_for(@account) - link_self xml, account_url(@account, format: 'atom') - link_next xml, account_url(@account, format: 'atom', max_id: @entries.last.id) if @entries.size == 20 - link_hub xml, api_push_url - link_salmon xml, api_salmon_url(@account.id) - - @entries.each do |stream_entry| - entry(xml, false) do - include_entry xml, stream_entry - end - end - end -end.to_xml diff --git a/app/views/stream_entries/show.atom.ruby b/app/views/stream_entries/show.atom.ruby deleted file mode 100644 index a298f3269..000000000 --- a/app/views/stream_entries/show.atom.ruby +++ /dev/null @@ -1,9 +0,0 @@ -Nokogiri::XML::Builder.new do |xml| - entry(xml, true) do - author(xml) do - include_author xml, @stream_entry.account - end - - include_entry xml, @stream_entry - end -end.to_xml diff --git a/app/workers/pubsubhubbub/delivery_worker.rb b/app/workers/pubsubhubbub/delivery_worker.rb index 466def3a8..8412be4b7 100644 --- a/app/workers/pubsubhubbub/delivery_worker.rb +++ b/app/workers/pubsubhubbub/delivery_worker.rb @@ -13,6 +13,9 @@ class Pubsubhubbub::DeliveryWorker def perform(subscription_id, payload) subscription = Subscription.find(subscription_id) headers = {} + host = Addressable::URI.parse(subscription.callback_url).host + + return if DomainBlock.blocked?(host) headers['User-Agent'] = 'Mastodon/PubSubHubbub' headers['Link'] = LinkHeader.new([[api_push_url, [%w(rel hub)]], [account_url(subscription.account, format: :atom), [%w(rel self)]]]).to_s diff --git a/app/workers/pubsubhubbub/distribution_worker.rb b/app/workers/pubsubhubbub/distribution_worker.rb index 82ff257af..68ca0f870 100644 --- a/app/workers/pubsubhubbub/distribution_worker.rb +++ b/app/workers/pubsubhubbub/distribution_worker.rb @@ -10,14 +10,10 @@ class Pubsubhubbub::DistributionWorker return if stream_entry.hidden? - account = stream_entry.account - renderer = AccountsController.renderer.new(method: 'get', http_host: Rails.configuration.x.local_domain, https: Rails.configuration.x.use_https) - payload = renderer.render(:show, assigns: { account: account, entries: [stream_entry] }, formats: [:atom]) - # domains = account.followers_domains + account = stream_entry.account + payload = AtomSerializer.render(AtomSerializer.new.feed(account, [stream_entry])) Subscription.where(account: account).active.select('id, callback_url').find_each do |subscription| - host = Addressable::URI.parse(subscription.callback_url).host - next if DomainBlock.blocked?(host) # || !domains.include?(host) Pubsubhubbub::DeliveryWorker.perform_async(subscription.id, payload) end rescue ActiveRecord::RecordNotFound -- cgit From e3a3422a65901c71ec3ff4a2729309c441660d63 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Fri, 7 Apr 2017 12:40:26 +0200 Subject: Allow setting of default language through config Setting of locale in controller extracted to Localized concern, the doorkeeper authorized applications controller moved under custom namespace with inclusion of Localized, which resolves the "it sometimes appears in a different random language" bug --- .env.production.sample | 3 +++ app/controllers/application_controller.rb | 9 ++------- app/controllers/concerns/localized.rb | 19 ++++++++++++++++++ app/controllers/oauth/authorizations_controller.rb | 9 ++------- .../oauth/authorized_applications_controller.rb | 16 +++++++++++++++ .../authorized_applications/index.html.haml | 23 ---------------------- .../oauth/authorized_applications/index.html.haml | 23 ++++++++++++++++++++++ config/routes.rb | 2 +- 8 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 app/controllers/concerns/localized.rb create mode 100644 app/controllers/oauth/authorized_applications_controller.rb delete mode 100644 app/views/doorkeeper/authorized_applications/index.html.haml create mode 100644 app/views/oauth/authorized_applications/index.html.haml (limited to 'app/controllers') diff --git a/.env.production.sample b/.env.production.sample index a7f9eb4bf..a0e963ca6 100644 --- a/.env.production.sample +++ b/.env.production.sample @@ -25,6 +25,9 @@ OTP_SECRET= # Only allow registrations with the following e-mail domains # EMAIL_DOMAIN_WHITELIST=example1.com|example2.de|etc +# Optionally change default language +# DEFAULT_LOCALE=de + # E-mail configuration SMTP_SERVER=smtp.mailgun.org SMTP_PORT=587 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c06142fd4..f00f9c1e3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base + include Localized + # Prevent CSRF attacks by raising an exception. # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception @@ -14,7 +16,6 @@ class ApplicationController < ActionController::Base rescue_from ActionController::InvalidAuthenticityToken, with: :unprocessable_entity before_action :store_current_location, except: :raise_not_found, unless: :devise_controller? - before_action :set_locale before_action :set_user_activity before_action :check_suspension, if: :user_signed_in? @@ -28,12 +29,6 @@ class ApplicationController < ActionController::Base store_location_for(:user, request.url) end - def set_locale - I18n.locale = current_user.try(:locale) || I18n.default_locale - rescue I18n::InvalidLocale - I18n.locale = I18n.default_locale - end - def require_admin! redirect_to root_path unless current_user&.admin? end diff --git a/app/controllers/concerns/localized.rb b/app/controllers/concerns/localized.rb new file mode 100644 index 000000000..b6f868090 --- /dev/null +++ b/app/controllers/concerns/localized.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Localized + extend ActiveSupport::Concern + + included do + before_action :set_locale + end + + def set_locale + I18n.locale = current_user.try(:locale) || default_locale + rescue I18n::InvalidLocale + I18n.locale = default_locale + end + + def default_locale + ENV.fetch('DEFAULT_LOCALE') { I18n.default_locale } + end +end diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index 7c25266d8..cdbfde0fb 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -1,9 +1,10 @@ # frozen_string_literal: true class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController + include Localized + skip_before_action :authenticate_resource_owner! - before_action :set_locale before_action :store_current_location before_action :authenticate_resource_owner! @@ -12,10 +13,4 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController def store_current_location store_location_for(:user, request.url) end - - def set_locale - I18n.locale = current_user.try(:locale) || I18n.default_locale - rescue I18n::InvalidLocale - I18n.locale = I18n.default_locale - end end diff --git a/app/controllers/oauth/authorized_applications_controller.rb b/app/controllers/oauth/authorized_applications_controller.rb new file mode 100644 index 000000000..09dd5d3c4 --- /dev/null +++ b/app/controllers/oauth/authorized_applications_controller.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class Oauth::AuthorizedApplicationsController < Doorkeeper::AuthorizedApplicationsController + include Localized + + skip_before_action :authenticate_resource_owner! + + before_action :store_current_location + before_action :authenticate_resource_owner! + + private + + def store_current_location + store_location_for(:user, request.url) + end +end diff --git a/app/views/doorkeeper/authorized_applications/index.html.haml b/app/views/doorkeeper/authorized_applications/index.html.haml deleted file mode 100644 index d4719881c..000000000 --- a/app/views/doorkeeper/authorized_applications/index.html.haml +++ /dev/null @@ -1,23 +0,0 @@ -- content_for :page_title do - = t('doorkeeper.authorized_applications.index.title') - -%table.table - %thead - %tr - %th= t('doorkeeper.authorized_applications.index.application') - %th= t('doorkeeper.authorized_applications.index.scopes') - %th= t('doorkeeper.authorized_applications.index.created_at') - %th - %tbody - - @applications.each do |application| - %tr - %td - - if application.website.blank? - = application.name - - else - = link_to application.name, application.website - %th= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('
').html_safe - %td= l application.created_at - %td - - unless application.superapp? - = table_link_to 'times', t('doorkeeper.authorized_applications.buttons.revoke'), oauth_authorized_application_path(application), method: :delete, data: { confirm: t('doorkeeper.authorized_applications.confirmations.revoke') } diff --git a/app/views/oauth/authorized_applications/index.html.haml b/app/views/oauth/authorized_applications/index.html.haml new file mode 100644 index 000000000..d4719881c --- /dev/null +++ b/app/views/oauth/authorized_applications/index.html.haml @@ -0,0 +1,23 @@ +- content_for :page_title do + = t('doorkeeper.authorized_applications.index.title') + +%table.table + %thead + %tr + %th= t('doorkeeper.authorized_applications.index.application') + %th= t('doorkeeper.authorized_applications.index.scopes') + %th= t('doorkeeper.authorized_applications.index.created_at') + %th + %tbody + - @applications.each do |application| + %tr + %td + - if application.website.blank? + = application.name + - else + = link_to application.name, application.website + %th= application.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.join('
').html_safe + %td= l application.created_at + %td + - unless application.superapp? + = table_link_to 'times', t('doorkeeper.authorized_applications.buttons.revoke'), oauth_authorized_application_path(application), method: :delete, data: { confirm: t('doorkeeper.authorized_applications.confirmations.revoke') } diff --git a/config/routes.rb b/config/routes.rb index ca77191f7..315ad5da5 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -11,7 +11,7 @@ Rails.application.routes.draw do end use_doorkeeper do - controllers authorizations: 'oauth/authorizations' + controllers authorizations: 'oauth/authorizations', authorized_applications: 'oauth/authorized_applications' end get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta -- cgit