authorizable 0.9.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.
- checksums.yaml +7 -0
- data/.gitignore +33 -0
- data/.travis.yml +14 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +178 -0
- data/LICENSE +22 -0
- data/README.md +80 -0
- data/Rakefile +1 -0
- data/authorizable.gemspec +40 -0
- data/config/locales/en.yml +6 -0
- data/lib/authorizable.rb +31 -0
- data/lib/authorizable/controller.rb +156 -0
- data/lib/authorizable/model.rb +162 -0
- data/lib/authorizable/permission_utilities.rb +89 -0
- data/lib/authorizable/permissions.rb +112 -0
- data/lib/authorizable/version.rb +5 -0
- data/spec/integration/controller_spec.rb +127 -0
- data/spec/integration/model_spec.rb +169 -0
- data/spec/rails_helper.rb +14 -0
- data/spec/spec_helper.rb +48 -0
- data/spec/support/definitions.rb +16 -0
- data/spec/support/factories.rb +17 -0
- data/spec/support/factory_girl.rb +7 -0
- data/spec/support/rails_app/Rakefile +6 -0
- data/spec/support/rails_app/app/assets/images/.keep +0 -0
- data/spec/support/rails_app/app/assets/javascripts/application.js +16 -0
- data/spec/support/rails_app/app/assets/javascripts/some_resources.js +2 -0
- data/spec/support/rails_app/app/assets/javascripts/users.js +2 -0
- data/spec/support/rails_app/app/assets/stylesheets/application.css +15 -0
- data/spec/support/rails_app/app/assets/stylesheets/scaffold.css +56 -0
- data/spec/support/rails_app/app/assets/stylesheets/some_resources.css +4 -0
- data/spec/support/rails_app/app/assets/stylesheets/users.css +4 -0
- data/spec/support/rails_app/app/controllers/application_controller.rb +14 -0
- data/spec/support/rails_app/app/controllers/events_controller.rb +58 -0
- data/spec/support/rails_app/app/controllers/users_controller.rb +58 -0
- data/spec/support/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/support/rails_app/app/helpers/events_helper.rb +2 -0
- data/spec/support/rails_app/app/helpers/users_helper.rb +2 -0
- data/spec/support/rails_app/app/mailers/.keep +0 -0
- data/spec/support/rails_app/app/models/collaboration.rb +16 -0
- data/spec/support/rails_app/app/models/concerns/.keep +0 -0
- data/spec/support/rails_app/app/models/discount.rb +3 -0
- data/spec/support/rails_app/app/models/event.rb +5 -0
- data/spec/support/rails_app/app/models/user.rb +9 -0
- data/spec/support/rails_app/app/views/events/_form.html.erb +17 -0
- data/spec/support/rails_app/app/views/events/edit.html.erb +6 -0
- data/spec/support/rails_app/app/views/events/index.html.erb +25 -0
- data/spec/support/rails_app/app/views/events/new.html.erb +5 -0
- data/spec/support/rails_app/app/views/events/show.html.erb +4 -0
- data/spec/support/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/support/rails_app/app/views/users/_form.html.erb +17 -0
- data/spec/support/rails_app/app/views/users/edit.html.erb +6 -0
- data/spec/support/rails_app/app/views/users/index.html.erb +25 -0
- data/spec/support/rails_app/app/views/users/new.html.erb +5 -0
- data/spec/support/rails_app/app/views/users/show.html.erb +4 -0
- data/spec/support/rails_app/bin/bundle +3 -0
- data/spec/support/rails_app/bin/rails +8 -0
- data/spec/support/rails_app/bin/rake +4 -0
- data/spec/support/rails_app/config.ru +0 -0
- data/spec/support/rails_app/config/application.rb +29 -0
- data/spec/support/rails_app/config/boot.rb +3 -0
- data/spec/support/rails_app/config/database.yml +25 -0
- data/spec/support/rails_app/config/environment.rb +5 -0
- data/spec/support/rails_app/config/environments/development.rb +41 -0
- data/spec/support/rails_app/config/environments/production.rb +79 -0
- data/spec/support/rails_app/config/environments/test.rb +42 -0
- data/spec/support/rails_app/config/initializers/assets.rb +11 -0
- data/spec/support/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/support/rails_app/config/initializers/cookies_serializer.rb +3 -0
- data/spec/support/rails_app/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/support/rails_app/config/initializers/inflections.rb +16 -0
- data/spec/support/rails_app/config/initializers/mime_types.rb +4 -0
- data/spec/support/rails_app/config/initializers/session_store.rb +3 -0
- data/spec/support/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/support/rails_app/config/locales/en.yml +23 -0
- data/spec/support/rails_app/config/routes.rb +60 -0
- data/spec/support/rails_app/config/secrets.yml +22 -0
- data/spec/support/rails_app/db/development.sqlite3 +0 -0
- data/spec/support/rails_app/db/migrate/20141231134904_create_users.rb +8 -0
- data/spec/support/rails_app/db/migrate/20150102221633_create_collaborations.rb +13 -0
- data/spec/support/rails_app/db/migrate/20150102225507_create_events.rb +9 -0
- data/spec/support/rails_app/db/migrate/20150104171110_create_discounts.rb +11 -0
- data/spec/support/rails_app/db/schema.rb +45 -0
- data/spec/support/rails_app/db/seeds.rb +7 -0
- data/spec/support/rails_app/db/test.sqlite3 +0 -0
- data/spec/support/rails_app/log/development.log +26296 -0
- data/spec/support/rails_app/public/404.html +67 -0
- data/spec/support/rails_app/public/422.html +67 -0
- data/spec/support/rails_app/public/500.html +66 -0
- data/spec/support/rails_app/public/favicon.ico +0 -0
- data/spec/support/rails_app/public/robots.txt +5 -0
- data/spec/unit/permission_utilities_spec.rb +157 -0
- data/spec/unit/permissions_spec.rb +65 -0
- metadata +352 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
module Authorizable
|
|
2
|
+
# this should be included on the 'User' model or whatever
|
|
3
|
+
# is going to be performing action that need to be
|
|
4
|
+
# authorized
|
|
5
|
+
module Model
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
# @TODO figure out how to make roles generic
|
|
9
|
+
IS_OWNER = 0
|
|
10
|
+
IS_UNRELATED = 1
|
|
11
|
+
|
|
12
|
+
def method_missing(name, *args, &block)
|
|
13
|
+
string_name = name.to_s
|
|
14
|
+
|
|
15
|
+
if string_name =~ /can_(.+)\?/
|
|
16
|
+
permission_name = $1
|
|
17
|
+
permission_name.gsub!('destroy', 'delete')
|
|
18
|
+
if ["delete", "edit", "create"].include?(permission_name)
|
|
19
|
+
# shorthand for delete_{object_name}
|
|
20
|
+
object = args[0]
|
|
21
|
+
object_name = object.class.name.downcase
|
|
22
|
+
return send("can_#{permission_name}_#{object_name}?", *args, &block)
|
|
23
|
+
else
|
|
24
|
+
return process_permission(name, permission_name, args)
|
|
25
|
+
end
|
|
26
|
+
else
|
|
27
|
+
super(name, *args, &block)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def process_permission(method_name, permission_name, args)
|
|
34
|
+
permission = permission_name.to_sym
|
|
35
|
+
o = args[0] # object; Event, Discount, etc
|
|
36
|
+
# default to allow
|
|
37
|
+
result = true
|
|
38
|
+
|
|
39
|
+
role = get_role_of(o)
|
|
40
|
+
|
|
41
|
+
# don't perform the permission evaluation, if we have already computed it
|
|
42
|
+
permission_value_from_cache = value_from_permission_cache(method_name, role)
|
|
43
|
+
return permission_value_from_cache if permission_value_from_cache.present?
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# evaluate procs
|
|
47
|
+
if (proc = PermissionUtilities.has_procs?(permission))
|
|
48
|
+
result &= proc.call(o, self)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Here is where the addition of adding collaborations may reside
|
|
52
|
+
|
|
53
|
+
# finally, determine if the user (self) can do the requested action
|
|
54
|
+
result &= can?(permission, role)
|
|
55
|
+
|
|
56
|
+
# so we don't need to do everything again
|
|
57
|
+
set_permission_cache(
|
|
58
|
+
name: method_name,
|
|
59
|
+
value: result,
|
|
60
|
+
role: role
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
result
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @param [String] permission name of the permission
|
|
67
|
+
# @param [Number] role role of the user
|
|
68
|
+
# @param [Hash] set a hash of string keys and values
|
|
69
|
+
# @return [Boolean] the result of the whether or not the user, self,
|
|
70
|
+
# is allowed to perform the action
|
|
71
|
+
def can?(permission, role = IS_OWNER, set = {})
|
|
72
|
+
result = true
|
|
73
|
+
use_default = false
|
|
74
|
+
|
|
75
|
+
use_default = true if set[permission].nil?
|
|
76
|
+
|
|
77
|
+
if use_default
|
|
78
|
+
result &= PermissionUtilities.value_for(permission, role)
|
|
79
|
+
else
|
|
80
|
+
result &= set[permission]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
result
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# By default this will just be a pass-through to has_role_with
|
|
87
|
+
# This method is intended to be a part of a group/role implementation.
|
|
88
|
+
# for example, if working with a hierarchy of objects, such as a
|
|
89
|
+
# Book having many chapters, and the chapters themselves don't have a User
|
|
90
|
+
# but the Book does, that logic should be added in a method that overrides this one.
|
|
91
|
+
#
|
|
92
|
+
# @param [ActiveRecord::Base] object should be the object that is being tested
|
|
93
|
+
# if the user can perform the action on
|
|
94
|
+
def get_role_of(object)
|
|
95
|
+
return has_role_with(object)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# This method can also be overridden if one desires to have multiple types of
|
|
99
|
+
# ownership, such as a collaborator-type relationship
|
|
100
|
+
#
|
|
101
|
+
# @param [ActiveRecord::Base] object should be the object that is being tested
|
|
102
|
+
# if the user can perform the action on
|
|
103
|
+
# @return [Number] true if self owns object
|
|
104
|
+
def has_role_with(object)
|
|
105
|
+
if object.respond_to?(:user_id)
|
|
106
|
+
if object.user_id == self.id
|
|
107
|
+
return IS_OWNER
|
|
108
|
+
else
|
|
109
|
+
return IS_UNRELATED
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
# hopefully the object passed always responds to user_id
|
|
113
|
+
IS_UNRELATED
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# calculating the value of a permission is costly.
|
|
117
|
+
# there are several Database lookups and lots of merging
|
|
118
|
+
# of hashes.
|
|
119
|
+
# once a permission is calculated, we'll store it here, so we don't
|
|
120
|
+
# have to re-calculate/query/merge everything all over again
|
|
121
|
+
#
|
|
122
|
+
# for both object access and page access, check if we've
|
|
123
|
+
# already calculated the permission
|
|
124
|
+
#
|
|
125
|
+
# the structure of this cache is the following:
|
|
126
|
+
# {
|
|
127
|
+
# role_1: {
|
|
128
|
+
# permission1: true
|
|
129
|
+
# permission2: false
|
|
130
|
+
# },
|
|
131
|
+
# authorization_permission_name: true
|
|
132
|
+
# }
|
|
133
|
+
#
|
|
134
|
+
# @param [String] name name of the permission
|
|
135
|
+
# @param [Number] role role of the user
|
|
136
|
+
# @param [Boolean] value
|
|
137
|
+
def set_permission_cache(name: "", role: nil, value: nil)
|
|
138
|
+
@permission_cache ||= {}
|
|
139
|
+
if role
|
|
140
|
+
@permission_cache[role] ||= {}
|
|
141
|
+
@permission_cache[role][name] = value
|
|
142
|
+
else
|
|
143
|
+
@permission_cache[name] = value
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# @param [String] permission_name name of the permission
|
|
148
|
+
# @param [Number] role role of the user
|
|
149
|
+
# @return [Boolean] value of the previously stored permission
|
|
150
|
+
def value_from_permission_cache(permission_name, role = nil)
|
|
151
|
+
@permission_cache ||= {}
|
|
152
|
+
|
|
153
|
+
if role
|
|
154
|
+
@permission_cache[role] ||= {}
|
|
155
|
+
@permission_cache[role][permission_name]
|
|
156
|
+
else
|
|
157
|
+
@permission_cache[permission_name]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
end
|
|
162
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
module Authorizable
|
|
2
|
+
|
|
3
|
+
module PermissionUtilities
|
|
4
|
+
|
|
5
|
+
KIND = 0
|
|
6
|
+
DEFAULT_ACCESS = 1
|
|
7
|
+
DESCRIPTION = 2
|
|
8
|
+
VISIBILITY_PROC = 3
|
|
9
|
+
ACCESS_PROC = 4
|
|
10
|
+
|
|
11
|
+
OBJECT = 0
|
|
12
|
+
ACCESS = 1
|
|
13
|
+
DEFAULT_ROLE = 0
|
|
14
|
+
|
|
15
|
+
def self.permissions
|
|
16
|
+
Authorizable::Permissions.definitions
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.set_for_role(role)
|
|
20
|
+
permissions.inject({}) { |h,(k, v)|
|
|
21
|
+
value = v[DEFAULT_ACCESS]
|
|
22
|
+
h[k.to_sym] = value.is_a?(Array) ? value[role] : value
|
|
23
|
+
h
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# returns procs or false
|
|
28
|
+
def self.has_procs?(permission)
|
|
29
|
+
permission_data_helper(permission, ACCESS_PROC)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def self.has_visibility_procs?(permission)
|
|
33
|
+
permission_data_helper(permission, VISIBILITY_PROC)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.should_render?(permission, *args)
|
|
37
|
+
result = true
|
|
38
|
+
proc = self.has_visibility_procs?(permission)
|
|
39
|
+
|
|
40
|
+
if proc
|
|
41
|
+
result = proc.call(*args)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
result
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.description_for(permission)
|
|
48
|
+
result = permission_data_helper(permission.to_sym, DESCRIPTION)
|
|
49
|
+
|
|
50
|
+
if result.blank?
|
|
51
|
+
result = permission.to_s.humanize
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
result
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def self.value_for(permission, role = DEFAULT_ROLE)
|
|
58
|
+
value = permissions[permission.to_sym][DEFAULT_ACCESS]
|
|
59
|
+
value.is_a?(Array) ? value[role] : value
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def self.has_key?(permission)
|
|
63
|
+
permissions[permission.to_sym].present?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def self.is_access?(permission)
|
|
67
|
+
permissions[permission][KIND] == ACCESS
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def self.is_object?(permission)
|
|
71
|
+
permissions[permission][KIND] == OBJECT
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def self.permission_data_helper(permission, position)
|
|
77
|
+
result = false
|
|
78
|
+
data = permissions[permission]
|
|
79
|
+
|
|
80
|
+
if data && data.length >= (position + 1)
|
|
81
|
+
result = data[position]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
result
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
module Authorizable
|
|
2
|
+
|
|
3
|
+
class Permissions
|
|
4
|
+
|
|
5
|
+
# Aliased constants for easier typing / readability
|
|
6
|
+
OBJECT = PermissionUtilities::OBJECT
|
|
7
|
+
ACCESS = PermissionUtilities::ACCESS
|
|
8
|
+
|
|
9
|
+
# defaults for a resource
|
|
10
|
+
CRUD_TYPES = {
|
|
11
|
+
edit: OBJECT,
|
|
12
|
+
delete: OBJECT,
|
|
13
|
+
create: OBJECT,
|
|
14
|
+
view: ACCESS
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
# where all the permission definitions are stored
|
|
18
|
+
#
|
|
19
|
+
# example structure:
|
|
20
|
+
# {
|
|
21
|
+
# edit_organization: [OBJECT, [true, false]],
|
|
22
|
+
# delete_organization: [OBJECT, [true, false], nil, ->(e, user){ e.hosted_by == user }, ->(e, user){ e.owner == user }],
|
|
23
|
+
# create_organization: [ACCESS, [true, false], nil, nil],
|
|
24
|
+
#
|
|
25
|
+
# edit_collaborator: [OBJECT, [true, false]],
|
|
26
|
+
# delete_collaborator: [OBJECT, [true, false]],
|
|
27
|
+
# create_collaborator: [OBJECT, [true, false]],
|
|
28
|
+
# view_collaborators: [OBJECT, [true, false]],
|
|
29
|
+
#
|
|
30
|
+
# view_attendees: [OBJECT, true],
|
|
31
|
+
# view_unpaid_attendees: [OBJECT, true],
|
|
32
|
+
# view_cancelled_registrations: [OBJECT, true]
|
|
33
|
+
# }
|
|
34
|
+
#
|
|
35
|
+
# note that because this is a hash, order and organization of like-named
|
|
36
|
+
# permissions is non-existent
|
|
37
|
+
class_attribute :definitions
|
|
38
|
+
|
|
39
|
+
# @example:
|
|
40
|
+
# {
|
|
41
|
+
# update_event: [OBJECT, true, "Edit Event"],
|
|
42
|
+
# delete_event: [OBJECT, [true, false, false], nil, ->(e, user){ e.hosted_by == user }],
|
|
43
|
+
# create_event: [ACCESS, RESTRICT_COLLABORATORS]
|
|
44
|
+
# }
|
|
45
|
+
# CRUD authorizations can be expcitly defined
|
|
46
|
+
#
|
|
47
|
+
# @example
|
|
48
|
+
# {
|
|
49
|
+
# crud: [
|
|
50
|
+
# object_name: [true, false, false],
|
|
51
|
+
# ojbect2_name: true,
|
|
52
|
+
# ]
|
|
53
|
+
# }
|
|
54
|
+
# by providing a :crud array in the hash will generate permissions
|
|
55
|
+
# for the specified object: create, delete, read, and update
|
|
56
|
+
#
|
|
57
|
+
# @note:
|
|
58
|
+
# update is aliased with edit, and may be used interchangeably
|
|
59
|
+
# delete is aliased with destroy, and may be used interchangeably
|
|
60
|
+
#
|
|
61
|
+
# @note:
|
|
62
|
+
# descriptions are not provided by default, and are only specifiable
|
|
63
|
+
# when explicitly defining permissions (not using crud)
|
|
64
|
+
#
|
|
65
|
+
# @param [Hash] permissions
|
|
66
|
+
def self.set(permissions)
|
|
67
|
+
cruds = permissions.delete(:crud)
|
|
68
|
+
|
|
69
|
+
self.definitions = permissions
|
|
70
|
+
|
|
71
|
+
if cruds.present?
|
|
72
|
+
cruds.each do |set|
|
|
73
|
+
set.each do |key, values_for_roles|
|
|
74
|
+
CRUD_TYPES.each do |action, kind|
|
|
75
|
+
permission = "#{action}_#{key}"
|
|
76
|
+
permission << "s" if kind == ACCESS # need a better way to pluralize
|
|
77
|
+
permission = permission.to_sym
|
|
78
|
+
permission_array = [kind, values_for_roles]
|
|
79
|
+
self.definitions[permission] = permission_array
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# similar to how CanCan does the creation of permission
|
|
87
|
+
# but without the need for a user to exist immediately
|
|
88
|
+
#
|
|
89
|
+
# @param [Symbol] name what the permission should be called
|
|
90
|
+
# (the can prefix is automatic, and should be excluded)
|
|
91
|
+
# @param [Boolean] allow (true) default authorization for this permission
|
|
92
|
+
# @param [Array] allow (true) default authorization for this permission
|
|
93
|
+
# @param [String] description (nil) how to explain this permission
|
|
94
|
+
# @param [Proc] visibility (nil) conditions used when rendering this permission in the UI
|
|
95
|
+
# @param [Proc] conditions (nil) additional conditions used when authorizing a user
|
|
96
|
+
# @param [Number] kind (OBJECT) used to specify if this permission takes access on an object or not
|
|
97
|
+
def self.can(name, allow = true, description = nil, visibility = nil, conditions = nil, kind = OBJECT)
|
|
98
|
+
permission_array = [kind, allow, description, visibility, conditions]
|
|
99
|
+
self.add(name, permission_array)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
private
|
|
103
|
+
|
|
104
|
+
# @param [Symbol] key permission name
|
|
105
|
+
# @param [Array] array settings for permission
|
|
106
|
+
def self.add(key, array)
|
|
107
|
+
self.definitions[key.to_sym] = array
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
end
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
describe EventsController, type: :controller do
|
|
4
|
+
|
|
5
|
+
it 'includes authorizable' do
|
|
6
|
+
expect(controller.class.ancestors).to include(Authorizable::Controller)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
it 'calls authorizable' do
|
|
10
|
+
allow_any_instance_of(EventsController).to receive(:authorizable)
|
|
11
|
+
get :index
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
context 'actions' do
|
|
15
|
+
before(:each) do
|
|
16
|
+
EventsController.send(
|
|
17
|
+
:authorizable,
|
|
18
|
+
edit: {
|
|
19
|
+
target: :event,
|
|
20
|
+
redirect_path: Proc.new{ event_path(@event) }
|
|
21
|
+
},
|
|
22
|
+
create: {
|
|
23
|
+
permission: :can_create_event?,
|
|
24
|
+
redirect_path: Proc.new{ events_path }
|
|
25
|
+
},
|
|
26
|
+
destroy: {
|
|
27
|
+
target: :event,
|
|
28
|
+
redirect_path: Proc.new{ event_path(@event) }
|
|
29
|
+
}
|
|
30
|
+
)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
context 'is authorized' do
|
|
34
|
+
let(:user){ create(:user) }
|
|
35
|
+
let(:event){ create(:event, user: user) }
|
|
36
|
+
|
|
37
|
+
it 'is allowed' do
|
|
38
|
+
expect(controller).to receive(:authorizable_authorized?)
|
|
39
|
+
get :edit, id: event.id
|
|
40
|
+
expect(assigns(:event)).to eq event
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'redirects on' do
|
|
45
|
+
|
|
46
|
+
context 'json requests' do
|
|
47
|
+
let(:event){ create(:event) }
|
|
48
|
+
let(:user){ create(:user) }
|
|
49
|
+
|
|
50
|
+
after(:each) do
|
|
51
|
+
expect(response.status).to eq 401
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it 'edit' do
|
|
55
|
+
allow(user).to receive(:can_edit?){ false }
|
|
56
|
+
allow(controller).to receive(:current_user){ user }
|
|
57
|
+
|
|
58
|
+
get :edit, id: event, format: :json
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
context 'html requests' do
|
|
63
|
+
let(:event){ create(:event) }
|
|
64
|
+
let(:user){ create(:user) }
|
|
65
|
+
|
|
66
|
+
after(:each) do
|
|
67
|
+
expect(flash[:alert]).to eq I18n.t('authorizable.not_authorized')
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
context 'edit' do
|
|
71
|
+
before(:each) do
|
|
72
|
+
allow(user).to receive(:can_edit?){ false }
|
|
73
|
+
allow(controller).to receive(:current_user){ user }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it 'to show' do
|
|
77
|
+
get :edit, id: event.id
|
|
78
|
+
expected = { action: :show, id: event.id }
|
|
79
|
+
expect(response).to redirect_to expected
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context 'and update' do
|
|
83
|
+
it 'to show' do
|
|
84
|
+
put :update, id: event.id
|
|
85
|
+
expected = { action: :show, id: event.id }
|
|
86
|
+
expect(response).to redirect_to expected
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context 'create' do
|
|
93
|
+
before(:each) do
|
|
94
|
+
allow(user).to receive(:can_create_event?){ false }
|
|
95
|
+
allow(controller).to receive(:current_user){ user }
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it 'to index' do
|
|
99
|
+
post :create
|
|
100
|
+
expect(response).to redirect_to action: :index
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
context 'and new' do
|
|
104
|
+
it 'to index' do
|
|
105
|
+
get :new
|
|
106
|
+
expect(response).to redirect_to action: :index
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
context 'destroy' do
|
|
113
|
+
before(:each) do
|
|
114
|
+
allow(user).to receive(:can_destroy?).and_return(false)
|
|
115
|
+
allow(controller).to receive(:current_user){ user }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it 'to show' do
|
|
119
|
+
delete :destroy, id: event.id
|
|
120
|
+
expect(response).to redirect_to action: :show
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|