[dbapi] fix user handling on dbapi request. Avoid getting None as _user and remove the need for a property.
"""abstract form classes for CubicWeb web client:organization: Logilab:copyright: 2001-2010 LOGILAB S.A. (Paris, FRANCE), license is LGPL v2.:contact: http://www.logilab.fr/ -- mailto:contact@logilab.fr:license: GNU Lesser General Public License, v2.1 - http://www.gnu.org/licenses"""__docformat__="restructuredtext en"fromwarningsimportwarnfromlogilab.common.decoratorsimporticlassmethodfromlogilab.common.deprecationimportdeprecatedfromcubicweb.appobjectimportAppObjectfromcubicweb.viewimportNOINDEX,NOFOLLOWfromcubicweb.webimporthttpcache,formfields,controllerclassFormViewMixIn(object):"""abstract form view mix-in"""category='form'http_cache_manager=httpcache.NoHTTPCacheManageradd_to_breadcrumbs=Falsedefhtml_headers(self):"""return a list of html headers (eg something to be inserted between <head> and </head> of the returned page by default forms are neither indexed nor followed """return[NOINDEX,NOFOLLOW]deflinkable(self):"""override since forms are usually linked by an action, so we don't want them to be listed by appli.possible_views """returnFalse###############################################################################classmetafieldsform(type):"""metaclass for FieldsForm to retrieve fields defined as class attributes and put them into a single ordered list: '_fields_'. """def__new__(mcs,name,bases,classdict):allfields=[]forbaseinbases:ifhasattr(base,'_fields_'):allfields+=base._fields_clsfields=(itemforiteminclassdict.items()ifisinstance(item[1],formfields.Field))forfieldname,fieldinsorted(clsfields,key=lambdax:x[1].creation_rank):ifnotfield.name:field.set_name(fieldname)allfields.append(field)classdict['_fields_']=allfieldsreturnsuper(metafieldsform,mcs).__new__(mcs,name,bases,classdict)classFieldNotFound(Exception):"""raised by field_by_name when a field with the given name has not been found """classForm(AppObject):__metaclass__=metafieldsform__registry__='forms'internal_fields=('__errorurl',)+controller.NAV_FORM_PARAMETERSparent_form=Noneforce_session_key=Nonedomid='form'copy_nav_params=Falsedef__init__(self,req,rset=None,row=None,col=None,submitmsg=None,mainform=True,**kwargs):super(Form,self).__init__(req,rset=rset,row=row,col=col)self.fields=list(self.__class__._fields_)ifmainform:self.add_hidden(u'__form_id',kwargs.pop('formvid',self.__regid__))forkey,valinkwargs.iteritems():ifkeyincontroller.NAV_FORM_PARAMETERS:self.add_hidden(key,val)elifkey=='redirect_path':self.add_hidden(u'__redirectpath',val)elifhasattr(self.__class__,key)andnotkey[0]=='_':setattr(self,key,val)else:self.cw_extra_kwargs[key]=val# skip other parameters, usually given for selection# (else write a custom class to handle them)ifmainform:self.add_hidden(u'__errorurl',self.session_key())self.add_hidden(u'__domid',self.domid)self.restore_previous_post(self.session_key())# XXX why do we need two different variables (mainform and copy_nav_params ?)ifself.copy_nav_params:forparamincontroller.NAV_FORM_PARAMETERS:ifnotparaminkwargs:value=req.form.get(param)ifvalue:self.add_hidden(param,value)ifsubmitmsgisnotNone:self.add_hidden(u'__message',submitmsg)@propertydefroot_form(self):"""return the root form"""ifself.parent_formisNone:returnselfreturnself.parent_form.root_form@propertydefform_valerror(self):"""the validation error exception if any"""ifself.parent_formisNone:returnself._form_valerrorreturnself.parent_form.form_valerror@propertydefform_previous_values(self):"""previously posted values (on validation error)"""ifself.parent_formisNone:returnself._form_previous_valuesreturnself.parent_form.form_previous_values@iclassmethoddef_fieldsattr(cls_or_self):ifisinstance(cls_or_self,type):fields=cls_or_self._fields_else:fields=cls_or_self.fieldsreturnfields@iclassmethoddeffield_by_name(cls_or_self,name,role=None):"""return field with the given name and role. Raise FieldNotFound if the field can't be found. """forfieldincls_or_self._fieldsattr():iffield.name==nameandfield.role==role:returnfieldraiseFieldNotFound(name,role)@iclassmethoddeffields_by_name(cls_or_self,name,role=None):"""return a list of fields with the given name and role"""return[fieldforfieldincls_or_self._fieldsattr()iffield.name==nameandfield.role==role]@iclassmethoddefremove_field(cls_or_self,field):"""remove a field from form class or instance"""cls_or_self._fieldsattr().remove(field)@iclassmethoddefappend_field(cls_or_self,field):"""append a field to form class or instance"""cls_or_self._fieldsattr().append(field)@iclassmethoddefinsert_field_before(cls_or_self,new_field,name,role='subject'):field=cls_or_self.field_by_name(name,role)fields=cls_or_self._fieldsattr()fields.insert(fields.index(field),new_field)@iclassmethoddefinsert_field_after(cls_or_self,new_field,name,role='subject'):field=cls_or_self.field_by_name(name,role)fields=cls_or_self._fieldsattr()fields.insert(fields.index(field)+1,new_field)defsession_key(self):"""return the key that may be used to store / retreive data about a previous post which failed because of a validation error """ifself.force_session_keyisNone:return'%s#%s'%(self._cw.url(),self.domid)returnself.force_session_keydefrestore_previous_post(self,sessionkey):# get validation session data which may have been previously set.# deleting validation errors here breaks form reloading (errors are# no more available), they have to be deleted by application's publish# method on successful commitifhasattr(self,'_form_previous_values'):# XXX behaviour changed in 3.6.1, warnwarn('[3.6.1] restore_previous_post already called, remove this call',DeprecationWarning,stacklevel=2)returnforminfo=self._cw.session.data.pop(sessionkey,None)ifforminfo:self._form_previous_values=forminfo['values']self._form_valerror=forminfo['error']# if some validation error occured on entity creation, we have to# get the original variable name from its attributed eidforeid=self.form_valerror.entityforvar,eidinforminfo['eidmap'].items():ifforeid==eid:self.form_valerror.eid=varbreakelse:self.form_valerror.eid=foreidelse:self._form_previous_values={}self._form_valerror=Nonedeffield_error(self,field):"""return field's error if specified in current validation exception"""ifself.form_valerror:iffield.eidparamandself.edited_entity.eid!=self.form_valerror.eid:returnNonetry:returnself.form_valerror.errors.pop(field.role_name())exceptKeyError:iffield.roleandfield.nameinself.form_valerror:warn('%s: errors key of attribute/relation should be suffixed by "-<role>"'%self.form_valerror.__class__,DeprecationWarning)returnself.form_valerror.errors.pop(field.name)returnNonedefremaining_errors(self):returnsorted(self.form_valerror.errors.items())@deprecated('[3.6] use form.field_error and/or new renderer.render_error method')defform_field_error(self,field):"""return validation error for widget's field, if any"""err=self.field_error(field)iferr:returnu'<span class="error">%s</span>'%errreturnu''