troles 0.5.0 → 0.5.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/Gemfile.lock +1 -1
- data/README.textile +75 -16
- data/VERSION +1 -1
- data/lib/trole/adapters/active_record/config.rb +3 -3
- data/lib/trole/adapters/mongoid/config.rb +5 -5
- data/lib/trole/config.rb +2 -2
- data/lib/trole_groups.rb +10 -0
- data/lib/trole_groups/READ THIS.textile +4 -0
- data/lib/trole_groups/Rolegroups design.textile +218 -0
- data/lib/trole_groups/adapters/active_record.rb +8 -0
- data/lib/trole_groups/adapters/active_record/config.rb +0 -0
- data/lib/trole_groups/adapters/active_record/storage.rb +0 -0
- data/lib/trole_groups/adapters/active_record/strategy.rb +11 -0
- data/lib/trole_groups/adapters/mongoid.rb +8 -0
- data/lib/trole_groups/adapters/mongoid/config.rb +0 -0
- data/lib/trole_groups/api.rb +29 -0
- data/lib/trole_groups/api/cache.rb +13 -0
- data/lib/trole_groups/api/config.rb +4 -0
- data/lib/trole_groups/api/core.rb +50 -0
- data/lib/trole_groups/api/event.rb +29 -0
- data/lib/trole_groups/api/read.rb +56 -0
- data/lib/trole_groups/api/validation.rb +44 -0
- data/lib/trole_groups/api/write.rb +60 -0
- data/lib/trole_groups/config.rb +134 -0
- data/lib/trole_groups/config/schema.rb +65 -0
- data/lib/trole_groups/config/schema/helpers.rb +11 -0
- data/lib/trole_groups/config/schema/role_group_helpers.rb +11 -0
- data/lib/trole_groups/config/valid_role_groups.rb +21 -0
- data/lib/trole_groups/macros.rb +42 -0
- data/lib/trole_groups/macros/configuration.rb +89 -0
- data/lib/trole_groups/macros/configuration/base_loader.rb +35 -0
- data/lib/trole_groups/macros/configuration/config_loader.rb +19 -0
- data/lib/trole_groups/macros/configuration/storage_loader.rb +20 -0
- data/lib/trole_groups/macros/configuration/strategy_loader.rb +38 -0
- data/lib/trole_groups/macros/static_roles.rb +9 -0
- data/lib/trole_groups/macros/strategy_options.rb +21 -0
- data/lib/trole_groups/operations.rb +25 -0
- data/lib/trole_groups/operations/read.rb +36 -0
- data/lib/trole_groups/operations/write.rb +42 -0
- data/lib/trole_groups/storage.rb +27 -0
- data/lib/trole_groups/storage/base_many.rb +93 -0
- data/lib/trole_groups/storage/embed_many.rb +58 -0
- data/lib/trole_groups/storage/ref_many.rb +47 -0
- data/lib/trole_groups/strategy.rb +30 -0
- data/lib/troles/adapters/active_record/config.rb +32 -9
- data/lib/troles/adapters/mongoid/config.rb +7 -7
- data/lib/troles/common/api/core.rb +1 -1
- data/lib/troles/common/config.rb +49 -14
- data/lib/troles/common/config/schema.rb +17 -23
- data/lib/troles/common/config/schema/helpers.rb +77 -0
- data/lib/troles/common/config/schema/role_helpers.rb +27 -0
- data/lib/troles/common/config/static_roles.rb +4 -4
- data/lib/troles/common/macros.rb +4 -4
- data/lib/troles/common/macros/configuration.rb +8 -8
- data/lib/troles/common/macros/strategy_options.rb +4 -4
- data/lib/troles/common/storage.rb +1 -0
- data/lib/troles/config.rb +2 -2
- data/lib/troles/storage/ref_many.rb +2 -3
- data/spec/active_record/models/ref_many.rb +3 -0
- data/spec/active_record/strategies/many/ref_many_spec.rb +2 -1
- data/spec/generic/models/role.rb +2 -1
- data/spec/trole_groups/api/core_api_spec.rb +14 -0
- data/spec/trole_groups/api/read_api_spec.rb +36 -0
- data/spec/trole_groups/api/write_api_spec.rb +19 -0
- data/spec/trole_groups/api_spec.rb +27 -0
- data/spec/trole_groups/generic/models.rb +3 -0
- data/spec/trole_groups/generic/models/role_group.rb +44 -0
- data/spec/trole_groups/generic/models/user.rb +9 -0
- data/spec/trole_groups/strategies/ref_many.rb +51 -0
- data/spec/trole_groups/strategy_helper.rb +9 -0
- data/spec/trole_groups_spec.rb +11 -0
- data/spec/trole_spec_helper.rb +9 -0
- data/spec/troles/api_spec.rb +12 -18
- data/troles.gemspec +52 -4
- metadata +85 -37
- data/development.sqlite3 +0 -0
- data/lib/troles/common/config/schema_helpers.rb +0 -95
@@ -1,16 +1,17 @@
|
|
1
1
|
module Troles::Common
|
2
2
|
class Config
|
3
3
|
module Schema
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
autoload :Helpers, 'troles/common/config/schema/helpers'
|
5
|
+
autoload :RoleHelpers, 'troles/common/config/schema/role_helpers'
|
6
|
+
|
7
|
+
def configure_models
|
7
8
|
configure_generic
|
8
|
-
configure_field
|
9
|
-
configure_relation
|
9
|
+
configure_field if auto_config?(:fields)
|
10
|
+
configure_relation if auto_config?(:relations)
|
10
11
|
end
|
11
12
|
|
12
13
|
def configure_generic
|
13
|
-
|
14
|
+
subject_class.send(:attr_accessor, role_field) if generic? || orm == :generic # create troles accessor
|
14
15
|
end
|
15
16
|
|
16
17
|
# Adapter should customize this as needed
|
@@ -21,18 +22,6 @@ module Troles::Common
|
|
21
22
|
def configure_relation
|
22
23
|
end
|
23
24
|
|
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
25
|
# Sets the role model to use
|
37
26
|
# allows different role subject classes (fx User Accounts) to have different role schemas
|
38
27
|
# @param [Class] the model class
|
@@ -46,17 +35,21 @@ module Troles::Common
|
|
46
35
|
# @return [Class] the model class (defaults to Role)
|
47
36
|
def role_model
|
48
37
|
@role_model_found ||= begin
|
49
|
-
models = [@role_model,
|
50
|
-
try_class(class_name.to_s)
|
38
|
+
models = [@role_model, role_class_name].select do |class_name|
|
39
|
+
try_class(class_name.to_s.camelize)
|
51
40
|
end.compact
|
52
41
|
# puts "role models found: #{models}"
|
53
|
-
raise "No
|
42
|
+
raise "No #{role_class_name} class defined, define a #{role_class_name} class or set which class to use, using the :role_model option on configuration" if models.empty?
|
54
43
|
models.first.to_s.constantize
|
55
44
|
end
|
56
45
|
end
|
57
46
|
|
58
47
|
protected
|
59
48
|
|
49
|
+
def role_class_name
|
50
|
+
'Role'
|
51
|
+
end
|
52
|
+
|
60
53
|
def try_class clazz
|
61
54
|
begin
|
62
55
|
clazz = clazz.constantize if clazz.kind_of?(String)
|
@@ -66,7 +59,8 @@ module Troles::Common
|
|
66
59
|
end
|
67
60
|
end
|
68
61
|
|
69
|
-
include
|
70
|
-
|
62
|
+
include Helpers
|
63
|
+
include RoleHelpers
|
64
|
+
end
|
71
65
|
end
|
72
66
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Troles::Common
|
2
|
+
class Config
|
3
|
+
module Schema
|
4
|
+
module Helpers
|
5
|
+
def valid_field_name? name
|
6
|
+
return false if !name || name.empty?
|
7
|
+
raise ArgumentException, "Role field must not be named role or roles as these names are reserved by troles!" if [:role, :roles].include? name.to_sym
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def boolean? value
|
12
|
+
[true, false].include? value
|
13
|
+
end
|
14
|
+
|
15
|
+
# TODO: Needs extraction into helper module!
|
16
|
+
|
17
|
+
def belongs_to_for from, to, options = {}
|
18
|
+
make_relationship :belongs_to, from, to, options
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_many_for from, to, options = {}
|
22
|
+
make_relationship :has_many, from, to, options
|
23
|
+
end
|
24
|
+
|
25
|
+
def has_one_for from, to, options = {}
|
26
|
+
make_relationship :has_one, from, to, options
|
27
|
+
end
|
28
|
+
|
29
|
+
# To setup sth like this:
|
30
|
+
#
|
31
|
+
# class UserAccount < ActiveRecord::Base
|
32
|
+
# has_and_belongs_to_many :troles, :class_name => 'Role'
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# class Role < ActiveRecord::Base
|
36
|
+
# has_and_belongs_to_many :user_accounts, :class_name => 'User'
|
37
|
+
# end
|
38
|
+
def has_and_belongs_many from, to, options = {}
|
39
|
+
make_relationship :has_and_belongs_to_many, from, to, :key => role_field
|
40
|
+
make_relationship :has_and_belongs_to_many, to, from, options
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_model_type class_name
|
44
|
+
return :user if class_name == subject_class
|
45
|
+
return :role if class_name == object_model
|
46
|
+
raise "Not a known model: #{class_name}"
|
47
|
+
end
|
48
|
+
|
49
|
+
# options:
|
50
|
+
# - :opts, extras options, fx to set the :through relationship
|
51
|
+
# - :key (usually to enforce use of role_field as key name)
|
52
|
+
def make_relationship type, from, to, options = {}
|
53
|
+
# puts "type: #{type}, #{from}, #{to}"
|
54
|
+
from_type = get_model_type from
|
55
|
+
to_type = get_model_type to
|
56
|
+
|
57
|
+
model_key = options[:key] ? options[:key] : send("#{from_type}_key")
|
58
|
+
|
59
|
+
class_name = send "#{to_type}_class_name"
|
60
|
+
|
61
|
+
options = {:class_name => class_name}
|
62
|
+
options.merge!(options[:opts]) if options[:opts]
|
63
|
+
puts "#{from}.#{type} :#{model_key}, #{options.inspect}" if log_on?
|
64
|
+
from.send(type, model_key, options)
|
65
|
+
end
|
66
|
+
|
67
|
+
def object_key
|
68
|
+
make_key object_class_name
|
69
|
+
end
|
70
|
+
|
71
|
+
def make_key name
|
72
|
+
name.to_s.gsub(/::/, '__').underscore.pluralize
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Troles::Common
|
2
|
+
class Config
|
3
|
+
module Schema
|
4
|
+
module RoleHelpers
|
5
|
+
def subject_class_name
|
6
|
+
subject_class.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
def subject_key
|
10
|
+
make_key subject_class_name
|
11
|
+
end
|
12
|
+
|
13
|
+
def join_class_name
|
14
|
+
join_model.to_s
|
15
|
+
end
|
16
|
+
|
17
|
+
def join_key
|
18
|
+
make_key join_class_name
|
19
|
+
end
|
20
|
+
|
21
|
+
def object_class_name
|
22
|
+
object_model.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -1,13 +1,13 @@
|
|
1
1
|
module Troles::Common
|
2
2
|
class Config
|
3
3
|
module StaticRoles
|
4
|
-
def
|
4
|
+
def static_roles= value
|
5
5
|
raise ArgumentError, "Must be a boolean" if !boolean?(value)
|
6
|
-
@
|
6
|
+
@static_roles = value
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
@
|
9
|
+
def static_roles?
|
10
|
+
@static_roles || false
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
data/lib/troles/common/macros.rb
CHANGED
@@ -9,8 +9,6 @@
|
|
9
9
|
# troles_strategy :bit_many
|
10
10
|
#
|
11
11
|
|
12
|
-
puts "Troles macros enabled!"
|
13
|
-
|
14
12
|
module Troles
|
15
13
|
module Macros
|
16
14
|
autoload :Configuration, 'troles/common/macros/configuration'
|
@@ -19,12 +17,14 @@ module Troles
|
|
19
17
|
configuration = Configuration.new self, strategy, options
|
20
18
|
|
21
19
|
configuration.load_adapter
|
22
|
-
|
20
|
+
puts "strategy module: #{configuration.strategy_module}"
|
21
|
+
puts configuration.strategy_module.methods.grep /store/
|
22
|
+
|
23
23
|
send :include, configuration.strategy_module
|
24
24
|
|
25
25
|
configuration.define_hooks
|
26
26
|
configuration.apply_strategy_options!
|
27
|
-
|
27
|
+
|
28
28
|
if strategy == :bit_one
|
29
29
|
troles_config.valid_roles = [:user, :admin] # default binary roles
|
30
30
|
end
|
@@ -6,10 +6,10 @@ module Troles
|
|
6
6
|
autoload :StrategyLoader, 'troles/common/macros/configuration/strategy_loader'
|
7
7
|
autoload :StorageLoader, 'troles/common/macros/configuration/storage_loader'
|
8
8
|
|
9
|
-
attr_reader :strategy, :singularity, :orm, :auto_load, :options, :
|
9
|
+
attr_reader :strategy, :singularity, :orm, :auto_load, :options, :subject_class
|
10
10
|
|
11
|
-
def initialize
|
12
|
-
@
|
11
|
+
def initialize subject_class, strategy, options = {}
|
12
|
+
@subject_class = subject_class
|
13
13
|
@strategy = strategy
|
14
14
|
@orm = options[:orm] || Troles::Config.default_orm
|
15
15
|
@auto_load = options[:auto_load] || Troles::Config.auto_load?
|
@@ -33,23 +33,23 @@ module Troles
|
|
33
33
|
end
|
34
34
|
|
35
35
|
def apply_strategy_options!
|
36
|
-
|
36
|
+
subject_class.troles_config.apply_options! options
|
37
37
|
|
38
|
-
# StrategyOptions.new(
|
38
|
+
# StrategyOptions.new(subject_class)
|
39
39
|
# extract_macros(options).each{|m| apply_macro m}
|
40
40
|
end
|
41
41
|
|
42
42
|
def define_hooks
|
43
43
|
storage_class = storage_loader.storage_class
|
44
|
-
|
44
|
+
subject_class.send :define_method, :storage do
|
45
45
|
@storage ||= storage_class
|
46
46
|
end
|
47
47
|
|
48
48
|
config_class = config_loader.config_class
|
49
49
|
puts "config_class: #{config_class}" if Troles::Config.log_on
|
50
|
-
|
50
|
+
subject_class.singleton_class.class_eval %{
|
51
51
|
def troles_config
|
52
|
-
@troles_config ||= #{config_class}.new #{
|
52
|
+
@troles_config ||= #{config_class}.new #{subject_class}, #{options.inspect}
|
53
53
|
end
|
54
54
|
}
|
55
55
|
end
|
@@ -1,17 +1,17 @@
|
|
1
1
|
module Troles
|
2
2
|
module Macros
|
3
3
|
class StrategyOptions
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :subject_class
|
5
5
|
|
6
|
-
def initialize
|
7
|
-
@
|
6
|
+
def initialize subject_class
|
7
|
+
@subject_class = subject_class
|
8
8
|
end
|
9
9
|
|
10
10
|
# @param [Symbol] name of the macro to run
|
11
11
|
def apply_macro name
|
12
12
|
# overrides default method that returns false
|
13
13
|
begin
|
14
|
-
|
14
|
+
subject_class.send :include, "Troles::Macros::#{strategy_name.to_s.camelize}".constantize
|
15
15
|
rescue
|
16
16
|
end
|
17
17
|
end
|
@@ -28,6 +28,7 @@ module Troles::Common
|
|
28
28
|
# sets the value of the role field (@trole or @troles) and persists the value (in the data store)
|
29
29
|
# @param [Object] the value to set on the role field of the role subject
|
30
30
|
def set_ds_field value
|
31
|
+
return if ds_field_value == value
|
31
32
|
role_subject.send(:"#{ds_field_name}=", value)
|
32
33
|
persist_role_changes!
|
33
34
|
end
|
data/lib/troles/config.rb
CHANGED
@@ -26,9 +26,8 @@ module Troles::Storage
|
|
26
26
|
|
27
27
|
# saves the role for the user in the data store
|
28
28
|
def set_roles *roles
|
29
|
-
# finds and sets references to existing Role instances from symbols
|
30
|
-
|
31
|
-
set_ds_field found_roles
|
29
|
+
# finds and sets references to existing Role instances from symbols
|
30
|
+
set_ds_field find_roles(*roles)
|
32
31
|
end
|
33
32
|
|
34
33
|
# clears the role of the user in the data store
|
data/spec/generic/models/role.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
shared_examples_for "TroleGroup Core API" do
|
2
|
+
# Core API
|
3
|
+
specify { lambda { user.rolegroup_field }.should raise_error } # no, role_field is a class method
|
4
|
+
specify { User.rolegroup_field.should_not be_nil } # yes, role_field is a class method
|
5
|
+
|
6
|
+
subject { user }
|
7
|
+
its(:rolegroup_list) { should include(:blog_admin) }
|
8
|
+
its(:rolegroups) { should be_a TroleGroups::Operations }
|
9
|
+
|
10
|
+
# specify { user.static_role_groups?.should be_false }
|
11
|
+
# specify { User.static_role_groups?.should be_false }
|
12
|
+
|
13
|
+
# TODO: Add examples with other users?
|
14
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
shared_examples_for "TroleGroup Read API" do
|
2
|
+
|
3
|
+
specify { user.has_rolegroup?(:blog_admin).should be_true }
|
4
|
+
|
5
|
+
it "only be in role groups" do
|
6
|
+
user.only_in_rolegroup?(:blog_admin).should be_true
|
7
|
+
user.add_rolegroups :super_admin
|
8
|
+
user.only_in_rolegroup?(:blog_admin).should be_false
|
9
|
+
user.remove_rolegroups :super_admin
|
10
|
+
end
|
11
|
+
|
12
|
+
specify { user.has_rolegroups?(:blog_admin).should be_true }
|
13
|
+
|
14
|
+
it "should be in 2 role groups" do
|
15
|
+
user.add_rolegroups :super_admin
|
16
|
+
user.has_rolegroups?(:blog_admin, :super_admin).should be_true
|
17
|
+
user.has_any_rolegroup?(:super_admin).should be_true
|
18
|
+
|
19
|
+
# adding single roles and role groups together produces union of roles from all :)
|
20
|
+
user.add_roles :editor
|
21
|
+
user.role_list.should include(:editor, :blogger, :blog_editor, :admin, :blog_admin)
|
22
|
+
end
|
23
|
+
|
24
|
+
specify { user.has_any_rolegroup?(:blog_admin, :admin).should be_true }
|
25
|
+
specify { user.has_any_rolegroup?(:blip).should be_false }
|
26
|
+
|
27
|
+
subject { user }
|
28
|
+
its(:rolegroup_list) { should include(:blog_admin) }
|
29
|
+
|
30
|
+
it 'should cache the rolegroup list' do
|
31
|
+
user.rolegroup_list.should include(:blog_admin)
|
32
|
+
# calling rolegroup_list multiple times should NOT invalidate the cache :)
|
33
|
+
expect { user.rolegroup_list }.to_not change{ user.rolegroup_list_value }
|
34
|
+
user.rolegroup_list.should include(:blog_admin)
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
shared_examples_for "TroleGroup Write API" do
|
2
|
+
|
3
|
+
describe '#clear_rolegroups!' do
|
4
|
+
it "should clear rolegroups and invalidate rolegroups cache" do
|
5
|
+
user.set_rolegroups :admin
|
6
|
+
user.clear_rolegroups!
|
7
|
+
expect { user.rolegroup_list }.to change{user.rolegroup_list_value }
|
8
|
+
user.rolegroup_list.should be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
it "successive clear rolegroups should not invalidate rolegroups cache" do
|
12
|
+
user.set_rolegroups :admin
|
13
|
+
user.clear_rolegroups!
|
14
|
+
expect { user.rolegroup_list }.to change{user.rolegroup_list_value }
|
15
|
+
user.clear_rolegroups!
|
16
|
+
expect { user.rolegroup_list }.to_not change{user.rolegroup_list_value }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# See http://blog.davidchelimsky.net/2010/11/07/specifying-mixins-with-shared-example-groups-in-rspec-2/
|
2
|
+
# And: http://relishapp.com/rspec/rspec-core/v/2-6/dir/example-groups/shared-examples
|
3
|
+
# Also: http://stackoverflow.com/questions/6152359/dynamically-generating-shared-examples-in-rspec-2
|
4
|
+
|
5
|
+
require_all File.dirname(__FILE__) + '/api'
|
6
|
+
|
7
|
+
def define_users
|
8
|
+
let(:no_roles_user) { create_no_roles_user }
|
9
|
+
let(:user) { create_user }
|
10
|
+
let(:admin_user) { create_admin_user }
|
11
|
+
end
|
12
|
+
|
13
|
+
shared_examples_for "TroleGroup API" do
|
14
|
+
include UserSetup
|
15
|
+
|
16
|
+
it_behaves_like "TroleGroup Core API" do
|
17
|
+
define_users
|
18
|
+
end
|
19
|
+
|
20
|
+
it_behaves_like "TroleGroup Read API" do
|
21
|
+
define_users
|
22
|
+
end
|
23
|
+
|
24
|
+
it_behaves_like "TroleGroup Write API" do
|
25
|
+
define_users
|
26
|
+
end
|
27
|
+
end
|