From 998afa5f74558be215a924d95aa131a69831ca43 Mon Sep 17 00:00:00 2001
From: Robert Schilling <rschilling@student.tugraz.at>
Date: Wed, 1 Mar 2017 14:35:48 +0100
Subject: [PATCH] API: Respect the 'If-Unmodified-Since' for delete endpoints

---
 lib/api/access_requests.rb    |  3 +++
 lib/api/award_emoji.rb        |  1 +
 lib/api/boards.rb             |  1 +
 lib/api/broadcast_messages.rb |  1 +
 lib/api/deploy_keys.rb        |  2 ++
 lib/api/environments.rb       |  1 +
 lib/api/groups.rb             |  2 ++
 lib/api/helpers.rb            |  8 ++++++++
 lib/api/issues.rb             |  2 ++
 lib/api/labels.rb             |  2 ++
 lib/api/members.rb            |  3 ++-
 lib/api/merge_requests.rb     |  2 ++
 lib/api/notes.rb              |  2 ++
 lib/api/project_hooks.rb      |  2 ++
 lib/api/project_snippets.rb   |  2 ++
 lib/api/projects.rb           |  2 ++
 lib/api/runners.rb            |  2 ++
 lib/api/services.rb           |  2 ++
 lib/api/snippets.rb           |  1 +
 lib/api/system_hooks.rb       |  2 ++
 lib/api/triggers.rb           |  2 ++
 lib/api/users.rb              | 28 ++++++++++++++++++++++++++++
 22 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/lib/api/access_requests.rb b/lib/api/access_requests.rb
index cdacf9839e5..0c5b8862d79 100644
--- a/lib/api/access_requests.rb
+++ b/lib/api/access_requests.rb
@@ -67,6 +67,9 @@ module API
         end
         delete ":id/access_requests/:user_id" do
           source = find_source(source_type, params[:id])
+          member = source.public_send(:requesters).find_by!(user_id: params[:user_id])
+
+          check_unmodified_since(member.updated_at)
 
           status 204
           ::Members::DestroyService.new(source, current_user, params)
diff --git a/lib/api/award_emoji.rb b/lib/api/award_emoji.rb
index 5a028fc9d0b..51a8587d26e 100644
--- a/lib/api/award_emoji.rb
+++ b/lib/api/award_emoji.rb
@@ -85,6 +85,7 @@ module API
           end
           delete "#{endpoint}/:award_id" do
             award = awardable.award_emoji.find(params[:award_id])
+            check_unmodified_since(award.updated_at)
 
             unauthorized! unless award.user == current_user || current_user.admin?
 
diff --git a/lib/api/boards.rb b/lib/api/boards.rb
index 5a2d7a681e3..d36df77dc6c 100644
--- a/lib/api/boards.rb
+++ b/lib/api/boards.rb
@@ -124,6 +124,7 @@ module API
           authorize!(:admin_list, user_project)
 
           list = board_lists.find(params[:list_id])
+          check_unmodified_since(list.updated_at)
 
           service = ::Boards::Lists::DestroyService.new(user_project, current_user)
 
diff --git a/lib/api/broadcast_messages.rb b/lib/api/broadcast_messages.rb
index 9980aec4752..352972b584a 100644
--- a/lib/api/broadcast_messages.rb
+++ b/lib/api/broadcast_messages.rb
@@ -90,6 +90,7 @@ module API
       end
       delete ':id' do
         message = find_message
+        check_unmodified_since(message.updated_at)
 
         status 204
         message.destroy
diff --git a/lib/api/deploy_keys.rb b/lib/api/deploy_keys.rb
index 42e7c1486b0..971cc816454 100644
--- a/lib/api/deploy_keys.rb
+++ b/lib/api/deploy_keys.rb
@@ -125,6 +125,8 @@ module API
         key = user_project.deploy_keys_projects.find_by(deploy_key_id: params[:key_id])
         not_found!('Deploy Key') unless key
 
+        check_unmodified_since(key.updated_at)
+
         status 204
         key.destroy
       end
diff --git a/lib/api/environments.rb b/lib/api/environments.rb
index c774a5c6685..3fc423ae79a 100644
--- a/lib/api/environments.rb
+++ b/lib/api/environments.rb
@@ -78,6 +78,7 @@ module API
         authorize! :update_environment, user_project
 
         environment = user_project.environments.find(params[:environment_id])
+        check_unmodified_since(environment.updated_at)
 
         status 204
         environment.destroy
diff --git a/lib/api/groups.rb b/lib/api/groups.rb
index e56427304a6..c9b32a85487 100644
--- a/lib/api/groups.rb
+++ b/lib/api/groups.rb
@@ -117,6 +117,8 @@ module API
       delete ":id" do
         group = find_group!(params[:id])
         authorize! :admin_group, group
+        
+        check_unmodified_since(group.updated_at)
 
         status 204
         ::Groups::DestroyService.new(group, current_user).execute
diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb
index b56fd2388b3..1c74a14d91c 100644
--- a/lib/api/helpers.rb
+++ b/lib/api/helpers.rb
@@ -11,6 +11,14 @@ module API
       declared(params, options).to_h.symbolize_keys
     end
 
+    def check_unmodified_since(last_modified)
+      if_unmodified_since = Time.parse(headers['If-Unmodified-Since']) if headers.key?('If-Unmodified-Since') rescue nil
+
+      if if_unmodified_since && if_unmodified_since < last_modified
+        render_api_error!('412 Precondition Failed', 412)
+      end
+    end
+
     def current_user
       return @current_user if defined?(@current_user)
 
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 4cec1145f3a..cee9898d3a6 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -230,6 +230,8 @@ module API
         not_found!('Issue') unless issue
 
         authorize!(:destroy_issue, issue)
+        check_unmodified_since(issue.updated_at)
+
         status 204
         issue.destroy
       end
diff --git a/lib/api/labels.rb b/lib/api/labels.rb
index 4520c98d951..45fa57fdf55 100644
--- a/lib/api/labels.rb
+++ b/lib/api/labels.rb
@@ -56,6 +56,8 @@ module API
         label = user_project.labels.find_by(title: params[:name])
         not_found!('Label') unless label
 
+        check_unmodified_since(label.updated_at)
+
         status 204
         label.destroy
       end
diff --git a/lib/api/members.rb b/lib/api/members.rb
index bb970b7cd54..5634f123eca 100644
--- a/lib/api/members.rb
+++ b/lib/api/members.rb
@@ -94,7 +94,8 @@ module API
         delete ":id/members/:user_id" do
           source = find_source(source_type, params[:id])
           # Ensure that memeber exists
-          source.members.find_by!(user_id: params[:user_id])
+          member = source.members.find_by!(user_id: params[:user_id])
+          check_unmodified_since(member.updated_at)
 
           status 204
           ::Members::DestroyService.new(source, current_user, declared_params).execute
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index 8810d4e441d..c6fecc1aa6c 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -164,6 +164,8 @@ module API
         merge_request = find_project_merge_request(params[:merge_request_iid])
 
         authorize!(:destroy_merge_request, merge_request)
+        check_unmodified_since(merge_request.updated_at)
+
         status 204
         merge_request.destroy
       end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 4e4e473994b..58d71787aca 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -129,7 +129,9 @@ module API
         end
         delete ":id/#{noteables_str}/:noteable_id/notes/:note_id" do
           note = user_project.notes.find(params[:note_id])
+
           authorize! :admin_note, note
+          check_unmodified_since(note.updated_at)
 
           status 204
           ::Notes::DestroyService.new(user_project, current_user).execute(note)
diff --git a/lib/api/project_hooks.rb b/lib/api/project_hooks.rb
index 649dd891f56..74d736fda59 100644
--- a/lib/api/project_hooks.rb
+++ b/lib/api/project_hooks.rb
@@ -96,6 +96,8 @@ module API
       delete ":id/hooks/:hook_id" do
         hook = user_project.hooks.find(params.delete(:hook_id))
 
+        check_unmodified_since(hook.updated_at)
+
         status 204
         hook.destroy
       end
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index f3d905b0068..645162d564d 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -116,6 +116,8 @@ module API
         not_found!('Snippet') unless snippet
 
         authorize! :admin_project_snippet, snippet
+        check_unmodified_since(snippet.updated_at)
+
         status 204
         snippet.destroy
       end
diff --git a/lib/api/projects.rb b/lib/api/projects.rb
index 15c3832b032..eab0ca0b3c9 100644
--- a/lib/api/projects.rb
+++ b/lib/api/projects.rb
@@ -334,6 +334,8 @@ module API
       desc 'Remove a project'
       delete ":id" do
         authorize! :remove_project, user_project
+        check_unmodified_since(user_project.updated_at)
+
         ::Projects::DestroyService.new(user_project, current_user, {}).async_execute
 
         accepted!
diff --git a/lib/api/runners.rb b/lib/api/runners.rb
index 31f940fe96b..e3b2eb904b7 100644
--- a/lib/api/runners.rb
+++ b/lib/api/runners.rb
@@ -77,7 +77,9 @@ module API
       end
       delete ':id' do
         runner = get_runner(params[:id])
+
         authenticate_delete_runner!(runner)
+        check_unmodified_since(runner.updated_at)
 
         status 204
         runner.destroy!
diff --git a/lib/api/services.rb b/lib/api/services.rb
index 843c05ae32e..4fef3383e5e 100644
--- a/lib/api/services.rb
+++ b/lib/api/services.rb
@@ -655,6 +655,8 @@ module API
       end
       delete ":id/services/:service_slug" do
         service = user_project.find_or_initialize_service(params[:service_slug].underscore)
+        # Todo, not sure
+        check_unmodified_since(service.updated_at)
 
         attrs = service_attributes(service).inject({}) do |hash, key|
           hash.merge!(key => nil)
diff --git a/lib/api/snippets.rb b/lib/api/snippets.rb
index 35ece56c65c..7107b3d669c 100644
--- a/lib/api/snippets.rb
+++ b/lib/api/snippets.rb
@@ -122,6 +122,7 @@ module API
         return not_found!('Snippet') unless snippet
 
         authorize! :destroy_personal_snippet, snippet
+        check_unmodified_since(snippet.updated_at)
 
         status 204
         snippet.destroy
diff --git a/lib/api/system_hooks.rb b/lib/api/system_hooks.rb
index c0179037440..64066a75b15 100644
--- a/lib/api/system_hooks.rb
+++ b/lib/api/system_hooks.rb
@@ -66,6 +66,8 @@ module API
         hook = SystemHook.find_by(id: params[:id])
         not_found!('System hook') unless hook
 
+        check_unmodified_since(hook.updated_at)
+
         status 204
         hook.destroy
       end
diff --git a/lib/api/triggers.rb b/lib/api/triggers.rb
index edfdb63d183..4ae70c65759 100644
--- a/lib/api/triggers.rb
+++ b/lib/api/triggers.rb
@@ -140,6 +140,8 @@ module API
         trigger = user_project.triggers.find(params.delete(:trigger_id))
         return not_found!('Trigger') unless trigger
 
+        check_unmodified_since(trigger.updated_at)
+
         status 204
         trigger.destroy
       end
diff --git a/lib/api/users.rb b/lib/api/users.rb
index e2019d6d512..942bb72cf97 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -230,7 +230,12 @@ module API
         key = user.keys.find_by(id: params[:key_id])
         not_found!('Key') unless key
 
+<<<<<<< HEAD
         status 204
+=======
+        check_unmodified_since(key.updated_at)
+
+>>>>>>> API: Respect the 'If-Unmodified-Since' for delete endpoints
         key.destroy
       end
 
@@ -287,7 +292,14 @@ module API
         email = user.emails.find_by(id: params[:email_id])
         not_found!('Email') unless email
 
+<<<<<<< HEAD
         Emails::DestroyService.new(user, email: email.email).execute
+=======
+        check_unmodified_since(email.updated_at)
+
+        email.destroy
+        user.update_secondary_emails!
+>>>>>>> API: Respect the 'If-Unmodified-Since' for delete endpoints
       end
 
       desc 'Delete a user. Available only for admins.' do
@@ -299,11 +311,18 @@ module API
       end
       delete ":id" do
         authenticated_as_admin!
+
         user = User.find_by(id: params[:id])
         not_found!('User') unless user
 
+<<<<<<< HEAD
         status 204
         user.delete_async(deleted_by: current_user, params: params)
+=======
+        check_unmodified_since(user.updated_at)
+
+        ::Users::DestroyService.new(current_user).execute(user)
+>>>>>>> API: Respect the 'If-Unmodified-Since' for delete endpoints
       end
 
       desc 'Block a user. Available only for admins.'
@@ -481,6 +500,8 @@ module API
         key = current_user.keys.find_by(id: params[:key_id])
         not_found!('Key') unless key
 
+        check_unmodified_since(key.updated_at)
+
         status 204
         key.destroy
       end
@@ -533,6 +554,7 @@ module API
         email = current_user.emails.find_by(id: params[:email_id])
         not_found!('Email') unless email
 
+<<<<<<< HEAD
         status 204
         Emails::DestroyService.new(current_user, email: email.email).execute
       end
@@ -550,6 +572,12 @@ module API
           .reorder(last_activity_on: :asc)
 
         present paginate(activities), with: Entities::UserActivity
+=======
+        check_unmodified_since(email.updated_at)
+
+        email.destroy
+        current_user.update_secondary_emails!
+>>>>>>> API: Respect the 'If-Unmodified-Since' for delete endpoints
       end
     end
   end
-- 
2.30.9