hooks/integrity.py
changeset 2847 c2ee28f4d4b1
parent 2841 107ba1c45227
child 2896 1e7848c69be4
equal deleted inserted replaced
2846:e71d6a585b83 2847:c2ee28f4d4b1
    72     def __call__(self):
    72     def __call__(self):
    73         getattr(self, self.event)()
    73         getattr(self, self.event)()
    74 
    74 
    75     def checkrel_if_necessary(self, opcls, rtype, eid):
    75     def checkrel_if_necessary(self, opcls, rtype, eid):
    76         """check an equivalent operation has not already been added"""
    76         """check an equivalent operation has not already been added"""
    77         for op in self.cw_req.pending_operations:
    77         for op in self._cw.pending_operations:
    78             if isinstance(op, opcls) and op.rtype == rtype and op.eid == eid:
    78             if isinstance(op, opcls) and op.rtype == rtype and op.eid == eid:
    79                 break
    79                 break
    80         else:
    80         else:
    81             opcls(self.cw_req, rtype=rtype, eid=eid)
    81             opcls(self._cw, rtype=rtype, eid=eid)
    82 
    82 
    83     def after_add_entity(self):
    83     def after_add_entity(self):
    84         eid = self.entity.eid
    84         eid = self.entity.eid
    85         eschema = self.entity.e_schema
    85         eschema = self.entity.e_schema
    86         for rschema, targetschemas, x in eschema.relation_definitions():
    86         for rschema, targetschemas, x in eschema.relation_definitions():
   103 
   103 
   104     def before_delete_relation(self):
   104     def before_delete_relation(self):
   105         rtype = self.rtype
   105         rtype = self.rtype
   106         if rtype in DONT_CHECK_RTYPES_ON_DEL:
   106         if rtype in DONT_CHECK_RTYPES_ON_DEL:
   107             return
   107             return
   108         session = self.cw_req
   108         session = self._cw
   109         eidfrom, eidto = self.eidfrom, self.eidto
   109         eidfrom, eidto = self.eidfrom, self.eidto
   110         card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
   110         card = session.schema_rproperty(rtype, eidfrom, eidto, 'cardinality')
   111         pendingrdefs = session.transaction_data.get('pendingrdefs', ())
   111         pendingrdefs = session.transaction_data.get('pendingrdefs', ())
   112         if (session.describe(eidfrom)[0], rtype, session.describe(eidto)[0]) in pendingrdefs:
   112         if (session.describe(eidfrom)[0], rtype, session.describe(eidto)[0]) in pendingrdefs:
   113             return
   113             return
   147     """
   147     """
   148     __id__ = 'checkconstraint'
   148     __id__ = 'checkconstraint'
   149     events = ('after_add_relation',)
   149     events = ('after_add_relation',)
   150 
   150 
   151     def __call__(self):
   151     def __call__(self):
   152         constraints = self.cw_req.schema_rproperty(self.rtype, self.eidfrom, self.eidto,
   152         constraints = self._cw.schema_rproperty(self.rtype, self.eidfrom, self.eidto,
   153                                 'constraints')
   153                                 'constraints')
   154         if constraints:
   154         if constraints:
   155             _CheckConstraintsOp(self.cw_req, constraints=constraints,
   155             _CheckConstraintsOp(self._cw, constraints=constraints,
   156                                rdef=(self.eidfrom, self.rtype, self.eidto))
   156                                rdef=(self.eidfrom, self.rtype, self.eidto))
   157 
   157 
   158 
   158 
   159 class CheckUniqueHook(IntegrityHook):
   159 class CheckUniqueHook(IntegrityHook):
   160     __id__ = 'checkunique'
   160     __id__ = 'checkunique'
   168             if val is None:
   168             if val is None:
   169                 continue
   169                 continue
   170             if eschema.subject_relation(attr).is_final() and \
   170             if eschema.subject_relation(attr).is_final() and \
   171                    eschema.has_unique_values(attr):
   171                    eschema.has_unique_values(attr):
   172                 rql = '%s X WHERE X %s %%(val)s' % (entity.e_schema, attr)
   172                 rql = '%s X WHERE X %s %%(val)s' % (entity.e_schema, attr)
   173                 rset = self.cw_req.unsafe_execute(rql, {'val': val})
   173                 rset = self._cw.unsafe_execute(rql, {'val': val})
   174                 if rset and rset[0][0] != entity.eid:
   174                 if rset and rset[0][0] != entity.eid:
   175                     msg = self.cw_req._('the value "%s" is already used, use another one')
   175                     msg = self._cw._('the value "%s" is already used, use another one')
   176                     raise ValidationError(entity.eid, {attr: msg % val})
   176                     raise ValidationError(entity.eid, {attr: msg % val})
   177 
   177 
   178 
   178 
   179 class _DelayedDeleteOp(hook.Operation):
   179 class _DelayedDeleteOp(hook.Operation):
   180     """delete the object of composite relation except if the relation
   180     """delete the object of composite relation except if the relation
   197     """
   197     """
   198     __id__ = 'deletecomposite'
   198     __id__ = 'deletecomposite'
   199     events = ('before_delete_relation',)
   199     events = ('before_delete_relation',)
   200 
   200 
   201     def __call__(self):
   201     def __call__(self):
   202         composite = self.cw_req.schema_rproperty(self.rtype, self.eidfrom, self.eidto,
   202         composite = self._cw.schema_rproperty(self.rtype, self.eidfrom, self.eidto,
   203                                                  'composite')
   203                                                  'composite')
   204         if composite == 'subject':
   204         if composite == 'subject':
   205             _DelayedDeleteOp(self.cw_req, eid=self.eidto,
   205             _DelayedDeleteOp(self._cw, eid=self.eidto,
   206                              relation='Y %s X' % self.rtype)
   206                              relation='Y %s X' % self.rtype)
   207         elif composite == 'object':
   207         elif composite == 'object':
   208             _DelayedDeleteOp(self.cw_req, eid=self.eidfrom,
   208             _DelayedDeleteOp(self._cw, eid=self.eidfrom,
   209                              relation='X %s Y' % self.rtype)
   209                              relation='X %s Y' % self.rtype)
   210 
   210 
   211 
   211 
   212 class DontRemoveOwnersGroupHook(IntegrityHook):
   212 class DontRemoveOwnersGroupHook(IntegrityHook):
   213     """delete the composed of a composite relation when this relation is deleted
   213     """delete the composed of a composite relation when this relation is deleted
   216     __select__ = IntegrityHook.__select__ & entity_implements('CWGroup')
   216     __select__ = IntegrityHook.__select__ & entity_implements('CWGroup')
   217     events = ('before_delete_entity', 'before_update_entity')
   217     events = ('before_delete_entity', 'before_update_entity')
   218 
   218 
   219     def __call__(self):
   219     def __call__(self):
   220         if self.event == 'before_delete_entity' and self.entity.name == 'owners':
   220         if self.event == 'before_delete_entity' and self.entity.name == 'owners':
   221             raise ValidationError(self.entity.eid, {None: self.cw_req._('can\'t be deleted')})
   221             raise ValidationError(self.entity.eid, {None: self._cw._('can\'t be deleted')})
   222         elif self.event == 'before_update_entity' and 'name' in self.entity.edited_attribute:
   222         elif self.event == 'before_update_entity' and 'name' in self.entity.edited_attribute:
   223             newname = self.entity.pop('name')
   223             newname = self.entity.pop('name')
   224             oldname = self.entity.name
   224             oldname = self.entity.name
   225             if oldname == 'owners' and newname != oldname:
   225             if oldname == 'owners' and newname != oldname:
   226                 raise ValidationError(self.entity.eid, {'name': self.cw_req._('can\'t be changed')})
   226                 raise ValidationError(self.entity.eid, {'name': self._cw._('can\'t be changed')})
   227             self.entity['name'] = newname
   227             self.entity['name'] = newname
   228 
   228 
   229 
   229 
   230 class TidyHtmlFields(IntegrityHook):
   230 class TidyHtmlFields(IntegrityHook):
   231     """tidy HTML in rich text strings"""
   231     """tidy HTML in rich text strings"""
   241                     value = entity[attr]
   241                     value = entity[attr]
   242                 except KeyError:
   242                 except KeyError:
   243                     continue # no text to tidy
   243                     continue # no text to tidy
   244                 if isinstance(value, unicode): # filter out None and Binary
   244                 if isinstance(value, unicode): # filter out None and Binary
   245                     if getattr(entity, str(metaattr)) == 'text/html':
   245                     if getattr(entity, str(metaattr)) == 'text/html':
   246                         entity[attr] = soup2xhtml(value, self.cw_req.encoding)
   246                         entity[attr] = soup2xhtml(value, self._cw.encoding)
   247 
   247 
   248 
   248 
   249 class StripCWUserLoginHook(IntegrityHook):
   249 class StripCWUserLoginHook(IntegrityHook):
   250     """ensure user logins are stripped"""
   250     """ensure user logins are stripped"""
   251     __id__ = 'stripuserlogin'
   251     __id__ = 'stripuserlogin'