summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorPatrick Derichs <pderichs@gitlab.com>2019-08-26 09:20:00 +0000
committerKamil TrzciƄski <ayufan@ayufan.eu>2019-08-26 09:20:00 +0000
commita13abd6731ecc3dc24017729c019ad6af9a7b114 (patch)
treed92669207bc9eff3fc4b7e27561b639565976d40 /app
parente5e6a5fb563708d3e98dd164989afcf14df63e0c (diff)
downloadgitlab-ce-a13abd6731ecc3dc24017729c019ad6af9a7b114.tar.gz
Add edit_note and spec for editing quick actions
Call QuickActionsService on Note update Add support for notes which just contain commands after editing Return http status gone (410) if note was deleted Temporary frontend addition so it is not failing when a note is deleted Move specs to shared examples Fix rubocop style issue Deleting note on frontend when status is 410 Use guard clause for note which got deleted Simplified condition for nil note This method should no longer be called with nil note Refactoring of execute method to reduce complexity Move errors update to delete_note method Note is now deleted visually when it only contains commands after update Add expectation Fix style issues Changing action to fix tests Add tests for removeNote and update deleteNote expectations
Diffstat (limited to 'app')
-rw-r--r--app/assets/javascripts/lib/utils/http_status.js1
-rw-r--r--app/assets/javascripts/notes/components/noteable_note.vue31
-rw-r--r--app/assets/javascripts/notes/stores/actions.js22
-rw-r--r--app/controllers/concerns/notes_actions.rb5
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/services/notes/update_service.rb66
6 files changed, 98 insertions, 29 deletions
diff --git a/app/assets/javascripts/lib/utils/http_status.js b/app/assets/javascripts/lib/utils/http_status.js
index 37ad1676f7a..5e5d10883a3 100644
--- a/app/assets/javascripts/lib/utils/http_status.js
+++ b/app/assets/javascripts/lib/utils/http_status.js
@@ -19,6 +19,7 @@ const httpStatusCodes = {
UNAUTHORIZED: 401,
FORBIDDEN: 403,
NOT_FOUND: 404,
+ GONE: 410,
UNPROCESSABLE_ENTITY: 422,
};
diff --git a/app/assets/javascripts/notes/components/noteable_note.vue b/app/assets/javascripts/notes/components/noteable_note.vue
index 2f201839d45..9019f0542b6 100644
--- a/app/assets/javascripts/notes/components/noteable_note.vue
+++ b/app/assets/javascripts/notes/components/noteable_note.vue
@@ -14,6 +14,7 @@ import NoteBody from './note_body.vue';
import eventHub from '../event_hub';
import noteable from '../mixins/noteable';
import resolvable from '../mixins/resolvable';
+import httpStatusCodes from '~/lib/utils/http_status';
export default {
name: 'NoteableNote',
@@ -122,7 +123,13 @@ export default {
},
methods: {
- ...mapActions(['deleteNote', 'updateNote', 'toggleResolveNote', 'scrollToNoteIfNeeded']),
+ ...mapActions([
+ 'deleteNote',
+ 'removeNote',
+ 'updateNote',
+ 'toggleResolveNote',
+ 'scrollToNoteIfNeeded',
+ ]),
editHandler() {
this.isEditing = true;
this.$emit('handleEdit');
@@ -185,15 +192,21 @@ export default {
this.updateSuccess();
callback();
})
- .catch(() => {
- this.isRequesting = false;
- this.isEditing = true;
- this.$nextTick(() => {
- const msg = __('Something went wrong while editing your comment. Please try again.');
- Flash(msg, 'alert', this.$el);
- this.recoverNoteContent(noteText);
+ .catch(response => {
+ if (response.status === httpStatusCodes.GONE) {
+ this.removeNote(this.note);
+ this.updateSuccess();
callback();
- });
+ } else {
+ this.isRequesting = false;
+ this.isEditing = true;
+ this.$nextTick(() => {
+ const msg = __('Something went wrong while editing your comment. Please try again.');
+ Flash(msg, 'alert', this.$el);
+ this.recoverNoteContent(noteText);
+ callback();
+ });
+ }
});
},
formCancelHandler(shouldConfirm, isDirty) {
diff --git a/app/assets/javascripts/notes/stores/actions.js b/app/assets/javascripts/notes/stores/actions.js
index b7857997d42..411bd585672 100644
--- a/app/assets/javascripts/notes/stores/actions.js
+++ b/app/assets/javascripts/notes/stores/actions.js
@@ -61,18 +61,22 @@ export const updateDiscussion = ({ commit, state }, discussion) => {
return utils.findNoteObjectById(state.discussions, discussion.id);
};
-export const deleteNote = ({ commit, dispatch, state }, note) =>
- axios.delete(note.path).then(() => {
- const discussion = state.discussions.find(({ id }) => id === note.discussion_id);
+export const removeNote = ({ commit, dispatch, state }, note) => {
+ const discussion = state.discussions.find(({ id }) => id === note.discussion_id);
- commit(types.DELETE_NOTE, note);
+ commit(types.DELETE_NOTE, note);
- dispatch('updateMergeRequestWidget');
- dispatch('updateResolvableDiscussionsCounts');
+ dispatch('updateMergeRequestWidget');
+ dispatch('updateResolvableDiscussionsCounts');
- if (isInMRPage()) {
- dispatch('diffs/removeDiscussionsFromDiff', discussion);
- }
+ if (isInMRPage()) {
+ dispatch('diffs/removeDiscussionsFromDiff', discussion);
+ }
+};
+
+export const deleteNote = ({ dispatch }, note) =>
+ axios.delete(note.path).then(() => {
+ dispatch('removeNote', note);
});
export const updateNote = ({ commit, dispatch }, { endpoint, note }) =>
diff --git a/app/controllers/concerns/notes_actions.rb b/app/controllers/concerns/notes_actions.rb
index d2a961efff7..4b7899d469b 100644
--- a/app/controllers/concerns/notes_actions.rb
+++ b/app/controllers/concerns/notes_actions.rb
@@ -73,6 +73,11 @@ module NotesActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def update
@note = Notes::UpdateService.new(project, current_user, update_note_params).execute(note)
+ unless @note
+ head :gone
+ return
+ end
+
prepare_notes_for_rendering([@note])
respond_to do |format|
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 65d9b074eee..13e8453ed00 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -6,7 +6,7 @@ class Projects::NotesController < Projects::ApplicationController
include NotesHelper
include ToggleAwardEmoji
- before_action :whitelist_query_limiting, only: [:create]
+ before_action :whitelist_query_limiting, only: [:create, :update]
before_action :authorize_read_note!
before_action :authorize_create_note!, only: [:create]
before_action :authorize_resolve_note!, only: [:resolve, :unresolve]
diff --git a/app/services/notes/update_service.rb b/app/services/notes/update_service.rb
index 384d1dd2e50..853faed9d85 100644
--- a/app/services/notes/update_service.rb
+++ b/app/services/notes/update_service.rb
@@ -8,24 +8,70 @@ module Notes
old_mentioned_users = note.mentioned_users.to_a
note.update(params.merge(updated_by: current_user))
- note.create_new_cross_references!(current_user)
- if note.previous_changes.include?('note')
- TodoService.new.update_note(note, current_user, old_mentioned_users)
+ only_commands = false
+
+ quick_actions_service = QuickActionsService.new(project, current_user)
+ if quick_actions_service.supported?(note)
+ content, update_params, message = quick_actions_service.execute(note, {})
+
+ only_commands = content.empty?
+
+ note.note = content
+ end
+
+ unless only_commands
+ note.create_new_cross_references!(current_user)
+
+ update_todos(note, old_mentioned_users)
+
+ update_suggestions(note)
end
- if note.supports_suggestion?
- Suggestion.transaction do
- note.suggestions.delete_all
- Suggestions::CreateService.new(note).execute
+ if quick_actions_service.commands_executed_count.to_i > 0
+ if update_params.present?
+ quick_actions_service.apply_updates(update_params, note)
+ note.commands_changes = update_params
end
- # We need to refresh the previous suggestions call cache
- # in order to get the new records.
- note.reset
+ if only_commands
+ delete_note(note, message)
+ note = nil
+ else
+ note.save
+ end
end
note
end
+
+ private
+
+ def delete_note(note, message)
+ # We must add the error after we call #save because errors are reset
+ # when #save is called
+ note.errors.add(:commands_only, message.presence || _('Commands did not apply'))
+
+ Notes::DestroyService.new(project, current_user).execute(note)
+ end
+
+ def update_suggestions(note)
+ return unless note.supports_suggestion?
+
+ Suggestion.transaction do
+ note.suggestions.delete_all
+ Suggestions::CreateService.new(note).execute
+ end
+
+ # We need to refresh the previous suggestions call cache
+ # in order to get the new records.
+ note.reset
+ end
+
+ def update_todos(note, old_mentioned_users)
+ return unless note.previous_changes.include?('note')
+
+ TodoService.new.update_note(note, current_user, old_mentioned_users)
+ end
end
end