diff --git a/app/controllers/project_folders_controller.rb b/app/controllers/project_folders_controller.rb new file mode 100644 index 000000000..926b23954 --- /dev/null +++ b/app/controllers/project_folders_controller.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +class ProjectFoldersController < ApplicationController + before_action :check_manage_permissions, only: %i(move_to) + + def move_to + destination_folder = current_team.project_folders.find(move_params[:id]) + destination_folder.transaction do + move_projects(destination_folder) + move_folders(destination_folder) + end + respond_to do |format| + format.json { render json: { flash: I18n.t('projects.move.success_flash') } } + end + rescue StandardError => e + Rails.logger.error e.message + Rails.logger.error e.backtrace.join("\n") + respond_to do |format| + format.json { render json: { flash: I18n.t('projects.move.error_flash') }, status: :bad_request } + end + end + + private + + def check_manage_permissions + render_403 unless can_update_team?(current_team) + end + + def move_params + params.require(:id) + params.require(:movables) + params.permit(:id, movables: %i(type id)) + end + + def move_projects(destination_folder) + project_ids = move_params[:movables].collect { |movable| movable[:id] if movable[:type] == 'project' }.compact + return if project_ids.blank? + + current_team.projects.where(id: project_ids).each { |p| p.update!(project_folder: destination_folder) } + end + + def move_folders(destination_folder) + folder_ids = move_params[:movables].collect { |movable| movable[:id] if movable[:type] == 'project_folder' }.compact + return if folder_ids.blank? + + current_team.project_folders.where(id: folder_ids).each { |f| f.update!(parent_folder: destination_folder) } + end +end diff --git a/config/locales/en.yml b/config/locales/en.yml index 1807d164e..ff97036b4 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -416,6 +416,9 @@ en: update: success_flash: "Project %{name} successfully updated." error_flash: "Project %{name} not updated." + move: + success_flash: "You have successfully moved the selected project(s)/folder(s) to another folder." + error_flash: "An error occurred. The selected project(s)/folder(s) have not been moved." archive: success_flash: "Project %{name} successfully archived." error_flash: "Project %{name} not archived." diff --git a/config/routes.rb b/config/routes.rb index 344c5ef1d..df47b9f48 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -305,6 +305,10 @@ Rails.application.routes.draw do resources :project_folders, only: [] do get '/', to: 'projects#index' get 'cards', to: 'projects#cards' + + member do + post 'move_to', to: 'project_folders#move_to', defaults: { format: 'json' } + end end resources :experiments do diff --git a/spec/controllers/project_folders_controller_spec.rb b/spec/controllers/project_folders_controller_spec.rb new file mode 100644 index 000000000..b8dee3bef --- /dev/null +++ b/spec/controllers/project_folders_controller_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe ProjectFoldersController, type: :controller do + login_user + render_views + + let!(:user) { subject.current_user } + let!(:team) { create :team, created_by: user } + let!(:user_team) { create :user_team, team: team, user: user, role: :admin } + + describe 'POST #move_to' do + let!(:project_folder_1) do + create :project_folder, name: 'test folder A', team: team + end + let!(:project_folder_2) do + create :project_folder, name: 'test folder B', team: team + end + let!(:project_folder_3) do + create :project_folder, name: 'test folder C', team: team, parent_folder: project_folder_2 + end + let!(:project_1) do + create :project, name: 'test project A', team: team, created_by: user + end + let!(:project_2) do + create :project, name: 'test project B', team: team, project_folder: project_folder_2, created_by: user + end + let!(:project_3) do + create :project, name: 'test project C', team: team, project_folder: project_folder_3, created_by: user + end + + context 'in JSON format' do + let(:action) { post :move_to, params: params, format: :json } + let(:params) do + { + id: project_folder_1.id, + movables: [ + { id: project_1.id, type: :project }, + { id: project_folder_2.id, type: :project_folder } + ] + } + end + + it 'returns success response' do + post :move_to, params: params, format: :json + expect(response).to have_http_status(:success) + expect(response.media_type).to eq 'application/json' + expect(project_1.reload.project_folder).to(be_eql(project_folder_1)) + expect(project_folder_2.reload.parent_folder).to(be_eql(project_folder_1)) + expect(project_folder_3.reload.parent_folders).to(include(project_folder_1)) + expect(project_3.reload.project_folder.parent_folder.parent_folder).to(be_eql(project_folder_1)) + end + end + end +end