app/soc/views/helper/access.py
changeset 1007 3b66772d21a5
parent 999 71f15c023847
child 1012 73f0b61f2d9d
equal deleted inserted replaced
1006:6abf12b9e646 1007:3b66772d21a5
    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)