Class: ViewModel::AccessControl::Composed

Inherits:
ViewModel::AccessControl show all
Defined in:
lib/view_model/access_control/composed.rb

Overview

Provides access control as a combination of ‘x_if!` and `x_unless!` checks for each access check (visible, editable, edit_valid). An action is permitted if at least one `if` check and no `unless` checks succeed. For example:

edit_valid_if!("logged in as specified user") { ... }
edit_valid_unless!("user is on fire") { ... }

Direct Known Subclasses

Tree::Node

Defined Under Namespace

Classes: ComposedResult, NoRequiredConditionsError, PermissionsCheck

Constant Summary

Constants included from Callbacks

Callbacks::ALWAYS

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from ViewModel::AccessControl

#editable!, #initialize, #visible!

Methods included from Callbacks

#ineligible, #run_callback, wrap_deserialize, wrap_serialize

Constructor Details

This class inherits a constructor from ViewModel::AccessControl

Class Attribute Details

.edit_valid_ifsObject (readonly)

Returns the value of attribute edit_valid_ifs.



83
84
85
# File 'lib/view_model/access_control/composed.rb', line 83

def edit_valid_ifs
  @edit_valid_ifs
end

.edit_valid_unlessesObject (readonly)

Returns the value of attribute edit_valid_unlesses.



83
84
85
# File 'lib/view_model/access_control/composed.rb', line 83

def edit_valid_unlesses
  @edit_valid_unlesses
end

.editable_ifsObject (readonly)

Returns the value of attribute editable_ifs.



83
84
85
# File 'lib/view_model/access_control/composed.rb', line 83

def editable_ifs
  @editable_ifs
end

.editable_unlessesObject (readonly)

Returns the value of attribute editable_unlesses.



83
84
85
# File 'lib/view_model/access_control/composed.rb', line 83

def editable_unlesses
  @editable_unlesses
end

.visible_ifsObject (readonly)

Returns the value of attribute visible_ifs.



83
84
85
# File 'lib/view_model/access_control/composed.rb', line 83

def visible_ifs
  @visible_ifs
end

.visible_unlessesObject (readonly)

Returns the value of attribute visible_unlesses.



83
84
85
# File 'lib/view_model/access_control/composed.rb', line 83

def visible_unlesses
  @visible_unlesses
end

Class Method Details

.each_check(check_name, include_ancestor = nil) ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/view_model/access_control/composed.rb', line 147

def each_check(check_name, include_ancestor = nil)
  return enum_for(:each_check, check_name, include_ancestor) unless block_given?

  self.public_send(check_name).each { |x| yield x }

  visited = Set.new
  @included_checkers.each do |ancestor|
    next unless visited.add?(ancestor)
    next if include_ancestor && !include_ancestor.call(ancestor)

    ancestor.each_check(check_name) { |x| yield x }
  end
end

.edit_valid_if!(reason, &block) ⇒ Object



133
134
135
# File 'lib/view_model/access_control/composed.rb', line 133

def edit_valid_if!(reason, &block)
  @edit_valid_ifs      << new_permission_check(reason, &block)
end

.edit_valid_unless!(reason, &block) ⇒ Object



137
138
139
# File 'lib/view_model/access_control/composed.rb', line 137

def edit_valid_unless!(reason, &block)
  @edit_valid_unlesses << new_permission_check(reason, &block)
end

.editable_if!(reason, &block) ⇒ Object



125
126
127
# File 'lib/view_model/access_control/composed.rb', line 125

def editable_if!(reason, &block)
  @editable_ifs        << new_permission_check(reason, &block)
end

.editable_unless!(reason, &block) ⇒ Object



129
130
131
# File 'lib/view_model/access_control/composed.rb', line 129

def editable_unless!(reason, &block)
  @editable_unlesses   << new_permission_check(reason, &block)
end

.include_from(ancestor) ⇒ Object

Configuration API



109
110
111
112
113
114
115
# File 'lib/view_model/access_control/composed.rb', line 109

def include_from(ancestor)
  unless ancestor < ViewModel::AccessControl::Composed
    raise ArgumentError.new("Invalid ancestor: #{ancestor}")
  end

  @included_checkers << ancestor
end

.inherited(subclass) ⇒ Object



90
91
92
93
# File 'lib/view_model/access_control/composed.rb', line 90

def inherited(subclass)
  super
  subclass.initialize_as_composed_access_control
end

.initialize_as_composed_access_controlObject



95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/view_model/access_control/composed.rb', line 95

def initialize_as_composed_access_control
  @included_checkers = []

  @edit_valid_ifs      = []
  @edit_valid_unlesses = []

  @editable_ifs        = []
  @editable_unlesses   = []

  @visible_ifs         = []
  @visible_unlesses    = []
end

.inspectObject



161
162
163
164
165
166
167
# File 'lib/view_model/access_control/composed.rb', line 161

def inspect
  s = super + '('
  s += inspect_checks.join(', ')
  s += " includes checkers: #{@included_checkers.inspect}" if @included_checkers.present?
  s += ')'
  s
end

.inspect_checksObject



169
170
171
172
173
174
175
176
177
178
# File 'lib/view_model/access_control/composed.rb', line 169

def inspect_checks
  checks = []
  checks << "visible_if: #{@visible_ifs.map(&:reason)}"                if @visible_ifs.present?
  checks << "visible_unless: #{@visible_unlesses.map(&:reason)}"       if @visible_unlesses.present?
  checks << "editable_if: #{@editable_ifs.map(&:reason)}"              if @editable_ifs.present?
  checks << "editable_unless: #{@editable_unlesses.map(&:reason)}"     if @editable_unlesses.present?
  checks << "edit_valid_if: #{@edit_valid_ifs.map(&:reason)}"          if @edit_valid_ifs.present?
  checks << "edit_valid_unless: #{@edit_valid_unlesses.map(&:reason)}" if @edit_valid_unlesses.present?
  checks
end

.new_permission_check(reason, error_type: ViewModel::AccessControlError, &block) ⇒ Object

Implementation



143
144
145
# File 'lib/view_model/access_control/composed.rb', line 143

def new_permission_check(reason, error_type: ViewModel::AccessControlError, &block)
  PermissionsCheck.new(self.name&.demodulize, reason, error_type, block)
end

.visible_if!(reason, &block) ⇒ Object



117
118
119
# File 'lib/view_model/access_control/composed.rb', line 117

def visible_if!(reason, &block)
  @visible_ifs         << new_permission_check(reason, &block)
end

.visible_unless!(reason, &block) ⇒ Object



121
122
123
# File 'lib/view_model/access_control/composed.rb', line 121

def visible_unless!(reason, &block)
  @visible_unlesses    << new_permission_check(reason, &block)
end

Instance Method Details

#editable_check(traversal_env) ⇒ Object

final



187
188
189
# File 'lib/view_model/access_control/composed.rb', line 187

def editable_check(traversal_env)
  check_delegates(traversal_env, self.class.each_check(:editable_ifs), self.class.each_check(:editable_unlesses))
end

#valid_edit_check(traversal_env) ⇒ Object

final



192
193
194
# File 'lib/view_model/access_control/composed.rb', line 192

def valid_edit_check(traversal_env)
  check_delegates(traversal_env, self.class.each_check(:edit_valid_ifs), self.class.each_check(:edit_valid_unlesses))
end

#visible_check(traversal_env) ⇒ Object

final



182
183
184
# File 'lib/view_model/access_control/composed.rb', line 182

def visible_check(traversal_env)
  check_delegates(traversal_env, self.class.each_check(:visible_ifs), self.class.each_check(:visible_unlesses))
end