From aa222ef7b874841cd6688c620f75d35a7bbdea6b Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 6 Feb 2025 20:50:30 +0530 Subject: [PATCH] FEATURE: add first post likes data serializer (#31216) This PR adds two attributes (`op_can_like` & `op_liked`) to `TopicListItemSerializer`. We've also added `serialize_topic_op_likes_data` theme modifier so that these two attributes are only added when a theme or component needs this data. --- app/models/theme_modifier_set.rb | 19 +++---- app/serializers/topic_list_item_serializer.rb | 44 +++++++++++++++ ...lize_topic_op_likes_data_theme_modifier.rb | 6 +++ .../topic_list_item_serializer_spec.rb | 54 +++++++++++++++++++ 4 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 db/migrate/20250205174221_add_serialize_topic_op_likes_data_theme_modifier.rb diff --git a/app/models/theme_modifier_set.rb b/app/models/theme_modifier_set.rb index c68b564c4c3..218f254e150 100644 --- a/app/models/theme_modifier_set.rb +++ b/app/models/theme_modifier_set.rb @@ -140,15 +140,16 @@ end # # Table name: theme_modifier_sets # -# id :bigint not null, primary key -# theme_id :bigint not null -# serialize_topic_excerpts :boolean -# csp_extensions :string is an Array -# svg_icons :string is an Array -# topic_thumbnail_sizes :string is an Array -# custom_homepage :boolean -# serialize_post_user_badges :string is an Array -# theme_setting_modifiers :jsonb +# id :bigint not null, primary key +# theme_id :bigint not null +# serialize_topic_excerpts :boolean +# csp_extensions :string is an Array +# svg_icons :string is an Array +# topic_thumbnail_sizes :string is an Array +# custom_homepage :boolean +# serialize_post_user_badges :string is an Array +# theme_setting_modifiers :jsonb +# serialize_topic_op_likes_data :boolean # # Indexes # diff --git a/app/serializers/topic_list_item_serializer.rb b/app/serializers/topic_list_item_serializer.rb index f6189a23f99..37e74db6d3a 100644 --- a/app/serializers/topic_list_item_serializer.rb +++ b/app/serializers/topic_list_item_serializer.rb @@ -10,6 +10,8 @@ class TopicListItemSerializer < ListableTopicSerializer :last_poster_username, :category_id, :op_like_count, + :op_can_like, + :op_liked, :pinned_globally, :liked_post_numbers, :featured_link, @@ -32,6 +34,42 @@ class TopicListItemSerializer < ListableTopicSerializer object.first_post && object.first_post.like_count end + def include_op_can_like? + theme_modifier_helper.serialize_topic_op_likes_data + end + + def op_can_like + return false if !scope.user || !object.first_post + + first_post = object.first_post + return false if first_post.user_id == scope.user.id + return false unless scope.post_can_act?(first_post, :like) + + first_post_liked = + PostAction.where( + user_id: scope.user.id, + post_id: first_post.id, + post_action_type_id: PostActionType.types[:like], + ).first + return scope.can_delete?(first_post_liked) if first_post_liked + + true + end + + def include_op_liked? + theme_modifier_helper.serialize_topic_op_likes_data + end + + def op_liked + return false if !scope.user || !object.first_post + + PostAction.where( + user_id: scope.user.id, + post_id: object.first_post.id, + post_action_type_id: PostActionType.types[:like], + ).exists? + end + def last_poster_username posters.find { |poster| poster.user.id == object.last_post_user_id }.try(:user).try(:username) end @@ -93,4 +131,10 @@ class TopicListItemSerializer < ListableTopicSerializer def include_allowed_user_count? object.private_message? end + + private + + def theme_modifier_helper + @theme_modifier_helper ||= ThemeModifierHelper.new(request: scope.request) + end end diff --git a/db/migrate/20250205174221_add_serialize_topic_op_likes_data_theme_modifier.rb b/db/migrate/20250205174221_add_serialize_topic_op_likes_data_theme_modifier.rb new file mode 100644 index 00000000000..e91a75ae4f7 --- /dev/null +++ b/db/migrate/20250205174221_add_serialize_topic_op_likes_data_theme_modifier.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true +class AddSerializeTopicOpLikesDataThemeModifier < ActiveRecord::Migration[7.2] + def change + add_column :theme_modifier_sets, :serialize_topic_op_likes_data, :boolean, null: true + end +end diff --git a/spec/serializers/topic_list_item_serializer_spec.rb b/spec/serializers/topic_list_item_serializer_spec.rb index 69dc330bdbb..56b26916ea7 100644 --- a/spec/serializers/topic_list_item_serializer_spec.rb +++ b/spec/serializers/topic_list_item_serializer_spec.rb @@ -96,4 +96,58 @@ RSpec.describe TopicListItemSerializer do expect(json[:posters].length).to eq(1) end end + + describe "correctly serializes op_likes data" do + let(:user) { Fabricate(:user) } + let(:moderator) { Fabricate(:moderator) } + let(:first_post) { Fabricate(:post, topic: topic, user: user) } + + before { topic.update!(first_post: first_post) } + + it "serializes op_can_like" do + allow_any_instance_of(ThemeModifierHelper).to receive( + :serialize_topic_op_likes_data, + ).and_return(true) + json = TopicListItemSerializer.new(topic, scope: Guardian.new(moderator), root: false).as_json + + expect(json[:op_can_like]).to eq(true) + end + + it "does not include op_can_like when theme modifier disallows" do + allow_any_instance_of(ThemeModifierHelper).to receive( + :serialize_topic_op_likes_data, + ).and_return(false) + json = TopicListItemSerializer.new(topic, scope: Guardian.new(moderator), root: false).as_json + + expect(json.key?(:op_can_like)).to eq(false) + end + + it "serializes op_liked" do + allow_any_instance_of(ThemeModifierHelper).to receive( + :serialize_topic_op_likes_data, + ).and_return(true) + PostAction.create!( + user: user, + post: first_post, + post_action_type_id: PostActionType.types[:like], + ) + json = TopicListItemSerializer.new(topic, scope: Guardian.new(user), root: false).as_json + + expect(json[:op_liked]).to eq(true) + end + + it "does not include op_liked when theme modifier disallows" do + allow_any_instance_of(ThemeModifierHelper).to receive( + :serialize_topic_op_likes_data, + ).and_return(false) + PostAction.create!( + user: user, + post: first_post, + post_action_type_id: PostActionType.types[:like], + ) + json = TopicListItemSerializer.new(topic, scope: Guardian.new(user), root: false).as_json + + expect(json.key?(:op_liked)).to eq(false) + end + end end