mirror of
https://github.com/discourse/discourse.git
synced 2024-11-23 20:54:31 +08:00
800c6e1a68
Previously we would re-calculate topic_user.liked for all users who have ever viewed the source or destination topic. This can be very expensive on large sites. Instead, we can use the array of moved post ids to find which users are actually affected by the move, and restrict the update query to only check/update their records. On an example site this reduced the `update_post_action_cache` time from ~27s to 300ms
1376 lines
56 KiB
Ruby
1376 lines
56 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
describe PostMover do
|
|
fab!(:admin) { Fabricate(:admin) }
|
|
fab!(:evil_trout) { Fabricate(:evil_trout) }
|
|
|
|
describe '#move_types' do
|
|
context "verify enum sequence" do
|
|
before do
|
|
@move_types = PostMover.move_types
|
|
end
|
|
|
|
it "'new_topic' should be at 1st position" do
|
|
expect(@move_types[:new_topic]).to eq(1)
|
|
end
|
|
|
|
it "'existing_topic' should be at 2nd position" do
|
|
expect(@move_types[:existing_topic]).to eq(2)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe 'move_posts' do
|
|
context 'topics' do
|
|
before { freeze_time }
|
|
|
|
fab!(:user) { Fabricate(:user, admin: true) }
|
|
fab!(:another_user) { evil_trout }
|
|
fab!(:category) { Fabricate(:category, user: user) }
|
|
fab!(:topic) { Fabricate(:topic, user: user, created_at: 4.hours.ago) }
|
|
fab!(:p1) { Fabricate(:post, topic: topic, user: user, created_at: 3.hours.ago, reply_count: 2) }
|
|
|
|
fab!(:p2) do
|
|
Fabricate(
|
|
:post,
|
|
topic: topic,
|
|
user: another_user,
|
|
raw: "Has a link to [evil trout](http://eviltrout.com) which is a cool site.",
|
|
reply_to_post_number: p1.post_number,
|
|
reply_count: 1,
|
|
created_at: 2.hours.ago
|
|
)
|
|
end
|
|
|
|
fab!(:p3) { Fabricate(:post, topic: topic, reply_to_post_number: p1.post_number, user: user, created_at: 1.hour.ago) }
|
|
fab!(:p4) { Fabricate(:post, topic: topic, reply_to_post_number: p2.post_number, user: user, created_at: 45.minutes.ago) }
|
|
fab!(:p5) { Fabricate(:post, created_at: 30.minutes.ago) }
|
|
let(:p6) { Fabricate(:post, topic: topic, created_at: 15.minutes.ago) }
|
|
|
|
before do
|
|
SiteSetting.tagging_enabled = true
|
|
Jobs.run_immediately!
|
|
p1.replies.push(p2, p3)
|
|
p2.replies.push(p4)
|
|
UserActionManager.enable
|
|
@like = PostActionCreator.like(another_user, p4)
|
|
end
|
|
|
|
def add_moderator_post_to(topic, post_type)
|
|
topic.add_moderator_post(
|
|
user,
|
|
"message",
|
|
post_type: post_type,
|
|
action_code: "split_topic")
|
|
end
|
|
|
|
context 'success' do
|
|
|
|
it "correctly handles notifications and bread crumbs" do
|
|
old_topic = p2.topic
|
|
|
|
old_topic_id = p2.topic_id
|
|
|
|
topic.move_posts(user, [p2.id, p4.id, p6.id], title: "new testing topic name")
|
|
|
|
p2.reload
|
|
expect(p2.topic_id).not_to eq(old_topic_id)
|
|
expect(p2.reply_to_post_number).to eq(nil)
|
|
expect(p2.reply_to_user_id).to eq(nil)
|
|
|
|
notification = p2.user.notifications.where(notification_type: Notification.types[:moved_post]).first
|
|
|
|
expect(notification.topic_id).to eq(p2.topic_id)
|
|
expect(notification.topic_id).not_to eq(old_topic_id)
|
|
expect(notification.post_number).to eq(1)
|
|
|
|
# no message for person who made the move
|
|
expect(p4.user.notifications.where(notification_type: Notification.types[:moved_post]).length).to eq(0)
|
|
|
|
# notify at the right spot in the stream
|
|
notification = p6.user.notifications.where(notification_type: Notification.types[:moved_post]).first
|
|
|
|
expect(notification.topic_id).to eq(p2.topic_id)
|
|
expect(notification.topic_id).not_to eq(old_topic_id)
|
|
|
|
# this is the 3rd post we moved
|
|
expect(notification.post_number).to eq(3)
|
|
|
|
old_topic.reload
|
|
move_message = old_topic.posts.find_by(post_number: 2)
|
|
expect(move_message.post_type).to eq(Post.types[:small_action])
|
|
expect(move_message.raw).to include("3 posts were split")
|
|
end
|
|
|
|
it "correctly remaps quotes" do
|
|
raw = <<~RAW
|
|
[quote="dan, post:#{p2.post_number}, topic:#{p2.topic_id}, full:true"]
|
|
some quote from the other post
|
|
[/quote]
|
|
|
|
the quote above should be updated with new post number and topic id
|
|
RAW
|
|
|
|
p3.update!(raw: raw)
|
|
p3.rebake!
|
|
|
|
expect { topic.move_posts(user, [p2.id], title: "new testing topic name") }
|
|
.to change { p2.reload.topic_id }
|
|
.and change { p2.post_number }
|
|
.and change { p3.reload.raw }
|
|
.and change { p3.baked_version }.to nil
|
|
|
|
expect(p3.raw).to include("post:#{p2.post_number}, topic:#{p2.topic_id}")
|
|
end
|
|
end
|
|
|
|
context "errors" do
|
|
|
|
it "raises an error when one of the posts doesn't exist" do
|
|
non_existent_post_id = Post.maximum(:id)&.next || 1
|
|
expect { topic.move_posts(user, [non_existent_post_id], title: "new testing topic name") }.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
|
|
it "raises an error and does not create a topic if no posts were moved" do
|
|
Topic.count.tap do |original_topic_count|
|
|
expect {
|
|
topic.move_posts(user, [], title: "new testing topic name")
|
|
}.to raise_error(Discourse::InvalidParameters)
|
|
|
|
expect(Topic.count).to eq original_topic_count
|
|
end
|
|
end
|
|
end
|
|
|
|
context "successfully moved" do
|
|
before do
|
|
TopicUser.update_last_read(user, topic.id, p4.post_number, p4.post_number, 0)
|
|
TopicLink.extract_from(p2)
|
|
end
|
|
|
|
def create_post_timing(post, user, msecs)
|
|
PostTiming.create!(
|
|
topic_id: post.topic_id,
|
|
user_id: user.id,
|
|
post_number: post.post_number,
|
|
msecs: msecs
|
|
)
|
|
end
|
|
|
|
context "post replies" do
|
|
describe "when a post with replies is moved" do
|
|
it "should update post replies correctly" do
|
|
topic.move_posts(
|
|
user,
|
|
[p2.id],
|
|
title: 'GOT is a very addictive show', category_id: category.id
|
|
)
|
|
|
|
expect(p2.reload.replies).to eq([])
|
|
end
|
|
|
|
it "doesn't raise errors with deleted replies" do
|
|
p4.trash!
|
|
topic.move_posts(
|
|
user,
|
|
[p2.id],
|
|
title: 'GOT is a very addictive show', category_id: category.id
|
|
)
|
|
|
|
expect(p2.reload.replies).to eq([])
|
|
end
|
|
end
|
|
|
|
describe "when replies of a post have been moved" do
|
|
it "should update post replies correctly" do
|
|
p5 = Fabricate(
|
|
:post,
|
|
topic: topic,
|
|
reply_to_post_number: p2.post_number,
|
|
user: another_user
|
|
)
|
|
|
|
p2.replies << p5
|
|
|
|
topic.move_posts(
|
|
user,
|
|
[p4.id],
|
|
title: 'GOT is a very addictive show', category_id: category.id
|
|
)
|
|
|
|
expect(p2.reload.replies).to eq([p5])
|
|
end
|
|
end
|
|
|
|
describe "when only one reply is left behind" do
|
|
it "should update post replies correctly" do
|
|
p5 = Fabricate(
|
|
:post,
|
|
topic: topic,
|
|
reply_to_post_number: p2.post_number,
|
|
user: another_user
|
|
)
|
|
|
|
p2.replies << p5
|
|
|
|
topic.move_posts(
|
|
user,
|
|
[p2.id, p4.id],
|
|
title: 'GOT is a very addictive show', category_id: category.id
|
|
)
|
|
|
|
expect(p2.reload.replies).to eq([p4])
|
|
end
|
|
end
|
|
end
|
|
|
|
context "to a new topic" do
|
|
it "works correctly" do
|
|
topic.expects(:add_moderator_post).once
|
|
new_topic = topic.move_posts(user, [p2.id, p4.id], title: "new testing topic name", category_id: category.id, tags: ["tag1", "tag2"])
|
|
|
|
expect(TopicUser.find_by(user_id: user.id, topic_id: topic.id).last_read_post_number).to eq(p3.post_number)
|
|
|
|
expect(new_topic).to be_present
|
|
expect(new_topic.featured_user1_id).to eq(p4.user_id)
|
|
expect(new_topic.like_count).to eq(1)
|
|
|
|
expect(new_topic.category).to eq(category)
|
|
expect(new_topic.tags.pluck(:name)).to contain_exactly("tag1", "tag2")
|
|
expect(topic.featured_user1_id).to be_blank
|
|
expect(new_topic.posts.by_post_number).to match_array([p2, p4])
|
|
|
|
new_topic.reload
|
|
expect(new_topic.posts_count).to eq(2)
|
|
expect(new_topic.highest_post_number).to eq(2)
|
|
|
|
p4.reload
|
|
expect(new_topic.last_post_user_id).to eq(p4.user_id)
|
|
expect(new_topic.last_posted_at).to eq_time(p4.created_at)
|
|
expect(new_topic.bumped_at).to eq_time(Time.zone.now)
|
|
|
|
p2.reload
|
|
expect(p2.sort_order).to eq(1)
|
|
expect(p2.post_number).to eq(1)
|
|
expect(p2.topic_links.first.topic_id).to eq(new_topic.id)
|
|
|
|
expect(p4.post_number).to eq(2)
|
|
expect(p4.sort_order).to eq(2)
|
|
|
|
topic.reload
|
|
expect(topic.featured_user1_id).to be_blank
|
|
expect(topic.like_count).to eq(0)
|
|
expect(topic.posts_count).to eq(2)
|
|
expect(topic.posts.by_post_number).to match_array([p1, p3])
|
|
expect(topic.highest_post_number).to eq(p3.post_number)
|
|
|
|
# both the like and was_liked user actions should be correct
|
|
action = UserAction.find_by(user_id: another_user.id)
|
|
expect(action.target_topic_id).to eq(new_topic.id)
|
|
|
|
expect(TopicUser.exists?(
|
|
user_id: another_user,
|
|
topic_id: new_topic.id,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
notifications_reason_id: TopicUser.notification_reasons[:created_topic]
|
|
)).to eq(true)
|
|
expect(TopicUser.exists?(user_id: user, topic_id: new_topic.id)).to eq(true)
|
|
end
|
|
|
|
it "moving all posts will close the topic" do
|
|
topic.expects(:add_moderator_post).twice
|
|
new_topic = topic.move_posts(user, [p1.id, p2.id, p3.id, p4.id], title: "new testing topic name", category_id: category.id)
|
|
expect(new_topic).to be_present
|
|
|
|
topic.reload
|
|
expect(topic.closed).to eq(true)
|
|
end
|
|
|
|
it 'does not move posts that do not belong to the existing topic' do
|
|
new_topic = topic.move_posts(
|
|
user, [p2.id, p3.id, p5.id], title: 'Logan is a pretty good movie'
|
|
)
|
|
|
|
expect(new_topic.posts.pluck(:id).sort).to eq([p2.id, p3.id].sort)
|
|
end
|
|
|
|
it "uses default locale for moderator post" do
|
|
I18n.locale = 'de'
|
|
|
|
new_topic = topic.move_posts(user, [p2.id, p4.id], title: "new testing topic name", category_id: category.id)
|
|
post = Post.find_by(topic_id: topic.id, post_type: Post.types[:small_action])
|
|
|
|
expected_text = I18n.with_locale(:en) do
|
|
I18n.t("move_posts.new_topic_moderator_post",
|
|
count: 2,
|
|
topic_link: "[#{new_topic.title}](#{new_topic.relative_url})")
|
|
end
|
|
|
|
expect(post.raw).to eq(expected_text)
|
|
end
|
|
|
|
it "does not try to move small action posts" do
|
|
small_action = Fabricate(:post, topic: topic, raw: "A small action", post_type: Post.types[:small_action])
|
|
hidden_small_action = Fabricate(:post, topic: topic, post_type: Post.types[:whisper])
|
|
hidden_small_action.update_attribute(:raw, "")
|
|
new_topic = topic.move_posts(user, [p2.id, p4.id, small_action.id, hidden_small_action.id], title: "new testing topic name", category_id: category.id)
|
|
|
|
expect(new_topic.posts_count).to eq(2)
|
|
expect(small_action.topic_id).to eq(topic.id)
|
|
expect(hidden_small_action.topic_id).to eq(topic.id)
|
|
|
|
moderator_post = topic.posts.last
|
|
expect(moderator_post.raw).to include("2 posts were split")
|
|
end
|
|
|
|
it "forces resulting topic owner to watch the new topic" do
|
|
new_topic = topic.move_posts(user, [p2.id, p4.id], title: "new testing topic name", category_id: category.id)
|
|
|
|
expect(new_topic.posts_count).to eq(2)
|
|
|
|
expect(TopicUser.exists?(
|
|
user_id: another_user,
|
|
topic_id: new_topic.id,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
notifications_reason_id: TopicUser.notification_reasons[:created_topic]
|
|
)).to eq(true)
|
|
end
|
|
|
|
it "updates existing notifications" do
|
|
n3 = Fabricate(:mentioned_notification, post: p3, user: another_user)
|
|
n4 = Fabricate(:mentioned_notification, post: p4, user: another_user)
|
|
|
|
new_topic = topic.move_posts(user, [p3.id], title: "new testing topic name")
|
|
|
|
n3 = Notification.find(n3.id)
|
|
expect(n3.topic_id).to eq(new_topic.id)
|
|
expect(n3.post_number).to eq(1)
|
|
expect(n3.data_hash[:topic_title]).to eq(new_topic.title)
|
|
|
|
n4 = Notification.find(n4.id)
|
|
expect(n4.topic_id).to eq(topic.id)
|
|
expect(n4.post_number).to eq(4)
|
|
end
|
|
|
|
it "doesn't update notifications of type 'watching_first_post'" do
|
|
n1 = Fabricate(:watching_first_post_notification, post: p1, user: another_user)
|
|
|
|
topic.move_posts(user, [p1.id], title: "new testing topic name")
|
|
|
|
n1 = Notification.find(n1.id)
|
|
expect(n1.topic_id).to eq(topic.id)
|
|
expect(n1.data_hash[:topic_title]).to eq(topic.title)
|
|
expect(n1.post_number).to eq(1)
|
|
end
|
|
|
|
it "deletes notifications for users not allowed to see the topic" do
|
|
another_admin = Fabricate(:admin)
|
|
staff_category = Fabricate(:private_category, group: Group[:staff])
|
|
user_notification = Fabricate(:mentioned_notification, post: p3, user: another_user)
|
|
admin_notification = Fabricate(:mentioned_notification, post: p3, user: another_admin)
|
|
|
|
topic.move_posts(user, [p3.id], title: "new testing topic name", category_id: staff_category.id)
|
|
|
|
expect(Notification.exists?(user_notification.id)).to eq(false)
|
|
expect(Notification.exists?(admin_notification.id)).to eq(true)
|
|
end
|
|
|
|
it "moves post timings" do
|
|
some_user = Fabricate(:user)
|
|
create_post_timing(p1, some_user, 500)
|
|
create_post_timing(p2, some_user, 1000)
|
|
create_post_timing(p3, some_user, 1500)
|
|
create_post_timing(p4, some_user, 750)
|
|
|
|
new_topic = topic.move_posts(user, [p1.id, p4.id], title: "new testing topic name")
|
|
|
|
expect(PostTiming.where(topic_id: topic.id, user_id: some_user.id).pluck(:post_number, :msecs))
|
|
.to contain_exactly([1, 500], [2, 1000], [3, 1500])
|
|
|
|
expect(PostTiming.where(topic_id: new_topic.id, user_id: some_user.id).pluck(:post_number, :msecs))
|
|
.to contain_exactly([1, 500], [2, 750])
|
|
end
|
|
|
|
it "updates bookmark topic_ids to the new topic id and does not affect bookmarks for posts not moving" do
|
|
some_user = Fabricate(:user)
|
|
new_post = Fabricate(:post, topic: p1.topic)
|
|
bookmark1 = Fabricate(:bookmark, topic: p1.topic, post: p1, user: some_user)
|
|
bookmark2 = Fabricate(:bookmark, topic: p4.topic, post: p4)
|
|
bookmark3 = Fabricate(:bookmark, topic: p4.topic, post: p4)
|
|
bookmark4 = Fabricate(:bookmark, topic: new_post.topic, post: new_post)
|
|
new_topic = topic.move_posts(user, [p1.id, p4.id], title: "new testing topic name")
|
|
expect(bookmark1.reload.topic_id).to eq(new_topic.id)
|
|
expect(bookmark2.reload.topic_id).to eq(new_topic.id)
|
|
expect(bookmark3.reload.topic_id).to eq(new_topic.id)
|
|
expect(bookmark4.reload.topic_id).to eq(new_post.topic_id)
|
|
end
|
|
|
|
it "makes sure the topic_user.bookmarked value is reflected for users in the source and destination topic" do
|
|
Jobs.run_immediately!
|
|
user1 = Fabricate(:user)
|
|
user2 = Fabricate(:user)
|
|
|
|
bookmark1 = Fabricate(:bookmark, topic: p1.topic, post: p1, user: user1)
|
|
bookmark2 = Fabricate(:bookmark, topic: p4.topic, post: p4, user: user1)
|
|
|
|
bookmark3 = Fabricate(:bookmark, topic: p3.topic, post: p3, user: user2)
|
|
bookmark4 = Fabricate(:bookmark, topic: p4.topic, post: p4, user: user2)
|
|
|
|
tu1 = Fabricate(
|
|
:topic_user,
|
|
user: user1,
|
|
topic: p1.topic,
|
|
bookmarked: true,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
last_read_post_number: 4,
|
|
last_emailed_post_number: 3
|
|
)
|
|
tu2 = Fabricate(
|
|
:topic_user,
|
|
user: user2,
|
|
topic: p1.topic,
|
|
bookmarked: true,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
last_read_post_number: 4,
|
|
last_emailed_post_number: 3
|
|
)
|
|
|
|
new_topic = topic.move_posts(user, [p1.id, p4.id], title: "new testing topic name")
|
|
new_topic_user1 = TopicUser.find_by(topic: new_topic, user: user1)
|
|
new_topic_user2 = TopicUser.find_by(topic: new_topic, user: user2)
|
|
|
|
expect(tu1.reload.bookmarked).to eq(false)
|
|
expect(tu2.reload.bookmarked).to eq(true)
|
|
expect(new_topic_user1.bookmarked).to eq(true)
|
|
expect(new_topic_user2.bookmarked).to eq(true)
|
|
end
|
|
|
|
context "read state and other stats per user" do
|
|
def create_topic_user(user, opts = {})
|
|
notification_level = opts.delete(:notification_level) || :regular
|
|
|
|
Fabricate(:topic_user, opts.merge(
|
|
notification_level: TopicUser.notification_levels[notification_level],
|
|
topic: topic,
|
|
user: user
|
|
))
|
|
end
|
|
|
|
fab!(:user1) { Fabricate(:user) }
|
|
fab!(:user2) { Fabricate(:user) }
|
|
fab!(:user3) { Fabricate(:user) }
|
|
fab!(:admin1) { Fabricate(:admin) }
|
|
fab!(:admin2) { Fabricate(:admin) }
|
|
|
|
it "correctly moves topic_user records" do
|
|
create_topic_user(
|
|
user1,
|
|
last_read_post_number: 4,
|
|
last_emailed_post_number: 3,
|
|
notification_level: :tracking
|
|
)
|
|
create_topic_user(
|
|
user2,
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 2,
|
|
notification_level: :tracking
|
|
)
|
|
create_topic_user(
|
|
user3,
|
|
last_read_post_number: 1,
|
|
last_emailed_post_number: 4,
|
|
notification_level: :watching
|
|
)
|
|
|
|
p2.update!(user_id: user2.id)
|
|
new_topic = topic.move_posts(user, [p1.id, p2.id], title: "new testing topic name")
|
|
|
|
expect(TopicUser.where(topic_id: topic.id).count).to eq(4)
|
|
expect(TopicUser.find_by(topic: topic, user: user))
|
|
.to have_attributes(
|
|
last_read_post_number: 4,
|
|
last_emailed_post_number: nil,
|
|
notification_level: TopicUser.notification_levels[:tracking]
|
|
)
|
|
expect(TopicUser.find_by(topic: topic, user: user1))
|
|
.to have_attributes(
|
|
last_read_post_number: 4,
|
|
last_emailed_post_number: 3,
|
|
notification_level: TopicUser.notification_levels[:tracking]
|
|
)
|
|
expect(TopicUser.find_by(topic: topic, user: user2))
|
|
.to have_attributes(
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 2,
|
|
notification_level: TopicUser.notification_levels[:tracking]
|
|
)
|
|
expect(TopicUser.find_by(topic: topic, user: user3))
|
|
.to have_attributes(
|
|
last_read_post_number: 1,
|
|
last_emailed_post_number: 4,
|
|
notification_level: TopicUser.notification_levels[:watching]
|
|
)
|
|
|
|
expect(TopicUser.where(topic_id: new_topic.id).count).to eq(4)
|
|
expect(TopicUser.find_by(topic: new_topic, user: user))
|
|
.to have_attributes(
|
|
last_read_post_number: 1,
|
|
last_emailed_post_number: nil,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
posted: true
|
|
)
|
|
expect(TopicUser.find_by(topic: new_topic, user: user1))
|
|
.to have_attributes(
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 2,
|
|
notification_level: TopicUser.notification_levels[:tracking],
|
|
posted: false
|
|
)
|
|
expect(TopicUser.find_by(topic: new_topic, user: user2))
|
|
.to have_attributes(
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 2,
|
|
notification_level: TopicUser.notification_levels[:tracking],
|
|
posted: true
|
|
)
|
|
expect(TopicUser.find_by(topic: new_topic, user: user3))
|
|
.to have_attributes(
|
|
last_read_post_number: 1,
|
|
last_emailed_post_number: 2,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
posted: false
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "to an existing topic" do
|
|
fab!(:destination_topic) { Fabricate(:topic, user: another_user) }
|
|
fab!(:destination_op) { Fabricate(:post, topic: destination_topic, user: another_user, created_at: 1.day.ago) }
|
|
|
|
it "works correctly" do
|
|
topic.expects(:add_moderator_post).once
|
|
moved_to = topic.move_posts(user, [p2.id, p4.id], destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to eq(destination_topic)
|
|
|
|
# Check out new topic
|
|
moved_to.reload
|
|
expect(moved_to.posts_count).to eq(3)
|
|
expect(moved_to.highest_post_number).to eq(3)
|
|
expect(moved_to.user_id).to eq(destination_op.user_id)
|
|
expect(moved_to.like_count).to eq(1)
|
|
expect(moved_to.category_id).to eq(SiteSetting.uncategorized_category_id)
|
|
p4.reload
|
|
expect(moved_to.last_post_user_id).to eq(p4.user_id)
|
|
expect(moved_to.last_posted_at).to eq_time(p4.created_at)
|
|
expect(moved_to.bumped_at).to eq_time(Time.zone.now)
|
|
|
|
# Posts should be re-ordered
|
|
p2.reload
|
|
expect(p2.sort_order).to eq(2)
|
|
expect(p2.post_number).to eq(2)
|
|
expect(p2.topic_id).to eq(moved_to.id)
|
|
expect(p2.reply_count).to eq(1)
|
|
expect(p2.reply_to_post_number).to eq(nil)
|
|
|
|
expect(p4.post_number).to eq(3)
|
|
expect(p4.sort_order).to eq(3)
|
|
expect(p4.topic_id).to eq(moved_to.id)
|
|
expect(p4.reply_count).to eq(0)
|
|
expect(p4.reply_to_post_number).to eq(2)
|
|
|
|
# Check out the original topic
|
|
topic.reload
|
|
expect(topic.posts_count).to eq(2)
|
|
expect(topic.highest_post_number).to eq(3)
|
|
expect(topic.featured_user1_id).to be_blank
|
|
expect(topic.like_count).to eq(0)
|
|
expect(topic.posts_count).to eq(2)
|
|
expect(topic.posts.by_post_number).to match_array([p1, p3])
|
|
expect(topic.highest_post_number).to eq(p3.post_number)
|
|
|
|
# Should notify correctly
|
|
notification = p2.user.notifications.where(notification_type: Notification.types[:moved_post]).first
|
|
|
|
expect(notification.topic_id).to eq(destination_topic.id)
|
|
expect(notification.post_number).to eq(p2.post_number)
|
|
|
|
# Should update last reads
|
|
expect(TopicUser.find_by(user_id: user.id, topic_id: topic.id).last_read_post_number).to eq(p3.post_number)
|
|
end
|
|
|
|
it "moving all posts will close the topic" do
|
|
topic.expects(:add_moderator_post).twice
|
|
posts_to_move = [p1.id, p2.id, p3.id, p4.id]
|
|
moved_to = topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
topic.reload
|
|
expect(topic).to be_closed
|
|
end
|
|
|
|
it "doesn't close the topic when not all posts were moved" do
|
|
topic.expects(:add_moderator_post).once
|
|
posts_to_move = [p2.id, p3.id]
|
|
moved_to = topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
topic.reload
|
|
expect(topic).to_not be_closed
|
|
end
|
|
|
|
it "doesn't close the topic when all posts except the first one were moved" do
|
|
topic.expects(:add_moderator_post).once
|
|
posts_to_move = [p2.id, p3.id, p4.id]
|
|
moved_to = topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
topic.reload
|
|
expect(topic).to_not be_closed
|
|
end
|
|
|
|
it "schedules topic deleting when all posts were moved" do
|
|
SiteSetting.delete_merged_stub_topics_after_days = 7
|
|
freeze_time
|
|
|
|
topic.expects(:add_moderator_post).twice
|
|
posts_to_move = [p1.id, p2.id, p3.id, p4.id]
|
|
moved_to = topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
timer = topic.topic_timers.find_by(status_type: TopicTimer.types[:delete])
|
|
expect(timer).to be_present
|
|
expect(timer.execute_at).to eq_time(7.days.from_now)
|
|
end
|
|
|
|
it "doesn't schedule topic deleting when not all posts were moved" do
|
|
SiteSetting.delete_merged_stub_topics_after_days = 7
|
|
|
|
topic.expects(:add_moderator_post).once
|
|
posts_to_move = [p1.id, p2.id, p3.id]
|
|
moved_to = topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
timer = topic.topic_timers.find_by(status_type: TopicTimer.types[:delete])
|
|
expect(timer).to be_nil
|
|
end
|
|
|
|
it "doesn't schedule topic deleting when all posts were moved if it's disabled in settings" do
|
|
SiteSetting.delete_merged_stub_topics_after_days = 0
|
|
|
|
topic.expects(:add_moderator_post).twice
|
|
posts_to_move = [p1.id, p2.id, p3.id, p4.id]
|
|
moved_to = topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
timer = topic.topic_timers.find_by(status_type: TopicTimer.types[:delete])
|
|
expect(timer).to be_nil
|
|
end
|
|
|
|
it "ignores moderator posts and closes the topic if all regular posts were moved" do
|
|
add_moderator_post_to topic, Post.types[:moderator_action]
|
|
add_moderator_post_to topic, Post.types[:small_action]
|
|
|
|
posts_to_move = [p1.id, p2.id, p3.id, p4.id]
|
|
topic.move_posts(user, posts_to_move, destination_topic_id: destination_topic.id)
|
|
|
|
topic.reload
|
|
expect(topic).to be_closed
|
|
end
|
|
|
|
it "does not try to move small action posts" do
|
|
small_action = Fabricate(:post, topic: topic, raw: "A small action", post_type: Post.types[:small_action])
|
|
moved_to = topic.move_posts(user, [p1.id, p2.id, p3.id, p4.id, small_action.id], destination_topic_id: destination_topic.id)
|
|
|
|
moved_to.reload
|
|
expect(moved_to.posts_count).to eq(5)
|
|
expect(small_action.topic_id).to eq(topic.id)
|
|
|
|
moderator_post = topic.posts.find_by(post_number: 2)
|
|
expect(moderator_post.raw).to include("4 posts were merged")
|
|
end
|
|
|
|
it "updates existing notifications" do
|
|
n3 = Fabricate(:mentioned_notification, post: p3, user: another_user)
|
|
n4 = Fabricate(:mentioned_notification, post: p4, user: another_user)
|
|
|
|
moved_to = topic.move_posts(user, [p3.id], destination_topic_id: destination_topic.id)
|
|
|
|
n3 = Notification.find(n3.id)
|
|
expect(n3.topic_id).to eq(moved_to.id)
|
|
expect(n3.post_number).to eq(2)
|
|
expect(n3.data_hash[:topic_title]).to eq(moved_to.title)
|
|
|
|
n4 = Notification.find(n4.id)
|
|
expect(n4.topic_id).to eq(topic.id)
|
|
expect(n4.post_number).to eq(4)
|
|
end
|
|
|
|
it "deletes notifications for users not allowed to see the topic" do
|
|
another_admin = Fabricate(:admin)
|
|
staff_category = Fabricate(:private_category, group: Group[:staff])
|
|
user_notification = Fabricate(:mentioned_notification, post: p3, user: another_user)
|
|
admin_notification = Fabricate(:mentioned_notification, post: p3, user: another_admin)
|
|
|
|
destination_topic.update!(category_id: staff_category.id)
|
|
topic.move_posts(user, [p3.id], destination_topic_id: destination_topic.id)
|
|
|
|
expect(Notification.exists?(user_notification.id)).to eq(false)
|
|
expect(Notification.exists?(admin_notification.id)).to eq(true)
|
|
end
|
|
|
|
it "updates bookmark topic_ids to the new topic id and does not affect bookmarks for posts not moving" do
|
|
some_user = Fabricate(:user)
|
|
new_post = Fabricate(:post, topic: p3.topic)
|
|
bookmark1 = Fabricate(:bookmark, topic: p3.topic, post: p3, user: some_user)
|
|
bookmark2 = Fabricate(:bookmark, topic: p3.topic, post: p3)
|
|
bookmark3 = Fabricate(:bookmark, topic: p3.topic, post: p3)
|
|
bookmark4 = Fabricate(:bookmark, topic: new_post.topic, post: new_post)
|
|
topic.move_posts(user, [p3.id], destination_topic_id: destination_topic.id)
|
|
expect(bookmark1.reload.topic_id).to eq(destination_topic.id)
|
|
expect(bookmark2.reload.topic_id).to eq(destination_topic.id)
|
|
expect(bookmark3.reload.topic_id).to eq(destination_topic.id)
|
|
expect(bookmark4.reload.topic_id).to eq(new_post.topic_id)
|
|
end
|
|
|
|
context "post timings" do
|
|
fab!(:some_user) { Fabricate(:user) }
|
|
|
|
it "successfully moves timings" do
|
|
create_post_timing(p1, some_user, 500)
|
|
create_post_timing(p2, some_user, 1000)
|
|
create_post_timing(p3, some_user, 1500)
|
|
create_post_timing(p4, some_user, 750)
|
|
|
|
moved_to = topic.move_posts(user, [p1.id, p4.id], destination_topic_id: destination_topic.id)
|
|
|
|
expect(PostTiming.where(topic_id: topic.id, user_id: some_user.id).pluck(:post_number, :msecs))
|
|
.to contain_exactly([1, 500], [2, 1000], [3, 1500])
|
|
|
|
expect(PostTiming.where(topic_id: moved_to.id, user_id: some_user.id).pluck(:post_number, :msecs))
|
|
.to contain_exactly([2, 500], [3, 750])
|
|
end
|
|
|
|
it "moves timings when post timing exists in destination topic" do
|
|
PostTiming.create!(
|
|
topic_id: destination_topic.id,
|
|
user_id: some_user.id,
|
|
post_number: 2,
|
|
msecs: 800
|
|
)
|
|
create_post_timing(p1, some_user, 500)
|
|
|
|
moved_to = topic.move_posts(user, [p1.id], destination_topic_id: destination_topic.id)
|
|
|
|
expect(PostTiming.where(topic_id: moved_to.id, user_id: some_user.id).pluck(:post_number, :msecs))
|
|
.to contain_exactly([2, 500])
|
|
end
|
|
end
|
|
|
|
it "updates topic_user.liked values for both source and destination topics" do
|
|
expect(TopicUser.find_by(topic: topic, user: user).liked).to eq(false)
|
|
|
|
like = Fabricate(:post_action, post: p3, user: user, post_action_type_id: PostActionType.types[:like])
|
|
expect(TopicUser.find_by(topic: topic, user: user).liked).to eq(true)
|
|
|
|
expect(TopicUser.find_by(topic: destination_topic, user: user)).to eq(nil)
|
|
topic.move_posts(user, [p3.id], destination_topic_id: destination_topic.id)
|
|
|
|
expect(TopicUser.find_by(topic: topic, user: user).liked).to eq(false)
|
|
expect(TopicUser.find_by(topic: destination_topic, user: user).liked).to eq(true)
|
|
end
|
|
|
|
context "read state and other stats per user" do
|
|
def create_topic_user(user, topic, opts = {})
|
|
notification_level = opts.delete(:notification_level) || :regular
|
|
|
|
Fabricate(:topic_user, opts.merge(
|
|
notification_level: TopicUser.notification_levels[notification_level],
|
|
topic: topic,
|
|
user: user
|
|
))
|
|
end
|
|
|
|
fab!(:user1) { Fabricate(:user) }
|
|
fab!(:user2) { Fabricate(:user) }
|
|
fab!(:user3) { Fabricate(:user) }
|
|
fab!(:admin1) { Fabricate(:admin) }
|
|
fab!(:admin2) { Fabricate(:admin) }
|
|
|
|
it "leaves post numbers unchanged when they were lower then the topic's highest post number" do
|
|
Fabricate(:post, topic: destination_topic)
|
|
Fabricate(:whisper, topic: destination_topic)
|
|
|
|
destination_topic.reload
|
|
expect(destination_topic.highest_post_number).to eq(2)
|
|
expect(destination_topic.highest_staff_post_number).to eq(3)
|
|
|
|
create_topic_user(
|
|
user1, topic,
|
|
last_read_post_number: 3,
|
|
last_emailed_post_number: 3
|
|
)
|
|
create_topic_user(
|
|
user1, destination_topic,
|
|
last_read_post_number: 1,
|
|
last_emailed_post_number: 1
|
|
)
|
|
|
|
create_topic_user(
|
|
user2, topic,
|
|
last_read_post_number: 3,
|
|
last_emailed_post_number: 3
|
|
)
|
|
create_topic_user(
|
|
user2, destination_topic,
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 2
|
|
)
|
|
|
|
create_topic_user(
|
|
admin1, topic,
|
|
last_read_post_number: 3,
|
|
last_emailed_post_number: 3
|
|
)
|
|
create_topic_user(
|
|
admin1, destination_topic,
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 1
|
|
)
|
|
|
|
create_topic_user(
|
|
admin2, topic,
|
|
last_read_post_number: 3,
|
|
last_emailed_post_number: 3
|
|
)
|
|
create_topic_user(
|
|
admin2, destination_topic,
|
|
last_read_post_number: 3,
|
|
last_emailed_post_number: 3
|
|
)
|
|
|
|
moved_to_topic = topic.move_posts(user, [p1.id, p2.id], destination_topic_id: destination_topic.id)
|
|
|
|
expect(TopicUser.find_by(topic: moved_to_topic, user: user1))
|
|
.to have_attributes(
|
|
last_read_post_number: 1,
|
|
last_emailed_post_number: 1
|
|
)
|
|
|
|
expect(TopicUser.find_by(topic: moved_to_topic, user: user2))
|
|
.to have_attributes(
|
|
last_read_post_number: 5,
|
|
last_emailed_post_number: 5
|
|
)
|
|
|
|
expect(TopicUser.find_by(topic: moved_to_topic, user: admin1))
|
|
.to have_attributes(
|
|
last_read_post_number: 2,
|
|
last_emailed_post_number: 1
|
|
)
|
|
|
|
expect(TopicUser.find_by(topic: moved_to_topic, user: admin2))
|
|
.to have_attributes(
|
|
last_read_post_number: 5,
|
|
last_emailed_post_number: 5
|
|
)
|
|
end
|
|
|
|
it "correctly updates existing topic_user records" do
|
|
destination_topic.update!(created_at: 1.day.ago)
|
|
|
|
original_topic_user1 = create_topic_user(
|
|
user1, topic,
|
|
last_read_post_number: 5,
|
|
first_visited_at: 5.hours.ago,
|
|
last_visited_at: 30.minutes.ago,
|
|
notification_level: :tracking
|
|
).reload
|
|
destination_topic_user1 = create_topic_user(
|
|
user1, destination_topic,
|
|
last_read_post_number: 5,
|
|
first_visited_at: 7.hours.ago,
|
|
last_visited_at: 2.hours.ago,
|
|
notification_level: :watching
|
|
).reload
|
|
|
|
original_topic_user2 = create_topic_user(
|
|
user2, topic,
|
|
last_read_post_number: 5,
|
|
first_visited_at: 3.hours.ago,
|
|
last_visited_at: 1.hour.ago,
|
|
notification_level: :watching
|
|
).reload
|
|
destination_topic_user2 = create_topic_user(
|
|
user2, destination_topic,
|
|
last_read_post_number: 5,
|
|
first_visited_at: 2.hours.ago,
|
|
last_visited_at: 1.hour.ago,
|
|
notification_level: :tracking
|
|
).reload
|
|
|
|
new_topic = topic.move_posts(user, [p1.id, p2.id], destination_topic_id: destination_topic.id)
|
|
|
|
expect(TopicUser.find_by(topic: new_topic, user: user))
|
|
.to have_attributes(
|
|
notification_level: TopicUser.notification_levels[:tracking],
|
|
posted: true
|
|
)
|
|
|
|
expect(TopicUser.find_by(topic: new_topic, user: user1))
|
|
.to have_attributes(
|
|
first_visited_at: destination_topic_user1.first_visited_at,
|
|
last_visited_at: original_topic_user1.last_visited_at,
|
|
notification_level: destination_topic_user1.notification_level,
|
|
posted: false
|
|
)
|
|
|
|
expect(TopicUser.find_by(topic: new_topic, user: user2))
|
|
.to have_attributes(
|
|
first_visited_at: original_topic_user2.first_visited_at,
|
|
last_visited_at: destination_topic_user2.last_visited_at,
|
|
notification_level: destination_topic_user2.notification_level,
|
|
posted: false
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
context "to a message" do
|
|
|
|
it "works correctly" do
|
|
topic.expects(:add_moderator_post).once
|
|
new_topic = topic.move_posts(user, [p2.id, p4.id], title: "new testing topic name", archetype: "private_message")
|
|
|
|
expect(TopicUser.find_by(user_id: user.id, topic_id: topic.id).last_read_post_number).to eq(p3.post_number)
|
|
|
|
expect(new_topic).to be_present
|
|
expect(new_topic.featured_user1_id).to eq(p4.user_id)
|
|
expect(new_topic.like_count).to eq(1)
|
|
|
|
expect(new_topic.archetype).to eq(Archetype.private_message)
|
|
expect(topic.featured_user1_id).to be_blank
|
|
expect(new_topic.posts.by_post_number).to match_array([p2, p4])
|
|
|
|
new_topic.reload
|
|
expect(new_topic.posts_count).to eq(2)
|
|
expect(new_topic.highest_post_number).to eq(2)
|
|
|
|
p4.reload
|
|
expect(new_topic.last_post_user_id).to eq(p4.user_id)
|
|
expect(new_topic.last_posted_at).to eq_time(p4.created_at)
|
|
expect(new_topic.bumped_at).to eq_time(Time.zone.now)
|
|
|
|
p2.reload
|
|
expect(p2.sort_order).to eq(1)
|
|
expect(p2.post_number).to eq(1)
|
|
expect(p2.topic_links.first.topic_id).to eq(new_topic.id)
|
|
|
|
expect(p4.post_number).to eq(2)
|
|
expect(p4.sort_order).to eq(2)
|
|
|
|
topic.reload
|
|
expect(topic.featured_user1_id).to be_blank
|
|
expect(topic.like_count).to eq(0)
|
|
expect(topic.posts_count).to eq(2)
|
|
expect(topic.posts.by_post_number).to match_array([p1, p3])
|
|
expect(topic.highest_post_number).to eq(p3.post_number)
|
|
|
|
# both the like and was_liked user actions should be correct
|
|
action = UserAction.find_by(user_id: another_user.id)
|
|
expect(action.target_topic_id).to eq(new_topic.id)
|
|
|
|
expect(TopicUser.exists?(
|
|
user_id: another_user,
|
|
topic_id: new_topic.id,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
notifications_reason_id: TopicUser.notification_reasons[:created_topic]
|
|
)).to eq(true)
|
|
expect(TopicUser.exists?(
|
|
user_id: user,
|
|
topic_id: new_topic.id,
|
|
notification_level: TopicUser.notification_levels[:watching],
|
|
notifications_reason_id: TopicUser.notification_reasons[:created_post]
|
|
)).to eq(true)
|
|
end
|
|
|
|
end
|
|
|
|
shared_examples "moves email related stuff" do
|
|
it "moves incoming email" do
|
|
Fabricate(:incoming_email, user: old_post.user, topic: old_post.topic, post: old_post)
|
|
|
|
new_topic = topic.move_posts(user, [old_post.id], title: "new testing topic name")
|
|
new_post = new_topic.first_post
|
|
email = new_post.incoming_email
|
|
|
|
expect(email).to be_present
|
|
expect(email.topic_id).to eq(new_topic.id)
|
|
expect(email.post_id).to eq(new_post.id)
|
|
|
|
expect(old_post.reload.incoming_email).to_not be_present unless old_post.id == new_post.id
|
|
end
|
|
|
|
it "moves email log entries" do
|
|
old_topic = old_post.topic
|
|
|
|
2.times do
|
|
Fabricate(:email_log,
|
|
user: old_post.user,
|
|
post: old_post,
|
|
email_type: :mailing_list
|
|
)
|
|
end
|
|
|
|
some_post = Fabricate(:post)
|
|
|
|
Fabricate(:email_log,
|
|
user: some_post.user,
|
|
post: some_post,
|
|
email_type: :mailing_list
|
|
)
|
|
|
|
expect(EmailLog.where(post_id: old_post.id).count).to eq(2)
|
|
|
|
new_topic = old_topic.move_posts(
|
|
user,
|
|
[old_post.id],
|
|
title: "new testing topic name"
|
|
)
|
|
|
|
new_post = new_topic.first_post
|
|
|
|
expect(EmailLog.where(post_id: new_post.id).count).to eq(2)
|
|
end
|
|
|
|
it "preserves post attributes" do
|
|
old_post.update_columns(cook_method: Post.cook_methods[:email], via_email: true, raw_email: "raw email content")
|
|
|
|
new_topic = old_post.topic.move_posts(user, [old_post.id], title: "new testing topic name")
|
|
new_post = new_topic.first_post
|
|
|
|
expect(new_post.cook_method).to eq(Post.cook_methods[:email])
|
|
expect(new_post.via_email).to eq(true)
|
|
expect(new_post.raw_email).to eq("raw email content")
|
|
end
|
|
end
|
|
|
|
context "moving the first post" do
|
|
it "copies the OP, doesn't delete it" do
|
|
topic.expects(:add_moderator_post).once
|
|
new_topic = topic.move_posts(user, [p1.id, p2.id], title: "new testing topic name")
|
|
|
|
expect(new_topic).to be_present
|
|
expect(new_topic.posts.by_post_number.first.raw).to eq(p1.raw)
|
|
expect(new_topic.posts_count).to eq(2)
|
|
expect(new_topic.highest_post_number).to eq(2)
|
|
|
|
# First post didn't move
|
|
p1.reload
|
|
expect(p1.sort_order).to eq(1)
|
|
expect(p1.post_number).to eq(1)
|
|
expect(p1.topic_id).to eq(topic.id)
|
|
expect(p1.reply_count).to eq(1)
|
|
|
|
# New first post
|
|
new_first = new_topic.posts.where(post_number: 1).first
|
|
expect(new_first.reply_count).to eq(1)
|
|
expect(new_first.created_at).to eq_time(p1.created_at)
|
|
|
|
# Second post is in a new topic
|
|
p2.reload
|
|
expect(p2.post_number).to eq(2)
|
|
expect(p2.sort_order).to eq(2)
|
|
expect(p2.topic_id).to eq(new_topic.id)
|
|
expect(p2.reply_to_post_number).to eq(1)
|
|
expect(p2.reply_count).to eq(0)
|
|
|
|
topic.reload
|
|
expect(topic.posts.by_post_number).to match_array([p1, p3, p4])
|
|
expect(topic.highest_post_number).to eq(p4.post_number)
|
|
|
|
# updates replies for posts moved to same topic
|
|
expect(PostReply.where(reply_post_id: p2.id).pluck(:post_id)).to contain_exactly(new_first.id)
|
|
|
|
# leaves replies to the first post of the original topic unchanged
|
|
expect(PostReply.where(reply_post_id: p3.id).pluck(:post_id)).to contain_exactly(p1.id)
|
|
end
|
|
|
|
it "preserves post actions in the new post" do
|
|
PostActionCreator.like(another_user, p1)
|
|
|
|
new_topic = topic.move_posts(user, [p1.id], title: "new testing topic name")
|
|
new_post = new_topic.posts.where(post_number: 1).first
|
|
|
|
expect(new_topic.like_count).to eq(1)
|
|
expect(new_post.like_count).to eq(1)
|
|
expect(new_post.post_actions.size).to eq(1)
|
|
end
|
|
|
|
it "preserves the custom_fields in the new post" do
|
|
custom_fields = { "some_field" => 'payload' }
|
|
p1.custom_fields = custom_fields
|
|
p1.save_custom_fields
|
|
|
|
new_topic = topic.move_posts(user, [p1.id], title: "new testing topic name")
|
|
|
|
expect(new_topic.first_post.custom_fields).to eq(custom_fields)
|
|
end
|
|
|
|
include_examples "moves email related stuff" do
|
|
let!(:old_post) { p1 }
|
|
end
|
|
end
|
|
|
|
context "moving replies" do
|
|
include_examples "moves email related stuff" do
|
|
let!(:old_post) { p3 }
|
|
end
|
|
end
|
|
|
|
context "to an existing topic with a deleted post" do
|
|
|
|
before do
|
|
topic.expects(:add_moderator_post)
|
|
end
|
|
|
|
fab!(:destination_topic) { Fabricate(:topic, user: user) }
|
|
fab!(:destination_op) { Fabricate(:post, topic: destination_topic, user: user) }
|
|
fab!(:destination_deleted_reply) { Fabricate(:post, topic: destination_topic, user: another_user) }
|
|
let(:moved_to) { topic.move_posts(user, [p2.id, p4.id], destination_topic_id: destination_topic.id) }
|
|
|
|
it "works correctly" do
|
|
destination_deleted_reply.trash!
|
|
|
|
expect(moved_to).to eq(destination_topic)
|
|
|
|
# Check out new topic
|
|
moved_to.reload
|
|
expect(moved_to.posts_count).to eq(3)
|
|
expect(moved_to.highest_post_number).to eq(4)
|
|
|
|
# Posts should be re-ordered
|
|
p2.reload
|
|
expect(p2.sort_order).to eq(3)
|
|
expect(p2.post_number).to eq(3)
|
|
expect(p2.topic_id).to eq(moved_to.id)
|
|
expect(p2.reply_count).to eq(1)
|
|
expect(p2.reply_to_post_number).to eq(nil)
|
|
|
|
p4.reload
|
|
expect(p4.post_number).to eq(4)
|
|
expect(p4.sort_order).to eq(4)
|
|
expect(p4.topic_id).to eq(moved_to.id)
|
|
expect(p4.reply_to_post_number).to eq(p2.post_number)
|
|
end
|
|
end
|
|
|
|
context "to an existing closed topic" do
|
|
fab!(:destination_topic) { Fabricate(:topic, closed: true) }
|
|
|
|
it "works correctly for admin" do
|
|
moved_to = topic.move_posts(admin, [p1.id, p2.id], destination_topic_id: destination_topic.id)
|
|
expect(moved_to).to be_present
|
|
|
|
moved_to.reload
|
|
expect(moved_to.posts_count).to eq(2)
|
|
expect(moved_to.highest_post_number).to eq(2)
|
|
end
|
|
end
|
|
|
|
it "skips validations when moving posts" do
|
|
p1.update_attribute(:raw, "foo")
|
|
p2.update_attribute(:raw, "bar")
|
|
|
|
new_topic = topic.move_posts(user, [p1.id, p2.id], title: "new testing topic name")
|
|
|
|
expect(new_topic).to be_present
|
|
expect(new_topic.posts.by_post_number.first.raw).to eq(p1.raw)
|
|
expect(new_topic.posts.by_post_number.last.raw).to eq(p2.raw)
|
|
expect(new_topic.posts_count).to eq(2)
|
|
end
|
|
|
|
it "corrects reply_counts within original topic" do
|
|
expect do
|
|
topic.move_posts(user, [p4.id], title: "new testing topic name 1")
|
|
end.to change { PostReply.count }.by(-1)
|
|
expect(p1.reload.reply_count).to eq(2)
|
|
expect(p2.reload.reply_count).to eq(0)
|
|
|
|
expect do
|
|
topic.move_posts(user, [p2.id, p3.id], title: "new testing topic name 2")
|
|
end.to change { PostReply.count }.by(-2)
|
|
expect(p1.reload.reply_count).to eq(0)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'messages' do
|
|
fab!(:user) { Fabricate(:user) }
|
|
fab!(:another_user) { Fabricate(:user) }
|
|
fab!(:regular_user) { Fabricate(:trust_level_4) }
|
|
fab!(:personal_message) { Fabricate(:private_message_topic, user: evil_trout) }
|
|
fab!(:p1) { Fabricate(:post, topic: personal_message, user: user, created_at: 4.hours.ago) }
|
|
fab!(:p2) { Fabricate(:post, topic: personal_message, reply_to_post_number: p1.post_number, user: another_user, created_at: 3.hours.ago) }
|
|
fab!(:p3) { Fabricate(:post, topic: personal_message, reply_to_post_number: p1.post_number, user: user, created_at: 2.hours.ago) }
|
|
fab!(:p4) { Fabricate(:post, topic: personal_message, reply_to_post_number: p2.post_number, user: user, created_at: 1.hour.ago) }
|
|
fab!(:p5) { Fabricate(:post, topic: personal_message, user: evil_trout, created_at: 30.minutes.ago) }
|
|
let(:another_personal_message) do
|
|
Fabricate(:private_message_topic, user: user, topic_allowed_users: [
|
|
Fabricate.build(:topic_allowed_user, user: admin)
|
|
])
|
|
end
|
|
let!(:p6) { Fabricate(:post, topic: another_personal_message, user: evil_trout) }
|
|
|
|
before do
|
|
SiteSetting.tagging_enabled = true
|
|
Jobs.run_immediately!
|
|
p1.replies << p3
|
|
p2.replies << p4
|
|
UserActionManager.enable
|
|
@like = PostActionCreator.like(another_user, p4)
|
|
end
|
|
|
|
context 'move to new message' do
|
|
it "adds post users as topic allowed users" do
|
|
TopicUser.change(user, personal_message, notification_level: TopicUser.notification_levels[:muted])
|
|
TopicUser.change(another_user, personal_message, notification_level: TopicUser.notification_levels[:tracking])
|
|
|
|
personal_message.move_posts(admin, [p2.id, p3.id, p4.id, p5.id], title: "new testing message name", tags: ["tag1", "tag2"], archetype: "private_message")
|
|
|
|
p2.reload
|
|
destination_topic = p2.topic
|
|
expect(destination_topic.archetype).to eq(Archetype.private_message)
|
|
expect(destination_topic.topic_allowed_users.where(user_id: user.id).count).to eq(1)
|
|
expect(destination_topic.topic_allowed_users.where(user_id: another_user.id).count).to eq(1)
|
|
expect(destination_topic.topic_allowed_users.where(user_id: evil_trout.id).count).to eq(1)
|
|
expect(destination_topic.tags.pluck(:name)).to eq([])
|
|
expect(TopicUser.exists?(
|
|
user_id: another_user,
|
|
topic_id: destination_topic.id,
|
|
notification_level: TopicUser.notification_levels[:tracking],
|
|
notifications_reason_id: TopicUser.notification_reasons[:created_topic]
|
|
)).to eq(true)
|
|
expect(TopicUser.exists?(
|
|
user_id: user,
|
|
topic_id: destination_topic.id,
|
|
notification_level: TopicUser.notification_levels[:muted],
|
|
notifications_reason_id: TopicUser.notification_reasons[:created_post]
|
|
)).to eq(true)
|
|
end
|
|
|
|
it "can add tags to new message when allow_staff_to_tag_pms is enabled" do
|
|
SiteSetting.allow_staff_to_tag_pms = true
|
|
personal_message.move_posts(admin, [p2.id, p5.id], title: "new testing message name", tags: ["tag1", "tag2"], archetype: "private_message")
|
|
|
|
p2.reload
|
|
expect(p2.topic.tags.pluck(:name)).to contain_exactly("tag1", "tag2")
|
|
end
|
|
|
|
it "correctly handles notifications" do
|
|
old_message = p2.topic
|
|
old_message_id = p2.topic_id
|
|
|
|
personal_message.move_posts(admin, [p2.id, p4.id], title: "new testing message name", archetype: "private_message")
|
|
|
|
p2.reload
|
|
expect(p2.topic_id).not_to eq(old_message_id)
|
|
expect(p2.reply_to_post_number).to eq(nil)
|
|
expect(p2.reply_to_user_id).to eq(nil)
|
|
|
|
notification = p2.user.notifications.where(notification_type: Notification.types[:moved_post]).first
|
|
|
|
expect(notification.topic_id).to eq(p2.topic_id)
|
|
expect(notification.topic_id).not_to eq(old_message_id)
|
|
expect(notification.post_number).to eq(1)
|
|
|
|
# no message for person who made the move
|
|
expect(admin.notifications.where(notification_type: Notification.types[:moved_post]).length).to eq(0)
|
|
|
|
old_message.reload
|
|
move_message = old_message.posts.find_by(post_number: 2)
|
|
expect(move_message.post_type).to eq(Post.types[:whisper])
|
|
expect(move_message.raw).to include("2 posts were split")
|
|
end
|
|
end
|
|
|
|
context 'move to existing message' do
|
|
it "adds post users as topic allowed users" do
|
|
personal_message.move_posts(admin, [p2.id, p5.id], destination_topic_id: another_personal_message.id, archetype: "private_message")
|
|
|
|
p2.reload
|
|
expect(p2.topic_id).to eq(another_personal_message.id)
|
|
|
|
another_personal_message.reload
|
|
expect(another_personal_message.topic_allowed_users.where(user_id: another_user.id).count).to eq(1)
|
|
expect(another_personal_message.topic_allowed_users.where(user_id: evil_trout.id).count).to eq(1)
|
|
end
|
|
|
|
it "can add additional participants" do
|
|
personal_message.move_posts(admin, [p2.id, p5.id], destination_topic_id: another_personal_message.id, participants: [regular_user.username], archetype: "private_message")
|
|
|
|
another_personal_message.reload
|
|
expect(another_personal_message.topic_allowed_users.where(user_id: another_user.id).count).to eq(1)
|
|
expect(another_personal_message.topic_allowed_users.where(user_id: evil_trout.id).count).to eq(1)
|
|
expect(another_personal_message.topic_allowed_users.where(user_id: regular_user.id).count).to eq(1)
|
|
end
|
|
|
|
it "does not allow moving regular topic posts in personal message" do
|
|
topic = Fabricate(:topic, created_at: 4.hours.ago)
|
|
|
|
expect {
|
|
personal_message.move_posts(admin, [p2.id, p5.id], destination_topic_id: topic.id)
|
|
}.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
|
|
it "moving all posts will close the message" do
|
|
moved_to = personal_message.move_posts(admin, [p1.id, p2.id, p3.id, p4.id, p5.id], destination_topic_id: another_personal_message.id, archetype: "private_message")
|
|
expect(moved_to).to be_present
|
|
|
|
personal_message.reload
|
|
expect(personal_message.closed).to eq(true)
|
|
expect(moved_to.posts_count).to eq(6)
|
|
end
|
|
|
|
it "uses the correct small action post" do
|
|
moved_to = personal_message.move_posts(admin, [p2.id], destination_topic_id: another_personal_message.id, archetype: "private_message")
|
|
post = Post.find_by(topic_id: personal_message.id, post_type: Post.types[:whisper])
|
|
|
|
expected_text = I18n.t(
|
|
"move_posts.existing_message_moderator_post",
|
|
count: 1,
|
|
topic_link: "[#{moved_to.title}](#{p2.reload.url})",
|
|
locale: :en
|
|
)
|
|
|
|
expect(post.raw).to eq(expected_text)
|
|
end
|
|
end
|
|
end
|
|
|
|
context 'banner topic' do
|
|
fab!(:regular_user) { Fabricate(:trust_level_4) }
|
|
fab!(:topic) { Fabricate(:topic) }
|
|
fab!(:personal_message) { Fabricate(:private_message_topic, user: regular_user) }
|
|
fab!(:banner_topic) { Fabricate(:banner_topic, user: evil_trout) }
|
|
fab!(:p1) { Fabricate(:post, topic: banner_topic, user: evil_trout) }
|
|
fab!(:p2) { Fabricate(:post, topic: banner_topic, reply_to_post_number: p1.post_number, user: regular_user) }
|
|
|
|
context 'move to existing topic' do
|
|
it "allows moving banner topic posts in regular topic" do
|
|
banner_topic.move_posts(admin, [p2.id], destination_topic_id: topic.id)
|
|
expect(p2.reload.topic_id).to eq(topic.id)
|
|
end
|
|
|
|
it "does not allow moving banner topic posts in personal message" do
|
|
expect {
|
|
banner_topic.move_posts(admin, [p2.id], destination_topic_id: personal_message.id)
|
|
}.to raise_error(Discourse::InvalidParameters)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|