Class: OpenLoam::Policy
- Inherits:
-
Object
- Object
- OpenLoam::Policy
- Defined in:
- lib/open_loam/policy.rb
Overview
Base policy. One policy class per entity, one instance per (actor, record) pair. Action checks (read?/create?/update?/destroy?) default to "any member of the current tenant"; field-level write access is declared, not coded:
class EquipmentPolicy < OpenLoam::Policy
field :daily_rate, writable: [:manager]
end
Roles come from OpenLoam::Membership (actor + current tenant -> role).
Instance Attribute Summary collapse
-
#actor ⇒ Object
readonly
Returns the value of attribute actor.
-
#record ⇒ Object
readonly
Returns the value of attribute record.
Class Method Summary collapse
- .field(name, writable: nil, readable: nil) ⇒ Object
- .field_rules ⇒ Object
- .for(record) ⇒ Object
-
.for_model(model, actor) ⇒ Object
A policy for a MODEL rather than one record — for bulk paths (export, import) that decide the column set once, before any row is read.
-
.policy_class_for(model) ⇒ Object
Falling back to the base Policy for a model with no policy class would fail OPEN — every check there answers "any member", so a missing policy would silently grant what an explicit one restricts.
Instance Method Summary collapse
- #create? ⇒ Boolean
-
#custom_field_readable?(field_name) ⇒ Boolean
Read counterpart of custom_field_writable?: a runtime field with no readable_roles is readable by any member; with some, only by those roles.
-
#custom_field_writable?(field_name) ⇒ Boolean
Same semantics as the static
field writable:declaration, but for a runtime OpenLoam::FieldDefinition (see OpenLoam::CustomFields): no writable_roles recorded means any member may write it. - #destroy? ⇒ Boolean
-
#initialize(actor, record) ⇒ Policy
constructor
A new instance of Policy.
- #member? ⇒ Boolean
- #permitted_custom_fields(field_names) ⇒ Object
- #permitted_fields(field_names) ⇒ Object
- #read? ⇒ Boolean
-
#readable?(field_name) ⇒ Boolean
Field-level READ check (used by CSV export): a field with no
readable:rule is readable by any member; with one, only by the listed roles. - #readable_custom_fields(field_names) ⇒ Object
- #readable_fields(field_names) ⇒ Object
- #role ⇒ Object
- #update? ⇒ Boolean
-
#writable?(field_name) ⇒ Boolean
Field-level check: fields without a declared rule are writable by any member; fields with
writable:only by the listed roles.
Constructor Details
#initialize(actor, record) ⇒ Policy
Returns a new instance of Policy.
44 45 46 47 |
# File 'lib/open_loam/policy.rb', line 44 def initialize(actor, record) @actor = actor @record = record end |
Instance Attribute Details
#actor ⇒ Object (readonly)
Returns the value of attribute actor.
42 43 44 |
# File 'lib/open_loam/policy.rb', line 42 def actor @actor end |
#record ⇒ Object (readonly)
Returns the value of attribute record.
42 43 44 |
# File 'lib/open_loam/policy.rb', line 42 def record @record end |
Class Method Details
.field(name, writable: nil, readable: nil) ⇒ Object
17 18 19 |
# File 'lib/open_loam/policy.rb', line 17 def field(name, writable: nil, readable: nil) field_rules[name.to_sym] = { writable: writable, readable: readable } end |
.field_rules ⇒ Object
13 14 15 |
# File 'lib/open_loam/policy.rb', line 13 def field_rules @field_rules ||= {} end |
.for(record) ⇒ Object
21 22 23 |
# File 'lib/open_loam/policy.rb', line 21 def for(record) policy_class_for(record.class).new(OpenLoam::Current.actor, record) end |
.for_model(model, actor) ⇒ Object
A policy for a MODEL rather than one record — for bulk paths (export, import) that decide the column set once, before any row is read. The blank instance is a stand-in: the field checks key off the role, but the custom-field ones need record.class to find the definitions.
29 30 31 |
# File 'lib/open_loam/policy.rb', line 29 def for_model(model, actor) policy_class_for(model).new(actor, model.new) end |
.policy_class_for(model) ⇒ Object
Falling back to the base Policy for a model with no policy class would fail OPEN — every check there answers "any member", so a missing policy would silently grant what an explicit one restricts.
36 37 38 39 |
# File 'lib/open_loam/policy.rb', line 36 def policy_class_for(model) "#{model.name}Policy".safe_constantize || raise(Error, "No policy defined for #{model.name} (expected #{model.name}Policy)") end |
Instance Method Details
#create? ⇒ Boolean
58 |
# File 'lib/open_loam/policy.rb', line 58 def create? = member? |
#custom_field_readable?(field_name) ⇒ Boolean
Read counterpart of custom_field_writable?: a runtime field with no readable_roles is readable by any member; with some, only by those roles.
106 107 108 109 110 111 112 113 |
# File 'lib/open_loam/policy.rb', line 106 def custom_field_readable?(field_name) return false unless member? definition = record.class.custom_field_definitions.find_by(name: field_name.to_s) return false unless definition definition.readable_by?(role) end |
#custom_field_writable?(field_name) ⇒ Boolean
Same semantics as the static field writable: declaration, but for a
runtime OpenLoam::FieldDefinition (see OpenLoam::CustomFields): no
writable_roles recorded means any member may write it.
91 92 93 94 95 96 97 98 |
# File 'lib/open_loam/policy.rb', line 91 def custom_field_writable?(field_name) return false unless member? definition = record.class.custom_field_definitions.find_by(name: field_name.to_s) return false unless definition definition.writable_roles.blank? || definition.writable_roles.map(&:to_sym).include?(role) end |
#destroy? ⇒ Boolean
60 |
# File 'lib/open_loam/policy.rb', line 60 def destroy? = member? |
#member? ⇒ Boolean
55 |
# File 'lib/open_loam/policy.rb', line 55 def member? = role.present? |
#permitted_custom_fields(field_names) ⇒ Object
100 101 102 |
# File 'lib/open_loam/policy.rb', line 100 def permitted_custom_fields(field_names) field_names.select { |f| custom_field_writable?(f) } end |
#permitted_fields(field_names) ⇒ Object
71 72 73 |
# File 'lib/open_loam/policy.rb', line 71 def permitted_fields(field_names) field_names.select { |f| writable?(f) } end |
#read? ⇒ Boolean
57 |
# File 'lib/open_loam/policy.rb', line 57 def read? = member? |
#readable?(field_name) ⇒ Boolean
Field-level READ check (used by CSV export): a field with no readable:
rule is readable by any member; with one, only by the listed roles.
77 78 79 80 81 82 |
# File 'lib/open_loam/policy.rb', line 77 def readable?(field_name) rule = self.class.field_rules[field_name.to_sym] return member? if rule.nil? || rule[:readable].nil? Array(rule[:readable]).map(&:to_sym).include?(role) end |
#readable_custom_fields(field_names) ⇒ Object
115 116 117 |
# File 'lib/open_loam/policy.rb', line 115 def readable_custom_fields(field_names) field_names.select { |f| custom_field_readable?(f) } end |
#readable_fields(field_names) ⇒ Object
84 85 86 |
# File 'lib/open_loam/policy.rb', line 84 def readable_fields(field_names) field_names.select { |f| readable?(f) } end |
#role ⇒ Object
49 50 51 52 53 |
# File 'lib/open_loam/policy.rb', line 49 def role return nil unless actor @role ||= OpenLoam::Membership.find_by(user_id: actor.id)&.role&.to_sym end |
#update? ⇒ Boolean
59 |
# File 'lib/open_loam/policy.rb', line 59 def update? = member? |
#writable?(field_name) ⇒ Boolean
Field-level check: fields without a declared rule are writable by any
member; fields with writable: only by the listed roles.
64 65 66 67 68 69 |
# File 'lib/open_loam/policy.rb', line 64 def writable?(field_name) rule = self.class.field_rules[field_name.to_sym] return member? if rule.nil? || rule[:writable].nil? Array(rule[:writable]).map(&:to_sym).include?(role) end |