let user provide search criteria for states query

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2599 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2008-05-16 10:10:28 +00:00
parent 8b5df16afc
commit 9b8b0096fd
12 changed files with 160 additions and 48 deletions

View file

@ -267,7 +267,10 @@ class BaseView(GenericView, I18NView):
def viewIterator(self, objs): def viewIterator(self, objs):
request = self.request request = self.request
for o in objs: 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): def renderText(self, text, contentType):
typeKey = util.renderingFactories.get(contentType, None) typeKey = util.renderingFactories.get(contentType, None)
@ -391,11 +394,10 @@ class BaseView(GenericView, I18NView):
if not checkPermission('loops.ManageSite', self.context): if not checkPermission('loops.ManageSite', self.context):
# TODO: replace by more sensible permission # TODO: replace by more sensible permission
return result return result
#statesDefs = ['loops.classification_quality', 'loops.simple_publishing']
if IResource.providedBy(self.target): if IResource.providedBy(self.target):
statesDefs = self.globalOptions('organize.stateful.resource', ()) statesDefs = self.globalOptions('organize.stateful.resource', ())
else: else:
statesDefs = () statesDefs = self.globalOptions('organize.stateful.concept', ())
for std in statesDefs: for std in statesDefs:
stf = component.getAdapter(self.target, IStateful, name=std) stf = component.getAdapter(self.target, IStateful, name=std)
result.append(stf) result.append(stf)

View file

@ -111,8 +111,6 @@ class ObjectForm(NodeView):
@Lazy @Lazy
def schema(self): def schema(self):
#ti = self.typeInterface or IConceptSchema
#schemaFactory = component.getAdapter(self.adapted, ISchemaFactory)
schemaFactory = ISchemaFactory(self.adapted) schemaFactory = ISchemaFactory(self.adapted)
return schemaFactory(self.typeInterface, manager=self, return schemaFactory(self.typeInterface, manager=self,
request=self.request) request=self.request)
@ -398,9 +396,7 @@ class EditObject(FormController, I18NView):
@Lazy @Lazy
def schema(self): def schema(self):
#schemaFactory = component.getAdapter(self.adapted, ISchemaFactory)
schemaFactory = ISchemaFactory(self.adapted) schemaFactory = ISchemaFactory(self.adapted)
#return schemaFactory(self.typeInterface)
return schemaFactory(self.typeInterface, manager=self, return schemaFactory(self.typeInterface, manager=self,
request=self.request) request=self.request)

View file

@ -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 As we have not yet set up any states definitions for our objects we get
an empty result. an empty result.
>>> qu = query.State('loops.classification_quality', 'classified') >>> qu = query.State('classification_quality', 'classified')
>>> list(qu.apply()) >>> list(qu.apply())
[] []
@ -78,12 +78,12 @@ corresponding adapter and activate it for the current loops site.
>>> from loops.organize.stateful.quality import classificationQuality >>> from loops.organize.stateful.quality import classificationQuality
>>> component.provideUtility(classificationQuality(), >>> component.provideUtility(classificationQuality(),
... name='loops.classification_quality') ... name='classification_quality')
>>> from loops.organize.stateful.quality import ClassificationQualityCheckable >>> from loops.organize.stateful.quality import ClassificationQualityCheckable
>>> component.provideAdapter(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 We have now to reindex all documents so that the state index gets populated
according to the new settings. 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 Now the three documents we are working with are shown as classified (as
they have at least one concept assigned). they have at least one concept assigned).
>>> qu = query.State('loops.classification_quality', 'classified') >>> qu = query.State('classification_quality', 'classified')
>>> list(qu.apply()) >>> list(qu.apply())
[23, 25, 27] [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 >>> from cybertools.stateful.interfaces import IStateful
>>> statefulD001 = component.getAdapter(resources['d001.txt'], IStateful, >>> statefulD001 = component.getAdapter(resources['d001.txt'], IStateful,
... name='loops.classification_quality') ... name='classification_quality')
>>> statefulD001.doTransition('verify') >>> statefulD001.doTransition('verify')
Now only two resources are still in the ``qualified`` state, the changed 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()) >>> list(qu.apply())
[25, 27] [25, 27]
>>> qu = query.State('loops.classification_quality', 'verified') >>> qu = query.State('classification_quality', 'verified')
>>> list(qu.apply()) >>> list(qu.apply())
[23] [23]
We may also provide a sequence of states for querying. 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()) >>> list(qu.apply())
[23, 25, 27] [23, 25, 27]

View file

@ -31,7 +31,7 @@ from zope.component import adapts
from zope.interface import implements, implementer from zope.interface import implements, implementer
from zope.cachedescriptors.property import Lazy 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 Text as BaseText
from cybertools.catalog.query import AnyOf from cybertools.catalog.query import AnyOf
from loops.expert.interfaces import IQuery from loops.expert.interfaces import IQuery

View file

@ -32,17 +32,17 @@ making an object statful we'll use an adapter.
>>> from cybertools.stateful.interfaces import IStatesDefinition, IStateful >>> from cybertools.stateful.interfaces import IStatesDefinition, IStateful
>>> from cybertools.stateful.publishing import simplePublishing >>> 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 >>> 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 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. check the document's state and perform transitions to other states.
>>> doc01 = resources['d001.txt'] >>> doc01 = resources['d001.txt']
>>> statefulDoc01 = component.getAdapter(doc01, IStateful, >>> statefulDoc01 = component.getAdapter(doc01, IStateful,
... name='loops.simple_publishing') ... name='simple_publishing')
>>> statefulDoc01.state >>> statefulDoc01.state
'draft' '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. not just kept in the adapter.
>>> statefulDoc01_x = component.getAdapter(doc01, IStateful, >>> statefulDoc01_x = component.getAdapter(doc01, IStateful,
... name='loops.simple_publishing') ... name='simple_publishing')
>>> statefulDoc01.state >>> statefulDoc01.state
'published' 'published'
@ -68,10 +68,10 @@ We again first have to register states definitions and adapter classes.
>>> from loops.organize.stateful.quality import classificationQuality >>> from loops.organize.stateful.quality import classificationQuality
>>> component.provideUtility(classificationQuality(), >>> component.provideUtility(classificationQuality(),
... name='loops.classification_quality') ... name='classification_quality')
>>> from loops.organize.stateful.quality import ClassificationQualityCheckable >>> from loops.organize.stateful.quality import ClassificationQualityCheckable
>>> component.provideAdapter(ClassificationQualityCheckable, >>> component.provideAdapter(ClassificationQualityCheckable,
... name='loops.classification_quality') ... name='classification_quality')
>>> from loops.organize.stateful.quality import assign, deassign >>> from loops.organize.stateful.quality import assign, deassign
>>> component.provideHandler(assign) >>> component.provideHandler(assign)
>>> component.provideHandler(deassign) >>> 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. Now we can get a stateful adapter for a resource.
>>> qcheckedDoc01 = component.getAdapter(doc01, IStateful, >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful,
... name='loops.classification_quality') ... name='classification_quality')
>>> qcheckedDoc01.state >>> qcheckedDoc01.state
'new' 'new'
@ -99,7 +99,7 @@ When we change the concept assignments of the resource - i.e. its classification
>>> c01.assignResource(doc01) >>> c01.assignResource(doc01)
>>> qcheckedDoc01 = component.getAdapter(doc01, IStateful, >>> qcheckedDoc01 = component.getAdapter(doc01, IStateful,
... name='loops.classification_quality') ... name='classification_quality')
>>> qcheckedDoc01.state >>> qcheckedDoc01.state
'classified' '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. The form view gives us access to the states of the object.
>>> loopsRoot.options = ['organize.stateful.resource:' >>> loopsRoot.options = ['organize.stateful.resource:'
... 'loops.classification_quality,loops.simple_publishing'] ... 'classification_quality,simple_publishing']
>>> form = EditObjectForm(node, TestRequest()) >>> form = EditObjectForm(node, TestRequest())
>>> for st in form.states: >>> for st in form.states:
@ -147,12 +147,12 @@ The form view gives us access to the states of the object.
... userTrans = st.getAvailableTransitionsForUser() ... userTrans = st.getAvailableTransitionsForUser()
... print st.statesDefinition, sto.title, [t.title for t in transitions], ... print st.statesDefinition, sto.title, [t.title for t in transitions],
... print [t.title for t in userTrans] ... print [t.title for t in userTrans]
loops.classification_quality unclassified ['classify', 'verify'] ['verify'] classification_quality unclassified ['classify', 'verify'] ['verify']
loops.simple_publishing published ['retract', 'archive'] ['retract', 'archive'] simple_publishing published ['retract', 'archive'] ['retract', 'archive']
Let's now update the form. Let's now update the form.
>>> input = {'state.loops.classification_quality': 'verify'} >>> input = {'state.classification_quality': 'verify'}
>>> proc = EditObject(form, TestRequest(form=input)) >>> proc = EditObject(form, TestRequest(form=input))
>>> proc.update() >>> proc.update()
False False
@ -160,6 +160,25 @@ Let's now update the form.
>>> qcheckedDoc01.state >>> qcheckedDoc01.state
'verified' '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 Fin de partie
============= =============

View file

@ -56,7 +56,7 @@ class StatefulLoopsObject(Stateful, StatefulAdapter):
class SimplePublishable(StatefulLoopsObject): class SimplePublishable(StatefulLoopsObject):
statesDefinition = 'loops.simple_publishing' statesDefinition = 'simple_publishing'
class StatefulResourceIndexInfo(IndexInfo): class StatefulResourceIndexInfo(IndexInfo):

View file

@ -27,16 +27,16 @@ from zope.app.pagetemplate import ViewPageTemplateFile
from zope.cachedescriptors.property import Lazy from zope.cachedescriptors.property import Lazy
from cybertools.browser.action import Action, actions 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.common import BaseView
from loops.browser.concept import ConceptView 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.search.browser import template as search_template
from loops.util import _ from loops.util import _
statefulActions = ('loops.classification_quality', statefulActions = ('classification_quality',
'loops.simple_publishing',) 'simple_publishing',)
class StateAction(Action): class StateAction(Action):
@ -84,9 +84,48 @@ class StateQuery(BaseView):
def macro(self): def macro(self):
return self.template.macros['query'] 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 @Lazy
def results(self): def results(self):
uids = query.State('loops.classification_quality', conceptCriteria = {}
#['new', 'unclassified', 'classified']).apply() resourceCriteria = {}
['new', 'unclassified']).apply() q = None
return self.viewIterator(query.getObjects(uids, self.loopsRoot)) 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 []

View file

@ -16,11 +16,11 @@
<zope:utility <zope:utility
factory="cybertools.stateful.publishing.simplePublishing" factory="cybertools.stateful.publishing.simplePublishing"
name="loops.simple_publishing" /> name="simple_publishing" />
<zope:adapter <zope:adapter
factory="loops.organize.stateful.base.SimplePublishable" factory="loops.organize.stateful.base.SimplePublishable"
name="loops.simple_publishing" trusted="True" /> name="simple_publishing" trusted="True" />
<zope:class class="loops.organize.stateful.base.SimplePublishable"> <zope:class class="loops.organize.stateful.base.SimplePublishable">
<require permission="zope.View" <require permission="zope.View"
interface="cybertools.stateful.interfaces.IStateful" /> interface="cybertools.stateful.interfaces.IStateful" />
@ -30,11 +30,11 @@
<zope:utility <zope:utility
factory="loops.organize.stateful.quality.classificationQuality" factory="loops.organize.stateful.quality.classificationQuality"
name="loops.classification_quality" /> name="classification_quality" />
<zope:adapter <zope:adapter
factory="loops.organize.stateful.quality.ClassificationQualityCheckable" factory="loops.organize.stateful.quality.ClassificationQualityCheckable"
name="loops.classification_quality" trusted="True" /> name="classification_quality" trusted="True" />
<zope:class class="loops.organize.stateful.quality.ClassificationQualityCheckable"> <zope:class class="loops.organize.stateful.quality.ClassificationQualityCheckable">
<require permission="zope.View" <require permission="zope.View"
interface="cybertools.stateful.interfaces.IStateful" /> interface="cybertools.stateful.interfaces.IStateful" />

View file

@ -39,7 +39,7 @@ from loops.versioning.interfaces import IVersionable
@implementer(IStatesDefinition) @implementer(IStatesDefinition)
def classificationQuality(): def classificationQuality():
return StatesDefinition('classificationQuality', return StatesDefinition('classification_quality',
State('new', 'new', ('classify', 'verify', State('new', 'new', ('classify', 'verify',
'change_classification', 'remove_classification'), 'change_classification', 'remove_classification'),
color='red'), color='red'),
@ -60,7 +60,7 @@ def classificationQuality():
class ClassificationQualityCheckable(StatefulLoopsObject): class ClassificationQualityCheckable(StatefulLoopsObject):
statesDefinition = 'loops.classification_quality' statesDefinition = 'classification_quality'
def getAvailableTransitionsForUser(self): def getAvailableTransitionsForUser(self):
return [tr for tr in self.getAvailableTransitions() return [tr for tr in self.getAvailableTransitions()
@ -127,11 +127,11 @@ class ClassificationQualityCheckable(StatefulLoopsObject):
@adapter(ILoopsObject, IAssignmentEvent) @adapter(ILoopsObject, IAssignmentEvent)
def assign(obj, event): def assign(obj, event):
stf = component.getAdapter(event.relation.second, IStateful, stf = component.getAdapter(event.relation.second, IStateful,
name='loops.classification_quality') name='classification_quality')
stf.assign(event.relation) stf.assign(event.relation)
@adapter(ILoopsObject, IDeassignmentEvent) @adapter(ILoopsObject, IDeassignmentEvent)
def deassign(obj, event): def deassign(obj, event):
stf = component.getAdapter(event.relation.second, IStateful, stf = component.getAdapter(event.relation.second, IStateful,
name='loops.classification_quality') name='classification_quality')
stf.deassign(event.relation) stf.deassign(event.relation)

View file

@ -2,5 +2,49 @@
<metal:query define-macro="query"> <metal:query define-macro="query">
<metal:results use-macro="item/search_macros/results" /> <div>
<form method="post">
<input type="hidden" name="search_submitted" value="yes" />
<h1 i18n:translate="">Select Objects by State</h1>
<br />
<table class="listing"
tal:define="defs item/statesDefinitions">
<tr>
<th i18n:translate="">Object Type</th>
<th i18n:translate="">Workflow</th>
<th i18n:translate="">States</th>
</tr>
<tal:def repeat="deftype defs">
<tr tal:repeat="def defs/?deftype">
<td valign="top">
<span tal:condition="repeat/def/start"
tal:content="deftype"
i18n:translate="" />
</td>
<td tal:content="def/name"
i18n:translate=""></td>
<td>
<tal:state repeat="state def/states">
<input type="checkbox"
tal:define="name string:state.$deftype.${def/name};
value state/name"
tal:attributes="name string:$name:list;
value value;
checked python:
value in item.selectedStates.get(name, ())"
/><span tal:content="state/title"
i18n:translate="" />
&nbsp;
</tal:state>
</td>
</tr>
</tal:def>
</table>
<input type="submit" name="button.search" value="Search" class="submit"
i18n:attributes="value" />
</form>
</div>
<tal:results condition="request/search_submitted|nothing">
<metal:results use-macro="item/search_macros/results" />
</tal:results>
</metal:query> </metal:query>

View file

@ -34,6 +34,7 @@ from cybertools.ajax import innerHtml
from cybertools.relation.interfaces import IRelationRegistry from cybertools.relation.interfaces import IRelationRegistry
from cybertools.typology.interfaces import ITypeManager from cybertools.typology.interfaces import ITypeManager
from loops.browser.common import BaseView from loops.browser.common import BaseView
from loops.browser.node import NodeView
from loops.common import adapted from loops.common import adapted
from loops.query import ConceptQuery, FullQuery from loops.query import ConceptQuery, FullQuery
from loops import util from loops import util
@ -137,7 +138,8 @@ class Search(BaseView):
'%s/.target%s/@@searchresults.html' % (view.url, self.uniqueId)) '%s/.target%s/@@searchresults.html' % (view.url, self.uniqueId))
class SearchResults(BaseView): #class SearchResults(BaseView):
class SearchResults(NodeView):
""" Provides results as inner HTML """ """ Provides results as inner HTML """
@Lazy @Lazy

View file

@ -44,7 +44,9 @@
<div metal:define-macro="search_results" id="1.search.results" <div metal:define-macro="search_results" id="1.search.results"
tal:attributes="id resultsId | request/search.resultsId" tal:attributes="id resultsId | request/search.resultsId"
i18n:domain="loops" i18n:domain="loops"
tal:define="item nocall:view"> tal:define="item nocall:view;
controller nocall:view/@@controller;
resourceBase controller/resourceBase;">
<fieldset class="box" <fieldset class="box"
tal:condition="request/search.submitted | nothing"> tal:condition="request/search.submitted | nothing">
<metal:results define-macro="results"> <metal:results define-macro="results">
@ -60,6 +62,8 @@
<th i18n:translate="">Size</th> <th i18n:translate="">Size</th>
<th i18n:translate="">Modification Date</th> <th i18n:translate="">Modification Date</th>
<th i18n:translate="">Author(s)</th> <th i18n:translate="">Author(s)</th>
<th i18n:translate=""
tal:condition="view/showObjectActions">Info</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -88,6 +92,12 @@
</td> </td>
<td><span tal:replace="row/modified">modified</span></td> <td><span tal:replace="row/modified">modified</span></td>
<td><span tal:replace="row/creators">John</span></td> <td><span tal:replace="row/creators">John</span></td>
<td style="white-space: nowrap"
tal:define="target nocall:row;
style nothing"
tal:condition="view/showObjectActions">
<div metal:use-macro="views/node_macros/object_actions" />
</td>
</tr> </tr>
</tal:item> </tal:item>
</tal:items> </tal:items>