mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2025-10-03 18:35:36 +08:00
Add permission management to repositories [SCI-12029]
This commit is contained in:
parent
3544131b8b
commit
1693729b42
17 changed files with 170 additions and 30 deletions
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module AccessPermissions
|
||||
class RepositoriesController < BaseController
|
||||
private
|
||||
|
||||
def set_model
|
||||
@model = current_team.repositories.includes(user_assignments: %i(user user_role)).find_by(id: params[:id])
|
||||
|
||||
render_404 unless @model
|
||||
end
|
||||
|
||||
def check_manage_permissions
|
||||
render_403 unless can_manage_repository_users?(@model)
|
||||
end
|
||||
|
||||
def check_read_permissions
|
||||
render_403 unless can_read_repository?(@model) || can_manage_team?(@model.team)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -8,17 +8,18 @@ class RepositoriesController < ApplicationController
|
|||
include TeamsHelper
|
||||
include RepositoriesDatatableHelper
|
||||
include MyModulesHelper
|
||||
include UserRolesHelper
|
||||
|
||||
before_action :switch_team_with_param, only: %i(index)
|
||||
before_action :load_repository, except: %i(index create create_modal sidebar archive restore actions_toolbar
|
||||
export_repositories list)
|
||||
export_repositories list user_roles)
|
||||
before_action :load_repositories, only: %i(index list)
|
||||
before_action :load_repositories_for_archiving, only: :archive
|
||||
before_action :load_repositories_for_restoring, only: :restore
|
||||
before_action :check_view_all_permissions, only: %i(index sidebar list)
|
||||
before_action :check_view_permissions, except: %i(index create_modal create update destroy parse_sheet
|
||||
import_records sidebar archive restore actions_toolbar
|
||||
export_repositories list)
|
||||
export_repositories list user_roles)
|
||||
before_action :check_manage_permissions, only: %i(rename_modal update)
|
||||
before_action :check_delete_permissions, only: %i(destroy destroy_modal)
|
||||
before_action :check_archive_permissions, only: %i(archive restore)
|
||||
|
@ -482,6 +483,10 @@ class RepositoriesController < ApplicationController
|
|||
}
|
||||
end
|
||||
|
||||
def user_roles
|
||||
render json: { data: user_roles_collection(Repository.new).map(&:reverse) }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_repository
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
@share="share"
|
||||
@create="newRepository = true"
|
||||
@tableReloaded="reloadingTable = false"
|
||||
@access="access"
|
||||
/>
|
||||
</div>
|
||||
<ConfirmationModal
|
||||
|
@ -75,6 +76,8 @@
|
|||
confirm: 'e2e-BT-confirmSharingChangesModal-delete'
|
||||
}"
|
||||
></ConfirmationModal>
|
||||
<AccessModal v-if="accessModalParams" :params="accessModalParams"
|
||||
@close="accessModalParams = null" @refresh="reloadingTable = true" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
@ -89,6 +92,8 @@ import DuplicateRepositoryModal from './modals/duplicate.vue';
|
|||
import ShareObjectModal from '../shared/share_modal.vue';
|
||||
import DataTable from '../shared/datatable/table.vue';
|
||||
import NameRenderer from './renderers/name.vue';
|
||||
import AccessModal from '../shared/access_modal/modal.vue';
|
||||
import UsersRenderer from '../projects/renderers/users.vue';
|
||||
|
||||
export default {
|
||||
name: 'RepositoriesTable',
|
||||
|
@ -100,7 +105,9 @@ export default {
|
|||
EditRepositoryModal,
|
||||
DuplicateRepositoryModal,
|
||||
NameRenderer,
|
||||
ShareObjectModal
|
||||
ShareObjectModal,
|
||||
AccessModal,
|
||||
UsersRenderer
|
||||
},
|
||||
props: {
|
||||
dataSource: {
|
||||
|
@ -125,11 +132,16 @@ export default {
|
|||
archivedPageUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
userRolesUrl: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
reloadingTable: false,
|
||||
accessModalParams: null,
|
||||
exportRepository: null,
|
||||
newRepository: false,
|
||||
editRepository: null,
|
||||
|
@ -186,8 +198,14 @@ export default {
|
|||
field: 'created_at',
|
||||
headerName: this.i18n.t('libraries.index.table.added_on'),
|
||||
sortable: true
|
||||
},
|
||||
{
|
||||
}, {
|
||||
field: 'assigned_users',
|
||||
headerName: this.i18n.t('repositories.index.table.access'),
|
||||
sortable: true,
|
||||
cellRenderer: 'UsersRenderer',
|
||||
minWidth: 210,
|
||||
notSelectable: true
|
||||
}, {
|
||||
field: 'created_by',
|
||||
headerName: this.i18n.t('libraries.index.table.added_by'),
|
||||
sortable: true
|
||||
|
@ -252,6 +270,12 @@ export default {
|
|||
HelperModule.flashAlertMsg(error.response.data.error, 'danger');
|
||||
});
|
||||
},
|
||||
access(_event, rows) {
|
||||
this.accessModalParams = {
|
||||
object: rows[0],
|
||||
roles_path: this.userRolesUrl
|
||||
};
|
||||
},
|
||||
async deleteRepository(event, rows) {
|
||||
const [repository] = rows;
|
||||
this.deleteModal.e2eAttributes = {
|
||||
|
|
|
@ -12,8 +12,6 @@ module UserAssignments
|
|||
assign_to_experiment(object)
|
||||
when MyModule
|
||||
assign_to_my_module(object)
|
||||
when Repository
|
||||
assign_to_repository(object)
|
||||
when Protocol
|
||||
assign_to_protocol(object)
|
||||
when Report
|
||||
|
@ -54,13 +52,6 @@ module UserAssignments
|
|||
end
|
||||
end
|
||||
|
||||
def assign_to_repository(repository)
|
||||
team = repository.team
|
||||
team.user_assignments.find_each do |assignment|
|
||||
create_or_update_assignment(assignment, repository)
|
||||
end
|
||||
end
|
||||
|
||||
def assign_to_protocol(protocol)
|
||||
if protocol.parent_id && protocol.in_repository_draft?
|
||||
Protocol.transaction(requires_new: true) do
|
||||
|
|
|
@ -29,6 +29,7 @@ class Repository < RepositoryBase
|
|||
inverse_of: :original_repository
|
||||
has_many :repository_ledger_records, as: :reference, dependent: :nullify
|
||||
has_many :repository_table_filters, dependent: :destroy
|
||||
has_many :users, through: :user_assignments
|
||||
|
||||
before_save :sync_name_with_snapshots, if: :name_changed?
|
||||
before_destroy :refresh_report_references_on_destroy, prepend: true
|
||||
|
@ -70,6 +71,14 @@ class Repository < RepositoryBase
|
|||
active.where(id: (readable_ids + shared_with_team_ids + globally_shared_ids).uniq)
|
||||
}
|
||||
|
||||
def top_level_assignable
|
||||
true
|
||||
end
|
||||
|
||||
def has_permission_children?
|
||||
false
|
||||
end
|
||||
|
||||
def readable_by_user?(user)
|
||||
permission_granted?(user, RepositoryPermissions::READ)
|
||||
end
|
||||
|
|
|
@ -127,6 +127,10 @@ Canaid::Permissions.register_for(Repository) do
|
|||
can :manage_repository_stock do |user, repository|
|
||||
RepositoryBase.stock_management_enabled? && can_manage_repository_rows?(user, repository)
|
||||
end
|
||||
|
||||
can :manage_repository_users do |user, repository|
|
||||
repository.permission_granted?(user, RepositoryPermissions::USERS_MANAGE)
|
||||
end
|
||||
end
|
||||
|
||||
Canaid::Permissions.register_for(RepositoryColumn) do
|
||||
|
|
|
@ -78,8 +78,6 @@ module Lists
|
|||
urls_list[:create_access] = access_permissions_forms_path(id: object.id)
|
||||
urls_list[:unassigned_user_groups] = unassigned_user_groups_access_permissions_form_path(id: object.id)
|
||||
urls_list[:user_group_members] = users_users_settings_team_user_groups_path(team_id: object.team.id)
|
||||
urls_list[:default_public_user_role_path] =
|
||||
update_default_public_user_role_access_permissions_form_path(object)
|
||||
end
|
||||
|
||||
urls_list
|
||||
|
|
|
@ -168,8 +168,6 @@ module Lists
|
|||
urls_list[:unassigned_user_groups] = unassigned_user_groups_access_permissions_project_path(id: object.id)
|
||||
urls_list[:create_access] = access_permissions_projects_path(id: object.id)
|
||||
urls_list[:user_group_members] = users_users_settings_team_user_groups_path(team_id: object.team.id)
|
||||
urls_list[:default_public_user_role_path] =
|
||||
update_default_public_user_role_access_permissions_project_path(object)
|
||||
end
|
||||
|
||||
urls_list
|
||||
|
|
|
@ -122,8 +122,6 @@ module Lists
|
|||
urls_list[:create_access] = access_permissions_protocols_path(id: object.id)
|
||||
urls_list[:unassigned_user_groups] = unassigned_user_groups_access_permissions_protocol_path(id: object.id)
|
||||
urls_list[:user_group_members] = users_users_settings_team_user_groups_path(team_id: object.team.id)
|
||||
urls_list[:default_public_user_role_path] =
|
||||
update_default_public_user_role_access_permissions_protocol_path(object)
|
||||
end
|
||||
|
||||
urls_list
|
||||
|
|
|
@ -6,7 +6,8 @@ module Lists
|
|||
include Rails.application.routes.url_helpers
|
||||
include ShareableSerializer
|
||||
|
||||
attributes :name, :code, :nr_of_rows, :team, :created_at, :created_by, :archived_on, :archived_by, :urls
|
||||
attributes :name, :code, :nr_of_rows, :team, :created_at, :created_by, :archived_on, :archived_by,
|
||||
:urls, :top_level_assignable, :assigned_users, :permissions
|
||||
|
||||
def nr_of_rows
|
||||
object[:repository_rows_count]
|
||||
|
@ -32,16 +33,52 @@ module Lists
|
|||
object[:archived_by_user]
|
||||
end
|
||||
|
||||
def urls
|
||||
def assigned_users
|
||||
users = object.user_assignments.map do |ua|
|
||||
{
|
||||
avatar: avatar_path(ua.user, :icon_small),
|
||||
full_name: ua.user_name_with_role
|
||||
}
|
||||
end
|
||||
|
||||
user_groups = object.user_group_assignments.map do |ua|
|
||||
{
|
||||
avatar: ActionController::Base.helpers.asset_path('icon/group.svg'),
|
||||
full_name: ua.user_group_name_with_role
|
||||
}
|
||||
end
|
||||
|
||||
users + user_groups
|
||||
end
|
||||
|
||||
def permissions
|
||||
{
|
||||
manage_users_assignments: can_manage_repository_users?(object)
|
||||
}
|
||||
end
|
||||
|
||||
def urls
|
||||
urls = {
|
||||
show: repository_path(object),
|
||||
update: team_repository_path(current_user.current_team, id: object, format: :json),
|
||||
duplicate: team_repository_copy_path(current_user.current_team, repository_id: object, format: :json),
|
||||
shareable_teams: shareable_teams_team_shared_objects_path(
|
||||
current_user.current_team, object_id: object.id, object_type: 'Repository'
|
||||
),
|
||||
show_access: access_permissions_repository_path(object),
|
||||
share: team_shared_objects_path(current_user.current_team, object_id: object.id, object_type: 'Repository')
|
||||
}
|
||||
|
||||
if can_manage_repository_users?(object)
|
||||
urls[:update_access] = access_permissions_repository_path(id: object)
|
||||
urls[:new_access] = new_access_permissions_repository_path(id: object.id)
|
||||
urls[:create_access] = access_permissions_repositories_path(id: object.id)
|
||||
urls[:unassigned_user_groups] = unassigned_user_groups_access_permissions_project_path(id: object.id)
|
||||
urls[:user_group_members] = users_users_settings_team_user_groups_path(team_id: object.team.id)
|
||||
urls[:show_user_group_assignments_access] = show_user_group_assignments_access_permissions_repository_path(object)
|
||||
end
|
||||
|
||||
urls
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -60,7 +60,7 @@ class UserAssignmentSerializer < ActiveModel::Serializer
|
|||
def user_assignment_resource_role_name(user, resource, inherit = '')
|
||||
user_assignment = resource.user_assignments.find_by(user: user)
|
||||
|
||||
return '' if ([Project, Protocol].include?(resource.class) && inherit.blank?) || user_assignment.blank?
|
||||
return '' if ([Project, Protocol, Repository].any? { |c| resource.is_a?(c) } && inherit.blank?) || user_assignment.blank?
|
||||
|
||||
if user_assignment.automatically_assigned? && resource.permission_parent.present?
|
||||
parent = resource.permission_parent
|
||||
|
|
|
@ -22,14 +22,25 @@ module Toolbars
|
|||
return [] if @repositories.none?
|
||||
|
||||
if @archived_state
|
||||
[export_action, restore_action, delete_action]
|
||||
[access_action, export_action, restore_action, delete_action]
|
||||
else
|
||||
[rename_action, duplicate_action, export_action, archive_action, share_action]
|
||||
[access_action, rename_action, duplicate_action, export_action, archive_action, share_action]
|
||||
end.compact
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def access_action
|
||||
return unless @single
|
||||
|
||||
{
|
||||
name: 'access',
|
||||
label: I18n.t('general.access'),
|
||||
icon: 'sn-icon sn-icon-project-member-access',
|
||||
type: :emit
|
||||
}
|
||||
end
|
||||
|
||||
def rename_action
|
||||
return unless @single && can_manage_repository?(@repository)
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
active-page-url="<%= repositories_path %>"
|
||||
archived-page-url="<%= repositories_path(view_mode: :archived) %>"
|
||||
current-view-mode="<%= params[:view_mode] || :active %>"
|
||||
user-roles-url="<%= user_roles_repositories_path %>"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -612,7 +612,16 @@ class Extends
|
|||
experiment_access_changed_user_group: 393,
|
||||
my_module_access_changed_user_group: 394,
|
||||
step_and_result_linked: 395,
|
||||
step_and_result_unlinked: 396
|
||||
step_and_result_unlinked: 396,
|
||||
repository_access_granted: 397,
|
||||
repository_access_changed: 398,
|
||||
repository_access_revoked: 399,
|
||||
repository_access_granted_all_team_members: 400,
|
||||
repository_access_changed_all_team_members: 401,
|
||||
repository_access_revoked_all_team_members: 402,
|
||||
repository_access_granted_user_group: 403,
|
||||
repository_access_changed_user_group: 404,
|
||||
repository_access_revoked_user_group: 405
|
||||
}
|
||||
|
||||
ACTIVITY_GROUPS = {
|
||||
|
@ -626,7 +635,7 @@ class Extends
|
|||
experiment: [*27..31, 57, 141, 165, *363..369, 393],
|
||||
reports: [48, 50, 49, 163, 164],
|
||||
inventories: [70, 71, 105, 144, 145, 72, 73, 74, 102, 142, 143, 75, 76, 77,
|
||||
78, 96, 107, 113, 114, *133..136, 180, 181, 182, *292..298, 308, 329],
|
||||
78, 96, 107, 113, 114, *133..136, 180, 181, 182, *292..298, 308, 329, *397..405],
|
||||
protocol_repository: [80, 103, 89, 87, 79, 90, 91, 88, 85, 86, 84, 81, 82,
|
||||
83, 101, 112, 123, 125, 117, 119, 129, 131, 187, 186,
|
||||
190, 191, *204..215, 220, 223, 227, 228, 229, *230..235,
|
||||
|
|
|
@ -3253,6 +3253,7 @@ en:
|
|||
no_libraries:
|
||||
create_new_button: "New inventory"
|
||||
create_new_button_tooltip: "Create new inventory"
|
||||
access: 'Access'
|
||||
show:
|
||||
head_title: "Inventories | %{library}"
|
||||
repository_row:
|
||||
|
@ -4609,6 +4610,8 @@ en:
|
|||
mymodule_tooltip: "This role was set on this task"
|
||||
form_tooltip: "This role was set on this form."
|
||||
form_tooltip_inherit: "This role was inherited from the form."
|
||||
repository_tooltip: "This role was set on this inventory."
|
||||
repository_tooltip_inherit: "This role was inherited from the inventory."
|
||||
public_members_dropdown:
|
||||
title: "Members of team %{team}"
|
||||
|
||||
|
@ -4624,6 +4627,12 @@ en:
|
|||
title: "Access to %{resource_name}"
|
||||
edit_modal:
|
||||
title: "Manage access for %{resource_name}"
|
||||
repositories:
|
||||
modals:
|
||||
show_modal:
|
||||
title: "Access to %{resource_name}"
|
||||
edit_modal:
|
||||
title: "Manage access for %{resource_name}"
|
||||
experiments:
|
||||
modals:
|
||||
show_modal:
|
||||
|
|
|
@ -412,6 +412,15 @@ en:
|
|||
step_and_result_unlinked_html: "%{user} unlinked result <strong>%{result}</strong> and step <strong>%{position}</strong> <strong>%{step}</strong> on task <strong>%{my_module}</strong>."
|
||||
step_and_result_linked_html: "%{user} linked result <strong>%{result}</strong> and step <strong>%{step_position}</strong> <strong>%{step}</strong> on task <strong>%{my_module}</strong>."
|
||||
step_and_result_unlinked_html: "%{user} unlinked result <strong>%{result}</strong> and step <strong>%{step_position}</strong> <strong>%{step}</strong> on task <strong>%{my_module}</strong>."
|
||||
repository_access_granted_html: "%{user} granted access to %{user_target} with user role %{role} to inventory %{repository}."
|
||||
repository_access_changed_html: "%{user} changed %{user_target}’s role on inventory %{repository} to %{role}."
|
||||
repository_access_revoked_html: "%{user} removed %{user_target} with user role %{role} from inventory %{repository}."
|
||||
repository_access_granted_all_team_members_html: "%{user} granted access to all team members of %{team} team with user role %{role} to inventory %{repository}."
|
||||
repository_access_changed_all_team_members_html: "%{user} changed %{team}’s role on inventory %{repository} to %{role}."
|
||||
repository_access_revoked_all_team_members_html: "%{user} removed %{team} team members with user role %{role} from inventory %{repository}."
|
||||
repository_granted_user_group_html: "%{user} granted access to %{user_group} with user role %{role} to inventory template %{repository}."
|
||||
repository_changed_user_group_html: "%{user} changed %{user_group}'s role on inventory template %{repository} to %{role}."
|
||||
repository_revoked_user_group_html: "%{user} removed group %{user_group} with user role %{role} from inventory template %{repository}."
|
||||
activity_name:
|
||||
create_project: "Project created"
|
||||
edit_project: "Project edited"
|
||||
|
@ -779,6 +788,15 @@ en:
|
|||
my_module_access_changed_user_group: "Change role of group"
|
||||
step_and_result_linked: "Task Result and Task protocol step linked"
|
||||
step_and_result_unlinked: "Task Result and Task protocol step unlinked"
|
||||
repository_access_granted: "User granted access to inventory"
|
||||
repository_access_changed: "User role changed on inventory"
|
||||
repository_access_revoked: "User removed from inventory"
|
||||
repository_access_granted_all_team_members: "Grant access to all team members"
|
||||
repository_access_changed_all_team_members: "Change role of all team members"
|
||||
repository_access_revoked_all_team_members: "Remove access from all team members"
|
||||
repository_access_granted_user_group: "Grant access to group"
|
||||
repository_access_changed_user_group: "Change role of group"
|
||||
repository_access_revoked_user_group: "Remove access to group"
|
||||
activity_group:
|
||||
projects: "Projects"
|
||||
task_results: "Task results"
|
||||
|
|
|
@ -340,7 +340,6 @@ Rails.application.routes.draw do
|
|||
member do
|
||||
get :show_user_group_assignments
|
||||
get :unassigned_user_groups
|
||||
put :update_default_public_user_role
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -348,7 +347,6 @@ Rails.application.routes.draw do
|
|||
member do
|
||||
get :show_user_group_assignments
|
||||
get :unassigned_user_groups
|
||||
put :update_default_public_user_role
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -356,7 +354,13 @@ Rails.application.routes.draw do
|
|||
member do
|
||||
get :show_user_group_assignments
|
||||
get :unassigned_user_groups
|
||||
put :update_default_public_user_role
|
||||
end
|
||||
end
|
||||
|
||||
resources :repositories, defaults: { format: 'json' } do
|
||||
member do
|
||||
get :show_user_group_assignments
|
||||
get :unassigned_user_groups
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -795,6 +799,9 @@ Rails.application.routes.draw do
|
|||
get :repository_users
|
||||
get :load_table
|
||||
end
|
||||
collection do
|
||||
get :user_roles
|
||||
end
|
||||
# Save repository table state
|
||||
post 'state_save',
|
||||
to: 'user_repositories#save_table_state',
|
||||
|
|
Loading…
Add table
Reference in a new issue