def __call__(self): entity = self.entity if self.event == 'before_delete_entity' and entity.name == 'owners': raise validation_error(entity, {None: _("can't be deleted")}) elif self.event == 'before_update_entity' \ and 'name' in entity.cw_edited: oldname, newname = entity.cw_edited.oldnewvalue('name') if oldname == 'owners' and newname != oldname: raise validation_error( entity, {('name', 'subject'): _("can't be changed")})
def precommit_event(self): # notice that enforcement that new workflow apply to the entity's type is # done by schema rule, no need to check it here cnx = self.cnx pendingeids = cnx.transaction_data.get('pendingeids', ()) if self.eid in pendingeids: return entity = cnx.entity_from_eid(self.eid) iworkflowable = entity.cw_adapt_to('IWorkflowable') # check custom workflow has not been rechanged to another one in the same # transaction mainwf = iworkflowable.main_workflow if mainwf.eid == self.wfeid: deststate = mainwf.initial if not deststate: msg = _('workflow has no initial state') raise validation_error(entity, {('custom_workflow', 'subject'): msg}) if mainwf.state_by_eid(iworkflowable.current_state.eid): # nothing to do return # if there are no history, simply go to new workflow's initial state if not iworkflowable.workflow_history: if iworkflowable.current_state.eid != deststate.eid: _change_state(cnx, entity.eid, iworkflowable.current_state.eid, deststate.eid) _FireAutotransitionOp(cnx, eid=entity.eid) return msg = cnx._('workflow changed to "%s"') msg %= cnx._(mainwf.name) cnx.transaction_data[(entity.eid, 'customwf')] = self.wfeid iworkflowable.change_state(deststate, msg, u'text/plain')
def __call__(self): if self.entity.type not in SOURCE_TYPES: msg = _('Unknown source type') raise validation_error(self.entity, {('type', 'subject'): msg}) source = self.get_source(self.entity) source.check_urls(self.entity) source.check_config(self.entity)
def __call__(self): key, value = self.entity.pkey, self.entity.value if key.startswith('sources.'): return cnx = self._cw try: value = cnx.vreg.typed_value(key, value) except UnknownProperty: msg = _('unknown property key %s') raise validation_error(self.entity, {('pkey', 'subject'): msg}, (key, )) except ValueError as ex: raise validation_error(self.entity, {('value', 'subject'): str(ex)}) if cnx.user.matching_groups('managers'): _ChangeSiteWideCWPropertyOp(cnx, cwprop=self.entity) else: cnx.add_relation(self.entity.eid, 'for_user', cnx.user.eid)
def precommit_event(self): tr = self.cnx.entity_from_eid(self.treid) outputs = set() for ep in tr.subworkflow_exit: if ep.subwf_state.eid in outputs: msg = _("can't have multiple exits on the same state") raise validation_error(self.treid, {('subworkflow_exit', 'subject'): msg}) outputs.add(ep.subwf_state.eid)
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})
def __call__(self): if 'name' in self.entity.cw_edited: oldname, newname = self.entity.cw_edited.oldnewvalue('name') if oldname == 'system': msg = _("You cannot rename the system source") raise validation_error(self.entity, {('name', 'subject'): msg}) source = self.get_source(self.entity) if 'url' in self.entity.cw_edited: source.check_urls(self.entity) if 'config' in self.entity.cw_edited: source.check_config(self.entity)
def signalerror(etype, eid, rtype, role): msg = _( 'at least one relation %(rtype)s is required on %(etype)s (%(eid)s)' ) errors.append({ etype: str( validation_error(eid, {(rtype, role): msg}, { 'rtype': rtype, 'etype': etype, 'eid': eid }, ['rtype', 'etype'])) })
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})
def __call__(self): entity = self.entity if not ('pkey' in entity.cw_edited or 'value' in entity.cw_edited): return key, value = entity.pkey, entity.value if key.startswith('sources.'): return cnx = self._cw try: value = cnx.vreg.typed_value(key, value) except UnknownProperty: return except ValueError as ex: raise validation_error(entity, {('value', 'subject'): str(ex)}) if not entity.for_user: _ChangeSiteWideCWPropertyOp(cnx, cwprop=self.entity)
def precommit_event(self): cnx = self.cnx forentity = cnx.entity_from_eid(self.foreid) iworkflowable = forentity.cw_adapt_to('IWorkflowable') trinfo = self.trinfo # we're in a subworkflow, check if we've reached an exit point wftr = iworkflowable.subworkflow_input_transition() if wftr is None: # inconsistency detected msg = _("state doesn't belong to entity's current workflow") raise validation_error(self.trinfo, {('to_state', 'subject'): msg}) tostate = wftr.get_exit_point(forentity, trinfo.cw_attr_cache['to_state']) if tostate is not None: # reached an exit point msg = _('exiting from subworkflow %s') msg %= cnx._(iworkflowable.current_workflow.name) cnx.transaction_data[(forentity.eid, 'subwfentrytr')] = True iworkflowable.change_state(tostate, msg, u'text/plain', tr=wftr)
def precommit_event(self): cnx = self.cnx pendingeids = cnx.transaction_data.get('pendingeids', ()) pendingrtypes = cnx.transaction_data.get('pendingrtypes', ()) for eid, rtype in self.get_data(): # recheck pending eids / relation types if eid in pendingeids: continue if rtype in pendingrtypes: continue if not cnx.execute(self.base_rql % rtype, {'x': eid}): etype = cnx.entity_type(eid) msg = _('at least one relation %(rtype)s is required on ' '%(etype)s (%(eid)s)') raise validation_error(eid, {(rtype, self.role): msg}, { 'rtype': rtype, 'etype': etype, 'eid': eid }, ['rtype', 'etype'])
def __call__(self): if self.entity.name == 'system': msg = _("You cannot remove the system source") raise validation_error(self.entity, {None: msg})
def __call__(self): cnx = self._cw entity = self.entity # first retreive entity to which the state change apply try: foreid = entity.cw_attr_cache['wf_info_for'] except KeyError: msg = _('mandatory relation') raise validation_error(entity, {('wf_info_for', 'subject'): msg}) forentity = cnx.entity_from_eid(foreid) # see comment in the TrInfo entity definition entity.cw_edited['tr_count'] = len(forentity.reverse_wf_info_for) iworkflowable = forentity.cw_adapt_to('IWorkflowable') # then check it has a workflow set, unless we're in the process of changing # entity's workflow if cnx.transaction_data.get((forentity.eid, 'customwf')): wfeid = cnx.transaction_data[(forentity.eid, 'customwf')] wf = cnx.entity_from_eid(wfeid) else: wf = iworkflowable.current_workflow if wf is None: msg = _('related entity has no workflow set') raise validation_error(entity, {None: msg}) # then check it has a state set fromstate = iworkflowable.current_state if fromstate is None: msg = _('related entity has no state') raise validation_error(entity, {None: msg}) # True if we are coming back from subworkflow swtr = cnx.transaction_data.pop((forentity.eid, 'subwfentrytr'), None) cowpowers = (cnx.user.is_in_group('managers') or not cnx.write_security) # no investigate the requested state change... try: treid = entity.cw_attr_cache['by_transition'] except KeyError: # no transition set, check user is a manager and destination state # is specified (and valid) if not cowpowers: msg = _('mandatory relation') raise validation_error(entity, {('by_transition', 'subject'): msg}) deststateeid = entity.cw_attr_cache.get('to_state') if not deststateeid: msg = _('mandatory relation') raise validation_error(entity, {('by_transition', 'subject'): msg}) deststate = wf.state_by_eid(deststateeid) if deststate is None: msg = _("state doesn't belong to entity's workflow") raise validation_error(entity, {('to_state', 'subject'): msg}) else: # check transition is valid and allowed, unless we're coming back # from subworkflow tr = cnx.entity_from_eid(treid) if swtr is None: qname = ('by_transition', 'subject') if tr is None: msg = _("transition doesn't belong to entity's workflow") raise validation_error(entity, {qname: msg}) if not tr.has_input_state(fromstate): msg = _("transition %(tr)s isn't allowed from %(st)s") raise validation_error(entity, {qname: msg}, { 'tr': tr.name, 'st': fromstate.name }, ['tr', 'st']) if not tr.may_be_fired(foreid): msg = _("transition may not be fired") raise validation_error(entity, {qname: msg}) deststateeid = entity.cw_attr_cache.get('to_state') if deststateeid is not None: if not cowpowers and deststateeid != tr.destination( forentity).eid: msg = _("transition isn't allowed") raise validation_error(entity, {('by_transition', 'subject'): msg}) if swtr is None: deststate = cnx.entity_from_eid(deststateeid) if not cowpowers and deststate is None: msg = _("state doesn't belong to entity's workflow") raise validation_error(entity, {('to_state', 'subject'): msg}) else: deststateeid = tr.destination(forentity).eid # everything is ok, add missing information on the trinfo entity entity.cw_edited['from_state'] = fromstate.eid entity.cw_edited['to_state'] = deststateeid nocheck = cnx.transaction_data.setdefault('skip-security', set()) nocheck.add((entity.eid, 'from_state', fromstate.eid)) nocheck.add((entity.eid, 'to_state', deststateeid)) _FireAutotransitionOp(cnx, eid=forentity.eid)