--- a/hooks/workflow.py Wed Mar 24 10:23:31 2010 +0100
+++ b/hooks/workflow.py Wed Apr 28 11:54:13 2010 +0200
@@ -1,14 +1,29 @@
+# copyright 2003-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
+# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
+#
+# This file is part of CubicWeb.
+#
+# CubicWeb is free software: you can redistribute it and/or modify it under the
+# terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation, either version 2.1 of the License, or (at your option)
+# any later version.
+#
+# logilab-common is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+# details.
+#
+# You should have received a copy of the GNU Lesser General Public License along
+# with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
"""Core hooks: workflow related hooks
-: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"
from datetime import datetime
+from yams.schema import role_name
+
from cubicweb import RepositoryError, ValidationError
from cubicweb.interfaces import IWorkflowable
from cubicweb.selectors import implements
@@ -19,8 +34,8 @@
nocheck = session.transaction_data.setdefault('skip-security', set())
nocheck.add((x, 'in_state', oldstate))
nocheck.add((x, 'in_state', newstate))
- # delete previous state first in case we're using a super session,
- # unless in_state isn't stored in the system source
+ # delete previous state first unless in_state isn't stored in the system
+ # source
fromsource = session.describe(x)[1]
if fromsource == 'system' or \
not session.repo.sources_by_uri[fromsource].support_relation('in_state'):
@@ -42,10 +57,8 @@
and entity.current_workflow:
state = entity.current_workflow.initial
if state:
- # use super session to by-pass security checks
- session.super_session.add_relation(entity.eid, 'in_state',
- state.eid)
-
+ session.add_relation(entity.eid, 'in_state', state.eid)
+ _FireAutotransitionOp(session, entity=entity)
class _FireAutotransitionOp(hook.Operation):
"""try to fire auto transition after state changes"""
@@ -75,8 +88,9 @@
if mainwf.eid == self.wfeid:
deststate = mainwf.initial
if not deststate:
+ qname = role_name('custom_workflow', 'subject')
msg = session._('workflow has no initial state')
- raise ValidationError(entity.eid, {'custom_workflow': msg})
+ raise ValidationError(entity.eid, {qname: msg})
if mainwf.state_by_eid(entity.current_state.eid):
# nothing to do
return
@@ -85,6 +99,7 @@
if entity.current_state.eid != deststate.eid:
_change_state(session, entity.eid,
entity.current_state.eid, deststate.eid)
+ _FireAutotransitionOp(session, entity=entity)
return
msg = session._('workflow changed to "%s"')
msg %= session._(mainwf.name)
@@ -99,8 +114,9 @@
outputs = set()
for ep in tr.subworkflow_exit:
if ep.subwf_state.eid in outputs:
+ qname = role_name('subworkflow_exit', 'subject')
msg = self.session._("can't have multiple exits on the same state")
- raise ValidationError(self.treid, {'subworkflow_exit': msg})
+ raise ValidationError(self.treid, {qname: msg})
outputs.add(ep.subwf_state.eid)
@@ -114,6 +130,7 @@
wftr = forentity.subworkflow_input_transition()
if wftr is None:
# inconsistency detected
+ qname = role_name('to_state', 'subject')
msg = session._("state doesn't belong to entity's current workflow")
raise ValidationError(self.trinfo.eid, {'to_state': msg})
tostate = wftr.get_exit_point(forentity, trinfo['to_state'])
@@ -122,14 +139,7 @@
msg = session._('exiting from subworkflow %s')
msg %= session._(forentity.current_workflow.name)
session.transaction_data[(forentity.eid, 'subwfentrytr')] = True
- # XXX iirk
- req = forentity._cw
- forentity._cw = session.super_session
- try:
- trinfo = forentity.change_state(tostate, msg, u'text/plain',
- tr=wftr)
- finally:
- forentity._cw = req
+ forentity.change_state(tostate, msg, u'text/plain', tr=wftr)
# hooks ########################################################################
@@ -175,8 +185,9 @@
try:
foreid = entity['wf_info_for']
except KeyError:
+ qname = role_name('wf_info_for', 'subject')
msg = session._('mandatory relation')
- raise ValidationError(entity.eid, {'wf_info_for': msg})
+ raise ValidationError(entity.eid, {qname: msg})
forentity = session.entity_from_eid(foreid)
# then check it has a workflow set, unless we're in the process of changing
# entity's workflow
@@ -195,7 +206,8 @@
raise ValidationError(entity.eid, {None: msg})
# True if we are coming back from subworkflow
swtr = session.transaction_data.pop((forentity.eid, 'subwfentrytr'), None)
- cowpowers = session.is_super_session or 'managers' in session.user.groups
+ cowpowers = (session.user.is_in_group('managers')
+ or not session.write_security)
# no investigate the requested state change...
try:
treid = entity['by_transition']
@@ -203,41 +215,47 @@
# no transition set, check user is a manager and destination state
# is specified (and valid)
if not cowpowers:
+ qname = role_name('by_transition', 'subject')
msg = session._('mandatory relation')
- raise ValidationError(entity.eid, {'by_transition': msg})
+ raise ValidationError(entity.eid, {qname: msg})
deststateeid = entity.get('to_state')
if not deststateeid:
+ qname = role_name('by_transition', 'subject')
msg = session._('mandatory relation')
- raise ValidationError(entity.eid, {'by_transition': msg})
+ raise ValidationError(entity.eid, {qname: msg})
deststate = wf.state_by_eid(deststateeid)
if deststate is None:
+ qname = role_name('to_state', 'subject')
msg = session._("state doesn't belong to entity's workflow")
- raise ValidationError(entity.eid, {'to_state': msg})
+ raise ValidationError(entity.eid, {qname: msg})
else:
# check transition is valid and allowed, unless we're coming back
# from subworkflow
tr = session.entity_from_eid(treid)
if swtr is None:
+ qname = role_name('by_transition', 'subject')
if tr is None:
msg = session._("transition doesn't belong to entity's workflow")
- raise ValidationError(entity.eid, {'by_transition': msg})
+ raise ValidationError(entity.eid, {qname: msg})
if not tr.has_input_state(fromstate):
msg = session._("transition %(tr)s isn't allowed from %(st)s") % {
'tr': session._(tr.name), 'st': session._(fromstate.name)}
- raise ValidationError(entity.eid, {'by_transition': msg})
+ raise ValidationError(entity.eid, {qname: msg})
if not tr.may_be_fired(foreid):
msg = session._("transition may not be fired")
- raise ValidationError(entity.eid, {'by_transition': msg})
+ raise ValidationError(entity.eid, {qname: msg})
if entity.get('to_state'):
deststateeid = entity['to_state']
if not cowpowers and deststateeid != tr.destination(forentity).eid:
+ qname = role_name('by_transition', 'subject')
msg = session._("transition isn't allowed")
- raise ValidationError(entity.eid, {'by_transition': msg})
+ raise ValidationError(entity.eid, {qname: msg})
if swtr is None:
deststate = session.entity_from_eid(deststateeid)
if not cowpowers and deststate is None:
+ qname = role_name('to_state', 'subject')
msg = session._("state doesn't belong to entity's workflow")
- raise ValidationError(entity.eid, {'to_state': msg})
+ raise ValidationError(entity.eid, {qname: msg})
else:
deststateeid = tr.destination(forentity).eid
# everything is ok, add missing information on the trinfo entity
@@ -266,7 +284,7 @@
class CheckInStateChangeAllowed(WorkflowHook):
- """check state apply, in case of direct in_state change using unsafe_execute
+ """check state apply, in case of direct in_state change using unsafe execute
"""
__regid__ = 'wfcheckinstate'
__select__ = WorkflowHook.__select__ & hook.match_rtype('in_state')
@@ -287,12 +305,14 @@
if wf.state_by_eid(self.eidto):
break
else:
+ qname = role_name('in_state', 'subject')
msg = session._("state doesn't belong to entity's workflow. You may "
"want to set a custom workflow for this entity first.")
- raise ValidationError(self.eidfrom, {'in_state': msg})
+ raise ValidationError(self.eidfrom, {qname: msg})
if entity.current_workflow and wf.eid != entity.current_workflow.eid:
+ qname = role_name('in_state', 'subject')
msg = session._("state doesn't belong to entity's current workflow")
- raise ValidationError(self.eidfrom, {'in_state': msg})
+ raise ValidationError(self.eidfrom, {qname: msg})
class SetModificationDateOnStateChange(WorkflowHook):
@@ -307,8 +327,7 @@
return
entity = self._cw.entity_from_eid(self.eidfrom)
try:
- entity.set_attributes(modification_date=datetime.now(),
- _cw_unsafe=True)
+ entity.set_attributes(modification_date=datetime.now())
except RepositoryError, ex:
# usually occurs if entity is coming from a read-only source
# (eg ldap user)