mirror of
https://gh.wpcy.net/https://github.com/discourse/discourse.git
synced 2026-05-27 00:42:45 +08:00
Editing a post that's a reply produced a "The requested URL or resource
could not be found" dialog when the post had been viewed via its
parent's expanded replies list. The dialog came from a `PUT
/post_replies/:id` request that 404s; the URL should be `PUT
/posts/:id`.
`loadMoreReplies` calls `store.find("post-reply", …)` then
`store.createRecord("post", reply)` on each result. The first stamps
`__type = "post-reply"` (and `__munge`, `__state`) onto each model. The
second re-hydrates the same `id` under `post` — and the topic stream's
canonical post for that `id` is already in the store. `_hydrate`'s
"update existing" path copies those internal fields onto the canonical
record via `setProperties`, so a later `post.save()` builds its URL from
the wrong `__type`.
Fix: skip every `__`-prefixed key when diffing in `_hydrate`'s update
path. Internal store/RestModel metadata stamped at hydration time has no
business being carried across types. The `__` prefix is the existing
convention for "internal", so future additions are protected by the same
guard.
https://meta.discourse.org/t/402747
87 lines
2.4 KiB
Ruby
Vendored
87 lines
2.4 KiB
Ruby
Vendored
# frozen_string_literal: true
|
|
|
|
describe "Post replies" do
|
|
fab!(:user)
|
|
fab!(:topic)
|
|
fab!(:post) { Fabricate(:post, user:, topic:) }
|
|
|
|
let(:first_post) { PageObjects::Components::Post.new(1) }
|
|
let(:third_chained_reply) { PageObjects::Components::Post.new(7) }
|
|
|
|
context "when loading post replies" do
|
|
before do
|
|
25.times do
|
|
reply = Fabricate(:post, topic:, reply_to_post_number: 1)
|
|
PostReply.create!(post:, reply:)
|
|
end
|
|
|
|
post.update!(reply_count: post.replies.count)
|
|
end
|
|
|
|
it "supports pagination" do
|
|
sign_in(user)
|
|
visit(topic.url)
|
|
|
|
first_post.show_replies
|
|
|
|
expect(first_post).to have_replies(count: 20)
|
|
expect(first_post).to have_more_replies
|
|
|
|
first_post.load_more_replies
|
|
|
|
expect(first_post).to have_replies(count: post.replies.count)
|
|
expect(first_post).to have_loaded_all_replies
|
|
end
|
|
end
|
|
|
|
context "when loading parent posts" do
|
|
before do
|
|
SiteSetting.max_reply_history = 2
|
|
|
|
3.times do |i|
|
|
PostReply.create!(post:, reply: Fabricate(:post, topic:))
|
|
|
|
reply = Fabricate(:post, topic:, reply_to_post_number: (i * 2) + 1, raw: "reply #{i + 1}")
|
|
PostReply.create!(post:, reply:)
|
|
end
|
|
|
|
post.update!(reply_count: post.replies.count)
|
|
end
|
|
|
|
it "does not duplicate replies" do
|
|
sign_in(user)
|
|
visit(topic.url)
|
|
|
|
third_chained_reply.show_parent_posts
|
|
expect(third_chained_reply).to have_parent_posts(count: 2)
|
|
expect(third_chained_reply).to have_no_parent_post_content("reply 3")
|
|
end
|
|
end
|
|
|
|
context "when editing a reply reached via expanded replies" do
|
|
fab!(:admin) { Fabricate(:admin, refresh_auto_groups: true) }
|
|
fab!(:reply_1) { Fabricate(:post, topic:, reply_to_post_number: post.post_number) }
|
|
fab!(:reply_2) { Fabricate(:post, topic:, reply_to_post_number: post.post_number) }
|
|
|
|
let(:composer) { PageObjects::Components::Composer.new }
|
|
let(:reply_1_post) { PageObjects::Components::Post.new(reply_1.post_number) }
|
|
|
|
before do
|
|
PostReply.create!(post:, reply: reply_1)
|
|
PostReply.create!(post:, reply: reply_2)
|
|
post.update!(reply_count: 2)
|
|
end
|
|
|
|
it "saves a no-op edit without errors" do
|
|
sign_in(admin)
|
|
visit(topic.url)
|
|
|
|
first_post.show_replies
|
|
first_post.jump_to_reply(reply_1)
|
|
reply_1_post.edit
|
|
composer.submit
|
|
|
|
expect(page).to have_no_css(".dialog-body")
|
|
end
|
|
end
|
|
end
|