mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 13:08:40 +08:00
Converting a topic between a private message and a regular topic is meant to go through the dedicated staff-only conversion flow. The generic topic update path did not apply that same restriction, so the topic's archetype could be changed there without it. Route archetype changes involving private messages through the same `can_convert_topic?` permission the conversion flow already uses, so both paths behave consistently.
329 lines
13 KiB
Ruby
Vendored
329 lines
13 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
RSpec.describe TopicConverter do
|
|
describe "convert_to_public_topic" do
|
|
fab!(:admin)
|
|
fab!(:author, :user)
|
|
fab!(:category) { Fabricate(:category, topic_count: 1) }
|
|
fab!(:private_message) { Fabricate(:private_message_topic, user: author) } # creates a topic without a first post
|
|
let(:first_post) do
|
|
create_post(user: author, topic: private_message, allow_uncategorized_topics: false)
|
|
end
|
|
let(:other_user) { private_message.topic_allowed_users.find { |u| u.user != author }.user }
|
|
|
|
let(:uncategorized_category) { Category.find(SiteSetting.uncategorized_category_id) }
|
|
|
|
context "with success" do
|
|
it "converts private message to regular topic" do
|
|
SiteSetting.allow_uncategorized_topics = true
|
|
topic = nil
|
|
|
|
_pm_post_2 = Fabricate(:post, topic: private_message, user: author)
|
|
_pm_post_3 = Fabricate(:post, topic: private_message, user: author)
|
|
|
|
other_pm = Fabricate(:private_message_post).topic
|
|
other_pm_post = Fabricate(:private_message_post, topic: other_pm)
|
|
other_pm_post_2 =
|
|
Fabricate(:private_message_post, topic: other_pm, user: other_pm_post.user)
|
|
|
|
expect do
|
|
topic = TopicConverter.new(first_post.topic, admin).convert_to_public_topic
|
|
topic.reload
|
|
end.to change { uncategorized_category.reload.topic_count }.by(1).and change {
|
|
author.reload.topic_count
|
|
}.from(0).to(1).and change { author.reload.post_count }.from(0).to(2)
|
|
|
|
# Ensure query does not affect users from other topics or posts as DB query to update count is quite complex.
|
|
expect(other_pm.user.topic_count).to eq(0)
|
|
expect(other_pm.user.post_count).to eq(0)
|
|
expect(other_pm_post.user.topic_count).to eq(0)
|
|
expect(other_pm_post.user.post_count).to eq(0)
|
|
|
|
expect(topic).to be_valid
|
|
expect(topic.archetype).to eq("regular")
|
|
expect(topic.category_id).to eq(SiteSetting.uncategorized_category_id)
|
|
end
|
|
|
|
context "when uncategorized category is not allowed" do
|
|
before do
|
|
SiteSetting.allow_uncategorized_topics = false
|
|
category.update!(read_restricted: false)
|
|
end
|
|
|
|
it "should convert private message into the right category" do
|
|
topic = TopicConverter.new(first_post.topic, admin).convert_to_public_topic
|
|
topic.reload
|
|
|
|
expect(topic).to be_valid
|
|
expect(topic.archetype).to eq("regular")
|
|
|
|
first_category =
|
|
Category
|
|
.where.not(id: SiteSetting.uncategorized_category_id)
|
|
.where(read_restricted: false)
|
|
.order("id asc")
|
|
.first
|
|
|
|
expect(topic.category_id).to eq(first_category.id)
|
|
expect(topic.category.topic_count).to eq(2)
|
|
end
|
|
end
|
|
|
|
context "when a custom category_id is given" do
|
|
it "should convert private message into the right category" do
|
|
topic = TopicConverter.new(first_post.topic, admin).convert_to_public_topic(category.id)
|
|
|
|
expect(topic.reload.category).to eq(category)
|
|
expect(topic.category.topic_count).to eq(2)
|
|
end
|
|
end
|
|
|
|
it "updates user stats" do
|
|
first_post
|
|
topic_user = TopicUser.find_by(user_id: author.id, topic_id: private_message.id)
|
|
expect(private_message.user.user_stat.topic_count).to eq(0)
|
|
expect(private_message.user.user_stat.post_count).to eq(0)
|
|
private_message.convert_to_public_topic(admin)
|
|
expect(private_message.reload.user.user_stat.topic_count).to eq(1)
|
|
expect(private_message.user.user_stat.post_count).to eq(0)
|
|
expect(topic_user.reload.notification_level).to eq(TopicUser.notification_levels[:watching])
|
|
end
|
|
|
|
context "with a reply" do
|
|
before do
|
|
Jobs.run_immediately!
|
|
UserActionManager.enable
|
|
first_post
|
|
create_post(topic: private_message, user: other_user)
|
|
private_message.reload
|
|
end
|
|
|
|
it "updates UserActions" do
|
|
TopicConverter.new(private_message, admin).convert_to_public_topic
|
|
expect(
|
|
author.user_actions.where(action_type: UserAction::NEW_PRIVATE_MESSAGE).count,
|
|
).to eq(0)
|
|
expect(author.user_actions.where(action_type: UserAction::NEW_TOPIC).count).to eq(1)
|
|
expect(
|
|
other_user.user_actions.where(action_type: UserAction::NEW_PRIVATE_MESSAGE).count,
|
|
).to eq(0)
|
|
expect(
|
|
other_user.user_actions.where(action_type: UserAction::GOT_PRIVATE_MESSAGE).count,
|
|
).to eq(0)
|
|
expect(other_user.user_actions.where(action_type: UserAction::REPLY).count).to eq(1)
|
|
end
|
|
end
|
|
|
|
it "creates small action and revision when not silent" do
|
|
Jobs.run_immediately!
|
|
first_post
|
|
|
|
expect do
|
|
TopicConverter.new(private_message, admin).convert_to_public_topic(category.id)
|
|
end.to change { PostRevision.count }.by(1)
|
|
|
|
expect(
|
|
private_message.posts.where(
|
|
post_type: Post.types[:small_action],
|
|
action_code: "public_topic",
|
|
),
|
|
).to be_present
|
|
end
|
|
|
|
it "records a revision but skips small action and bump when silent" do
|
|
Jobs.run_immediately!
|
|
first_post
|
|
bumped_at = private_message.reload.bumped_at
|
|
|
|
expect do
|
|
TopicConverter.new(private_message, admin, silent: true).convert_to_public_topic(
|
|
category.id,
|
|
)
|
|
end.to change { PostRevision.count }.by(1)
|
|
|
|
expect(private_message.first_post.revisions.last.hidden).to eq(true)
|
|
expect(private_message.posts.where(post_type: Post.types[:small_action])).to be_empty
|
|
expect(private_message.reload.bumped_at).to be_within(1.second).of(bumped_at)
|
|
end
|
|
|
|
it "deletes notifications for users not allowed to see the topic" do
|
|
staff_category = Fabricate(:private_category, group: Group[:staff])
|
|
user_notification =
|
|
Fabricate(:mentioned_notification, post: first_post, user: Fabricate(:user))
|
|
admin_notification =
|
|
Fabricate(:mentioned_notification, post: first_post, user: Fabricate(:admin))
|
|
|
|
Jobs.run_immediately!
|
|
TopicConverter.new(first_post.topic, admin).convert_to_public_topic(staff_category.id)
|
|
|
|
expect(Notification.exists?(user_notification.id)).to eq(false)
|
|
expect(Notification.exists?(admin_notification.id)).to eq(true)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "convert_to_private_message" do
|
|
fab!(:admin)
|
|
fab!(:author, :user)
|
|
fab!(:category)
|
|
fab!(:topic) { Fabricate(:topic, user: author, category_id: category.id) }
|
|
fab!(:post) { Fabricate(:post, topic: topic, user: topic.user) }
|
|
|
|
context "with success" do
|
|
it "converts regular topic to private message" do
|
|
private_message = topic.convert_to_private_message(admin)
|
|
expect(private_message).to be_valid
|
|
expect(topic.archetype).to eq("private_message")
|
|
expect(topic.category_id).to eq(nil)
|
|
expect(category.reload.topic_count).to eq(0)
|
|
end
|
|
|
|
it "converts unlisted topic to private message" do
|
|
topic.update_status("visible", false, admin)
|
|
private_message = topic.convert_to_private_message(admin)
|
|
|
|
expect(private_message).to be_valid
|
|
expect(topic.archetype).to eq("private_message")
|
|
expect(topic.category_id).to eq(nil)
|
|
expect(topic.user.post_count).to eq(0)
|
|
expect(topic.user.topic_count).to eq(0)
|
|
expect(category.reload.topic_count).to eq(0)
|
|
end
|
|
|
|
it "updates user stats when converting topic to private message" do
|
|
_post_2 = Fabricate(:post, topic: topic, user: author)
|
|
_post_3 = Fabricate(:post, topic: topic, user: author)
|
|
|
|
other_topic = Fabricate(:post).topic
|
|
other_post = Fabricate(:post, topic: other_topic)
|
|
|
|
topic_user = TopicUser.create!(user_id: author.id, topic_id: topic.id, posted: true)
|
|
|
|
expect do topic.convert_to_private_message(admin) end.to change {
|
|
author.reload.post_count
|
|
}.from(2).to(0).and change { author.reload.topic_count }.from(1).to(0)
|
|
|
|
# Ensure query does not affect users from other topics or posts as DB query to update count is quite complex.
|
|
expect(other_topic.user.post_count).to eq(0)
|
|
expect(other_topic.user.topic_count).to eq(1)
|
|
expect(other_post.user.post_count).to eq(1)
|
|
expect(other_post.user.topic_count).to eq(0)
|
|
|
|
expect(topic.reload.topic_allowed_users.where(user_id: author.id).count).to eq(1)
|
|
expect(topic_user.reload.notification_level).to eq(TopicUser.notification_levels[:watching])
|
|
end
|
|
|
|
it "invites only users with regular posts" do
|
|
post2 = Fabricate(:post, topic: topic)
|
|
Fabricate(:post, topic: topic, post_type: Post.types[:whisper])
|
|
Fabricate(:post, topic: topic, post_type: Post.types[:small_action])
|
|
|
|
topic.convert_to_private_message(admin)
|
|
|
|
expect(topic.reload.topic_allowed_users.pluck(:user_id)).to contain_exactly(
|
|
admin.id,
|
|
post.user_id,
|
|
post2.user_id,
|
|
)
|
|
end
|
|
|
|
it "changes user_action type" do
|
|
Jobs.run_immediately!
|
|
UserActionManager.enable
|
|
topic.convert_to_private_message(admin)
|
|
expect(author.user_actions.where(action_type: UserAction::NEW_TOPIC).count).to eq(0)
|
|
expect(author.user_actions.where(action_type: UserAction::NEW_PRIVATE_MESSAGE).count).to eq(
|
|
1,
|
|
)
|
|
end
|
|
|
|
it "deletes notifications for users not allowed to see the message" do
|
|
user_notification = Fabricate(:mentioned_notification, post: post, user: Fabricate(:user))
|
|
admin_notification = Fabricate(:mentioned_notification, post: post, user: Fabricate(:admin))
|
|
|
|
Jobs.run_immediately!
|
|
topic.convert_to_private_message(admin)
|
|
|
|
expect(Notification.exists?(user_notification.id)).to eq(false)
|
|
expect(Notification.exists?(admin_notification.id)).to eq(true)
|
|
end
|
|
|
|
it "fails with an error when posters exceed max_allowed_message_recipients" do
|
|
SiteSetting.max_allowed_message_recipients = 2
|
|
Fabricate(:post, topic: topic)
|
|
Fabricate(:post, topic: topic)
|
|
|
|
result = TopicConverter.new(topic, admin).convert_to_private_message
|
|
|
|
expect(result.errors[:base]).to be_present
|
|
expect(topic.reload.archetype).to eq(Archetype.default)
|
|
end
|
|
|
|
it "creates small action and revision when not silent" do
|
|
Jobs.run_immediately!
|
|
|
|
expect do TopicConverter.new(topic, admin).convert_to_private_message end.to change {
|
|
PostRevision.count
|
|
}.by(1)
|
|
|
|
expect(
|
|
topic.posts.where(post_type: Post.types[:small_action], action_code: "private_topic"),
|
|
).to be_present
|
|
end
|
|
|
|
it "records a revision but skips small action and bump when silent" do
|
|
Jobs.run_immediately!
|
|
bumped_at = topic.bumped_at
|
|
|
|
expect do
|
|
TopicConverter.new(topic, admin, silent: true).convert_to_private_message
|
|
end.to change { PostRevision.count }.by(1)
|
|
|
|
expect(topic.first_post.revisions.last.hidden).to eq(true)
|
|
expect(topic.posts.where(post_type: Post.types[:small_action])).to be_empty
|
|
expect(topic.reload.bumped_at).to be_within(1.second).of(bumped_at)
|
|
end
|
|
|
|
it "includes the poster of a single-post topic" do
|
|
moderator = Fabricate(:moderator)
|
|
private_message = topic.convert_to_private_message(moderator)
|
|
expect(private_message.allowed_users).to match_array([topic.user, moderator])
|
|
end
|
|
end
|
|
|
|
context "when topic has replies" do
|
|
let(:replied_user) { Fabricate(:coding_horror) }
|
|
|
|
before do
|
|
create_post(topic: topic, user: replied_user)
|
|
topic.reload
|
|
end
|
|
|
|
it "adds users who replied to topic in Private Message" do
|
|
topic.convert_to_private_message(admin)
|
|
|
|
expect(topic.reload.topic_allowed_users.where(user_id: replied_user.id).count).to eq(1)
|
|
expect(topic.reload.user.user_stat.post_count).to eq(0)
|
|
end
|
|
end
|
|
|
|
context "when user already exists in topic_allowed_users table" do
|
|
before { topic.topic_allowed_users.create!(user_id: admin.id) }
|
|
|
|
it "works" do
|
|
topic.convert_to_private_message(admin)
|
|
|
|
expect(topic.reload.archetype).to eq("private_message")
|
|
end
|
|
end
|
|
|
|
context "with user_profiles with newly converted PM as featured topic" do
|
|
it "sets all matching user_profile featured topic ids to nil" do
|
|
author.user_profile.update(featured_topic: topic)
|
|
topic.convert_to_private_message(admin)
|
|
|
|
expect(author.user_profile.reload.featured_topic).to eq(nil)
|
|
end
|
|
end
|
|
end
|
|
end
|