FEATURE: Report edit conflicts when saving draft. (#6585)

This commit is contained in:
Bianca Nenciu 2018-11-14 13:56:25 +02:00 committed by Régis Hanol
parent d078808144
commit 34e4d82f1a
6 changed files with 69 additions and 11 deletions

View File

@ -977,6 +977,7 @@ const Composer = RestModel.extend({
const data = {
reply: this.get("reply"),
originalText: this.get("originalText"),
action: this.get("action"),
title: this.get("title"),
categoryId: this.get("categoryId"),
@ -991,22 +992,35 @@ const Composer = RestModel.extend({
noBump: this.get("noBump")
};
this.set("draftStatus", I18n.t("composer.saving_draft_tip"));
const composer = this;
this.setProperties({
draftStatus: I18n.t("composer.saving_draft_tip"),
draftConflictUser: null
});
if (this._clearingStatus) {
Em.run.cancel(this._clearingStatus);
this._clearingStatus = null;
}
// try to save the draft
return Draft.save(this.get("draftKey"), this.get("draftSequence"), data)
.then(function() {
composer.set("draftStatus", I18n.t("composer.saved_draft_tip"));
.then(result => {
if (result.conflict_user) {
this.setProperties({
draftStatus: I18n.t("composer.edit_conflict"),
draftConflictUser: result.conflict_user
});
} else {
this.setProperties({
draftStatus: I18n.t("composer.saved_draft_tip"),
draftConflictUser: null
});
}
})
.catch(function() {
composer.set("draftStatus", I18n.t("composer.drafts_offline"));
.catch(() => {
this.setProperties({
draftStatus: I18n.t("composer.drafts_offline"),
draftConflictUser: null
});
});
},
@ -1019,6 +1033,7 @@ const Composer = RestModel.extend({
this,
function() {
self.set("draftStatus", null);
self.set("draftConflictUser", null);
self._clearingStatus = null;
},
1000

View File

@ -25,13 +25,15 @@ Draft.reopenClass({
},
save(key, sequence, data) {
data = typeof data === "string" ? data : JSON.stringify(data);
const dataJson = typeof data === "string" ? dataJson : JSON.stringify(data);
return ajax("/draft.json", {
type: "POST",
data: {
draft_key: key,
data: data,
sequence: sequence
data: dataJson,
sequence,
post_id: data.postId,
original_text: data.originalText
}
});
}

View File

@ -149,6 +149,9 @@
</div>
{{/if}}
<div id='draft-status' class="{{if isUploading 'hidden'}}">
{{#if model.draftConflictUser}}
{{avatar model.draftConflictUser imageSize="small"}}
{{/if}}
{{model.draftStatus}}
</div>
</div>

View File

@ -10,6 +10,15 @@ class DraftController < ApplicationController
def update
Draft.set(current_user, params[:draft_key], params[:sequence].to_i, params[:data])
if params[:post_id] && params[:original_text]
post = Post.find_by(id: params[:post_id])
if post && post.raw != params[:original_text]
conflict_user = BasicUserSerializer.new(post.last_editor, root: false)
return render json: success_json.merge(conflict_user: conflict_user)
end
end
render json: success_json
end

View File

@ -1356,6 +1356,7 @@ en:
saved_local_draft_tip: "saved locally"
similar_topics: "Your topic is similar to..."
drafts_offline: "drafts offline"
edit_conflict: 'edit conflict'
group_mentioned_limit: "<b>Warning!</b> You mentioned <a href='{{group_link}}'>{{group}}</a>, however this group has more members than the administrator configured mention limit of {{max}} users. Nobody will be notified. "
group_mentioned:

View File

@ -13,6 +13,34 @@ describe DraftController do
expect(Draft.get(user, 'xyz', 0)).to eq('my data')
end
it 'checks for an conflict on update' do
user = sign_in(Fabricate(:user))
post = Fabricate(:post, user: user)
post "/draft.json", params: {
username: user.username,
draft_key: "topic",
sequence: 0,
data: "{}",
post_id: post.id,
original_text: post.raw
}
expect(JSON.parse(response.body)['conflict_user']).to eq(nil)
post "/draft.json", params: {
username: user.username,
draft_key: "topic",
sequence: 0,
data: "{}",
post_id: post.id,
original_text: "something else"
}
expect(JSON.parse(response.body)['conflict_user']['id']).to eq(post.last_editor.id)
expect(JSON.parse(response.body)['conflict_user']).to include('avatar_template')
end
it 'destroys drafts when required' do
user = sign_in(Fabricate(:user))
Draft.set(user, 'xxx', 0, 'hi')