Skip to content

Commit

Permalink
Add reactions to relationships
Browse files Browse the repository at this point in the history
There's probably tons of room for optimization here.
  • Loading branch information
TheEssem committed Dec 16, 2024
1 parent 4e0ca43 commit bab5447
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 36 deletions.
32 changes: 9 additions & 23 deletions app/controllers/api/v1/statuses/reactions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,24 @@ def create
def destroy
react = current_account.status_reactions.find_by(status_id: params[:status_id], name: params[:id])

reactions = StatusReaction.select(
[:name, :custom_emoji_id, 'COUNT(*) as count', 'FALSE AS me']
).where(status_id: @status.id)

if react
@status = react.status
count = [@status.reactions_count - 1, 0].max
reactions = reactions.where.not(id: react.id)
UnreactWorker.perform_async(current_account.id, @status.id, params[:id])
else
@status = Status.find(params[:status_id])
count = @status.reactions_count
authorize @status, :show?
end

relationships = StatusRelationshipsPresenter.new([@status], current_account.id, reactions_map: { @status.id => false }, attributes_map: { @status.id => { reactions_count: count } })
reactions = reactions.group(:status_id, :name, :custom_emoji_id).order(Arel.sql('MIN(created_at)').asc).to_a

relationships = StatusRelationshipsPresenter.new([@status], current_account.id, reactions_map: { @status.id => reactions }, attributes_map: { @status.id => { reactions_count: count } })
render json: @status, serializer: REST::StatusSerializer, relationships: relationships
rescue Mastodon::NotPermittedError
not_found
Expand All @@ -43,7 +50,7 @@ def destroy
def set_reactions
@reactions = ordered_reactions.select(
[:id, :account_id, :name, :custom_emoji_id].tap do |values|
values << value_for_reaction_me_column(current_account)
values << Status.value_for_reaction_me_column(current_account.id)
end
).to_a_paginated_by_id(
limit_param(REACTIONS_LIMIT),
Expand All @@ -68,27 +75,6 @@ def filtered?
params[:emoji].present?
end

def value_for_reaction_me_column(account)
if account.nil?
'FALSE AS me'
else
<<~SQL.squish
EXISTS(
SELECT 1
FROM status_reactions inner_reactions
WHERE inner_reactions.account_id = #{account.id}
AND inner_reactions.status_id = status_reactions.status_id
AND inner_reactions.name = status_reactions.name
AND (
inner_reactions.custom_emoji_id = status_reactions.custom_emoji_id
OR inner_reactions.custom_emoji_id IS NULL
AND status_reactions.custom_emoji_id IS NULL
)
) AS me
SQL
end
end

def insert_pagination_headers
set_pagination_headers(next_path, prev_path)
end
Expand Down
20 changes: 10 additions & 10 deletions app/models/status.rb
Original file line number Diff line number Diff line change
Expand Up @@ -489,16 +489,6 @@ def unlink_from_conversations!
end
end

private

def grouped_ordered_status_reactions
status_reactions
.group(:status_id, :name, :custom_emoji_id)
.order(
Arel.sql('MIN(created_at)').asc
)
end

def value_for_reaction_me_column(account_id)
if account_id.nil?
'FALSE AS me'
Expand All @@ -520,6 +510,16 @@ def value_for_reaction_me_column(account_id)
end
end

private

def grouped_ordered_status_reactions
status_reactions
.group(:status_id, :name, :custom_emoji_id)
.order(
Arel.sql('MIN(created_at)').asc
)
end

def update_status_stat!(attrs)
return if marked_for_destruction? || destroyed?

Expand Down
40 changes: 38 additions & 2 deletions app/presenters/status_relationships_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
class StatusRelationshipsPresenter
PINNABLE_VISIBILITIES = %w(public unlisted private).freeze

attr_reader :reblogs_map, :favourites_map, :mutes_map, :pins_map,
:bookmarks_map, :filters_map, :attributes_map
attr_reader :reblogs_map, :favourites_map, :reactions_map, :mutes_map,
:pins_map, :bookmarks_map, :filters_map, :attributes_map

def initialize(statuses, current_account_id = nil, **options)
if current_account_id.nil?
@reblogs_map = {}
@favourites_map = {}
@reactions_map = {}
@bookmarks_map = {}
@mutes_map = {}
@pins_map = {}
Expand All @@ -23,6 +24,7 @@ def initialize(statuses, current_account_id = nil, **options)
@filters_map = build_filters_map(statuses, current_account_id).merge(options[:filters_map] || {})
@reblogs_map = Status.reblogs_map(status_ids, current_account_id).merge(options[:reblogs_map] || {})
@favourites_map = Status.favourites_map(status_ids, current_account_id).merge(options[:favourites_map] || {})
@reactions_map = build_reactions_map(status_ids, current_account_id).merge(options[:reactions_map] || {})
@bookmarks_map = Status.bookmarks_map(status_ids, current_account_id).merge(options[:bookmarks_map] || {})
@mutes_map = Status.mutes_map(conversation_ids, current_account_id).merge(options[:mutes_map] || {})
@pins_map = Status.pins_map(pinnable_status_ids, current_account_id).merge(options[:pins_map] || {})
Expand All @@ -44,4 +46,38 @@ def build_filters_map(statuses, current_account_id)
end
end
end

def build_reactions_map(status_ids, current_account_id)
reactions = StatusReaction.select(
[:status_id, :name, :custom_emoji_id, 'COUNT(*) as count'].tap do |values|
values << value_for_reaction_me_column(current_account_id)
end
).where(status_id: status_ids).where(account_id: current_account_id).group(:status_id, :name, :custom_emoji_id).order(Arel.sql('MIN(created_at)').asc).to_a

reactions.each_with_object({}) do |r, h|
h[r.status_id] = [] if h[r.status_id].nil?
h[r.status_id].push(r.attributes.except(:status_id))
end
end

def value_for_reaction_me_column(account_id)
if account_id.nil?
'FALSE AS me'
else
<<~SQL.squish
EXISTS(
SELECT 1
FROM status_reactions inner_reactions
WHERE inner_reactions.account_id = #{account_id}
AND inner_reactions.status_id = status_reactions.status_id
AND inner_reactions.name = status_reactions.name
AND (
inner_reactions.custom_emoji_id = status_reactions.custom_emoji_id
OR inner_reactions.custom_emoji_id IS NULL
AND status_reactions.custom_emoji_id IS NULL
)
) AS me
SQL
end
end
end
6 changes: 5 additions & 1 deletion app/serializers/rest/status_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,11 @@ def ordered_mentions
end

def reactions
object.reactions(current_user&.account&.id)
if relationships
relationships.reactions_map[object.id] || []
else
object.reactions(current_user&.account&.id)
end
end

private
Expand Down

0 comments on commit bab5447

Please sign in to comment.