# frozen_string_literal: true RSpec.describe PostSerializer do fab!(:post) { Fabricate(:post) } before do Group.refresh_automatic_groups! end context "with a post with lots of actions" do fab!(:actor) { Fabricate(:user) } fab!(:admin) { Fabricate(:admin) } let(:acted_ids) { PostActionType.public_types.values .concat([:notify_user, :spam].map { |k| PostActionType.types[k] }) } def visible_actions_for(user) serializer = PostSerializer.new(post, scope: Guardian.new(user), root: false) # NOTE this is messy, we should extract all this logic elsewhere serializer.post_actions = PostAction.counts_for([post], actor)[post.id] if user.try(:id) == actor.id actions = serializer.as_json[:actions_summary] lookup = PostActionType.types.invert actions.keep_if { |a| (a[:count] || 0) > 0 }.map { |a| lookup[a[:id]] } end before do acted_ids.each do |id| PostActionCreator.new(actor, post, id).perform end post.reload end it "displays the correct info" do expect(visible_actions_for(actor).sort).to eq([:like, :notify_user, :spam]) expect(visible_actions_for(post.user).sort).to eq([:like]) expect(visible_actions_for(nil).sort).to eq([:like]) expect(visible_actions_for(admin).sort).to eq([:like, :notify_user, :spam]) end it "can't flag your own post to notify yourself" do serializer = PostSerializer.new(post, scope: Guardian.new(post.user), root: false) notify_user_action = serializer.actions_summary.find { |a| a[:id] == PostActionType.types[:notify_user] } expect(notify_user_action).to be_blank end it "should not allow user to flag post and notify non human user" do post.update!(user: Discourse.system_user) serializer = PostSerializer.new( post, scope: Guardian.new(actor), root: false ) notify_user_action = serializer.actions_summary.find do |a| a[:id] == PostActionType.types[:notify_user] end expect(notify_user_action).to eq(nil) end end context "with a post with reviewable content" do let!(:reviewable) { PostActionCreator.spam(Fabricate(:user), post).reviewable } it "includes the reviewable data" do json = PostSerializer.new(post, scope: Guardian.new(Fabricate(:moderator)), root: false).as_json expect(json[:reviewable_id]).to eq(reviewable.id) expect(json[:reviewable_score_count]).to eq(1) expect(json[:reviewable_score_pending_count]).to eq(1) end end context "with a post by a nuked user" do before do post.update!( user_id: nil, deleted_at: Time.zone.now ) end subject { PostSerializer.new(post, scope: Guardian.new(Fabricate(:admin)), root: false).as_json } it "serializes correctly" do [:name, :username, :display_username, :avatar_template, :user_title, :trust_level].each do |attr| expect(subject[attr]).to be_nil end [:moderator, :staff, :yours].each do |attr| expect(subject[attr]).to eq(false) end end end context "with a post by a suspended user" do def subject PostSerializer.new(post, scope: Guardian.new(Fabricate(:admin)), root: false).as_json end it "serializes correctly" do expect(subject[:user_suspended]).to be_nil post.user.update!( suspended_till: 1.month.from_now, ) expect(subject[:user_suspended]).to eq(true) freeze_time (2.months.from_now) expect(subject[:user_suspended]).to be_nil end end describe "#display_username" do let(:user) { post.user } let(:serializer) { PostSerializer.new(post, scope: Guardian.new, root: false) } let(:json) { serializer.as_json } it "returns the display_username it when `enable_names` is on" do SiteSetting.enable_names = true expect(json[:display_username]).to be_present end it "doesn't return the display_username it when `enable_names` is off" do SiteSetting.enable_names = false expect(json[:display_username]).to be_blank end end context "with a hidden post with add_raw enabled" do let(:user) { Fabricate.build(:user, id: -99999) } let(:raw) { "Raw contents of the post." } context "with a public post" do let(:post) { Fabricate.build(:post, raw: raw, user: user) } it "includes the raw post for everyone" do [nil, user, Fabricate(:user), Fabricate(:moderator), Fabricate(:admin)].each do |user| expect(serialized_post_for_user(user)[:raw]).to eq(raw) end end end context "with a hidden post" do let(:post) { Fabricate.build(:post, raw: raw, user: user, hidden: true, hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached]) } it "shows the raw post only if authorized to see it" do expect(serialized_post_for_user(nil)[:raw]).to eq(nil) expect(serialized_post_for_user(Fabricate(:user))[:raw]).to eq(nil) expect(serialized_post_for_user(user)[:raw]).to eq(raw) expect(serialized_post_for_user(Fabricate(:moderator))[:raw]).to eq(raw) expect(serialized_post_for_user(Fabricate(:admin))[:raw]).to eq(raw) end it "can view edit history only if authorized" do expect(serialized_post_for_user(nil)[:can_view_edit_history]).to eq(false) expect(serialized_post_for_user(Fabricate(:user))[:can_view_edit_history]).to eq(false) expect(serialized_post_for_user(user)[:can_view_edit_history]).to eq(true) expect(serialized_post_for_user(Fabricate(:moderator))[:can_view_edit_history]).to eq(true) expect(serialized_post_for_user(Fabricate(:admin))[:can_view_edit_history]).to eq(true) end end context "with a hidden revised post" do fab!(:post) { Fabricate(:post, raw: 'Hello world!', hidden: true) } before do SiteSetting.editing_grace_period_max_diff = 1 revisor = PostRevisor.new(post) revisor.revise!(post.user, raw: 'Hello, everyone!') end it "will not leak version to users" do json = PostSerializer.new(post, scope: Guardian.new(user), root: false).as_json expect(json[:version]).to eq(1) end it "will show real version to staff" do json = PostSerializer.new(post, scope: Guardian.new(Fabricate(:admin)), root: false).as_json expect(json[:version]).to eq(2) end end context "with a public wiki post" do let(:post) { Fabricate.build(:post, raw: raw, user: user, wiki: true) } it "can view edit history" do [nil, user, Fabricate(:user), Fabricate(:moderator), Fabricate(:admin)].each do |user| expect(serialized_post_for_user(user)[:can_view_edit_history]).to eq(true) end end end context "with a hidden wiki post" do let(:post) { Fabricate.build( :post, raw: raw, user: user, wiki: true, hidden: true, hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached]) } it "can view edit history only if authorized" do expect(serialized_post_for_user(nil)[:can_view_edit_history]).to eq(false) expect(serialized_post_for_user(Fabricate(:user))[:can_view_edit_history]).to eq(false) expect(serialized_post_for_user(user)[:can_view_edit_history]).to eq(true) expect(serialized_post_for_user(Fabricate(:moderator))[:can_view_edit_history]).to eq(true) expect(serialized_post_for_user(Fabricate(:admin))[:can_view_edit_history]).to eq(true) end end end context "with a post with notices" do fab!(:user) { Fabricate(:user, trust_level: 1) } fab!(:user_tl1) { Fabricate(:user, trust_level: 1) } fab!(:user_tl2) { Fabricate(:user, trust_level: 2) } let(:post) { post = Fabricate(:post, user: user) post.custom_fields[Post::NOTICE] = { type: Post.notices[:returning_user], last_posted_at: 1.day.ago } post.save_custom_fields post } def json_for_user(user) PostSerializer.new(post, scope: Guardian.new(user), root: false).as_json end it "is visible for TL2+ users (except poster)" do expect(json_for_user(nil)[:notice]).to eq(nil) expect(json_for_user(user)[:notice]).to eq(nil) SiteSetting.returning_user_notice_tl = 2 expect(json_for_user(user_tl1)[:notice]).to eq(nil) expect(json_for_user(user_tl2)[:notice][:type]).to eq(Post.notices[:returning_user]) SiteSetting.returning_user_notice_tl = 1 expect(json_for_user(user_tl1)[:notice][:type]).to eq(Post.notices[:returning_user]) expect(json_for_user(user_tl2)[:notice][:type]).to eq(Post.notices[:returning_user]) end end context "with a post with bookmarks" do let(:current_user) { Fabricate(:user) } let(:topic_view) { TopicView.new(post.topic, current_user) } let(:serialized) do s = serialized_post(current_user) s.post_actions = PostAction.counts_for([post], current_user)[post.id] s.topic_view = topic_view s end context "when a Bookmark record exists for the user on the post" do let!(:bookmark) { Fabricate(:bookmark_next_business_day_reminder, user: current_user, bookmarkable: post) } context "with bookmarks with reminders" do it "returns true" do expect(serialized.as_json[:bookmarked]).to eq(true) end it "returns the reminder_at for the bookmark" do expect(serialized.as_json[:bookmark_reminder_at]).to eq(bookmark.reminder_at.iso8601) end end end end context "with posts when group moderation is enabled" do fab!(:topic) { Fabricate(:topic) } fab!(:group_user) { Fabricate(:group_user) } fab!(:post) { Fabricate(:post, topic: topic) } before do SiteSetting.enable_category_group_moderation = true topic.category.update!(reviewable_by_group_id: group_user.group.id) end it "does nothing for regular users" do expect(serialized_post_for_user(nil)[:group_moderator]).to eq(nil) end it "returns a group_moderator attribute for category group moderators" do post.update!(user: group_user.user) expect(serialized_post_for_user(nil)[:group_moderator]).to eq(true) end end context "with a post with small action" do fab!(:post) { Fabricate(:small_action, action_code: "public_topic") } it "returns `action_code` based on `login_required` site setting" do expect(serialized_post_for_user(nil)[:action_code]).to eq("public_topic") SiteSetting.login_required = true expect(serialized_post_for_user(nil)[:action_code]).to eq("open_topic") end end describe "#user_status" do fab!(:user_status) { Fabricate(:user_status) } fab!(:user) { Fabricate(:user, user_status: user_status) } fab!(:post) { Fabricate(:post, user: user) } let(:serializer) { described_class.new(post, scope: Guardian.new(user), root: false) } it "adds user status when enabled" do SiteSetting.enable_user_status = true json = serializer.as_json expect(json[:user_status]).to_not be_nil do |status| expect(status.description).to eq(user_status.description) expect(status.emoji).to eq(user_status.emoji) end end it "doesn't add user status when disabled" do SiteSetting.enable_user_status = false json = serializer.as_json expect(json.keys).not_to include :user_status end it "doesn't add status if user doesn't have it" do SiteSetting.enable_user_status = true user.clear_status! user.reload json = serializer.as_json expect(json.keys).not_to include :user_status end end def serialized_post(u) s = PostSerializer.new(post, scope: Guardian.new(u), root: false) s.add_raw = true s end def serialized_post_for_user(u) s = serialized_post(u) s.as_json end end