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:
parent
8b5df16afc
commit
9b8b0096fd
12 changed files with 160 additions and 48 deletions
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
=============
|
||||
|
|
|
@ -56,7 +56,7 @@ class StatefulLoopsObject(Stateful, StatefulAdapter):
|
|||
|
||||
class SimplePublishable(StatefulLoopsObject):
|
||||
|
||||
statesDefinition = 'loops.simple_publishing'
|
||||
statesDefinition = 'simple_publishing'
|
||||
|
||||
|
||||
class StatefulResourceIndexInfo(IndexInfo):
|
||||
|
|
|
@ -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 []
|
||||
|
|
|
@ -16,11 +16,11 @@
|
|||
|
||||
<zope:utility
|
||||
factory="cybertools.stateful.publishing.simplePublishing"
|
||||
name="loops.simple_publishing" />
|
||||
name="simple_publishing" />
|
||||
|
||||
<zope:adapter
|
||||
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">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.stateful.interfaces.IStateful" />
|
||||
|
@ -30,11 +30,11 @@
|
|||
|
||||
<zope:utility
|
||||
factory="loops.organize.stateful.quality.classificationQuality"
|
||||
name="loops.classification_quality" />
|
||||
name="classification_quality" />
|
||||
|
||||
<zope:adapter
|
||||
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">
|
||||
<require permission="zope.View"
|
||||
interface="cybertools.stateful.interfaces.IStateful" />
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -2,5 +2,49 @@
|
|||
|
||||
|
||||
<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="" />
|
||||
|
||||
</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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -44,7 +44,9 @@
|
|||
<div metal:define-macro="search_results" id="1.search.results"
|
||||
tal:attributes="id resultsId | request/search.resultsId"
|
||||
i18n:domain="loops"
|
||||
tal:define="item nocall:view">
|
||||
tal:define="item nocall:view;
|
||||
controller nocall:view/@@controller;
|
||||
resourceBase controller/resourceBase;">
|
||||
<fieldset class="box"
|
||||
tal:condition="request/search.submitted | nothing">
|
||||
<metal:results define-macro="results">
|
||||
|
@ -60,6 +62,8 @@
|
|||
<th i18n:translate="">Size</th>
|
||||
<th i18n:translate="">Modification Date</th>
|
||||
<th i18n:translate="">Author(s)</th>
|
||||
<th i18n:translate=""
|
||||
tal:condition="view/showObjectActions">Info</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
@ -88,6 +92,12 @@
|
|||
</td>
|
||||
<td><span tal:replace="row/modified">modified</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>
|
||||
</tal:item>
|
||||
</tal:items>
|
||||
|
|
Loading…
Add table
Reference in a new issue