diff --git a/app/controllers/concerns/attachment_actions.rb b/app/controllers/concerns/attachment_actions.rb new file mode 100644 index 0000000000..91d0c28ba8 --- /dev/null +++ b/app/controllers/concerns/attachment_actions.rb @@ -0,0 +1,130 @@ +# frozen_string_literal: true + +# Common Attachment Actions +module AttachmentActions # rubocop:disable Metrics/ModuleLength + extend ActiveSupport::Concern + + included do + before_action proc { current_page } + before_action proc { set_namespace } + before_action proc { set_authorization_object } + before_action :new_destroy_params, only: %i[new_destroy] + before_action :attachment, only: %i[destroy] + end + + def index + authorize! @authorize_object, to: :view_attachments? + + @render_individual_attachments = filter_requested? + @q = build_ransack_query + set_default_sort + @pagy, @attachments = pagy_with_metadata_sort(@q.result) + end + + def new + authorize! @authorize_object, to: :create_attachment? + + render turbo_stream: turbo_stream.update('attachment_modal', + partial: 'new_attachment_modal', + locals: { + open: true, + attachment: Attachment.new(attachable: @namespace), + namespace: @namespace + }), status: :ok + end + + def create + @attachments = ::Attachments::CreateService.new(current_user, @namespace, attachment_params).execute + + status = if !@attachments.count.positive? + :unprocessable_entity + elsif @attachments.count(&:persisted?) == @attachments.count + :ok + else + :multi_status + end + + respond_to do |format| + format.turbo_stream do + render status:, locals: { attachment: Attachment.new(attachable: @namespace), + attachments: @attachments } + end + end + end + + def new_destroy + authorize! @authorize_object, to: :destroy_attachment? + render turbo_stream: turbo_stream.update('attachment_modal', + partial: 'delete_attachment_modal', + locals: { + open: true, + attachment: @attachment, + namespace: @namespace + }), status: :ok + end + + def destroy # rubocop:disable Metrics/MethodLength + @destroyed_attachments = ::Attachments::DestroyService.new(@namespace, @attachment, current_user).execute + respond_to do |format| + if @destroyed_attachments.count.positive? + status = destroy_status(@attachment, @destroyed_attachments.length) + format.turbo_stream do + render status:, locals: { destroyed_attachments: @destroyed_attachments } + end + else + format.turbo_stream do + render status: :unprocessable_entity, + locals: { message: t('.error', + filename: @attachment.file.filename, + errors: @attachment.errors.full_messages.first), + destroyed_attachments: nil } + end + end + end + end + + private + + def filter_requested? + params.dig(:q, :puid_or_file_blob_filename_cont).present? + end + + def build_ransack_query + if @render_individual_attachments + @namespace.attachments.all.ransack(params[:q]) + else + @namespace.attachments + .where.not(Attachment.arel_table[:metadata].contains({ direction: 'reverse' })) + .ransack(params[:q]) + end + end + + def new_destroy_params + @attachment = Attachment.find_by(id: params[:attachment_id]) + end + + def attachment + @attachment = Attachment.find_by(id: params[:id]) + end + + def destroy_status(attachment, count) + return count == 2 ? :ok : :multi_status if attachment.associated_attachment + + count == 1 ? :ok : :unprocessable_entity + end + + def layout_fixed + super + return unless action_name == 'index' + + @fixed = false + end + + def set_default_sort + @q.sorts = 'updated_at desc' if @q.sorts.empty? + end + + def attachment_params + params.require(:attachment).permit(:attachable_id, :attachable_type, files: []) + end +end diff --git a/app/controllers/groups/attachments_controller.rb b/app/controllers/groups/attachments_controller.rb index 18487c082f..8f3829fe1f 100644 --- a/app/controllers/groups/attachments_controller.rb +++ b/app/controllers/groups/attachments_controller.rb @@ -2,87 +2,24 @@ module Groups # Controller actions for Group Attachments - class AttachmentsController < Groups::ApplicationController # rubocop:disable Metrics/ClassLength + class AttachmentsController < Groups::ApplicationController include Metadata - before_action :group, :current_page - before_action :new_destroy_params, only: %i[new_destroy] - before_action :attachment, only: %i[destroy] + include AttachmentActions - def index - authorize! @group, to: :view_attachments? + before_action :group - @render_individual_attachments = filter_requested? - @q = build_ransack_query - set_default_sort - @pagy, @attachments = pagy_with_metadata_sort(@q.result) - end - - def new - authorize! @group, to: :create_attachment? - - render turbo_stream: turbo_stream.update('attachment_modal', - partial: 'new_attachment_modal', - locals: { - open: true, - attachment: Attachment.new(attachable: @group), - namespace: @group - }), status: :ok - end - - def create - @attachments = ::Attachments::CreateService.new(current_user, @group, attachment_params).execute - - status = if !@attachments.count.positive? - :unprocessable_entity - elsif @attachments.count(&:persisted?) == @attachments.count - :ok - else - :multi_status - end - - respond_to do |format| - format.turbo_stream do - render status:, locals: { attachment: Attachment.new(attachable: @group), - attachments: @attachments } - end - end - end + private - def new_destroy - authorize! @group, to: :destroy_attachment? - render turbo_stream: turbo_stream.update('attachment_modal', - partial: 'delete_attachment_modal', - locals: { - open: true, - attachment: @attachment, - namespace: @group - }), status: :ok + def group + @group = Group.find_by_full_path(params[:group_id]) # rubocop:disable Rails/DynamicFindBy end - def destroy # rubocop:disable Metrics/MethodLength - @destroyed_attachments = ::Attachments::DestroyService.new(@group, @attachment, current_user).execute - respond_to do |format| - if @destroyed_attachments.count.positive? - status = destroy_status(@attachment, @destroyed_attachments.length) - format.turbo_stream do - render status:, locals: { destroyed_attachments: @destroyed_attachments } - end - else - format.turbo_stream do - render status: :unprocessable_entity, - locals: { message: t('.error', - filename: @attachment.file.filename, - errors: @attachment.errors.full_messages.first), - destroyed_attachments: nil } - end - end - end + def set_namespace + @namespace = group end - private - - def group - @group = Group.find_by_full_path(params[:group_id]) # rubocop:disable Rails/DynamicFindBy + def set_authorization_object + @authorize_object = group end def current_page @@ -97,48 +34,5 @@ def context_crumbs path: group_attachments_path(@group) }] end - - def filter_requested? - params.dig(:q, :puid_or_file_blob_filename_cont).present? - end - - def build_ransack_query - if @render_individual_attachments - @group.attachments.all.ransack(params[:q]) - else - @group.attachments - .where.not(Attachment.arel_table[:metadata].contains({ direction: 'reverse' })) - .ransack(params[:q]) - end - end - - def layout_fixed - super - return unless action_name == 'index' - - @fixed = false - end - - def set_default_sort - @q.sorts = 'updated_at desc' if @q.sorts.empty? - end - - def attachment_params - params.require(:attachment).permit(:attachable_id, :attachable_type, files: []) - end - - def new_destroy_params - @attachment = Attachment.find_by(id: params[:attachment_id]) - end - - def attachment - @attachment = Attachment.find_by(id: params[:id]) - end - - def destroy_status(attachment, count) - return count == 2 ? :ok : :multi_status if attachment.associated_attachment - - count == 1 ? :ok : :unprocessable_entity - end end end diff --git a/app/controllers/projects/attachments_controller.rb b/app/controllers/projects/attachments_controller.rb index 8362745db3..5bf125fde2 100644 --- a/app/controllers/projects/attachments_controller.rb +++ b/app/controllers/projects/attachments_controller.rb @@ -2,87 +2,20 @@ module Projects # Controller actions for Project Attachments - class AttachmentsController < Projects::ApplicationController # rubocop:disable Metrics/ClassLength + class AttachmentsController < Projects::ApplicationController include Metadata - before_action :current_page - before_action :new_destroy_params, only: %i[new_destroy] - before_action :attachment, only: %i[destroy] + include AttachmentActions - def index - authorize! @project, to: :view_attachments? - - @render_individual_attachments = filter_requested? - @q = build_ransack_query - set_default_sort - @pagy, @attachments = pagy_with_metadata_sort(@q.result) - end - - def new - authorize! @project, to: :create_attachment? - namespace = @project.namespace - - render turbo_stream: turbo_stream.update('attachment_modal', - partial: 'new_attachment_modal', - locals: { - open: true, - attachment: Attachment.new(attachable: namespace), - namespace: - }), status: :ok - end - - def create - @attachments = ::Attachments::CreateService.new(current_user, @project.namespace, attachment_params).execute - - status = if !@attachments.count.positive? - :unprocessable_entity - elsif @attachments.count(&:persisted?) == @attachments.count - :ok - else - :multi_status - end - - respond_to do |format| - format.turbo_stream do - render status:, locals: { attachment: Attachment.new(attachable: @project.namespace), - attachments: @attachments } - end - end - end + private - def new_destroy - authorize! @project, to: :destroy_attachment? - render turbo_stream: turbo_stream.update('attachment_modal', - partial: 'delete_attachment_modal', - locals: { - open: true, - attachment: @attachment, - namespace: @project.namespace - }), status: :ok + def set_namespace + @namespace = @project.namespace end - def destroy # rubocop:disable Metrics/MethodLength - @destroyed_attachments = ::Attachments::DestroyService.new(@project.namespace, @attachment, current_user).execute - - respond_to do |format| - if @destroyed_attachments.count.positive? - status = destroy_status(@attachment, @destroyed_attachments.length) - format.turbo_stream do - render status:, locals: { destroyed_attachments: @destroyed_attachments } - end - else - format.turbo_stream do - render status: :unprocessable_entity, - locals: { message: t('.error', - filename: @attachment.file.filename, - errors: @attachment.errors.full_messages.first), - destroyed_attachments: nil } - end - end - end + def set_authorization_object + @authorize_object = @project end - private - def current_page @current_page = t(:'projects.sidebar.files') end @@ -95,48 +28,5 @@ def context_crumbs path: namespace_project_attachments_path(@project.parent, @project) }] end - - def filter_requested? - params.dig(:q, :puid_or_file_blob_filename_cont).present? - end - - def build_ransack_query - if @render_individual_attachments - @project.namespace.attachments.all.ransack(params[:q]) - else - @project.namespace.attachments - .where.not(Attachment.arel_table[:metadata].contains({ direction: 'reverse' })) - .ransack(params[:q]) - end - end - - def new_destroy_params - @attachment = Attachment.find_by(id: params[:attachment_id]) - end - - def attachment - @attachment = Attachment.find_by(id: params[:id]) - end - - def destroy_status(attachment, count) - return count == 2 ? :ok : :multi_status if attachment.associated_attachment - - count == 1 ? :ok : :unprocessable_entity - end - - def layout_fixed - super - return unless action_name == 'index' - - @fixed = false - end - - def set_default_sort - @q.sorts = 'updated_at desc' if @q.sorts.empty? - end - - def attachment_params - params.require(:attachment).permit(:attachable_id, :attachable_type, files: []) - end end end diff --git a/config/locales/en.yml b/config/locales/en.yml index c67eec2733..f622b49824 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -375,6 +375,9 @@ en: description: No items found matching your search title: No items found concerns: + attachment_actions: + destroy: + error: 'File %{filename} was not removed due to the following errors: %{errors}' bot_actions: create: success: Bot account was successfully added to the group @@ -585,7 +588,6 @@ en: failure: 'File %{filename} was not uploaded due to the following errors: %{errors}' success: File %{filename} was successfully uploaded. destroy: - error: 'File %{filename} was not removed due to the following errors: %{errors}' success: File %{filename} was successfully removed. index: search: @@ -999,7 +1001,6 @@ en: failure: 'File %{filename} was not uploaded due to the following errors: %{errors}' success: File %{filename} was successfully uploaded. destroy: - error: 'File %{filename} was not removed due to the following errors: %{errors}' success: File %{filename} was successfully removed. index: search: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index b458338032..1b4ad31259 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -375,6 +375,9 @@ fr: description: No items found matching your search title: No items found concerns: + attachment_actions: + destroy: + error: 'File %{filename} was not removed due to the following errors: %{errors}' bot_actions: create: success: Bot account was successfully added to the group @@ -585,7 +588,6 @@ fr: failure: 'File %{filename} was not uploaded due to the following errors: %{errors}' success: File %{filename} was successfully uploaded. destroy: - error: 'File %{filename} was not removed due to the following errors: %{errors}' success: File %{filename} was successfully removed. index: search: @@ -999,7 +1001,6 @@ fr: failure: 'File %{filename} was not uploaded due to the following errors: %{errors}' success: File %{filename} was successfully uploaded. destroy: - error: 'File %{filename} was not removed due to the following errors: %{errors}' success: File %{filename} was successfully removed. index: search: