-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathdefault_pundit_authorizer.rb
229 lines (211 loc) · 8.28 KB
/
default_pundit_authorizer.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
module JSONAPI
module Authorization
# An authorizer is a class responsible for linking JSONAPI operations to
# your choice of authorization mechanism.
#
# This class uses Pundit for authorization. It does not yet support all
# the available operations — you can use your own authorizer class instead
# if you have different needs. See the README.md for configuration
# information.
#
# Fetching records is the concern of +PunditScopedResource+ which in turn
# affects which records end up being passed here.
class DefaultPunditAuthorizer
attr_reader :user
# Creates a new DefaultPunditAuthorizer instance
#
# ==== Parameters
#
# * +context+ - The context passed down from the controller layer
def initialize(context)
@user = JSONAPI::Authorization.configuration.user_context(context)
end
# <tt>GET /resources</tt>
#
# ==== Parameters
#
# * +source_class+ - The source class (e.g. +Article+ for +ArticleResource+)
def find(source_class)
::Pundit.authorize(user, source_class, 'index?')
end
# <tt>GET /resources/:id</tt>
#
# ==== Parameters
#
# * +source_record+ - The record to show
def show(source_record)
::Pundit.authorize(user, source_record, 'show?')
end
# <tt>GET /resources/:id/relationships/other-resources</tt>
# <tt>GET /resources/:id/relationships/another-resource</tt>
#
# A query for a +has_one+ or a +has_many+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is queried
# * +related_record+ - The associated +has_one+ record to show or +nil+
# if the associated record was not found. For a +has_many+ association,
# this will always be +nil+
def show_relationship(source_record, related_record)
::Pundit.authorize(user, source_record, 'show?')
::Pundit.authorize(user, related_record, 'show?') unless related_record.nil?
end
# <tt>GET /resources/:id/another-resource</tt>
#
# A query for a record through a +has_one+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is queried
# * +related_record+ - The associated record to show or +nil+ if the
# associated record was not found
def show_related_resource(source_record, related_record)
::Pundit.authorize(user, source_record, 'show?')
::Pundit.authorize(user, related_record, 'show?') unless related_record.nil?
end
# <tt>GET /resources/:id/other-resources</tt>
#
# A query for records through a +has_many+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is queried
def show_related_resources(source_record)
::Pundit.authorize(user, source_record, 'show?')
end
# <tt>PATCH /resources/:id</tt>
#
# ==== Parameters
#
# * +source_record+ - The record to be modified
# * +new_related_records+ - An array of records to be associated to the
# +source_record+. This will contain the records specified in the
# "relationships" key in the request
#--
# TODO: Should probably take old records as well
def replace_fields(source_record, new_related_records)
::Pundit.authorize(user, source_record, 'update?')
new_related_records.each do |record|
::Pundit.authorize(user, record, 'update?')
end
end
# <tt>POST /resources</tt>
#
# ==== Parameters
#
# * +source_class+ - The class of the record to be created
# * +related_records+ - An array of records to be associated to the new
# record. This will contain the records specified in the
# "relationships" key in the request
def create_resource(source_class, related_records)
::Pundit.authorize(user, source_class, 'create?')
related_records.each do |record|
::Pundit.authorize(user, record, 'update?')
end
end
# <tt>DELETE /resources/:id</tt>
#
# ==== Parameters
#
# * +source_record+ - The record to be removed
def remove_resource(source_record)
::Pundit.authorize(user, source_record, 'destroy?')
end
# <tt>PATCH /resources/:id/relationships/another-resource</tt>
#
# A replace request for a +has_one+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is modified
# * +old_related_record+ - The current associated record
# * +new_related_record+ - The new record replacing the +old_record+
# association, or +nil+ if the association is to be cleared
def replace_to_one_relationship(source_record, old_related_record, new_related_record)
raise NotImplementedError
end
# <tt>POST /resources/:id/relationships/other-resources</tt>
#
# A request for adding to a +has_many+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is modified
# * +new_related_records+ - The new records to be added to the association
def create_to_many_relationship(source_record, new_related_records)
raise NotImplementedError
end
# <tt>PATCH /resources/:id/relationships/other-resources</tt>
#
# A replace request for a +has_many+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is modified
# * +new_related_records+ - The new records replacing the entire +has_many+
# association
#--
# TODO: Should probably take old records as well
def replace_to_many_relationship(source_record, new_related_records)
raise NotImplementedError
end
# <tt>DELETE /resources/:id/relationships/other-resources</tt>
#
# A request to deassociate elements of a +has_many+ association
#
# NOTE: this is called once per related record, not all at once
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is modified
# * +related_record+ - The record which will be deassociatied from +source_record+
def remove_to_many_relationship(source_record, related_record)
raise NotImplementedError
end
# <tt>DELETE /resources/:id/relationships/another-resource</tt>
#
# A request to deassociate a +has_one+ association
#
# ==== Parameters
#
# * +source_record+ - The record whose relationship is modified
# * +related_record+ - The record which will be deassociatied from +source_record+
def remove_to_one_relationship(source_record, related_record)
raise NotImplementedError
end
# Any request including <tt>?include=other-resources</tt>
#
# This will be called for each has_many relationship if the include goes
# deeper than one level until some authorization fails or the include
# directive has been travelled completely.
#
# We can't pass all the records of a +has_many+ association here due to
# performance reasons, so the class is passed instead.
#
# ==== Parameters
#
# * +source_record+ — The source relationship record, e.g. an Article in
# article.comments check
# * +record_class+ - The underlying record class for the relationships
# resource.
def include_has_many_resource(source_record, record_class)
::Pundit.authorize(user, record_class, 'index?')
end
# Any request including <tt>?include=another-resource</tt>
#
# This will be called for each has_one relationship if the include goes
# deeper than one level until some authorization fails or the include
# directive has been travelled completely.
#
# ==== Parameters
#
# * +source_record+ — The source relationship record, e.g. an Article in
# article.author check
# * +related_record+ - The associated record to return
def include_has_one_resource(source_record, related_record)
::Pundit.authorize(user, related_record, 'show?')
end
end
end
end