app/soc/views/models/base.py
changeset 610 e0bd276ffd82
parent 606 65d35584ee31
child 611 2ec30182e5f1
equal deleted inserted replaced
609:45bc26f48090 610:e0bd276ffd82
    64   def __init__(self, params=None):
    64   def __init__(self, params=None):
    65     """
    65     """
    66 
    66 
    67     Args:
    67     Args:
    68       params: This dictionary should be filled with the parameters
    68       params: This dictionary should be filled with the parameters
    69         specific to this entity, required fields are:
    69         specific to this entity. See the methods in this class on
    70         rights: This dictionary should be filled with the access check
    70         the fields it should contain, and how they are used.
    71                 functions that should be called
       
    72         name: the name of the entity (names should have sentence-style caps) 
       
    73         name_short: the short form name of the name ('org' vs 'organization')
       
    74         name_plural: the plural form of the name
       
    75         url_name: the name of the entity used in urls
       
    76         edit_form: the class of the Django form to be used when editing
       
    77         create_form: the class of the Django form to be used when creating
       
    78         edit_template: the Django template to be used for editing
       
    79         public_template: the Django template to be used as public page 
       
    80         list_template: the Django template to be used as list page
       
    81         lists_template: the Django templates to search for the list page
       
    82         delete_redirect: the Django template to redirect to on delete
       
    83         create_redirect: the Django template to redirect to after creation
       
    84         save_message: the message to display when the entity is saved
       
    85         edit_params: the params to use when editing
       
    86         sidebar: the sidebar menu items for this view
       
    87         sidebar_defaults: a dictionary with defaults for the sidebar; each
       
    88           value in the dict is a two-tuple:
       
    89           (url_format,       # supplied a single positional url_name
       
    90            menu_text_format) # supplied the params dict
       
    91     """
    71     """
    92 
    72 
    93     rights = {}
    73     rights = {}
    94     rights['unspecified'] = []
    74     rights['unspecified'] = []
    95     rights['any_access'] = [access.checkIsLoggedIn]
    75     rights['any_access'] = [access.checkIsLoggedIn]
   209         )
   189         )
   210 
   190 
   211   def public(self, request, page_name=None, params=None, **kwargs):
   191   def public(self, request, page_name=None, params=None, **kwargs):
   212     """Displays the public page for the entity specified by **kwargs.
   192     """Displays the public page for the entity specified by **kwargs.
   213 
   193 
       
   194     Params usage:
       
   195       rights: The rights dictionary is used to check if the user has
       
   196         the required rights to view the public page for this entity.
       
   197         See checkAccess for more details on how the rights dictionary
       
   198         is used to check access rights.
       
   199       error_public: The error_public value is used as template when
       
   200         the key values (as defined by the page's url) do not
       
   201         correspond to an existing entity.
       
   202       name: The name value is used to set the entity_type in the
       
   203         context so that the template can refer to it.
       
   204       public_template: The public_template value is used as template
       
   205         to display the public page of the found entity.
       
   206 
   214     Args:
   207     Args:
   215       request: the standard Django HTTP request object
   208       request: the standard Django HTTP request object
   216       page_name: the page name displayed in templates as page and header title
   209       page_name: the page name displayed in templates as page and header title
   217       params: a dict with params for this View
   210       params: a dict with params for this View
   218       kwargs: the Key Fields for the specified entity
   211       kwargs: the Key Fields for the specified entity
   219     """
   212     """
   220 
   213 
   221     params = dicts.merge(params, self._params)
   214     params = dicts.merge(params, self._params)
   222 
   215 
   223     try:
   216     try:
   224       self.checkAccess('public', request)
   217       self.checkAccess('public', request, rights=params['rights'])
   225     except out_of_band.Error, error:
   218     except out_of_band.Error, error:
   226       return error.response(request)
   219       return error.response(request)
   227 
   220 
   228     # create default template context for use with any templates
   221     # create default template context for use with any templates
   229     context = helper.responses.getUniversalContext(request)
   222     context = helper.responses.getUniversalContext(request)
   251     return helper.responses.respond(request, template, context)
   244     return helper.responses.respond(request, template, context)
   252 
   245 
   253   def create(self, request, page_name=None, params=None, **kwargs):
   246   def create(self, request, page_name=None, params=None, **kwargs):
   254     """Displays the create page for this entity type.
   247     """Displays the create page for this entity type.
   255 
   248 
       
   249     Params usage:
       
   250       The params dictionary is passed on to edit, see the docstring
       
   251       for edit on how it uses it.
       
   252 
   256     Args:
   253     Args:
   257       request: the standard Django HTTP request object
   254       request: the standard Django HTTP request object
   258       page_name: the page name displayed in templates as page and header title
   255       page_name: the page name displayed in templates as page and header title
   259       params: a dict with params for this View
   256       params: a dict with params for this View
   260       kwargs: not used for create()
   257       kwargs: not used for create()
   275       return self.edit(request, page_name=page_name, params=params,
   272       return self.edit(request, page_name=page_name, params=params,
   276                        seed=kwargs, **empty_kwargs)
   273                        seed=kwargs, **empty_kwargs)
   277 
   274 
   278   def edit(self, request, page_name=None, params=None, seed=None, **kwargs):
   275   def edit(self, request, page_name=None, params=None, seed=None, **kwargs):
   279     """Displays the edit page for the entity specified by **kwargs.
   276     """Displays the edit page for the entity specified by **kwargs.
       
   277 
       
   278     Params usage:
       
   279       The params dictionary is passed on to either editGet or editPost
       
   280       depending on the method type of the request. See the docstring
       
   281       for editGet and editPost on how they use it.
       
   282 
       
   283       rights: The rights dictionary is used to check if the user has
       
   284         the required rights to edit (or create) a new entity.
       
   285         See checkAccess for more details on how the rights dictionary
       
   286         is used to check access rights.
       
   287       name: The name value is used to construct the message_fmt of the
       
   288         raised error when there key_values do not define an existing
       
   289         entity. See DEF_CREATE_NEW_ENTITY_MSG_FMT on how the name
       
   290         (and the lower() version of it) is used.
       
   291       missing_redirect: The missing_redirect value is also used to
       
   292         construct the message_fmt mentioned above.
       
   293       error_public: The error_public value is used as the template for
       
   294         the error response mentioned above.
   280 
   295 
   281     Args:
   296     Args:
   282       request: the standard Django HTTP request object
   297       request: the standard Django HTTP request object
   283       page_name: the page name displayed in templates as page and header title
   298       page_name: the page name displayed in templates as page and header title
   284       params: a dict with params for this View
   299       params: a dict with params for this View
   314       return self.editPost(request, entity, context, params)
   329       return self.editPost(request, entity, context, params)
   315     else:
   330     else:
   316       return self.editGet(request, entity, context, seed, params)
   331       return self.editGet(request, entity, context, seed, params)
   317 
   332 
   318   def editPost(self, request, entity, context, params):
   333   def editPost(self, request, entity, context, params):
   319     """Same as edit, but on POST.
   334     """Processes POST requests for the specified entity
       
   335 
       
   336     Params usage:
       
   337       The params dictionary is passed to _constructResponse when the
       
   338       form is not valid (see edit_form and create_form below). See
       
   339       the docstring of _constructResponse on how it uses it.
       
   340 
       
   341       edit_form: The edit_form value is used as form when there is an
       
   342         existing entity. It is provided with with the request.POST
       
   343         dictionary on construction. The collectCleanedFields method
       
   344         is called with the newly constructed form. If the form is
       
   345         not valid, it is passed as argument to _constructResponse.
       
   346       create_form: The create_form value is used in a similar way to
       
   347         edit_form, only it is used when there is no existing entity.
       
   348       edit_redirect: The edit_redirect value is used as the first part
       
   349         of the url if the form was valid. The last part of the url is
       
   350         created using the getKeySuffix method of the _logic object.
       
   351       edit_params: The edit_params dictionary is used as argument to
       
   352         redirectToChangedSuffix, it will be appended to the url in the
       
   353         standard ?key=value format.
       
   354 
       
   355     Args:
       
   356       request: a django request object
       
   357       entity: the entity that will be modified or created, may be None
       
   358       context: the context dictionary that will be provided to Django
       
   359       params: a dict with params for this View
   320     """
   360     """
   321 
   361 
   322     params = dicts.merge(params, self._params)
   362     params = dicts.merge(params, self._params)
   323 
   363 
   324     if entity:
   364     if entity:
   351     return helper.responses.redirectToChangedSuffix(
   391     return helper.responses.redirectToChangedSuffix(
   352         request, None, new_suffix,
   392         request, None, new_suffix,
   353         params=page_params)
   393         params=page_params)
   354 
   394 
   355   def editGet(self, request, entity, context, seed, params):
   395   def editGet(self, request, entity, context, seed, params):
   356     """Same as edit, but on GET.
   396     """Processes GET requests for the specified entity
       
   397 
       
   398     Params usage:
       
   399       The params dictionary is passed to _constructResponse, see the
       
   400         docstring  of _constructResponse on how it uses it.
       
   401 
       
   402       save_message: The save_message list is used as argument to
       
   403         getSingleIndexedParamValue when an existing entity was saved.
       
   404       edit_form: The edit_form is used as form if there is an existing
       
   405         entity. The existing entity is passed as instance to it on
       
   406         construction. If key_name is part of it's fields it will be
       
   407         set to the entity's key().name() value. It is also passed as
       
   408         argument to the _editGet method. See the docstring for
       
   409         _editGet on how it uses it.
       
   410       create_form: The create_form is used as form if there was no
       
   411         existing entity. If the seed argument is present, it is passed
       
   412         as the 'initial' argument on construction. Otherwise, it is
       
   413         called with no arguments.
       
   414 
       
   415     Args:
       
   416       request: the django request object
       
   417       entity: the entity that will be edited, may be None
       
   418       context: the context dictionary that will be provided to django
       
   419       seed: if no entity is provided, the initial values for the new entity
       
   420       params: a dict with paras for this View
   357     """
   421     """
   358 
   422 
   359     params = dicts.merge(params, self._params)
   423     params = dicts.merge(params, self._params)
   360     suffix = self._logic.getKeySuffix(entity)
   424     suffix = self._logic.getKeySuffix(entity)
   361 
   425 
   372           request, self.DEF_SUBMIT_MSG_PARAM_NAME,
   436           request, self.DEF_SUBMIT_MSG_PARAM_NAME,
   373           values=params['save_message'])
   437           values=params['save_message'])
   374 
   438 
   375       # populate form with the existing entity
   439       # populate form with the existing entity
   376       form = params['edit_form'](instance=entity)
   440       form = params['edit_form'](instance=entity)
       
   441 
   377       if 'key_name' in form.fields:
   442       if 'key_name' in form.fields:
   378         form.fields['key_name'].initial = entity.key().name()
   443         form.fields['key_name'].initial = entity.key().name()
       
   444 
   379       self._editGet(request, entity, form)
   445       self._editGet(request, entity, form)
   380     else:
   446     else:
   381       if seed:
   447       if seed:
   382         self._editSeed(request, seed)
   448         self._editSeed(request, seed)
   383         form = params['create_form'](initial=seed)
   449         form = params['create_form'](initial=seed)
   392     Args:
   458     Args:
   393       request: the standard Django HTTP request object
   459       request: the standard Django HTTP request object
   394       page_name: the page name displayed in templates as page and header title
   460       page_name: the page name displayed in templates as page and header title
   395       params: a dict with params for this View
   461       params: a dict with params for this View
   396       filter: a dict for the properties that the entities should have
   462       filter: a dict for the properties that the entities should have
       
   463 
       
   464     Params usage:
       
   465       The params dictionary is passed as argument to getListContent in
       
   466         the soc.views.helper.list module. See the docstring for
       
   467         getListContent on how it uses it.
       
   468       The params dictionary is also passed as argument to the _list
       
   469         method. See the docstring for _list on how it uses it.
       
   470 
       
   471       rights: The rights dictionary is used to check if the user has
       
   472         the required rights to list all entities of this View's type.
       
   473         See checkAccess for more details on how the rights dictionary
       
   474         is used to check access rights.
   397     """
   475     """
   398 
   476 
   399     params = dicts.merge(params, self._params)
   477     params = dicts.merge(params, self._params)
   400 
   478 
   401     try:
   479     try:
   402       self.checkAccess('list', request)
   480       self.checkAccess('list', request, rights=params['rights'])
   403     except out_of_band.Error, error:
   481     except out_of_band.Error, error:
   404       return error.response(request)
   482       return error.response(request)
   405 
   483 
   406     content = helper.lists.getListContent(request, params, self._logic, filter)
   484     content = helper.lists.getListContent(request, params, self._logic, filter)
   407     contents = [content]
   485     contents = [content]
   414     Args:
   492     Args:
   415       request: the standard Django HTTP request object
   493       request: the standard Django HTTP request object
   416       params: a dict with params for this View
   494       params: a dict with params for this View
   417       contents: a list of content dicts
   495       contents: a list of content dicts
   418       page_name: the page name displayed in templates as page and header title
   496       page_name: the page name displayed in templates as page and header title
       
   497 
       
   498     Params usage:
       
   499       name: The name value is used to set the entity_type in the
       
   500         context so that the template can refer to it.
       
   501       name_plural: The name_plural value is used to set
       
   502         the entity_type_plural value in the context so that the
       
   503         template can refer to it.
       
   504       list_template: The list_template value is used as template for
       
   505         to display the list of all entities for this View.
   419     """
   506     """
   420 
   507 
   421     context = helper.responses.getUniversalContext(request)
   508     context = helper.responses.getUniversalContext(request)
   422     context['page_name'] = page_name
   509     context['page_name'] = page_name
   423     context['list'] = soc.logic.lists.Lists(contents)
   510     context['list'] = soc.logic.lists.Lists(contents)
   435     Args:
   522     Args:
   436       request: the standard Django HTTP request object
   523       request: the standard Django HTTP request object
   437       page_name: the page name displayed in templates as page and header title
   524       page_name: the page name displayed in templates as page and header title
   438       params: a dict with params for this View
   525       params: a dict with params for this View
   439       kwargs: The Key Fields for the specified entity
   526       kwargs: The Key Fields for the specified entity
       
   527 
       
   528     Params usage:
       
   529       rights: The rights dictionary is used to check if the user has
       
   530         the required rights to delete the specified entity.
       
   531         See checkAccess for more details on how the rights dictionary
       
   532         is used to check access rights.
       
   533       name: used in the same way as in edit(), see it's docstring for
       
   534         a more detailed explanation on how it is used.
       
   535       missing_redirect: see name
       
   536       error_edit: see name
       
   537       delete_redirect: The delete_redirect value is used as the url to
       
   538         redirect to after having successfully deleted the entity.
   440     """
   539     """
   441 
   540 
   442     params = dicts.merge(params, self._params)
   541     params = dicts.merge(params, self._params)
   443 
   542 
   444     try:
   543     try:
   445       self.checkAccess('delete', request)
   544       self.checkAccess('delete', request, rights=params['rights'])
   446     except out_of_band.Error, error:
   545     except out_of_band.Error, error:
   447       return error.response(request)
   546       return error.response(request)
   448 
   547 
   449     # create default template context for use with any templates
   548     # create default template context for use with any templates
   450     context = helper.responses.getUniversalContext(request)
   549     context = helper.responses.getUniversalContext(request)
   531   def _constructResponse(self, request, entity, context, form, params):
   630   def _constructResponse(self, request, entity, context, form, params):
   532     """Updates the context and returns a response for the specified arguments.
   631     """Updates the context and returns a response for the specified arguments.
   533 
   632 
   534     Args:
   633     Args:
   535       request: the django request object
   634       request: the django request object
   536       entity: the entity that is used
   635       entity: the entity that is used and set in the context
   537       context: the context to be used
   636       context: the context to be used
   538       form: the form that will be used
   637       form: the form that will be used and set in the context
   539       params: a dict with params for this View
   638       params: a dict with params for this View
       
   639 
       
   640     Params usage:
       
   641       name: The name_plural value is used to set the entity_type
       
   642        value in the context so that the template can refer to it.
       
   643       name_plural: same as name, but used to set entity_type_plural
       
   644       name_short: same as name, but used to set entity_type_short
       
   645       url_name: same as name, but used to set entity_type_url
       
   646       edit_template: The edit_template value is used as template when
       
   647         there is an existing entity to display the edit page for the
       
   648         specified entity.
       
   649       create_template: similar to edit_template, but is used when
       
   650         there is no existing entity.
   540     """
   651     """
   541 
   652 
   542     suffix = self._logic.getKeySuffix(entity)
   653     suffix = self._logic.getKeySuffix(entity)
   543 
   654 
   544     context['form'] = form
   655     context['form'] = form
   560     """Runs all the defined checks for the specified type
   671     """Runs all the defined checks for the specified type
   561 
   672 
   562     Args:
   673     Args:
   563       access_type: the type of request (such as 'list' or 'edit')
   674       access_type: the type of request (such as 'list' or 'edit')
   564       request: the Django request object
   675       request: the Django request object
       
   676       rights: A dictionary containing access check functions
       
   677 
       
   678     Rights usage: The rights dictionary is used to check if the
       
   679       current user is allowed to view the page specified. The
       
   680       functions defined in this dictionary are always called with the
       
   681       django request object as argument.
       
   682       On any request, regardless of what type, the functions in the
       
   683       'any_access' value are called.
       
   684       If the specified type is not in the rights dictionary, all the
       
   685       functions in the 'unspecified' value are called.
       
   686       When the specified type _is_ in the rights dictionary, all the
       
   687       functions in that access_type's value are called.
   565 
   688 
   566     Returns:
   689     Returns:
   567       True: If all the required access checks have been made successfully
   690       True: If all the required access checks have been made successfully
   568       False: If a check failed, in this case self._response will contain
   691       False: If a check failed, in this case self._response will contain
   569              the response provided by the failed access check.
   692              the response provided by the failed access check.
   575     for check in rights['any_access']:
   698     for check in rights['any_access']:
   576       check(request)
   699       check(request)
   577 
   700 
   578     if access_type not in rights:
   701     if access_type not in rights:
   579       for check in rights['unspecified']:
   702       for check in rights['unspecified']:
   580         # No checks defined, so do the 'generic check' and bail out
   703         # No checks defined, so do the 'generic' checks and bail out
   581         check(request)
   704         check(request)
   582       return
   705       return
   583 
   706 
   584     for check in rights[access_type]:
   707     for check in rights[access_type]:
   585       check(request)
   708       check(request)
   587   def collectCleanedFields(self, form):
   710   def collectCleanedFields(self, form):
   588     """Collects all cleaned fields and returns them with the key_name.
   711     """Collects all cleaned fields and returns them with the key_name.
   589 
   712 
   590     Args:
   713     Args:
   591       form: The form from which the cleaned fields should be collected
   714       form: The form from which the cleaned fields should be collected
       
   715 
       
   716     Returns: All the fields that are in the form's cleaned_data
       
   717     property are returned. If there is a key_name field, it is not
       
   718     included in the returend fields, instead, it is returned as the
       
   719     first element in the returned tuple. If no key_name field is
       
   720     present, None is returned as first value instead.
   592     """
   721     """
   593 
   722 
   594     fields = {}
   723     fields = {}
   595 
   724 
   596     key_name = None
   725     key_name = None
   601       fields[field] = value
   730       fields[field] = value
   602 
   731 
   603     return key_name, fields
   732     return key_name, fields
   604 
   733 
   605   def getKeyFieldsPattern(self, params):
   734   def getKeyFieldsPattern(self, params):
   606     """
   735     """Returns the Django pattern for this View's entity
       
   736 
       
   737     Params usage:
       
   738       key_fields_prefix: The key_fields_prefix value is used as the
       
   739       first part of the returned pattern.
   607     """
   740     """
   608 
   741 
   609     names = self._logic.getKeyFieldNames()
   742     names = self._logic.getKeyFieldNames()
   610     patterns = params['key_fields_prefix']
   743     patterns = params['key_fields_prefix']
   611 
   744 
   615 
   748 
   616     result = '/'.join(patterns)
   749     result = '/'.join(patterns)
   617     return result
   750     return result
   618 
   751 
   619   def _getSidebarItems(self, params):
   752   def _getSidebarItems(self, params):
   620     """Retrieves a list of sidebar entries for this view from self._params.
   753     """Retrieves a list of sidebar entries for this view
   621 
   754 
   622     If params['sidebar'] is None default entries will be constructed 
   755     Params usage:
       
   756       The params dictionary is provided to the menu_text's format.
       
   757 
       
   758       sidebar: The sidebar value is returned directly if non-False
       
   759       sidebar_defaults: The sidebar_defaults are used to construct the
       
   760         sidebar items for this View. It is expected to be a tuple of
       
   761         three items, the item's url, it's menu_text, and it's
       
   762         access_type, see getSidebarLinks on how access_type is used.
       
   763       sidebar_additional: The sidebar_additional values are appended
       
   764         to the list of items verbatim, and should be in the format
       
   765         expected by getSidebarLinks.
       
   766 
       
   767     Args:
       
   768       params: a dict with params for this View.
   623     """
   769     """
   624 
   770 
   625     # Return the found result
   771     # Return the found result
   626     if params['sidebar']:
   772     if params['sidebar']:
   627       return params['sidebar']
   773       return params['sidebar']
   642     return result
   788     return result
   643 
   789 
   644   def getSidebarLinks(self, request, params=None):
   790   def getSidebarLinks(self, request, params=None):
   645     """Returns an dictionary with one sidebar entry.
   791     """Returns an dictionary with one sidebar entry.
   646 
   792 
   647     Args:
   793     Calls _getSidebarItems to retrieve the items that should be in the
   648       params: see __init__
   794     menu. Expected is a tuple with an url, a menu_text, and an
       
   795     access_type. The access_type is then passed to checkAccess, if it
       
   796     raises out_of_band.Error, the item will not be added.
       
   797 
       
   798     Args:
       
   799       request: the django request object
       
   800       params: a dict with params for this View
       
   801 
       
   802     Params usage:
       
   803       The params dictionary is passed as argument to _getSidebarItems,
       
   804         see the docstring of _getSidebarItems on how it uses it.
       
   805 
       
   806       rights: The rights dictionary is used to check if the user has
       
   807         the required rights to see a sidebar item.
       
   808         See checkAccess for more details on how the rights dictionary
       
   809         is used to check access rights.
       
   810       sidebar_heading: The sidebar_heading value is used to set the
       
   811         heading variable in the result.
       
   812       name: The name value is used if sidebar_heading is not present.
       
   813 
       
   814     Returns: A dictionary is returned with it's 'heading' value set
       
   815       as explained above. It's 'items' value is constructed by
       
   816       calling _getSidebarItems. It constists of dictionaries with a
       
   817       url and a title field.
   649     """
   818     """
   650 
   819 
   651     params = dicts.merge(params, self._params)
   820     params = dicts.merge(params, self._params)
   652     rights = params['rights']
   821     rights = params['rights']
   653 
   822 
   676   def getDjangoURLPatterns(self, params=None):
   845   def getDjangoURLPatterns(self, params=None):
   677     """Retrieves a list of sidebar entries for this view from self._params.
   846     """Retrieves a list of sidebar entries for this view from self._params.
   678 
   847 
   679     If self._params['django_patterns'] is None default entries will be
   848     If self._params['django_patterns'] is None default entries will be
   680     constructed.
   849     constructed.
       
   850 
       
   851     Params usage:
       
   852       The params dictionary is passed to the getKeyFieldsPatterns
       
   853         method, see it's docstring on how it is used.
       
   854       django_patterns: The django_patterns value is returned directly
       
   855         if it is non-False.
       
   856       django_patterns_defaults: The dajngo_patterns_defaults value is
       
   857         used to construct the url patterns. It is expected to be a
       
   858         list of tuples. The tuples should contain an url, a module
       
   859         name, and the name of the url. The name is used as the
       
   860         page_name passed as keyword argument, but also as the name
       
   861         by which the url is known to Django internally.
       
   862       url_name: The url_name argument is passed as argument to each
       
   863         url, together with the link_id pattern, the link_id core
       
   864         pattern, and the key fields for this View.
       
   865 
       
   866     Args:
       
   867       params: a dict with params for this View
   681     """
   868     """
   682 
   869 
   683     params = dicts.merge(params, self._params)
   870     params = dicts.merge(params, self._params)
   684 
   871 
   685     # Return the found result
   872     # Return the found result