diff --git a/app/controllers/access_permissions/protocols_controller.rb b/app/controllers/access_permissions/protocols_controller.rb new file mode 100644 index 000000000..c9562c97a --- /dev/null +++ b/app/controllers/access_permissions/protocols_controller.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +module AccessPermissions + class ProtocolsController < ApplicationController + before_action :set_protocol + before_action :check_read_permissions, only: %i(show) + before_action :check_manage_permissions, except: %i(show) + + def new + respond_to do |format| + format.json + end + end + + def show + respond_to do |format| + format.json + end + end + + def edit + respond_to do |format| + format.json + end + end + + def update + @user_assignment = UserAssignment.find_by(user_id: permitted_update_params[:user_id], assignable: @protocol) + @user_assignment.update(permitted_update_params) + respond_to do |format| + format.json do + render :protocol_member + end + end + end + + def create + respond_to do |format| + if @form.save + @message = t('access_permissions.create.success', count: @form.new_members_count) + format.json { render :edit } + else + @message = t('access_permissions.create.failure') + format.json { render :new } + end + end + end + + def destroy + respond_to do |format| + if project_member.destroy + format.json do + render json: { flash: t('access_permissions.destroy.success', member_name: user.full_name) }, + status: :ok + end + else + format.json do + render json: { flash: t('access_permissions.destroy.failure') }, + status: :unprocessable_entity + end + end + end + end + + def update_default_public_user_role + @protocol.update!(permitted_default_public_user_role_params) + end + + private + + def permitted_default_public_user_role_params + params.require(:protocol).permit(:default_public_user_role_id) + end + + def permitted_update_params + params.require(:user_assignment) + .permit(%i(user_role_id user_id)) + end + + def permitted_create_params + params.require(:access_permissions_new_user_protocol_form) + .permit(resource_members: %i(assign user_id user_role_id)) + end + + def set_protocol + @protocol = current_team.protocols.includes(user_assignments: %i(user user_role)).find_by(id: params[:id]) + + render_404 unless @protocol + end + + def check_manage_permissions + render_403 unless can_manage_protocol_users?(@protocol) + end + + def check_read_permissions + render_403 unless can_read_protocol?(@protocol) + end + end +end diff --git a/app/models/user_assignment.rb b/app/models/user_assignment.rb index 210dd3e0e..969b5da32 100644 --- a/app/models/user_assignment.rb +++ b/app/models/user_assignment.rb @@ -16,6 +16,10 @@ class UserAssignment < ApplicationRecord validates :user, uniqueness: { scope: %i(assignable team_id) } + def last_assignable_owner? + assignable_owners.count == 1 && user_role.owner? + end + private def assign_team_child_objects @@ -29,4 +33,10 @@ class UserAssignment < ApplicationRecord def unassign_team_child_objects UserAssignments::RemoveTeamUserAssignmentsService.new(self).call end + + def assignable_owners + @assignable_owners ||= assignable.user_assignments + .includes(:user_role) + .where(user_roles: { name: I18n.t('user_roles.predefined.owner') }) + end end diff --git a/app/views/access_permissions/partials/_protocol_member_field.html.erb b/app/views/access_permissions/partials/_protocol_member_field.html.erb new file mode 100644 index 000000000..ae047d377 --- /dev/null +++ b/app/views/access_permissions/partials/_protocol_member_field.html.erb @@ -0,0 +1,33 @@ +<% # frozen_string_literal: true %> + +<% + protocol_assignment = UserAssignment.find_by(user_id: user.id, assignable: protocol) + item_id = dom_id(user, :protocol_member) +%> + +<%= form_with(model: protocol_assignment, url: update_path, method: :put, remote: true, html: { class: 'row member-item', id: item_id, data: { action: 'replace-form autosave-form', object_type: :protocol } }) do |f| %> + <%= f.hidden_field :user_id, value: f.object.user.id %> +
+
+ <%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %> +
+
+ <%= current_assignee_name(user) %> +
+ <%= user_assignment_resource_role_name(user, protocol) %> +
+
+
+
+ <%= f.select :user_role_id, options_for_select(user_roles_collection, selected: f.object.user_role.id), {}, class: 'form-control selectpicker', title: t('user_assignment.change_protocol_role'), data: { 'selected-text-format' => 'static' } %> +
+
+ <% unless protocol_assignment.last_assignable_owner? %> + <%= link_to access_permissions_protocol_path(protocol, user_id: user), remote: true, method: :delete, class: 'btn btn-secondary', data: { action: 'remote-destroy', target: "##{item_id}" } do %> + + <%= t 'general.remove' %> + <% end %> + <% end %> +
+
+<% end %> diff --git a/app/views/access_permissions/partials/_protocol_public_user_role_form.html.erb b/app/views/access_permissions/partials/_protocol_public_user_role_form.html.erb new file mode 100644 index 000000000..a9552df11 --- /dev/null +++ b/app/views/access_permissions/partials/_protocol_public_user_role_form.html.erb @@ -0,0 +1,20 @@ +<%= form_with(model: protocol, url: update_default_public_user_role_access_permissions_protocol_path(protocol), method: :put, remote: true, html: { class: 'row member-item', id: 'public_assignments', data: { action: 'replace-form autosave-form', object_type: :protocol } }) do |f| %> +
+
+ <%= image_tag "icon/team.png", class: 'img-circle pull-left' %> +
+
+ <%= t('access_permissions.everyone_else', team_name: protocol.team.name) %> + <%= render 'access_permissions/partials/public_members_dropdown', team: protocol.team, protocol: protocol %> +
+
+
+
+ <% if editable %> + <%= f.select :default_public_user_role_id, options_for_select(user_roles_collection) {}, class: 'form-control selectpicker', title: t('user_assignment.change_protocol_role'), data: { 'selected-text-format' => 'static' } %> + <% end %> +
+
+
+
+<% end %> diff --git a/app/views/access_permissions/partials/_public_members_dropdown.html.erb b/app/views/access_permissions/partials/_public_members_dropdown.html.erb index dd7c7a362..8022f022b 100644 --- a/app/views/access_permissions/partials/_public_members_dropdown.html.erb +++ b/app/views/access_permissions/partials/_public_members_dropdown.html.erb @@ -5,7 +5,14 @@
<%= t('.title', team: team.name) %>
- <% team.users.order(full_name: :asc).where.not(id: project.manually_assigned_users.select(:id)).each do |user| %> + <% + users_excluded = if defined? project + project.manually_assigned_users.select(:id) + elsif protocol + protocol.manually_assigned_users.select(:id) + end + %> + <% team.users.order(full_name: :asc).where.not(id: users_excluded).each do |user| %>
<%= user.full_name %>
diff --git a/app/views/access_permissions/protocols/edit.json.jbuilder b/app/views/access_permissions/protocols/edit.json.jbuilder new file mode 100644 index 000000000..3cd9a7ec5 --- /dev/null +++ b/app/views/access_permissions/protocols/edit.json.jbuilder @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +json.modal controller.render_to_string( + partial: 'access_permissions/protocols/modals/edit_modal', + formats: [:html], + locals: { + protocol: @protocol, + update_path: access_permissions_protocol_path(@protocol), + new_resource_path: new_access_permissions_protocol_path(id: @protocol) + }, + layout: false +) + +json.flash @message diff --git a/app/views/access_permissions/protocols/modals/_edit_modal.html.erb b/app/views/access_permissions/protocols/modals/_edit_modal.html.erb new file mode 100644 index 000000000..47b6e8492 --- /dev/null +++ b/app/views/access_permissions/protocols/modals/_edit_modal.html.erb @@ -0,0 +1,25 @@ +<% # frozen_string_literal: true %> + + diff --git a/app/views/access_permissions/protocols/modals/_show_modal.html.erb b/app/views/access_permissions/protocols/modals/_show_modal.html.erb new file mode 100644 index 000000000..4edfd3c93 --- /dev/null +++ b/app/views/access_permissions/protocols/modals/_show_modal.html.erb @@ -0,0 +1,19 @@ +<% # frozen_string_literal: true %> + + diff --git a/app/views/access_permissions/protocols/new.json.jbuilder b/app/views/access_permissions/protocols/new.json.jbuilder new file mode 100644 index 000000000..8fd64ccf4 --- /dev/null +++ b/app/views/access_permissions/protocols/new.json.jbuilder @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +json.html controller.render_to_string( + partial: 'access_permissions/partials/new_assignments_form', + formats: [:html], + locals: { + resource: @protocol, + form_object: @form, + create_path: access_permissions_protocol_path(id: @protocol.id), + resource_path: edit_access_permissions_protocol_path(@protocol) + }, + layout: false +) diff --git a/app/views/access_permissions/protocols/protocol_member.json.jbuilder b/app/views/access_permissions/protocols/protocol_member.json.jbuilder new file mode 100644 index 000000000..7024964e9 --- /dev/null +++ b/app/views/access_permissions/protocols/protocol_member.json.jbuilder @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +json.form controller.render_to_string( + partial: 'access_permissions/partials/protocol_member_field', + formats: [:html], + locals: { + user: @user_assignment.user, + protocol: @protocol, + update_path: access_permissions_protocol_path(@protocol) + }, + layout: false +) diff --git a/app/views/access_permissions/protocols/show.json.jbuilder b/app/views/access_permissions/protocols/show.json.jbuilder new file mode 100644 index 000000000..97c1a389c --- /dev/null +++ b/app/views/access_permissions/protocols/show.json.jbuilder @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +json.modal controller.render_to_string( + partial: 'access_permissions/protocols/modals/show_modal', + formats: [:html], + locals: { + protocol: @protocol, + users: @protocol.manually_assigned_users, + can_manage_resource: can_manage_protocol_users?(@protocol) + }, + layout: false +) diff --git a/app/views/access_permissions/protocols/update_default_public_user_role.json.jbuilder b/app/views/access_permissions/protocols/update_default_public_user_role.json.jbuilder new file mode 100644 index 000000000..77e3bb070 --- /dev/null +++ b/app/views/access_permissions/protocols/update_default_public_user_role.json.jbuilder @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +json.form controller.render_to_string( + partial: 'access_permissions/partials/default_public_user_role_form', + formats: [:html], + locals: { + protocol: @protocol, + editable: true + }, + layout: false +) diff --git a/config/locales/en.yml b/config/locales/en.yml index c40e6c62e..54d85b8e0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -3036,6 +3036,7 @@ en: user_assignment: current_assignee: "(you)" change_project_role: "Change project role" + change_protocol_role: "Change protocol role" select_default_user_role: "Select default user role" change_experiment_role: "Change experiment role" change_my_module_role: "Change task role" @@ -3078,6 +3079,9 @@ en: project: "Project" project_tooltip: "This role was set on this project." project_tooltip_inherit: "This role was inherited from the project." + protocol: "Protocol" + protocol_tooltip: "This role was set on this protocol." + protocol_tooltip_inherit: "This role was inherited from the protocol." experiment: "Experiment" experiment_tooltip: "This role was set on this experiment." experiment_tooltip_inherit: "This role was inherited from the experiment." @@ -3091,6 +3095,14 @@ en: show_modal: title: "Access to %{resource_name}" new_resource_assignments: "Grant new access to %{resource}" + protocols: + modals: + show_modal: + title: "Access to %{resource_name}" + new_resource_assignments: "Grant new access to %{resource}" + edit_modal: + title: "Manage access for %{resource_name}" + new_resource_assignments: "Grant new access to %{resource}" experiments: modals: show_modal: diff --git a/config/routes.rb b/config/routes.rb index 8c4daea22..0c0b96966 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -280,6 +280,9 @@ Rails.application.routes.draw do end namespace :access_permissions do + resources :protocols, defaults: { format: 'json' } do + put :update_default_public_user_role, on: :member + end resources :projects, defaults: { format: 'json' } do put :update_default_public_user_role, on: :member resources :experiments, only: %i(show update edit) do