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