logo

mastofe

My custom branche(s) on git.pleroma.social/pleroma/mastofe
commit: 8b2cad56374b2dbb6e7a445e7917810935c45536
parent: 2d6128672fcadeb29c99551a33648b4880969d22
Author: Eugen Rochko <eugen@zeonfederated.com>
Date:   Fri,  7 Jul 2017 04:02:06 +0200

Refactor JSON templates to be generated with ActiveModelSerializers instead of Rabl (#4090)


Diffstat:

MGemfile1+
MGemfile.lock9+++++++++
Mapp/controllers/api/v1/accounts/credentials_controller.rb4++--
Mapp/controllers/api/v1/accounts/follower_accounts_controller.rb2+-
Mapp/controllers/api/v1/accounts/following_accounts_controller.rb2+-
Mapp/controllers/api/v1/accounts/relationships_controller.rb11+++++------
Mapp/controllers/api/v1/accounts/search_controller.rb3+--
Mapp/controllers/api/v1/accounts/statuses_controller.rb5++---
Mapp/controllers/api/v1/accounts_controller.rb38+++++++++++---------------------------
Mapp/controllers/api/v1/apps_controller.rb1+
Mapp/controllers/api/v1/blocks_controller.rb1+
Mapp/controllers/api/v1/favourites_controller.rb5++---
Mapp/controllers/api/v1/follow_requests_controller.rb1+
Mapp/controllers/api/v1/follows_controller.rb2+-
Mapp/controllers/api/v1/instances_controller.rb4+++-
Mapp/controllers/api/v1/media_controller.rb1+
Mapp/controllers/api/v1/mutes_controller.rb1+
Mapp/controllers/api/v1/notifications_controller.rb7++-----
Mapp/controllers/api/v1/reports_controller.rb3++-
Mapp/controllers/api/v1/search_controller.rb3++-
Mapp/controllers/api/v1/statuses/favourited_by_accounts_controller.rb2+-
Mapp/controllers/api/v1/statuses/favourites_controller.rb4++--
Mapp/controllers/api/v1/statuses/mutes_controller.rb4++--
Mapp/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb2+-
Mapp/controllers/api/v1/statuses/reblogs_controller.rb4++--
Mapp/controllers/api/v1/statuses_controller.rb16+++++++++++-----
Mapp/controllers/api/v1/timelines/home_controller.rb6++----
Mapp/controllers/api/v1/timelines/public_controller.rb6++----
Mapp/controllers/api/v1/timelines/tag_controller.rb6++----
Dapp/lib/inline_rabl_scope.rb17-----------------
Mapp/lib/inline_renderer.rb36++++++++++++++++++++++++++++--------
Aapp/models/context.rb5+++++
Aapp/models/search.rb5+++++
Aapp/presenters/account_relationships_presenter.rb15+++++++++++++++
Aapp/presenters/status_relationships_presenter.rb19+++++++++++++++++++
Aapp/serializers/rest/account_serializer.rb33+++++++++++++++++++++++++++++++++
Aapp/serializers/rest/application_serializer.rb14++++++++++++++
Aapp/serializers/rest/context_serializer.rb6++++++
Aapp/serializers/rest/instance_serializer.rb30++++++++++++++++++++++++++++++
Aapp/serializers/rest/media_attachment_serializer.rb24++++++++++++++++++++++++
Aapp/serializers/rest/notification_serializer.rb12++++++++++++
Aapp/serializers/rest/preview_card_serializer.rb14++++++++++++++
Aapp/serializers/rest/relationship_serializer.rb30++++++++++++++++++++++++++++++
Aapp/serializers/rest/report_serializer.rb5+++++
Aapp/serializers/rest/search_serializer.rb12++++++++++++
Aapp/serializers/rest/status_serializer.rb93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mapp/services/fan_out_on_write_service.rb2+-
Mapp/services/notify_service.rb2+-
Dapp/views/api/v1/accounts/index.rabl2--
Dapp/views/api/v1/accounts/relationship.rabl9---------
Dapp/views/api/v1/accounts/relationships/index.rabl2--
Dapp/views/api/v1/accounts/show.rabl12------------
Dapp/views/api/v1/accounts/statuses/index.rabl2--
Dapp/views/api/v1/apps/create.rabl4----
Dapp/views/api/v1/apps/show.rabl3---
Dapp/views/api/v1/blocks/index.rabl2--
Dapp/views/api/v1/favourites/index.rabl2--
Dapp/views/api/v1/follow_requests/index.rabl2--
Dapp/views/api/v1/follows/show.rabl2--
Dapp/views/api/v1/instances/show.rabl10----------
Dapp/views/api/v1/media/create.rabl7-------
Dapp/views/api/v1/mutes/index.rabl2--
Dapp/views/api/v1/notifications/index.rabl2--
Dapp/views/api/v1/notifications/show.rabl11-----------
Dapp/views/api/v1/reports/index.rabl2--
Dapp/views/api/v1/reports/show.rabl2--
Dapp/views/api/v1/search/index.rabl13-------------
Dapp/views/api/v1/statuses/_media.rabl6------
Dapp/views/api/v1/statuses/_mention.rabl4----
Dapp/views/api/v1/statuses/_show.rabl29-----------------------------
Dapp/views/api/v1/statuses/_tags.rabl2--
Dapp/views/api/v1/statuses/accounts.rabl2--
Dapp/views/api/v1/statuses/card.rabl7-------
Dapp/views/api/v1/statuses/context.rabl9---------
Dapp/views/api/v1/statuses/index.rabl2--
Dapp/views/api/v1/statuses/show.rabl15---------------
Dapp/views/api/v1/timelines/show.rabl2--
Mapp/views/home/initial_state.json.rabl4++--
Mapp/workers/push_update_worker.rb2+-
Dspec/lib/inline_rabl_scope_spec.rb23-----------------------
80 files changed, 425 insertions(+), 301 deletions(-)

diff --git a/Gemfile b/Gemfile @@ -18,6 +18,7 @@ gem 'aws-sdk', '~> 2.9' gem 'paperclip', '~> 5.1' gem 'paperclip-av-transcoder', '~> 0.6' +gem 'active_model_serializers', '~> 0.10' gem 'addressable', '~> 2.5' gem 'bootsnap' gem 'browser' diff --git a/Gemfile.lock b/Gemfile.lock @@ -24,6 +24,11 @@ GEM erubi (~> 1.4) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.3) + active_model_serializers (0.10.6) + actionpack (>= 4.1, < 6) + activemodel (>= 4.1, < 6) + case_transform (>= 0.2) + jsonapi-renderer (>= 0.1.1.beta1, < 0.2) active_record_query_trace (1.5.4) activejob (5.1.2) activesupport (= 5.1.2) @@ -101,6 +106,8 @@ GEM rack (>= 1.0.0) rack-test (>= 0.5.4) xpath (~> 2.0) + case_transform (0.2) + activesupport chunky_png (1.3.8) cld3 (3.1.3) ffi (>= 1.1.0, < 1.10.0) @@ -200,6 +207,7 @@ GEM terminal-table (>= 1.5.1) jmespath (1.3.1) json (2.1.0) + jsonapi-renderer (0.1.2) kaminari (1.0.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.0.1) @@ -476,6 +484,7 @@ PLATFORMS ruby DEPENDENCIES + active_model_serializers (~> 0.10) active_record_query_trace (~> 1.5) addressable (~> 2.5) annotate (~> 2.7) diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -6,13 +6,13 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController def show @account = current_account - render 'api/v1/accounts/show' + render json: @account, serializer: REST::AccountSerializer end def update current_account.update!(account_params) @account = current_account - render 'api/v1/accounts/show' + render json: @account, serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -9,7 +9,7 @@ class Api::V1::Accounts::FollowerAccountsController < Api::BaseController def index @accounts = load_accounts - render 'api/v1/accounts/index' + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -9,7 +9,7 @@ class Api::V1::Accounts::FollowingAccountsController < Api::BaseController def index @accounts = load_accounts - render 'api/v1/accounts/index' + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb @@ -8,16 +8,15 @@ class Api::V1::Accounts::RelationshipsController < Api::BaseController def index @accounts = Account.where(id: account_ids).select('id') - @following = Account.following_map(account_ids, current_user.account_id) - @followed_by = Account.followed_by_map(account_ids, current_user.account_id) - @blocking = Account.blocking_map(account_ids, current_user.account_id) - @muting = Account.muting_map(account_ids, current_user.account_id) - @requested = Account.requested_map(account_ids, current_user.account_id) - @domain_blocking = Account.domain_blocking_map(account_ids, current_user.account_id) + render json: @accounts, each_serializer: REST::RelationshipSerializer, relationships: relationships end private + def relationships + AccountRelationshipsPresenter.new(@accounts, current_user.account_id) + end + def account_ids @_account_ids ||= Array(params[:id]).map(&:to_i) end diff --git a/app/controllers/api/v1/accounts/search_controller.rb b/app/controllers/api/v1/accounts/search_controller.rb @@ -8,8 +8,7 @@ class Api::V1::Accounts::SearchController < Api::BaseController def show @accounts = account_search - - render 'api/v1/accounts/index' + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -9,6 +9,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController def index @statuses = load_statuses + render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private @@ -18,9 +19,7 @@ class Api::V1::Accounts::StatusesController < Api::BaseController end def load_statuses - cached_account_statuses.tap do |statuses| - set_maps(statuses) - end + cached_account_statuses end def cached_account_statuses diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb @@ -8,49 +8,38 @@ class Api::V1::AccountsController < Api::BaseController respond_to :json - def show; end + def show + render json: @account, serializer: REST::AccountSerializer + end def follow FollowService.new.call(current_user.account, @account.acct) - set_relationship - render :relationship + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end def block BlockService.new.call(current_user.account, @account) - - @following = { @account.id => false } - @followed_by = { @account.id => false } - @blocking = { @account.id => true } - @requested = { @account.id => false } - @muting = { @account.id => current_account.muting?(@account.id) } - @domain_blocking = { @account.id => current_account.domain_blocking?(@account.domain) } - - render :relationship + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end def mute MuteService.new.call(current_user.account, @account) - set_relationship - render :relationship + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end def unfollow UnfollowService.new.call(current_user.account, @account) - set_relationship - render :relationship + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end def unblock UnblockService.new.call(current_user.account, @account) - set_relationship - render :relationship + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end def unmute UnmuteService.new.call(current_user.account, @account) - set_relationship - render :relationship + render json: @account, serializer: REST::RelationshipSerializer, relationships: relationships end private @@ -59,12 +48,7 @@ class Api::V1::AccountsController < Api::BaseController @account = Account.find(params[:id]) end - def set_relationship - @following = Account.following_map([@account.id], current_user.account_id) - @followed_by = Account.followed_by_map([@account.id], current_user.account_id) - @blocking = Account.blocking_map([@account.id], current_user.account_id) - @muting = Account.muting_map([@account.id], current_user.account_id) - @requested = Account.requested_map([@account.id], current_user.account_id) - @domain_blocking = Account.domain_blocking_map([@account.id], current_user.account_id) + def relationships + AccountRelationshipsPresenter.new([@account.id], current_user.account_id) end end diff --git a/app/controllers/api/v1/apps_controller.rb b/app/controllers/api/v1/apps_controller.rb @@ -5,6 +5,7 @@ class Api::V1::AppsController < Api::BaseController def create @app = Doorkeeper::Application.create!(application_options) + render json: @app, serializer: REST::ApplicationSerializer end private diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb @@ -9,6 +9,7 @@ class Api::V1::BlocksController < Api::BaseController def index @accounts = load_accounts + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb @@ -9,14 +9,13 @@ class Api::V1::FavouritesController < Api::BaseController def index @statuses = load_statuses + render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private def load_statuses - cached_favourites.tap do |statuses| - set_maps(statuses) - end + cached_favourites end def cached_favourites diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb @@ -7,6 +7,7 @@ class Api::V1::FollowRequestsController < Api::BaseController def index @accounts = load_accounts + render json: @accounts, each_serializer: REST::AccountSerializer end def authorize diff --git a/app/controllers/api/v1/follows_controller.rb b/app/controllers/api/v1/follows_controller.rb @@ -10,7 +10,7 @@ class Api::V1::FollowsController < Api::BaseController raise ActiveRecord::RecordNotFound if follow_params[:uri].blank? @account = FollowService.new.call(current_user.account, target_uri).try(:target_account) - render :show + render json: @account, serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/instances_controller.rb b/app/controllers/api/v1/instances_controller.rb @@ -3,5 +3,7 @@ class Api::V1::InstancesController < Api::BaseController respond_to :json - def show; end + def show + render json: {}, serializer: REST::InstanceSerializer + end end diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb @@ -11,6 +11,7 @@ class Api::V1::MediaController < Api::BaseController def create @media = current_account.media_attachments.create!(file: media_params[:file]) + render json: @media, serializer: REST::MediaAttachmentSerializer rescue Paperclip::Errors::NotIdentifiedByImageMagickError render json: file_type_error, status: 422 rescue Paperclip::Error diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb @@ -9,6 +9,7 @@ class Api::V1::MutesController < Api::BaseController def index @accounts = load_accounts + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb @@ -11,11 +11,12 @@ class Api::V1::NotificationsController < Api::BaseController def index @notifications = load_notifications - set_maps_for_notification_target_statuses + render json: @notifications, each_serializer: REST::NotificationSerializer, relationships: StatusRelationshipsPresenter.new(target_statuses_from_notifications, current_user&.account_id) end def show @notification = current_account.notifications.find(params[:id]) + render json: @notification, serializer: REST::NotificationSerializer end def clear @@ -46,10 +47,6 @@ class Api::V1::NotificationsController < Api::BaseController current_account.notifications.browserable(exclude_types) end - def set_maps_for_notification_target_statuses - set_maps target_statuses_from_notifications - end - def target_statuses_from_notifications @notifications.reject { |notification| notification.target_status.nil? }.map(&:target_status) end diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb @@ -9,6 +9,7 @@ class Api::V1::ReportsController < Api::BaseController def index @reports = current_account.reports + render json: @reports, each_serializer: REST::ReportSerializer end def create @@ -20,7 +21,7 @@ class Api::V1::ReportsController < Api::BaseController User.admins.includes(:account).each { |u| AdminMailer.new_report(u.account, @report).deliver_later } - render :show + render json: @report, serializer: REST::ReportSerializer end private diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb @@ -6,7 +6,8 @@ class Api::V1::SearchController < Api::BaseController respond_to :json def index - @search = OpenStruct.new(search_results) + @search = Search.new(search_results) + render json: @search, serializer: REST::SearchSerializer end private diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb @@ -11,7 +11,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController def index @accounts = load_accounts - render 'api/v1/statuses/accounts' + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/statuses/favourites_controller.rb b/app/controllers/api/v1/statuses/favourites_controller.rb @@ -10,7 +10,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController def create @status = favourited_status - render 'api/v1/statuses/show' + render json: @status, serializer: REST::StatusSerializer end def destroy @@ -19,7 +19,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController UnfavouriteWorker.perform_async(current_user.account_id, @status.id) - render 'api/v1/statuses/show' + render json: @status, serializer: REST::StatusSerializer end private diff --git a/app/controllers/api/v1/statuses/mutes_controller.rb b/app/controllers/api/v1/statuses/mutes_controller.rb @@ -14,14 +14,14 @@ class Api::V1::Statuses::MutesController < Api::BaseController current_account.mute_conversation!(@conversation) @mutes_map = { @conversation.id => true } - render 'api/v1/statuses/show' + render json: @status, serializer: REST::StatusSerializer end def destroy current_account.unmute_conversation!(@conversation) @mutes_map = { @conversation.id => false } - render 'api/v1/statuses/show' + render json: @status, serializer: REST::StatusSerializer end private diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -11,7 +11,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController def index @accounts = load_accounts - render 'api/v1/statuses/accounts' + render json: @accounts, each_serializer: REST::AccountSerializer end private diff --git a/app/controllers/api/v1/statuses/reblogs_controller.rb b/app/controllers/api/v1/statuses/reblogs_controller.rb @@ -10,7 +10,7 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController def create @status = ReblogService.new.call(current_user.account, status_for_reblog) - render 'api/v1/statuses/show' + render json: @status, serializer: REST::StatusSerializer end def destroy @@ -20,7 +20,7 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController authorize status_for_destroy, :unreblog? RemovalWorker.perform_async(status_for_destroy.id) - render 'api/v1/statuses/show' + render json: @status, serializer: REST::StatusSerializer end private diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb @@ -13,6 +13,7 @@ class Api::V1::StatusesController < Api::BaseController def show cached = Rails.cache.read(@status.cache_key) @status = cached unless cached.nil? + render json: @status, serializer: REST::StatusSerializer end def context @@ -21,15 +22,20 @@ class Api::V1::StatusesController < Api::BaseController loaded_ancestors = cache_collection(ancestors_results, Status) loaded_descendants = cache_collection(descendants_results, Status) - @context = OpenStruct.new(ancestors: loaded_ancestors, descendants: loaded_descendants) - statuses = [@status] + @context[:ancestors] + @context[:descendants] + @context = Context.new(ancestors: loaded_ancestors, descendants: loaded_descendants) + statuses = [@status] + @context.ancestors + @context.descendants - set_maps(statuses) + render json: @context, serializer: REST::ContextSerializer, relationships: StatusRelationshipsPresenter.new(statuses, current_user&.account_id) end def card @card = PreviewCard.find_by(status: @status) - render_empty if @card.nil? + + if @card.nil? + render_empty + else + render json: @card, serializer: REST::PreviewCardSerializer + end end def create @@ -43,7 +49,7 @@ class Api::V1::StatusesController < Api::BaseController application: doorkeeper_token.application, idempotency: request.headers['Idempotency-Key']) - render :show + render json: @status, serializer: REST::StatusSerializer end def destroy diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb @@ -9,15 +9,13 @@ class Api::V1::Timelines::HomeController < Api::BaseController def show @statuses = load_statuses - render 'api/v1/timelines/show' + render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private def load_statuses - cached_home_statuses.tap do |statuses| - set_maps(statuses) - end + cached_home_statuses end def cached_home_statuses diff --git a/app/controllers/api/v1/timelines/public_controller.rb b/app/controllers/api/v1/timelines/public_controller.rb @@ -7,15 +7,13 @@ class Api::V1::Timelines::PublicController < Api::BaseController def show @statuses = load_statuses - render 'api/v1/timelines/show' + render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private def load_statuses - cached_public_statuses.tap do |statuses| - set_maps(statuses) - end + cached_public_statuses end def cached_public_statuses diff --git a/app/controllers/api/v1/timelines/tag_controller.rb b/app/controllers/api/v1/timelines/tag_controller.rb @@ -8,7 +8,7 @@ class Api::V1::Timelines::TagController < Api::BaseController def show @statuses = load_statuses - render 'api/v1/timelines/show' + render json: @statuses, each_serializer: REST::StatusSerializer, relationships: StatusRelationshipsPresenter.new(@statuses, current_user&.account_id) end private @@ -18,9 +18,7 @@ class Api::V1::Timelines::TagController < Api::BaseController end def load_statuses - cached_tagged_statuses.tap do |statuses| - set_maps(statuses) - end + cached_tagged_statuses end def cached_tagged_statuses diff --git a/app/lib/inline_rabl_scope.rb b/app/lib/inline_rabl_scope.rb @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -class InlineRablScope - include RoutingHelper - - def initialize(account) - @account = account - end - - def current_user - @account.try(:user) - end - - def current_account - @account - end -end diff --git a/app/lib/inline_renderer.rb b/app/lib/inline_renderer.rb @@ -1,13 +1,33 @@ # frozen_string_literal: true class InlineRenderer - def self.render(status, current_account, template) - Rabl::Renderer.new( - template, - status, - view_path: 'app/views', - format: :json, - scope: InlineRablScope.new(current_account) - ).render + def initialize(object, current_account, template) + @object = object + @current_account = current_account + @template = template + end + + def render + case @template + when :status + serializer = REST::StatusSerializer + when :notification + serializer = REST::NotificationSerializer + else + return + end + + serializable_resource = ActiveModelSerializers::SerializableResource.new(@object, serializer: serializer, scope: current_user, scope_name: :current_user) + serializable_resource.as_json + end + + def self.render(object, current_account, template) + new(object, current_account, template).render + end + + private + + def current_user + @current_account&.user end end diff --git a/app/models/context.rb b/app/models/context.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Context < ActiveModelSerializers::Model + attributes :ancestors, :descendants +end diff --git a/app/models/search.rb b/app/models/search.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Search < ActiveModelSerializers::Model + attributes :accounts, :statuses, :hashtags +end diff --git a/app/presenters/account_relationships_presenter.rb b/app/presenters/account_relationships_presenter.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class AccountRelationshipsPresenter + attr_reader :following, :followed_by, :blocking, + :muting, :requested, :domain_blocking + + def initialize(account_ids, current_account_id) + @following = Account.following_map(account_ids, current_account_id) + @followed_by = Account.followed_by_map(account_ids, current_account_id) + @blocking = Account.blocking_map(account_ids, current_account_id) + @muting = Account.muting_map(account_ids, current_account_id) + @requested = Account.requested_map(account_ids, current_account_id) + @domain_blocking = Account.domain_blocking_map(account_ids, current_account_id) + end +end diff --git a/app/presenters/status_relationships_presenter.rb b/app/presenters/status_relationships_presenter.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class StatusRelationshipsPresenter + attr_reader :reblogs_map, :favourites_map, :mutes_map + + def initialize(statuses, current_account_id = nil) + if current_account_id.nil? + @reblogs_map = {} + @favourites_map = {} + @mutes_map = {} + else + status_ids = statuses.compact.flat_map { |s| [s.id, s.reblog_of_id] }.uniq + conversation_ids = statuses.compact.map(&:conversation_id).compact.uniq + @reblogs_map = Status.reblogs_map(status_ids, current_account_id) + @favourites_map = Status.favourites_map(status_ids, current_account_id) + @mutes_map = Status.mutes_map(conversation_ids, current_account_id) + end + end +end diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +class REST::AccountSerializer < ActiveModel::Serializer + include RoutingHelper + + attributes :id, :username, :acct, :display_name, :locked, :created_at, + :note, :url, :avatar, :avatar_static, :header, :header_static, + :followers_count, :following_count, :statuses_count + + def note + Formatter.instance.simplified_format(object) + end + + def url + TagManager.instance.url_for(object) + end + + def avatar + full_asset_url(object.avatar_original_url) + end + + def avatar_static + full_asset_url(object.avatar_static_url) + end + + def header + full_asset_url(object.header_original_url) + end + + def header_static + full_asset_url(object.header_static_url) + end +end diff --git a/app/serializers/rest/application_serializer.rb b/app/serializers/rest/application_serializer.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class REST::ApplicationSerializer < ActiveModel::Serializer + attributes :id, :name, :website, :redirect_uri, + :client_id, :client_secret + + def client_id + object.uid + end + + def client_secret + object.secret + end +end diff --git a/app/serializers/rest/context_serializer.rb b/app/serializers/rest/context_serializer.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +class REST::ContextSerializer < ActiveModel::Serializer + has_many :ancestors, serializer: REST::StatusSerializer + has_many :descendants, serializer: REST::StatusSerializer +end diff --git a/app/serializers/rest/instance_serializer.rb b/app/serializers/rest/instance_serializer.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class REST::InstanceSerializer < ActiveModel::Serializer + attributes :uri, :title, :description, :email, + :version, :urls + + def uri + Rails.configuration.x.local_domain + end + + def title + Setting.site_title + end + + def description + Setting.site_description + end + + def email + Setting.site_contact_email + end + + def version + Mastodon::Version.to_s + end + + def urls + { streaming_api: Rails.configuration.x.streaming_api_base_url } + end +end diff --git a/app/serializers/rest/media_attachment_serializer.rb b/app/serializers/rest/media_attachment_serializer.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +class REST::MediaAttachmentSerializer < ActiveModel::Serializer + include RoutingHelper + + attributes :id, :type, :url, :preview_url, + :remote_url, :text_url, :meta + + def url + full_asset_url(object.file.url(:original)) + end + + def preview_url + full_asset_url(object.file.url(:small)) + end + + def text_url + medium_url(object.id) + end + + def meta + object.file.meta + end +end diff --git a/app/serializers/rest/notification_serializer.rb b/app/serializers/rest/notification_serializer.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class REST::NotificationSerializer < ActiveModel::Serializer + attributes :id, :type, :created_at + + belongs_to :from_account, key: :account, serializer: REST::AccountSerializer + belongs_to :status, if: :status_type?, serializer: REST::StatusSerializer + + def status_type? + [:favourite, :reblog, :mention].include?(object.type) + end +end diff --git a/app/serializers/rest/preview_card_serializer.rb b/app/serializers/rest/preview_card_serializer.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class REST::PreviewCardSerializer < ActiveModel::Serializer + include RoutingHelper + + attributes :url, :title, :description, :type, + :author_name, :author_url, :provider_name, + :provider_url, :html, :width, :height, + :image + + def image + object.image? ? full_asset_url(object.image.url(:original)) : nil + end +end diff --git a/app/serializers/rest/relationship_serializer.rb b/app/serializers/rest/relationship_serializer.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +class REST::RelationshipSerializer < ActiveModel::Serializer + attributes :id, :following, :followed_by, :blocking, + :muting, :requested, :domain_blocking + + def following + instance_options[:relationships].following[object.id] || false + end + + def followed_by + instance_options[:relationships].followed_by[object.id] || false + end + + def blocking + instance_options[:relationships].blocking[object.id] || false + end + + def muting + instance_options[:relationships].muting[object.id] || false + end + + def requested + instance_options[:relationships].requested[object.id] || false + end + + def domain_blocking + instance_options[:relationships].domain_blocking[object.id] || false + end +end diff --git a/app/serializers/rest/report_serializer.rb b/app/serializers/rest/report_serializer.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class REST::ReportSerializer < ActiveModel::Serializer + attributes :id, :action_taken +end diff --git a/app/serializers/rest/search_serializer.rb b/app/serializers/rest/search_serializer.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class REST::SearchSerializer < ActiveModel::Serializer + attributes :hashtags + + has_many :accounts, serializer: REST::AccountSerializer + has_many :statuses, serializer: REST::StatusSerializer + + def hashtags + object.hashtags.map(&:name) + end +end diff --git a/app/serializers/rest/status_serializer.rb b/app/serializers/rest/status_serializer.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +class REST::StatusSerializer < ActiveModel::Serializer + attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id, + :sensitive, :spoiler_text, :visibility, :language, + :uri, :content, :url, :reblogs_count, :favourites_count + + attribute :favourited, if: :current_user? + attribute :reblogged, if: :current_user? + attribute :muted, if: :current_user? + + belongs_to :reblog, serializer: REST::StatusSerializer + belongs_to :application + belongs_to :account, serializer: REST::AccountSerializer + + has_many :media_attachments, serializer: REST::MediaAttachmentSerializer + has_many :mentions + has_many :tags + + def current_user? + !current_user.nil? + end + + def uri + TagManager.instance.uri_for(object) + end + + def content + Formatter.instance.format(object) + end + + def url + TagManager.instance.url_for(object) + end + + def favourited + if instance_options && instance_options[:relationships] + instance_options[:relationships].favourites_map[object.id] || false + else + current_user.account.favourited?(object) + end + end + + def reblogged + if instance_options && instance_options[:relationships] + instance_options[:relationships].reblogs_map[object.id] || false + else + current_user.account.reblogged?(object) + end + end + + def muted + if instance_options && instance_options[:relationships] + instance_options[:relationships].mutes_map[object.conversation_id] || false + else + current_user.account.muting_conversation?(object.conversation) + end + end + + class ApplicationSerializer < ActiveModel::Serializer + attributes :name, :website + end + + class MentionSerializer < ActiveModel::Serializer + attributes :id, :username, :url, :acct + + def id + object.account_id + end + + def username + object.account_username + end + + def url + TagManager.instance.url_for(object.account) + end + + def acct + object.account_acct + end + end + + class TagSerializer < ActiveModel::Serializer + include RoutingHelper + + attributes :name, :url + + def url + tag_url(object) + end + end +end diff --git a/app/services/fan_out_on_write_service.rb b/app/services/fan_out_on_write_service.rb @@ -54,7 +54,7 @@ class FanOutOnWriteService < BaseService end def render_anonymous_payload(status) - @payload = InlineRenderer.render(status, nil, 'api/v1/statuses/show') + @payload = InlineRenderer.render(status, nil, :status) @payload = Oj.dump(event: :update, payload: @payload) end diff --git a/app/services/notify_service.rb b/app/services/notify_service.rb @@ -60,7 +60,7 @@ class NotifyService < BaseService def create_notification @notification.save! return unless @notification.browserable? - Redis.current.publish("timeline:#{@recipient.id}", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, 'api/v1/notifications/show'))) + Redis.current.publish("timeline:#{@recipient.id}", Oj.dump(event: :notification, payload: InlineRenderer.render(@notification, @recipient, :notification))) end def send_email diff --git a/app/views/api/v1/accounts/index.rabl b/app/views/api/v1/accounts/index.rabl @@ -1,2 +0,0 @@ -collection @accounts -extends 'api/v1/accounts/show' diff --git a/app/views/api/v1/accounts/relationship.rabl b/app/views/api/v1/accounts/relationship.rabl @@ -1,9 +0,0 @@ -object @account - -attribute :id -node(:following) { |account| @following[account.id] || false } -node(:followed_by) { |account| @followed_by[account.id] || false } -node(:blocking) { |account| @blocking[account.id] || false } -node(:muting) { |account| @muting[account.id] || false } -node(:requested) { |account| @requested[account.id] || false } -node(:domain_blocking) { |account| @domain_blocking[account.id] || false } diff --git a/app/views/api/v1/accounts/relationships/index.rabl b/app/views/api/v1/accounts/relationships/index.rabl @@ -1,2 +0,0 @@ -collection @accounts -extends 'api/v1/accounts/relationship' diff --git a/app/views/api/v1/accounts/show.rabl b/app/views/api/v1/accounts/show.rabl @@ -1,12 +0,0 @@ -object @account - -attributes :id, :username, :acct, :display_name, :locked, :created_at - -node(:note) { |account| Formatter.instance.simplified_format(account) } -node(:url) { |account| TagManager.instance.url_for(account) } -node(:avatar) { |account| full_asset_url(account.avatar_original_url) } -node(:avatar_static) { |account| full_asset_url(account.avatar_static_url) } -node(:header) { |account| full_asset_url(account.header_original_url) } -node(:header_static) { |account| full_asset_url(account.header_static_url) } - -attributes :followers_count, :following_count, :statuses_count diff --git a/app/views/api/v1/accounts/statuses/index.rabl b/app/views/api/v1/accounts/statuses/index.rabl @@ -1,2 +0,0 @@ -collection @statuses -extends 'api/v1/statuses/show' diff --git a/app/views/api/v1/apps/create.rabl b/app/views/api/v1/apps/create.rabl @@ -1,4 +0,0 @@ -object @app -attributes :id, :redirect_uri -node(:client_id) { |app| app.uid } -node(:client_secret) { |app| app.secret } diff --git a/app/views/api/v1/apps/show.rabl b/app/views/api/v1/apps/show.rabl @@ -1,3 +0,0 @@ -object @application - -attributes :name, :website diff --git a/app/views/api/v1/blocks/index.rabl b/app/views/api/v1/blocks/index.rabl @@ -1,2 +0,0 @@ -collection @accounts -extends 'api/v1/accounts/show' diff --git a/app/views/api/v1/favourites/index.rabl b/app/views/api/v1/favourites/index.rabl @@ -1,2 +0,0 @@ -collection @statuses -extends 'api/v1/statuses/show' diff --git a/app/views/api/v1/follow_requests/index.rabl b/app/views/api/v1/follow_requests/index.rabl @@ -1,2 +0,0 @@ -collection @accounts -extends 'api/v1/accounts/show' diff --git a/app/views/api/v1/follows/show.rabl b/app/views/api/v1/follows/show.rabl @@ -1,2 +0,0 @@ -object @account -extends('api/v1/accounts/show') diff --git a/app/views/api/v1/instances/show.rabl b/app/views/api/v1/instances/show.rabl @@ -1,10 +0,0 @@ -object false - -node(:uri) { site_hostname } -node(:title) { Setting.site_title } -node(:description) { Setting.site_description } -node(:email) { Setting.site_contact_email } -node(:version) { Mastodon::Version.to_s } -node :urls do - { :streaming_api => Rails.configuration.x.streaming_api_base_url } -end diff --git a/app/views/api/v1/media/create.rabl b/app/views/api/v1/media/create.rabl @@ -1,7 +0,0 @@ -object @media -attribute :id, :type - -node(:url) { |media| full_asset_url(media.file.url(:original)) } -node(:preview_url) { |media| full_asset_url(media.file.url(:small)) } -node(:text_url) { |media| medium_url(media) } -node(:meta) { |media| media.file.meta } diff --git a/app/views/api/v1/mutes/index.rabl b/app/views/api/v1/mutes/index.rabl @@ -1,2 +0,0 @@ -collection @accounts -extends 'api/v1/accounts/show' diff --git a/app/views/api/v1/notifications/index.rabl b/app/views/api/v1/notifications/index.rabl @@ -1,2 +0,0 @@ -collection @notifications -extends 'api/v1/notifications/show' diff --git a/app/views/api/v1/notifications/show.rabl b/app/views/api/v1/notifications/show.rabl @@ -1,11 +0,0 @@ -object @notification - -attributes :id, :type, :created_at - -child from_account: :account do - extends 'api/v1/accounts/show' -end - -node(:status, if: lambda { |n| [:favourite, :reblog, :mention].include?(n.type) }) do |n| - partial 'api/v1/statuses/show', object: n.target_status -end diff --git a/app/views/api/v1/reports/index.rabl b/app/views/api/v1/reports/index.rabl @@ -1,2 +0,0 @@ -collection @reports -extends 'api/v1/reports/show' diff --git a/app/views/api/v1/reports/show.rabl b/app/views/api/v1/reports/show.rabl @@ -1,2 +0,0 @@ -object @report -attributes :id, :action_taken diff --git a/app/views/api/v1/search/index.rabl b/app/views/api/v1/search/index.rabl @@ -1,13 +0,0 @@ -object @search - -child :accounts, object_root: false do - extends 'api/v1/accounts/show' -end - -node(:hashtags) do |search| - search.hashtags.map(&:name) -end - -child :statuses, object_root: false do - extends 'api/v1/statuses/show' -end diff --git a/app/views/api/v1/statuses/_media.rabl b/app/views/api/v1/statuses/_media.rabl @@ -1,6 +0,0 @@ -attributes :id, :remote_url, :type - -node(:url) { |media| full_asset_url(media.file.url(:original)) } -node(:preview_url) { |media| full_asset_url(media.file.url(:small)) } -node(:text_url) { |media| media.local? ? medium_url(media) : nil } -node(:meta) { |media| media.file.meta } diff --git a/app/views/api/v1/statuses/_mention.rabl b/app/views/api/v1/statuses/_mention.rabl @@ -1,4 +0,0 @@ -node(:url) { |mention| TagManager.instance.url_for(mention.account) } -node(:acct) { |mention| mention.account_acct } -node(:id) { |mention| mention.account_id } -node(:username) { |mention| mention.account_username } diff --git a/app/views/api/v1/statuses/_show.rabl b/app/views/api/v1/statuses/_show.rabl @@ -1,29 +0,0 @@ -attributes :id, :created_at, :in_reply_to_id, - :in_reply_to_account_id, :sensitive, - :spoiler_text, :visibility, :language - -node(:uri) { |status| TagManager.instance.uri_for(status) } -node(:content) { |status| Formatter.instance.format(status) } -node(:url) { |status| TagManager.instance.url_for(status) } -node(:reblogs_count) { |status| defined?(@reblogs_counts_map) ? (@reblogs_counts_map[status.id] || 0) : status.reblogs_count } -node(:favourites_count) { |status| defined?(@favourites_counts_map) ? (@favourites_counts_map[status.id] || 0) : status.favourites_count } - -child :application do - extends 'api/v1/apps/show' -end - -child :account do - extends 'api/v1/accounts/show' -end - -child :media_attachments, object_root: false do - extends 'api/v1/statuses/_media' -end - -child :mentions, object_root: false do - extends 'api/v1/statuses/_mention' -end - -child :tags, object_root: false do - extends 'api/v1/statuses/_tags' -end diff --git a/app/views/api/v1/statuses/_tags.rabl b/app/views/api/v1/statuses/_tags.rabl @@ -1,2 +0,0 @@ -attribute :name -node(:url) { |tag| tag_url(tag) } diff --git a/app/views/api/v1/statuses/accounts.rabl b/app/views/api/v1/statuses/accounts.rabl @@ -1,2 +0,0 @@ -collection @accounts -extends 'api/v1/accounts/show' diff --git a/app/views/api/v1/statuses/card.rabl b/app/views/api/v1/statuses/card.rabl @@ -1,7 +0,0 @@ -object @card - -attributes :url, :title, :description, :type, - :author_name, :author_url, :provider_name, - :provider_url, :html, :width, :height - -node(:image) { |card| card.image? ? full_asset_url(card.image.url(:original)) : nil } diff --git a/app/views/api/v1/statuses/context.rabl b/app/views/api/v1/statuses/context.rabl @@ -1,9 +0,0 @@ -object @context - -node :ancestors do |context| - partial 'api/v1/statuses/index', object: context.ancestors -end - -node :descendants do |context| - partial 'api/v1/statuses/index', object: context.descendants -end diff --git a/app/views/api/v1/statuses/index.rabl b/app/views/api/v1/statuses/index.rabl @@ -1,2 +0,0 @@ -collection @statuses -extends('api/v1/statuses/show') diff --git a/app/views/api/v1/statuses/show.rabl b/app/views/api/v1/statuses/show.rabl @@ -1,15 +0,0 @@ -object @status - -extends 'api/v1/statuses/_show' - -node(:favourited, if: proc { !current_account.nil? }) { |status| defined?(@favourites_map) ? @favourites_map[status.id] : current_account.favourited?(status) } -node(:reblogged, if: proc { !current_account.nil? }) { |status| defined?(@reblogs_map) ? @reblogs_map[status.id] : current_account.reblogged?(status) } -node(:muted, if: proc { !current_account.nil? }) { |status| defined?(@mutes_map) ? @mutes_map[status.conversation_id] : current_account.muting_conversation?(status.conversation) } - -child reblog: :reblog do - extends 'api/v1/statuses/_show' - - node(:favourited, if: proc { !current_account.nil? }) { |status| defined?(@favourites_map) ? @favourites_map[status.id] : current_account.favourited?(status) } - node(:reblogged, if: proc { !current_account.nil? }) { |status| defined?(@reblogs_map) ? @reblogs_map[status.id] : current_account.reblogged?(status) } - node(:muted, if: proc { !current_account.nil? }) { false } -end diff --git a/app/views/api/v1/timelines/show.rabl b/app/views/api/v1/timelines/show.rabl @@ -1,2 +0,0 @@ -collection @statuses -extends('api/v1/statuses/show') diff --git a/app/views/home/initial_state.json.rabl b/app/views/home/initial_state.json.rabl @@ -24,8 +24,8 @@ end node(:accounts) do store = {} - store[current_account.id] = partial('api/v1/accounts/show', object: current_account) - store[@admin.id] = partial('api/v1/accounts/show', object: @admin) unless @admin.nil? + store[current_account.id] = ActiveModelSerializers::SerializableResource.new(current_account, serializer: REST::AccountSerializer) + store[@admin.id] = ActiveModelSerializers::SerializableResource.new(@admin, serializer: REST::AccountSerializer) unless @admin.nil? store end diff --git a/app/workers/push_update_worker.rb b/app/workers/push_update_worker.rb @@ -6,7 +6,7 @@ class PushUpdateWorker def perform(account_id, status_id) account = Account.find(account_id) status = Status.find(status_id) - message = InlineRenderer.render(status, account, 'api/v1/statuses/show') + message = InlineRenderer.render(status, account, :status) Redis.current.publish("timeline:#{account.id}", Oj.dump(event: :update, payload: message, queued_at: (Time.now.to_f * 1000.0).to_i)) rescue ActiveRecord::RecordNotFound diff --git a/spec/lib/inline_rabl_scope_spec.rb b/spec/lib/inline_rabl_scope_spec.rb @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -require 'rails_helper' - -describe InlineRablScope do - describe '#current_account' do - it 'returns the given account' do - account = Fabricate(:account) - expect(InlineRablScope.new(account).current_account).to eq account - end - end - - describe '#current_user' do - it 'returns nil if the given account is nil' do - expect(InlineRablScope.new(nil).current_user).to eq nil - end - - it 'returns user of account if the given account is not nil' do - user = Fabricate(:user) - expect(InlineRablScope.new(user.account).current_user).to eq user - end - end -end