fix security issue #36564 (integrity error w/ RQLUniqueConstraint) by using a global lock serializing commit when some RQLUniqueConstraint is encountered.
"""base application's entities class implementation: `AnyEntity`: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.deprecationimportdeprecatedfromlogilab.common.decoratorsimportcachedfromcubicwebimportUnauthorized,typed_eidfromcubicweb.entityimportEntityfromcubicweb.interfacesimportIBreadCrumbs,IFeedclassAnyEntity(Entity):"""an entity instance has e_schema automagically set on the class and instances have access to their issuing cursor """id='Any'__implements__=(IBreadCrumbs,IFeed)fetch_attrs=('modification_date',)@classmethoddeffetch_order(cls,attr,var):"""class method used to control sort order when multiple entities of this type are fetched """returncls.fetch_unrelated_order(attr,var)@classmethoddeffetch_unrelated_order(cls,attr,var):"""class method used to control sort order when multiple entities of this type are fetched to use in edition (eg propose them to create a new relation on an edited entity). """ifattr=='modification_date':return'%s DESC'%varreturnNone# meta data api ###########################################################defdc_title(self):"""return a suitable *unicode* title for this entity"""forrschema,attrschemainself.e_schema.attribute_definitions():ifrschema.meta:continuevalue=self.get_value(rschema.type)ifvalue:# make the value printable (dates, floats, bytes, etc.)returnself.printable_value(rschema.type,value,attrschema.type,format='text/plain')returnu'%s #%s'%(self.dc_type(),self.eid)defdc_long_title(self):"""return a more detailled title for this entity"""returnself.dc_title()defdc_description(self,format='text/plain'):"""return a suitable description for this entity"""if'description'inself.e_schema.subjrels:returnself.printable_value('description',format=format)returnu''defdc_authors(self):"""return a suitable description for the author(s) of the entity"""try:return', '.join(u.name()foruinself.owned_by)exceptUnauthorized:returnu''defdc_creator(self):"""return a suitable description for the creator of the entity"""ifself.creator:returnself.creator.name()returnu''defdc_date(self,date_format=None):# XXX default to ISO 8601 ?"""return latest modification date of this entity"""returnself.format_date(self.modification_date,date_format=date_format)defdc_type(self,form=''):"""return the display name for the type of this entity (translated)"""returnself.e_schema.display_name(self.req,form)defdc_language(self):"""return language used by this entity (translated)"""# check if entities has internationalizable attributes# XXX one is enough or check if all String attributes are internationalizable?forrschema,attrschemainself.e_schema.attribute_definitions():ifrschema.rproperty(self.e_schema,attrschema,'internationalizable'):returnself.req._(self.req.user.property_value('ui.language'))returnself.req._(self.vreg.property_value('ui.language'))@propertydefcreator(self):"""return the CWUser entity which has created this entity, or None if unknown or if the curent user doesn't has access to this euser """try:returnself.created_by[0]except(Unauthorized,IndexError):returnNonedefbreadcrumbs(self,view=None,recurs=False):path=[self]ifhasattr(self,'parent'):parent=self.parent()ifparentisnotNone:try:path=parent.breadcrumbs(view,True)+[self]exceptTypeError:warn("breadcrumbs method's now takes two arguments ""(view=None, recurs=False), please update",DeprecationWarning)path=parent.breadcrumbs(view)+[self]ifnotrecurs:ifviewisNone:if'vtitle'inself.req.form:# embeding for instancepath.append(self.req.form['vtitle'])elifview.id!='primary'andhasattr(view,'title'):path.append(self.req._(view.title))returnpath## IFeed interface ########################################################defrss_feed_url(self):returnself.absolute_url(vid='rss')# abstractions making the whole things (well, some at least) working ######defsortvalue(self,rtype=None):"""return a value which can be used to sort this entity or given entity's attribute """ifrtypeisNone:returnself.dc_title().lower()value=self.get_value(rtype)# do not restrict to `unicode` because Bytes will return a `str` valueifisinstance(value,basestring):returnself.printable_value(rtype,format='text/plain').lower()returnvalue# edition helper functions ################################################deflinked_to(self,rtype,role,remove=True):"""if entity should be linked to another using __linkto form param for the given relation/role, return eids of related entities This method is consuming matching link-to information from form params if `remove` is True (by default). """try:returnself.__linkto[(rtype,role)]exceptAttributeError:self.__linkto={}exceptKeyError:passlinktos=list(self.req.list_form_param('__linkto'))linkedto=[]forlinktoinlinktos[:]:ltrtype,eid,ltrole=linkto.split(':')ifrtype==ltrtypeandrole==ltrole:# delete __linkto from form param to avoid it being added as# hidden inputifremove:linktos.remove(linkto)self.req.form['__linkto']=linktoslinkedto.append(typed_eid(eid))self.__linkto[(rtype,role)]=linkedtoreturnlinkedto# edit controller callbacks ###############################################defafter_deletion_path(self):"""return (path, parameters) which should be used as redirect information when this entity is being deleted """ifhasattr(self,'parent')andself.parent():returnself.parent().rest_path(),{}returnstr(self.e_schema).lower(),{}defpre_web_edit(self):"""callback called by the web editcontroller when an entity will be created/modified, to let a chance to do some entity specific stuff. Do nothing by default. """pass# server side helpers #####################################################defnotification_references(self,view):"""used to control References field of email send on notification for this entity. `view` is the notification view. Should return a list of eids which can be used to generate message ids of previously sent email """return()# XXX deprecates, may be killed once old widgets system is gone ###########@classmethoddefget_widget(cls,rschema,x='subject'):"""return a widget to view or edit a relation notice that when the relation support multiple target types, the widget is necessarily the same for all those types """# let ImportError propage if web par isn't availablefromcubicweb.web.widgetsimportwidgetifisinstance(rschema,basestring):rschema=cls.schema.rschema(rschema)ifx=='subject':tschema=rschema.objects(cls.e_schema)[0]wdg=widget(cls.vreg,cls,rschema,tschema,'subject')else:tschema=rschema.subjects(cls.e_schema)[0]wdg=widget(cls.vreg,tschema,rschema,cls,'object')returnwdg@deprecated('use EntityFieldsForm.subject_relation_vocabulary')defsubject_relation_vocabulary(self,rtype,limit):form=self.vreg.select('forms','edition',self.req,entity=self)returnform.subject_relation_vocabulary(rtype,limit)@deprecated('use EntityFieldsForm.object_relation_vocabulary')defobject_relation_vocabulary(self,rtype,limit):form=self.vreg.select('forms','edition',self.req,entity=self)returnform.object_relation_vocabulary(rtype,limit)@deprecated('use AutomaticEntityForm.[e]relations_by_category')defrelations_by_category(self,categories=None,permission=None):fromcubicweb.web.views.autoformimportAutomaticEntityFormreturnAutomaticEntityForm.erelations_by_category(self,categories,permission)@deprecated('use AutomaticEntityForm.[e]srelations_by_category')defsrelations_by_category(self,categories=None,permission=None):fromcubicweb.web.views.autoformimportAutomaticEntityFormreturnAutomaticEntityForm.esrelations_by_category(self,categories,permission)defattribute_values(self,attrname):ifself.has_eid()orattrnameinself:try:values=self[attrname]exceptKeyError:values=getattr(self,attrname)# actual relation return a list of entitiesifisinstance(values,list):return[v.eidforvinvalues]return(values,)# the entity is being created, try to find default value for# this attributetry:values=self.req.form[attrname]exceptKeyError:try:values=self[attrname]# copyingexceptKeyError:values=getattr(self,'default_%s'%attrname,self.e_schema.default(attrname))ifcallable(values):values=values()ifvaluesisNone:values=()elifnotisinstance(values,(list,tuple)):values=(values,)returnvaluesdefuse_fckeditor(self,attr):"""return True if fckeditor should be used to edit entity's attribute named `attr`, according to user preferences """ifself.req.use_fckeditor()andself.e_schema.has_metadata(attr,'format'):ifself.has_eid()or'%s_format'%attrinself:returnself.attr_metadata(attr,'format')=='text/html'returnself.req.property_value('ui.default-text-format')=='text/html'returnFalse# XXX: store a reference to the AnyEntity class since it is hijacked in goa# configuration and we need the actual reference to avoid infinite loops# in mroANYENTITY=AnyEntitydeffetch_config(fetchattrs,mainattr=None,pclass=AnyEntity,order='ASC'):ifpclassisANYENTITY:pclass=AnyEntity# AnyEntity and ANYENTITY may be different classesifpclassisnotNone:fetchattrs+=pclass.fetch_attrsifmainattrisNone:mainattr=fetchattrs[0]@classmethoddeffetch_order(cls,attr,var):ifattr==mainattr:return'%s%s'%(var,order)returnNonereturnfetchattrs,fetch_order