third-prestige-rolify 3.3.0.rc5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.travis.yml +17 -0
  4. data/CHANGELOG.rdoc +157 -0
  5. data/Gemfile +21 -0
  6. data/LICENSE +20 -0
  7. data/README.md +220 -0
  8. data/Rakefile +34 -0
  9. data/UPGRADE.rdoc +44 -0
  10. data/gemfiles/Gemfile.rails-3.2 +21 -0
  11. data/gemfiles/Gemfile.rails-4.0 +27 -0
  12. data/lib/generators/active_record/rolify_generator.rb +50 -0
  13. data/lib/generators/active_record/templates/README +8 -0
  14. data/lib/generators/active_record/templates/migration.rb +19 -0
  15. data/lib/generators/mongoid/rolify_generator.rb +51 -0
  16. data/lib/generators/mongoid/templates/README-mongoid +4 -0
  17. data/lib/generators/rolify/rolify_generator.rb +35 -0
  18. data/lib/generators/rolify/templates/README +13 -0
  19. data/lib/generators/rolify/templates/initializer.rb +8 -0
  20. data/lib/generators/rolify/templates/role-active_record.rb +11 -0
  21. data/lib/generators/rolify/templates/role-mongoid.rb +17 -0
  22. data/lib/generators/rolify/user_generator.rb +39 -0
  23. data/lib/rolify.rb +57 -0
  24. data/lib/rolify/adapters/active_record/resource_adapter.rb +26 -0
  25. data/lib/rolify/adapters/active_record/role_adapter.rb +86 -0
  26. data/lib/rolify/adapters/active_record/scopes.rb +27 -0
  27. data/lib/rolify/adapters/base.rb +60 -0
  28. data/lib/rolify/adapters/mongoid/resource_adapter.rb +27 -0
  29. data/lib/rolify/adapters/mongoid/role_adapter.rb +89 -0
  30. data/lib/rolify/adapters/mongoid/scopes.rb +27 -0
  31. data/lib/rolify/configure.rb +56 -0
  32. data/lib/rolify/dynamic.rb +21 -0
  33. data/lib/rolify/finders.rb +40 -0
  34. data/lib/rolify/matchers.rb +13 -0
  35. data/lib/rolify/railtie.rb +20 -0
  36. data/lib/rolify/resource.rb +31 -0
  37. data/lib/rolify/role.rb +85 -0
  38. data/lib/rolify/utils.rb +10 -0
  39. data/lib/rolify/version.rb +3 -0
  40. data/rolify.gemspec +30 -0
  41. data/spec/README.rdoc +24 -0
  42. data/spec/generators/rolify/rolify_activerecord_generator_spec.rb +163 -0
  43. data/spec/generators/rolify/rolify_mongoid_generator_spec.rb +112 -0
  44. data/spec/generators_helper.rb +21 -0
  45. data/spec/rolify/config_spec.rb +191 -0
  46. data/spec/rolify/custom_spec.rb +20 -0
  47. data/spec/rolify/matchers_spec.rb +24 -0
  48. data/spec/rolify/namespace_spec.rb +24 -0
  49. data/spec/rolify/resource_spec.rb +389 -0
  50. data/spec/rolify/resourcifed_and_rolifed_spec.rb +24 -0
  51. data/spec/rolify/role_spec.rb +20 -0
  52. data/spec/rolify/shared_contexts.rb +92 -0
  53. data/spec/rolify/shared_examples/shared_examples_for_add_role.rb +92 -0
  54. data/spec/rolify/shared_examples/shared_examples_for_callbacks.rb +65 -0
  55. data/spec/rolify/shared_examples/shared_examples_for_dynamic.rb +151 -0
  56. data/spec/rolify/shared_examples/shared_examples_for_finders.rb +77 -0
  57. data/spec/rolify/shared_examples/shared_examples_for_has_all_roles.rb +71 -0
  58. data/spec/rolify/shared_examples/shared_examples_for_has_any_role.rb +71 -0
  59. data/spec/rolify/shared_examples/shared_examples_for_has_role.rb +135 -0
  60. data/spec/rolify/shared_examples/shared_examples_for_only_has_role.rb +174 -0
  61. data/spec/rolify/shared_examples/shared_examples_for_remove_role.rb +121 -0
  62. data/spec/rolify/shared_examples/shared_examples_for_roles.rb +102 -0
  63. data/spec/rolify/shared_examples/shared_examples_for_scopes.rb +38 -0
  64. data/spec/spec_helper.rb +30 -0
  65. data/spec/support/adapters/active_record.rb +76 -0
  66. data/spec/support/adapters/mongoid.rb +143 -0
  67. data/spec/support/adapters/mongoid.yml +6 -0
  68. data/spec/support/data.rb +25 -0
  69. data/spec/support/schema.rb +52 -0
  70. metadata +254 -0
@@ -0,0 +1,26 @@
1
+ require 'rolify/adapters/base'
2
+
3
+ module Rolify
4
+ module Adapter
5
+ class ResourceAdapter < ResourceAdapterBase
6
+ def resources_find(roles_table, relation, role_name)
7
+ resources = relation.joins("INNER JOIN #{quote(roles_table)} ON #{quote(roles_table)}.resource_type = '#{relation.to_s}' AND
8
+ (#{quote(roles_table)}.resource_id IS NULL OR #{quote(roles_table)}.resource_id = #{quote(relation.table_name)}.#{relation.primary_key})")
9
+ resources = resources.where("#{quote(roles_table)}.name IN (?) AND #{quote(roles_table)}.resource_type = ?", Array(role_name), relation.to_s)
10
+ resources = resources.select("#{quote(relation.table_name)}.*")
11
+ resources
12
+ end
13
+
14
+ def in(relation, user, role_names)
15
+ roles = user.roles.where(:name => role_names)
16
+ relation.where("#{quote(role_class.table_name)}.#{role_class.primary_key} IN (?) AND ((resource_id = #{quote(relation.table_name)}.#{relation.primary_key}) OR (resource_id IS NULL))", roles)
17
+ end
18
+
19
+ private
20
+
21
+ def quote(column)
22
+ ActiveRecord::Base.connection.quote_column_name column
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,86 @@
1
+ require 'rolify/adapters/base'
2
+
3
+ module Rolify
4
+ module Adapter
5
+ class RoleAdapter < RoleAdapterBase
6
+ def where(relation, *args)
7
+ conditions, values = build_conditions(relation, args)
8
+ relation.where(conditions, *values)
9
+ end
10
+
11
+ def find_or_create_by(role_name, resource_type = nil, resource_id = nil)
12
+ role_class.where(:name => role_name, :resource_type => resource_type, :resource_id => resource_id).first_or_create
13
+ end
14
+
15
+ def add(relation, role)
16
+ relation.role_ids |= [role.id]
17
+ end
18
+
19
+ def remove(relation, role_name, resource = nil)
20
+ cond = { :name => role_name }
21
+ cond[:resource_type] = (resource.is_a?(Class) ? resource.to_s : resource.class.name) if resource
22
+ cond[:resource_id] = resource.id if resource && !resource.is_a?(Class)
23
+ roles = relation.roles.where(cond)
24
+ if roles
25
+ relation.roles.delete(roles)
26
+ roles.each do |role|
27
+ role.destroy if role.send(ActiveSupport::Inflector.demodulize(user_class).tableize.to_sym).empty?
28
+ end
29
+ end
30
+ roles
31
+ end
32
+
33
+ def exists?(relation, column)
34
+ relation.where("#{column} IS NOT NULL")
35
+ end
36
+
37
+ def scope(relation, conditions)
38
+ if Rails.version < "4.0"
39
+ query = relation.scoped
40
+ else
41
+ query = relation.all
42
+ end
43
+ query = query.joins(:roles)
44
+ query = where(query, conditions)
45
+ query
46
+ end
47
+
48
+ private
49
+
50
+ def build_conditions(relation, args)
51
+ conditions = []
52
+ values = []
53
+ args.each do |arg|
54
+ if arg.is_a? Hash
55
+ a, v = build_query(arg[:name], arg[:resource])
56
+ elsif arg.is_a?(String) || arg.is_a?(Symbol)
57
+ a, v = build_query(arg.to_s)
58
+ else
59
+ raise ArgumentError, "Invalid argument type: only hash or string or a symbol allowed"
60
+ end
61
+ conditions << a
62
+ values += v
63
+ end
64
+ conditions = conditions.join(' OR ')
65
+ [ conditions, values ]
66
+ end
67
+
68
+ def build_query(role, resource = nil)
69
+ return [ "#{role_table}.name = ?", [ role ] ] if resource == :any
70
+ query = "((#{role_table}.name = ?) AND (#{role_table}.resource_type IS NULL) AND (#{role_table}.resource_id IS NULL))"
71
+ values = [ role ]
72
+ if resource
73
+ query.insert(0, "(")
74
+ query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id IS NULL))"
75
+ values << role << (resource.is_a?(Class) ? resource.to_s : resource.class.name)
76
+ if !resource.is_a? Class
77
+ query += " OR ((#{role_table}.name = ?) AND (#{role_table}.resource_type = ?) AND (#{role_table}.resource_id = ?))"
78
+ values << role << resource.class.name << resource.id
79
+ end
80
+ query += ")"
81
+ end
82
+ [ query, values ]
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,27 @@
1
+ module Rolify
2
+ module Adapter
3
+ module Scopes
4
+ def global
5
+ where(:resource_type => nil, :resource_id => nil)
6
+ end
7
+
8
+ def class_scoped(resource_type = nil)
9
+ where_conditions = "resource_type IS NOT NULL AND resource_id IS NULL"
10
+ where_conditions = [ "resource_type = ? AND resource_id IS NULL", resource_type.name ] if resource_type
11
+ where(where_conditions)
12
+ end
13
+
14
+ def instance_scoped(resource_type = nil)
15
+ where_conditions = "resource_type IS NOT NULL AND resource_id IS NOT NULL"
16
+ if resource_type
17
+ if resource_type.is_a? Class
18
+ where_conditions = [ "resource_type = ? AND resource_id IS NOT NULL", resource_type.name ]
19
+ else
20
+ where_conditions = [ "resource_type = ? AND resource_id = ?", resource_type.class.name, resource_type.id ]
21
+ end
22
+ end
23
+ where(where_conditions)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,60 @@
1
+ module Rolify
2
+ module Adapter
3
+ class Base
4
+ def initialize(role_cname, user_cname)
5
+ @role_cname = role_cname
6
+ @user_cname = user_cname
7
+ end
8
+
9
+ def role_class
10
+ @role_cname.constantize
11
+ end
12
+
13
+ def user_class
14
+ @user_cname.constantize
15
+ end
16
+
17
+ def role_table
18
+ role_class.table_name
19
+ end
20
+
21
+ def self.create(adapter, role_cname, user_cname)
22
+ load "rolify/adapters/#{Rolify.orm}/#{adapter}.rb"
23
+ load "rolify/adapters/#{Rolify.orm}/scopes.rb"
24
+ Rolify::Adapter.const_get(adapter.camelize.to_sym).new(role_cname, user_cname)
25
+ end
26
+ end
27
+
28
+ class RoleAdapterBase < Adapter::Base
29
+ def where(relation, args)
30
+ raise NotImplementedError.new("You must implement where")
31
+ end
32
+
33
+ def find_or_create_by(role_name, resource_type = nil, resource_id = nil)
34
+ raise NotImplementedError.new("You must implement find_or_create_by")
35
+ end
36
+
37
+ def add(relation, role_name, resource = nil)
38
+ raise NotImplementedError.new("You must implement add")
39
+ end
40
+
41
+ def remove(relation, role_name, resource = nil)
42
+ raise NotImplementedError.new("You must implement delete")
43
+ end
44
+
45
+ def exists?(relation, column)
46
+ raise NotImplementedError.new("You must implement exists?")
47
+ end
48
+ end
49
+
50
+ class ResourceAdapterBase < Adapter::Base
51
+ def resources_find(roles_table, relation, role_name)
52
+ raise NotImplementedError.new("You must implement resources_find")
53
+ end
54
+
55
+ def in(resources, roles)
56
+ raise NotImplementedError.new("You must implement in")
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,27 @@
1
+ require 'rolify/adapters/base'
2
+
3
+ module Rolify
4
+ module Adapter
5
+ class ResourceAdapter < ResourceAdapterBase
6
+ def resources_find(roles_table, relation, role_name)
7
+ roles = roles_table.classify.constantize.where(:name.in => Array(role_name), :resource_type => relation.to_s)
8
+ resources = []
9
+ roles.each do |role|
10
+ if role.resource_id.nil?
11
+ resources += relation.all
12
+ else
13
+ resources << role.resource
14
+ end
15
+ end
16
+ resources.compact.uniq
17
+ end
18
+
19
+ def in(resources, user, role_names)
20
+ roles = user.roles.where(:name.in => Array(role_names))
21
+ return [] if resources.empty? || roles.empty?
22
+ resources.delete_if { |resource| (resource.applied_roles & roles).empty? }
23
+ resources
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,89 @@
1
+ require 'rolify/adapters/base'
2
+
3
+ module Rolify
4
+ module Adapter
5
+ class RoleAdapter < RoleAdapterBase
6
+ def where(relation, *args)
7
+ conditions = build_conditions(relation, args)
8
+ relation.any_of(*conditions)
9
+ end
10
+
11
+ def find_or_create_by(role_name, resource_type = nil, resource_id = nil)
12
+ self.role_class.find_or_create_by(:name => role_name,
13
+ :resource_type => resource_type,
14
+ :resource_id => resource_id)
15
+ end
16
+
17
+ def add(relation, role)
18
+ relation.roles << role
19
+ end
20
+
21
+ def remove(relation, role_name, resource = nil)
22
+ #roles = { :name => role_name }
23
+ #roles.merge!({:resource_type => (resource.is_a?(Class) ? resource.to_s : resource.class.name)}) if resource
24
+ #roles.merge!({ :resource_id => resource.id }) if resource && !resource.is_a?(Class)
25
+ #roles_to_remove = relation.roles.where(roles)
26
+ #roles_to_remove.each do |role|
27
+ # # Deletion in n-n relations is unreliable. Sometimes it works, sometimes not.
28
+ # # So, this does not work all the time: `relation.roles.delete(role)`
29
+ # # @see http://stackoverflow.com/questions/9132596/rails3-mongoid-many-to-many-relation-and-delete-operation
30
+ # # We instead remove ids from the Role object and the relation object.
31
+ # relation.role_ids.delete(role.id)
32
+ # role.send((user_class.to_s.underscore + '_ids').to_sym).delete(relation.id)
33
+ #
34
+ # role.destroy if role.send(user_class.to_s.tableize.to_sym).empty?
35
+ #end
36
+ cond = { :name => role_name }
37
+ cond[:resource_type] = (resource.is_a?(Class) ? resource.to_s : resource.class.name) if resource
38
+ cond[:resource_id] = resource.id if resource && !resource.is_a?(Class)
39
+ roles = relation.roles.where(cond)
40
+ roles.each do |role|
41
+ relation.roles.delete(role)
42
+ role.send(ActiveSupport::Inflector.demodulize(user_class).tableize.to_sym).delete(relation)
43
+ role.destroy if role.send(ActiveSupport::Inflector.demodulize(user_class).tableize.to_sym).empty?
44
+ end if roles
45
+ roles
46
+ end
47
+
48
+ def exists?(relation, column)
49
+ relation.where(column.to_sym.ne => nil)
50
+ end
51
+
52
+ def scope(relation, conditions)
53
+ roles = where(role_class, conditions).map { |role| role.id }
54
+ return [] if roles.size.zero?
55
+ query = relation.any_in(:role_ids => roles)
56
+ query
57
+ end
58
+
59
+ private
60
+
61
+ def build_conditions(relation, args)
62
+ conditions = []
63
+ args.each do |arg|
64
+ if arg.is_a? Hash
65
+ query = build_query(arg[:name], arg[:resource])
66
+ elsif arg.is_a?(String) || arg.is_a?(Symbol)
67
+ query = build_query(arg)
68
+ else
69
+ raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
70
+ end
71
+ conditions += query
72
+ end
73
+ conditions
74
+ end
75
+
76
+ def build_query(role, resource = nil)
77
+ return [{ :name => role }] if resource == :any
78
+ query = [{ :name => role, :resource_type => nil, :resource_id => nil }]
79
+ if resource
80
+ query << { :name => role, :resource_type => (resource.is_a?(Class) ? resource.to_s : resource.class.name), :resource_id => nil }
81
+ if !resource.is_a? Class
82
+ query << { :name => role, :resource_type => resource.class.name, :resource_id => resource.id }
83
+ end
84
+ end
85
+ query
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ module Rolify
2
+ module Adapter
3
+ module Scopes
4
+ def global
5
+ where(:resource_type => nil, :resource_id => nil)
6
+ end
7
+
8
+ def class_scoped(resource_type = nil)
9
+ where_conditions = { :resource_type.ne => nil, :resource_id => nil }
10
+ where_conditions = { :resource_type => resource_type.name, :resource_id => nil } if resource_type
11
+ where(where_conditions)
12
+ end
13
+
14
+ def instance_scoped(resource_type = nil)
15
+ where_conditions = { :resource_type.ne => nil, :resource_id.ne => nil }
16
+ if resource_type
17
+ if resource_type.is_a? Class
18
+ where_conditions = { :resource_type => resource_type.name, :resource_id.ne => nil }
19
+ else
20
+ where_conditions = { :resource_type => resource_type.class.name, :resource_id => resource_type.id }
21
+ end
22
+ end
23
+ where(where_conditions)
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,56 @@
1
+ module Rolify
2
+ module Configure
3
+ @@dynamic_shortcuts = false
4
+ @@orm = "active_record"
5
+
6
+ def configure(*role_cnames)
7
+ return if !sanity_check(role_cnames)
8
+ yield self if block_given?
9
+ end
10
+
11
+ def dynamic_shortcuts
12
+ @@dynamic_shortcuts
13
+ end
14
+
15
+ def dynamic_shortcuts=(is_dynamic)
16
+ @@dynamic_shortcuts = is_dynamic
17
+ end
18
+
19
+ def orm
20
+ @@orm
21
+ end
22
+
23
+ def orm=(orm)
24
+ @@orm = orm
25
+ end
26
+
27
+ def use_mongoid
28
+ self.orm = "mongoid"
29
+ end
30
+
31
+ def use_dynamic_shortcuts
32
+ self.dynamic_shortcuts = true #if defined?(Rails::Server) || defined?(Rails::Console)
33
+ end
34
+
35
+ def use_defaults
36
+ configure do |config|
37
+ config.dynamic_shortcuts = false
38
+ config.orm = "active_record"
39
+ end
40
+ end
41
+
42
+ private
43
+
44
+ def sanity_check(role_cnames)
45
+ role_cnames = [ "Role" ] if role_cnames.empty?
46
+ role_cnames.each do |role_cname|
47
+ role_class = role_cname.constantize
48
+ if role_class.superclass.to_s == "ActiveRecord" && !role_class.table_exists?
49
+ warn "[WARN] table '#{role_cname}' doesn't exist. Did you run the migration ? Ignoring rolify config."
50
+ return false
51
+ end
52
+ end
53
+ true
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,21 @@
1
+ module Rolify
2
+ module Dynamic
3
+ def load_dynamic_methods
4
+ self.role_class.all.each do |r|
5
+ define_dynamic_method(r.name, r.resource)
6
+ end
7
+ end
8
+
9
+ def define_dynamic_method(role_name, resource)
10
+ class_eval do
11
+ define_method("is_#{role_name}?".to_sym) do
12
+ has_role?("#{role_name}")
13
+ end if !method_defined?("is_#{role_name}?".to_sym)
14
+
15
+ define_method("is_#{role_name}_of?".to_sym) do |arg|
16
+ has_role?("#{role_name}", arg)
17
+ end if !method_defined?("is_#{role_name}_of?".to_sym) && resource
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ module Rolify
2
+ module Finders
3
+ def with_role(role_name, resource = nil)
4
+ self.adapter.scope(self, :name => role_name, :resource => resource)
5
+ end
6
+
7
+ def with_all_roles(*args)
8
+ users = []
9
+ parse_args(args, users) do |users_to_add|
10
+ users = users_to_add if users.empty?
11
+ users &= users_to_add
12
+ return [] if users.empty?
13
+ end
14
+ users
15
+ end
16
+
17
+ def with_any_role(*args)
18
+ users = []
19
+ parse_args(args, users) do |users_to_add|
20
+ users += users_to_add
21
+ end
22
+ users.uniq
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def parse_args(args, users, &block)
29
+ args.each do |arg|
30
+ if arg.is_a? Hash
31
+ users_to_add = self.with_role(arg[:name], arg[:resource])
32
+ elsif arg.is_a?(String) || arg.is_a?(Symbol)
33
+ users_to_add = self.with_role(arg)
34
+ else
35
+ raise ArgumentError, "Invalid argument type: only hash or string or symbol allowed"
36
+ end
37
+ block.call(users_to_add)
38
+ end
39
+ end
40
+ end