|
|
|
|
@ -3,71 +3,101 @@
|
|
|
|
|
class Ability
|
|
|
|
|
include CanCan::Ability
|
|
|
|
|
|
|
|
|
|
# Maps config resource names → CanCan model + action rules.
|
|
|
|
|
# All condition procs MUST return hashes (not AR relations) so that
|
|
|
|
|
# class-level can?/authorize! checks work (e.g. `authorize! :index, Template`).
|
|
|
|
|
RESOURCE_MAP = {
|
|
|
|
|
'templates' => [
|
|
|
|
|
[Template, :read, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[Template, :create, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[Template, :update, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[Template, :destroy, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[TemplateFolder, :manage, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[TemplateSharing, :manage, ->(u) { { template: { account_id: u.account_id } } }]
|
|
|
|
|
],
|
|
|
|
|
'submissions' => [
|
|
|
|
|
[Submission, :manage, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[Submitter, :manage, ->(u) { { account_id: u.account_id } }]
|
|
|
|
|
],
|
|
|
|
|
'users' => [
|
|
|
|
|
[User, :manage, ->(u) { { account_id: u.account_id } }]
|
|
|
|
|
],
|
|
|
|
|
'settings' => [
|
|
|
|
|
[EncryptedConfig, :manage, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[AccountConfig, :manage, ->(u) { { account_id: u.account_id } }],
|
|
|
|
|
[Account, :manage, ->(u) { { id: u.account_id } }],
|
|
|
|
|
[WebhookUrl, :manage, ->(u) { { account_id: u.account_id } }]
|
|
|
|
|
]
|
|
|
|
|
}.freeze
|
|
|
|
|
|
|
|
|
|
def initialize(user)
|
|
|
|
|
case user.role
|
|
|
|
|
when User::ADMIN_ROLE
|
|
|
|
|
admin_abilities(user)
|
|
|
|
|
when User::GESTIONNAIRE_ROLE
|
|
|
|
|
gestionnaire_abilities(user)
|
|
|
|
|
when User::USER_ROLE
|
|
|
|
|
user_abilities(user)
|
|
|
|
|
end
|
|
|
|
|
return unless user
|
|
|
|
|
|
|
|
|
|
always_allowed(user)
|
|
|
|
|
apply_role_permissions(user)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
private
|
|
|
|
|
|
|
|
|
|
# Accès complet à tout le compte
|
|
|
|
|
def admin_abilities(user)
|
|
|
|
|
can %i[read create update], Template, Abilities::TemplateConditions.collection(user) do |template|
|
|
|
|
|
Abilities::TemplateConditions.entity(template, user:, ability: 'manage')
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
can :destroy, Template, account_id: user.account_id
|
|
|
|
|
can :manage, TemplateFolder, account_id: user.account_id
|
|
|
|
|
can :manage, TemplateSharing, template: { account_id: user.account_id }
|
|
|
|
|
can :manage, Submission, account_id: user.account_id
|
|
|
|
|
can :manage, Submitter, account_id: user.account_id
|
|
|
|
|
can :manage, User, account_id: user.account_id
|
|
|
|
|
can :manage, EncryptedConfig, account_id: user.account_id
|
|
|
|
|
# Personal resources — always available regardless of role.
|
|
|
|
|
def always_allowed(user)
|
|
|
|
|
can :manage, EncryptedUserConfig, user_id: user.id
|
|
|
|
|
can :manage, AccountConfig, account_id: user.account_id
|
|
|
|
|
can :manage, UserConfig, user_id: user.id
|
|
|
|
|
can :manage, Account, id: user.account_id
|
|
|
|
|
can :manage, User, id: user.id
|
|
|
|
|
can :read, Account, id: user.account_id
|
|
|
|
|
can :manage, AccessToken, user_id: user.id
|
|
|
|
|
can :manage, WebhookUrl, account_id: user.account_id
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Peut créer/gérer documents et envois — pas les paramètres ni les utilisateurs
|
|
|
|
|
def gestionnaire_abilities(user)
|
|
|
|
|
can %i[read create update], Template, Abilities::TemplateConditions.collection(user) do |template|
|
|
|
|
|
Abilities::TemplateConditions.entity(template, user:, ability: 'manage')
|
|
|
|
|
def apply_role_permissions(user)
|
|
|
|
|
role = user.role.to_s
|
|
|
|
|
|
|
|
|
|
RESOURCE_MAP.each do |resource_key, model_rules|
|
|
|
|
|
config_actions = Whitelabel.role_permissions(role, resource_key)
|
|
|
|
|
|
|
|
|
|
model_rules.each do |model, cancan_action, condition_proc|
|
|
|
|
|
grant_if_allowed(user, model, cancan_action, condition_proc, config_actions)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
can :destroy, Template, account_id: user.account_id
|
|
|
|
|
can :manage, TemplateFolder, account_id: user.account_id
|
|
|
|
|
can :manage, TemplateSharing, template: { account_id: user.account_id }
|
|
|
|
|
can :manage, Submission, account_id: user.account_id
|
|
|
|
|
can :manage, Submitter, account_id: user.account_id
|
|
|
|
|
can :manage, EncryptedUserConfig, user_id: user.id
|
|
|
|
|
can :manage, UserConfig, user_id: user.id
|
|
|
|
|
can :manage, User, id: user.id
|
|
|
|
|
can :read, Account, id: user.account_id
|
|
|
|
|
can :manage, AccessToken, user_id: user.id
|
|
|
|
|
def grant_if_allowed(user, model, cancan_action, condition_proc, config_actions)
|
|
|
|
|
needed = action_to_config(cancan_action)
|
|
|
|
|
return unless (needed & config_actions).any?
|
|
|
|
|
|
|
|
|
|
conditions = condition_proc.call(user)
|
|
|
|
|
granted = map_cancan_actions(cancan_action, config_actions)
|
|
|
|
|
return if granted.empty?
|
|
|
|
|
|
|
|
|
|
# Hash-only conditions. Shared-template / linked-account filtering
|
|
|
|
|
# is handled at the controller level (TemplateConditions.collection,
|
|
|
|
|
# filter_templates, etc.) — CanCanCan forbids hash + block together.
|
|
|
|
|
can granted, model, conditions
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Lecture seule — ne peut pas créer ni modifier
|
|
|
|
|
def user_abilities(user)
|
|
|
|
|
can :read, Template, Abilities::TemplateConditions.collection(user) do |template|
|
|
|
|
|
Abilities::TemplateConditions.entity(template, user:)
|
|
|
|
|
# Map a CanCan :manage action to the individual config actions that are allowed.
|
|
|
|
|
def map_cancan_actions(cancan_action, config_actions)
|
|
|
|
|
if cancan_action == :manage
|
|
|
|
|
mapped = []
|
|
|
|
|
mapped << :read if config_actions.include?('read')
|
|
|
|
|
mapped << :create if config_actions.include?('create')
|
|
|
|
|
mapped << :update if config_actions.include?('update')
|
|
|
|
|
mapped << :destroy if config_actions.include?('delete')
|
|
|
|
|
mapped
|
|
|
|
|
elsif cancan_action == :destroy
|
|
|
|
|
config_actions.include?('delete') ? [:destroy] : []
|
|
|
|
|
else
|
|
|
|
|
config_actions.include?(cancan_action.to_s) ? [cancan_action] : []
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
can :read, TemplateFolder, account_id: user.account_id
|
|
|
|
|
can :read, Submission, account_id: user.account_id
|
|
|
|
|
can :read, Submitter, account_id: user.account_id
|
|
|
|
|
can :manage, EncryptedUserConfig, user_id: user.id
|
|
|
|
|
can :manage, UserConfig, user_id: user.id
|
|
|
|
|
can :manage, User, id: user.id
|
|
|
|
|
can :read, Account, id: user.account_id
|
|
|
|
|
can :manage, AccessToken, user_id: user.id
|
|
|
|
|
def action_to_config(cancan_action)
|
|
|
|
|
case cancan_action
|
|
|
|
|
when :manage then %w[read create update delete]
|
|
|
|
|
when :read then %w[read]
|
|
|
|
|
when :create then %w[create]
|
|
|
|
|
when :update then %w[update]
|
|
|
|
|
when :destroy then %w[delete]
|
|
|
|
|
else [cancan_action.to_s]
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|