erp_tech_svcs 3.1.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/app/models/group.rb CHANGED
@@ -140,15 +140,29 @@ class Group < ActiveRecord::Base
140
140
  end
141
141
 
142
142
  def role_class_capabilities
143
- roles.collect{|r| r.class_capabilities }.flatten.uniq.compact
143
+ scope_type = ScopeType.find_by_internal_identifier('class')
144
+ Capability.joins(:capability_type).joins(:capability_accessors).
145
+ where(:capability_accessors => { :capability_accessor_record_type => "SecurityRole" }).
146
+ where("capability_accessor_record_id IN (#{roles.select('security_roles.id').to_sql})").
147
+ where(:scope_type_id => scope_type.id)
144
148
  end
145
149
 
146
150
  def all_class_capabilities
147
- (role_class_capabilities + class_capabilities).uniq
151
+ scope_type = ScopeType.find_by_internal_identifier('class')
152
+ Capability.joins(:capability_type).joins(:capability_accessors).
153
+ where("(capability_accessors.capability_accessor_record_type = 'Group' AND
154
+ capability_accessor_record_id = (#{self.id})) OR
155
+ (capability_accessors.capability_accessor_record_type = 'SecurityRole' AND
156
+ capability_accessor_record_id IN (#{roles.select('security_roles.id').to_sql}))").
157
+ where(:scope_type_id => scope_type.id)
158
+ end
159
+
160
+ def all_uniq_class_capabilities
161
+ all_class_capabilities.all.uniq
148
162
  end
149
163
 
150
164
  def class_capabilities_to_hash
151
- all_class_capabilities.map {|capability|
165
+ all_uniq_class_capabilities.map {|capability|
152
166
  { :capability_type_iid => capability.capability_type.internal_identifier,
153
167
  :capability_resource_type => capability.capability_resource_type
154
168
  }
data/app/models/user.rb CHANGED
@@ -46,7 +46,7 @@ class User < ActiveRecord::Base
46
46
  passed_roles.flatten!
47
47
  passed_roles.each do |role|
48
48
  role_iid = role.is_a?(SecurityRole) ? role.internal_identifier : role.to_s
49
- all_roles.each do |this_role|
49
+ all_uniq_roles.each do |this_role|
50
50
  result = true if (this_role.internal_identifier == role_iid)
51
51
  break if result
52
52
  end
@@ -103,40 +103,70 @@ class User < ActiveRecord::Base
103
103
 
104
104
  # roles assigned to the groups this user belongs to
105
105
  def group_roles
106
- groups.collect{|g| g.roles }.flatten.uniq
106
+ SecurityRole.joins(:parties).
107
+ where(:parties => {:business_party_type => 'Group'}).
108
+ where("parties.business_party_id IN (#{groups.select('groups.id').to_sql})")
107
109
  end
108
110
 
109
111
  # composite roles for this user
110
112
  def all_roles
111
- (group_roles + roles).uniq
113
+ SecurityRole.joins(:parties).joins("LEFT JOIN users ON parties.id=users.party_id").
114
+ where("(parties.business_party_type='Group' AND
115
+ parties.business_party_id IN (#{groups.select('groups.id').to_sql})) OR
116
+ (users.id=#{self.id})")
117
+ end
118
+
119
+ def all_uniq_roles
120
+ all_roles.all.uniq
112
121
  end
113
122
 
114
123
  def group_capabilities
115
- groups.collect{|r| r.capabilities }.flatten.uniq.compact
124
+ Capability.joins(:capability_type).joins(:capability_accessors).
125
+ where(:capability_accessors => { :capability_accessor_record_type => "Group" }).
126
+ where("capability_accessor_record_id IN (#{groups.select('groups.id').to_sql})")
116
127
  end
117
128
 
118
129
  def role_capabilities
119
- all_roles.collect{|r| r.capabilities }.flatten.compact
130
+ Capability.joins(:capability_type).joins(:capability_accessors).
131
+ where(:capability_accessors => { :capability_accessor_record_type => "SecurityRole" }).
132
+ where("capability_accessor_record_id IN (#{all_roles.select('security_roles.id').to_sql})")
120
133
  end
121
134
 
122
135
  def all_capabilities
123
- (role_capabilities + group_capabilities + capabilities).uniq
136
+ Capability.joins(:capability_type).joins(:capability_accessors).
137
+ where("(capability_accessors.capability_accessor_record_type = 'Group' AND
138
+ capability_accessor_record_id IN (#{groups.select('groups.id').to_sql})) OR
139
+ (capability_accessors.capability_accessor_record_type = 'SecurityRole' AND
140
+ capability_accessor_record_id IN (#{all_roles.select('security_roles.id').to_sql})) OR
141
+ (capability_accessors.capability_accessor_record_type = 'User' AND
142
+ capability_accessor_record_id = #{self.id})")
143
+ end
144
+
145
+ def all_uniq_capabilities
146
+ all_capabilities.all.uniq
124
147
  end
125
148
 
126
149
  def group_class_capabilities
127
- groups.collect{|g| g.class_capabilities }.flatten.uniq.compact
150
+ scope_type = ScopeType.find_by_internal_identifier('class')
151
+ group_capabilities.where(:scope_type_id => scope_type.id)
128
152
  end
129
153
 
130
154
  def role_class_capabilities
131
- all_roles.collect{|r| r.class_capabilities }.flatten.uniq.compact
155
+ scope_type = ScopeType.find_by_internal_identifier('class')
156
+ role_capabilities.where(:scope_type_id => scope_type.id)
132
157
  end
133
158
 
134
159
  def all_class_capabilities
135
- (role_class_capabilities + group_class_capabilities + class_capabilities).uniq
160
+ scope_type = ScopeType.find_by_internal_identifier('class')
161
+ all_capabilities.where(:scope_type_id => scope_type.id)
162
+ end
163
+
164
+ def all_uniq_class_capabilities
165
+ all_class_capabilities.all.uniq
136
166
  end
137
167
 
138
168
  def class_capabilities_to_hash
139
- all_class_capabilities.map {|capability|
169
+ all_uniq_class_capabilities.map {|capability|
140
170
  { :capability_type_iid => capability.capability_type.internal_identifier,
141
171
  :capability_resource_type => capability.capability_resource_type
142
172
  }
@@ -77,7 +77,8 @@ module ErpTechSvcs
77
77
 
78
78
  # pass in (capability_type_iid, klass) or (capability) object
79
79
  def add_capability(*capability)
80
- capability = capability.first.is_a?(String) ? get_or_create_capability(capability.first, capability.second) : capability.first
80
+ capability_type_iid = capability.first.is_a?(Symbol) ? capability.first.to_s : capability.first
81
+ capability = capability_type_iid.is_a?(String) ? get_or_create_capability(capability_type_iid, capability.second) : capability.first
81
82
  ca = CapabilityAccessor.find_or_create_by_capability_accessor_record_type_and_capability_accessor_record_id_and_capability_id(get_superclass, self.id, capability.id)
82
83
  self.reload
83
84
  ca
@@ -89,8 +90,12 @@ module ErpTechSvcs
89
90
 
90
91
  def get_or_create_capability(capability_type_iid, klass)
91
92
  capability_type = convert_capability_type(capability_type_iid)
92
- scope_type = ScopeType.find_by_internal_identifier('class')
93
- Capability.find_or_create_by_capability_resource_type_and_capability_type_id_and_scope_type_id(klass, capability_type.id, scope_type.id)
93
+ if klass.is_a?(String)
94
+ scope_type = ScopeType.find_by_internal_identifier('class')
95
+ Capability.find_or_create_by_capability_resource_type_and_capability_type_id_and_scope_type_id(klass, capability_type.id, scope_type.id)
96
+ else
97
+ klass.add_capability(capability_type_iid) # create instance capability
98
+ end
94
99
  end
95
100
 
96
101
  def get_capability(capability_type_iid, klass)
@@ -101,7 +106,8 @@ module ErpTechSvcs
101
106
 
102
107
  # pass in (capability_type_iid, klass) or (capability) object
103
108
  def remove_capability(*capability)
104
- capability = capability.first.is_a?(String) ? get_or_create_capability(capability.first, capability.second) : capability.first
109
+ capability_type_iid = capability.first.is_a?(Symbol) ? capability.first.to_s : capability.first
110
+ capability = capability_type_iid.is_a?(String) ? get_or_create_capability(capability_type_iid, capability.second) : capability.first
105
111
  ca = capability_accessors.where(:capability_accessor_record_type => get_superclass, :capability_accessor_record_id => self.id, :capability_id => capability.id).first
106
112
  ca.destroy unless ca.nil?
107
113
  self.reload
@@ -9,15 +9,24 @@ module ErpTechSvcs
9
9
 
10
10
  module ClassMethods
11
11
 
12
- def protected_with_capabilities
12
+ def protected_with_capabilities(options = {})
13
13
  extend ProtectedByCapabilities::SingletonMethods
14
14
  include ProtectedByCapabilities::InstanceMethods
15
-
16
- has_many :capabilities, :as => :capability_resource
17
15
 
18
- # get records filtered via query scope capabilities
19
- # by default Compass AE treats query scopes as restrictions
20
- # a user will see all records unless the user has a capability accessor with a query scope
16
+ has_many :capabilities, :as => :capability_resource
17
+
18
+ # protect all instance of this class by default
19
+ class_attribute :protect_all_instances
20
+ self.protect_all_instances = (options[:protect_all_instances].nil? ? false : options[:protect_all_instances])
21
+
22
+ # Get records filtered via query scope capabilities
23
+ # By default Compass AE treats query scopes as restrictions
24
+ # A user will see all records unless the user has a capability accessor with a query scope
25
+ # If you set :protect_all_instances => true it is honored via with_user_security & with_instance_security but NOT with_query_security
26
+ # arguments: user, capability_type_iids
27
+ # capability_type_iids is optional and can be a single string or an array of strings
28
+ # Example: which files can this user download? FileAsset.with_query_security(user, 'download').all
29
+ # Example: which website sections can this user either view or edit? WebsiteSection.with_query_security(user, ['view','edit']).all
21
30
  scope :with_query_security, lambda{|*args|
22
31
  raise ArgumentError if args.empty? || args.size > 2
23
32
  user = args.first
@@ -25,11 +34,11 @@ module ErpTechSvcs
25
34
  capability_type_iids = [capability_type_iids] if capability_type_iids.is_a?(String)
26
35
 
27
36
  scope_type = ScopeType.find_by_internal_identifier('query')
28
- granted_capabilities = user.all_capabilities.collect{|c| c if c.scope_type_id == scope_type.id and c.capability_resource_type == self.name }.compact
37
+ granted_capabilities = user.all_capabilities.where(:scope_type_id => scope_type.id).where(:capability_resource_type => self.name)
29
38
 
30
39
  unless capability_type_iids.empty?
31
40
  capability_type_ids = capability_type_iids.collect{|type| convert_capability_type(type).id }
32
- granted_capabilities = granted_capabilities.collect{|c| c if capability_type_ids.include?(c.capability_type_id)}.compact
41
+ granted_capabilities = granted_capabilities.where("capability_type_id IN (?)", capability_type_ids.join(','))
33
42
  end
34
43
 
35
44
  query = nil
@@ -39,34 +48,45 @@ module ErpTechSvcs
39
48
  query
40
49
  }
41
50
 
42
- # get records for this model without capabilities or that are not in a list of denied capabilities
43
- scope :with_instance_security, lambda{|denied_capabilities|
44
- query = joins("LEFT JOIN capabilities AS c ON c.capability_resource_id = #{self.table_name}.id AND c.capability_resource_type = '#{self.name}'").
45
- group(columns.collect{|c| "#{self.table_name}.#{c.name}" })
46
- query = (denied_capabilities.empty? ? query.where("c.id IS NULL OR c.id = c.id") : query.where("c.id IS NULL OR c.id NOT IN (?)", denied_capabilities.collect{|c| c.id }))
47
- query
48
- }
49
-
50
- # get records for this model that the given user has access to
51
+ # Get records for this model permitted via instance capabilities
52
+ # If :protect_all_instances => true return only instances user has explicitly been granted access to
53
+ # If :protect_all_instances => false return instances without capabilities or that user is granted access to (default)
51
54
  # arguments: user, capability_type_iids
52
55
  # capability_type_iids is optional and can be a single string or an array of strings
53
- # Example: which files can this user download? FileAsset.with_user_security(user, 'download').all
54
- # Example: which website sections can this user either view or edit? WebsiteSection.with_user_security(user, ['view','edit']).all
55
- scope :with_user_security, lambda{|*args|
56
+ # Example: which files can this user download? FileAsset.with_instance_security(user, 'download').all
57
+ # Example: which website sections can this user either view or edit? WebsiteSection.with_instance_security(user, ['view','edit']).all
58
+ scope :with_instance_security, lambda{|*args|
56
59
  raise ArgumentError if args.empty? || args.size > 2
57
60
  user = args.first
58
61
  capability_type_iids = args.second || []
59
62
  capability_type_iids = [capability_type_iids] if capability_type_iids.is_a?(String)
60
63
 
61
64
  scope_type = ScopeType.find_by_internal_identifier('instance')
62
- granted_capabilities = user.all_capabilities.collect{|c| c if c.scope_type_id == scope_type.id and c.capability_resource_type == self.name }.compact
65
+ granted_capabilities = user.all_capabilities.where(:scope_type_id => scope_type.id).where(:capability_resource_type => self.name)
63
66
 
64
67
  unless capability_type_iids.empty?
65
68
  capability_type_ids = capability_type_iids.collect{|type| convert_capability_type(type).id }
66
- granted_capabilities = granted_capabilities.collect{|c| c if capability_type_ids.include?(c.capability_type_id)}.compact
69
+ granted_capabilities = granted_capabilities.where("capability_type_id IN (#{capability_type_ids.join(',')})")
67
70
  end
68
-
69
- with_query_security(*args).with_instance_security(instance_capabilities - granted_capabilities)
71
+
72
+ denied_capabilities = instance_capabilities.select('capabilities.id').where("capabilities.id NOT IN (#{granted_capabilities.select('capabilities.id').to_sql})")
73
+ deny_count = denied_capabilities.count
74
+
75
+ join_type = (self.protect_all_instances ? 'JOIN' : 'LEFT JOIN')
76
+ query = joins("#{join_type} capabilities AS c ON c.capability_resource_id = #{self.table_name}.id AND c.capability_resource_type = '#{self.name}'").
77
+ group(columns.collect{|c| "#{self.table_name}.#{c.name}" })
78
+ query = (deny_count == 0 ? query.where("c.id IS NULL OR c.id = c.id") : query.where("c.id IS NULL OR c.id NOT IN (#{denied_capabilities.to_sql})"))
79
+ query
80
+ }
81
+
82
+ # Get records for this model that the given user has access to
83
+ # arguments: user, capability_type_iids
84
+ # capability_type_iids is optional and can be a single string or an array of strings
85
+ # Example: which files can this user download? FileAsset.with_user_security(user, 'download').all
86
+ # Example: which website sections can this user either view or edit? WebsiteSection.with_user_security(user, ['view','edit']).all
87
+ scope :with_user_security, lambda{|*args|
88
+ raise ArgumentError if args.empty? || args.size > 2
89
+ with_instance_security(*args).with_query_security(*args)
70
90
  }
71
91
  end
72
92
  end
@@ -102,9 +122,9 @@ module ErpTechSvcs
102
122
  capabilities.where(:scope_type_id => scope_type.id)
103
123
  end
104
124
 
105
- # collect unique roles on capabilities
125
+ # return unique roles on capabilities for this model
106
126
  def capability_roles
107
- capabilities.collect{|c| c.roles }.flatten.uniq
127
+ SecurityRole.joins(:capability_accessors => :capability).where(:capability_accessors => {:capabilities => {:capability_resource_type => get_superclass(self.name) }}).all.uniq
108
128
  end
109
129
 
110
130
  # add a class level capability (capability_resource_id will be NULL)
@@ -147,6 +167,11 @@ module ErpTechSvcs
147
167
 
148
168
  module InstanceMethods
149
169
 
170
+ # convenience method to access class method
171
+ def protect_all_instances
172
+ self.class.protect_all_instances
173
+ end
174
+
150
175
  def add_capability(capability_type_iid)
151
176
  capability_type = convert_capability_type(capability_type_iid)
152
177
  scope_type = ScopeType.find_by_internal_identifier('instance')
@@ -165,11 +190,11 @@ module ErpTechSvcs
165
190
  end
166
191
 
167
192
  def protected_with_capability?(capability_type_iid)
168
- !get_capability(capability_type_iid).nil?
193
+ !get_capability(capability_type_iid).nil? or protect_all_instances
169
194
  end
170
195
 
171
196
  def allow_access?(user, capability_type_iid)
172
- if !self.protected_with_capability?(capability_type_iid.to_s) or (user and user.has_capability?(capability_type_iid.to_s, self))
197
+ if (!self.protect_all_instances and !self.protected_with_capability?(capability_type_iid.to_s)) or (user and user.has_capability?(capability_type_iid.to_s, self))
173
198
  return true
174
199
  else
175
200
  return false
@@ -13,15 +13,17 @@ module ErpTechSvcs
13
13
  where(:capability_resource_type => klass).
14
14
  where(:scope_type_id => scope_type.id).
15
15
  where(:capability_types => {:internal_identifier => capability_type_iid}).first
16
+ return nil if capability.nil? # capability not found so return nil
16
17
  else
17
18
  scope_type = ScopeType.find_by_internal_identifier('instance')
18
19
  capability = klass.capabilities.joins(:capability_type).
19
20
  where(:scope_type_id => scope_type.id).
20
21
  where(:capability_types => {:internal_identifier => capability_type_iid}).first
21
- return true if capability.nil? # object is not secured, so return true
22
+ # if capability not found, we see if all instances are protected
23
+ # if all instance are protected, return false, otherwise true
24
+ return !klass.protect_all_instances if capability.nil?
22
25
  end
23
- result = all_capabilities.find{|c| c == capability }
24
- result.nil? ? false : true
26
+ all_capabilities.include?(capability)
25
27
  end
26
28
 
27
29
  # pass in (capability_type_iid, class name or any class instance, a block of code)
@@ -2,7 +2,7 @@ module ErpTechSvcs
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 1
5
- TINY = 0
5
+ TINY = 1
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].compact.join('.')
8
8
  end
@@ -8,8 +8,8 @@ namespace :erp_tech_svcs do
8
8
 
9
9
  #sync shared
10
10
  puts "Syncing Shared Assets..."
11
- file_support.sync(File.join(file_support.root, '/images'), CompassAeInstance.first)
12
- file_support.sync(File.join(file_support.root, '/files'), CompassAeInstance.first)
11
+ file_support.sync(File.join(file_support.root, '/images'), CompassAeInstance.find_by_internal_identifier('base'))
12
+ file_support.sync(File.join(file_support.root, '/files'), CompassAeInstance.find_by_internal_identifier('base'))
13
13
  puts "Complete"
14
14
 
15
15
  #sync websites
@@ -4,17 +4,20 @@ describe ErpTechSvcs::Extensions::ActiveRecord::HasSecurityRoles do
4
4
  before(:all) do
5
5
  @user = FactoryGirl.create(:user)
6
6
  @user_2 = FactoryGirl.create(:user)
7
- @admin_role = SecurityRole.create(:description => 'Admin', :internal_identifier => 'admin')
8
- @employee_role = SecurityRole.create(:description => 'Employee', :internal_identifier => 'employee')
9
- @manager_role = SecurityRole.create(:description => 'Manager', :internal_identifier => 'manager')
7
+
8
+ @admin_role = SecurityRole.find_or_create_by_description_and_internal_identifier(:description => 'Admin', :internal_identifier => 'admin')
9
+ @employee_role = SecurityRole.find_or_create_by_description_and_internal_identifier(:description => 'Employee', :internal_identifier => 'employee')
10
+ @manager_role = SecurityRole.find_or_create_by_description_and_internal_identifier(:description => 'Manager', :internal_identifier => 'manager')
10
11
  end
11
12
 
12
13
  it "should allow you to add a role" do
13
14
  @user.add_role(@admin_role)
15
+ @user.remove_all_roles
14
16
  end
15
17
 
16
18
  it "should allow you to add multiple roles by Role instance or iid" do
17
19
  @user.add_roles(@admin_role, 'manager')
20
+ @user.remove_all_roles
18
21
  end
19
22
 
20
23
  it "should allow you to add multiple roles by array or arguments" do
@@ -35,11 +38,13 @@ describe ErpTechSvcs::Extensions::ActiveRecord::HasSecurityRoles do
35
38
  end
36
39
 
37
40
  it "should allow you to remove a role" do
41
+ @user.add_role(@admin_role)
38
42
  @user.remove_role(@admin_role)
39
43
  @user.has_role?(@admin_role).should eq false
40
44
  end
41
45
 
42
46
  it "should allow you to remove multiple roles by Role instance or iid" do
47
+ @user.add_roles(@admin_role, 'manager')
43
48
  @user.remove_roles(@employee_role, 'manager')
44
49
  @user.has_role?(@employee_role).should eq false
45
50
  @user.has_role?('manager').should eq false
data/spec/spec_helper.rb CHANGED
@@ -20,6 +20,8 @@ Spork.prefork do
20
20
  require File.expand_path(DUMMY_APP_ROOT + "/config/environment.rb", __FILE__)
21
21
 
22
22
  ActiveRecord::Base.configurations = YAML::load(IO.read(DUMMY_APP_ROOT + "/config/database.yml"))
23
+ `rake db:drop RAILS_ENV=spec`
24
+ `rake db:create RAILS_ENV=spec`
23
25
  ActiveRecord::Base.establish_connection(ENV["DB"] || "spec")
24
26
  ActiveRecord::Migration.verbose = false
25
27
 
@@ -43,12 +45,12 @@ Spork.each_run do
43
45
  #We have to execute the migrations from dummy app directory
44
46
  Dir.chdir DUMMY_APP_ROOT
45
47
  `rake db:drop RAILS_ENV=spec`
48
+ `rake db:create RAILS_ENV=spec`
46
49
  Dir.chdir ENGINE_RAILS_ROOT
47
50
 
48
51
  #We have to execute the migratiapp:compass_ae:install:data_migrationsons from dummy app directory
49
52
  Dir.chdir DUMMY_APP_ROOT
50
53
 
51
-
52
54
  `rake compass_ae:install:migrations RAILS_ENV=spec`
53
55
  `rake compass_ae:install:data_migrations RAILS_ENV=spec`
54
56
  `rake db:migrate RAILS_ENV=spec`
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: erp_tech_svcs
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.0
4
+ version: 3.1.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-11 00:00:00.000000000 Z
12
+ date: 2013-02-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: erp_base_erp_svcs
@@ -305,18 +305,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
305
305
  - - ! '>='
306
306
  - !ruby/object:Gem::Version
307
307
  version: '0'
308
- segments:
309
- - 0
310
- hash: 697401427352755655
311
308
  required_rubygems_version: !ruby/object:Gem::Requirement
312
309
  none: false
313
310
  requirements:
314
311
  - - ! '>='
315
312
  - !ruby/object:Gem::Version
316
313
  version: '0'
317
- segments:
318
- - 0
319
- hash: 697401427352755655
320
314
  requirements: []
321
315
  rubyforge_project:
322
316
  rubygems_version: 1.8.24