loops/organize/stateful
2015-03-20 08:03:14 +01:00
..
__init__.py move stateful and process to organize; work in progress: organize.tracking 2008-04-09 10:03:52 +00:00
base.py take fields for state change form from transition; store in context (if appropriate) and in change record 2013-07-12 10:34:41 +02:00
browser.py provide new 'contact' states definition to be used for persons or other kinds of parties 2015-03-16 16:31:52 +01:00
configure.zcml provide new 'contact' states definition to be used for persons or other kinds of parties 2015-03-16 16:31:52 +01:00
contact.py filter qualification reports by contact state 2015-03-20 08:03:14 +01:00
quality.py use 'baseObject' for properties that are not available for adapted objects 2010-09-08 09:07:53 +00:00
README.txt provide new 'contact' states definition to be used for persons or other kinds of parties 2015-03-16 16:31:52 +01:00
task.py allow re-open (retract to draft state) of active task 2014-11-17 09:08:45 +01:00
tests.py move stateful and process to organize; work in progress: organize.tracking 2008-04-09 10:03:52 +00:00
view_macros.pt provide state icon with link to state transition form for comments 2014-04-09 13:07:39 +02:00

===============================================================
loops - Linked Objects for Organization and Processing Services
===============================================================

  >>> from zope import component
  >>> from zope.traversing.api import getName

First we set up a loops site with basic and example concepts and resources.

  >>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
  >>> site = placefulSetUp(True)

  >>> from loops.organize.setup import SetupManager
  >>> component.provideAdapter(SetupManager, name='organize')
  >>> from loops.expert.testsetup import TestSite
  >>> t = TestSite(site)
  >>> concepts, resources, views = t.setup()
  >>> loopsRoot = site['loops']


Stateful Objects
================

A simple publishing workflow
----------------------------

Let's start with registering the states definitions and adapters needed.
The states definition (aka 'workflow') is registered as a utility; for
making an object statful we'll use an adapter.

  >>> from cybertools.stateful.interfaces import IStatesDefinition, IStateful
  >>> from cybertools.stateful.publishing import simplePublishing
  >>> component.provideUtility(simplePublishing(), name='simple_publishing')

  >>> from loops.organize.stateful.base import SimplePublishable
  >>> component.provideAdapter(SimplePublishable, name='simple_publishing')

We may now take a document and adapt it to IStateful so that we may
check the document's state and perform transitions to other states.

  >>> from loops.resource import Resource
  >>> from loops.setup import addAndConfigureObject
  >>> tText = concepts['textdocument']
  >>> doc01 = resources['doc01.txt'] = addAndConfigureObject(resources,
  ...                       Resource, 'doc01.txt', conceptType=tText)
  >>> statefulDoc01 = component.getAdapter(doc01, IStateful,
  ...                                      name='simple_publishing')

  >>> statefulDoc01.state
  'draft'

  >>> statefulDoc01.doTransition('publish')
  >>> statefulDoc01.state
  'published'

Let's check if the state is really stored in the underlying object and
not just kept in the adapter.

  >>> statefulDoc01_x = component.getAdapter(doc01, IStateful,
  ...                                        name='simple_publishing')

  >>> statefulDoc01.state
  'published'


Controlling classification quality
----------------------------------

We again first have to register states definitions and adapter classes.

  >>> from loops.organize.stateful.quality import classificationQuality
  >>> component.provideUtility(classificationQuality(),
  ...                          name='classification_quality')
  >>> from loops.organize.stateful.quality import ClassificationQualityCheckable
  >>> component.provideAdapter(ClassificationQualityCheckable,
  ...                          name='classification_quality')
  >>> from loops.organize.stateful.quality import assign, deassign
  >>> component.provideHandler(assign)
  >>> component.provideHandler(deassign)

Now we can get a stateful adapter for a resource.

  >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful,
  ...                                      name='classification_quality')
  >>> qcheckedDoc01.state
  'new'

Let's create two customer objects to be used for classification of resources
later.

  >>> tCustomer = concepts['customer']
  >>> from loops.concept import Concept
  >>> c01 = addAndConfigureObject(concepts, Concept, 'c01', conceptType=tCustomer,
  ...                   title='im publishing')
  >>> c02 = addAndConfigureObject(concepts, Concept, 'c02', conceptType=tCustomer,
  ...                   title='DocFive')

When we change the concept assignments of the resource - i.e. its classification
- the classification quality state changes automatically

  >>> c01.assignResource(doc01)
  >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful,
  ...                                      name='classification_quality')
  >>> qcheckedDoc01.state
  'classified'

  >>> c02.assignResource(doc01)
  >>> qcheckedDoc01.state
  'classified'

In order to mark the classification as "verified" (i.e. quality-checked)
we have to perform the corresponding transition explicitly.

  >>> qcheckedDoc01.doTransition('verify')
  >>> qcheckedDoc01.state
  'verified'

Upon later changes of classification the "verified" state gets lost again.

  >>> c02.deassignResource(doc01)
  >>> qcheckedDoc01.state
  'classified'

  >>> c01.deassignResource(doc01)
  >>> qcheckedDoc01.state
  'unclassified'

Changing states when editing
----------------------------

We first need a node that provides us access to the resource as its target

  >>> from loops.view import Node
  >>> node = addAndConfigureObject(views, Node, 'node', target=doc01)

  >>> from loops.browser.form import EditObjectForm, EditObject
  >>> from zope.publisher.browser import TestRequest

The form view gives us access to the states of the object.

  >>> loopsRoot.options = ['organize.stateful.resource:'
  ...           'classification_quality,simple_publishing']

  >>> form = EditObjectForm(node, TestRequest())
  >>> for st in form.states:
  ...     sto = st.getStateObject()
  ...     transitions = st.getAvailableTransitions()
  ...     userTrans = st.getAvailableTransitionsForUser()
  ...     print st.statesDefinition, sto.title, [t.title for t in transitions],
  ...     print [t.title for t in userTrans]
  classification_quality unclassified ['classify', 'verify'] ['verify']
  simple_publishing published ['retract', 'archive'] ['retract', 'archive']

Let's now update the form.

  >>> input = {'state.classification_quality': 'verify'}
  >>> proc = EditObject(form, TestRequest(form=input))
  >>> proc.update()
  False

  >>> qcheckedDoc01.state
  'verified'

Querying objects by state
-------------------------

  >>> stateQuery = addAndConfigureObject(concepts, Concept, 'state_query',
  ...                   conceptType=concepts['query'], viewName='select_state.html')
  >>> from loops.organize.stateful.browser import StateQuery
  >>> view = StateQuery(stateQuery, TestRequest())

  >>> view.rcStatesDefinitions
  {'concept': [], 'resource': [...StatesDefinition..., ...StatesDefinition...]}

  >>> input = {'state.resource.classification_quality': ['verified']}
  >>> view = StateQuery(stateQuery, TestRequest(form=input))
  >>> view.selectedStates
  {'state.resource.classification_quality': ['verified']}

  >>> list(view.results)
  [<...>]


Task States
===========

  >>> from loops.organize.stateful.task import taskStates, publishableTask


Contact States
===========

  >>> from loops.organize.stateful.contact import contactStates


Fin de partie
=============

  >>> placefulTearDown()