role-auth 0.1.9
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/.gitignore +15 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +48 -0
- data/LICENSE +22 -0
- data/README.md +58 -0
- data/Rakefile +1 -0
- data/lib/role-auth.rb +86 -0
- data/lib/role-auth/adapters/data_mapper.rb +60 -0
- data/lib/role-auth/adapters/merb.rb +39 -0
- data/lib/role-auth/builder.rb +141 -0
- data/lib/role-auth/checker.rb +46 -0
- data/lib/role-auth/parser.rb +250 -0
- data/lib/role-auth/version.rb +3 -0
- data/role-auth.gemspec +28 -0
- data/spec/authorization_file_spec.rb +62 -0
- data/spec/datamapper_spec.rb +250 -0
- data/spec/in_memory_spec.rb +123 -0
- data/spec/shared_specs.rb +225 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/support/authorization.rb +68 -0
- data/spec/support/authorization2.rb +3 -0
- data/spec/support/authorization3.rb +5 -0
- data/spec/support/authorization4.rb +4 -0
- data/spec/support/classes.rb +80 -0
- metadata +216 -0
@@ -0,0 +1,46 @@
|
|
1
|
+
module RoleAuth
|
2
|
+
|
3
|
+
# The Checker class checks the permissions of the current User.
|
4
|
+
# It is accessable via RoleAuth.checker.
|
5
|
+
class Checker
|
6
|
+
|
7
|
+
Alias = {:destroy => :delete, :index => :list, :show => :read, :new => :create, :edit => :update}
|
8
|
+
|
9
|
+
# @param [Parser] parser The parser
|
10
|
+
# @param [String] eval_string The ruby code for checking the defined tasks
|
11
|
+
def initialize(parser,eval_string)
|
12
|
+
@parser = parser
|
13
|
+
# puts eval_string
|
14
|
+
instance_eval(eval_string)
|
15
|
+
end
|
16
|
+
|
17
|
+
# Attribute accessor
|
18
|
+
#
|
19
|
+
# @return [Hash] The Hash representation of the defined roles
|
20
|
+
def roles ; @parser.roles; end
|
21
|
+
|
22
|
+
def can?(task, object, options = {}, user = User.current)
|
23
|
+
raise ArgumentError, 'User is missing. Did you forget to set User.current?' unless user
|
24
|
+
self.send(Alias[task] || task, user, object, options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def is?(role_name, options, user = User.current)
|
28
|
+
role_definition = @parser.roles[role_name]
|
29
|
+
child_roles = role_definition[:descendants].dup << role_name
|
30
|
+
|
31
|
+
# Check the :on parameter
|
32
|
+
return false if options[:on] && role_definition[:on] && options[:on].class != role_definition[:on]
|
33
|
+
|
34
|
+
user.roles.any? do |role|
|
35
|
+
child_roles.include?(role.name.to_sym) && ( !role_definition[:on] || !role.type || (role.type == role_definition[:on].to_s && options[:on] && (role.object_id.nil? || role.object_id == options[:on].id)))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def method_missing(name, *args)
|
42
|
+
file = caller.find{|line| line !~ /lib\/role-auth/}
|
43
|
+
puts "RoleAuth warning: Task #{name} hasn't been defined but you tried to access it in #{file}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
module RoleAuth
|
2
|
+
|
3
|
+
# Within the Parser class your authorization file will be evaled.
|
4
|
+
class Parser
|
5
|
+
attr_reader :tasks, :restrictions, :permissions, :roles
|
6
|
+
|
7
|
+
DEFAULT_TASKS = [:create, :update, :delete, :list, :read]
|
8
|
+
|
9
|
+
# @param [File] authorization_file The authorization file which will be evaled.
|
10
|
+
def initialize(authorization_file)
|
11
|
+
@permissions = Hash.new {|h,k| h[k] = (Hash.new {|h,k| h[k] = {}})}
|
12
|
+
@restrictions = Hash.new {|h,k| h[k] = (Hash.new {|h,k| h[k] = {}})}
|
13
|
+
@tasks, @roles = {}, {}
|
14
|
+
|
15
|
+
DEFAULT_TASKS.each {|t| task(t)}
|
16
|
+
instance_eval(authorization_file.read)
|
17
|
+
process_roles
|
18
|
+
process_tasks
|
19
|
+
end
|
20
|
+
|
21
|
+
# Define a new role which can be given to a user.
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# role :moderator, :on => Site do
|
25
|
+
# is :user
|
26
|
+
# can :moderate, Comment
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @param [Symbol] name The name of the Role.
|
30
|
+
# @param [Hash] options
|
31
|
+
# @option options [Class] :on The Role will be bound to instances of the given Class.
|
32
|
+
# @yield Defines the details of the role
|
33
|
+
def role(name, options = {})
|
34
|
+
@roles[name] = options.merge(:name => name, :is => [], :descendants => [])
|
35
|
+
@role = InternalRole.new(name,options)
|
36
|
+
yield if block_given?
|
37
|
+
@role = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
# Define parent roles for the current role.
|
41
|
+
# The current role will behave exactly like the given roles.
|
42
|
+
#
|
43
|
+
# Can only be called within a role block.
|
44
|
+
#
|
45
|
+
# @example define many parents
|
46
|
+
# is :moderator, :author, :user
|
47
|
+
#
|
48
|
+
# @param [Symbol, ...] parent_roles
|
49
|
+
def is(*parent_roles)
|
50
|
+
@roles[@role.name][:is] += parent_roles
|
51
|
+
end
|
52
|
+
|
53
|
+
# Define a permission for the current role.
|
54
|
+
#
|
55
|
+
# Can only be called within a role block.
|
56
|
+
#
|
57
|
+
# @example Author permissions
|
58
|
+
# can :delete, :update, Post, :if => [%{ !post.published }, only_changed(:content)]
|
59
|
+
# can :create, Post, :if => %{ !post.published }
|
60
|
+
#
|
61
|
+
# @example alternative definition
|
62
|
+
# task :update_and_delete_unpublished, :is => [:delete, :update], :if => %{ !post.published }
|
63
|
+
# can :update_and_delete_unpublished, Post, if => only_changed(:content)
|
64
|
+
# can :create, Post, :if => %{ !post.published }
|
65
|
+
#
|
66
|
+
# @overload can(*tasks, *classes, options = {})
|
67
|
+
# @param [Symbol, ...] tasks One or more tasks to bind the permission to
|
68
|
+
# @param [Class, ...] classes One or more classes to bind the permission to
|
69
|
+
# @param [Hash] options
|
70
|
+
def can(*args)
|
71
|
+
add_permission(@permissions, *args)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Define a restriction ( a negative permission ) for the current role.
|
75
|
+
#
|
76
|
+
# Can only be called within a role block.
|
77
|
+
#
|
78
|
+
# @example
|
79
|
+
# can_not :delete, Post
|
80
|
+
#
|
81
|
+
# @see #can Argument details and further examples
|
82
|
+
def can_not(*args)
|
83
|
+
args.last.is_a?(Hash) ? args.last[:restriction]= true : args << {:restriction => true}
|
84
|
+
add_permission(@restrictions, *args)
|
85
|
+
end
|
86
|
+
|
87
|
+
# Define a new task.
|
88
|
+
#
|
89
|
+
# @example Define an entirely new task
|
90
|
+
# task :push
|
91
|
+
#
|
92
|
+
# @example Define a publish task
|
93
|
+
# task :publish, :is => :update, :if => only_changed(:published)
|
94
|
+
#
|
95
|
+
# @example Define a joined manage task
|
96
|
+
# task :manage, :is => [:update, :create, :delete]
|
97
|
+
#
|
98
|
+
# @see #can More examples for the :if option
|
99
|
+
# @see DEFAULT_TASKS Default tasks
|
100
|
+
#
|
101
|
+
# @param [Symbol] name The name of the task.
|
102
|
+
# @param [Hash] options
|
103
|
+
# @option options [Symbol, Array<Symbol>] :is Optional parent tasks. The options of the parents will be inherited.
|
104
|
+
# @option options [String, Hash, Array<String,Hash>] :if The conditions for this task.
|
105
|
+
def task(name, options = {})
|
106
|
+
options[:is] = options[:is].is_a?(Array) ? options[:is] : [options[:is]].compact
|
107
|
+
@tasks[name] = Task.new(name,options)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Define fields that can be changed by the current user.
|
111
|
+
# Use this on an :if attribute of #can, #can_not, #task.
|
112
|
+
#
|
113
|
+
# @see #task Usage examples with a task definition
|
114
|
+
#
|
115
|
+
# @return [Hash] An internal representation
|
116
|
+
def only_changed(*fields)
|
117
|
+
{:change => fields}
|
118
|
+
end
|
119
|
+
|
120
|
+
# Restrict access to the owner of the object.
|
121
|
+
# Use this on an :if attribute of #can, #can_not, #task.
|
122
|
+
def is_owner
|
123
|
+
"object.user_id == user.id"
|
124
|
+
end
|
125
|
+
|
126
|
+
protected
|
127
|
+
|
128
|
+
# Creates an internal Permission
|
129
|
+
#
|
130
|
+
# @param [Hash] target Either the permissions or the restrictions hash
|
131
|
+
# @param [Array] args The function arguments to the #can, #can_not methods
|
132
|
+
def add_permission(target, *args)
|
133
|
+
raise '#can and #can_not have to be used inside a role block' unless @role
|
134
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
135
|
+
tasks = []
|
136
|
+
models = []
|
137
|
+
|
138
|
+
models << args.pop if args.last == :any
|
139
|
+
args.each {|arg| arg.is_a?(Symbol) ? tasks << arg : models << arg}
|
140
|
+
|
141
|
+
tasks.each do |task|
|
142
|
+
models.each do |model|
|
143
|
+
if permission = target[task][model][@role]
|
144
|
+
permission.load_options(options)
|
145
|
+
else
|
146
|
+
target[task][model][@role] = Permission.new(@role, task, model, options)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
# Flattens the tasks. It sets the ancestors and the alternative tasks
|
153
|
+
def process_tasks
|
154
|
+
@tasks.each_value do |task|
|
155
|
+
task.options[:ancestors] = []
|
156
|
+
set_ancestor_tasks(task)
|
157
|
+
set_alternative_tasks(task) if @permissions.key? task.name
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Set the ancestors on task.
|
162
|
+
#
|
163
|
+
# @param [Task] task The task for which the ancestors are set
|
164
|
+
# @param [Task] ancestor The ancestor to process. This is the recursive parameter
|
165
|
+
def set_ancestor_tasks(task, ancestor = nil)
|
166
|
+
task.options[:ancestors] += (ancestor || task).options[:is]
|
167
|
+
(ancestor || task).options[:is].each do |parent_task|
|
168
|
+
set_ancestor_tasks(task, @tasks[parent_task])
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# Set the alternatives of the task.
|
173
|
+
# Alternatives are the nearest ancestors, which are used in permission definitions.
|
174
|
+
#
|
175
|
+
# @param [Task] task The task for which the alternatives are set
|
176
|
+
# @param [Task] ancestor The ancestor to process. This is the recursive parameter
|
177
|
+
def set_alternative_tasks(task, ancestor = nil)
|
178
|
+
(ancestor || task).options[:is].each do |task_name|
|
179
|
+
if @permissions.key? task_name
|
180
|
+
(@tasks[task_name].options[:alternatives] ||= []) << task.name
|
181
|
+
else
|
182
|
+
set_alternative_tasks(task, @tasks[task_name])
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# Flattens the roles. It sets all descendants of a role.
|
188
|
+
def process_roles
|
189
|
+
@roles.each_value {|role| set_descendant_roles(role)}
|
190
|
+
end
|
191
|
+
|
192
|
+
# Set the descendant_role as a descendant of the ancestor
|
193
|
+
def set_descendant_roles(descendant_role, ancestor_role = nil)
|
194
|
+
role = ancestor_role || descendant_role
|
195
|
+
return unless role[:is]
|
196
|
+
|
197
|
+
role[:is].each do |role_name|
|
198
|
+
(@roles[role_name][:descendants] ||= []) << descendant_role[:name]
|
199
|
+
set_descendant_roles(descendant_role, @roles[role_name])
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# InternalRole because otherwise it might conflict with other Role classes
|
204
|
+
InternalRole = Struct.new('InternalRole', :name, :options)
|
205
|
+
Task = Struct.new('Task', :name, :options)
|
206
|
+
|
207
|
+
class Permission
|
208
|
+
attr_reader :role, :task, :model, :options
|
209
|
+
def initialize(role, task, model, options)
|
210
|
+
@role, @task, @model = role, task, model
|
211
|
+
@options = Hash.new {|h,k| h[k]=[]}
|
212
|
+
@options[:if] = Hash.new {|h,k| h[k]=[]}
|
213
|
+
|
214
|
+
load_options(options)
|
215
|
+
load_options(@role.options)
|
216
|
+
end
|
217
|
+
|
218
|
+
def load_options(options)
|
219
|
+
return unless options.is_a? Hash
|
220
|
+
[:on].each do |key|
|
221
|
+
@options[key] << options[key] if options.key? key
|
222
|
+
end
|
223
|
+
add_if(options[:if])
|
224
|
+
end
|
225
|
+
|
226
|
+
def add_if(options)
|
227
|
+
case options
|
228
|
+
when Hash then @options[:if].update(options)
|
229
|
+
when Array then options.each { |entry| add_if(entry) }
|
230
|
+
when String then @options[:if][:string] << options
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# Load the options of the task and all ancestor tasks.
|
235
|
+
# The tasks are not necessarily accessable at the creation of the permission.
|
236
|
+
#
|
237
|
+
# @param parser[Parser] the parser which provides the tasks
|
238
|
+
def load_task_options(parser)
|
239
|
+
return if @loaded_task_options || parser.tasks[@task].nil?
|
240
|
+
load_options(parser.tasks[@task].options)
|
241
|
+
parser.tasks[@task].options[:ancestors].each do |task|
|
242
|
+
load_options(parser.tasks[task].options)
|
243
|
+
end
|
244
|
+
@loaded_task_options = true
|
245
|
+
end
|
246
|
+
|
247
|
+
end
|
248
|
+
|
249
|
+
end
|
250
|
+
end
|
data/role-auth.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'role-auth/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "role-auth"
|
8
|
+
spec.version = RoleAuth::VERSION
|
9
|
+
spec.authors = ["Jonas von Andrian"]
|
10
|
+
spec.email = ["jvadev@gmail.com"]
|
11
|
+
spec.description = %q{Rolebased authorization}
|
12
|
+
spec.summary = %q{Compatible with dm and merb. Compiles into Ruby statements}
|
13
|
+
spec.homepage = "http://github.com/johnny/role-auth"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_development_dependency "bundler"
|
21
|
+
spec.add_development_dependency "rake"
|
22
|
+
spec.add_development_dependency "sqlite3"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "dm-core"
|
25
|
+
spec.add_development_dependency "dm-migrations"
|
26
|
+
spec.add_development_dependency "dm-sqlite-adapter"
|
27
|
+
spec.add_development_dependency "do_sqlite3"
|
28
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe 'authorization2' do
|
4
|
+
before(:all) do
|
5
|
+
User = Memory::User
|
6
|
+
load_authorization_file('authorization2')
|
7
|
+
sysop_role = Memory::Role.new('sysop')
|
8
|
+
Memory::User.current = Memory::User.new(1,[sysop_role])
|
9
|
+
end
|
10
|
+
it 'should define default actions :create, :delete, :update' do
|
11
|
+
can?(:create, Memory::Site).should be_true
|
12
|
+
can?(:update, Memory::Site).should be_true
|
13
|
+
can?(:delete, Memory::Site).should be_true
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should not raise on uninitialised method' do
|
17
|
+
lambda { can?(:praise, Memory::Site) }.should_not raise_error
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe 'authorization3' do
|
22
|
+
|
23
|
+
before(:all) do
|
24
|
+
User = Memory::User
|
25
|
+
load_authorization_file('authorization3')
|
26
|
+
role = Memory::Role.new('user')
|
27
|
+
Memory::User.current = Memory::User.new(1,[role])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should override update' do
|
31
|
+
site = Memory::Site
|
32
|
+
can?(:update, Memory::Post.new(1, site, 2)).should be_false
|
33
|
+
can?(:update, Memory::Post.new(1, site, 1)).should be_true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should accept class as argument' do
|
37
|
+
can?(:create, Memory::Post).should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should handle User classes gracefully' do
|
41
|
+
can?(:create, User).should be_true
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'authorization4' do
|
47
|
+
|
48
|
+
before(:all) do
|
49
|
+
User = Memory::User
|
50
|
+
load_authorization_file('authorization4')
|
51
|
+
role = Memory::Role.new('user')
|
52
|
+
Memory::User.current = Memory::User.new(1,[role])
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'can_not has precidence over can' do
|
56
|
+
can?(:create, Memory::Site).should be_false
|
57
|
+
can?(:create, Memory::Role).should be_false
|
58
|
+
can?(:create, Memory::Post).should be_false
|
59
|
+
can?(:delete, Memory::Site).should be_nil
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
sysop = DataMapper::User.create
|
4
|
+
admin = DataMapper::User.create
|
5
|
+
alternative_admin = DataMapper::User.create
|
6
|
+
author = DataMapper::User.create
|
7
|
+
class_author = DataMapper::User.create
|
8
|
+
general_author = DataMapper::User.create
|
9
|
+
alternative_author = DataMapper::User.create
|
10
|
+
moderator = DataMapper::User.create
|
11
|
+
moderator_author = DataMapper::User.create
|
12
|
+
site_admin = DataMapper::User.create
|
13
|
+
user = DataMapper::User.create
|
14
|
+
|
15
|
+
sysop_role = DataMapper::Role.create(:name => 'sysop', :user => sysop)
|
16
|
+
admin_role = DataMapper::Role.create(:name => 'admin', :user => admin)
|
17
|
+
alternative_admin_role = DataMapper::Role.create(:name => 'alternative_admin', :user => alternative_admin)
|
18
|
+
author_role = DataMapper::Role.create(:name =>'author', :type => 'DataMapper::Site', :object_id => 1, :user => author)
|
19
|
+
general_author_role = DataMapper::Role.create(:name =>'author', :user => general_author)
|
20
|
+
class_author_role = DataMapper::Role.create(:name =>'author', :type => 'DataMapper::Site', :user => class_author)
|
21
|
+
alternative_author_role = DataMapper::Role.create(:name => 'alternative_author', :type => 'DataMapper::Site', :object_id => 1, :user => alternative_author)
|
22
|
+
moderator_author_role = DataMapper::Role.create(:name => 'moderator_author', :user => moderator_author)
|
23
|
+
moderator_role = DataMapper::Role.create(:name => 'moderator', :user => moderator)
|
24
|
+
site_admin_role = DataMapper::Role.create(:name => 'site_admin', :type => 'DataMapper::Site', :object_id => 1, :user => site_admin)
|
25
|
+
user_role = DataMapper::Role.create(:name => 'user', :user => user)
|
26
|
+
# guest_role = DataMapper::Role.new('guest')
|
27
|
+
|
28
|
+
site = DataMapper::Site.create
|
29
|
+
|
30
|
+
own_post = DataMapper::Post.create(:site_id => site.id, :user => author)
|
31
|
+
other_authors_post = DataMapper::Post.create(:site_id => site.id, :user => sysop)
|
32
|
+
published_post = DataMapper::Post.create(:site => site, :user => author, :published => true)
|
33
|
+
comment = DataMapper::Comment.create(:site => site, :post => own_post)
|
34
|
+
comment_on_published_post = DataMapper::Comment.create(:site => site, :post => published_post)
|
35
|
+
|
36
|
+
other_site = DataMapper::Site.create
|
37
|
+
|
38
|
+
other_post = DataMapper::Post.create(:site => other_site, :user => author)
|
39
|
+
other_comment = DataMapper::Comment.create(:site => other_site, :post => other_post)
|
40
|
+
|
41
|
+
describe "RoleAuth DataMapper" do
|
42
|
+
before :all do
|
43
|
+
Comment = DataMapper::Comment
|
44
|
+
Site = DataMapper::Site
|
45
|
+
Role = DataMapper::Role
|
46
|
+
Post = DataMapper::Post
|
47
|
+
User = DataMapper::User
|
48
|
+
load_authorization_file
|
49
|
+
@site = site
|
50
|
+
@own_post = own_post
|
51
|
+
@other_authors_post = other_authors_post
|
52
|
+
@published_post = published_post
|
53
|
+
@comment = comment
|
54
|
+
@comment_on_published_post = comment_on_published_post
|
55
|
+
@other_site = other_site
|
56
|
+
@other_post = other_post
|
57
|
+
@other_comment = other_comment
|
58
|
+
end
|
59
|
+
|
60
|
+
before :each do
|
61
|
+
@own_post.reload
|
62
|
+
end
|
63
|
+
|
64
|
+
after :all do
|
65
|
+
User.current = nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def update_attributes(object, *attrs)
|
69
|
+
object.reload
|
70
|
+
attrs.each do |attr|
|
71
|
+
case attr
|
72
|
+
when :content then object.content = Time.now.to_s
|
73
|
+
when :published then object.published = !object.published
|
74
|
+
when :user_id then object.user_id = (User.current.id + 1)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'admin' do
|
80
|
+
include_context "admin_role"
|
81
|
+
before(:all){ User.current = admin }
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'alternative admin' do
|
85
|
+
include_context "admin_role"
|
86
|
+
before(:all){ User.current = alternative_admin }
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'author on site instance' do
|
90
|
+
include_context "author_role"
|
91
|
+
before(:all){ User.current = author }
|
92
|
+
end
|
93
|
+
|
94
|
+
describe 'author on Site class' do
|
95
|
+
include_context "class_author_role"
|
96
|
+
before(:all) do
|
97
|
+
User.current = nil
|
98
|
+
@own_post = DataMapper::Post.create(:site_id => site.id, :user => class_author)
|
99
|
+
@comment = DataMapper::Comment.create(:site => site, :post => @own_post)
|
100
|
+
@published_post = DataMapper::Post.create(:site => site, :user => class_author, :published => true)
|
101
|
+
User.current = class_author
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'author' do
|
106
|
+
include_context "general_author_role"
|
107
|
+
before(:all) do
|
108
|
+
User.current = nil
|
109
|
+
@own_post = DataMapper::Post.create(:site_id => site.id, :user => general_author)
|
110
|
+
@comment = DataMapper::Comment.create(:site => site, :post => @own_post)
|
111
|
+
@published_post = DataMapper::Post.create(:site => site, :user => general_author, :published => true)
|
112
|
+
User.current = general_author
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'alternative author' do
|
117
|
+
include_context "author_role"
|
118
|
+
before(:all) do
|
119
|
+
User.current = alternative_author
|
120
|
+
@own_post = DataMapper::Post.create(:site => site, :user => alternative_author)
|
121
|
+
@published_post = DataMapper::Post.create(:site => site, :user => alternative_author, :published => true)
|
122
|
+
@comment = DataMapper::Comment.create(:site => site, :post => @own_post)
|
123
|
+
@comment_on_published_post = DataMapper::Comment.create(:site => site, :post => @published_post)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'moderator author' do
|
128
|
+
include_context "moderator_author_role"
|
129
|
+
before(:all) do
|
130
|
+
User.current = moderator_author
|
131
|
+
@own_post = DataMapper::Post.create(:site => site, :user => moderator_author)
|
132
|
+
@published_post = DataMapper::Post.create(:site => site, :user => moderator_author, :published => true)
|
133
|
+
@comment = DataMapper::Comment.create(:site => site, :post => @own_post)
|
134
|
+
@comment_on_published_post = DataMapper::Comment.create(:site => site, :post => @published_post)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
describe 'moderator' do
|
139
|
+
include_context "moderator_role"
|
140
|
+
before(:all) do
|
141
|
+
User.current = nil
|
142
|
+
@own_post = DataMapper::Post.create(:site_id => site.id, :user => moderator)
|
143
|
+
@comment = DataMapper::Comment.create(:site => site, :post => @own_post)
|
144
|
+
User.current = moderator
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'site admin' do
|
149
|
+
include_context "site_admin_role"
|
150
|
+
before :all do
|
151
|
+
User.current = site_admin
|
152
|
+
@own_post = DataMapper::Post.create(:site_id => site.id, :user => site_admin)
|
153
|
+
@comment = DataMapper::Comment.create(:site => site, :post => @own_post)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
describe 'sysop' do
|
158
|
+
include_context "sysop_role"
|
159
|
+
before(:all){ User.current = sysop }
|
160
|
+
end
|
161
|
+
|
162
|
+
describe 'user' do
|
163
|
+
include_context "user_role"
|
164
|
+
before(:all){ User.current = user }
|
165
|
+
end
|
166
|
+
|
167
|
+
describe 'callbacks' do
|
168
|
+
def create_post(options = {})
|
169
|
+
lambda {Post.create({:user => User.current}.merge(options))}
|
170
|
+
end
|
171
|
+
def new_post(options = {})
|
172
|
+
lambda {Post.new({:user => User.current}.merge(options))}
|
173
|
+
end
|
174
|
+
def update(post, options = {})
|
175
|
+
lambda {post.reload.update(options)}
|
176
|
+
end
|
177
|
+
def destroy(post)
|
178
|
+
lambda {post.destroy}
|
179
|
+
end
|
180
|
+
it 'should work with create' do
|
181
|
+
User.current = user
|
182
|
+
create_post(:site => site).should raise_error
|
183
|
+
User.current = author
|
184
|
+
create_post(:site => site).should_not raise_error
|
185
|
+
create_post(:site_id => site.id).should_not raise_error
|
186
|
+
create_post(:site => other_site).should raise_error
|
187
|
+
create_post.should raise_error
|
188
|
+
User.current = moderator_author
|
189
|
+
create_post(:site => site).should_not raise_error
|
190
|
+
create_post(:site => other_site).should_not raise_error
|
191
|
+
end
|
192
|
+
it 'should work with destroy' do
|
193
|
+
post = Post.create(:user => author, :site => site)
|
194
|
+
published_post = Post.create(:user => author, :site => site, :published => true)
|
195
|
+
other_post = Post.create(:user => moderator_author, :site => site)
|
196
|
+
|
197
|
+
User.current = user
|
198
|
+
destroy(post).should raise_error
|
199
|
+
|
200
|
+
User.current = author
|
201
|
+
destroy(post).should_not raise_error
|
202
|
+
destroy(published_post).should raise_error
|
203
|
+
destroy(other_post).should raise_error
|
204
|
+
|
205
|
+
User.current = moderator_author
|
206
|
+
destroy(other_post).should_not raise_error
|
207
|
+
destroy(published_post).should raise_error
|
208
|
+
|
209
|
+
User.current = admin
|
210
|
+
destroy(published_post).should_not raise_error
|
211
|
+
end
|
212
|
+
it 'should work with initialize' do
|
213
|
+
User.current = user
|
214
|
+
new_post(:site => site).should raise_error
|
215
|
+
User.current = author
|
216
|
+
new_post(:site => site).should_not raise_error
|
217
|
+
new_post(:site_id => site.id).should_not raise_error
|
218
|
+
new_post(:site => other_site).should raise_error
|
219
|
+
new_post.should raise_error
|
220
|
+
User.current = moderator_author
|
221
|
+
new_post(:site => site).should_not raise_error
|
222
|
+
new_post(:site => other_site).should_not raise_error
|
223
|
+
end
|
224
|
+
it 'should work with update' do
|
225
|
+
post = Post.create(:user => user, :site => site)
|
226
|
+
other_post = Post.create(:user => moderator_author, :site => site)
|
227
|
+
published_post = Post.create(:user => author, :site => site, :published => true)
|
228
|
+
|
229
|
+
User.current = user
|
230
|
+
update(post, :content => rands).should raise_error
|
231
|
+
User.current = author
|
232
|
+
post = Post.create(:user => author, :site => site)
|
233
|
+
update(post, :content => rands).should_not raise_error
|
234
|
+
update(post).should_not raise_error
|
235
|
+
update(post, :content => rands, :published => true).should raise_error
|
236
|
+
update(post, :published => true).should raise_error
|
237
|
+
update(published_post, :content => rands).should raise_error
|
238
|
+
update(published_post).should_not raise_error
|
239
|
+
User.current = moderator_author
|
240
|
+
update(post, :published => true).should_not raise_error
|
241
|
+
update(post, :content => rands).should raise_error
|
242
|
+
update(published_post, :published => false).should_not raise_error
|
243
|
+
update(other_post, :published => true, :content => rands).should_not raise_error
|
244
|
+
end
|
245
|
+
|
246
|
+
def rands
|
247
|
+
(rand*Time.now.to_i).to_s
|
248
|
+
end
|
249
|
+
end
|
250
|
+
end
|