diff --git a/browser/common.py b/browser/common.py index d6a9141..c224521 100644 --- a/browser/common.py +++ b/browser/common.py @@ -267,7 +267,10 @@ class BaseView(GenericView, I18NView): def viewIterator(self, objs): request = self.request for o in objs: - yield BaseView(o, request) + view = component.queryMultiAdapter((o, request), name='index.html') + if view is None: + view = BaseView(o, request) + yield view def renderText(self, text, contentType): typeKey = util.renderingFactories.get(contentType, None) @@ -391,11 +394,10 @@ class BaseView(GenericView, I18NView): if not checkPermission('loops.ManageSite', self.context): # TODO: replace by more sensible permission return result - #statesDefs = ['loops.classification_quality', 'loops.simple_publishing'] if IResource.providedBy(self.target): statesDefs = self.globalOptions('organize.stateful.resource', ()) else: - statesDefs = () + statesDefs = self.globalOptions('organize.stateful.concept', ()) for std in statesDefs: stf = component.getAdapter(self.target, IStateful, name=std) result.append(stf) diff --git a/browser/form.py b/browser/form.py index 37b967d..90e2b7d 100644 --- a/browser/form.py +++ b/browser/form.py @@ -111,8 +111,6 @@ class ObjectForm(NodeView): @Lazy def schema(self): - #ti = self.typeInterface or IConceptSchema - #schemaFactory = component.getAdapter(self.adapted, ISchemaFactory) schemaFactory = ISchemaFactory(self.adapted) return schemaFactory(self.typeInterface, manager=self, request=self.request) @@ -398,9 +396,7 @@ class EditObject(FormController, I18NView): @Lazy def schema(self): - #schemaFactory = component.getAdapter(self.adapted, ISchemaFactory) schemaFactory = ISchemaFactory(self.adapted) - #return schemaFactory(self.typeInterface) return schemaFactory(self.typeInterface, manager=self, request=self.request) diff --git a/expert/README.txt b/expert/README.txt index e47ab3d..9c7eb7f 100644 --- a/expert/README.txt +++ b/expert/README.txt @@ -69,7 +69,7 @@ arguments, the name of the states definition and the state to search for. As we have not yet set up any states definitions for our objects we get an empty result. - >>> qu = query.State('loops.classification_quality', 'classified') + >>> qu = query.State('classification_quality', 'classified') >>> list(qu.apply()) [] @@ -78,12 +78,12 @@ corresponding adapter and activate it for the current loops site. >>> from loops.organize.stateful.quality import classificationQuality >>> component.provideUtility(classificationQuality(), - ... name='loops.classification_quality') + ... name='classification_quality') >>> from loops.organize.stateful.quality import ClassificationQualityCheckable >>> component.provideAdapter(ClassificationQualityCheckable, - ... name='loops.classification_quality') + ... name='classification_quality') - >>> loopsRoot.options = ['organize.stateful.resource:loops.classification_quality'] + >>> loopsRoot.options = ['organize.stateful.resource:classification_quality'] We have now to reindex all documents so that the state index gets populated according to the new settings. @@ -97,7 +97,7 @@ according to the new settings. Now the three documents we are working with are shown as classified (as they have at least one concept assigned). - >>> qu = query.State('loops.classification_quality', 'classified') + >>> qu = query.State('classification_quality', 'classified') >>> list(qu.apply()) [23, 25, 27] @@ -106,7 +106,7 @@ Using the stateful adapter for a resource we now manually execute the >>> from cybertools.stateful.interfaces import IStateful >>> statefulD001 = component.getAdapter(resources['d001.txt'], IStateful, - ... name='loops.classification_quality') + ... name='classification_quality') >>> statefulD001.doTransition('verify') Now only two resources are still in the ``qualified`` state, the changed @@ -114,13 +114,13 @@ one being in the ``verified`` state. >>> list(qu.apply()) [25, 27] - >>> qu = query.State('loops.classification_quality', 'verified') + >>> qu = query.State('classification_quality', 'verified') >>> list(qu.apply()) [23] We may also provide a sequence of states for querying. - >>> qu = query.State('loops.classification_quality', ('classified', 'verified',)) + >>> qu = query.State('classification_quality', ('classified', 'verified',)) >>> list(qu.apply()) [23, 25, 27] diff --git a/expert/query.py b/expert/query.py index 34b77cb..f7a0cec 100644 --- a/expert/query.py +++ b/expert/query.py @@ -31,7 +31,7 @@ from zope.component import adapts from zope.interface import implements, implementer from zope.cachedescriptors.property import Lazy -from cybertools.catalog.query import Term, Eq, Between, Or +from cybertools.catalog.query import Term, Eq, Between, And, Or from cybertools.catalog.query import Text as BaseText from cybertools.catalog.query import AnyOf from loops.expert.interfaces import IQuery diff --git a/organize/stateful/README.txt b/organize/stateful/README.txt index 1be2694..7d737f2 100644 --- a/organize/stateful/README.txt +++ b/organize/stateful/README.txt @@ -32,17 +32,17 @@ 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='loops.simple_publishing') + >>> component.provideUtility(simplePublishing(), name='simple_publishing') >>> from loops.organize.stateful.base import SimplePublishable - >>> component.provideAdapter(SimplePublishable, name='loops.simple_publishing') + >>> 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. >>> doc01 = resources['d001.txt'] >>> statefulDoc01 = component.getAdapter(doc01, IStateful, - ... name='loops.simple_publishing') + ... name='simple_publishing') >>> statefulDoc01.state 'draft' @@ -55,7 +55,7 @@ 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='loops.simple_publishing') + ... name='simple_publishing') >>> statefulDoc01.state 'published' @@ -68,10 +68,10 @@ We again first have to register states definitions and adapter classes. >>> from loops.organize.stateful.quality import classificationQuality >>> component.provideUtility(classificationQuality(), - ... name='loops.classification_quality') + ... name='classification_quality') >>> from loops.organize.stateful.quality import ClassificationQualityCheckable >>> component.provideAdapter(ClassificationQualityCheckable, - ... name='loops.classification_quality') + ... name='classification_quality') >>> from loops.organize.stateful.quality import assign, deassign >>> component.provideHandler(assign) >>> component.provideHandler(deassign) @@ -79,7 +79,7 @@ We again first have to register states definitions and adapter classes. Now we can get a stateful adapter for a resource. >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful, - ... name='loops.classification_quality') + ... name='classification_quality') >>> qcheckedDoc01.state 'new' @@ -99,7 +99,7 @@ When we change the concept assignments of the resource - i.e. its classification >>> c01.assignResource(doc01) >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful, - ... name='loops.classification_quality') + ... name='classification_quality') >>> qcheckedDoc01.state 'classified' @@ -138,7 +138,7 @@ We first need a node that provides us access to the resource as its target The form view gives us access to the states of the object. >>> loopsRoot.options = ['organize.stateful.resource:' - ... 'loops.classification_quality,loops.simple_publishing'] + ... 'classification_quality,simple_publishing'] >>> form = EditObjectForm(node, TestRequest()) >>> for st in form.states: @@ -147,12 +147,12 @@ The form view gives us access to the states of the object. ... userTrans = st.getAvailableTransitionsForUser() ... print st.statesDefinition, sto.title, [t.title for t in transitions], ... print [t.title for t in userTrans] - loops.classification_quality unclassified ['classify', 'verify'] ['verify'] - loops.simple_publishing published ['retract', 'archive'] ['retract', 'archive'] + classification_quality unclassified ['classify', 'verify'] ['verify'] + simple_publishing published ['retract', 'archive'] ['retract', 'archive'] Let's now update the form. - >>> input = {'state.loops.classification_quality': 'verify'} + >>> input = {'state.classification_quality': 'verify'} >>> proc = EditObject(form, TestRequest(form=input)) >>> proc.update() False @@ -160,6 +160,25 @@ Let's now update the form. >>> 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.statesDefinitions + {'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) + [<...>] + Fin de partie ============= diff --git a/organize/stateful/base.py b/organize/stateful/base.py index d38e833..221cc9a 100644 --- a/organize/stateful/base.py +++ b/organize/stateful/base.py @@ -56,7 +56,7 @@ class StatefulLoopsObject(Stateful, StatefulAdapter): class SimplePublishable(StatefulLoopsObject): - statesDefinition = 'loops.simple_publishing' + statesDefinition = 'simple_publishing' class StatefulResourceIndexInfo(IndexInfo): diff --git a/organize/stateful/browser.py b/organize/stateful/browser.py index 7551940..a2dd73a 100644 --- a/organize/stateful/browser.py +++ b/organize/stateful/browser.py @@ -27,16 +27,16 @@ from zope.app.pagetemplate import ViewPageTemplateFile from zope.cachedescriptors.property import Lazy from cybertools.browser.action import Action, actions -from cybertools.stateful.interfaces import IStateful +from cybertools.stateful.interfaces import IStateful, IStatesDefinition from loops.browser.common import BaseView from loops.browser.concept import ConceptView -from loops.expert import query +from loops.expert.query import And, Or, State, Type, getObjects from loops.search.browser import template as search_template from loops.util import _ -statefulActions = ('loops.classification_quality', - 'loops.simple_publishing',) +statefulActions = ('classification_quality', + 'simple_publishing',) class StateAction(Action): @@ -84,9 +84,48 @@ class StateQuery(BaseView): def macro(self): return self.template.macros['query'] + @Lazy + def statesDefinitions(self): + result = {} + result['resource'] = [component.getUtility(IStatesDefinition, name=n) + for n in self.globalOptions('organize.stateful.resource', ())] + result['concept'] = [component.getUtility(IStatesDefinition, name=n) + for n in self.globalOptions('organize.stateful.concept', ())] + return result + + @Lazy + def selectedStates(self): + result = {} + for k, v in self.request.form.items(): + if k.startswith('state.') and v: + result[k] = v + return result + @Lazy def results(self): - uids = query.State('loops.classification_quality', - #['new', 'unclassified', 'classified']).apply() - ['new', 'unclassified']).apply() - return self.viewIterator(query.getObjects(uids, self.loopsRoot)) + conceptCriteria = {} + resourceCriteria = {} + q = None + for k, v in self.selectedStates.items(): + k = k[len('state.'):] + type, statesDef = k.split('.') + if type == 'concept': + conceptCriteria[statesDef] = v + elif type == 'resource': + resourceCriteria[statesDef] = v + if conceptCriteria: + conceptQuery = And(Type('loops:concept:*'), + *[State(c, v) for c, v in conceptCriteria.items()]) + if resourceCriteria: + resourceQuery = And(Type('loops:resource:*'), + *[State(c, v) for c, v in resourceCriteria.items()]) + if conceptCriteria: + q = Or(conceptQuery, resourceQuery) + else: + q = resourceQuery + elif conceptCriteria: + q = conceptQuery + if q is not None: + uids = q.apply() + return self.viewIterator(getObjects(uids, self.loopsRoot)) + return [] diff --git a/organize/stateful/configure.zcml b/organize/stateful/configure.zcml index 5c23a31..5f84a96 100644 --- a/organize/stateful/configure.zcml +++ b/organize/stateful/configure.zcml @@ -16,11 +16,11 @@ + name="simple_publishing" /> + name="simple_publishing" trusted="True" /> @@ -30,11 +30,11 @@ + name="classification_quality" /> + name="classification_quality" trusted="True" /> diff --git a/organize/stateful/quality.py b/organize/stateful/quality.py index 132aca3..f78955b 100644 --- a/organize/stateful/quality.py +++ b/organize/stateful/quality.py @@ -39,7 +39,7 @@ from loops.versioning.interfaces import IVersionable @implementer(IStatesDefinition) def classificationQuality(): - return StatesDefinition('classificationQuality', + return StatesDefinition('classification_quality', State('new', 'new', ('classify', 'verify', 'change_classification', 'remove_classification'), color='red'), @@ -60,7 +60,7 @@ def classificationQuality(): class ClassificationQualityCheckable(StatefulLoopsObject): - statesDefinition = 'loops.classification_quality' + statesDefinition = 'classification_quality' def getAvailableTransitionsForUser(self): return [tr for tr in self.getAvailableTransitions() @@ -127,11 +127,11 @@ class ClassificationQualityCheckable(StatefulLoopsObject): @adapter(ILoopsObject, IAssignmentEvent) def assign(obj, event): stf = component.getAdapter(event.relation.second, IStateful, - name='loops.classification_quality') + name='classification_quality') stf.assign(event.relation) @adapter(ILoopsObject, IDeassignmentEvent) def deassign(obj, event): stf = component.getAdapter(event.relation.second, IStateful, - name='loops.classification_quality') + name='classification_quality') stf.deassign(event.relation) diff --git a/organize/stateful/view_macros.pt b/organize/stateful/view_macros.pt index 227843b..41aa2c7 100644 --- a/organize/stateful/view_macros.pt +++ b/organize/stateful/view_macros.pt @@ -2,5 +2,49 @@ - +
+
+ +

Select Objects by State

+
+ + + + + + + + + + + + + +
Object TypeWorkflowStates
+ + + + +   + +
+ +
+
+ + +
diff --git a/search/browser.py b/search/browser.py index b5ba843..1f523fb 100644 --- a/search/browser.py +++ b/search/browser.py @@ -34,6 +34,7 @@ from cybertools.ajax import innerHtml from cybertools.relation.interfaces import IRelationRegistry from cybertools.typology.interfaces import ITypeManager from loops.browser.common import BaseView +from loops.browser.node import NodeView from loops.common import adapted from loops.query import ConceptQuery, FullQuery from loops import util @@ -137,7 +138,8 @@ class Search(BaseView): '%s/.target%s/@@searchresults.html' % (view.url, self.uniqueId)) -class SearchResults(BaseView): +#class SearchResults(BaseView): +class SearchResults(NodeView): """ Provides results as inner HTML """ @Lazy diff --git a/search/search.pt b/search/search.pt index f0e3f83..670f19e 100644 --- a/search/search.pt +++ b/search/search.pt @@ -44,7 +44,9 @@
+ tal:define="item nocall:view; + controller nocall:view/@@controller; + resourceBase controller/resourceBase;">
@@ -60,6 +62,8 @@ Size Modification Date Author(s) + Info @@ -88,6 +92,12 @@ modified John + +
+