wcs/wcs/wf/timeout_jump.py

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)))