FEATURE: Report edit conflicts when saving draft. (#6585)
This commit is contained in:
parent
d078808144
commit
34e4d82f1a
|
@ -977,6 +977,7 @@ const Composer = RestModel.extend({
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
reply: this.get("reply"),
|
reply: this.get("reply"),
|
||||||
|
originalText: this.get("originalText"),
|
||||||
action: this.get("action"),
|
action: this.get("action"),
|
||||||
title: this.get("title"),
|
title: this.get("title"),
|
||||||
categoryId: this.get("categoryId"),
|
categoryId: this.get("categoryId"),
|
||||||
|
@ -991,22 +992,35 @@ const Composer = RestModel.extend({
|
||||||
noBump: this.get("noBump")
|
noBump: this.get("noBump")
|
||||||
};
|
};
|
||||||
|
|
||||||
this.set("draftStatus", I18n.t("composer.saving_draft_tip"));
|
this.setProperties({
|
||||||
|
draftStatus: I18n.t("composer.saving_draft_tip"),
|
||||||
const composer = this;
|
draftConflictUser: null
|
||||||
|
});
|
||||||
|
|
||||||
if (this._clearingStatus) {
|
if (this._clearingStatus) {
|
||||||
Em.run.cancel(this._clearingStatus);
|
Em.run.cancel(this._clearingStatus);
|
||||||
this._clearingStatus = null;
|
this._clearingStatus = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to save the draft
|
|
||||||
return Draft.save(this.get("draftKey"), this.get("draftSequence"), data)
|
return Draft.save(this.get("draftKey"), this.get("draftSequence"), data)
|
||||||
.then(function() {
|
.then(result => {
|
||||||
composer.set("draftStatus", I18n.t("composer.saved_draft_tip"));
|
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() {
|
.catch(() => {
|
||||||
composer.set("draftStatus", I18n.t("composer.drafts_offline"));
|
this.setProperties({
|
||||||
|
draftStatus: I18n.t("composer.drafts_offline"),
|
||||||
|
draftConflictUser: null
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -1019,6 +1033,7 @@ const Composer = RestModel.extend({
|
||||||
this,
|
this,
|
||||||
function() {
|
function() {
|
||||||
self.set("draftStatus", null);
|
self.set("draftStatus", null);
|
||||||
|
self.set("draftConflictUser", null);
|
||||||
self._clearingStatus = null;
|
self._clearingStatus = null;
|
||||||
},
|
},
|
||||||
1000
|
1000
|
||||||
|
|
|
@ -25,13 +25,15 @@ Draft.reopenClass({
|
||||||
},
|
},
|
||||||
|
|
||||||
save(key, sequence, data) {
|
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", {
|
return ajax("/draft.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: {
|
data: {
|
||||||
draft_key: key,
|
draft_key: key,
|
||||||
data: data,
|
data: dataJson,
|
||||||
sequence: sequence
|
sequence,
|
||||||
|
post_id: data.postId,
|
||||||
|
original_text: data.originalText
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,6 +149,9 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<div id='draft-status' class="{{if isUploading 'hidden'}}">
|
<div id='draft-status' class="{{if isUploading 'hidden'}}">
|
||||||
|
{{#if model.draftConflictUser}}
|
||||||
|
{{avatar model.draftConflictUser imageSize="small"}}
|
||||||
|
{{/if}}
|
||||||
{{model.draftStatus}}
|
{{model.draftStatus}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -10,6 +10,15 @@ class DraftController < ApplicationController
|
||||||
|
|
||||||
def update
|
def update
|
||||||
Draft.set(current_user, params[:draft_key], params[:sequence].to_i, params[:data])
|
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
|
render json: success_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1356,6 +1356,7 @@ en:
|
||||||
saved_local_draft_tip: "saved locally"
|
saved_local_draft_tip: "saved locally"
|
||||||
similar_topics: "Your topic is similar to..."
|
similar_topics: "Your topic is similar to..."
|
||||||
drafts_offline: "drafts offline"
|
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_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:
|
group_mentioned:
|
||||||
|
|
|
@ -13,6 +13,34 @@ describe DraftController do
|
||||||
expect(Draft.get(user, 'xyz', 0)).to eq('my data')
|
expect(Draft.get(user, 'xyz', 0)).to eq('my data')
|
||||||
end
|
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
|
it 'destroys drafts when required' do
|
||||||
user = sign_in(Fabricate(:user))
|
user = sign_in(Fabricate(:user))
|
||||||
Draft.set(user, 'xxx', 0, 'hi')
|
Draft.set(user, 'xxx', 0, 'hi')
|
||||||
|
|
Loading…
Reference in New Issue