diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index cc0e68ece..2baf0ebd8 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -175,7 +175,7 @@ module Api def load_task(key = :task_id) @task = @experiment.my_modules.find(params.require(key)) - raise PermissionError.new(MyModule, :read) unless can_read_protocol_in_module?(@task.protocol) + raise PermissionError.new(MyModule, :read) unless can_read_my_module?(@task) end def load_protocol(key = :protocol_id) diff --git a/app/controllers/api/v1/experiment_user_assignments_controller.rb b/app/controllers/api/v1/experiment_user_assignments_controller.rb index 1a41ccf19..1339226e7 100644 --- a/app/controllers/api/v1/experiment_user_assignments_controller.rb +++ b/app/controllers/api/v1/experiment_user_assignments_controller.rb @@ -6,6 +6,7 @@ module Api before_action :load_team before_action :load_project before_action :load_experiment + before_action :check_read_permissions before_action :load_user_assignment, only: %i(update show) before_action :load_user_assignment_for_managing, only: %i(update show) @@ -47,12 +48,16 @@ module Api private + def check_read_permissions + raise PermissionError.new(Experiment, :read_users) unless can_read_experiment_users?(@experiment) + end + def load_user_assignment @user_assignment = @experiment.user_assignments.find(params.require(:id)) end def load_user_assignment_for_managing - raise PermissionError.new(Experiment, :manage) unless can_manage_experiment?(@experiment) + raise PermissionError.new(Experiment, :manage_users) unless can_manage_experiment_users?(@experiment) end def user_assignment_params diff --git a/app/controllers/api/v1/project_comments_controller.rb b/app/controllers/api/v1/project_comments_controller.rb index 2dc018511..90ffd2dcf 100644 --- a/app/controllers/api/v1/project_comments_controller.rb +++ b/app/controllers/api/v1/project_comments_controller.rb @@ -5,6 +5,7 @@ module Api class ProjectCommentsController < BaseController before_action :load_team before_action :load_project + before_action :check_read_permissions before_action :load_project_comment, only: :show def index @@ -26,6 +27,10 @@ module Api private + def check_read_permissions + raise PermissionError.new(Project, :read_comments) unless can_read_project_comments?(@project) + end + def load_project_comment @project_comment = @project.project_comments.find(params.require(:id)) end diff --git a/app/controllers/api/v1/project_user_assignments_controller.rb b/app/controllers/api/v1/project_user_assignments_controller.rb index d994d2646..bed81a2e8 100644 --- a/app/controllers/api/v1/project_user_assignments_controller.rb +++ b/app/controllers/api/v1/project_user_assignments_controller.rb @@ -5,6 +5,7 @@ module Api class ProjectUserAssignmentsController < BaseController before_action :load_team before_action :load_project + before_action :check_read_permissions before_action :load_user_assignment, only: %i(show update destroy) before_action :load_user_project_for_managing, only: %i(show update destroy) @@ -26,7 +27,7 @@ module Api end def create - raise PermissionError.new(Project, :manage) unless can_manage_project?(@project) + raise PermissionError.new(Project, :manage) unless can_manage_project_users?(@project) # internally we reuse the same logic as for user project assignment user = @team.users.find(user_project_params[:user_id]) @@ -62,12 +63,16 @@ module Api private + def check_read_permissions + raise PermissionError.new(Project, :read_users) unless can_read_project_users?(@project) + end + def load_user_assignment @user_assignment = @project.user_assignments.find(params.require(:id)) end def load_user_project_for_managing - raise PermissionError.new(Project, :manage) unless can_manage_project?(@project) + raise PermissionError.new(Project, :manage_users) unless can_manage_project_users?(@project) end def user_project_params diff --git a/app/controllers/api/v1/task_user_assignments_controller.rb b/app/controllers/api/v1/task_user_assignments_controller.rb index f8b63820e..9b44c11ed 100644 --- a/app/controllers/api/v1/task_user_assignments_controller.rb +++ b/app/controllers/api/v1/task_user_assignments_controller.rb @@ -7,6 +7,7 @@ module Api before_action :load_project before_action :load_experiment before_action :load_task + before_action :check_read_permissions before_action :load_user_assignment, only: %i(update show) before_action :load_user_assignment_for_managing, only: %i(update show) @@ -50,12 +51,16 @@ module Api private + def check_read_permissions + raise PermissionError.new(MyModule, :read_users) unless can_read_my_module_users?(@task) + end + def load_user_assignment @user_assignment = @task.user_assignments.find(params.require(:id)) end def load_user_assignment_for_managing - raise PermissionError.new(MyModule, :manage) unless can_manage_my_module?(@task) + raise PermissionError.new(MyModule, :manage_users) unless can_manage_my_module_users?(@task) end def user_assignment_params diff --git a/app/controllers/api/v1/tasks_controller.rb b/app/controllers/api/v1/tasks_controller.rb index 26a26f621..84c3463da 100644 --- a/app/controllers/api/v1/tasks_controller.rb +++ b/app/controllers/api/v1/tasks_controller.rb @@ -34,7 +34,7 @@ module Api end def create - raise PermissionError.new(MyModule, :create) unless can_manage_experiment?(@experiment) + raise PermissionError.new(MyModule, :create) unless can_manage_experiment_tasks?(@experiment) my_module = @experiment.my_modules.create!(task_params_create.merge(created_by: current_user)) diff --git a/app/permissions/my_module.rb b/app/permissions/my_module.rb index 9931b8032..efa004601 100644 --- a/app/permissions/my_module.rb +++ b/app/permissions/my_module.rb @@ -107,8 +107,12 @@ Canaid::Permissions.register_for(MyModule) do my_module.permission_granted?(user, MyModulePermissions::STEPS_COMMENTS_CREATE) end + can :read_my_module_users do |user, my_module| + my_module.permission_granted?(user, MyModulePermissions::USERS_READ) + end + can :manage_my_module_users do |user, my_module| - my_module.permission_granted?(user, MyModulePermissions::MANAGE) + my_module.permission_granted?(user, MyModulePermissions::USERS_MANAGE) end can :restore_my_module do |user, my_module| diff --git a/app/permissions/project.rb b/app/permissions/project.rb index f160ddbf5..0fa9f522f 100644 --- a/app/permissions/project.rb +++ b/app/permissions/project.rb @@ -62,6 +62,10 @@ Canaid::Permissions.register_for(Project) do project.permission_granted?(user, ProjectPermissions::EXPERIMENTS_CREATE) end + can :read_project_comments do |user, project| + project.permission_granted?(user, ProjectPermissions::COMMENTS_READ) + end + can :create_project_comments do |user, project| project.permission_granted?(user, ProjectPermissions::COMMENTS_CREATE) end diff --git a/config/initializers/extends/permission_extends.rb b/config/initializers/extends/permission_extends.rb index b115558e4..4cc1acbc9 100644 --- a/config/initializers/extends/permission_extends.rb +++ b/config/initializers/extends/permission_extends.rb @@ -60,6 +60,7 @@ module PermissionExtends STEPS_COMMENTS_UPDATE_OWN REPOSITORY_ROWS_ASSIGN REPOSITORY_ROWS_MANAGE + USERS_READ USERS_MANAGE ).each { |permission| const_set(permission, "task_#{permission.underscore}") } end @@ -123,7 +124,8 @@ module PermissionExtends MyModulePermissions::STEPS_COMMENTS_DELETE_OWN, MyModulePermissions::STEPS_COMMENTS_UPDATE_OWN, MyModulePermissions::REPOSITORY_ROWS_ASSIGN, - MyModulePermissions::REPOSITORY_ROWS_MANAGE + MyModulePermissions::REPOSITORY_ROWS_MANAGE, + MyModulePermissions::USERS_READ ] TECHNICIAN_PERMISSIONS = [ @@ -154,7 +156,8 @@ module PermissionExtends MyModulePermissions::STEPS_COMMENTS_DELETE_OWN, MyModulePermissions::STEPS_COMMENTS_UPDATE_OWN, MyModulePermissions::REPOSITORY_ROWS_ASSIGN, - MyModulePermissions::REPOSITORY_ROWS_MANAGE + MyModulePermissions::REPOSITORY_ROWS_MANAGE, + MyModulePermissions::USERS_READ ] VIEWER_PERMISSIONS = [ @@ -169,6 +172,7 @@ module PermissionExtends ExperimentPermissions::ACTIVITIES_READ, ExperimentPermissions::USERS_READ, MyModulePermissions::READ, + MyModulePermissions::USERS_READ, MyModulePermissions::ACTIVITIES_READ ] end diff --git a/spec/permissions/controllers/api/v1/assets_controller_spec.rb b/spec/permissions/controllers/api/v1/assets_controller_spec.rb new file mode 100644 index 000000000..5fcb21808 --- /dev/null +++ b/spec/permissions/controllers/api/v1/assets_controller_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::AssetsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + }, + destroy: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + id: 1 + }, + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + step: true, + step_asset: true + } + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + id: step_asset.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + id: step_asset.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/checklist_items_controller_spec.rb b/spec/permissions/controllers/api/v1/checklist_items_controller_spec.rb new file mode 100644 index 000000000..5688de5b9 --- /dev/null +++ b/spec/permissions/controllers/api/v1/checklist_items_controller_spec.rb @@ -0,0 +1,139 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ChecklistItemsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + checklist_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + checklist_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + checklist_id: 1 + }, + destroy: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + checklist_id: 1, + id: 1 + }, + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + checklist_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + step: true, + checklist: true + } + + let(:checklist_item) { create(:checklist_item, checklist: checklist) } + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + checklist_id: checklist.id, + id: checklist_item.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + checklist_id: checklist.id, + id: checklist_item.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :delete, :destroy do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + checklist_id: checklist.id, + id: checklist_item.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + checklist_id: checklist.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/connections_controller_spec.rb b/spec/permissions/controllers/api/v1/connections_controller_spec.rb new file mode 100644 index 000000000..36e2e5469 --- /dev/null +++ b/spec/permissions/controllers/api/v1/connections_controller_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ConnectionsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + my_modules: 2, + connection: true + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [ExperimentPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + id: connection.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/experiment_user_assignments_controller_spec.rb b/spec/permissions/controllers/api/v1/experiment_user_assignments_controller_spec.rb new file mode 100644 index 000000000..f6d5206da --- /dev/null +++ b/spec/permissions/controllers/api/v1/experiment_user_assignments_controller_spec.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ExperimentUserAssignmentsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + experiment_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + experiment_id: 1, + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::USERS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:user_assignment) { UserAssignment.find_by(assignable: experiment) } + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::USERS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + id: user_assignment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:user_assignment) { UserAssignment.find_by(assignable: experiment) } + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::USERS_MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + id: user_assignment.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/experiments_controller_spec.rb b/spec/permissions/controllers/api/v1/experiments_controller_spec.rb new file mode 100644 index 000000000..dc5d489fe --- /dev/null +++ b/spec/permissions/controllers/api/v1/experiments_controller_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ExperimentsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + }, + show: { + team_id: 1, + project_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + }, + activities: { + team_id: 1, + project_id: 1, + experiment_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: experiment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::EXPERIMENTS_CREATE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + data: { + type: "experiments", + attributes: { + name: "test" + } + } + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: experiment.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/project_comments_controller_spec.rb b/spec/permissions/controllers/api/v1/project_comments_controller_spec.rb new file mode 100644 index 000000000..820a28c2f --- /dev/null +++ b/spec/permissions/controllers/api/v1/project_comments_controller_spec.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ProjectCommentsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + }, + show: { + team_id: 1, + project_id: 1, + id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + project_comment: true + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::COMMENTS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { experiment } + let(:permissions) { [ProjectPermissions::COMMENTS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: project_comment.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/project_user_assignments_controller_spec.rb b/spec/permissions/controllers/api/v1/project_user_assignments_controller_spec.rb new file mode 100644 index 000000000..9a0de093a --- /dev/null +++ b/spec/permissions/controllers/api/v1/project_user_assignments_controller_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ProjectUserAssignmentsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1 + }, + show: { + team_id: 1, + project_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1 + }, + update: { + team_id: 1, + project_id: 1, + id: 1 + }, + destroy: { + team_id: 1, + project_id: 1, + id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::USERS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:user_assignment) { UserAssignment.find_by(assignable: project) } + let(:testable) { project } + let(:permissions) { [ProjectPermissions::USERS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: user_assignment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:user_assignment) { UserAssignment.find_by(assignable: project) } + let(:testable) { project } + let(:permissions) { [ProjectPermissions::USERS_MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: user_assignment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :delete, :destroy do + let(:user_assignment) { UserAssignment.find_by(assignable: project) } + let(:testable) { project } + let(:permissions) { [ProjectPermissions::USERS_MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: user_assignment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:user_assignment) { UserAssignment.find_by(assignable: project) } + let(:testable) { project } + let(:permissions) { [ProjectPermissions::USERS_MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + id: user_assignment.id, + data: { + type: "project_user_assignments", + attributes: { + user_id: 1, + role_id: 1 + } + } + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/projects_controller_spec.rb b/spec/permissions/controllers/api/v1/projects_controller_spec.rb new file mode 100644 index 000000000..aae09e794 --- /dev/null +++ b/spec/permissions/controllers/api/v1/projects_controller_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ProjectsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1 + }, + show: { + team_id: 1, + id: 1 + }, + update: { + team_id: 1, + id: 1 + }, + create: { + team_id: 1 + }, + activities: { + team_id: 1, + project_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :guest + } + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + id: project.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { project } + let(:permissions) { [] } + let(:action_params) { + { + team_id: team.id, + data: { + type: "projects", + attributes: { + name: "test" + } + } + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + id: project.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :activities do + let(:testable) { project } + let(:permissions) { [ProjectPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/results_controller_spec.rb b/spec/permissions/controllers/api/v1/results_controller_spec.rb new file mode 100644 index 000000000..e47078e36 --- /dev/null +++ b/spec/permissions/controllers/api/v1/results_controller_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::ResultsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + show: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + }, + update: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + }, + index: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + } + }, [:create, :destroy], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + result_text: true + } + + let!(:result) { result_text.result } + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: result.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: result.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: result.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/steps_controller_spec.rb b/spec/permissions/controllers/api/v1/steps_controller_spec.rb new file mode 100644 index 000000000..4921fe3d4 --- /dev/null +++ b/spec/permissions/controllers/api/v1/steps_controller_spec.rb @@ -0,0 +1,112 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::StepsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + show: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + id: 1 + }, + update: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + id: 1 + }, + create: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1 + }, + destroy: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + id: 1 + }, + index: { + id: 1, + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + step: true, + result_text: true + } + + let!(:result) { result_text.result } + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + id: step.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + id: step.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + id: step.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/tables_controller_spec.rb b/spec/permissions/controllers/api/v1/tables_controller_spec.rb new file mode 100644 index 000000000..ab9f2a1b2 --- /dev/null +++ b/spec/permissions/controllers/api/v1/tables_controller_spec.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::TablesController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + }, + destroy: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1, + id: 1 + }, + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + protocol_id: 1, + step_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + step: true, + step_table: true + } + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + id: step_table.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + id: step_table.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :delete, :destroy do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + id: step_table.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + protocol_id: step.protocol_id, + step_id: step.id, + id: step_table.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/task_groups_controller_spec.rb b/spec/permissions/controllers/api/v1/task_groups_controller_spec.rb new file mode 100644 index 000000000..3d0bf1e58 --- /dev/null +++ b/spec/permissions/controllers/api/v1/task_groups_controller_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::TaskGroupsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + my_module_group: true + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [ExperimentPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + id: my_module_group.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/task_inventory_items_controller_spec.rb b/spec/permissions/controllers/api/v1/task_inventory_items_controller_spec.rb new file mode 100644 index 000000000..cc5434897 --- /dev/null +++ b/spec/permissions/controllers/api/v1/task_inventory_items_controller_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::TaskInventoryItemsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:user_assignment) { UserAssignment.find_by(assignable: my_module) } + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: 1 + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/task_tags_controller_spec.rb b/spec/permissions/controllers/api/v1/task_tags_controller_spec.rb new file mode 100644 index 000000000..0ba9a8b62 --- /dev/null +++ b/spec/permissions/controllers/api/v1/task_tags_controller_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::TaskTagsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user, + my_module_tag: true + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:user_assignment) { UserAssignment.find_by(assignable: my_module) } + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: my_module_tag.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/task_user_assignments_controller_spec.rb b/spec/permissions/controllers/api/v1/task_user_assignments_controller_spec.rb new file mode 100644 index 000000000..392343611 --- /dev/null +++ b/spec/permissions/controllers/api/v1/task_user_assignments_controller_spec.rb @@ -0,0 +1,89 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::TaskUserAssignmentsController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::USERS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:user_assignment) { UserAssignment.find_by(assignable: my_module) } + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::USERS_READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: user_assignment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:user_assignment) { UserAssignment.find_by(assignable: my_module) } + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::USERS_MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id, + id: user_assignment.id + } + } + end + end +end diff --git a/spec/permissions/controllers/api/v1/tasks_controller_spec.rb b/spec/permissions/controllers/api/v1/tasks_controller_spec.rb new file mode 100644 index 000000000..b0480257c --- /dev/null +++ b/spec/permissions/controllers/api/v1/tasks_controller_spec.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe Api::V1::TasksController, type: :controller do + include PermissionExtends + + it_behaves_like "a controller with authentication", { + index: { + team_id: 1, + project_id: 1, + experiment_id: 1, + }, + show: { + team_id: 1, + project_id: 1, + experiment_id: 1, + id: 1 + }, + update: { + team_id: 1, + project_id: 1, + experiment_id: 1, + id: 1 + }, + create: { + team_id: 1, + project_id: 1, + experiment_id: 1, + }, + activities: { + team_id: 1, + project_id: 1, + experiment_id: 1, + task_id: 1 + } + }, [], + :unauthorized + + + describe 'permissions checking' do + login_api_user + + include_context 'reference_project_structure', { + team_role: :normal_user + } + + it_behaves_like "a controller action with permissions checking", :get, :index do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :show do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + id: my_module.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :post, :create do + let(:testable) { experiment } + let(:permissions) { [ExperimentPermissions::TASKS_MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + data: { + type: "experiments", + attributes: { + name: "test" + } + } + } + } + end + + it_behaves_like "a controller action with permissions checking", :put, :update do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::MANAGE] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + id: my_module.id + } + } + end + + it_behaves_like "a controller action with permissions checking", :get, :activities do + let(:testable) { my_module } + let(:permissions) { [MyModulePermissions::READ] } + let(:action_params) { + { + team_id: team.id, + project_id: project.id, + experiment_id: experiment.id, + task_id: my_module.id + } + } + end + end +end diff --git a/spec/requests/api/v1/project_user_assignments_controller_spec.rb b/spec/requests/api/v1/project_user_assignments_controller_spec.rb index ebe3ec482..de4677338 100644 --- a/spec/requests/api/v1/project_user_assignments_controller_spec.rb +++ b/spec/requests/api/v1/project_user_assignments_controller_spec.rb @@ -106,8 +106,8 @@ RSpec.describe "Api::V1::ProjectUserAssignmentsController", type: :request do } end - it 'creates new user project and user assignment' do - expect { action }.to change { UserAssignment.count }.by(1).and(change { UserProject.count }.by(1)) + it 'creates new user assignment' do + expect { action }.to change { UserAssignment.count }.by(1) end it 'returns status 201' do diff --git a/spec/support/controller_macros.rb b/spec/support/controller_macros.rb index 6183adfd1..efb5f92d9 100644 --- a/spec/support/controller_macros.rb +++ b/spec/support/controller_macros.rb @@ -7,4 +7,18 @@ module ControllerMacros sign_in user end end + + def login_api_user + before(:each) do + user = create :user + user.confirm + + @request.headers.merge!({ + 'Authorization': 'Bearer ' + Api::CoreJwt.encode(sub: user.id), + 'Content-Type': 'application/json' + }) + + subject.send(:authenticate_request!) + end + end end diff --git a/spec/support/reference_project_structure_context.rb b/spec/support/reference_project_structure_context.rb index e5def1b23..ab9482f5a 100644 --- a/spec/support/reference_project_structure_context.rb +++ b/spec/support/reference_project_structure_context.rb @@ -14,6 +14,7 @@ RSpec.shared_context 'reference_project_structure' do |config| config ||= {} + let!(:user) { subject.current_user } let!(:role) do if config[:role] @@ -34,8 +35,14 @@ RSpec.shared_context 'reference_project_structure' do |config| let!(:my_module) { create :my_module, experiment: experiment, created_by: user } unless config[:skip_my_module] let!(:my_modules) { create_list :my_module, config[:my_modules], experiment: experiment } if config[:my_modules] - let(:tag) { create :tag, project: project} if config[:tag] - let(:tags) { create_list :tag, config[:tags], project: project} if config[:tags] + let!(:connection) { create :connection, input_id: my_modules.first.id, output_id: my_modules.last.id } if config[:connection] + + let!(:my_module_group) do + create :my_module_group, experiment: experiment, created_by: user, my_modules: [my_module] + end if config[:my_module_group] + + let(:tag) { create :tag, project: project} if config[:tag] || config[:my_module_tag] + let(:tags) { create_list :tag, config[:tags], project: project} if config[:tags] || config[:my_module_tags] let(:project_comment) { create :project_comment, project: project, user: user } if config[:project_comment] let(:project_comments) { create_list :project_comment, config[:project_comments], project: project, user: user } if config[:project_comments] @@ -43,15 +50,20 @@ RSpec.shared_context 'reference_project_structure' do |config| let(:my_module_comment) { create :task_comment, my_module: my_module, user: user } if config[:my_module_comment] let(:my_module_comments) { create_list :task_comment, config[:my_module_comments], my_module: my_module, user: user } if config[:my_module_comments] + let(:my_module_tag) { create :my_module_tag, my_module: my_module, tag: tag } if config[:my_module_tag] + let(:my_module_tags) do + tags.map { |t| create(:my_module_tag, my_module: my_module, tag: t) } + end if config[:my_module_tags] + if config[:step] let(:step) { create :step, protocol: my_module.protocol, user: user} let(:step_comment) { create :step_comment, step: step, user: user} if config[:step_comment] let(:step_comments) { create_list :step_comment, config[:step_comments], step: step, user: user} if config[:step_comments] - [:step_asset, :step_table, :step_checklist].each do |step_component| + [:step_asset, :step_table, :checklist].each do |step_component| let(step_component) { create step_component, step: step } if config[step_component] end - [:step_assets, :step_tables, :step_checklists].each do |step_components| + [:step_assets, :step_tables, :checklists].each do |step_components| let(step_components) { create_list step_components, config[step_components], step: step } if config[step_components] end end diff --git a/spec/support/shared_examples/controller_action_with_permission_checking.rb b/spec/support/shared_examples/controller_action_with_permission_checking.rb index dd5691d45..720bceda3 100644 --- a/spec/support/shared_examples/controller_action_with_permission_checking.rb +++ b/spec/support/shared_examples/controller_action_with_permission_checking.rb @@ -3,7 +3,6 @@ require 'rails_helper' RSpec.shared_examples 'a controller action with permissions checking' do |verb, action| - describe 'controller action' do context 'user without permissions' do it "returns forbidden response for action :#{action}" do diff --git a/spec/support/shared_examples/controller_with_authentication.rb b/spec/support/shared_examples/controller_with_authentication.rb index 50da97791..6733a09b8 100644 --- a/spec/support/shared_examples/controller_with_authentication.rb +++ b/spec/support/shared_examples/controller_with_authentication.rb @@ -2,18 +2,18 @@ require 'rails_helper' -RSpec.shared_examples 'a controller with authentication' do |actions_with_params, actions_to_skip| +RSpec.shared_examples 'a controller with authentication' do |actions_with_params, actions_to_skip, custom_response| let (:protected_actions) { described_class.instance_methods(false) - (actions_to_skip || []) } describe 'controller actions' do context 'unauthenticated user' do - it 'returns forbidden response for all actions' do + it "returns #{custom_response || :forbidden} response for all actions" do sign_out :user actions_with_params ||= {} protected_actions.each do |action| params = actions_with_params[action] get action, params: params - expect(response).to have_http_status(:forbidden).or redirect_to('/users/sign_in') + expect(response).to have_http_status(custom_response || :forbidden).or redirect_to('/users/sign_in') end end end