schemas/workflow.py
changeset 11057 0b59724cb3f2
parent 11052 058bb3dc685f
child 11058 23eb30449fe5
equal deleted inserted replaced
11052:058bb3dc685f 11057:0b59724cb3f2
     1 # copyright 2003-2011 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
       
     2 # contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
       
     3 #
       
     4 # This file is part of CubicWeb.
       
     5 #
       
     6 # CubicWeb is free software: you can redistribute it and/or modify it under the
       
     7 # terms of the GNU Lesser General Public License as published by the Free
       
     8 # Software Foundation, either version 2.1 of the License, or (at your option)
       
     9 # any later version.
       
    10 #
       
    11 # CubicWeb is distributed in the hope that it will be useful, but WITHOUT
       
    12 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
       
    13 # FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
       
    14 # details.
       
    15 #
       
    16 # You should have received a copy of the GNU Lesser General Public License along
       
    17 # with CubicWeb.  If not, see <http://www.gnu.org/licenses/>.
       
    18 """workflow related schemas
       
    19 
       
    20 """
       
    21 __docformat__ = "restructuredtext en"
       
    22 from cubicweb import _
       
    23 
       
    24 from yams.buildobjs import (EntityType, RelationType, RelationDefinition,
       
    25                             SubjectRelation,
       
    26                             RichString, String, Int)
       
    27 from cubicweb.schema import RQLConstraint
       
    28 from cubicweb.schemas import (PUB_SYSTEM_ENTITY_PERMS, PUB_SYSTEM_REL_PERMS,
       
    29                               RO_REL_PERMS)
       
    30 
       
    31 class Workflow(EntityType):
       
    32     __permissions__ = PUB_SYSTEM_ENTITY_PERMS
       
    33 
       
    34     name = String(required=True, indexed=True, internationalizable=True,
       
    35                   maxsize=256)
       
    36     description = RichString(default_format='text/rest',
       
    37                              description=_('semantic description of this workflow'))
       
    38 
       
    39     workflow_of = SubjectRelation('CWEType', cardinality='+*',
       
    40                                   description=_('entity types which may use this workflow'),
       
    41                                   constraints=[RQLConstraint('O final FALSE')])
       
    42 
       
    43     initial_state = SubjectRelation('State', cardinality='?*',
       
    44                                    constraints=[RQLConstraint('O state_of S',
       
    45                                                               msg=_('state doesn\'t belong to this workflow'))],
       
    46                                    description=_('initial state for this workflow'))
       
    47 
       
    48 
       
    49 class default_workflow(RelationType):
       
    50     """default workflow for an entity type"""
       
    51     __permissions__ = PUB_SYSTEM_REL_PERMS
       
    52 
       
    53     subject = 'CWEType'
       
    54     object = 'Workflow'
       
    55     cardinality = '?*'
       
    56     constraints = [RQLConstraint('S final FALSE, O workflow_of S',
       
    57                                  msg=_('workflow isn\'t a workflow for this type'))]
       
    58 
       
    59 
       
    60 class State(EntityType):
       
    61     """used to associate simple states to an entity type and/or to define
       
    62     workflows
       
    63     """
       
    64     __permissions__ = PUB_SYSTEM_ENTITY_PERMS
       
    65     __unique_together__ = [('name', 'state_of')]
       
    66     name = String(required=True, indexed=True, internationalizable=True, maxsize=256)
       
    67     description = RichString(default_format='text/rest',
       
    68                              description=_('semantic description of this state'))
       
    69 
       
    70     # XXX should be on BaseTransition w/ AND/OR selectors when we will
       
    71     # implements #345274
       
    72     allowed_transition = SubjectRelation('BaseTransition', cardinality='**',
       
    73                                          constraints=[RQLConstraint('S state_of WF, O transition_of WF',
       
    74                                                                     msg=_('state and transition don\'t belong the the same workflow'))],
       
    75                                          description=_('allowed transitions from this state'))
       
    76     state_of = SubjectRelation('Workflow', cardinality='1*', composite='object', inlined=True,
       
    77                                description=_('workflow to which this state belongs'))
       
    78 
       
    79 
       
    80 class BaseTransition(EntityType):
       
    81     """abstract base class for transitions"""
       
    82     __permissions__ = PUB_SYSTEM_ENTITY_PERMS
       
    83     __unique_together__ = [('name', 'transition_of')]
       
    84 
       
    85     name = String(required=True, indexed=True, internationalizable=True, maxsize=256)
       
    86     type = String(vocabulary=(_('normal'), _('auto')), default='normal')
       
    87     description = RichString(description=_('semantic description of this transition'))
       
    88 
       
    89     transition_of = SubjectRelation('Workflow', cardinality='1*', composite='object', inlined=True,
       
    90                                     description=_('workflow to which this transition belongs'))
       
    91 
       
    92 
       
    93 class require_group(RelationDefinition):
       
    94     """group in which a user should be to be allowed to pass this transition"""
       
    95     __permissions__ = PUB_SYSTEM_REL_PERMS
       
    96     subject = 'BaseTransition'
       
    97     object = 'CWGroup'
       
    98 
       
    99 
       
   100 class condition(RelationDefinition):
       
   101     """a RQL expression which should return some results, else the transition
       
   102     won't be available.
       
   103 
       
   104     This query may use X and U variables that will respectivly represents the
       
   105     current entity and the current user.
       
   106     """
       
   107     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   108     subject = 'BaseTransition'
       
   109     object = 'RQLExpression'
       
   110     cardinality = '*?'
       
   111     composite = 'subject'
       
   112 
       
   113 
       
   114 class Transition(BaseTransition):
       
   115     """use to define a transition from one or multiple states to a destination
       
   116     states in workflow's definitions. Transition without destination state will
       
   117     go back to the state from which we arrived to the current state.
       
   118     """
       
   119     __specializes_schema__ = True
       
   120 
       
   121     destination_state = SubjectRelation(
       
   122         'State', cardinality='?*',
       
   123         constraints=[RQLConstraint('S transition_of WF, O state_of WF',
       
   124                                    msg=_('state and transition don\'t belong the the same workflow'))],
       
   125         description=_('destination state for this transition'))
       
   126 
       
   127 
       
   128 class WorkflowTransition(BaseTransition):
       
   129     """special transition allowing to go through a sub-workflow"""
       
   130     __specializes_schema__ = True
       
   131 
       
   132     subworkflow = SubjectRelation('Workflow', cardinality='1*',
       
   133                                   constraints=[RQLConstraint('S transition_of WF, WF workflow_of ET, O workflow_of ET',
       
   134                                                              msg=_('subworkflow isn\'t a workflow for the same types as the transition\'s workflow'))]
       
   135                                   )
       
   136     # XXX use exit_of and inline it
       
   137     subworkflow_exit = SubjectRelation('SubWorkflowExitPoint', cardinality='*1',
       
   138                                        composite='subject')
       
   139 
       
   140 
       
   141 class SubWorkflowExitPoint(EntityType):
       
   142     """define how we get out from a sub-workflow"""
       
   143     subworkflow_state = SubjectRelation(
       
   144         'State', cardinality='1*',
       
   145         constraints=[RQLConstraint('T subworkflow_exit S, T subworkflow WF, O state_of WF',
       
   146                                    msg=_('exit state must be a subworkflow state'))],
       
   147         description=_('subworkflow state'))
       
   148     destination_state = SubjectRelation(
       
   149         'State', cardinality='?*',
       
   150         constraints=[RQLConstraint('T subworkflow_exit S, T transition_of WF, O state_of WF',
       
   151                                    msg=_('destination state must be in the same workflow as our parent transition'))],
       
   152         description=_('destination state. No destination state means that transition '
       
   153                       'should go back to the state from which we\'ve entered the '
       
   154                       'subworkflow.'))
       
   155 
       
   156 
       
   157 class TrInfo(EntityType):
       
   158     """workflow history item"""
       
   159     # 'add' security actually done by hooks
       
   160     __permissions__ = {
       
   161         'read':   ('managers', 'users', 'guests',), # XXX U has_read_permission O ?
       
   162         'add':    ('managers', 'users', 'guests',),
       
   163         'delete': (), # XXX should we allow managers to delete TrInfo?
       
   164         'update': ('managers', 'owners',),
       
   165     }
       
   166     # The unique_together constraint ensures that 2 repositories
       
   167     # sharing the db won't be able to fire a transition simultaneously
       
   168     # on the same entity tr_count is filled in the FireTransitionHook
       
   169     # to the number of TrInfo attached to the entity on which we
       
   170     # attempt to fire a transition. In other word, it contains the
       
   171     # rank of the TrInfo for that entity, and the constraint says we
       
   172     # cannot have 2 TrInfo with the same rank.
       
   173     __unique_together__ = [('tr_count', 'wf_info_for')]
       
   174     from_state = SubjectRelation('State', cardinality='1*', inlined=True)
       
   175     to_state = SubjectRelation('State', cardinality='1*', inlined=True)
       
   176     # make by_transition optional because we want to allow managers to set
       
   177     # entity into an arbitrary state without having to respect wf transition
       
   178     by_transition = SubjectRelation('BaseTransition', cardinality='?*')
       
   179     comment = RichString(fulltextindexed=True, default_format='text/plain')
       
   180     tr_count = Int(description='autocomputed attribute used to ensure transition coherency')
       
   181     # get actor and date time using owned_by and creation_date
       
   182 
       
   183 class from_state(RelationType):
       
   184     __permissions__ = RO_REL_PERMS.copy()
       
   185     inlined = True
       
   186 
       
   187 class to_state(RelationType):
       
   188     __permissions__ = RO_REL_PERMS.copy()
       
   189     inlined = True
       
   190 
       
   191 class by_transition(RelationType):
       
   192     # 'add' security actually done by hooks
       
   193     __permissions__ = {
       
   194         'read':   ('managers', 'users', 'guests',),
       
   195         'add':    ('managers', 'users', 'guests',),
       
   196         'delete': (),
       
   197     }
       
   198     inlined = True
       
   199 
       
   200 
       
   201 class workflow_of(RelationType):
       
   202     """link a workflow to one or more entity type"""
       
   203     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   204 
       
   205 class state_of(RelationType):
       
   206     """link a state to one or more workflow"""
       
   207     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   208     inlined = True
       
   209 
       
   210 class transition_of(RelationType):
       
   211     """link a transition to one or more workflow"""
       
   212     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   213     inlined = True
       
   214 
       
   215 class destination_state(RelationType):
       
   216     """destination state of a transition"""
       
   217     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   218     inlined = True
       
   219 
       
   220 class allowed_transition(RelationType):
       
   221     """allowed transitions from this state"""
       
   222     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   223 
       
   224 class initial_state(RelationType):
       
   225     """indicate which state should be used by default when an entity using
       
   226     states is created
       
   227     """
       
   228     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   229     inlined = True
       
   230 
       
   231 
       
   232 class subworkflow(RelationType):
       
   233     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   234     inlined = True
       
   235 
       
   236 class exit_point(RelationType):
       
   237     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   238 
       
   239 class subworkflow_state(RelationType):
       
   240     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   241     inlined = True
       
   242 
       
   243 
       
   244 # "abstract" relations, set by WorkflowableEntityType ##########################
       
   245 
       
   246 class custom_workflow(RelationType):
       
   247     """allow to set a specific workflow for an entity"""
       
   248     __permissions__ = PUB_SYSTEM_REL_PERMS
       
   249 
       
   250     cardinality = '?*'
       
   251     constraints = [RQLConstraint('S is ET, O workflow_of ET',
       
   252                                  msg=_('workflow isn\'t a workflow for this type'))]
       
   253     object = 'Workflow'
       
   254 
       
   255 
       
   256 class wf_info_for(RelationType):
       
   257     """link a transition information to its object"""
       
   258     # 'add' security actually done by hooks
       
   259     __permissions__ = {
       
   260         'read':   ('managers', 'users', 'guests',),
       
   261         'add':    ('managers', 'users', 'guests',),
       
   262         'delete': (),
       
   263     }
       
   264     inlined = True
       
   265 
       
   266     cardinality = '1*'
       
   267     composite = 'object'
       
   268     fulltext_container = composite
       
   269     subject = 'TrInfo'
       
   270 
       
   271 
       
   272 class in_state(RelationType):
       
   273     """indicate the current state of an entity"""
       
   274     __permissions__ = RO_REL_PERMS
       
   275 
       
   276     # not inlined intentionnally since when using ldap sources, user'state
       
   277     # has to be stored outside the CWUser table
       
   278     inlined = False
       
   279 
       
   280     cardinality = '1*'
       
   281     constraints = [RQLConstraint('S is ET, O state_of WF, WF workflow_of ET',
       
   282                                  msg=_('state doesn\'t apply to this entity\'s type'))]
       
   283     object = 'State'