workflows: allow generated timeout to be in "human time" (#54930)

This commit is contained in:
Frédéric Péters 2021-11-01 20:56:03 +01:00
parent aa721f2b8e
commit 5b0a943366
2 changed files with 107 additions and 3 deletions

View File

@ -2431,6 +2431,88 @@ def test_timeout(two_pubs):
_apply_timeouts(two_pubs)
def test_timeout_with_humantime_template(two_pubs):
workflow = Workflow(name='timeout')
st1 = workflow.add_status('Status1', 'st1')
workflow.add_status('Status2', 'st2')
jump = JumpWorkflowStatusItem()
jump.id = '_jump'
jump.by = ['_submitter', '_receiver']
jump.timeout = '{{ 30 }} minutes'
jump.status = 'st2'
st1.items.append(jump)
jump.parent = st1
workflow.store()
formdef = FormDef()
formdef.name = 'baz'
formdef.fields = []
formdef.workflow_id = workflow.id
assert formdef.get_workflow().id == workflow.id
formdef.store()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
formdata_id = formdata.id
_apply_timeouts(two_pubs)
assert formdef.data_class().get(formdata_id).status == 'wf-st1' # no change
rewind(formdata, seconds=40 * 60)
formdata.store()
_apply_timeouts(two_pubs)
assert formdef.data_class().get(formdata_id).status == 'wf-st2'
# invalid timeout value
jump.timeout = '{{ 30 }} plop'
workflow.store()
formdef.refresh_from_storage()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
formdata_id = formdata.id
if two_pubs.is_using_postgresql():
two_pubs.loggederror_class.wipe()
rewind(formdata, seconds=40 * 60)
formdata.store()
_apply_timeouts(two_pubs)
assert formdef.data_class().get(formdata_id).status == 'wf-st1' # no change
if two_pubs.is_using_postgresql():
assert two_pubs.loggederror_class.count() == 1
logged_error = two_pubs.loggederror_class.select()[0]
assert logged_error.summary == "Error in timeout value '30 plop' (computed from '{{ 30 }} plop')"
# template timeout value returning nothing
jump.timeout = '{% if 1 %}{% endif %}'
workflow.store()
formdef.refresh_from_storage()
formdata = formdef.data_class()()
formdata.just_created()
formdata.store()
formdata_id = formdata.id
if two_pubs.is_using_postgresql():
two_pubs.loggederror_class.wipe()
rewind(formdata, seconds=40 * 60)
formdata.store()
_apply_timeouts(two_pubs)
assert formdef.data_class().get(formdata_id).status == 'wf-st1' # no change
if two_pubs.is_using_postgresql():
assert two_pubs.loggederror_class.count() == 1
logged_error = two_pubs.loggederror_class.select()[0]
assert logged_error.summary == "Error in timeout value '' (computed from '{% if 1 %}{% endif %}')"
def test_legacy_timeout(pub):
workflow = Workflow(name='timeout')
st1 = workflow.add_status('Status1', 'st1')
@ -2542,6 +2624,9 @@ def test_jump_missing_previous_mark(two_pubs):
pytest.skip('this requires SQL')
return
FormDef.wipe()
Workflow.wipe()
workflow = Workflow(name='jump-mark')
st1 = workflow.add_status('Status1', 'st1')
@ -5483,6 +5568,8 @@ def test_workflow_action_condition(two_pubs):
formdef.workflow_id = workflow.id
formdef.store()
formdef.data_class().wipe()
formdata1 = formdef.data_class()()
formdata1.data = {'1': 'foo'}
formdata1.just_created()

View File

@ -277,11 +277,28 @@ class JumpWorkflowStatusItem(WorkflowStatusJumpItem):
must_jump = must_jump and triggered
if self.timeout:
timeout = float(self.compute(self.timeout))
timeout_str = self.compute(self.timeout)
try:
timeout_seconds = float(timeout_str)
except ValueError:
try:
timeout_seconds = humanduration2seconds(timeout_str)
except ValueError:
timeout_seconds = 0
if timeout_seconds == 0:
get_publisher().record_error(
_('Error in timeout value %r (computed from %r)') % (timeout_str, self.timeout),
formdata=formdata,
formdef=formdata.formdef,
workflow=formdata.formdef.workflow,
notify=False,
record=True,
)
must_jump = False
last = formdata.last_update_time
if last:
if last and timeout_seconds:
diff = time.time() - time.mktime(last)
must_jump = (diff > timeout) and must_jump
must_jump = (diff > timeout_seconds) and must_jump
return must_jump