72 |
72 |
73 DEF_GROUP_NOT_FOUND_MSG = ugettext( |
73 DEF_GROUP_NOT_FOUND_MSG = ugettext( |
74 'The requested Group can not be found') |
74 'The requested Group can not be found') |
75 |
75 |
76 |
76 |
77 def checkAccess(access_type, rights, kwargs=None): |
77 def denySidebar(fun): |
78 """Runs all the defined checks for the specified type. |
78 """Decorator that denies access if the sidebar is calling. |
79 |
|
80 Args: |
|
81 access_type: the type of request (such as 'list' or 'edit') |
|
82 rights: a dictionary containing access check functions |
|
83 kwargs: a dictionary with django's arguments |
|
84 |
|
85 Rights usage: |
|
86 The rights dictionary is used to check if the current user is allowed |
|
87 to view the page specified. The functions defined in this dictionary |
|
88 are always called with the provided kwargs dictionary as argument. On any |
|
89 request, regardless of what type, the functions in the 'any_access' value |
|
90 are called. If the specified type is not in the rights dictionary, all |
|
91 the functions in the 'unspecified' value are called. When the specified |
|
92 type _is_ in the rights dictionary, all the functions in that access_type's |
|
93 value are called. |
|
94 """ |
79 """ |
95 |
80 |
96 # Call each access checker |
81 from functools import wraps |
97 for check in rights['any_access']: |
82 |
98 check(kwargs) |
83 @wraps(fun) |
99 |
84 def wrapper(self, django_args, *args, **kwargs): |
100 if access_type not in rights: |
85 if django_args.get('SIDEBAR_CALLING'): |
101 for check in rights['unspecified']: |
86 raise out_of_band.Error("Sidebar Calling") |
102 # No checks defined, so do the 'generic' checks and bail out |
87 return fun(self, django_args, *args, **kwargs) |
103 check(kwargs) |
88 return wrapper |
|
89 |
|
90 |
|
91 class Checker(object): |
|
92 """ |
|
93 The __setitem__() and __getitem__() methods are overloaded to DTRT |
|
94 when adding new access rights, and retrieving them, so use these |
|
95 rather then modifying rights directly if so desired. |
|
96 """ |
|
97 |
|
98 def __init__(self, params): |
|
99 """Adopts base.rights as rights if base is set. |
|
100 """ |
|
101 |
|
102 base = params.get('rights') if params else None |
|
103 self.rights = base.rights if base else {} |
|
104 |
|
105 def __setitem__(self, key, value): |
|
106 """Sets a value only if no old value exists. |
|
107 """ |
|
108 |
|
109 oldvalue = self.rights.get(key) |
|
110 self.rights[key] = oldvalue if oldvalue else value |
|
111 |
|
112 def __getitem__(self, key): |
|
113 """Retrieves the right checkers and massages then into a default format. |
|
114 |
|
115 The result is guaranteed to be a list of 2-tuples, the first element is a |
|
116 checker (iff there is an checker with the specified name), the second |
|
117 element is a list of arguments that should be passed to the checker when |
|
118 calling it in addition to the standard django_args. |
|
119 """ |
|
120 |
|
121 result = [] |
|
122 |
|
123 for i in self.rights.get(key, []): |
|
124 # Be nice an repack so that it is always a list with tuples |
|
125 if isinstance(i, tuple): |
|
126 name, arg = i |
|
127 tmp = (getattr(self, name), (arg if isinstance(arg, list) else [arg])) |
|
128 result.append(tmp) |
|
129 else: |
|
130 tmp = (getattr(self, i), []) |
|
131 result.append(tmp) |
|
132 |
|
133 return result |
|
134 |
|
135 def checkAccess(self, access_type, django_args): |
|
136 """Runs all the defined checks for the specified type. |
|
137 |
|
138 Args: |
|
139 access_type: the type of request (such as 'list' or 'edit') |
|
140 rights: a dictionary containing access check functions |
|
141 django_args: a dictionary with django's arguments |
|
142 |
|
143 Rights usage: |
|
144 The rights dictionary is used to check if the current user is allowed |
|
145 to view the page specified. The functions defined in this dictionary |
|
146 are always called with the provided django_args dictionary as argument. On any |
|
147 request, regardless of what type, the functions in the 'any_access' value |
|
148 are called. If the specified type is not in the rights dictionary, all |
|
149 the functions in the 'unspecified' value are called. When the specified |
|
150 type _is_ in the rights dictionary, all the functions in that access_type's |
|
151 value are called. |
|
152 """ |
|
153 |
|
154 self.id = users.get_current_user() |
|
155 |
|
156 # Call each access checker |
|
157 for check, args in self['any_access']: |
|
158 check(django_args, *args) |
|
159 |
|
160 if access_type not in self.rights: |
|
161 for check, args in self['unspecified']: |
|
162 # No checks defined, so do the 'generic' checks and bail out |
|
163 check(django_args, *args) |
|
164 return |
|
165 |
|
166 for check, args in self[access_type]: |
|
167 check(django_args, *args) |
|
168 |
|
169 def allow(self, django_args): |
|
170 """Never raises an alternate HTTP response. (an access no-op, basically). |
|
171 |
|
172 Args: |
|
173 django_args: a dictionary with django's arguments |
|
174 """ |
|
175 |
104 return |
176 return |
105 |
177 |
106 for check in rights[access_type]: |
178 def deny(self, django_args): |
107 check(kwargs) |
179 """Always raises an alternate HTTP response. |
108 |
180 |
109 |
181 Args: |
110 def allow(kwargs): |
182 django_args: a dictionary with django's arguments |
111 """Never raises an alternate HTTP response. (an access no-op, basically). |
183 |
112 |
184 Raises: |
113 Args: |
185 always raises AccessViolationResponse if called |
114 kwargs: a dictionary with django's arguments |
186 """ |
115 """ |
187 |
116 |
188 context = django_args.get('context', {}) |
117 return |
189 context['title'] = 'Access denied' |
118 |
190 |
119 |
191 raise out_of_band.AccessViolation(DEF_PAGE_DENIED_MSG, context=context) |
120 def deny(kwargs): |
192 |
121 """Always raises an alternate HTTP response. |
193 def checkIsLoggedIn(self, django_args): |
122 |
194 """Raises an alternate HTTP response if Google Account is not logged in. |
123 Args: |
195 |
124 kwargs: a dictionary with django's arguments |
196 Args: |
125 |
197 django_args: a dictionary with django's arguments |
126 Raises: |
198 |
127 always raises AccessViolationResponse if called |
199 Raises: |
128 """ |
200 AccessViolationResponse: |
129 |
201 * if no Google Account is even logged in |
130 import soc.views.helper.responses |
202 """ |
131 |
203 |
132 context = kwargs.get('context', {}) |
204 if self.id: |
133 context['title'] = 'Access denied' |
205 return |
134 |
206 |
135 raise out_of_band.AccessViolation(DEF_PAGE_DENIED_MSG, context=context) |
207 raise out_of_band.LoginRequest() |
136 |
208 |
137 |
209 def checkNotLoggedIn(self, django_args): |
138 def checkIsLoggedIn(kwargs): |
210 """Raises an alternate HTTP response if Google Account is logged in. |
139 """Raises an alternate HTTP response if Google Account is not logged in. |
211 |
140 |
212 Args: |
141 Args: |
213 django_args: a dictionary with django's arguments |
142 kwargs: a dictionary with django's arguments |
214 |
143 |
215 Raises: |
144 Raises: |
216 AccessViolationResponse: |
145 AccessViolationResponse: |
217 * if a Google Account is currently logged in |
146 * if no Google Account is even logged in |
218 """ |
147 """ |
219 |
148 |
220 if not self.id: |
149 if users.get_current_user(): |
221 return |
150 return |
222 |
151 |
223 raise out_of_band.LoginRequest(message_fmt=DEF_LOGOUT_MSG_FMT) |
152 raise out_of_band.LoginRequest() |
224 |
153 |
225 def checkIsUser(self, django_args): |
154 |
226 """Raises an alternate HTTP response if Google Account has no User entity. |
155 def checkNotLoggedIn(kwargs): |
227 |
156 """Raises an alternate HTTP response if Google Account is logged in. |
228 Args: |
157 |
229 django_args: a dictionary with django's arguments |
158 Args: |
230 |
159 kwargs: a dictionary with django's arguments |
231 Raises: |
160 |
232 AccessViolationResponse: |
161 Raises: |
233 * if no User exists for the logged-in Google Account, or |
162 AccessViolationResponse: |
234 * if no Google Account is logged in at all |
163 * if a Google Account is currently logged in |
235 """ |
164 """ |
236 |
165 |
237 self.checkIsLoggedIn(django_args) |
166 if not users.get_current_user(): |
238 |
167 return |
239 user = user_logic.getForCurrentAccount() |
168 |
240 |
169 raise out_of_band.LoginRequest(message_fmt=DEF_LOGOUT_MSG_FMT) |
241 if user: |
170 |
242 return |
171 |
243 |
172 def checkIsUser(kwargs): |
244 raise out_of_band.LoginRequest(message_fmt=DEF_NO_USER_LOGIN_MSG_FMT) |
173 """Raises an alternate HTTP response if Google Account has no User entity. |
245 |
174 |
246 def checkAgreesToSiteToS(self, django_args): |
175 Args: |
247 """Raises an alternate HTTP response if User has not agreed to site-wide ToS. |
176 kwargs: a dictionary with django's arguments |
248 |
177 |
249 Args: |
178 Raises: |
250 django_args: a dictionary with django's arguments |
179 AccessViolationResponse: |
251 |
180 * if no User exists for the logged-in Google Account, or |
252 Raises: |
181 * if no Google Account is logged in at all |
253 AccessViolationResponse: |
182 """ |
254 * if User has not agreed to the site-wide ToS, or |
183 |
255 * if no User exists for the logged-in Google Account, or |
184 checkIsLoggedIn(kwargs) |
256 * if no Google Account is logged in at all |
185 |
257 """ |
186 user = user_logic.getForCurrentAccount() |
258 |
187 |
259 self.checkIsUser(django_args) |
188 if user: |
260 |
189 return |
261 user = user_logic.getForCurrentAccount() |
190 |
262 |
191 raise out_of_band.LoginRequest(message_fmt=DEF_NO_USER_LOGIN_MSG_FMT) |
263 if user_logic.agreesToSiteToS(user): |
192 |
264 return |
193 |
265 |
194 def checkAgreesToSiteToS(kwargs): |
266 # Would not reach this point of site-wide ToS did not exist, since |
195 """Raises an alternate HTTP response if User has not agreed to site-wide ToS. |
267 # agreesToSiteToS() call above always returns True if no ToS is in effect. |
196 |
268 login_msg_fmt = DEF_AGREE_TO_TOS_MSG_FMT % { |
197 Args: |
269 'tos_link': redirects.getToSRedirect(site_logic.getSingleton())} |
198 kwargs: a dictionary with django's arguments |
270 |
199 |
271 raise out_of_band.LoginRequest(message_fmt=login_msg_fmt) |
200 Raises: |
272 |
201 AccessViolationResponse: |
273 def checkIsDeveloper(self, django_args): |
202 * if User has not agreed to the site-wide ToS, or |
274 """Raises an alternate HTTP response if Google Account is not a Developer. |
203 * if no User exists for the logged-in Google Account, or |
275 |
204 * if no Google Account is logged in at all |
276 Args: |
205 """ |
277 django_args: a dictionary with django's arguments |
206 |
278 |
207 checkIsUser(kwargs) |
279 Raises: |
208 |
280 AccessViolationResponse: |
209 user = user_logic.getForCurrentAccount() |
281 * if User is not a Developer, or |
210 |
282 * if no User exists for the logged-in Google Account, or |
211 if user_logic.agreesToSiteToS(user): |
283 * if no Google Account is logged in at all |
212 return |
284 """ |
213 |
285 |
214 # Would not reach this point of site-wide ToS did not exist, since |
286 self.checkAgreesToSiteToS(django_args) |
215 # agreesToSiteToS() call above always returns True if no ToS is in effect. |
287 |
216 login_msg_fmt = DEF_AGREE_TO_TOS_MSG_FMT % { |
288 if accounts.isDeveloper(account=self.id): |
217 'tos_link': redirects.getToSRedirect(site_logic.getSingleton())} |
289 return |
218 |
290 |
219 raise out_of_band.LoginRequest(message_fmt=login_msg_fmt) |
291 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
220 |
292 'role': 'a Site Developer '} |
221 |
293 |
222 def checkIsDeveloper(kwargs): |
294 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
223 """Raises an alternate HTTP response if Google Account is not a Developer. |
295 |
224 |
296 def checkCanMakeRequestToGroup(self, django_args, group_logic): |
225 Args: |
297 """Raises an alternate HTTP response if the specified group is not in an |
226 kwargs: a dictionary with django's arguments |
298 active state. |
227 |
299 |
228 Raises: |
300 Note that state hasn't been implemented yet |
229 AccessViolationResponse: |
301 |
230 * if User is not a Developer, or |
302 Args: |
231 * if no User exists for the logged-in Google Account, or |
303 group_logic: Logic module for the type of group which the request is for |
232 * if no Google Account is logged in at all |
304 """ |
233 """ |
305 |
234 |
|
235 checkAgreesToSiteToS(kwargs) |
|
236 |
|
237 if accounts.isDeveloper(account=users.get_current_user()): |
|
238 return |
|
239 |
|
240 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
241 'role': 'a Site Developer '} |
|
242 |
|
243 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
244 |
|
245 |
|
246 def checkCanMakeRequestToGroup(group_logic): |
|
247 """Raises an alternate HTTP response if the specified group is not in an |
|
248 active state. |
|
249 |
|
250 Note that state hasn't been implemented yet |
|
251 |
|
252 Args: |
|
253 group_logic: Logic module for the type of group which the request is for |
|
254 """ |
|
255 |
|
256 def wrapper(kwargs): |
|
257 group_entity = role_logic.getGroupEntityFromScopePath( |
306 group_entity = role_logic.getGroupEntityFromScopePath( |
258 group_logic.logic, kwargs['scope_path']) |
307 group_logic.logic, django_args['scope_path']) |
259 |
308 |
260 if not group_entity: |
309 if not group_entity: |
261 raise out_of_band.Error(DEF_GROUP_NOT_FOUND_MSG, status=404) |
310 raise out_of_band.Error(DEF_GROUP_NOT_FOUND_MSG, status=404) |
262 |
311 |
263 # TODO(ljvderijk) check if the group is active |
312 # TODO(ljvderijk) check if the group is active |
264 return |
313 return |
265 return wrapper |
314 |
266 |
315 def checkCanCreateFromRequest(self, django_args, role_name): |
267 |
316 """Raises an alternate HTTP response if the specified request does not exist |
268 def checkCanCreateFromRequest(role_name): |
317 or if it's state is not group_accepted. |
269 """Raises an alternate HTTP response if the specified request does not exist |
318 """ |
270 or if it's state is not group_accepted. |
319 |
271 """ |
320 self.checkAgreesToSiteToS(django_args) |
272 |
|
273 def wrapper(kwargs): |
|
274 checkAgreesToSiteToS(kwargs) |
|
275 |
321 |
276 user_entity = user_logic.getForCurrentAccount() |
322 user_entity = user_logic.getForCurrentAccount() |
277 |
323 |
278 if user_entity.link_id != kwargs['link_id']: |
324 if user_entity.link_id != django_args['link_id']: |
279 deny(kwargs) |
325 deny(django_args) |
280 |
326 |
281 fields = {'link_id': kwargs['link_id'], |
327 fields = {'link_id': django_args['link_id'], |
282 'scope_path': kwargs['scope_path'], |
328 'scope_path': django_args['scope_path'], |
283 'role': role_name} |
329 'role': role_name} |
284 |
330 |
285 request_entity = request_logic.getFromFieldsOr404(**fields) |
331 request_entity = request_logic.getFromFieldsOr404(**fields) |
286 |
332 |
287 if request_entity.state != 'group_accepted': |
333 if request_entity.state != 'group_accepted': |
288 # TODO tell the user that this request has not been accepted yet |
334 # TODO tell the user that this request has not been accepted yet |
289 deny(kwargs) |
335 deny(django_args) |
290 |
336 |
291 return |
337 return |
292 |
338 |
293 return wrapper |
339 def checkCanProcessRequest(self, django_args, role_name): |
294 |
340 """Raises an alternate HTTP response if the specified request does not exist |
295 |
341 or if it's state is completed or denied. |
296 def checkCanProcessRequest(role_name): |
342 """ |
297 """Raises an alternate HTTP response if the specified request does not exist |
343 |
298 or if it's state is completed or denied. |
344 fields = {'link_id': django_args['link_id'], |
299 """ |
345 'scope_path': django_args['scope_path'], |
300 |
|
301 def wrapper(kwargs): |
|
302 |
|
303 fields = {'link_id': kwargs['link_id'], |
|
304 'scope_path': kwargs['scope_path'], |
|
305 'role': role_name} |
346 'role': role_name} |
306 |
347 |
307 request_entity = request_logic.getFromFieldsOr404(**fields) |
348 request_entity = request_logic.getFromFieldsOr404(**fields) |
308 |
349 |
309 if request_entity.state in ['completed', 'denied']: |
350 if request_entity.state in ['completed', 'denied']: |
310 # TODO tell the user that this request has been processed |
351 # TODO tell the user that this request has been processed |
311 deny(kwargs) |
352 deny(django_args) |
312 |
353 |
313 return |
354 return |
314 |
355 |
315 return wrapper |
356 def checkIsMyGroupAcceptedRequest(self, django_args): |
316 |
357 """Raises an alternate HTTP response if the specified request does not exist |
317 |
358 or if it's state is not group_accepted. |
318 def checkIsMyGroupAcceptedRequest(kwargs): |
359 """ |
319 """Raises an alternate HTTP response if the specified request does not exist |
360 |
320 or if it's state is not group_accepted. |
361 self.checkAgreesToSiteToS(django_args) |
321 """ |
362 |
322 |
363 user_entity = user_logic.getForCurrentAccount() |
323 checkAgreesToSiteToS(kwargs) |
364 |
324 |
365 if user_entity.link_id != django_args['link_id']: |
325 user_entity = user_logic.getForCurrentAccount() |
366 # not the current user's request |
326 |
367 return deny(django_args) |
327 if user_entity.link_id != kwargs['link_id']: |
368 |
328 # not the current user's request |
369 fields = {'link_id': django_args['link_id'], |
329 return deny(kwargs) |
370 'scope_path': django_args['scope_path'], |
330 |
371 'role': django_args['role']} |
331 fields = {'link_id': kwargs['link_id'], |
372 |
332 'scope_path': kwargs['scope_path'], |
373 request_entity = request_logic.getForFields(fields, unique=True) |
333 'role': kwargs['role']} |
374 |
334 |
375 if not request_entity: |
335 request_entity = request_logic.getForFields(fields, unique=True) |
376 # TODO return 404 |
336 |
377 return deny(django_args) |
337 if not request_entity: |
378 |
338 # TODO return 404 |
379 if request_entity.state != 'group_accepted': |
339 return deny(kwargs) |
380 return deny(django_args) |
340 |
381 |
341 if request_entity.state != 'group_accepted': |
|
342 return deny(kwargs) |
|
343 |
|
344 return |
|
345 |
|
346 |
|
347 def checkIsHost(kwargs): |
|
348 """Raises an alternate HTTP response if Google Account has no Host entity. |
|
349 |
|
350 Args: |
|
351 request: a Django HTTP request |
|
352 |
|
353 Raises: |
|
354 AccessViolationResponse: |
|
355 * if User is not already a Host, or |
|
356 * if User has not agreed to the site-wide ToS, or |
|
357 * if no User exists for the logged-in Google Account, or |
|
358 * if the user is not even logged in |
|
359 """ |
|
360 |
|
361 try: |
|
362 # if the current user is a developer we allow access |
|
363 checkIsDeveloper(kwargs) |
|
364 return |
382 return |
365 except out_of_band.Error: |
383 |
366 pass |
384 @denySidebar |
367 |
385 def checkIsHost(self, django_args): |
368 checkAgreesToSiteToS(kwargs) |
386 """Raises an alternate HTTP response if Google Account has no Host entity. |
369 |
387 |
370 user = user_logic.getForCurrentAccount() |
388 Args: |
371 |
389 request: a Django HTTP request |
372 fields = {'user': user, |
390 |
373 'state': 'active'} |
391 Raises: |
374 |
392 AccessViolationResponse: |
375 host = host_logic.getForFields(fields, unique=True) |
393 * if User is not already a Host, or |
376 |
394 * if User has not agreed to the site-wide ToS, or |
377 if host: |
395 * if no User exists for the logged-in Google Account, or |
378 return |
396 * if the user is not even logged in |
379 |
397 """ |
380 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
398 |
381 'role': 'a Program Administrator '} |
|
382 |
|
383 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
384 |
|
385 |
|
386 def checkIsHostForSponsor(kwargs): |
|
387 """Raises an alternate HTTP response if Google Account has no Host entity |
|
388 for the specified Sponsor. |
|
389 |
|
390 Args: |
|
391 request: a Django HTTP request |
|
392 |
|
393 Raises: |
|
394 AccessViolationResponse: |
|
395 * if User is not already a Host for the specified program, or |
|
396 * if User has not agreed to the site-wide ToS, or |
|
397 * if no User exists for the logged-in Google Account, or |
|
398 * if the user is not even logged in |
|
399 """ |
|
400 |
|
401 try: |
|
402 # if the current user is a developer we allow access |
|
403 checkIsDeveloper(kwargs) |
|
404 return |
|
405 except out_of_band.Error: |
|
406 pass |
|
407 |
|
408 checkAgreesToSiteToS(kwargs) |
|
409 |
|
410 user = user_logic.getForCurrentAccount() |
|
411 |
|
412 if kwargs.get('scope_path'): |
|
413 scope_path = kwargs['scope_path'] |
|
414 else: |
|
415 scope_path = kwargs['link_id'] |
|
416 |
|
417 fields = {'user': user, |
|
418 'scope_path': scope_path, |
|
419 'state': 'active'} |
|
420 |
|
421 host = host_logic.getForFields(fields, unique=True) |
|
422 |
|
423 if host: |
|
424 return |
|
425 |
|
426 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
427 'role': 'a Program Administrator '} |
|
428 |
|
429 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
430 |
|
431 |
|
432 def checkIsClubAdminForClub(kwargs): |
|
433 """Returns an alternate HTTP response if Google Account has no Club Admin |
|
434 entity for the specified club. |
|
435 |
|
436 Args: |
|
437 kwargs: a dictionary with django's arguments |
|
438 |
|
439 Raises: |
|
440 AccessViolationResponse: if the required authorization is not met |
|
441 |
|
442 Returns: |
|
443 None if Club Admin exists for the specified club, or a subclass of |
|
444 django.http.HttpResponse which contains the alternate response |
|
445 should be returned by the calling view. |
|
446 """ |
|
447 |
|
448 try: |
|
449 # if the current user is invited to create a host profile we allow access |
|
450 checkIsDeveloper(kwargs) |
|
451 return |
|
452 except out_of_band.Error: |
|
453 pass |
|
454 |
|
455 checkAgreesToSiteToS(kwargs) |
|
456 |
|
457 user = user_logic.getForCurrentAccount() |
|
458 |
|
459 if kwargs.get('scope_path'): |
|
460 scope_path = kwargs['scope_path'] |
|
461 else: |
|
462 scope_path = kwargs['link_id'] |
|
463 |
|
464 fields = {'user': user, |
|
465 'scope_path': scope_path, |
|
466 'state': 'active'} |
|
467 |
|
468 club_admin_entity = club_admin_logic.getForFields(fields, unique=True) |
|
469 |
|
470 if club_admin_entity: |
|
471 return |
|
472 |
|
473 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
474 'role': 'a Club Admin for this Club'} |
|
475 |
|
476 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
477 |
|
478 |
|
479 def checkIsApplicationAccepted(app_logic): |
|
480 """Returns an alternate HTTP response if Google Account has no Club App |
|
481 entity for the specified Club. |
|
482 |
|
483 Args: |
|
484 kwargs: a dictionary with django's arguments |
|
485 |
|
486 Raises: |
|
487 AccessViolationResponse: if the required authorization is not met |
|
488 |
|
489 Returns: |
|
490 None if Club App exists for the specified program, or a subclass |
|
491 of django.http.HttpResponse which contains the alternate response |
|
492 should be returned by the calling view. |
|
493 """ |
|
494 |
|
495 def wrapper(kwargs): |
|
496 try: |
399 try: |
497 # if the current user is a developer we allow access |
400 # if the current user is a developer we allow access |
498 checkIsDeveloper(kwargs) |
401 self.checkIsDeveloper(django_args) |
499 return |
402 return |
500 except out_of_band.Error: |
403 except out_of_band.Error: |
501 pass |
404 pass |
502 |
405 |
503 checkAgreesToSiteToS(kwargs) |
406 self.checkAgreesToSiteToS(django_args) |
|
407 |
|
408 user = user_logic.getForCurrentAccount() |
|
409 |
|
410 if django_args.get('scope_path'): |
|
411 scope_path = django_args['scope_path'] |
|
412 else: |
|
413 scope_path = django_args['link_id'] |
|
414 |
|
415 fields = {'user': user, |
|
416 'scope_path': scope_path, |
|
417 'state': 'active'} |
|
418 |
|
419 host = host_logic.getForFields(fields, unique=True) |
|
420 |
|
421 self.checkAgreesToSiteToS(django_args) |
|
422 |
|
423 user = user_logic.getForCurrentAccount() |
|
424 |
|
425 fields = {'user': user, |
|
426 'state': 'active'} |
|
427 |
|
428 host = host_logic.getForFields(fields, unique=True) |
|
429 |
|
430 if host: |
|
431 return |
|
432 |
|
433 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
434 'role': 'a Program Administrator '} |
|
435 |
|
436 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
437 |
|
438 def checkIsHostForSponsor(self, django_args): |
|
439 """Raises an alternate HTTP response if Google Account has no Host entity |
|
440 for the specified Sponsor. |
|
441 |
|
442 Args: |
|
443 request: a Django HTTP request |
|
444 |
|
445 Raises: |
|
446 AccessViolationResponse: |
|
447 * if User is not already a Host for the specified program, or |
|
448 * if User has not agreed to the site-wide ToS, or |
|
449 * if no User exists for the logged-in Google Account, or |
|
450 * if the user is not even logged in |
|
451 """ |
|
452 |
|
453 self.checkAgreesToSiteToS(django_args) |
|
454 |
|
455 user = user_logic.getForCurrentAccount() |
|
456 |
|
457 if django_args.get('scope_path'): |
|
458 scope_path = django_args['scope_path'] |
|
459 else: |
|
460 scope_path = django_args['link_id'] |
|
461 |
|
462 fields = {'user': user, |
|
463 'scope_path': scope_path, |
|
464 'state': 'active'} |
|
465 |
|
466 host = host_logic.getForFields(fields, unique=True) |
|
467 |
|
468 if host: |
|
469 return |
|
470 |
|
471 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
472 'role': 'a Program Administrator '} |
|
473 |
|
474 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
475 |
|
476 def checkIsClubAdminForClub(self, django_args): |
|
477 """Returns an alternate HTTP response if Google Account has no Club Admin |
|
478 entity for the specified club. |
|
479 |
|
480 Args: |
|
481 django_args: a dictionary with django's arguments |
|
482 |
|
483 Raises: |
|
484 AccessViolationResponse: if the required authorization is not met |
|
485 |
|
486 Returns: |
|
487 None if Club Admin exists for the specified club, or a subclass of |
|
488 django.http.HttpResponse which contains the alternate response |
|
489 should be returned by the calling view. |
|
490 """ |
|
491 |
|
492 try: |
|
493 # if the current user is invited to create a host profile we allow access |
|
494 checkIsDeveloper(django_args) |
|
495 return |
|
496 except out_of_band.Error: |
|
497 pass |
|
498 |
|
499 self.checkAgreesToSiteToS(django_args) |
|
500 |
|
501 user = user_logic.getForCurrentAccount() |
|
502 |
|
503 if django_args.get('scope_path'): |
|
504 scope_path = django_args['scope_path'] |
|
505 else: |
|
506 scope_path = django_args['link_id'] |
|
507 |
|
508 fields = {'user': user, |
|
509 'scope_path': scope_path, |
|
510 'state': 'active'} |
|
511 |
|
512 club_admin_entity = club_admin_logic.getForFields(fields, unique=True) |
|
513 |
|
514 if club_admin_entity: |
|
515 return |
|
516 |
|
517 login_message_fmt = DEF_DEV_LOGOUT_LOGIN_MSG_FMT % { |
|
518 'role': 'a Club Admin for this Club'} |
|
519 |
|
520 raise out_of_band.LoginRequest(message_fmt=login_message_fmt) |
|
521 |
|
522 def checkIsApplicationAccepted(self, django_args, app_logic): |
|
523 """Returns an alternate HTTP response if Google Account has no Club App |
|
524 entity for the specified Club. |
|
525 |
|
526 Args: |
|
527 django_args: a dictionary with django's arguments |
|
528 |
|
529 Raises: |
|
530 AccessViolationResponse: if the required authorization is not met |
|
531 |
|
532 Returns: |
|
533 None if Club App exists for the specified program, or a subclass |
|
534 of django.http.HttpResponse which contains the alternate response |
|
535 should be returned by the calling view. |
|
536 """ |
|
537 |
|
538 try: |
|
539 # if the current user is a developer we allow access |
|
540 checkIsDeveloper(django_args) |
|
541 return |
|
542 except out_of_band.Error: |
|
543 pass |
|
544 |
|
545 self.checkAgreesToSiteToS(django_args) |
504 |
546 |
505 user = user_logic.getForCurrentAccount() |
547 user = user_logic.getForCurrentAccount() |
506 |
548 |
507 properties = { |
549 properties = { |
508 'applicant': user, |
550 'applicant': user, |
513 |
555 |
514 if application: |
556 if application: |
515 return |
557 return |
516 |
558 |
517 # TODO(srabbelier) Make this give a proper error message |
559 # TODO(srabbelier) Make this give a proper error message |
518 deny(kwargs) |
560 deny(django_args) |
519 |
561 |
520 return wrapper |
562 def checkIsMyNotification(self, django_args): |
521 |
563 """Returns an alternate HTTP response if this request is for |
522 |
564 a Notification belonging to the current user. |
523 def checkIsMyNotification(kwargs): |
565 |
524 """Returns an alternate HTTP response if this request is for |
566 Args: |
525 a Notification belonging to the current user. |
567 django_args: a dictionary with django's arguments |
526 |
568 |
527 Args: |
569 Raises: |
528 kwargs: a dictionary with django's arguments |
570 AccessViolationResponse: if the required authorization is not met |
529 |
571 |
530 Raises: |
572 Returns: |
531 AccessViolationResponse: if the required authorization is not met |
573 None if the current User is allowed to access this Notification. |
532 |
574 """ |
533 Returns: |
575 |
534 None if the current User is allowed to access this Notification. |
|
535 """ |
|
536 |
|
537 try: |
|
538 # if the current user is a developer we allow access |
|
539 checkIsDeveloper(kwargs) |
|
540 return |
|
541 except out_of_band.Error: |
|
542 pass |
|
543 |
|
544 checkAgreesToSiteToS(kwargs) |
|
545 |
|
546 properties = dicts.filter(kwargs, ['link_id', 'scope_path']) |
|
547 |
|
548 notification = notification_logic.getForFields(properties, unique=True) |
|
549 user = user_logic.getForCurrentAccount() |
|
550 |
|
551 # We need to check to see if the key's are equal since the User |
|
552 # objects are different and the default __eq__ method does not check |
|
553 # if the keys are equal (which is what we want). |
|
554 if user.key() == notification.scope.key(): |
|
555 return None |
|
556 |
|
557 # TODO(ljvderijk) Make this give a proper error message |
|
558 deny(kwargs) |
|
559 |
|
560 |
|
561 def checkIsMyApplication(app_logic): |
|
562 """Returns an alternate HTTP response if this request is for |
|
563 a Application belonging to the current user. |
|
564 |
|
565 Args: |
|
566 request: a Django HTTP request |
|
567 |
|
568 Raises: |
|
569 AccessViolationResponse: if the required authorization is not met |
|
570 |
|
571 Returns: |
|
572 None if the current User is allowed to access this Application. |
|
573 """ |
|
574 |
|
575 def wrapper(kwargs): |
|
576 try: |
576 try: |
577 # if the current user is a developer we allow access |
577 # if the current user is a developer we allow access |
578 checkIsDeveloper(kwargs) |
578 checkIsDeveloper(django_args) |
579 return |
579 return |
580 except out_of_band.Error: |
580 except out_of_band.Error: |
581 pass |
581 pass |
582 |
582 |
583 checkAgreesToSiteToS(kwargs) |
583 self.checkAgreesToSiteToS(django_args) |
584 |
584 |
585 properties = dicts.filter(kwargs, ['link_id']) |
585 properties = dicts.filter(django_args, ['link_id', 'scope_path']) |
|
586 |
|
587 notification = notification_logic.getForFields(properties, unique=True) |
|
588 user = user_logic.getForCurrentAccount() |
|
589 |
|
590 # We need to check to see if the key's are equal since the User |
|
591 # objects are different and the default __eq__ method does not check |
|
592 # if the keys are equal (which is what we want). |
|
593 if user.key() == notification.scope.key(): |
|
594 return None |
|
595 |
|
596 # TODO(ljvderijk) Make this give a proper error message |
|
597 deny(django_args) |
|
598 |
|
599 def checkIsMyApplication(self, django_args, app_logic): |
|
600 """Returns an alternate HTTP response if this request is for |
|
601 a Application belonging to the current user. |
|
602 |
|
603 Args: |
|
604 request: a Django HTTP request |
|
605 |
|
606 Raises: |
|
607 AccessViolationResponse: if the required authorization is not met |
|
608 |
|
609 Returns: |
|
610 None if the current User is allowed to access this Application. |
|
611 """ |
|
612 |
|
613 try: |
|
614 # if the current user is a developer we allow access |
|
615 self.checkIsDeveloper(django_args) |
|
616 return |
|
617 except out_of_band.Error: |
|
618 pass |
|
619 |
|
620 self.checkAgreesToSiteToS(django_args) |
|
621 |
|
622 properties = dicts.filter(django_args, ['link_id']) |
586 |
623 |
587 application = app_logic.logic.getForFields(properties, unique=True) |
624 application = app_logic.logic.getForFields(properties, unique=True) |
588 |
625 |
589 if not application: |
626 if not application: |
590 deny(kwargs) |
627 deny(django_args) |
591 |
628 |
592 user = user_logic.getForCurrentAccount() |
629 user = user_logic.getForCurrentAccount() |
593 |
630 |
594 # We need to check to see if the key's are equal since the User |
631 # We need to check to see if the key's are equal since the User |
595 # objects are different and the default __eq__ method does not check |
632 # objects are different and the default __eq__ method does not check |
596 # if the keys are equal (which is what we want). |
633 # if the keys are equal (which is what we want). |
597 if user.key() == application.applicant.key(): |
634 if user.key() == application.applicant.key(): |
598 return None |
635 return None |
599 |
636 |
600 # TODO(srabbelier) Make this give a proper error message |
637 # TODO(srabbelier) Make this give a proper error message |
601 deny(kwargs) |
638 deny(django_args) |
602 |
639 |
603 return wrapper |
640 def checkIsMyActiveRole(self, django_args, role_logic): |
604 |
641 """Returns an alternate HTTP response if there is no active role found for |
605 |
642 the current user using the given role_logic. |
606 def checkIsMyActiveRole(role_logic): |
643 |
607 """Returns an alternate HTTP response if there is no active role found for |
644 Raises: |
608 the current user using the given role_logic. |
645 AccessViolationResponse: if the required authorization is not met |
609 |
646 |
610 Raises: |
647 Returns: |
611 AccessViolationResponse: if the required authorization is not met |
648 None if the current User has no active role for the given role_logic. |
612 |
649 """ |
613 Returns: |
650 |
614 None if the current User has no active role for the given role_logic. |
|
615 """ |
|
616 |
|
617 def wrapper(kwargs): |
|
618 try: |
651 try: |
619 # if the current user is a developer we allow access |
652 # if the current user is a developer we allow access |
620 checkIsDeveloper(kwargs) |
653 checkIsDeveloper(django_args) |
621 return |
654 return |
622 except out_of_band.Error: |
655 except out_of_band.Error: |
623 pass |
656 pass |
624 |
657 |
625 user = user_logic.getForCurrentAccount() |
658 user = user_logic.getForCurrentAccount() |
626 |
659 |
627 if not user or user.link_id != kwargs['link_id']: |
660 if not user or user.link_id != django_args['link_id']: |
628 # not my role |
661 # not my role |
629 deny(kwargs) |
662 deny(django_args) |
630 |
663 |
631 fields = {'link_id': kwargs['link_id'], |
664 fields = {'link_id': django_args['link_id'], |
632 'scope_path': kwargs['scope_path'] |
665 'scope_path': django_args['scope_path'] |
633 } |
666 } |
634 |
667 |
635 role_entity = role_logic.logic.getForFields(fields, unique=True) |
668 role_entity = role_logic.logic.getForFields(fields, unique=True) |
636 |
669 |
637 if not role_entity: |
670 if not role_entity: |
638 # no role found |
671 # no role found |
639 deny(kwargs) |
672 deny(django_args) |
640 |
673 |
641 if role_entity.state == 'active': |
674 if role_entity.state == 'active': |
642 # this role exist and is active |
675 # this role exist and is active |
643 return |
676 return |
644 else: |
677 else: |
645 # this role is not active |
678 # this role is not active |
646 deny(kwargs) |
679 deny(django_args) |
647 |
680 |
648 return wrapper |
681 def checkHasPickGetArgs(self, django_args): |
649 |
682 """Raises an alternate HTTP response if the request misses get args. |
650 |
683 |
651 def checkHasPickGetArgs(kwargs): |
684 Args: |
652 """Raises an alternate HTTP response if the request misses get args. |
685 django_args: a dictionary with django's arguments |
653 |
686 |
654 Args: |
687 Raises: |
655 kwargs: a dictionary with django's arguments |
688 AccessViolationResponse: |
656 |
689 * if continue is not in request.GET |
657 Raises: |
690 * if field is not in request.GET |
658 AccessViolationResponse: |
691 """ |
659 * if continue is not in request.GET |
692 |
660 * if field is not in request.GET |
693 get_args = django_args.get('GET', {}) |
661 """ |
694 |
662 |
695 if 'continue' in get_args and 'field' in get_args: |
663 get_args = kwargs.get('GET', {}) |
696 return |
664 |
697 |
665 if 'continue' in get_args and 'field' in get_args: |
698 #TODO(SRabbelier) inform user that return_url and field are required |
666 return |
699 deny(django_args) |
667 |
700 |
668 #TODO(SRabbelier) inform user that return_url and field are required |
701 def checkIsDocumentPublic(self, django_args): |
669 deny(kwargs) |
702 """Checks whether a document is public. |
670 |
703 |
671 |
704 Args: |
672 def checkIsDocumentPublic(kwargs): |
705 django_args: a dictionary with django's arguments |
673 """Checks whether a document is public. |
706 """ |
674 |
707 |
675 Args: |
708 # TODO(srabbelier): A proper check needs to be done to see if the document |
676 kwargs: a dictionary with django's arguments |
709 # is public or not, probably involving analysing it's scope or such. |
677 """ |
710 allow(django_args) |
678 |
|
679 # TODO(srabbelier): A proper check needs to be done to see if the document |
|
680 # is public or not, probably involving analysing it's scope or such. |
|
681 allow(kwargs) |
|