troles 0.5.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 (243) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +26 -0
  3. data/Gemfile.lock +161 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.textile +686 -0
  6. data/Rakefile +48 -0
  7. data/VERSION +1 -0
  8. data/config/database.yml +4 -0
  9. data/development.sqlite3 +0 -0
  10. data/lib/trole/adapters/active_record/config.rb +23 -0
  11. data/lib/trole/adapters/active_record/storage.rb +0 -0
  12. data/lib/trole/adapters/active_record/strategy.rb +0 -0
  13. data/lib/trole/adapters/active_record.rb +8 -0
  14. data/lib/trole/adapters/mongoid/config.rb +34 -0
  15. data/lib/trole/adapters/mongoid/storage.rb +0 -0
  16. data/lib/trole/adapters/mongoid/strategy.rb +0 -0
  17. data/lib/trole/adapters/mongoid.rb +0 -0
  18. data/lib/trole/api/cache.rb +9 -0
  19. data/lib/trole/api/config.rb +12 -0
  20. data/lib/trole/api/core.rb +20 -0
  21. data/lib/trole/api/event.rb +9 -0
  22. data/lib/trole/api/read.rb +14 -0
  23. data/lib/trole/api/validation.rb +9 -0
  24. data/lib/trole/api/write.rb +25 -0
  25. data/lib/trole/api.rb +41 -0
  26. data/lib/trole/config.rb +15 -0
  27. data/lib/trole/macros.rb +5 -0
  28. data/lib/trole/operations/read.rb +12 -0
  29. data/lib/trole/operations/write.rb +11 -0
  30. data/lib/trole/operations.rb +34 -0
  31. data/lib/trole/storage/base_one.rb +46 -0
  32. data/lib/trole/storage/bit_one.rb +43 -0
  33. data/lib/trole/storage/embed_one.rb +36 -0
  34. data/lib/trole/storage/ref_one.rb +39 -0
  35. data/lib/trole/storage/string_one.rb +50 -0
  36. data/lib/trole/storage.rb +14 -0
  37. data/lib/trole/strategy.rb +35 -0
  38. data/lib/trole.rb +10 -0
  39. data/lib/troles/adapters/active_record/Design Notes.textile +4 -0
  40. data/lib/troles/adapters/active_record/config.rb +51 -0
  41. data/lib/troles/adapters/active_record/storage/embed_many.rb +8 -0
  42. data/lib/troles/adapters/active_record/storage.rb +5 -0
  43. data/lib/troles/adapters/active_record/strategy.rb +11 -0
  44. data/lib/troles/adapters/active_record.rb +8 -0
  45. data/lib/troles/adapters/mongoid/Design Notes.textile +3 -0
  46. data/lib/troles/adapters/mongoid/config.rb +45 -0
  47. data/lib/troles/adapters/mongoid.rb +8 -0
  48. data/lib/troles/api/cache.rb +4 -0
  49. data/lib/troles/api/config.rb +9 -0
  50. data/lib/troles/api/core.rb +9 -0
  51. data/lib/troles/api/event.rb +4 -0
  52. data/lib/troles/api/read.rb +4 -0
  53. data/lib/troles/api/validation.rb +4 -0
  54. data/lib/troles/api/write.rb +4 -0
  55. data/lib/troles/api.rb +40 -0
  56. data/lib/troles/common/api/cache.rb +12 -0
  57. data/lib/troles/common/api/config.rb +4 -0
  58. data/lib/troles/common/api/core.rb +52 -0
  59. data/lib/troles/common/api/event.rb +39 -0
  60. data/lib/troles/common/api/read.rb +44 -0
  61. data/lib/troles/common/api/validation.rb +44 -0
  62. data/lib/troles/common/api/write.rb +76 -0
  63. data/lib/troles/common/api.rb +28 -0
  64. data/lib/troles/common/config/schema.rb +72 -0
  65. data/lib/troles/common/config/schema_helpers.rb +95 -0
  66. data/lib/troles/common/config/static_roles.rb +14 -0
  67. data/lib/troles/common/config/valid_roles.rb +21 -0
  68. data/lib/troles/common/config.rb +96 -0
  69. data/lib/troles/common/dependencies.rb +9 -0
  70. data/lib/troles/common/event_manager.rb +40 -0
  71. data/lib/troles/common/macros/configuration/base_loader.rb +40 -0
  72. data/lib/troles/common/macros/configuration/config_loader.rb +19 -0
  73. data/lib/troles/common/macros/configuration/storage_loader.rb +20 -0
  74. data/lib/troles/common/macros/configuration/strategy_loader.rb +38 -0
  75. data/lib/troles/common/macros/configuration.rb +89 -0
  76. data/lib/troles/common/macros/static_roles.rb +9 -0
  77. data/lib/troles/common/macros/strategy_options.rb +21 -0
  78. data/lib/troles/common/macros.rb +38 -0
  79. data/lib/troles/common/marshaller/bitmask.rb +43 -0
  80. data/lib/troles/common/marshaller/generic.rb +24 -0
  81. data/lib/troles/common/marshaller.rb +14 -0
  82. data/lib/troles/common/operations/read.rb +28 -0
  83. data/lib/troles/common/operations/write.rb +42 -0
  84. data/lib/troles/common/operations.rb +33 -0
  85. data/lib/troles/common/storage.rb +73 -0
  86. data/lib/troles/common.rb +17 -0
  87. data/lib/troles/config.rb +15 -0
  88. data/lib/troles/macros.rb +7 -0
  89. data/lib/troles/meta.rb +5 -0
  90. data/lib/troles/operations/read.rb +6 -0
  91. data/lib/troles/operations/write.rb +6 -0
  92. data/lib/troles/operations.rb +12 -0
  93. data/lib/troles/storage/base_many.rb +25 -0
  94. data/lib/troles/storage/bit_many.rb +56 -0
  95. data/lib/troles/storage/embed_many.rb +58 -0
  96. data/lib/troles/storage/ref_many.rb +44 -0
  97. data/lib/troles/storage/string_many.rb +41 -0
  98. data/lib/troles/storage.rb +13 -0
  99. data/lib/troles/strategy.rb +34 -0
  100. data/lib/troles.rb +11 -0
  101. data/playbox/old_rake +25 -0
  102. data/spec/Guide to running specs.textile +16 -0
  103. data/spec/active_record/migrations/many/bit_many.rb +16 -0
  104. data/spec/active_record/migrations/many/ref_many.rb +31 -0
  105. data/spec/active_record/migrations/many/string_many.rb +16 -0
  106. data/spec/active_record/migrations/one/bit_one.rb +14 -0
  107. data/spec/active_record/migrations/one/ref_one.rb +20 -0
  108. data/spec/active_record/migrations/one/string_one.rb +14 -0
  109. data/spec/active_record/models/ref_many.rb +10 -0
  110. data/spec/active_record/models/ref_one.rb +10 -0
  111. data/spec/active_record/models/role.rb +2 -0
  112. data/spec/active_record/models/user.rb +5 -0
  113. data/spec/active_record/models.rb +2 -0
  114. data/spec/active_record/strategies/many/bit_many_spec.rb +41 -0
  115. data/spec/active_record/strategies/many/ref_many_spec.rb +45 -0
  116. data/spec/active_record/strategies/many/string_many_spec.rb +39 -0
  117. data/spec/active_record/strategies/one/bit_one_spec.rb +35 -0
  118. data/spec/active_record/strategies/one/ref_one_spec.rb +41 -0
  119. data/spec/active_record/strategies/one/string_one_spec.rb +35 -0
  120. data/spec/active_record/strategy_helper.rb +4 -0
  121. data/spec/active_record_helper.rb +50 -0
  122. data/spec/db/database.yml +4 -0
  123. data/spec/dummy/Gemfile.lock +108 -0
  124. data/spec/dummy/Rakefile +7 -0
  125. data/spec/dummy/app/assets/images/rails.png +0 -0
  126. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  127. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  128. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  129. data/spec/dummy/app/controllers/main_controller.rb +16 -0
  130. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  131. data/spec/dummy/app/mailers/.gitkeep +0 -0
  132. data/spec/dummy/app/models/.gitkeep +0 -0
  133. data/spec/dummy/app/models/ref_many_user.rb +7 -0
  134. data/spec/dummy/app/models/ref_one_user.rb +3 -0
  135. data/spec/dummy/app/models/role.rb +4 -0
  136. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  137. data/spec/dummy/app/views/main/index.html.erb +3 -0
  138. data/spec/dummy/config/application.rb +54 -0
  139. data/spec/dummy/config/boot.rb +10 -0
  140. data/spec/dummy/config/database.yml +25 -0
  141. data/spec/dummy/config/environment.rb +5 -0
  142. data/spec/dummy/config/environments/development.rb +24 -0
  143. data/spec/dummy/config/environments/production.rb +52 -0
  144. data/spec/dummy/config/environments/test.rb +39 -0
  145. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  146. data/spec/dummy/config/initializers/inflections.rb +10 -0
  147. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  148. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  149. data/spec/dummy/config/initializers/session_store.rb +8 -0
  150. data/spec/dummy/config/initializers/troles.rb +3 -0
  151. data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
  152. data/spec/dummy/config/locales/en.yml +5 -0
  153. data/spec/dummy/config/routes.rb +60 -0
  154. data/spec/dummy/config.ru +4 -0
  155. data/spec/dummy/db/migrate/01_create_roles.rb +14 -0
  156. data/spec/dummy/db/migrate/02_create_ref_many_users.rb +20 -0
  157. data/spec/dummy/db/schema.rb +32 -0
  158. data/spec/dummy/db/seeds.rb +4 -0
  159. data/spec/dummy/log/.gitkeep +0 -0
  160. data/spec/dummy/public/404.html +26 -0
  161. data/spec/dummy/public/422.html +26 -0
  162. data/spec/dummy/public/500.html +26 -0
  163. data/spec/dummy/public/favicon.ico +0 -0
  164. data/spec/dummy/script/rails +6 -0
  165. data/spec/dummy_spec_helper.rb +33 -0
  166. data/spec/factories.rb +8 -0
  167. data/spec/generic/models/accounts/admin_account.rb +7 -0
  168. data/spec/generic/models/accounts/blogger_account.rb +7 -0
  169. data/spec/generic/models/accounts/user_account.rb +7 -0
  170. data/spec/generic/models/accounts.rb +1 -0
  171. data/spec/generic/models/base_user.rb +27 -0
  172. data/spec/generic/models/role.rb +37 -0
  173. data/spec/generic/models/user.rb +7 -0
  174. data/spec/generic/models.rb +3 -0
  175. data/spec/integration/navigation_spec.rb +9 -0
  176. data/spec/integration/troles/Running dummy tests.textile +35 -0
  177. data/spec/integration/troles/navigation_spec.rb +49 -0
  178. data/spec/mongoid/models/ref_many.rb +15 -0
  179. data/spec/mongoid/models/ref_one.rb +15 -0
  180. data/spec/mongoid/models/role.rb +5 -0
  181. data/spec/mongoid/models/user.rb +9 -0
  182. data/spec/mongoid/models.rb +2 -0
  183. data/spec/mongoid/strategies/many/bit_many_spec.rb +35 -0
  184. data/spec/mongoid/strategies/many/ref_many_spec.rb +35 -0
  185. data/spec/mongoid/strategies/many/string_many_spec.rb +30 -0
  186. data/spec/mongoid/strategies/one/bit_one_spec.rb +26 -0
  187. data/spec/mongoid/strategies/one/ref_one_spec.rb +31 -0
  188. data/spec/mongoid/strategies/one/string_one_spec.rb +26 -0
  189. data/spec/mongoid/strategy_helper.rb +4 -0
  190. data/spec/mongoid_helper.rb +19 -0
  191. data/spec/playbox/rspec_examples.rb +381 -0
  192. data/spec/support/shared_examples.rb +1 -0
  193. data/spec/trole/Trole Design.textile +4 -0
  194. data/spec/trole/api/cache_api_spec.rb +2 -0
  195. data/spec/trole/api/core_api_spec.rb +4 -0
  196. data/spec/trole/api/event_api.rb +2 -0
  197. data/spec/trole/api/operations_api_spec.rb +2 -0
  198. data/spec/trole/api/read_api_spec.rb +5 -0
  199. data/spec/trole/api/validation_api_spec.rb +2 -0
  200. data/spec/trole/api/write_api_spec.rb +2 -0
  201. data/spec/trole/api_spec.rb +60 -0
  202. data/spec/trole/multi_roles_spec.rb +163 -0
  203. data/spec/trole/operations/read_spec.rb +18 -0
  204. data/spec/trole/operations/write_spec.rb +0 -0
  205. data/spec/trole/playbox/shared_examples.rb +107 -0
  206. data/spec/trole/strategies/bit_one_spec.rb +22 -0
  207. data/spec/trole/strategies/embed_one_spec.rb +32 -0
  208. data/spec/trole/strategies/ref_one_spec.rb +29 -0
  209. data/spec/trole/strategies/string_one_spec.rb +26 -0
  210. data/spec/trole/strategy_helper.rb +3 -0
  211. data/spec/trole/two_roles_spec.rb +76 -0
  212. data/spec/trole_spec.rb +12 -0
  213. data/spec/trole_spec_helper.rb +20 -0
  214. data/spec/troles/api/cache_api_spec.rb +2 -0
  215. data/spec/troles/api/core_api_spec.rb +4 -0
  216. data/spec/troles/api/event_api.rb +2 -0
  217. data/spec/troles/api/read_api_spec.rb +2 -0
  218. data/spec/troles/api/validation_api_spec.rb +2 -0
  219. data/spec/troles/api/write_api_spec.rb +2 -0
  220. data/spec/troles/api_spec.rb +41 -0
  221. data/spec/troles/common/api/cache_api_spec.rb +31 -0
  222. data/spec/troles/common/api/config_api.rb +0 -0
  223. data/spec/troles/common/api/core_api_spec.rb +14 -0
  224. data/spec/troles/common/api/event_api_spec.rb +9 -0
  225. data/spec/troles/common/api/operations_api_spec.rb +55 -0
  226. data/spec/troles/common/api/read_api_spec.rb +23 -0
  227. data/spec/troles/common/api/validation_api_spec.rb +46 -0
  228. data/spec/troles/common/api/write_api_spec.rb +81 -0
  229. data/spec/troles/common/api_spec.rb +101 -0
  230. data/spec/troles/common/config_spec.rb +11 -0
  231. data/spec/troles/common/multi_roles_spec.rb +142 -0
  232. data/spec/troles/marshaller/bitmask_spec.rb +14 -0
  233. data/spec/troles/operations/read_ops_spec.rb +0 -0
  234. data/spec/troles/operations/write_ops_spec.rb +0 -0
  235. data/spec/troles/playbox/shared_examples.rb +68 -0
  236. data/spec/troles/strategies/bit_many_spec.rb +30 -0
  237. data/spec/troles/strategies/embed_many_spec.rb +35 -0
  238. data/spec/troles/strategies/ref_many_spec.rb +36 -0
  239. data/spec/troles/strategies/string_many_spec.rb +32 -0
  240. data/spec/troles/strategy_helper.rb +3 -0
  241. data/spec/troles_spec.rb +10 -0
  242. data/troles.gemspec +325 -0
  243. metadata +469 -0
@@ -0,0 +1,51 @@
1
+ module Troles::ActiveRecord
2
+ class Config < Troles::Common::Config
3
+
4
+ attr_accessor :role_join_model
5
+
6
+ def initialize clazz, options = {}
7
+ super
8
+ end
9
+
10
+ def configure_relation
11
+ case strategy
12
+ when :ref_many
13
+ return configure_join_model if role_join_model
14
+ has_and_belongs_many clazz, role_model, :key => :accounts
15
+ when :embed_many
16
+ raise "Embed many configuration not yet implemented for ActiveRecord"
17
+ end
18
+ end
19
+
20
+ # AR sets this up ont its own using DB Table info
21
+ def configure_field
22
+ end
23
+
24
+ protected
25
+
26
+ def join_key
27
+ make_key role_join_model
28
+ end
29
+
30
+ def join_model
31
+ # UserAccount
32
+ # has_many :troles, :class_name => 'Role', :through => :users_roles
33
+ has_many_for clazz, role_model, :through => join_key
34
+ # has_many :user_roles, :class_name => 'UserRole'
35
+ has_many_for clazz, role_join_model, :key => join_key
36
+
37
+ # UserRole (custom join class name)
38
+ # belongs_to :user, :class_name => 'UserAccount'
39
+ belongs_to_for role_join_model, clazz
40
+ # belongs_to :role, :class_name => 'Role'
41
+ belongs_to_for role_join_model, role_model
42
+
43
+ # Role
44
+ # has_many :accounts, :class_name => 'User', :through => :user_roles
45
+ has_many_for role, clazz, :through => join_key, :key => :accounts
46
+
47
+ # has_many :user_roles, :class_name => 'UserRole'
48
+ has_many_for role, role_join_model, :key => join_key
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,8 @@
1
+ # Could use the AR serializer feature, to save the embedded roles as YAML
2
+ module Troles::ActiveRecord::Storage
3
+ class StringMany < Troles::Storage::StringMany
4
+ def initialize role_subject
5
+ super
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Troles::ActiveRecord
2
+ module Storage
3
+ autoload :EmbedMany, 'troles/adapters/active_record/strategy/embed_many'
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Troles::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, Troles::Strategy::BaseMany
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module Troles
2
+ module ActiveRecord
3
+ autoload :Config, 'troles/adapters/active_record/config'
4
+ # autoload :Api, 'troles/adapters/active_record/api'
5
+ autoload :Storage, 'troles/adapters/active_record/storage'
6
+ autoload :Strategy, 'troles/adapters/active_record/strategy'
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ h1. Design Notes for Mongoid adapter
2
+
3
+ We have to come up with an easier way to initialize the Config object than to do the whole API thing!
@@ -0,0 +1,45 @@
1
+ module Troles::Mongoid
2
+ class Config < Troles::Common::Config
3
+
4
+ def initialize clazz, options = {}
5
+ super
6
+ end
7
+
8
+ # more likely, strategy should be part of configuration options directly when Config object is created!
9
+ def configure_relation
10
+ case strategy
11
+ when :ref_many
12
+ has_many_for clazz, :role, :through => join_key
13
+
14
+ belongs_to_for join_model, :user
15
+ belongs_to_for join_model, :role
16
+
17
+ has_many_for role, :user, :through => join_key
18
+
19
+ when :embed_many
20
+ embeds_many clazz, :role
21
+ end
22
+ end
23
+
24
+ def configure_field
25
+ type = case strategy
26
+ when :bit_many
27
+ Integer
28
+ when :string_many
29
+ String
30
+ end
31
+ # field :name, :type => String
32
+ clazz.send(:field, role_field, type_opts(type)) if type
33
+ end
34
+
35
+ def type_opts type
36
+ { :type => type }
37
+ end
38
+
39
+ protected
40
+
41
+ def embeds_many from, to
42
+ make_relationship :embeds_many, from, to
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ module Troles
2
+ module Mongoid
3
+ autoload :Config, 'troles/adapters/mongoid/config'
4
+ # autoload :Api, 'troles/adapters/mongoid/api'
5
+ # autoload :Storage, 'troles/adapters/mongoid/storage'
6
+ # autoload :Strategy, 'troles/adapters/mongoid/strategy'
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ module Troles::Api
2
+ module Cache
3
+ end
4
+ end
@@ -0,0 +1,9 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Many roles Config Api
5
+ #
6
+ module Troles::Api
7
+ module Config
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Troles::Api
2
+ module Core
3
+ module ClassMethods
4
+ def role_field
5
+ troles_config.role_field
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,4 @@
1
+ module Troles::Api
2
+ module Event
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Troles::Api
2
+ module Read
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Troles::Api
2
+ module Validation
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Troles::Api
2
+ module Write
3
+ end
4
+ end
data/lib/troles/api.rb ADDED
@@ -0,0 +1,40 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Many roles Api to be included directly on the role subject class (fx User or User Account)
5
+ #
6
+ module Troles
7
+ module Api
8
+ autoload :Core, 'troles/api/core'
9
+ autoload :Config, 'troles/api/config'
10
+ autoload :Cache, 'troles/api/cache'
11
+
12
+ autoload :Event, 'troles/api/event'
13
+ autoload :Read, 'troles/api/read'
14
+ autoload :Store, 'troles/api/store'
15
+ autoload :Validation, 'troles/api/validation'
16
+ autoload :Write, 'troles/api/write'
17
+
18
+ module ClassMethods
19
+ #
20
+ # When the Troles::Api is included by the Role Subject class (fx a User Account)
21
+ # first include methods from Troles Common API
22
+ # then include Troles API on top
23
+ #
24
+ # @param [Class] the role subject class (fx User or UserAccount)
25
+ #
26
+ def included(base)
27
+ base.send :include, Troles::Common::Api
28
+ self.extend Troles::Common::Api::ClassMethods # draws in the #apis method from Common Api
29
+ apis.each do |api|
30
+ begin
31
+ base.send :include, "Troles::Api::#{api.to_s.camelize}".constantize
32
+ base.extend "Troles::Api::#{api.to_s.camelize}::ClassMethods".constantize
33
+ rescue
34
+ end
35
+ end
36
+ end
37
+ end
38
+ extend ClassMethods
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Caching Api to ensure the role list of a role subject is cached and invalidated on role change
5
+ #
6
+ module Troles::Common::Api
7
+ module Cache
8
+ def invalidate_role_cache!
9
+ @role_list = nil
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ module Troles::Common::Api
2
+ module Config
3
+ end
4
+ end
@@ -0,0 +1,52 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Core Troles API functions
5
+ #
6
+ module Troles::Common::Api
7
+ module Core
8
+
9
+ # Access to the Troles operations API
10
+ # @return [Troles::Operations] the operations API object
11
+ def roles
12
+ @roles ||= Troles::Operations.new(self)
13
+ end
14
+
15
+ # Sets the roles of the subject
16
+ # (see #set_roles)
17
+ def roles= *new_roles
18
+ roles.set_roles new_roles
19
+ end
20
+
21
+ # If this role subject instance should have static (immutable) roles
22
+ # @return [true, false] defaults to false so a role subject is allowed to change roles
23
+ def static_roles?
24
+ false
25
+ end
26
+
27
+ def troles_config
28
+ self.class.troles_config
29
+ end
30
+
31
+ module ClassMethods
32
+
33
+ def valid_roles
34
+ troles_config.valid_roles
35
+ end
36
+
37
+ # # TODO: make sure alphanumeric only
38
+ # def valid_roles= *roles
39
+ # troles_config.valid_roles = *roles
40
+ # end
41
+
42
+ # If all role subjects using this strategy should have static (immutable) roles
43
+ #
44
+ # @note Should also proxy Config object?
45
+ #
46
+ # @return [true, false] if role subjects have static roles or not (default: false)
47
+ def static_roles?
48
+ troles_config.static_roles_for_class?
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,39 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Event API
5
+ #
6
+ module Troles::Common::Api
7
+ module Event
8
+ # A change to the roles of the user should be published to an event handler
9
+ # this can be used to update both the Role cache of the user and fx the RolePermit cache.
10
+ # A Role Groups listener can also subscribe to this event
11
+ def update_roles
12
+ publish_change(:roles) if role_field_changed?(troles_config.role_field)
13
+ end
14
+
15
+ # Check if a field on the model changed
16
+ # For Rails 3, See http://api.rubyonrails.org/classes/ActiveModel/Dirty.html
17
+ # @param [String] the field to test for change
18
+ def role_field_changed? name
19
+ begin
20
+ send :"#{name}_changed?"
21
+ rescue
22
+ false
23
+ end
24
+ end
25
+
26
+ # Publishes change event to the EventManager configured
27
+ # The EventManager is notied of the even type and who (which instance) sent it
28
+ # @param [Symbol] the event
29
+ def publish_change event
30
+ send :invalidate_role_cache! if event == :roles
31
+ event_manager.publish_change event, :from => self
32
+ end
33
+
34
+ # @return [Trole::EventManager] The event manager singleton (class) to use to handle role events
35
+ def event_manager
36
+ Troles::Common::EventManager
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,44 @@
1
+ # @author Kristian Mandrup
2
+ #
3
+ # Common Read API
4
+ #
5
+ require 'set'
6
+
7
+ module Troles::Common::Api
8
+ module Read
9
+
10
+ # Ensures that the common API methods always have a common underlying model to work on
11
+ # @note This Set should be cached and only invalidated when the user has a change of roles
12
+ # @return Array<Symbol> Set of role names
13
+ def role_list
14
+ @role_list ||= begin
15
+ store.display_roles.flatten
16
+ end
17
+ end
18
+
19
+ # Does the role subject has the role or not?
20
+ # @return [true, false]
21
+ def has_role? role
22
+ role_list.include? role.to_sym
23
+ end
24
+
25
+ # Does the role subject have ONLY that role or not?
26
+ # @return [true, false]
27
+ def is_role? role
28
+ role_list.first == role.to_sym && role_list.size == 1
29
+ end
30
+
31
+ # Checks if the role subject has any of the listed roles
32
+ # @param [Array<Symbol>]
33
+ # @return [true, false]
34
+ def has_roles? *roles
35
+ (roles.to_symbols - role_list).empty?
36
+ end
37
+
38
+ # Checks if the role subject has any of the listed roles
39
+ # (see #has_roles?)
40
+ def has_any_role? *roles
41
+ !(role_list & roles.to_symbols).empty?
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ #
2
+ # @author Kristian Mandrup
3
+ #
4
+ # Common Validation API
5
+ #
6
+ module Troles::Common::Api
7
+ module Validation
8
+
9
+ # @return [Symbol, false] returns the role if it's valid, false if not
10
+ def check_valid_role? role
11
+ return role if valid_roles.include? role.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_roles? *roles
17
+ valid_roles & roles.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_role role
26
+ raise ArgumentError, "Role to set must be a Symbol or String" if !role.kind_of_label?
27
+ check_valid_role? role.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_roles *roles
34
+ roles = roles.to_symbols_uniq
35
+ return [] if roles.empty?
36
+ check_valid_roles? roles.map{|r| r.to_s.alpha_numeric}
37
+ end
38
+
39
+ # @return [Array<Symbol>] the valid roles of the role subject
40
+ def valid_roles
41
+ self.class.troles_config.valid_roles
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,76 @@
1
+ # @author Kristian Mandrup
2
+ #
3
+ # @note all methods should operate on the data store via the #store
4
+ #
5
+ module Troles::Common::Api
6
+ module Write
7
+
8
+ # Do we need a static_roles! method? I think so!
9
+ def static_role! role_name
10
+ raise ArgumentError, "Take a single role name, was: #{role_name}" if !role_name || !role_name.kind_of_label?
11
+ troles_config.add_valid_roles role_name
12
+ if set_roles role_name
13
+ define_method :static_roles? do
14
+ true
15
+ end
16
+ end
17
+ end
18
+
19
+ # Add a single new role to the roles of the subject
20
+ # @param [Symbol] role to add
21
+ # @return (see #add_roles)
22
+ def add_role role_name
23
+ raise ArgumentError, "Take a single role name, was: #{role_name}" if !role_name || !role_name.kind_of_label?
24
+ add_roles role_name
25
+ end
26
+
27
+ # Remove a single role from the roles of the subject
28
+ # @param [Symbol] role to remove
29
+ # @return (see #remove_roles)
30
+ def remove_role role_name
31
+ raise ArgumentError, "Take a single role name, was: #{role_name}" if !role_name || !role_name.kind_of_label?
32
+ remove_roles role_name
33
+ end
34
+
35
+ # Adds a set of new roles to the roles of the subject
36
+ # @param [Array<Symbol>] list of roles to add
37
+ # @return [true, false, Error] true if ok, false if static or invalid, Error on some error
38
+ def add_roles *new_roles
39
+ store.set_roles (role_list | new_roles.to_symbols_uniq) # Set Union (joined set)
40
+ end
41
+
42
+ # Removes a set of new roles to the roles of the subject
43
+ # (see #add_roles)
44
+ def remove_roles *the_roles
45
+ store.set_roles (role_list - the_roles.to_symbols_uniq)
46
+ end
47
+
48
+ # Sets new roles for the subject
49
+ # @param [Array<Symbol>] list of role names
50
+ # @return [true, false, Error] true if set ok, false if any roles were invalid, Error on some error
51
+ def set_roles *roles
52
+ roles_to_set = make_valid_roles(*roles).flat_uniq
53
+ return false if !roles_to_set || roles_to_set.empty?
54
+ store.set_roles(roles_to_set)
55
+ end
56
+
57
+ # Clears all the roles of the subject
58
+ # @return [true, false, Error] true if ok, false if roles are static, Error on some error
59
+ def clear_roles!
60
+ store.clear!
61
+ end
62
+
63
+ module ClassMethods
64
+ # Sets which roles are valid for the role subject class (fx User or UserAccount)
65
+ #
66
+ # @note this in effect limits what roles can be assigned to any instance of the class
67
+ #
68
+ # @param [Array<Symbol>] list of role names
69
+ def set_valid_roles *roles
70
+ roles = roles.to_symbols_uniq
71
+ raise ArgumentError, "Roles must contain Symbols or Strings" if roles.empty?
72
+ @valid_roles = roles
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,28 @@
1
+ module Troles::Common
2
+ module Api
3
+ autoload :Core, 'troles/common/api/core'
4
+ autoload :Cache, 'troles/common/api/cache'
5
+ autoload :Config, 'troles/common/api/config'
6
+ autoload :Event, 'troles/common/api/event'
7
+ autoload :Read, 'troles/common/api/read'
8
+ autoload :Write, 'troles/common/api/write'
9
+ autoload :Validation, 'troles/common/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
+ end
23
+ end
24
+ end
25
+ end
26
+ extend ClassMethods
27
+ end
28
+ end
@@ -0,0 +1,72 @@
1
+ module Troles::Common
2
+ class Config
3
+ module Schema
4
+ attr_accessor :join_model
5
+
6
+ def configure_role_field
7
+ configure_generic
8
+ configure_field
9
+ configure_relation
10
+ end
11
+
12
+ def configure_generic
13
+ clazz.send(:attr_accessor, role_field) if generic? || orm == :generic # create troles accessor
14
+ end
15
+
16
+ # Adapter should customize this as needed
17
+ def configure_field
18
+ end
19
+
20
+ # Adapter should customize this as needed
21
+ def configure_relation
22
+ end
23
+
24
+ def join_model
25
+ @join_model ||= begin
26
+ return UsersRoles if defined? UsersRoles
27
+ raise "Join model not defined"
28
+ end
29
+ end
30
+
31
+ def join_model= model_class
32
+ @join_model = model_class and return if model_class.kind_of?(Class)
33
+ raise "The role model must be a Class, was: #{model_class}"
34
+ end
35
+
36
+ # Sets the role model to use
37
+ # allows different role subject classes (fx User Accounts) to have different role schemas
38
+ # @param [Class] the model class
39
+ def role_model= model_class
40
+ @role_model = model_class.to_s and return if model_class.any_kind_of?(Class, String, Symbol)
41
+ raise "The role model must be a Class, was: #{model_class}"
42
+ end
43
+
44
+ # Gets the role model to be used
45
+ # see (#role_model=)
46
+ # @return [Class] the model class (defaults to Role)
47
+ def role_model
48
+ @role_model_found ||= begin
49
+ models = [@role_model, 'Role'].select do |class_name|
50
+ try_class(class_name.to_s)
51
+ end.compact
52
+ # puts "role models found: #{models}"
53
+ raise "No Role class defined, define Role one or set using #role_model method on config" if models.empty?
54
+ models.first.to_s.constantize
55
+ end
56
+ end
57
+
58
+ protected
59
+
60
+ def try_class clazz
61
+ begin
62
+ clazz = clazz.constantize if clazz.kind_of?(String)
63
+ clazz
64
+ rescue
65
+ false
66
+ end
67
+ end
68
+
69
+ include SchemaHelpers
70
+ end
71
+ end
72
+ end