improve queries: make configurable via query options
git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@3181 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
parent
8ef18c8b59
commit
466f05e5a8
4 changed files with 113 additions and 51 deletions
|
@ -102,16 +102,15 @@ by calling the form controller's update method
|
||||||
Work items views
|
Work items views
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
>>> from loops.organize.work.browser import WorkItemView, WorkItemsView
|
>>> from loops.organize.work.browser import WorkItemView, TaskWorkItems
|
||||||
>>> wi01 = workItems['0000001']
|
>>> wi01 = workItems['0000001']
|
||||||
>>> view = WorkItemView(wi01, TestRequest())
|
>>> view = WorkItemView(wi01, TestRequest())
|
||||||
>>> view.taskUrl
|
>>> view.taskUrl
|
||||||
'http://127.0.0.1/loops/concepts/loops_dev/@@SelectedManagementView.html'
|
'http://127.0.0.1/loops/concepts/loops_dev/@@SelectedManagementView.html'
|
||||||
|
|
||||||
>>> itemsView = WorkItemsView(home, request)
|
>>> work = TaskWorkItems(task01, request)
|
||||||
|
|
||||||
>>> from loops.organize.work.browser import WorkItemDetails
|
>>> from loops.organize.work.browser import WorkItemDetails
|
||||||
>>> view = WorkItemDetails(itemsView, wi01)
|
>>> view = WorkItemDetails(work, wi01)
|
||||||
>>> view.day, view.start, view.end
|
>>> view.day, view.start, view.end
|
||||||
(u'08/12/28', u'19:00', u'20:15')
|
(u'08/12/28', u'19:00', u'20:15')
|
||||||
|
|
||||||
|
@ -144,6 +143,39 @@ work item, the form will be pre-filled with some of the item's data.
|
||||||
{'name': 'modify', 'title': 'modify'}]
|
{'name': 'modify', 'title': 'modify'}]
|
||||||
|
|
||||||
|
|
||||||
|
Work Item Queries
|
||||||
|
=================
|
||||||
|
|
||||||
|
>>> from loops.common import adapted
|
||||||
|
>>> from loops.expert.concept import IQueryConcept
|
||||||
|
>>> from loops.organize.work.browser import UserWorkItems, PersonWorkItems
|
||||||
|
|
||||||
|
>>> tQuery = addAndConfigureObject(concepts, Concept, 'query',
|
||||||
|
... title=u'Query', conceptType=concepts.getTypeConcept(),
|
||||||
|
... typeInterface=IQueryConcept)
|
||||||
|
|
||||||
|
>>> query = addAndConfigureObject(concepts, Concept, 'userworkitems',
|
||||||
|
... conceptType=tQuery)
|
||||||
|
|
||||||
|
The UserWorkItems view does not give any results because there is no current
|
||||||
|
user (principal) available in our test setting.
|
||||||
|
|
||||||
|
>>> work = UserWorkItems(query, TestRequest())
|
||||||
|
>>> work.listWorkItems()
|
||||||
|
|
||||||
|
So we use the PersonWorkItems view, assigning john to the query.
|
||||||
|
|
||||||
|
>>> query.assignParent(johnC)
|
||||||
|
>>> adapted(query).options = ['wi_from:2009-01-01', 'wi_to:today']
|
||||||
|
|
||||||
|
>>> input = dict()
|
||||||
|
>>> work = PersonWorkItems(query, TestRequest(form=input))
|
||||||
|
>>> work.listWorkItems()
|
||||||
|
[<WorkItem ['36', 2, '33', '2009-01-19 08:00', 'planned']:
|
||||||
|
{'start': 1232352000, 'created': ..., 'title': u'Install Zope',
|
||||||
|
'creator': '33'}>]
|
||||||
|
|
||||||
|
|
||||||
Fin de partie
|
Fin de partie
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ View class(es) for work items.
|
||||||
$Id$
|
$Id$
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
import time
|
import time
|
||||||
from zope import component
|
from zope import component
|
||||||
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
|
from zope.app.security.interfaces import IAuthentication, PrincipalLookupError
|
||||||
|
@ -165,6 +166,10 @@ class BaseWorkItemsView(object):
|
||||||
def work_macros(self):
|
def work_macros(self):
|
||||||
return work_macros.macros
|
return work_macros.macros
|
||||||
|
|
||||||
|
@property
|
||||||
|
def macro(self):
|
||||||
|
return self.work_macros['workitems_query']
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
def workItems(self):
|
def workItems(self):
|
||||||
rm = self.loopsRoot.getRecordManager()
|
rm = self.loopsRoot.getRecordManager()
|
||||||
|
@ -177,15 +182,21 @@ class BaseWorkItemsView(object):
|
||||||
def baseCriteria(self):
|
def baseCriteria(self):
|
||||||
result = {}
|
result = {}
|
||||||
form = self.request.form
|
form = self.request.form
|
||||||
start = parseDate(form.get('wi_start'))
|
tsFrom = parseDate(form.get('wi_from') or self.options.wi_from)
|
||||||
end = parseDate(form.get('wi_end'))
|
tsTo = parseDate(form.get('wi_to') or self.options.wi_to)
|
||||||
if end:
|
if tsTo:
|
||||||
end += 3600 * 24 # include full end date
|
tsTo += 3600 * 24 # include full end date
|
||||||
if start or end:
|
if tsFrom or tsTo:
|
||||||
result['timeFromTo'] = (start, end)
|
result['timeFromTo'] = (tsFrom, tsTo)
|
||||||
state = form.get('wi_state')
|
state = form.get('wi_state') or self.options.wi_state
|
||||||
if state is not None:
|
if not state:
|
||||||
result['state'] = state
|
result['state'] = ['planned', 'accepted', 'running', 'done', 'done_x',
|
||||||
|
'finished', 'delegated']
|
||||||
|
else:
|
||||||
|
if state == 'all':
|
||||||
|
del result['state']
|
||||||
|
else:
|
||||||
|
result['state'] = state
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def query(self, **criteria):
|
def query(self, **criteria):
|
||||||
|
@ -195,17 +206,15 @@ class BaseWorkItemsView(object):
|
||||||
for wi in self.workItems.query(**criteria)]
|
for wi in self.workItems.query(**criteria)]
|
||||||
|
|
||||||
|
|
||||||
class WorkItemsView(BaseWorkItemsView, NodeView):
|
class TaskWorkItems(BaseWorkItemsView, ConceptView):
|
||||||
""" Standard view for showing work items for a node's target.
|
""" Standard view for showing work items for a node's target.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
columns = set(['User', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
|
columns = set(['User', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def listWorkItems(self):
|
def listWorkItems(self):
|
||||||
target = self.virtualTargetObject
|
|
||||||
criteria = self.baseCriteria
|
criteria = self.baseCriteria
|
||||||
criteria['task'] = util.getUidForObject(target)
|
criteria['task'] = util.getUidForObject(self.context)
|
||||||
return sorted(self.query(**criteria), key=lambda x: x.track.timeStamp)
|
return sorted(self.query(**criteria), key=lambda x: x.track.timeStamp)
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,22 +224,9 @@ class PersonWorkItems(BaseWorkItemsView, ConceptView):
|
||||||
|
|
||||||
columns = set(['Task', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
|
columns = set(['Task', 'Title', 'Day', 'Start', 'End', 'Duration', 'Info'])
|
||||||
|
|
||||||
@property
|
|
||||||
def macro(self):
|
|
||||||
return self.work_macros['userworkitems']
|
|
||||||
|
|
||||||
def getCriteria(self):
|
def getCriteria(self):
|
||||||
crit = self.baseCriteria
|
return self.baseCriteria
|
||||||
tft = crit.get('timeFromTo') or (None, None)
|
|
||||||
if not tft[0]:
|
|
||||||
tft = (getTimeStamp() - (3 * 24 * 3600), tft[1])
|
|
||||||
crit['timeFromTo'] = tft
|
|
||||||
if not crit.get('state'):
|
|
||||||
crit['state'] = ['planned', 'accepted', 'running', 'done', 'done_x',
|
|
||||||
'finished', 'delegated']
|
|
||||||
return crit
|
|
||||||
|
|
||||||
@Lazy
|
|
||||||
def listWorkItems(self):
|
def listWorkItems(self):
|
||||||
criteria = self.getCriteria()
|
criteria = self.getCriteria()
|
||||||
for target in self.context.getParents([self.defaultPredicate]):
|
for target in self.context.getParents([self.defaultPredicate]):
|
||||||
|
@ -239,6 +235,16 @@ class PersonWorkItems(BaseWorkItemsView, ConceptView):
|
||||||
return sorted(self.query(**criteria), key=lambda x: x.track.timeStamp)
|
return sorted(self.query(**criteria), key=lambda x: x.track.timeStamp)
|
||||||
|
|
||||||
|
|
||||||
|
class UserWorkItems(PersonWorkItems):
|
||||||
|
|
||||||
|
def listWorkItems(self):
|
||||||
|
criteria = self.getCriteria()
|
||||||
|
p = getPersonForUser(self.context, self.request)
|
||||||
|
if p is not None:
|
||||||
|
criteria['userName'] = util.getUidForObject(p)
|
||||||
|
return sorted(self.query(**criteria), key=lambda x: x.track.timeStamp)
|
||||||
|
|
||||||
|
|
||||||
# forms and form controllers
|
# forms and form controllers
|
||||||
|
|
||||||
class CreateWorkItemForm(ObjectForm, BaseTrackView):
|
class CreateWorkItemForm(ObjectForm, BaseTrackView):
|
||||||
|
@ -344,19 +350,15 @@ class CreateWorkItem(EditObject, BaseTrackView):
|
||||||
for k in ('title', 'description', 'comment'):
|
for k in ('title', 'description', 'comment'):
|
||||||
setValue(k)
|
setValue(k)
|
||||||
startDate = form.get('start_date', '').strip()
|
startDate = form.get('start_date', '').strip()
|
||||||
startTime = form.get('start_time', '').strip().replace('T', '')
|
startTime = form.get('start_time', '').strip().replace('T', '') or '00:00:00'
|
||||||
endTime = form.get('end_time', '').strip().replace('T', '')
|
endTime = form.get('end_time', '').strip().replace('T', '') or '00:00:00'
|
||||||
#print '***', startDate, startTime, endTime
|
#print '***', startDate, startTime, endTime
|
||||||
if startDate and startTime:
|
#if startDate and startTime:
|
||||||
|
if startDate:
|
||||||
result['start'] = parseDateTime('T'.join((startDate, startTime)))
|
result['start'] = parseDateTime('T'.join((startDate, startTime)))
|
||||||
if startDate and endTime:
|
|
||||||
result['end'] = parseDateTime('T'.join((startDate, endTime)))
|
result['end'] = parseDateTime('T'.join((startDate, endTime)))
|
||||||
duration = form.get('duration')
|
result['duration'] = parseTime(form.get('duration'))
|
||||||
if duration:
|
result['effort'] = parseTime(form.get('effort'))
|
||||||
result['duration'] = parseTime(duration)
|
|
||||||
effort = form.get('effort')
|
|
||||||
if effort:
|
|
||||||
result['effort'] = parseTime(effort)
|
|
||||||
return action, result
|
return action, result
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
|
@ -403,6 +405,9 @@ class WorkItemStateAction(StateAction):
|
||||||
|
|
||||||
# auxiliary functions
|
# auxiliary functions
|
||||||
|
|
||||||
|
specialDays = ['yesterday', 'today', 'tomorrow']
|
||||||
|
weekDays = ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday']
|
||||||
|
|
||||||
def parseTime(s):
|
def parseTime(s):
|
||||||
if not s:
|
if not s:
|
||||||
return None
|
return None
|
||||||
|
@ -420,6 +425,20 @@ def parseDateTime(s):
|
||||||
def parseDate(s):
|
def parseDate(s):
|
||||||
if not s:
|
if not s:
|
||||||
return None
|
return None
|
||||||
|
if isinstance(s, (list, tuple)):
|
||||||
|
s = s[0]
|
||||||
|
if s[0] in ('-', '+') or s.isdigit():
|
||||||
|
delta = int(s) * 3600 * 24
|
||||||
|
return int(time.mktime(date.today().timetuple())) + delta
|
||||||
|
elif s in specialDays:
|
||||||
|
delta = (specialDays.index(s) - 1) * 3600 * 24
|
||||||
|
return int(time.mktime(date.today().timetuple())) + delta
|
||||||
|
elif s in weekDays:
|
||||||
|
wd = weekDays.index(s)
|
||||||
|
today = date.today()
|
||||||
|
todayWd = today.weekday
|
||||||
|
delta = (wd + 8 - todayWd) % 8
|
||||||
|
return int(time.mktime(today.timetuple())) + delta
|
||||||
return int(time.mktime(time.strptime(s, '%Y-%m-%d')))
|
return int(time.mktime(time.strptime(s, '%Y-%m-%d')))
|
||||||
|
|
||||||
def formatTimeDelta(value):
|
def formatTimeDelta(value):
|
||||||
|
|
|
@ -22,11 +22,13 @@
|
||||||
|
|
||||||
<!-- application views -->
|
<!-- application views -->
|
||||||
|
|
||||||
<browser:page
|
<zope:adapter
|
||||||
name="workitems.html"
|
name="taskworkitems.html"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.IConcept
|
||||||
class="loops.organize.work.browser.WorkItemsView"
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
permission="zope.View" />
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.organize.work.browser.TaskWorkItems"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
<zope:adapter
|
<zope:adapter
|
||||||
name="personworkitems.html"
|
name="personworkitems.html"
|
||||||
|
@ -36,6 +38,14 @@
|
||||||
factory="loops.organize.work.browser.PersonWorkItems"
|
factory="loops.organize.work.browser.PersonWorkItems"
|
||||||
permission="zope.View" />
|
permission="zope.View" />
|
||||||
|
|
||||||
|
<zope:adapter
|
||||||
|
name="userworkitems.html"
|
||||||
|
for="loops.interfaces.IConcept
|
||||||
|
zope.publisher.interfaces.browser.IBrowserRequest"
|
||||||
|
provides="zope.interface.Interface"
|
||||||
|
factory="loops.organize.work.browser.UserWorkItems"
|
||||||
|
permission="zope.View" />
|
||||||
|
|
||||||
<browser:page
|
<browser:page
|
||||||
name="create_workitem.html"
|
name="create_workitem.html"
|
||||||
for="loops.interfaces.INode"
|
for="loops.interfaces.INode"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
<metal:work define-macro="workitems"
|
<metal:work define-macro="workitems"
|
||||||
tal:define="work nocall:view/workItems"
|
tal:define="work nocall:view/workItems"
|
||||||
tal:condition="work/listWorkItems">
|
tal:condition="work/listWorkItems|nothing">
|
||||||
<br />
|
<br />
|
||||||
<h2 i18n:translate="">Work Items</h2>
|
<h2 i18n:translate="">Work Items</h2>
|
||||||
<metal:workitems define-macro="workitems_listing"
|
<metal:workitems define-macro="workitems_listing"
|
||||||
|
@ -49,10 +49,11 @@
|
||||||
</metal:workitems>
|
</metal:workitems>
|
||||||
</metal:work>
|
</metal:work>
|
||||||
|
|
||||||
<metal:work define-macro="userworkitems"
|
|
||||||
|
<metal:work define-macro="workitems_query"
|
||||||
tal:define="work nocall:item">
|
tal:define="work nocall:item">
|
||||||
<br />
|
<br />
|
||||||
<h2 i18n:translate="" tal:content="item/title">Work Items</h2>
|
<metal:block use-macro="view/concept_macros/concepttitle" />
|
||||||
<metal:workitems use-macro="item/work_macros/workitems_listing" />
|
<metal:workitems use-macro="item/work_macros/workitems_listing" />
|
||||||
</metal:work>
|
</metal:work>
|
||||||
|
|
||||||
|
@ -106,11 +107,11 @@
|
||||||
<div id="duration-effort">
|
<div id="duration-effort">
|
||||||
<input type="text" name="duration" style="width: 5em"
|
<input type="text" name="duration" style="width: 5em"
|
||||||
dojoType="dijit.form.ValidationTextBox"
|
dojoType="dijit.form.ValidationTextBox"
|
||||||
regexp="[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
||||||
tal:attributes="value view/duration" /> /
|
tal:attributes="value view/duration" /> /
|
||||||
<input type="text" name="effort" style="width: 5em"
|
<input type="text" name="effort" style="width: 5em"
|
||||||
dojoType="dijit.form.ValidationTextBox"
|
dojoType="dijit.form.ValidationTextBox"
|
||||||
regexp="[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
regexp="-{0,1}[0-9]{1,2}(:[0-5][0-9]){0,1}"
|
||||||
tal:attributes="value view/effort" /></div>
|
tal:attributes="value view/effort" /></div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
Loading…
Add table
Reference in a new issue