=============================================================== 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) [<...>] Person States ============= >>> from loops.organize.stateful.person import personStates Task States =========== >>> from loops.organize.stateful.task import taskStates, publishableTask Contact States =========== >>> from loops.organize.stateful.contact import contactStates Fin de partie ============= >>> placefulTearDown()