diff options
author | Patrick Derichs <pderichs@gitlab.com> | 2019-08-26 12:20:00 +0300 |
---|---|---|
committer | Kamil TrzciĆski <ayufan@ayufan.eu> | 2019-08-26 12:20:00 +0300 |
commit | a13abd6731ecc3dc24017729c019ad6af9a7b114 (patch) | |
tree | d92669207bc9eff3fc4b7e27561b639565976d40 /app | |
parent | e5e6a5fb563708d3e98dd164989afcf14df63e0c (diff) |
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.js | 1 | ||||
-rw-r--r-- | app/assets/javascripts/notes/components/noteable_note.vue | 31 | ||||
-rw-r--r-- | app/assets/javascripts/notes/stores/actions.js | 22 | ||||
-rw-r--r-- | app/controllers/concerns/notes_actions.rb | 5 | ||||
-rw-r--r-- | app/controllers/projects/notes_controller.rb | 2 | ||||
-rw-r--r-- | app/services/notes/update_service.rb | 66 |
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 |