module Volt::Model::Permissions
The permissions module provides helpers for working with Volt
permissions.
Public Class Methods
included(base)
click to toggle source
# File lib/volt/models/permissions.rb, line 62 def self.included(base) base.send(:extend, ClassMethods) base.class_attribute :__permissions__ end
Public Instance Methods
action_allowed?(action_name)
click to toggle source
Checks if any denies are in place for an action (read or delete)
# File lib/volt/models/permissions.rb, line 118 def action_allowed?(action_name) # TODO: this does some unnecessary work compute_allow_and_deny(action_name).then do deny = @__deny_fields == true || (@__deny_fields && @__deny_fields.size > 0) clear_allow_and_deny !deny end end
allow(*fields)
click to toggle source
# File lib/volt/models/permissions.rb, line 67 def allow(*fields) if @__allow_fields if @__allow_fields != true if fields.size == 0 # No field's were passed, this means we deny all @__allow_fields = true else # Fields were specified, add them to the list @__allow_fields += fields.map(&:to_sym) end end else fail 'allow should be called inside of a permissions block' end end
allow_and_deny_fields(action_name)
click to toggle source
Return the list of allowed fields
# File lib/volt/models/permissions.rb, line 131 def allow_and_deny_fields(action_name) compute_allow_and_deny(action_name).then do result = [@__allow_fields, @__deny_fields] clear_allow_and_deny result end end
deny(*fields)
click to toggle source
# File lib/volt/models/permissions.rb, line 83 def deny(*fields) if @__deny_fields if @__deny_fields != true if fields.size == 0 # No field's were passed, this means we deny all @__deny_fields = true else # Fields were specified, add them to the list @__deny_fields += fields.map(&:to_sym) end end else fail 'deny should be called inside of a permissions block' end end
filtered_attributes()
click to toggle source
Filter fields returns the attributes with any denied or not allowed fields removed based on the current user.
Run with Volt.as_user(...)
to change the user
# File lib/volt/models/permissions.rb, line 146 def filtered_attributes # Run the read permission check allow_and_deny_fields(:read).then do |allow, deny| result = nil if allow && allow != true && allow.size > 0 # always keep id allow << :id # Only keep fields in the allow list result = @attributes.select { |key| allow.include?(key) } elsif deny == true # Only keep id # TODO: Should this be a full reject? result = @attributes.reject { |key| key != :id } elsif deny && deny.size > 0 # Reject any in the deny list result = @attributes.reject { |key| deny.include?(key) } else result = @attributes end # Deeply filter any nested models result.then do |res| keys = [] values = [] res.each do |key, value| if value.is_a?(Model) value = value.filtered_attributes end keys << key values << value end Promise.when(*values).then do |values| keys.zip(values).to_h end end end end
owner?(key = :user_id)
click to toggle source
owner? can be called on a model to check if the currently logged in user (“`Volt.current_user“`) is the owner of this instance.
@param key [Symbol] the name of the attribute where the user_id is stored
# File lib/volt/models/permissions.rb, line 103 def owner?(key = :user_id) # Lookup the original user_id owner_id = was(key) || send(:"_#{key}") !owner_id.nil? && owner_id == Volt.current_user_id end
Private Instance Methods
add_error_if_changed(errors, field_name)
click to toggle source
# File lib/volt/models/permissions.rb, line 254 def add_error_if_changed(errors, field_name) if changed?(field_name) (errors[field_name] ||= []) << 'can not be changed' end end
clear_allow_and_deny()
click to toggle source
# File lib/volt/models/permissions.rb, line 224 def clear_allow_and_deny @__deny_fields = nil @__allow_fields = nil end
compute_allow_and_deny(action_name)
click to toggle source
Run through the permission blocks for the action name, acumulate all allow/deny fields.
# File lib/volt/models/permissions.rb, line 231 def compute_allow_and_deny(action_name) @__deny_fields = [] @__allow_fields = [] # Skip permissions can be run on the server to ignore the permissions return if Volt.in_mode?(:skip_permissions) # Run the permission blocks action_name ||= new? ? :create : :update # Run each of the permission blocks for this action permissions = self.class.__permissions__ if permissions && (blocks = permissions[action_name]) results = blocks.map do |block| # Call the block, pass the action name instance_exec(action_name, &block) end # Wait for any promises returned Promise.when(*results) end end
run_permissions(action_name = nil)
click to toggle source
# File lib/volt/models/permissions.rb, line 190 def run_permissions(action_name = nil) compute_allow_and_deny(action_name).then do errors = {} if @__allow_fields == true # Allow all fields elsif @__allow_fields && @__allow_fields.size > 0 # Deny all not specified in the allow list changed_attributes.keys.each do |field_name| unless @__allow_fields.include?(field_name) add_error_if_changed(errors, field_name) end end end if @__deny_fields == true # Don't allow any field changes changed_attributes.keys.each do |field_name| add_error_if_changed(errors, field_name) end elsif @__deny_fields # Allow all except the denied @__deny_fields.each do |field_name| add_error_if_changed(errors, field_name) if changed?(field_name) end end clear_allow_and_deny errors end end