discourse/spec/serializers/post_serializer_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

452 lines
16 KiB
Ruby
Raw Permalink Normal View History

# frozen_string_literal: true
RSpec.describe PostSerializer do
fab!(:post)
context "with a post with lots of actions" do
fab!(:actor) { Fabricate(:user, refresh_auto_groups: true) }
fab!(:admin)
let(:acted_ids) do
PostActionType.public_types.values.concat(
%i[notify_user spam].map { |k| PostActionType.types[k] },
)
end
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 { |id| PostActionCreator.new(actor, post, id).perform }
post.reload
end
it "displays the correct info" do
expect(visible_actions_for(actor).sort).to eq(%i[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(%i[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
2015-07-15 11:18:01 -04:00
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 { |a| a[:id] == PostActionType.types[:notify_user] }
expect(notify_user_action).to eq(nil)
end
end
context "with a post with reviewable content" do
let!(:reviewable) do
PostActionCreator.spam(Fabricate(:user, refresh_auto_groups: true), post).reviewable
end
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
subject(:serializer) do
PostSerializer.new(post, scope: Guardian.new(Fabricate(:admin)), root: false).as_json
end
before { post.update!(user_id: nil, deleted_at: Time.zone.now) }
it "serializes correctly" do
%i[name username display_username avatar_template user_title trust_level].each do |attr|
expect(serializer[attr]).to be_nil
end
%i[moderator staff yours].each { |attr| expect(serializer[attr]).to eq(false) }
end
end
context "with a post by a suspended user" do
def serializer
PostSerializer.new(post, scope: Guardian.new(Fabricate(:admin)), root: false).as_json
end
it "serializes correctly" do
expect(serializer[:user_suspended]).to be_nil
post.user.update!(suspended_till: 1.month.from_now)
expect(serializer[:user_suspended]).to eq(true)
freeze_time(2.months.from_now)
expect(serializer[: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(:user) }
let(:raw) { "Raw contents of the post." }
context "with a public post" do
let(:post) { Fabricate(: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) do
Fabricate(
:post,
raw: raw,
user: user,
hidden: true,
hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached],
)
end
it "includes if the user can see it" do
expect(serialized_post_for_user(Fabricate(:moderator))[:can_see_hidden_post]).to eq(true)
expect(serialized_post_for_user(Fabricate(:admin))[:can_see_hidden_post]).to eq(true)
expect(serialized_post_for_user(user)[:can_see_hidden_post]).to eq(true)
expect(serialized_post_for_user(Fabricate(:user))[:can_see_hidden_post]).to eq(false)
end
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
2019-05-10 06:59:31 -04:00
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(: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) do
Fabricate(
:post,
raw: raw,
user: user,
wiki: true,
hidden: true,
hidden_reason_id: Post.hidden_reasons[:flag_threshold_reached],
)
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
end
context "with a post with notices" do
2019-05-10 06:59:31 -04:00
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) do
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
end
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
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
let(:current_user) { Fabricate(:user) }
let(:topic_view) { TopicView.new(post.topic, current_user) }
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
let(:serialized) do
s = serialized_post(current_user)
s.post_actions = PostAction.counts_for([post], current_user)[post.id]
s.topic_view = topic_view
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
s
end
context "when a Bookmark record exists for the user on the post" do
let!(:bookmark) do
Fabricate(:bookmark_next_business_day_reminder, user: current_user, bookmarkable: post)
end
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
context "with bookmarks with reminders" do
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
it "returns true" do
expect(serialized.as_json[:bookmarked]).to eq(true)
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
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)
fab!(:group_user)
fab!(:post) { Fabricate(:post, topic: topic) }
fab!(:category_moderation_group) do
Fabricate(:category_moderation_group, category: topic.category, group: group_user.group)
end
before { SiteSetting.enable_category_group_moderation = true }
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
context "with allow_anonymous_likes enabled" do
fab!(:user)
fab!(:topic) { Fabricate(:topic, user: user) }
fab!(:post) { Fabricate(:post, topic: topic, user: topic.user) }
fab!(:anonymous_user) { Fabricate(:anonymous) }
let(:serializer) { PostSerializer.new(post, scope: Guardian.new(anonymous_user), root: false) }
let(:post_action) do
user.id = anonymous_user.id
post.id = 1
a =
PostAction.new(
user: anonymous_user,
post: post,
post_action_type_id: PostActionType.types[:like],
)
a.created_at = 1.minute.ago
a
end
before do
SiteSetting.allow_anonymous_posting = true
SiteSetting.allow_anonymous_likes = true
SiteSetting.post_undo_action_window_mins = 10
PostSerializer.any_instance.stubs(:post_actions).returns({ 2 => post_action })
end
context "when post_undo_action_window_mins has not passed" do
before { post_action.created_at = 5.minutes.ago }
it "allows anonymous users to unlike posts" do
like_actions_summary =
serializer.actions_summary.find { |a| a[:id] == PostActionType.types[:like] }
#When :can_act is present, the JavaScript allows the user to click the unlike button
expect(like_actions_summary[:can_act]).to eq(true)
end
end
context "when post_undo_action_window_mins has passed" do
before { post_action.created_at = 20.minutes.ago }
it "disallows anonymous users from unliking posts" do
# There are no other post actions available to anonymous users so the action_summary will be an empty array
expect(serializer.actions_summary.find { |a| a[:id] == PostActionType.types[:like] }).to eq(
nil,
)
end
end
end
context "with mentions" do
fab!(:user_status)
fab!(:user)
let(:username) { "joffrey" }
let(:user1) { Fabricate(:user, user_status: user_status, username: username) }
let(:post) { Fabricate(:post, user: user, raw: "Hey @#{user1.username}") }
let(:serializer) { described_class.new(post, scope: Guardian.new(user), root: false) }
context "when user status is enabled" do
before { SiteSetting.enable_user_status = true }
it "returns mentioned users with user status" do
json = serializer.as_json
expect(json[:mentioned_users]).to be_present
expect(json[:mentioned_users].length).to be(1)
expect(json[:mentioned_users][0]).to_not be_nil
expect(json[:mentioned_users][0][:id]).to eq(user1.id)
expect(json[:mentioned_users][0][:username]).to eq(user1.username)
expect(json[:mentioned_users][0][:name]).to eq(user1.name)
expect(json[:mentioned_users][0][:status][:description]).to eq(user_status.description)
expect(json[:mentioned_users][0][:status][:emoji]).to eq(user_status.emoji)
end
context "when username has a capital letter" do
let(:username) { "JoJo" }
it "returns mentioned users with user status" do
expect(serializer.as_json[:mentioned_users][0][:username]).to eq(user1.username)
end
end
end
context "when user status is disabled" do
before { SiteSetting.enable_user_status = false }
it "doesn't return mentioned users" do
expect(serializer.as_json[:mentioned_users]).to be_nil
end
end
end
describe "#user_status" do
fab!(: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
Improving bookmarks part 1 (#8466) Note: All of this functionality is hidden behind a hidden, default false, site setting called `enable_bookmarks_with_reminders`. Also, any feedback on Ember code would be greatly appreciated! This is part 1 of the bookmark improvements. The next PR will address the backend logic to send reminder notifications for bookmarked posts to users. This PR adds the following functionality: * We are adding a new `bookmarks` table and `Bookmark` model to make the bookmarks a first-class citizen and to allow attaching reminders to them. * Posts now have a new button in their actions menu that has the icon of an actual book * Clicking the button opens the new bookmark modal. * Both name and the reminder type are optional. * If you close the modal without doing anything, the bookmark is saved with no reminder. * If you click the Cancel button, no bookmark is saved at all. * All of the reminder type tiles are dynamic and the times they show will be based on your user timezone set in your profile (this should already be set for you). * If for some reason a user does not have their timezone set they will not be able to set a reminder, but they will still be able to create a bookmark. * A bookmark can be deleted by clicking on the book icon again which will be red if the post is bookmarked. This PR does NOT do anything to migrate or change existing bookmarks in the form of `PostActions`, the two features live side-by-side here. Also this does nothing to the topic bookmarking.
2019-12-10 23:04:02 -05:00
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