mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-09-07 21:55:20 +08:00
add assign user permission to experiment level
This commit is contained in:
parent
331a68e9b6
commit
ac91d9c2c4
19 changed files with 275 additions and 13 deletions
60
app/controllers/access_permissions/experiments_controller.rb
Normal file
60
app/controllers/access_permissions/experiments_controller.rb
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module AccessPermissions
|
||||||
|
class ExperimentsController < ApplicationController
|
||||||
|
before_action :set_project
|
||||||
|
before_action :set_experiment
|
||||||
|
before_action :check_read_permissions, only: %i(show)
|
||||||
|
before_action :check_manage_permissions, only: %i(create edit update)
|
||||||
|
|
||||||
|
def show
|
||||||
|
respond_to do |format|
|
||||||
|
format.json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def edit
|
||||||
|
respond_to do |format|
|
||||||
|
format.json
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
@experiment_member = ExperimentMember.new(current_user, @experiment, @project)
|
||||||
|
@experiment_member.update(permitted_update_params)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json do
|
||||||
|
render :experiment_member
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def permitted_update_params
|
||||||
|
params.require(:experiment_member)
|
||||||
|
.permit(%i(user_role_id user_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_project
|
||||||
|
@project = current_team.projects.find_by(id: params[:project_id])
|
||||||
|
|
||||||
|
render_404 unless @project
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_experiment
|
||||||
|
@experiment = @project.experiments.includes(user_assignments: %i(user user_role)).find_by(id: params[:id])
|
||||||
|
|
||||||
|
render_404 unless @experiment
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_manage_permissions
|
||||||
|
render_403 unless can_manage_experiment?(@experiment)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_read_permissions
|
||||||
|
render_403 unless can_read_experiment?(@experiment)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -264,7 +264,7 @@ class ProjectsController < ApplicationController
|
||||||
render json: {
|
render json: {
|
||||||
cards_html: render_to_string(
|
cards_html: render_to_string(
|
||||||
partial: 'projects/show/experiments_list.html.erb',
|
partial: 'projects/show/experiments_list.html.erb',
|
||||||
locals: { cards: overview_service.experiments }
|
locals: { cards: overview_service.experiments, project: @project }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,4 +9,23 @@ module UserAssignmentsHelper
|
||||||
end
|
end
|
||||||
sanitize_input(display_name)
|
sanitize_input(display_name)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def user_assignment_resource_role_name(user_assignment, user, resource)
|
||||||
|
# Triggers N+1 but the partial is cached
|
||||||
|
|
||||||
|
if resource.is_a?(Experiment)
|
||||||
|
project_user_assignment = resource.permission_parent.user_assignments.find_by(user: user)
|
||||||
|
current_user_assignment_name = user_assignment&.user_role&.name
|
||||||
|
|
||||||
|
[
|
||||||
|
t('user_assignment.from_project', user_role: project_user_assignment.user_role.name),
|
||||||
|
current_user_assignment_name
|
||||||
|
].compact.join(' / ')
|
||||||
|
elsif resource.is_a?(MyModule)
|
||||||
|
# TODO
|
||||||
|
else
|
||||||
|
user_assignment.user_role.name
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -10,4 +10,8 @@ module UserRolesHelper
|
||||||
def new_user_roles_collection
|
def new_user_roles_collection
|
||||||
[[t('user_assignment.select_role'), nil]] + user_roles_collection
|
[[t('user_assignment.select_role'), nil]] + user_roles_collection
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def experiment_user_roles_collection
|
||||||
|
[[t('user_assignment.select_role'), nil]] + user_roles_collection
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
44
app/models/experiment_member.rb
Normal file
44
app/models/experiment_member.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ExperimentMember
|
||||||
|
include ActiveModel::Model
|
||||||
|
|
||||||
|
attr_accessor :user_id, :user_role_id
|
||||||
|
attr_reader :current_user, :experiment, :user, :project, :user_role
|
||||||
|
|
||||||
|
|
||||||
|
def initialize(current_user, experiment, project, user = nil)
|
||||||
|
@experiment = experiment
|
||||||
|
@current_user = current_user
|
||||||
|
@project = project
|
||||||
|
|
||||||
|
if user
|
||||||
|
@user = user
|
||||||
|
@user_role = UserAssignment.find_by(assignable: experiment, user: user)&.user_role
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def update(params)
|
||||||
|
self.user_role_id = params[:user_role_id]
|
||||||
|
self.user_id = params[:user_id]
|
||||||
|
|
||||||
|
ActiveRecord::Base.transaction do
|
||||||
|
@user = @project.users.find(user_id)
|
||||||
|
@user_role = UserRole.find_by(id: user_role_id)
|
||||||
|
user_assignment = UserAssignment.find_by(assignable: experiment, user: user)
|
||||||
|
|
||||||
|
if user_assignment.present? && user_role.nil?
|
||||||
|
user_assignment.destroy
|
||||||
|
elsif user_assignment.present?
|
||||||
|
user_assignment.update!(user_role: user_role)
|
||||||
|
else
|
||||||
|
UserAssignment.create!(
|
||||||
|
assignable: experiment,
|
||||||
|
user: user,
|
||||||
|
user_role: user_role,
|
||||||
|
assigned_by: current_user
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
13
app/views/access_permissions/experiments/edit.json.jbuilder
Normal file
13
app/views/access_permissions/experiments/edit.json.jbuilder
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.modal controller.render_to_string(
|
||||||
|
partial: 'access_permissions/experiments/modals/edit_modal',
|
||||||
|
formats: [:html],
|
||||||
|
locals: {
|
||||||
|
experiment: @experiment,
|
||||||
|
project: @project,
|
||||||
|
users: @project.users,
|
||||||
|
project_path: project_path(@project)
|
||||||
|
},
|
||||||
|
layout: false
|
||||||
|
)
|
|
@ -0,0 +1,13 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.form controller.render_to_string(
|
||||||
|
partial: 'access_permissions/partials/experiment_member_field',
|
||||||
|
formats: [:html],
|
||||||
|
locals: {
|
||||||
|
user: @experiment_member.user,
|
||||||
|
experiment: @experiment_member.experiment,
|
||||||
|
project: @experiment_member.project,
|
||||||
|
update_path: access_permissions_project_experiment_path(@experiment_member.project, @experiment_member.experiment)
|
||||||
|
},
|
||||||
|
layout: false
|
||||||
|
)
|
|
@ -0,0 +1,30 @@
|
||||||
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
|
<div class="modal fade" tabindex="-1" role="dialog" data-action="modal-close" data-target="<%= project_path %>">
|
||||||
|
<div class="modal-dialog modal-md" role="document">
|
||||||
|
<div class="modal-content" id="user_assignments_modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title"><%= t '.title', resource_name: experiment.name %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<% users.each do |user| %>
|
||||||
|
<% user_assignment = experiment.user_assignments.find_by(user: user) %>
|
||||||
|
|
||||||
|
<% cache [user_assignment, experiment, user] do %>
|
||||||
|
<%= render partial: 'access_permissions/partials/experiment_member_field',
|
||||||
|
locals: {
|
||||||
|
user: user,
|
||||||
|
project: project,
|
||||||
|
experiment: experiment,
|
||||||
|
update_path: access_permissions_project_experiment_path(project, experiment)
|
||||||
|
} %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type='button' class='btn btn-default' data-dismiss='modal'><%= t('general.cancel')%></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
|
<div class="modal fade" tabindex="-1" role="dialog" data-action="modal-close" data-target="<%= project_path %>">
|
||||||
|
<div class="modal-dialog modal-md" role="document">
|
||||||
|
<div class="modal-content" id="user_assignments_modal">
|
||||||
|
<div class="modal-header">
|
||||||
|
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
|
||||||
|
<h4 class="modal-title"><%= t '.title', resource_name: experiment.name %></h4>
|
||||||
|
</div>
|
||||||
|
<div class="modal-body">
|
||||||
|
<% users.each do |user| %>
|
||||||
|
<% user_assignment = experiment.user_assignments.find_by(user: user) %>
|
||||||
|
|
||||||
|
<% cache [user_assignment, experiment, current_user, user] do %>
|
||||||
|
<%= render partial: 'access_permissions/partials/user_assignment', locals: { user_assignment: user_assignment, user: user, resource: experiment } %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
<div class="modal-footer">
|
||||||
|
<button type='button' class='btn btn-default' data-dismiss='modal'><%= t('general.cancel')%></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
12
app/views/access_permissions/experiments/show.json.jbuilder
Normal file
12
app/views/access_permissions/experiments/show.json.jbuilder
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
json.modal controller.render_to_string(
|
||||||
|
partial: 'access_permissions/experiments/modals/show_modal',
|
||||||
|
formats: [:html],
|
||||||
|
locals: {
|
||||||
|
experiment: @experiment,
|
||||||
|
users: @project.users,
|
||||||
|
project_path: project_path(@project)
|
||||||
|
},
|
||||||
|
layout: false
|
||||||
|
)
|
|
@ -0,0 +1,25 @@
|
||||||
|
<% # frozen_string_literal: true %>
|
||||||
|
|
||||||
|
<%
|
||||||
|
experiment_member = ExperimentMember.new(current_user, experiment, project, user)
|
||||||
|
item_id = dom_id(user, :experiment_member)
|
||||||
|
%>
|
||||||
|
|
||||||
|
<%= form_with(model: experiment_member, url: update_path, method: :put, remote: true, html: { class: 'row experiment-member-item', id: item_id, data: { action: 'replace-form autosave-form' } }) do |f| %>
|
||||||
|
<%= f.hidden_field :user_id, value: f.object.user.id %>
|
||||||
|
<div class="col-xs-1">
|
||||||
|
<span class="global-avatar-container">
|
||||||
|
<%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-6">
|
||||||
|
<span><%= current_assignee_name(user) %></span>
|
||||||
|
<br>
|
||||||
|
<small class="text-muted"><%= user_assignment_resource_role_name(experiment_member, user, experiment) %></small>
|
||||||
|
</div>
|
||||||
|
<% unless user == current_user %>
|
||||||
|
<div class="col-xs-5">
|
||||||
|
<%= f.select :user_role_id, options_for_select(experiment_user_roles_collection, selected: f.object.user_role&.id), {}, class: 'form-control selectpicker' %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
|
@ -15,7 +15,7 @@
|
||||||
<div class="col-xs-3">
|
<div class="col-xs-3">
|
||||||
<span><%= current_assignee_name(user) %></span>
|
<span><%= current_assignee_name(user) %></span>
|
||||||
<br>
|
<br>
|
||||||
<small class="text-muted"><%= project_member.user_role.name %></small>
|
<small class="text-muted"><%= user_assignment_resource_role_name(project_member, user, project) %></small>
|
||||||
</div>
|
</div>
|
||||||
<% unless user == current_user %>
|
<% unless user == current_user %>
|
||||||
<div class="col-xs-7">
|
<div class="col-xs-7">
|
||||||
|
|
|
@ -3,13 +3,13 @@
|
||||||
<div class="row project-member-item">
|
<div class="row project-member-item">
|
||||||
<div class="col-xs-2">
|
<div class="col-xs-2">
|
||||||
<span class="global-avatar-container">
|
<span class="global-avatar-container">
|
||||||
<%= image_tag avatar_path(user_assignment.user, :icon_small), title: current_assignee_name(user_assignment.user), class: 'img-circle pull-left' %>
|
<%= image_tag avatar_path(user, :icon_small), title: current_assignee_name(user), class: 'img-circle pull-left' %>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="col-xs-10 col-sm-4">
|
<div class="col-xs-10 col-sm-4">
|
||||||
<span><%= current_assignee_name(user_assignment.user) %></span>
|
<span><%= current_assignee_name(user) %></span>
|
||||||
<br>
|
<br>
|
||||||
<small class="text-muted"><%= user_assignment.user_role.name %></small>
|
<small class="text-muted"><%= user_assignment_resource_role_name(user_assignment, user, resource) %></small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,7 +8,11 @@
|
||||||
<h4 class="modal-title"><%= t '.title', resource_name: resource.name %></h4>
|
<h4 class="modal-title"><%= t '.title', resource_name: resource.name %></h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<%= render partial: 'access_permissions/partials/user_assignment', collection: resource.user_assignments, cached: ->(user_assignment) { [user_assignment. resource, current_user] } %>
|
<% resource.user_assignments.each do |user_assignment| %>
|
||||||
|
<% cache [user_assignment, resource, current_user, user_assignment.user] do %>
|
||||||
|
<%= render partial: 'access_permissions/partials/user_assignment', locals: { user_assignment: user_assignment, user: user_assignment.user, resource: resource } %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<% if can_manage_resource %>
|
<% if can_manage_resource %>
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
json.modal controller.render_to_string(
|
json.modal controller.render_to_string(
|
||||||
partial: 'access_permissions/modals/show_modal',
|
partial: 'access_permissions/projects/modals/show_modal',
|
||||||
formats: [:html],
|
formats: [:html],
|
||||||
locals: {
|
locals: {
|
||||||
resource: @project,
|
resource: @project,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<span class="sci-checkbox-label"></span>
|
<span class="sci-checkbox-label"></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="experiment-name-cell table-cell">
|
<div class="experiment-name-cell table-cell">
|
||||||
<% if experiment.archived_branch? %>
|
<% if experiment.archived_branch? %>
|
||||||
<%= link_to experiment.name, module_archive_experiment_path(experiment), title: experiment.name %>
|
<%= link_to experiment.name, module_archive_experiment_path(experiment), title: experiment.name %>
|
||||||
|
@ -55,6 +56,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="description-cell table-cell">
|
<div class="description-cell table-cell">
|
||||||
|
<%= link_to 'Experiment Accesss', edit_access_permissions_project_experiment_path(project, experiment), remote: true, data: { action: 'remote-modal'} %>
|
||||||
|
<%= link_to 'Show Experiment Accesss', access_permissions_project_experiment_path(project, experiment), remote: true, data: { action: 'remote-modal'} %>
|
||||||
<div class="description-text">
|
<div class="description-text">
|
||||||
<%= custom_auto_link(experiment.description, team: current_team) %>
|
<%= custom_auto_link(experiment.description, team: current_team) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<% cards.each do |card| %>
|
<% cards.each do |card| %>
|
||||||
<% cache [current_user, card] do %>
|
<% cache [current_user, card] do %>
|
||||||
<%= render partial: 'projects/show/experiment_card', locals: { experiment: card } %>
|
<%= render partial: 'projects/show/experiment_card', locals: { experiment: card, project: project } %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
|
@ -2318,6 +2318,8 @@ en:
|
||||||
user_assignment:
|
user_assignment:
|
||||||
current_assignee: "(you)"
|
current_assignee: "(you)"
|
||||||
select_role: "Select role"
|
select_role: "Select role"
|
||||||
|
from_project: "%{user_role} [from project]"
|
||||||
|
experiment_select_role: "Change experiment role"
|
||||||
access_permissions:
|
access_permissions:
|
||||||
create:
|
create:
|
||||||
success:
|
success:
|
||||||
|
@ -2337,10 +2339,17 @@ en:
|
||||||
submit_singular: "Grand access to 1 user"
|
submit_singular: "Grand access to 1 user"
|
||||||
submit_plural: "Grand access to {num} users"
|
submit_plural: "Grand access to {num} users"
|
||||||
find_people_html: "🔍 Find people"
|
find_people_html: "🔍 Find people"
|
||||||
modals:
|
projects:
|
||||||
show_modal:
|
modals:
|
||||||
title: "Access to %{resource_name}"
|
show_modal:
|
||||||
new_resource_assignments: "Grant new access to %{resource}"
|
title: "Access to %{resource_name}"
|
||||||
|
new_resource_assignments: "Grant new access to %{resource}"
|
||||||
|
experiments:
|
||||||
|
modals:
|
||||||
|
show_modal:
|
||||||
|
title: "Access to %{resource_name}"
|
||||||
|
edit_modal:
|
||||||
|
title: "Manage access for %{resource_name}"
|
||||||
zip_export:
|
zip_export:
|
||||||
modal_label: 'Export inventory'
|
modal_label: 'Export inventory'
|
||||||
notification_title: 'Your requested export package is ready!'
|
notification_title: 'Your requested export package is ready!'
|
||||||
|
|
|
@ -228,7 +228,9 @@ Rails.application.routes.draw do
|
||||||
end
|
end
|
||||||
|
|
||||||
namespace :access_permissions do
|
namespace :access_permissions do
|
||||||
resources :projects
|
resources :projects, defaults: { format: 'json' } do
|
||||||
|
resources :experiments, only: %i(show update edit)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
resources :projects, except: [:destroy] do
|
resources :projects, except: [:destroy] do
|
||||||
|
|
Loading…
Add table
Reference in a new issue