UX: Warn users if the post that's currently edited has changed. (#6498)
This commit is contained in:
parent
065bf0762c
commit
f60b10d090
|
@ -387,9 +387,14 @@ const Composer = RestModel.extend({
|
||||||
return SAVE_ICONS[action];
|
return SAVE_ICONS[action];
|
||||||
},
|
},
|
||||||
|
|
||||||
@computed("action", "whisper")
|
@computed("action", "whisper", "editConflict")
|
||||||
saveLabel(action, whisper) {
|
saveLabel(action, whisper, editConflict) {
|
||||||
return whisper ? "composer.create_whisper" : SAVE_LABELS[action];
|
if (editConflict) {
|
||||||
|
return "composer.overwrite_edit";
|
||||||
|
} else if (whisper) {
|
||||||
|
return "composer.create_whisper";
|
||||||
|
}
|
||||||
|
return SAVE_LABELS[action];
|
||||||
},
|
},
|
||||||
|
|
||||||
hasMetaData: function() {
|
hasMetaData: function() {
|
||||||
|
@ -727,7 +732,8 @@ const Composer = RestModel.extend({
|
||||||
composerOpened: null,
|
composerOpened: null,
|
||||||
composerTotalOpened: 0,
|
composerTotalOpened: 0,
|
||||||
featuredLink: null,
|
featuredLink: null,
|
||||||
noBump: false
|
noBump: false,
|
||||||
|
editConflict: false
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -762,6 +768,7 @@ const Composer = RestModel.extend({
|
||||||
|
|
||||||
const props = {
|
const props = {
|
||||||
raw: this.get("reply"),
|
raw: this.get("reply"),
|
||||||
|
raw_old: this.get("editConflict") ? null : this.get("originalText"),
|
||||||
edit_reason: opts.editReason,
|
edit_reason: opts.editReason,
|
||||||
image_sizes: opts.imageSizes,
|
image_sizes: opts.imageSizes,
|
||||||
cooked: this.getCookedHtml()
|
cooked: this.getCookedHtml()
|
||||||
|
@ -769,9 +776,12 @@ const Composer = RestModel.extend({
|
||||||
|
|
||||||
this.set("composeState", SAVING);
|
this.set("composeState", SAVING);
|
||||||
|
|
||||||
let rollback = throwAjaxError(() => {
|
let rollback = throwAjaxError(error => {
|
||||||
post.set("cooked", oldCooked);
|
post.set("cooked", oldCooked);
|
||||||
this.set("composeState", OPEN);
|
this.set("composeState", OPEN);
|
||||||
|
if (error.jqXHR && error.jqXHR.status === 409) {
|
||||||
|
this.set("editConflict", true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return promise
|
return promise
|
||||||
|
|
|
@ -200,7 +200,7 @@ class PostsController < ApplicationController
|
||||||
post.image_sizes = params[:image_sizes] if params[:image_sizes].present?
|
post.image_sizes = params[:image_sizes] if params[:image_sizes].present?
|
||||||
|
|
||||||
if !guardian.send("can_edit?", post) && post.user_id == current_user.id && post.edit_time_limit_expired?
|
if !guardian.send("can_edit?", post) && post.user_id == current_user.id && post.edit_time_limit_expired?
|
||||||
return render json: { errors: [I18n.t('too_late_to_edit')] }, status: 422
|
return render_json_error(I18n.t('too_late_to_edit'))
|
||||||
end
|
end
|
||||||
|
|
||||||
guardian.ensure_can_edit!(post)
|
guardian.ensure_can_edit!(post)
|
||||||
|
@ -210,6 +210,11 @@ class PostsController < ApplicationController
|
||||||
edit_reason: params[:post][:edit_reason]
|
edit_reason: params[:post][:edit_reason]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
raw_old = params[:post][:raw_old]
|
||||||
|
if raw_old.present? && raw_old != post.raw
|
||||||
|
return render_json_error(I18n.t('edit_conflict'), status: 409)
|
||||||
|
end
|
||||||
|
|
||||||
# to stay consistent with the create api, we allow for title & category changes here
|
# to stay consistent with the create api, we allow for title & category changes here
|
||||||
if post.is_first_post?
|
if post.is_first_post?
|
||||||
changes[:title] = params[:title] if params[:title]
|
changes[:title] = params[:title] if params[:title]
|
||||||
|
|
|
@ -1372,6 +1372,7 @@ en:
|
||||||
tags_missing: "You must choose at least {{count}} tags"
|
tags_missing: "You must choose at least {{count}} tags"
|
||||||
|
|
||||||
save_edit: "Save Edit"
|
save_edit: "Save Edit"
|
||||||
|
overwrite_edit: "Overwrite Edit"
|
||||||
reply_original: "Reply on Original Topic"
|
reply_original: "Reply on Original Topic"
|
||||||
reply_here: "Reply Here"
|
reply_here: "Reply Here"
|
||||||
reply: "Reply"
|
reply: "Reply"
|
||||||
|
|
|
@ -304,6 +304,7 @@ en:
|
||||||
badge: "%{display_name} badge on %{site_title}"
|
badge: "%{display_name} badge on %{site_title}"
|
||||||
|
|
||||||
too_late_to_edit: "That post was created too long ago. It can no longer be edited or deleted."
|
too_late_to_edit: "That post was created too long ago. It can no longer be edited or deleted."
|
||||||
|
edit_conflict: "That post was edited by another user and your changes can no longer be saved."
|
||||||
revert_version_same: "The current version is same as the version you are trying to revert to."
|
revert_version_same: "The current version is same as the version you are trying to revert to."
|
||||||
|
|
||||||
excerpt_image: "image"
|
excerpt_image: "image"
|
||||||
|
|
|
@ -295,6 +295,13 @@ describe PostsController do
|
||||||
expect(post.raw).to eq("edited body")
|
expect(post.raw).to eq("edited body")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'checks for an edit conflict' do
|
||||||
|
update_params[:post][:raw_old] = 'old body'
|
||||||
|
put "/posts/#{post.id}.json", params: update_params
|
||||||
|
|
||||||
|
expect(response.status).to eq(409)
|
||||||
|
end
|
||||||
|
|
||||||
it "raises an error when the post parameter is missing" do
|
it "raises an error when the post parameter is missing" do
|
||||||
update_params.delete(:post)
|
update_params.delete(:post)
|
||||||
put "/posts/#{post.id}.json", params: update_params
|
put "/posts/#{post.id}.json", params: update_params
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { acceptance } from "helpers/qunit-helpers";
|
||||||
|
|
||||||
|
acceptance("Composer - Edit conflict", {
|
||||||
|
loggedIn: true,
|
||||||
|
|
||||||
|
pretend(server, helper) {
|
||||||
|
server.put("/posts/398", () => {
|
||||||
|
return helper.response(409, { errors: ["edit conflict"] });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
QUnit.test("Edit a post that causes an edit conflict", async assert => {
|
||||||
|
await visit("/t/internationalization-localization/280");
|
||||||
|
await click(".topic-post:eq(0) button.show-more-actions");
|
||||||
|
await click(".topic-post:eq(0) button.edit");
|
||||||
|
await click("#reply-control button.create");
|
||||||
|
assert.equal(
|
||||||
|
find("#reply-control button.create")
|
||||||
|
.text()
|
||||||
|
.trim(),
|
||||||
|
I18n.t("composer.overwrite_edit"),
|
||||||
|
"it shows the overwrite button"
|
||||||
|
);
|
||||||
|
});
|
Loading…
Reference in New Issue