Refactor JSON templates to be generated with ActiveModelSerializers instead of Rabl (#4090)
parent
2d6128672f
commit
8b2cad5637
@ -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
|
@ -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
|
||||
|
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Context < ActiveModelSerializers::Model
|
||||
attributes :ancestors, :descendants
|
||||
end
|
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class Search < ActiveModelSerializers::Model
|
||||
attributes :accounts, :statuses, :hashtags
|
||||
end
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -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
|
@ -0,0 +1,5 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class REST::ReportSerializer < ActiveModel::Serializer
|
||||
attributes :id, :action_taken
|
||||
end
|
@ -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
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
collection @accounts
|
||||
extends 'api/v1/accounts/show'
|
@ -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 }
|
@ -1,2 +0,0 @@
|
||||
collection @accounts
|
||||
extends 'api/v1/accounts/relationship'
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
collection @statuses
|
||||
extends 'api/v1/statuses/show'
|
@ -1,4 +0,0 @@
|
||||
object @app
|
||||
attributes :id, :redirect_uri
|
||||
node(:client_id) { |app| app.uid }
|
||||
node(:client_secret) { |app| app.secret }
|
@ -1,3 +0,0 @@
|
||||
object @application
|
||||
|
||||
attributes :name, :website
|
@ -1,2 +0,0 @@
|
||||
collection @accounts
|
||||
extends 'api/v1/accounts/show'
|
@ -1,2 +0,0 @@
|
||||
collection @statuses
|
||||
extends 'api/v1/statuses/show'
|
@ -1,2 +0,0 @@
|
||||
collection @accounts
|
||||
extends 'api/v1/accounts/show'
|
@ -1,2 +0,0 @@
|
||||
object @account
|
||||
extends('api/v1/accounts/show')
|
@ -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
|
@ -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 }
|
@ -1,2 +0,0 @@
|
||||
collection @accounts
|
||||
extends 'api/v1/accounts/show'
|
@ -1,2 +0,0 @@
|
||||
collection @notifications
|
||||
extends 'api/v1/notifications/show'
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
collection @reports
|
||||
extends 'api/v1/reports/show'
|
@ -1,2 +0,0 @@
|
||||
object @report
|
||||
attributes :id, :action_taken
|
@ -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
|
@ -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 }
|
@ -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 }
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
attribute :name
|
||||
node(:url) { |tag| tag_url(tag) }
|
@ -1,2 +0,0 @@
|
||||
collection @accounts
|
||||
extends 'api/v1/accounts/show'
|
@ -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 }
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
collection @statuses
|
||||
extends('api/v1/statuses/show')
|
@ -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
|
@ -1,2 +0,0 @@
|
||||
collection @statuses
|
||||
extends('api/v1/statuses/show')
|
@ -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
|
Loading…
Reference in new issue