troles 0.5.0 → 0.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. data/Gemfile.lock +1 -1
  2. data/README.textile +75 -16
  3. data/VERSION +1 -1
  4. data/lib/trole/adapters/active_record/config.rb +3 -3
  5. data/lib/trole/adapters/mongoid/config.rb +5 -5
  6. data/lib/trole/config.rb +2 -2
  7. data/lib/trole_groups.rb +10 -0
  8. data/lib/trole_groups/READ THIS.textile +4 -0
  9. data/lib/trole_groups/Rolegroups design.textile +218 -0
  10. data/lib/trole_groups/adapters/active_record.rb +8 -0
  11. data/lib/trole_groups/adapters/active_record/config.rb +0 -0
  12. data/lib/trole_groups/adapters/active_record/storage.rb +0 -0
  13. data/lib/trole_groups/adapters/active_record/strategy.rb +11 -0
  14. data/lib/trole_groups/adapters/mongoid.rb +8 -0
  15. data/lib/trole_groups/adapters/mongoid/config.rb +0 -0
  16. data/lib/trole_groups/api.rb +29 -0
  17. data/lib/trole_groups/api/cache.rb +13 -0
  18. data/lib/trole_groups/api/config.rb +4 -0
  19. data/lib/trole_groups/api/core.rb +50 -0
  20. data/lib/trole_groups/api/event.rb +29 -0
  21. data/lib/trole_groups/api/read.rb +56 -0
  22. data/lib/trole_groups/api/validation.rb +44 -0
  23. data/lib/trole_groups/api/write.rb +60 -0
  24. data/lib/trole_groups/config.rb +134 -0
  25. data/lib/trole_groups/config/schema.rb +65 -0
  26. data/lib/trole_groups/config/schema/helpers.rb +11 -0
  27. data/lib/trole_groups/config/schema/role_group_helpers.rb +11 -0
  28. data/lib/trole_groups/config/valid_role_groups.rb +21 -0
  29. data/lib/trole_groups/macros.rb +42 -0
  30. data/lib/trole_groups/macros/configuration.rb +89 -0
  31. data/lib/trole_groups/macros/configuration/base_loader.rb +35 -0
  32. data/lib/trole_groups/macros/configuration/config_loader.rb +19 -0
  33. data/lib/trole_groups/macros/configuration/storage_loader.rb +20 -0
  34. data/lib/trole_groups/macros/configuration/strategy_loader.rb +38 -0
  35. data/lib/trole_groups/macros/static_roles.rb +9 -0
  36. data/lib/trole_groups/macros/strategy_options.rb +21 -0
  37. data/lib/trole_groups/operations.rb +25 -0
  38. data/lib/trole_groups/operations/read.rb +36 -0
  39. data/lib/trole_groups/operations/write.rb +42 -0
  40. data/lib/trole_groups/storage.rb +27 -0
  41. data/lib/trole_groups/storage/base_many.rb +93 -0
  42. data/lib/trole_groups/storage/embed_many.rb +58 -0
  43. data/lib/trole_groups/storage/ref_many.rb +47 -0
  44. data/lib/trole_groups/strategy.rb +30 -0
  45. data/lib/troles/adapters/active_record/config.rb +32 -9
  46. data/lib/troles/adapters/mongoid/config.rb +7 -7
  47. data/lib/troles/common/api/core.rb +1 -1
  48. data/lib/troles/common/config.rb +49 -14
  49. data/lib/troles/common/config/schema.rb +17 -23
  50. data/lib/troles/common/config/schema/helpers.rb +77 -0
  51. data/lib/troles/common/config/schema/role_helpers.rb +27 -0
  52. data/lib/troles/common/config/static_roles.rb +4 -4
  53. data/lib/troles/common/macros.rb +4 -4
  54. data/lib/troles/common/macros/configuration.rb +8 -8
  55. data/lib/troles/common/macros/strategy_options.rb +4 -4
  56. data/lib/troles/common/storage.rb +1 -0
  57. data/lib/troles/config.rb +2 -2
  58. data/lib/troles/storage/ref_many.rb +2 -3
  59. data/spec/active_record/models/ref_many.rb +3 -0
  60. data/spec/active_record/strategies/many/ref_many_spec.rb +2 -1
  61. data/spec/generic/models/role.rb +2 -1
  62. data/spec/trole_groups/api/core_api_spec.rb +14 -0
  63. data/spec/trole_groups/api/read_api_spec.rb +36 -0
  64. data/spec/trole_groups/api/write_api_spec.rb +19 -0
  65. data/spec/trole_groups/api_spec.rb +27 -0
  66. data/spec/trole_groups/generic/models.rb +3 -0
  67. data/spec/trole_groups/generic/models/role_group.rb +44 -0
  68. data/spec/trole_groups/generic/models/user.rb +9 -0
  69. data/spec/trole_groups/strategies/ref_many.rb +51 -0
  70. data/spec/trole_groups/strategy_helper.rb +9 -0
  71. data/spec/trole_groups_spec.rb +11 -0
  72. data/spec/trole_spec_helper.rb +9 -0
  73. data/spec/troles/api_spec.rb +12 -18
  74. data/troles.gemspec +52 -4
  75. metadata +85 -37
  76. data/development.sqlite3 +0 -0
  77. data/lib/troles/common/config/schema_helpers.rb +0 -95
@@ -0,0 +1,8 @@
1
+ module TroleGroups
2
+ module ActiveRecord
3
+ autoload :Config, 'trole_groups/adapters/active_record/config'
4
+ # autoload :Api, 'trole_groups/adapters/active_record/api'
5
+ autoload :Storage, 'trole_groups/adapters/active_record/storage'
6
+ autoload :Strategy, 'trole_groups/adapters/active_record/strategy'
7
+ end
8
+ end
File without changes
@@ -0,0 +1,11 @@
1
+ module TroleGroups::ActiveRecord
2
+ module Strategy
3
+ module BaseMany
4
+ # @param [Class] the role subject class for which to include the Role strategy (fx User Account)
5
+ #
6
+ def self.included(base)
7
+ base.send :include, TroleGroups::Strategy::BaseMany
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module TroleGroups
2
+ module Mongoid
3
+ autoload :Config, 'trole_groups/adapters/mongoid/config'
4
+ # autoload :Api, 'trole_groups/adapters/mongoid/api'
5
+ # autoload :Storage, 'trole_groups/adapters/mongoid/storage'
6
+ # autoload :Strategy, 'trole_groups/adapters/mongoid/strategy'
7
+ end
8
+ end
File without changes
@@ -0,0 +1,29 @@
1
+ module TroleGroups
2
+ module Api
3
+ autoload :Core, 'trole_groups/api/core'
4
+ autoload :Cache, 'trole_groups/api/cache'
5
+ autoload :Config, 'trole_groups/api/config'
6
+ autoload :Event, 'trole_groups/api/event'
7
+ autoload :Read, 'trole_groups/api/read'
8
+ autoload :Write, 'trole_groups/api/write'
9
+ autoload :Validation, 'trole_groups/api/validation'
10
+
11
+
12
+ module ClassMethods
13
+ def apis
14
+ [:core, :cache, :config, :event, :read, :validation, :write]
15
+ end
16
+
17
+ def included(base)
18
+ apis.each do |api|
19
+ begin
20
+ base.include_and_extend :"#{api.to_s.camelize}"
21
+ rescue
22
+ puts "include error: #{api}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ extend ClassMethods
28
+ end
29
+ end
@@ -0,0 +1,13 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Caching Api to ensure the rolegroup list of a rolegroup subject is cached and invalidated on rolegroup change
5
+ #
6
+ module TroleGroups::Api
7
+ module Cache
8
+ def invalidate_rolegroups_cache!
9
+ @rolegroup_list = nil
10
+ invalidate_role_cache!
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,4 @@
1
+ module TroleGroups::Api
2
+ module Config
3
+ end
4
+ end
@@ -0,0 +1,50 @@
1
+ module TroleGroups::Api
2
+ module Core
3
+ # Access to the Troles operations API
4
+ # @return [Troles::Operations] the operations API object
5
+ def rolegroups
6
+ @rolegroups ||= TroleGroups::Operations.new(self)
7
+ end
8
+
9
+ # Sets the roles of the subject
10
+ # (see #set_roles)
11
+ def rolegroups= *new_rolegroups
12
+ rolegroups.set_rolegroups new_rolegroups
13
+ end
14
+
15
+ # If this role subject instance should have static (immutable) roles
16
+ # @return [true, false] defaults to false so a role subject is allowed to change roles
17
+ def static_roles?
18
+ false
19
+ end
20
+
21
+ def trolegroups_config
22
+ self.class.trolegroups_config
23
+ end
24
+
25
+ module ClassMethods
26
+
27
+ def rolegroup_field
28
+ trolegroups_config.rolegroup_field
29
+ end
30
+
31
+ def valid_rolegroups
32
+ trolegroups_config.valid_roles
33
+ end
34
+
35
+ # # TODO: make sure alphanumeric only
36
+ # def valid_roles= *roles
37
+ # troles_config.valid_roles = *roles
38
+ # end
39
+
40
+ # If all role subjects using this strategy should have static (immutable) roles
41
+ #
42
+ # @note Should also proxy Config object?
43
+ #
44
+ # @return [true, false] if role subjects have static roles or not (default: false)
45
+ def static_roles?
46
+ false # trolegroups_config.static_roles?
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,29 @@
1
+ module TroleGroups::Api
2
+ module Event
3
+ # a change to the roles of the user should be published to an event handler
4
+ # this can be used to update both the Role cache of the user and fx the RolePermit cache.
5
+ # Both (and potentially others, fx for Role Groups) can subscribe to this event!
6
+ def update_role_groups
7
+ publish_change(:role_groups) if field_changed?(rolegroups_field)
8
+ end
9
+
10
+ # check if a field on the model changed
11
+ # See http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
12
+ def field_changed? name
13
+ send :"#{name}_changed?"
14
+ end
15
+
16
+ # can be customized
17
+ # here uses singleton EventManager
18
+ def publish_change event
19
+ send :invalidate_rolegroups_cache! if event == :role_groups
20
+ event_manager.publish_change event, :from => self
21
+ end
22
+
23
+ protected
24
+
25
+ def event_manager
26
+ Troles::Common::EventManager
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,56 @@
1
+ module TroleGroups::Api
2
+ module Read
3
+ def roles_from_rolegroups
4
+ group_store.display_roles
5
+ end
6
+
7
+ def roles_for *names
8
+ group_store.display_roles_for *names
9
+ end
10
+
11
+ # any? on rolegroups_list
12
+ def in_rolegroup? rolegroup
13
+ rolegroup_list.include? rolegroup.to_sym
14
+ end
15
+ alias_method :has_rolegroup?, :in_rolegroup?
16
+
17
+ # rolegroup_list has one element which is rolegroup
18
+ def only_in_rolegroup? rolegroup
19
+ rolegroup_list.first == rolegroup.to_sym && rolegroup_list.size == 1
20
+ end
21
+
22
+ # subtraction of role_groups from rolegroups_list is empty
23
+ def in_rolegroups? *rolegroups
24
+ (rolegroups.to_symbols - rolegroup_list).empty?
25
+ end
26
+ alias_method :has_rolegroups?, :in_rolegroups?
27
+
28
+ # union of rolegroups and rolegroups_list is not empty
29
+ def in_any_rolegroup? *rolegroups
30
+ !(rolegroup_list & rolegroups.to_symbols).empty?
31
+ end
32
+ alias_method :has_any_rolegroup?, :in_any_rolegroup?
33
+
34
+ # return roles of that rolegroup
35
+ def roles_of rolegroup
36
+ raise "Pending"
37
+ end
38
+
39
+ # return Set of symbols,where each symbol is a rolegroup name
40
+ # This set should be cached and only invalidated when the user has a change of roles
41
+ def rolegroup_list
42
+ @rolegroup_list ||= begin
43
+ group_store.display_rolegroups
44
+ end
45
+ end
46
+
47
+ # Ensures that the common API methods always have a common underlying model to work on
48
+ # @note This Set should be cached and only invalidated when the user has a change of roles
49
+ # @return Array<Symbol> Set of role names
50
+ def role_list
51
+ @role_list ||= begin
52
+ (store.display_roles | group_store.display_roles)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Common Validation API
5
+ #
6
+ module TroleGroups::Api
7
+ module Validation
8
+
9
+ # @return [Symbol, false] returns the role if it's valid, false if not
10
+ def check_valid_rolegroup? rolegroup
11
+ return rolegroup if valid_rolegroups.include? rolegroup.to_sym
12
+ false
13
+ end
14
+
15
+ # @return [Array<Symbol>] returns the valid roles or empty list if no valid roles
16
+ def check_valid_rolegroups? *rolegroups
17
+ valid_rolegroups & rolegroups.to_symbols
18
+ end
19
+
20
+ protected
21
+
22
+ # Ensures the role is valid
23
+ # @param [Symbol] role name
24
+ # @return [Symbol, false, Error] a valid role name, false if invalid, or Error on some error
25
+ def make_valid_rolegroup rolegroup
26
+ raise ArgumentError, "Rolegroup to set must be a Symbol or String" if !rolegroup.kind_of_label?
27
+ check_valid_rolegroup? rolegroup.to_s.alpha_numeric
28
+ end
29
+
30
+ # Ensures the role are valid
31
+ # @param [Symbol] list of roles
32
+ # @return [Array<Symbol>] the valid roles from the list of roles given
33
+ def make_valid_rolegroups *rolegroups
34
+ rolegroups = rolegroups.to_symbols_uniq
35
+ return [] if rolegroups.empty?
36
+ check_valid_rolegroups? rolegroups.map{|r| r.to_s.alpha_numeric}
37
+ end
38
+
39
+ # @return [Array<Symbol>] the valid roles of the role subject
40
+ def valid_rolegroups
41
+ self.class.trolegroups_config.valid_rolegroups
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,60 @@
1
+ module TroleGroups::Api
2
+ module Write
3
+ # Add a single new rolegroup to the rolegroups of the subject
4
+ # @param [Symbol] rolegroup to add
5
+ # @return (see #add_rolegroups)
6
+ def add_rolegroup rolegroup_name
7
+ raise ArgumentError, "Take a single rolegroup name, was: #{rolegroup_name}" if !rolegroup_name || !rolegroup_name.kind_of_label?
8
+ add_rolegroups rolegroup_name
9
+ end
10
+
11
+ # Remove a single rolegroup from the rolegroups of the subject
12
+ # @param [Symbol] rolegroup to remove
13
+ # @return (see #remove_rolegroups)
14
+ def remove_rolegroup rolegroup_name
15
+ raise ArgumentError, "Take a single rolegroup name, was: #{rolegroup_name}" if !rolegroup_name || !rolegroup_name.kind_of_label?
16
+ remove_rolegroups rolegroup_name
17
+ end
18
+
19
+ # Adds a set of new rolegroups to the rolegroups of the subject
20
+ # @param [Array<Symbol>] list of rolegroups to add
21
+ # @return [true, false, Error] true if ok, false if static or invalid, Error on some error
22
+ def add_rolegroups *new_rolegroups
23
+ group_store.set_rolegroups (rolegroup_list | new_rolegroups.to_symbols_uniq) # Set Union (joined set)
24
+ end
25
+
26
+ # Removes a set of new rolegroups to the rolegroups of the subject
27
+ # (see #add_rolegroups)
28
+ def remove_rolegroups *the_rolegroups
29
+ group_store.set_rolegroups (rolegroup_list - the_rolegroups.to_symbols_uniq)
30
+ end
31
+
32
+ # Sets new rolegroups for the subject
33
+ # @param [Array<Symbol>] list of rolegroup names
34
+ # @return [true, false, Error] true if set ok, false if any rolegroups were invalid, Error on some error
35
+ def set_rolegroups *rolegroups
36
+ rolegroups_to_set = make_valid_rolegroups(*rolegroups).flat_uniq
37
+ return false if !rolegroups_to_set || rolegroups_to_set.empty?
38
+ group_store.set_rolegroups(rolegroups_to_set)
39
+ end
40
+
41
+ # Clears all the rolegroups of the subject
42
+ # @return [true, false, Error] true if ok, false if rolegroups are static, Error on some error
43
+ def clear_rolegroups!
44
+ group_store.clear!
45
+ end
46
+
47
+ module ClassMethods
48
+ # Sets which rolegroups are valid for the rolegroup subject class (fx User or UserAccount)
49
+ #
50
+ # @note this in effect limits what rolegroups can be assigned to any instance of the class
51
+ #
52
+ # @param [Array<Symbol>] list of rolegroup names
53
+ def set_valid_rolegroups *rolegroups
54
+ rolegroups = rolegroups.to_symbols_uniq
55
+ raise ArgumentError, "Roles must contain Symbols or Strings" if rolegroups.empty?
56
+ @valid_rolegroups = rolegroups
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,134 @@
1
+ module TroleGroups
2
+ class Config
3
+ autoload :ValidRoleGroups, 'trole_groups/config/valid_role_groups'
4
+ autoload :Schema, 'trole_groups/config/schema'
5
+
6
+ def self.sub_modules
7
+ [:valid_role_groups, :schema] # , :static_roles, ,
8
+ end
9
+
10
+ sub_modules.each do |name|
11
+ begin
12
+ self.send :include, "TroleGroups::Config::#{name.to_s.camelize}".constantize
13
+ rescue Error => e
14
+ puts "include sub-module #{name}, error: #{e}"
15
+ end
16
+ end
17
+
18
+ attr_accessor :subject_class, :strategy, :log_on, :generic, :auto_relations
19
+ attr_writer :orm
20
+
21
+ def initialize subject_class, options = {}
22
+ @subject_class = subject_class
23
+ # set instance var for each pair in options
24
+ apply_options! options
25
+ end
26
+
27
+ def apply_options! options = {}
28
+ options.each_pair do |key, value|
29
+ send("#{key}=", value) if self.respond_to?(:"#{key}")
30
+ end
31
+ end
32
+
33
+ def configure! options = {}
34
+ apply_options! options
35
+ configure_models if auto_config?(:models)
36
+ end
37
+
38
+ class << self
39
+ attr_reader :default_orm, :auto_load
40
+ attr_accessor :log_on
41
+
42
+ def log_on?
43
+ log_on || false
44
+ end
45
+
46
+ def default_orm= orm
47
+ @default_orm ||= orm
48
+ end
49
+
50
+ def auto_load= mode
51
+ raise "Autoload must be set to true or false" if ![true, false].include? mode
52
+ @auto_load = mode
53
+ end
54
+
55
+ def auto_load?
56
+ @auto_load
57
+ end
58
+
59
+ def auto_config
60
+ auto_config_setings
61
+ end
62
+
63
+ def auto_config? name
64
+ auto_config_setings[name]
65
+ end
66
+
67
+ protected
68
+
69
+
70
+ def auto_config_setings
71
+ @auto_config_setings ||= auto_config_defaults
72
+ end
73
+
74
+ # default auto_config settings
75
+ def auto_config_defaults
76
+ {:models => true, :relations => true, :fields => true}
77
+ end
78
+ end
79
+
80
+ def log_on?
81
+ log_on || Troles::Config.log_on
82
+ end
83
+
84
+ def auto_config
85
+ auto_config_setings
86
+ end
87
+
88
+ def auto_config? name
89
+ return auto_config_setings[name] if !auto_config_setings[name].nil?
90
+ Troles::Config.auto_config?(name)
91
+ end
92
+
93
+
94
+ def auto_config_setings
95
+ @auto_config_setings ||= {}
96
+ end
97
+
98
+ def role_field
99
+ @role_field ||= begin
100
+ default_role_field
101
+ end
102
+ end
103
+ alias_method :rolegroup_field, :role_field
104
+
105
+ def role_field= field_name
106
+ name = field_name.to_s.alpha_numeric.to_sym
107
+ raise ArgumentException, "Not a valid role field name: #{field_name}" if !valid_field_name?(name)
108
+ @role_field ||= name
109
+ end
110
+ alias_method :rolegroup_field=, :role_field=
111
+
112
+ def default_role_field
113
+ :trole_groups
114
+ end
115
+
116
+ def orm
117
+ @orm || self.class.default_orm
118
+ end
119
+
120
+ def singularity
121
+ @singularity ||= (strategy =~ /_many$/) ? :many : :one
122
+ end
123
+
124
+ # def singularity= value
125
+ # raise ArgumentError, "Must be :many or :one" if ![:one, :many].include?(value)
126
+ # @singularity ||= value
127
+ # end
128
+
129
+ def generic?
130
+ return true if orm.nil?
131
+ @generic.nil? ? false : @generic
132
+ end
133
+ end
134
+ end