erp_tech_svcs 4.0.0 → 4.2.0

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -24
  3. data/app/controllers/api/v1/audit_log_items_controller.rb +33 -0
  4. data/app/controllers/api/v1/audit_logs_controller.rb +32 -0
  5. data/app/controllers/api/v1/capabilities_controller.rb +160 -0
  6. data/app/controllers/api/v1/file_assets_controller.rb +40 -0
  7. data/app/controllers/api/v1/groups_controller.rb +236 -0
  8. data/app/controllers/api/v1/security_roles_controller.rb +276 -0
  9. data/app/controllers/api/v1/users_controller.rb +262 -0
  10. data/app/controllers/erp_tech_svcs/session_controller.rb +8 -5
  11. data/app/controllers/erp_tech_svcs/user_controller.rb +14 -15
  12. data/app/mailers/user_mailer.rb +8 -5
  13. data/app/models/audit_log.rb +111 -36
  14. data/app/models/audit_log_item.rb +30 -0
  15. data/app/models/audit_log_item_type.rb +1 -0
  16. data/app/models/audit_log_type.rb +19 -0
  17. data/app/models/capability.rb +22 -6
  18. data/app/models/extensions/tracked_status_type.rb +3 -0
  19. data/app/models/file_asset.rb +245 -20
  20. data/app/models/file_asset_holder.rb +20 -0
  21. data/app/models/group.rb +38 -25
  22. data/app/models/notification.rb +32 -13
  23. data/app/models/notification_type.rb +13 -0
  24. data/app/models/security_role.rb +17 -4
  25. data/app/models/user.rb +116 -29
  26. data/app/validators/password_strength_validator.rb +1 -1
  27. data/app/views/user_mailer/activation_needed_email.html.erb +293 -15
  28. data/app/views/user_mailer/reset_password_email.html.erb +268 -13
  29. data/config/initializers/logger.rb +19 -0
  30. data/config/initializers/sorcery.rb +2 -0
  31. data/config/initializers/wickedpdf.rb +4 -0
  32. data/config/routes.rb +64 -0
  33. data/db/data_migrations/20110802200222_schedule_delete_expired_sessions_job.rb +1 -5
  34. data/db/data_migrations/20150819140550_create_job_tracker_for_notification.rb +14 -0
  35. data/db/migrate/20080805000010_base_tech_services.rb +99 -39
  36. data/db/migrate/20150414151421_add_nested_set_columns_to_security_role.rb +13 -0
  37. data/db/migrate/20150609003216_update_user_for_sorcery.rb +11 -0
  38. data/db/migrate/20150819135108_add_custom_fields_to_notifications.rb +5 -0
  39. data/db/migrate/20160122155402_add_description_to_file_asset.rb +13 -0
  40. data/db/migrate/20160310163060_add_created_by_updated_by_to_erp_tech_svcs.rb +35 -0
  41. data/db/migrate/20160313161611_add_tenant_id_to_audit_log.rb +16 -0
  42. data/lib/erp_tech_svcs.rb +6 -10
  43. data/lib/erp_tech_svcs/config.rb +7 -2
  44. data/lib/erp_tech_svcs/delayed_jobs/delete_expired_sessions_job.rb +49 -0
  45. data/lib/erp_tech_svcs/delayed_jobs/notification_job.rb +50 -0
  46. data/lib/erp_tech_svcs/engine.rb +0 -1
  47. data/lib/erp_tech_svcs/erp_tech_svcs_audit_log.rb +12 -6
  48. data/lib/erp_tech_svcs/extensions.rb +0 -1
  49. data/lib/erp_tech_svcs/extensions/active_record/has_capability_accessors.rb +57 -29
  50. data/lib/erp_tech_svcs/extensions/active_record/has_file_assets.rb +57 -31
  51. data/lib/erp_tech_svcs/extensions/active_record/has_security_roles.rb +12 -4
  52. data/lib/erp_tech_svcs/extensions/active_record/is_json.rb +22 -15
  53. data/lib/erp_tech_svcs/extensions/active_record/scoped_by.rb +16 -13
  54. data/lib/erp_tech_svcs/extensions/compass_ae/erp_base_erp_svcs/controllers/api/parties_controller.rb +15 -0
  55. data/lib/erp_tech_svcs/file_support.rb +1 -0
  56. data/lib/erp_tech_svcs/file_support/file_system_manager.rb +77 -44
  57. data/lib/erp_tech_svcs/file_support/manager.rb +12 -3
  58. data/lib/erp_tech_svcs/file_support/railties/compass_ae_resolver.rb +49 -0
  59. data/lib/erp_tech_svcs/file_support/s3_manager.rb +73 -51
  60. data/lib/erp_tech_svcs/utils/compass_access_negotiator.rb +11 -2
  61. data/lib/erp_tech_svcs/utils/default_nested_set_methods.rb +238 -46
  62. data/lib/erp_tech_svcs/version.rb +1 -1
  63. data/lib/tasks/erp_tech_svcs_tasks.rake +43 -5
  64. metadata +73 -42
  65. data/app/models/user_defined_data.rb +0 -6
  66. data/app/models/user_defined_field.rb +0 -8
  67. data/config/initializers/pdfkit.rb +0 -18
  68. data/db/data_migrations/20121130212146_note_capabilities.rb +0 -23
  69. data/db/migrate/20121116151510_create_groups.rb +0 -18
  70. data/db/migrate/20121126171612_upgrade_security.rb +0 -53
  71. data/db/migrate/20121126173506_upgrade_security2.rb +0 -274
  72. data/db/migrate/20130410135419_add_queue_to_delayed_jobs.rb +0 -13
  73. data/db/migrate/20130610163240_create_notifications.rb +0 -37
  74. data/db/migrate/20130725212647_add_party_id_idx_to_users.rb +0 -9
  75. data/db/migrate/20131113213843_add_audit_log_item_old_value.rb +0 -13
  76. data/db/migrate/20131113213844_add_erp_tech_svcs_missing_indexes.rb +0 -31
  77. data/db/migrate/20131129203603_add_user_defined_fields.rb +0 -43
  78. data/db/migrate/20141013060204_add_custom_fields_to_notifications.rb +0 -12
  79. data/db/migrate/20141108182427_add_scoped_by_to_file_assets.rb +0 -14
  80. data/lib/erp_tech_svcs/extensions/active_record/has_user_defined_data.rb +0 -147
  81. data/lib/erp_tech_svcs/sessions/delete_expired_sessions_job.rb +0 -47
  82. data/lib/erp_tech_svcs/sessions/delete_expired_sessions_service.rb +0 -15
  83. data/lib/erp_tech_svcs/utils/compass_logger.rb +0 -87
@@ -1,3 +1,23 @@
1
+ # create_table :file_assets do |t|
2
+ # t.string :type
3
+ # t.string :name
4
+ # t.string :directory
5
+ # t.string :data_file_name
6
+ # t.string :data_content_type
7
+ # t.integer :data_file_size
8
+ # t.datetime :data_updated_at
9
+ # t.text :scoped_by
10
+ # t.string :width
11
+ # t.string :height
12
+ # t.string :description
13
+ #
14
+ # t.timestamps
15
+ # end
16
+ # add_index :file_assets, :type
17
+ # add_index :file_assets, [:file_asset_holder_id, :file_asset_holder_type], :name => 'file_asset_holder_idx'
18
+ # add_index :file_assets, :name
19
+ # add_index :file_assets, :directory
20
+
1
21
  require 'fileutils'
2
22
 
3
23
  Paperclip.interpolates(:file_path) { |data, style|
@@ -16,14 +36,12 @@ Paperclip.interpolates(:file_url) { |data, style|
16
36
  when :filesystem
17
37
  #if public is at the front of this path and we are using file_system remove it
18
38
  dir_pieces = url.split('/')
19
- path = unless dir_pieces[1] == 'public'
20
- "/download/#{data.instance.name}?path=#{dir_pieces.delete_if { |name| name == data.instance.name }.join('/')}"
21
- else
22
- dir_pieces.delete_at(1) if dir_pieces[1] == 'public'
23
- dir_pieces.join('/')
24
- end
25
-
26
- "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, path)}"
39
+ unless dir_pieces[1] == 'public'
40
+ "/download/#{data.instance.name}?path=#{dir_pieces.delete_if { |name| name == data.instance.name }.join('/')}"
41
+ else
42
+ dir_pieces.delete_at(1) if dir_pieces[1] == 'public'
43
+ dir_pieces.join('/')
44
+ end
27
45
  when :s3
28
46
  url
29
47
  end
@@ -32,6 +50,8 @@ Paperclip.interpolates(:file_url) { |data, style|
32
50
  class FileAsset < ActiveRecord::Base
33
51
  attr_protected :created_at, :updated_at
34
52
 
53
+ tracks_created_by_updated_by
54
+
35
55
  if respond_to?(:class_attribute)
36
56
  class_attribute :file_type
37
57
  class_attribute :valid_extensions
@@ -47,12 +67,16 @@ class FileAsset < ActiveRecord::Base
47
67
 
48
68
  after_create :set_sti
49
69
  # must fire after paperclip's after_save :save_attached_files
50
- after_save :set_data_file_name, :save_dimensions
70
+ after_save :set_data_file_name
71
+
51
72
  before_validation(on: :create) do
52
73
  self.check_name_uniqueness
53
74
  end
54
75
 
55
- belongs_to :file_asset_holder, :polymorphic => true
76
+ has_many :file_asset_holders, :dependent => :destroy
77
+
78
+ acts_as_taggable
79
+
56
80
  instantiates_with_sti
57
81
 
58
82
  protected_with_capabilities
@@ -68,6 +92,7 @@ class FileAsset < ActiveRecord::Base
68
92
  :validations => {:extension => lambda { |data, file| validate_extension(data, file) }}
69
93
 
70
94
  before_post_process :set_content_type
95
+ before_save :save_dimensions
71
96
 
72
97
  validates_attachment_presence :data
73
98
  validates_attachment_size :data, :less_than => ErpTechSvcs::Config.max_file_size_in_mb.megabytes
@@ -80,6 +105,29 @@ class FileAsset < ActiveRecord::Base
80
105
  validates_format_of :name, :with => /^\w/
81
106
 
82
107
  class << self
108
+ def adjust_image(data, size=nil)
109
+ file_support = ErpTechSvcs::FileSupport::FileSystemManager.new
110
+ name = "#{SecureRandom.uuid}.jpg"
111
+ path = File.join(Rails.root, 'tmp', name)
112
+
113
+ data = StringIO.new(data) if data.is_a?(String)
114
+ File.open(path, 'wb+') { |f| f.write(data.read) }
115
+
116
+ # resize
117
+ if size
118
+ Paperclip.run("convert", "#{path} -resize #{size}^ #{path}", :swallow_stderr => false)
119
+ end
120
+
121
+ # rotate
122
+ Paperclip.run("convert", "#{path} -auto-orient #{path}", :swallow_stderr => false)
123
+
124
+ #remove the file after we get the data
125
+ data = file_support.get_contents(path)[0]
126
+ FileUtils.rm(path)
127
+
128
+ data
129
+ end
130
+
83
131
  def acceptable?(name)
84
132
  valid_extensions.include?(File.extname(name))
85
133
  end
@@ -115,6 +163,60 @@ class FileAsset < ActiveRecord::Base
115
163
  directory = nil if directory == '.'
116
164
  [directory, name]
117
165
  end
166
+
167
+ # Filter records
168
+ #
169
+ # @param filters [Hash] a hash of filters to be applied,
170
+ # @param statement [ActiveRecord::Relation] the query being built
171
+ # @return [ActiveRecord::Relation] the query being built
172
+ def apply_filters(filters, statement=nil)
173
+ statement = FileAsset unless statement
174
+
175
+ if filters[:file_asset_holder_type].present? && filters[:file_asset_holder_id].present?
176
+ statement = statement.joins(:file_asset_holders)
177
+ .where(file_asset_holders: {
178
+ file_asset_holder_id: filters[:file_asset_holder_id],
179
+ file_asset_holder_type: filters[:file_asset_holder_type]
180
+ })
181
+ end
182
+
183
+ statement
184
+ end
185
+
186
+ # scope by dba organization
187
+ #
188
+ # @param dba_organization [Party] dba organization to scope by
189
+ #
190
+ # @return [ActiveRecord::Relation]
191
+ def scope_by_dba_organization(dba_organization)
192
+ scope_by_party(dba_organization, {role_types: [RoleType.iid('dba_org')]})
193
+ end
194
+
195
+ alias scope_by_dba_org scope_by_dba_organization
196
+
197
+ # scope by party
198
+ #
199
+ # @param party [Integer | Party | Array] either a id of Party record, a Party record, an array of Party records
200
+ # or an array of Party ids
201
+ # @param options [Hash] options to apply to this scope
202
+ # @option options [Array] :role_types role types to include in the scope
203
+ #
204
+ # @return [ActiveRecord::Relation]
205
+ def scope_by_party(party, options={})
206
+ table_alias = String.random
207
+
208
+ if options[:role_types]
209
+ joins("inner join entity_party_roles as #{table_alias} on #{table_alias}.entity_record_type = 'FileAsset'
210
+ and #{table_alias}.entity_record_id = file_assets.id and
211
+ #{table_alias}.role_type_id in (#{RoleType.find_child_role_types(options[:role_types]).collect(&:id).join(',')})
212
+ and #{table_alias}.party_id in (#{Party.select('id').where(id: party).to_sql})")
213
+
214
+ else
215
+ joins("inner join entity_party_roles as #{table_alias} on #{table_alias}.entity_record_type = 'FileAsset'
216
+ and #{table_alias}.entity_record_id = file_assets.id
217
+ and #{table_alias}.party_id in (#{Party.select('id').where(id: party).to_sql})")
218
+ end
219
+ end
118
220
  end
119
221
 
120
222
  def initialize(attributes = {}, options={})
@@ -125,7 +227,7 @@ class FileAsset < ActiveRecord::Base
125
227
  base_path ||= data.original_filename if data.respond_to?(:original_filename)
126
228
 
127
229
  directory, name = FileAsset.split_path(base_path) if base_path and name.blank?
128
- directory.gsub!(Rails.root.to_s, '')
230
+ directory.gsub!(Rails.root.to_s, '') if directory
129
231
 
130
232
  @type ||= FileAsset.type_for(name) if name
131
233
  @type = "TextFile" if @type.nil?
@@ -136,9 +238,18 @@ class FileAsset < ActiveRecord::Base
136
238
  super attributes.merge(:directory => directory, :name => name, :data => data)
137
239
  end
138
240
 
241
+ def fully_qualified_url
242
+ case ErpTechSvcs::Config.file_storage
243
+ when :filesystem
244
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, data.url)}"
245
+ when :s3
246
+ data.url
247
+ end
248
+ end
249
+
139
250
  def check_name_uniqueness
140
251
  # check if name is already taken
141
- unless FileAsset.where('directory = ? and name = ?', self.directory, self.name).first.nil?
252
+ unless FileAsset.where('directory = ? and name = ?', self.directory, self.name).first.nil?
142
253
  # if it is keeping add incrementing by 1 until we have a good name
143
254
  counter = 0
144
255
  while true
@@ -180,20 +291,23 @@ class FileAsset < ActiveRecord::Base
180
291
  file_path = File.join(self.directory, self.name).sub(%r{^/}, '')
181
292
  options = {}
182
293
  options[:expires] = ErpTechSvcs::Config.s3_url_expires_in_seconds if self.is_secured?
183
- return file_support.bucket.objects[file_path].url_for(:read, options).to_s
294
+ file_support.bucket.objects[file_path].url_for(:read, options).to_s
184
295
  else
185
- return File.join(Rails.root, self.directory, self.name)
296
+ File.join(Rails.root, self.directory, self.name)
186
297
  end
187
298
  end
188
299
 
189
300
  def save_dimensions
190
- if type == 'Image'
301
+ if @type == 'Image'
191
302
  begin
192
- f = Paperclip::Geometry.from_file(self.path)
193
- w = f.width.to_i
194
- h = f.height.to_i
195
- update_attribute(:width, w) if width != w
196
- update_attribute(:height, h) if height != h
303
+ tempfile = data.queued_for_write[:original]
304
+ unless tempfile.nil?
305
+ geometry = Paperclip::Geometry.from_file(tempfile)
306
+ w = geometry.width.to_i
307
+ h = geometry.height.to_i
308
+ update_attribute(:width, w) if width != w
309
+ update_attribute(:height, h) if height != h
310
+ end
197
311
  rescue => ex
198
312
  Rails.logger.error('Could not save width and height of image. Make sure Image Magick and the identify command are accessible')
199
313
  end
@@ -258,11 +372,40 @@ class FileAsset < ActiveRecord::Base
258
372
  return result, message
259
373
  end
260
374
 
375
+ def to_s
376
+ self.description
377
+ end
378
+
379
+ def to_data_hash
380
+ data = to_hash(only: [:id, :directory, :width, :height, :name, :description])
381
+
382
+ data[:url] = self.data.url
383
+ data[:fully_qualified_url] = self.fully_qualified_url
384
+ data[:tags] = self.tag_list.join(',')
385
+ data[:thumbnail_src] = self.thumbnail_src
386
+
387
+ data
388
+ end
389
+
390
+ def thumbnail_src
391
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, 'assets/default_file.png')}"
392
+ end
393
+
261
394
  end
262
395
 
263
396
  class Image < FileAsset
264
397
  self.file_type = :image
265
398
  self.valid_extensions = %w(.jpg .JPG .jpeg .JPEG .gif .GIF .png .PNG .ico .ICO .bmp .BMP .tif .tiff .TIF .TIFF)
399
+
400
+ def thumbnail_src
401
+ thumbnail_image = FileAsset.where("data_file_name = ? and directory like '%thumbnail%' and id = ?", self.name, self.id).first
402
+
403
+ if thumbnail_image
404
+ thumbnail_image.fully_qualified_url
405
+ else
406
+ self.fully_qualified_url
407
+ end
408
+ end
266
409
  end
267
410
 
268
411
  class TextFile < FileAsset
@@ -278,46 +421,128 @@ class TextFile < FileAsset
278
421
  def text
279
422
  @text ||= ::File.read(path) rescue ''
280
423
  end
424
+
425
+ def thumbnail_src
426
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, 'assets/default_file.png')}"
427
+ end
281
428
  end
282
429
 
283
430
  class Javascript < TextFile
284
431
  self.file_type = :javascript
285
432
  self.content_type = 'text/javascript'
286
433
  self.valid_extensions = %w(.js .JS)
434
+
435
+ def thumbnail_src
436
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/javascript_file.png')}"
437
+ end
287
438
  end
288
439
 
289
440
  class Stylesheet < TextFile
290
441
  self.file_type = :stylesheet
291
442
  self.content_type = 'text/css'
292
443
  self.valid_extensions = %w(.css .CSS)
444
+
445
+ def thumbnail_src
446
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/css_file.png')}"
447
+ end
293
448
  end
294
449
 
295
450
  class Template < TextFile
296
451
  self.file_type = :template
297
452
  self.content_type = 'text/plain'
298
453
  self.valid_extensions = %w(.erb .haml .liquid .builder)
454
+
455
+ def thumbnail_src
456
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, 'assets/tpl_file.png')}"
457
+ end
299
458
  end
300
459
 
301
460
  class HtmlFile < TextFile
302
461
  self.file_type = :html
303
462
  self.content_type = 'text/html'
304
463
  self.valid_extensions = %w(.html .HTML)
464
+
465
+ def thumbnail_src
466
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/html_file.png')}"
467
+ end
305
468
  end
306
469
 
307
470
  class XmlFile < TextFile
308
471
  self.file_type = :xml
309
472
  self.content_type = 'text/plain'
310
473
  self.valid_extensions = %w(.xml .XML)
474
+
475
+ def thumbnail_src
476
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/xml_file.png')}"
477
+ end
478
+ end
479
+
480
+ class DocFile < TextFile
481
+ self.file_type = :doc
482
+ self.content_type = 'application/msword'
483
+ self.valid_extensions = %w(.doc .dot)
484
+
485
+ def thumbnail_src
486
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/doc_file.png')}"
487
+ end
488
+ end
489
+
490
+ class DocxFile < TextFile
491
+ self.file_type = :docx
492
+ self.content_type = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'
493
+ self.valid_extensions = %w(.docx)
494
+
495
+ def thumbnail_src
496
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/docx_file.png')}"
497
+ end
498
+ end
499
+
500
+ class Xls < TextFile
501
+ self.file_type = :xls
502
+ self.content_type = 'application/vnd.ms-excel'
503
+ self.valid_extensions = %w(.xls .xlt .xla .xlsx)
504
+
505
+ def thumbnail_src
506
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/xls_file.png')}"
507
+ end
508
+ end
509
+
510
+ class Ppt < TextFile
511
+ self.file_type = :ppt
512
+ self.content_type = 'application/vnd.ms-powerpoint'
513
+ self.valid_extensions = %w(.ppt .pot .pps .ppa)
514
+
515
+ def thumbnail_src
516
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, 'assets/ppt_file.png')}"
517
+ end
518
+ end
519
+
520
+ class Pptx < TextFile
521
+ self.file_type = :pptx
522
+ self.content_type = 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
523
+ self.valid_extensions = %w(.pptx)
524
+
525
+ def thumbnail_src
526
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, 'assets/pptx_file.png')}"
527
+ end
311
528
  end
312
529
 
313
530
  class Pdf < TextFile
314
531
  self.file_type = :pdf
315
532
  self.content_type = 'application/pdf'
316
533
  self.valid_extensions = %w(.pdf .PDF)
534
+
535
+ def thumbnail_src
536
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/pdf_file.png')}"
537
+ end
317
538
  end
318
539
 
319
540
  class Swf < FileAsset
320
541
  self.file_type = :swf
321
542
  self.content_type = 'application/x-shockwave-flash'
322
543
  self.valid_extensions = %w(.swf .SWF)
544
+
545
+ def thumbnail_src
546
+ "#{ErpTechSvcs::Config.file_protocol}://#{File.join(ErpTechSvcs::Config.installation_domain, '/assets/shockwave_file.png')}"
547
+ end
323
548
  end
@@ -0,0 +1,20 @@
1
+ # create_table :file_asset_holders do |t|
2
+ # t.references :file_asset
3
+ # t.references :file_asset_holder, :polymorphic => true
4
+ # t.text :scoped_by
5
+ #
6
+ # t.timestamps
7
+ # end
8
+ #
9
+ # add_index :file_asset_holders, :file_asset_id, :name => 'file_asset_holder_file_id_idx'
10
+ # add_index :file_asset_holders, [:file_asset_holder_id, :file_asset_holder_type], :name => 'file_asset_holder_idx'
11
+
12
+ class FileAssetHolder < ActiveRecord::Base
13
+ attr_protected :created_at, :updated_at
14
+
15
+ belongs_to :file_asset
16
+ belongs_to :file_asset_holder, :polymorphic => true
17
+
18
+ # setup scoping
19
+ add_scoped_by :scoped_by
20
+ end
@@ -1,3 +1,10 @@
1
+ # unless table_exists?(:groups)
2
+ # create_table :groups do |t|
3
+ # t.column :description, :string
4
+ # t.timestamps
5
+ # end
6
+ # end
7
+
1
8
  # Security Group
2
9
  class Group < ActiveRecord::Base
3
10
  has_capability_accessors
@@ -5,7 +12,7 @@ class Group < ActiveRecord::Base
5
12
  after_create :create_party
6
13
  after_save :save_party
7
14
  after_destroy :destroy_party_relationships, :destroy_party
8
-
15
+
9
16
  has_one :party, :as => :business_party
10
17
 
11
18
  attr_accessible :description
@@ -46,11 +53,11 @@ class Group < ActiveRecord::Base
46
53
  pty = Party.new
47
54
  pty.description = self.description
48
55
  pty.business_party = self
49
-
56
+
50
57
  pty.save
51
58
  self.save
52
59
  end
53
-
60
+
54
61
  def save_party
55
62
  self.party.description = self.description
56
63
  self.party.save
@@ -61,7 +68,7 @@ class Group < ActiveRecord::Base
61
68
  self.party.destroy
62
69
  end
63
70
  end
64
-
71
+
65
72
  def destroy_party_relationships
66
73
  party_relationships.destroy_all
67
74
  end
@@ -71,23 +78,18 @@ class Group < ActiveRecord::Base
71
78
  PartyRelationship.where(:party_id_to => self.party.id)
72
79
  end
73
80
 
74
- def join_party_relationships
75
- role_type = RoleType.find_by_internal_identifier('group')
76
- "party_relationships ON party_id_to = #{self.party.id} AND party_id_from = parties.id AND role_type_id_to=#{role_type.id}"
77
- end
78
-
79
81
  def members
80
- Party.joins("JOIN #{join_party_relationships}")
82
+ Party.joins("JOIN #{group_member_join}")
81
83
  end
82
-
84
+
83
85
  # get users in this group
84
86
  def users
85
- User.joins(:party).joins("JOIN #{join_party_relationships}")
87
+ User.joins(:party).joins("JOIN #{group_member_join}")
86
88
  end
87
89
 
88
90
  # get users not in this group
89
91
  def users_not
90
- User.joins(:party).joins("LEFT JOIN #{join_party_relationships}").where("party_relationships.id IS NULL")
92
+ User.joins(:party).joins("LEFT JOIN #{group_member_join}").where("party_relationships.id IS NULL")
91
93
  end
92
94
 
93
95
  # add user to group
@@ -112,7 +114,7 @@ class Group < ActiveRecord::Base
112
114
  rel = get_relationship(a_party).first
113
115
  unless rel.nil?
114
116
  # if so, return relationship
115
- return rel
117
+ return rel
116
118
  else
117
119
  # if not then build party_relationship
118
120
  rt = RelationshipType.find_by_internal_identifier('group_membership')
@@ -141,20 +143,20 @@ class Group < ActiveRecord::Base
141
143
 
142
144
  def role_class_capabilities
143
145
  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)
146
+ Capability.includes(:capability_type).joins(:capability_type).joins(:capability_accessors).
147
+ where(:capability_accessors => { :capability_accessor_record_type => "SecurityRole" }).
148
+ where("capability_accessor_record_id IN (#{roles.select('security_roles.id').to_sql})").
149
+ where(:scope_type_id => scope_type.id)
148
150
  end
149
151
 
150
152
  def all_class_capabilities
151
153
  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.includes(:capability_type).joins(:capability_type).joins(:capability_accessors).
155
+ where("(capability_accessors.capability_accessor_record_type = 'Group' AND
154
156
  capability_accessor_record_id = (#{self.id})) OR
155
157
  (capability_accessors.capability_accessor_record_type = 'SecurityRole' AND
156
158
  capability_accessor_record_id IN (#{roles.select('security_roles.id').to_sql}))").
157
- where(:scope_type_id => scope_type.id)
159
+ where(:scope_type_id => scope_type.id)
158
160
  end
159
161
 
160
162
  def all_uniq_class_capabilities
@@ -162,11 +164,22 @@ class Group < ActiveRecord::Base
162
164
  end
163
165
 
164
166
  def class_capabilities_to_hash
165
- all_uniq_class_capabilities.map {|capability|
166
- { :capability_type_iid => capability.capability_type.internal_identifier,
167
- :capability_resource_type => capability.capability_resource_type
168
- }
167
+ all_uniq_class_capabilities.map {|capability|
168
+ { :capability_type_iid => capability.capability_type.description,
169
+ :capability_resource_type => capability.capability_resource_type
170
+ }
169
171
  }.compact
170
172
  end
171
173
 
174
+ def to_data_hash
175
+ self.to_hash(only: [:id, :description, :created_at, :updated_at])
176
+ end
177
+
178
+ protected
179
+
180
+ def group_member_join
181
+ role_type = RoleType.find_by_internal_identifier('group_member')
182
+ "party_relationships ON party_id_from = #{self.party.id} AND party_id_to = parties.id AND role_type_id_from=#{role_type.id}"
183
+ end
184
+
172
185
  end