127 lines
5.3 KiB
Python
127 lines
5.3 KiB
Python
# w.c.s. - web application for online forms
|
|
# Copyright (C) 2005-2010 Entr'ouvert
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from wcs.qommon.humantime import *
|
|
|
|
from wcs.workflows import Workflow, WorkflowStatusJumpItem, register_item_class
|
|
|
|
from wcs.formdata import Evolution
|
|
from qommon.form import *
|
|
from qommon.publisher import get_publisher_class
|
|
from qommon.cron import CronJob
|
|
|
|
class TimeoutWorkflowStatusItem(WorkflowStatusJumpItem):
|
|
description = N_('Change Status on Timeout')
|
|
key = 'timeout'
|
|
waitpoint = True
|
|
|
|
timeout = None
|
|
|
|
_granularity = 20 * 60 # default: 20 minutes, see bottom of file
|
|
|
|
def render_as_line(self):
|
|
if self.status and self.get_status() and self.timeout:
|
|
return _('Change Status on Timeout to "%(status)s" after %(time)s') % \
|
|
{'status': self.get_status().name, 'time': seconds2humanduration(self.timeout)}
|
|
else:
|
|
return _('Change Status on Timeout (not completed)')
|
|
|
|
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None):
|
|
WorkflowStatusJumpItem.add_parameters_widgets(self, form, parameters, prefix, formdef)
|
|
if 'timeout' in parameters:
|
|
_hint = htmltext(_("ex.: 7 days 1 minute<br/> Usable units of time: %(variables)s. " \
|
|
'<br/><span class="warning">Minimal duration is %(granularity)s</span>')) % {
|
|
'variables': ','.join(timewords()),
|
|
'granularity': seconds2humanduration(self._granularity)}
|
|
form.add(StringWidget, 'timeout', title=_('Timeout'),
|
|
value=seconds2humanduration(self.timeout), hint=_hint)
|
|
|
|
def timeout_parse(self, value):
|
|
try:
|
|
return humanduration2seconds(value)
|
|
except ValueError:
|
|
return None
|
|
|
|
def get_parameters(self):
|
|
return ('status', 'timeout')
|
|
|
|
|
|
def workflows_with_timeout():
|
|
'''Return a list of workflow objects with at least a status with a timeout object
|
|
'''
|
|
wfs_status = {}
|
|
|
|
for id in Workflow.keys():
|
|
workflow = Workflow.get(id, ignore_errors = True)
|
|
if not workflow:
|
|
continue
|
|
for status in workflow.possible_status:
|
|
status_str = 'wf-%s' % status.id
|
|
for item in status.items:
|
|
if isinstance(item, TimeoutWorkflowStatusItem) and item.status and item.timeout:
|
|
if not wfs_status.has_key(id):
|
|
wfs_status[id] = {}
|
|
if not wfs_status[id].has_key(status_str):
|
|
wfs_status[id][status_str] = []
|
|
if not item.get_status():
|
|
# this will catch status being a removed status
|
|
continue
|
|
wfs_status[id][status_str].append(item)
|
|
|
|
return wfs_status
|
|
|
|
def _apply_timeouts(publisher):
|
|
'''Traverse all filled form and apply expired timeout jumps if needed'''
|
|
from formdef import FormDef
|
|
wfs_status = workflows_with_timeout()
|
|
|
|
for formdef_id in FormDef.keys():
|
|
formdef = FormDef.get(formdef_id, ignore_errors = True)
|
|
if not formdef:
|
|
continue
|
|
if str(formdef.workflow_id) in wfs_status.keys():
|
|
for formdata_id in formdef.data_class().keys():
|
|
formdata = formdef.data_class().get(formdata_id, ignore_errors = True)
|
|
if not formdata:
|
|
continue
|
|
if formdata.status in wfs_status[str(formdef.workflow_id)]:
|
|
if formdata.evolution:
|
|
last = formdata.evolution[-1].time
|
|
else:
|
|
last = formdata.receipt_time
|
|
diff = time.time() - time.mktime(last)
|
|
for x in wfs_status[str(formdef.workflow_id)][formdata.status]:
|
|
if diff > x.timeout:
|
|
evo = Evolution()
|
|
evo.time = time.localtime()
|
|
evo.status = 'wf-%s' % x.status
|
|
if not formdata.evolution:
|
|
formdata.evolution = []
|
|
formdata.evolution.append(evo)
|
|
formdata.status = evo.status
|
|
formdata.store()
|
|
formdata.perform_workflow()
|
|
break
|
|
|
|
register_item_class(TimeoutWorkflowStatusItem)
|
|
|
|
if get_publisher_class():
|
|
# every 20 minutes check for expired status jump timeouts. If you change
|
|
# cronjob schedule, change also the granularity variable
|
|
TimeoutWorkflowStatusItem._granularity = 20*60 # 20 minutes
|
|
get_publisher_class().register_cronjob(
|
|
CronJob(_apply_timeouts, hours=range(24), minutes=range(0,60,20)))
|