class LinkAttachmentsToPersonHook(Hook): __regid__ = 'drh.linkattachments' __select__ = (Hook.__select__ & (match_rtype('sender', 'attachment') | match_rtype('use_email', frometypes=('Person', )))) events = ('after_add_relation', ) def __call__(self): LinkAttachmentsToPersonOp.get_instance(self._cw).add_data( (self.rtype, self.eidfrom, self.eidto))
class SetCustomWorkflow(WorkflowHook): __regid__ = 'wfsetcustom' __select__ = WorkflowHook.__select__ & hook.match_rtype('custom_workflow') events = ('after_add_relation', ) def __call__(self): _WorkflowChangedOp(self._cw, eid=self.eidfrom, wfeid=self.eidto)
class CheckInStateChangeAllowed(WorkflowHook): """check state apply, in case of direct in_state change using unsafe execute """ __regid__ = 'wfcheckinstate' __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state') events = ('before_add_relation', ) category = 'integrity' def __call__(self): cnx = self._cw nocheck = cnx.transaction_data.get('skip-security', ()) if (self.eidfrom, 'in_state', self.eidto) in nocheck: # state changed through TrInfo insertion, so we already know it's ok return entity = cnx.entity_from_eid(self.eidfrom) iworkflowable = entity.cw_adapt_to('IWorkflowable') mainwf = iworkflowable.main_workflow if mainwf is None: msg = _('entity has no workflow set') raise validation_error(entity, {None: msg}) for wf in mainwf.iter_workflows(): if wf.state_by_eid(self.eidto): break else: msg = _("state doesn't belong to entity's workflow. You may " "want to set a custom workflow for this entity first.") raise validation_error(self.eidfrom, {('in_state', 'subject'): msg}) if iworkflowable.current_workflow and wf.eid != iworkflowable.current_workflow.eid: msg = _("state doesn't belong to entity's current workflow") raise validation_error(self.eidfrom, {('in_state', 'subject'): msg})
class InGroupHook(hook.Hook): """ Set moderators rights when they administrate groups through the 'in_group' relation. """ __regid__ = "in-group-hook" __select__ = (hook.Hook.__select__ & hook.match_rtype("in_group") & ~match_user_groups("managers")) events = ("before_add_relation", "before_delete_relation") def __call__(self): """ Before an 'in_group' relation deletion or addition, check the assocaited group name: can't modifiy managers, users, guests and moderators group associated unless you are administrator. """ parent = self._cw.entity_from_eid(self.eidto) child = self._cw.entity_from_eid(self.eidfrom) group_name = parent.name if child.firstname is None or child.surname is None: user_name = child.login else: user_name = child.firstname + " " + child.surname if group_name in self._cw.vreg.config.get("restricted-groups", []): raise ConfigurationError( "You do not have sufficient permissions to administrate '%s' " "in the '%s' group." % (user_name, group_name))
class OnDeleteInlined(Hook): __regid__ = 'on_delete_inlined' __select__ = Hook.__select__ & hook.match_rtype('personne_inlined') events = ('before_delete_relation', 'after_delete_relation') CALLED = [] def __call__(self): OnDeleteInlined.CALLED.append(self.event)
class CheckWorkflowTransitionExitPoint(WorkflowHook): """check that there is no multiple exits from the same state""" __regid__ = 'wfcheckwftrexit' __select__ = WorkflowHook.__select__ & hook.match_rtype('subworkflow_exit') events = ('after_add_relation', ) def __call__(self): _CheckTrExitPoint(self._cw, treid=self.eidfrom)
class EcritParHook(hook.Hook): __regid__ = 'inlinedrelhook' __select__ = hook.Hook.__select__ & hook.match_rtype('ecrit_par') events = ('before_add_relation', 'after_add_relation', 'before_delete_relation', 'after_delete_relation') def __call__(self): CALLED.append( (self.event, self.eidfrom, self.rtype, self.eidto))
class DelBookmarkedByHook(hook.Hook): """ensure user logins are stripped""" __regid__ = 'autodelbookmark' __select__ = hook.Hook.__select__ & hook.match_rtype('bookmarked_by', ) category = 'bookmark' events = ('after_delete_relation', ) def __call__(self): AutoDeleteBookmarkOp(self._cw, bookmark=self._cw.entity_from_eid(self.eidfrom))
class InGroupHook(Hook): # non-inlined relation __regid__ = 'in_group' __select__ = Hook.__select__ & match_rtype('in_group') events = ('after_add_relation', ) def __call__(self): cnx = self._cw if not 'IN_GROUP' in cnx.data: cnx.data['IN_GROUP'] = [] cnx.data['IN_GROUP'].append((cnx.entity_from_eid(self.eidfrom).login, cnx.entity_from_eid(self.eidto).name))
class MyEmailHook(Hook): # inlined relation __regid__ = 'my_email' __select__ = Hook.__select__ & match_rtype('my_email') events = ('after_add_relation', ) def __call__(self): cnx = self._cw if not 'MY_EMAIL' in cnx.data: cnx.data['MY_EMAIL'] = [] cnx.data['MY_EMAIL'].append((cnx.entity_from_eid(self.eidfrom).login, cnx.entity_from_eid(self.eidto).address))
class SetUseEmailHook(hook.Hook): """notify when a bug or story or version has its state modified""" __regid__ = 'setprimaryemail' __select__ = hook.Hook.__select__ & hook.match_rtype('primary_email') category = 'email' events = ('after_add_relation', ) def __call__(self): entity = self._cw.entity_from_eid(self.eidfrom) if 'use_email' in entity.e_schema.subject_relations(): SetUseEmailRelationOp(self._cw, entity=entity, email=self._cw.entity_from_eid(self.eidto))
class AddForUserRelationHook(SyncSessionHook): __regid__ = 'addcwpropforuser' __select__ = SyncSessionHook.__select__ & hook.match_rtype('for_user') events = ('after_add_relation', ) def __call__(self): cnx = self._cw eidfrom = self.eidfrom if not cnx.entity_type(eidfrom) == 'CWProperty': return key, value = cnx.execute( 'Any K,V WHERE P eid %(x)s,P pkey K,P value V', {'x': eidfrom})[0] if cnx.vreg.property_info(key)['sitewide']: msg = _("site-wide property can't be set for user") raise validation_error(eidfrom, {('for_user', 'subject'): msg})
class OnExpenseAcceptedHook(hook.Hook): """ * when an expense is going from "submitted" to "accepted", create (or update) refund entities accordingly """ __regid__ = 'expense_accepted' __select__ = hook.Hook.__select__ & hook.match_rtype('in_state',) events = ('after_add_relation',) def __call__(self): cnx = self._cw etype = cnx.entity_type(self.eidfrom) if etype != 'Expense': return newstate = cnx.entity_from_eid(self.eidto).name if newstate == 'accepted': UpdateRefundStateOperation(cnx, expense=self.eidfrom)
class SetModificationDateOnStateChange(WorkflowHook): """update entity's modification date after changing its state""" __regid__ = 'wfsyncmdate' __select__ = WorkflowHook.__select__ & hook.match_rtype('in_state') events = ('after_add_relation', ) def __call__(self): if self._cw.added_in_transaction(self.eidfrom): # new entity, not needed return entity = self._cw.entity_from_eid(self.eidfrom) try: entity.cw_set(modification_date=datetime.utcnow()) except RepositoryError as ex: # usually occurs if entity is coming from a read-only source # (eg ldap user) self.warning('cant change modification date for %s: %s', entity, ex)
def generate_relation_change_hooks(self): for rdef, computed_attributes in self.computed_attribute_by_relation.items( ): regid = 'computed_attribute.%s_modified' % rdef.rtype selector = hook.match_rtype(rdef.rtype.type, frometypes=(rdef.subject.type, ), toetypes=(rdef.object.type, )) optimized_computed_attributes = [] for computed_rdef in computed_attributes: optimized_computed_attributes.append( (computed_rdef, _optimize_on(computed_rdef.formula_select, rdef.rtype))) yield type( '%sModifiedHook' % rdef.rtype, (RelationInvolvedInCAModifiedHook, ), { '__regid__': regid, '__select__': hook.Hook.__select__ & selector, 'optimized_computed_attributes': optimized_computed_attributes })
class EnsureSymmetricRelationsDelete(_EnsureSymmetricRelationsDelete): __select__ = _EnsureSymmetricRelationsDelete.__select__ & hook.match_rtype( *symmetric_rtypes)
class Validate_Autocomplete_RulesHook(Hook): """ Validate the correct application of the autocomplete rules """ __regid__ = 'validateAutocompleteRules' __select__ = Hook.__select__ & ~match_rtype('created_by', 'owned_by') events = ('before_add_relation', ) def __call__(self): #print 'eidfrom: %s, eidto: %s, rtype: %s' % (self.eidfrom, self.eidto, self.rtype) #Cuando ya existe la relación no se evaluan las condiciones especiales srql = 'Any X, Y WHERE X %s Y, X eid %s, Y eid %s' % ( self.rtype, self.eidfrom, self.eidto) if self._cw.execute(srql).rowcount > 0: return eidfrom = self._cw.entity_from_eid(self.eidfrom) eidto = self._cw.entity_from_eid(self.eidto) #Evaluate the direct relation target = '' specialsearch = AutoCompleteEntityRetriever().getSpecialSearch( self._cw, eidfrom, self.rtype, type(eidto).__name__, 'subject') if specialsearch != ' ': unrelated = eidfrom.cw_unrelated_rql(self.rtype, type(eidto).__name__, 'subject') srql = ((unrelated[0] % unrelated[1]) + specialsearch + ', O eid ' + str(self.eidto)) if self._cw.execute(srql).rowcount < 1: target = ('%(entity)s|%(relation)s%(role)s|%(etype_search)s' % { 'entity': type(eidfrom).__name__, 'relation': self.rtype, 'role': '', 'etype_search': type(eidto).__name__ }) helpmsg = self._cw._('Validation error, relation not valid') if target in AutoCompleteEntityRetriever().HELP_MESSAGES: helpmsg = self._cw._( AutoCompleteEntityRetriever().HELP_MESSAGES[target]) raise ValidationError(self.eidfrom, {self.rtype: helpmsg}) #Evaluate the reverse relation target = '' specialsearch = AutoCompleteEntityRetriever().getSpecialSearch( self._cw, eidto, self.rtype, type(eidfrom).__name__, 'object') if specialsearch != ' ': unrelated = eidto.cw_unrelated_rql(self.rtype, type(eidfrom).__name__, 'object') srql = ((unrelated[0] % unrelated[1]) + specialsearch + ', S eid ' + str(self.eidfrom)) if self._cw.execute(srql).rowcount < 1: target = ('%(entity)s|%(relation)s%(role)s|%(etype_search)s' % { 'entity': type(eidto).__name__, 'relation': self.rtype, 'role': '_object', 'etype_search': type(eidfrom).__name__ }) helpmsg = self._cw._('Validation error, relation not valid') if target in AutoCompleteEntityRetriever().HELP_MESSAGES: helpmsg = self._cw._( AutoCompleteEntityRetriever().HELP_MESSAGES[target]) raise ValidationError(self.eidto, {self.rtype: helpmsg})
class CloneDiamond(hooks.CloneContainer): __select__ = hooks.CloneContainer.__select__ & match_rtype('is_clone_of')
class EnsureSymmetricRelationsAdd(_EnsureSymmetricRelationsAdd): __select__ = _EnsureSymmetricRelationsAdd.__select__ & hook.match_rtype( *symmetric_rtypes)