Add emoji_reactions property to status api object

This commit is contained in:
KMY 2023-02-23 20:32:27 +09:00 committed by YoheiZuho
parent b88e3942cc
commit dca26cc504
7 changed files with 143 additions and 1 deletions

View File

@ -65,6 +65,7 @@ class Status < ApplicationRecord
belongs_to :quote, class_name: 'Status', inverse_of: :quoted, optional: true
has_many :favourites, inverse_of: :status, dependent: :destroy
has_many :emoji_reactions, inverse_of: :status, dependent: :destroy
has_many :bookmarks, inverse_of: :status, dependent: :destroy
has_many :reblogs, foreign_key: 'reblog_of_id', class_name: 'Status', inverse_of: :reblog, dependent: :destroy
has_many :reblogged_by_accounts, through: :reblogs, class_name: 'Account', source: :account
@ -323,6 +324,29 @@ class Status < ApplicationRecord
update_status_stat!(key => [public_send(key) - 1, 0].max)
end
def emoji_reactions_grouped_by_name(account = nil)
(Oj.load(status_stat&.emoji_reactions || '', mode: :strict) || []).tap do |emoji_reactions|
if account.present?
emoji_reactions.each do |emoji_reaction|
emoji_reaction['me'] = emoji_reaction['account_ids'].include?(account.id.to_s)
emoji_reaction['count'] = emoji_reaction['account_ids'].size
emoji_reaction['account_ids'] -= account.excluded_from_timeline_account_ids.map(&:to_s)
end
end
end
end
def generate_emoji_reactions_grouped_by_name
records = emoji_reactions.group(:name).order(Arel.sql('MIN(created_at) ASC')).select('name, min(custom_emoji_id) as custom_emoji_id, count(*) as count, array_agg(account_id::text order by created_at) as account_ids')
Oj.dump(ActiveModelSerializers::SerializableResource.new(records, each_serializer: REST::EmojiReactionsGroupedByNameSerializer, scope: nil, scope_name: :current_user))
end
def refresh_emoji_reactions_grouped_by_name!
generate_emoji_reactions_grouped_by_name.tap do |emoji_reactions|
update_status_stat!(emoji_reactions: emoji_reactions)
end
end
def trendable?
if attributes['trendable'].nil?
account.trendable?

View File

@ -9,6 +9,7 @@
# replies_count :bigint(8) default(0), not null
# reblogs_count :bigint(8) default(0), not null
# favourites_count :bigint(8) default(0), not null
# emoji_reactions :string
# created_at :datetime not null
# updated_at :datetime not null
#
@ -27,4 +28,14 @@ class StatusStat < ApplicationRecord
def favourites_count
[attributes['favourites_count'], 0].max
end
def emoji_reactions
attributes['emoji_reactions'] || ''
end
private
def reset_parent_cache
Rails.cache.delete("statuses/#{status_id}")
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
# name: string,
#count: number,
#account_ids: Array<string>,
#me: boolean,
#url: string,
#domain: string
class REST::EmojiReactionsGroupedByNameSerializer < ActiveModel::Serializer
attributes :name, :count
attribute :me, if: :current_user?
attribute :url, if: :custom_emoji?
attribute :static_url, if: :custom_emoji?
attribute :domain, if: :custom_emoji?
attribute :account_ids, if: :has_account_ids?
def current_user?
!current_user.nil?
end
def custom_emoji?
object.respond_to?(:custom_emoji)
end
def has_account_ids?
object.respond_to?(:account_ids)
end
end

View File

@ -6,7 +6,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,
:sensitive, :spoiler_text, :visibility, :language,
:uri, :url, :replies_count, :reblogs_count,
:favourites_count, :edited_at
:favourites_count, :emoji_reactions, :edited_at
attribute :favourited, if: :current_user?
attribute :reblogged, if: :current_user?
@ -103,6 +103,10 @@ class REST::StatusSerializer < ActiveModel::Serializer
end
end
def emoji_reactions
object.emoji_reactions_grouped_by_name(current_user&.account)
end
def reblogged
if relationships
relationships.reblogs_map[object.id] || false

View File

@ -0,0 +1,5 @@
class AddEmojiReactionsToStatusStats < ActiveRecord::Migration[6.1]
def change
add_column :status_stats, :emoji_reactions, :string
end
end

View File

@ -965,8 +965,14 @@ ActiveRecord::Schema[7.1].define(version: 2023_12_12_073317) do
t.bigint "replies_count", default: 0, null: false
t.bigint "reblogs_count", default: 0, null: false
t.bigint "favourites_count", default: 0, null: false
<<<<<<< HEAD
t.datetime "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false
=======
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "emoji_reactions"
>>>>>>> 092f9916b0 (Add emoji_reactions property to status api object)
t.index ["status_id"], name: "index_status_stats_on_status_id", unique: true
end

61
lib/mastodon/cache_cli.rb Normal file
View File

@ -0,0 +1,61 @@
# frozen_string_literal: true
require_relative '../../config/boot'
require_relative '../../config/environment'
require_relative 'cli_helper'
module Mastodon
class CacheCLI < Thor
include CLIHelper
def self.exit_on_failure?
true
end
desc 'clear', 'Clear out the cache storage'
def clear
Rails.cache.clear
say('OK', :green)
end
option :concurrency, type: :numeric, default: 5, aliases: [:c]
option :verbose, type: :boolean, aliases: [:v]
desc 'recount TYPE', 'Update hard-cached counters'
long_desc <<~LONG_DESC
Update hard-cached counters of TYPE by counting referenced
records from scratch. TYPE can be "accounts" or "statuses".
It may take a very long time to finish, depending on the
size of the database.
LONG_DESC
def recount(type)
case type
when 'accounts'
processed, = parallelize_with_progress(Account.local.includes(:account_stat)) do |account|
account_stat = account.account_stat
account_stat.following_count = account.active_relationships.count
account_stat.followers_count = account.passive_relationships.count
account_stat.statuses_count = account.statuses.where.not(visibility: :direct).count
account_stat.save if account_stat.changed?
end
when 'statuses'
processed, = parallelize_with_progress(Status.includes(:status_stat)) do |status|
status_stat = status.status_stat
status_stat.replies_count = status.replies.where.not(visibility: :direct).count
status_stat.reblogs_count = status.reblogs.count
status_stat.favourites_count = status.favourites.count
status_stat.emoji_reactions = status.generate_emoji_reactions_grouped_by_name
status_stat.save if status_stat.changed?
end
else
say("Unknown type: #{type}", :red)
exit(1)
end
say
say("OK, recounted #{processed} records", :green)
end
end
end