Module: ErpTechSvcs::Extensions::ActiveRecord::ProtectedByCapabilities::ClassMethods

Defined in:
lib/erp_tech_svcs/extensions/active_record/protected_with_capabilities.rb

Instance Method Summary collapse

Instance Method Details

#protected_with_capabilities(options = {}) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/erp_tech_svcs/extensions/active_record/protected_with_capabilities.rb', line 12

def protected_with_capabilities(options = {})
  extend ProtectedByCapabilities::SingletonMethods
		include ProtectedByCapabilities::InstanceMethods

      has_many :capabilities, :as => :capability_resource
		
      # protect all instance of this class by default
      class_attribute :protect_all_instances
      self.protect_all_instances = (options[:protect_all_instances].nil? ? false : options[:protect_all_instances])

      # Get records filtered via query scope capabilities
      # By default Compass AE treats query scopes as restrictions
      # A user will see all records unless the user has a capability accessor with a query scope
      # If you set :protect_all_instances => true it is honored via with_user_security & with_instance_security but NOT with_query_security
      # arguments: user, capability_type_iids 
      # capability_type_iids is optional and can be a single string or an array of strings
      # Example: which files can this user download? FileAsset.with_query_security(user, 'download').all
      # Example: which website sections can this user either view or edit? WebsiteSection.with_query_security(user, ['view','edit']).all
      scope :with_query_security, lambda{|*args|
        raise ArgumentError if args.empty? || args.size > 2
        user = args.first
        capability_type_iids = args.second || []
        capability_type_iids = [capability_type_iids] if capability_type_iids.is_a?(String)

        scope_type = ScopeType.find_by_internal_identifier('query')
        granted_capabilities = user.all_capabilities.where(:scope_type_id => scope_type.id).where(:capability_resource_type => self.name)

        unless capability_type_iids.empty?
          capability_type_ids = capability_type_iids.collect{|type| convert_capability_type(type).id }
          granted_capabilities = granted_capabilities.where("capability_type_id IN (?)", capability_type_ids.join(','))
        end

        query = nil
        granted_capabilities.each do |scope_capability|
          query = query.nil? ? where(scope_capability.scope_query) : query.where(scope_capability.scope_query)
        end
        query
      }

      # Get records for this model permitted via instance capabilities
      # If :protect_all_instances => true return only instances user has explicitly been granted access to
      # If :protect_all_instances => false return instances without capabilities or that user is granted access to (default)
      # arguments: user, capability_type_iids 
      # capability_type_iids is optional and can be a single string or an array of strings
      # Example: which files can this user download? FileAsset.with_instance_security(user, 'download').all
      # Example: which website sections can this user either view or edit? WebsiteSection.with_instance_security(user, ['view','edit']).all
      scope :with_instance_security, lambda{|*args|
        raise ArgumentError if args.empty? || args.size > 2
        user = args.first
        capability_type_iids = args.second || []
        capability_type_iids = [capability_type_iids] if capability_type_iids.is_a?(String)

        scope_type = ScopeType.find_by_internal_identifier('instance')
        granted_capabilities = user.all_capabilities.where(:scope_type_id => scope_type.id).where(:capability_resource_type => self.name)

        unless capability_type_iids.empty?
          capability_type_ids = capability_type_iids.collect{|type| convert_capability_type(type).id }
          granted_capabilities = granted_capabilities.where("capability_type_id IN (#{capability_type_ids.join(',')})")
        end

        denied_capabilities = instance_capabilities.select('capabilities.id').where("capabilities.id NOT IN (#{granted_capabilities.select('capabilities.id').to_sql})")
        deny_count = denied_capabilities.count

        join_type = (self.protect_all_instances ? 'JOIN' : 'LEFT JOIN')
        query = joins("#{join_type} capabilities AS c ON c.capability_resource_id = #{self.table_name}.id AND c.capability_resource_type = '#{self.name}'").
                group(columns.collect{|c| "#{self.table_name}.#{c.name}" })
        query = (deny_count == 0 ? query.where("c.id NOT IN (SELECT id FROM capabilities) OR c.id = c.id") : query.where("c.id NOT IN (SELECT id FROM capabilities) OR c.id NOT IN (#{denied_capabilities.to_sql})"))
        query
      }

      # Get records for this model that the given user has access to
      # arguments: user, capability_type_iids 
      # capability_type_iids is optional and can be a single string or an array of strings
      # Example: which files can this user download? FileAsset.with_user_security(user, 'download').all
      # Example: which website sections can this user either view or edit? WebsiteSection.with_user_security(user, ['view','edit']).all
      scope :with_user_security, lambda{|*args|
        raise ArgumentError if args.empty? || args.size > 2              
        with_instance_security(*args).with_query_security(*args)
      }
end