Module: HrLite::Permissions
- Defined in:
- lib/hr_lite/permissions.rb
Overview
The whole vocabulary of the engine's authorization, in one place.
A permission is a KEY plus a SCOPE. The key says what the action is ("approve leave"); the scope says whose rows it reaches:
self — only this person's own records
team — the people who report to them (EmployeeProfile#manager_id)
all — everyone in the company
That is why there is no leave.approve_own / leave.approve_team /
leave.approve_all triple: one key with three possible scopes says the
same thing without three times the surface to get wrong.
Keys are DATA — a role grants them from the database. They are declared here so that a typo in a controller is a boot-time failure rather than a permission that silently never matches.
Constant Summary collapse
- SCOPES =
%i[self team all].freeze
- SCOPE_RANK =
Ordered weakest to strongest.
allsatisfies ateamrequirement,teamsatisfiesself; never the other way round. { self: 0, team: 1, all: 2 }.freeze
- REGISTRY =
key => [ group, description ]. The group is what the roles screen renders as a heading; the description is the sentence beside the checkbox, so it is written for the person granting it.
{ "profile.view" => [ "People", "See employee profiles" ], "profile.manage" => [ "People", "Create and edit employee profiles, onboard and offboard" ], "attendance.view" => [ "Attendance", "See attendance records" ], "attendance.manage" => [ "Attendance", "Correct punches and decide regularization tickets" ], "leave.request" => [ "Leave", "Apply for leave and comp-off" ], "leave.view" => [ "Leave", "See leave requests and balances" ], "leave.approve" => [ "Leave", "Approve, reject and cancel leave and comp-off" ], "leave.manage" => [ "Leave", "Adjust balances, configure leave types and holidays" ], "payroll.view" => [ "Payroll", "See payroll runs and salary slips" ], "payroll.manage" => [ "Payroll", "Create, compute, finalize, unlock and publish payroll" ], "payroll.export" => [ "Payroll", "Download the payout register, including bank details" ], "salary.view" => [ "Payroll", "See salary structures" ], "salary.manage" => [ "Payroll", "Set and revise salary structures" ], "appraisal.view" => [ "Growth", "See appraisals" ], "appraisal.manage" => [ "Growth", "Write, share and act on appraisals and promotions" ], "resignation.view" => [ "Lifecycle", "See resignations" ], "resignation.manage" => [ "Lifecycle", "Accept resignations and set the last working day" ], "document.view" => [ "Documents", "Open other people's documents" ], "document.manage" => [ "Documents", "Upload, verify and open identity and bank documents" ], "tax.view" => [ "Payroll", "See tax declarations" ], "tax.manage" => [ "Payroll", "Verify tax declarations and the proof behind them" ], "expense.claim" => [ "Expenses", "Claim expenses" ], "expense.approve" => [ "Expenses", "Approve and reject expense claims" ], "expense.reimburse" => [ "Expenses", "Mark claims reimbursed with a payroll month" ], "benefit.view" => [ "Benefits", "See benefits and who is enrolled" ], "benefit.manage" => [ "Benefits", "Add benefits and enrol people" ], "hr_request.raise" => [ "Help desk", "Raise a request with HR" ], "hr_request.manage" => [ "Help desk", "Answer and assign HR requests" ], "policy.view" => [ "Policies", "Read published policies" ], "policy.manage" => [ "Policies", "Write, publish and re-issue policies" ], "asset.view" => [ "Assets", "See company assets and who holds them" ], "asset.manage" => [ "Assets", "Assign and take back company assets" ], "checklist.manage" => [ "Lifecycle", "Work through joining and leaving checklists" ], "settings.manage" => [ "Administration", "Change company settings, offices and policy" ], "audit.view" => [ "Administration", "Read the audit trail" ], "audit.view_money" => [ "Administration", "Read audit rows about pay, appraisals and promotions" ], "role.manage" => [ "Administration", "Create roles and grant permissions" ] }.freeze
- KEYS =
REGISTRY.keys.freeze
Class Method Summary collapse
- .description(key) ⇒ Object
- .group(key) ⇒ Object
- .grouped ⇒ Object
-
.scope_covers?(held, needed) ⇒ Boolean
Does
heldsatisfy a requirement forneeded?. - .valid?(key) ⇒ Boolean
-
.validate!(key) ⇒ Object
Raises rather than returning false: an unknown key in a controller is a typo that would otherwise read as "nobody may do this", which fails in the safe direction but silently, and is then very hard to find.
Class Method Details
.description(key) ⇒ Object
83 |
# File 'lib/hr_lite/permissions.rb', line 83 def self.description(key) = REGISTRY.fetch(key.to_s).last |
.group(key) ⇒ Object
82 |
# File 'lib/hr_lite/permissions.rb', line 82 def self.group(key) = REGISTRY.fetch(key.to_s).first |
.grouped ⇒ Object
85 86 87 88 |
# File 'lib/hr_lite/permissions.rb', line 85 def self.grouped REGISTRY.group_by { |_key, (group, _)| group } .transform_values { |pairs| pairs.map(&:first) } end |
.scope_covers?(held, needed) ⇒ Boolean
Does held satisfy a requirement for needed?
91 92 93 |
# File 'lib/hr_lite/permissions.rb', line 91 def self.scope_covers?(held, needed) SCOPE_RANK.fetch(held.to_sym) >= SCOPE_RANK.fetch(needed.to_sym) end |
.valid?(key) ⇒ Boolean
70 |
# File 'lib/hr_lite/permissions.rb', line 70 def self.valid?(key) = REGISTRY.key?(key.to_s) |
.validate!(key) ⇒ Object
Raises rather than returning false: an unknown key in a controller is a typo that would otherwise read as "nobody may do this", which fails in the safe direction but silently, and is then very hard to find.
75 76 77 78 79 80 |
# File 'lib/hr_lite/permissions.rb', line 75 def self.validate!(key) return key.to_s if valid?(key) raise ArgumentError, "Unknown HrLite permission #{key.inspect}. " \ "Declare it in HrLite::Permissions::REGISTRY first." end |