role-auth 0.1.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|