Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 144 additions & 21 deletions app/controllers/api/v1/roles_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,111 @@ class Api::V1::RolesController < Api::V1::BaseController
include RoleHelper

before_action :check_authorization

# Get available roles for account users (agent and administrator)
# This is a global endpoint as roles are not account-specific
before_action :load_role, only: [:show, :update, :destroy, :bulk_update_permissions]
before_action :enforce_role_scope!, only: [:show, :update, :destroy, :bulk_update_permissions]

def index
@roles = scoped_roles.includes(:role_permissions_actions, :users)
success_response(
data: @roles.map { |role| role_serializer(role) },
message: 'Roles retrieved successfully'
)
end

def show
success_response(
data: role_serializer(@role),
message: 'Role retrieved successfully'
)
end

def create
key = role_params[:name].to_s.downcase.gsub(/\s+/, '_').gsub(/[^a-z0-9_]/, '')
role = Role.new(
key: key,
name: role_params[:name],
description: role_params[:description],
system: false,
type: account_owner_only? ? 'account' : (role_params[:type].presence || 'account')
)

unless role.save
return render_unprocessable_entity(role.errors)
end

success_response(
data: role_serializer(role),
message: 'Role created successfully',
status: :created
)
end

def update
if @role.system? && role_params.key?(:key)
return error_response('FORBIDDEN', 'Cannot modify key of a system role', status: :forbidden)
end

unless @role.update(role_params.except(:key, :type))
return render_unprocessable_entity(@role.errors)
end

success_response(
data: role_serializer(@role),
message: 'Role updated successfully'
)
end

def destroy
unless @role.can_be_deleted?
message = @role.system? ? 'Cannot delete system roles' : 'Cannot delete role with assigned users'
return error_response('FORBIDDEN', message, status: :forbidden)
end

@role.destroy!
success_response(data: nil, message: 'Role deleted successfully')
end

def bulk_update_permissions
permission_keys = params[:permission_keys]

unless permission_keys.is_a?(Array)
return error_response('VALIDATION_ERROR', 'permission_keys must be an array', status: :bad_request)
end

valid_keys = permission_keys.select { |k| ResourceActionsConfig.valid_permission?(k) }
invalid_keys = permission_keys - valid_keys

if invalid_keys.any?
return error_response(
'VALIDATION_ERROR',
"Invalid permission keys: #{invalid_keys.join(', ')}",
status: :unprocessable_entity
)
end

ActiveRecord::Base.transaction do
@role.role_permissions_actions.destroy_all
valid_keys.each { |key| @role.role_permissions_actions.create!(permission_key: key) }
end

success_response(
data: role_serializer(@role.reload),
message: 'Permissions updated successfully'
)
end

# Get available roles for account users (agent and account_owner)
def account_user_roles
roles = Role.account_type.where(key: ['agent', 'account_owner']).map do |role|
RoleSerializer.basic(role)
end

success_response(
data: roles,
message: 'Account user roles retrieved successfully'
)
end

def check_authorization
# Verificar se usuário tem permissão para gerenciar roles
action_map = {
'account_user_roles' => 'roles.read'
}

required_permission = action_map[action_name]
if required_permission
resource_key, action_key = required_permission.split('.')
authorize_resource!(resource_key, action_key)
else
true # Para ações não mapeadas, permitir por enquanto
end
end

def full
load_roles
apply_role_filters
Expand All @@ -45,14 +121,61 @@ def full

private

def role_params
params.permit(:name, :description, :key, :type)
end

def load_role
@role = Role.find(params[:id])
rescue ActiveRecord::RecordNotFound
render_not_found('Role not found')
end

def scoped_roles
account_owner_only? ? Role.where(type: 'account') : Role.all
end

def account_owner_only?
current_api_user.has_role?('account_owner') && !current_api_user.has_role?('super_admin')
end

def enforce_role_scope!
return unless @role
return unless account_owner_only?
return if @role.type == 'account'

render json: { error: 'Cannot access or modify user-type roles' }, status: :forbidden
end
Comment thread
sourcery-ai[bot] marked this conversation as resolved.

def check_authorization
action_map = {
'index' => 'roles.read',
'show' => 'roles.read',
'account_user_roles' => 'roles.read',
'full' => 'roles.read',
'create' => 'roles.create',
'update' => 'roles.update',
'destroy' => 'roles.delete',
'bulk_update_permissions' => 'roles.bulk_update_permissions'
}

required_permission = action_map[action_name]
if required_permission
resource_key, action_key = required_permission.split('.')
authorize_resource!(resource_key, action_key)
else
true
end
end

def apply_role_filters
system_assignable_roles = @roles.where(system: true, key: ['agent', 'account_owner'])

if params[:type].present?
custom_roles = @roles.where(system: false, type: params[:type])
@roles = system_assignable_roles.or(custom_roles)
else
@roles = system_assignable_roles.or(@roles.where(system: false))
end
end
end
end
6 changes: 5 additions & 1 deletion app/models/resource_actions_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ class ResourceActionsConfig
description: 'Role and permission management',
actions: {
read: { name: 'View', description: 'View roles and permissions' },
bulk_assign: { name: 'Bulk Assign', description: 'Bulk assign roles to multiple users' }
create: { name: 'Create', description: 'Create custom roles' },
update: { name: 'Update', description: 'Update role details and permissions' },
delete: { name: 'Delete', description: 'Delete custom roles' },
bulk_assign: { name: 'Bulk Assign', description: 'Bulk assign roles to multiple users' },
bulk_update_permissions: { name: 'Update Permissions', description: 'Update role permission tree' }
}
},

Expand Down
4 changes: 4 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@
resources :roles do
collection do
get :full
get :account_user_roles
end
member do
put :bulk_update_permissions
end
end

Expand Down
4 changes: 0 additions & 4 deletions db/seeds/rbac.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,10 @@
'features.stats',
'features.seed',
'features.types',
'roles.create',
'roles.update',
'roles.delete',
'roles.stats',
'roles.seed',
'roles.add_permission',
'roles.remove_permission',
'roles.bulk_update_permissions',
'account_features.read',
'account_features.assign',
'account_features.remove',
Expand Down