Compare commits
9 Commits
f5f83a2839
...
6fb6771b4b
Author | SHA1 | Date |
---|---|---|
Valentin Deniaud | 6fb6771b4b | |
Valentin Deniaud | 2d71bbf3e5 | |
Valentin Deniaud | 75bc2011e4 | |
Frédéric Péters | d0358afa40 | |
Frédéric Péters | 4d5b309986 | |
Lauréline Guérin | e0857ce653 | |
Frédéric Péters | 8c3374e790 | |
Frédéric Péters | 03435d40a6 | |
Frédéric Péters | 70b7087ad9 |
|
@ -23,6 +23,7 @@ Depends: graphviz,
|
|||
python3-django-ratelimit,
|
||||
python3-dnspython,
|
||||
python3-emoji,
|
||||
python3-freezegun,
|
||||
python3-hobo,
|
||||
python3-lasso,
|
||||
python3-lxml,
|
||||
|
|
1
setup.py
1
setup.py
|
@ -204,6 +204,7 @@ setup(
|
|||
'setproctitle',
|
||||
'phonenumbers',
|
||||
'emoji',
|
||||
'pytest-freezegun',
|
||||
],
|
||||
package_dir={'wcs': 'wcs'},
|
||||
packages=find_packages(),
|
||||
|
|
|
@ -398,6 +398,7 @@ def test_backoffice_card_item_link_id_template(pub):
|
|||
resp = resp.form.submit('submit')
|
||||
assert resp.location.endswith('/backoffice/data/foo/blah/')
|
||||
resp = resp.follow()
|
||||
assert resp.pyquery('.breadcrumbs a')[-1].attrib['href'] == '/backoffice/data/foo/blah/'
|
||||
resp = app.get('/backoffice/data/foo/')
|
||||
assert [x.attrib['href'] for x in resp.pyquery('table a')] == ['blah/', 'test/']
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ from wcs.workflows import (
|
|||
Workflow,
|
||||
WorkflowBackofficeFieldsFormDef,
|
||||
WorkflowCriticalityLevel,
|
||||
WorkflowVariablesFieldsFormDef,
|
||||
)
|
||||
|
||||
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login
|
||||
|
@ -1205,3 +1206,72 @@ def test_inspect_page_idp_role(pub):
|
|||
resp.pyquery('[data-function-key="_receiver"] a').attr.href
|
||||
== 'https://idp.example.net/manage/roles/uuid:d4b59e1ffb204dfd99fd3760f4952999/'
|
||||
)
|
||||
|
||||
|
||||
def test_inspect_page_form_option(pub):
|
||||
create_user(pub, is_admin=True)
|
||||
FormDef.wipe()
|
||||
|
||||
wf = Workflow(name='variables')
|
||||
wf.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=wf)
|
||||
wf.add_status('st1')
|
||||
wf.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.fields = []
|
||||
formdef.workflow = wf
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
app = login(get_app(pub))
|
||||
resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
|
||||
assert 'form_option' not in resp.text
|
||||
|
||||
wf.variables_formdef.fields = [
|
||||
fields.StringField(label='String test', varname='string_test'),
|
||||
fields.DateField(label='Date test', varname='date_test'),
|
||||
]
|
||||
wf.store()
|
||||
resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_string_test"]').parents('li').children('div.value span').text()
|
||||
== 'None (no value)'
|
||||
)
|
||||
|
||||
wf.variables_formdef.fields[0].default_value = 'xxx'
|
||||
wf.variables_formdef.fields[1].default_value = '2024-03-20'
|
||||
wf.store()
|
||||
resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_string_test"]').parents('li').children('div.value span').text()
|
||||
== 'xxx'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_date_test"]').parents('li').children('div.value span').text()
|
||||
== '2024-03-20'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_date_test_year"]').parents('li').children('div.value span').text()
|
||||
== '2024 (integer number)'
|
||||
)
|
||||
|
||||
formdef.workflow_options = {'string_test': 'yyy', 'date_test': datetime.date(2024, 3, 21).timetuple()}
|
||||
formdef.store()
|
||||
resp = app.get('%sinspect' % formdata.get_url(backoffice=True), status=200)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_string_test"]').parents('li').children('div.value span').text()
|
||||
== 'yyy'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_date_test"]').parents('li').children('div.value span').text()
|
||||
== '2024-03-21'
|
||||
)
|
||||
assert (
|
||||
resp.pyquery('[title="form_option_date_test_year"]').parents('li').children('div.value span').text()
|
||||
== '2024 (integer number)'
|
||||
)
|
||||
|
|
|
@ -1626,6 +1626,57 @@ def test_card_update_related_cascading_loop(pub):
|
|||
assert carddata2.data['2_display'] == 'card1 card2 card1 None'
|
||||
|
||||
|
||||
def test_card_update_related_items_relation(pub):
|
||||
CardDef.wipe()
|
||||
FormDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = [
|
||||
StringField(id='1', label='Test', varname='foo'),
|
||||
]
|
||||
carddef.digest_templates = {'default': '{{ form_var_foo }}'}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'1': 'card1'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddata2 = carddef.data_class()()
|
||||
carddata2.data = {'1': 'card2'}
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'foo'
|
||||
formdef.fields = [
|
||||
ItemField(id='1', label='Test', data_source={'type': 'carddef:foo'}),
|
||||
ItemsField(id='2', label='Test2', data_source={'type': 'carddef:foo'}),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
formdata = formdef.data_class()()
|
||||
formdata.data = {'1': '1', '2': ['1', '2']}
|
||||
formdata.data['1_display'] = formdef.fields[0].store_display_value(formdata.data, formdef.fields[0].id)
|
||||
formdata.data['2_display'] = formdef.fields[1].store_display_value(formdata.data, formdef.fields[1].id)
|
||||
assert formdata.data['1_display'] == 'card1'
|
||||
assert formdata.data['2_display'] == 'card1, card2'
|
||||
formdata.just_created()
|
||||
formdata.store()
|
||||
|
||||
pub.cleanup()
|
||||
carddef = carddef.get(carddef.id)
|
||||
carddata1 = carddef.data_class().get(carddata1.id)
|
||||
carddata1.data = {'1': 'card1-change1'}
|
||||
carddata1.store()
|
||||
|
||||
formdata.refresh_from_storage()
|
||||
assert formdata.data['1_display'] == 'card1-change1'
|
||||
assert formdata.data['2_display'] == 'card1-change1, card2'
|
||||
|
||||
|
||||
def test_card_update_related_deleted(pub):
|
||||
BlockDef.wipe()
|
||||
CardDef.wipe()
|
||||
|
|
|
@ -458,7 +458,6 @@ def test_workflow_tests_automatic_jump_condition(pub):
|
|||
assert str(excinfo.value) == 'Form should be in status "Frog status" but is in status "Bear status".'
|
||||
|
||||
|
||||
@pytest.mark.freeze_time('2024-02-19 12:00')
|
||||
def test_workflow_tests_automatic_jump_timeout(pub):
|
||||
user = pub.user_class(name='test user')
|
||||
user.store()
|
||||
|
@ -547,9 +546,9 @@ def test_workflow_tests_global_action_timeout(pub):
|
|||
jump.status = end_status.id
|
||||
|
||||
# add choice so that new_status is not flagged as endpoint
|
||||
jump = new_status.add_action('choice')
|
||||
jump.label = 'Go to end status'
|
||||
jump.status = end_status.id
|
||||
choice = new_status.add_action('choice')
|
||||
choice.label = 'Go to end status'
|
||||
choice.status = end_status.id
|
||||
|
||||
workflow.store()
|
||||
|
||||
|
@ -585,6 +584,13 @@ def test_workflow_tests_global_action_timeout(pub):
|
|||
|
||||
testdef.run(formdef)
|
||||
|
||||
trigger.anchor = 'template'
|
||||
trigger.anchor_template = '{{ form_receipt_date|date:"Y-m-d" }}'
|
||||
workflow.store()
|
||||
formdef.refresh_from_storage()
|
||||
|
||||
testdef.run(formdef)
|
||||
|
||||
trigger.anchor = 'finalized'
|
||||
workflow.store()
|
||||
formdef.refresh_from_storage()
|
||||
|
@ -593,6 +599,27 @@ def test_workflow_tests_global_action_timeout(pub):
|
|||
testdef.run(formdef)
|
||||
assert str(excinfo.value) == 'Form should be in status "End status" but is in status "New status".'
|
||||
|
||||
# remove choice so new status becomes endpoint
|
||||
new_status.items = [x for x in new_status.items if x.id != choice.id]
|
||||
workflow.store()
|
||||
formdef.refresh_from_storage()
|
||||
|
||||
testdef.run(formdef)
|
||||
|
||||
trigger.anchor = 'anonymisation'
|
||||
workflow.store()
|
||||
formdef.refresh_from_storage()
|
||||
|
||||
with pytest.raises(WorkflowTestError) as excinfo:
|
||||
testdef.run(formdef)
|
||||
assert str(excinfo.value) == 'Form should be in status "End status" but is in status "New status".'
|
||||
|
||||
anonymise_action = new_status.add_action('anonymise')
|
||||
workflow.store()
|
||||
formdef.refresh_from_storage()
|
||||
|
||||
testdef.run(formdef)
|
||||
|
||||
|
||||
@mock.patch('wcs.qommon.emails.send_email')
|
||||
def test_workflow_tests_sendmail(mocked_send_email, pub):
|
||||
|
|
2
tox.ini
2
tox.ini
|
@ -23,7 +23,6 @@ deps =
|
|||
pytest-cov
|
||||
pytest-django
|
||||
pytest-xdist
|
||||
pytest-freezegun
|
||||
WebTest
|
||||
mechanize
|
||||
pyquery
|
||||
|
@ -53,7 +52,6 @@ deps =
|
|||
pytest-mock
|
||||
pytest-cov
|
||||
pytest-django
|
||||
pytest-freezegun
|
||||
WebTest
|
||||
mechanize
|
||||
pyquery
|
||||
|
|
|
@ -152,7 +152,7 @@ class BlockDirectory(FieldsDirectory):
|
|||
'Save snapshot'
|
||||
)
|
||||
r += htmltext('<li><a class="button button-paragraph" rel="popup" href="overwrite">%s</a>') % _(
|
||||
'Overwrite'
|
||||
'Overwrite with new import'
|
||||
)
|
||||
r += htmltext('</ul>')
|
||||
r += htmltext('<h3>%s</h3>') % _('Navigation')
|
||||
|
|
|
@ -196,7 +196,20 @@ class FieldDefPage(Directory):
|
|||
to_be_deleted.reverse()
|
||||
# add delete_fields checkbox only if the page has fields
|
||||
if to_be_deleted:
|
||||
form.add(CheckboxWidget, 'delete_fields', title=_('Also remove all fields from the page'))
|
||||
form.add(
|
||||
CheckboxWidget,
|
||||
'delete_fields',
|
||||
title=_('Also remove all fields from the page'),
|
||||
attrs={'data-dynamic-display-parent': 'true'},
|
||||
)
|
||||
form.widgets.append(
|
||||
HtmlWidget(
|
||||
'<div class="warningnotice" '
|
||||
'data-dynamic-display-child-of="delete_fields" '
|
||||
'data-dynamic-display-checked="true">%s</div>'
|
||||
% _('Warning: the page fields data will be permanently deleted.')
|
||||
)
|
||||
)
|
||||
form.add_submit('delete', _('Delete'))
|
||||
form.add_submit('cancel', _('Cancel'))
|
||||
if form.get_widget('cancel').parse():
|
||||
|
|
|
@ -1030,7 +1030,7 @@ class FormStatusPage(Directory, FormTemplateMixin):
|
|||
return Directory._q_lookup(self, component)
|
||||
|
||||
def _q_traverse(self, path):
|
||||
get_response().breadcrumb.append((str(self.filled.id) + '/', self.filled.get_display_id()))
|
||||
get_response().breadcrumb.append((self.filled.identifier + '/', self.filled.get_display_id()))
|
||||
return super()._q_traverse(path)
|
||||
|
||||
def wfedit(self, action_id):
|
||||
|
|
|
@ -4,8 +4,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: wcs 0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-03-21 12:07+0100\n"
|
||||
"PO-Revision-Date: 2024-03-21 12:04+0100\n"
|
||||
"POT-Creation-Date: 2024-03-21 19:00+0100\n"
|
||||
"PO-Revision-Date: 2024-03-21 19:00+0100\n"
|
||||
"Last-Translator: Thomas Noël <tnoel@entrouvert.com>\n"
|
||||
"Language-Team: french\n"
|
||||
"Language: fr\n"
|
||||
|
@ -931,6 +931,12 @@ msgstr "Vous allez supprimer le champ « %s »."
|
|||
msgid "Also remove all fields from the page"
|
||||
msgstr "Supprimer tous les champs de la page"
|
||||
|
||||
#: admin/fields.py
|
||||
msgid "Warning: the page fields data will be permanently deleted."
|
||||
msgstr ""
|
||||
"Attention : les informations contenues dans les champs de la page seront "
|
||||
"perdues de façon irréversible."
|
||||
|
||||
#: admin/fields.py
|
||||
#, python-format
|
||||
msgid "Deletion of field \"%s\""
|
||||
|
|
|
@ -757,8 +757,6 @@ class LazyFormDef:
|
|||
|
||||
@property
|
||||
def option(self):
|
||||
if not self._formdef.workflow.variables_formdef:
|
||||
return {}
|
||||
return LazyFormDefOptions(self._formdef)
|
||||
|
||||
@property
|
||||
|
@ -1989,14 +1987,20 @@ class LazyRequest:
|
|||
class LazyFormDefOptions(LazyFormDataVar):
|
||||
def __init__(self, formdef):
|
||||
self._formdef = formdef
|
||||
fields = self._formdef.workflow.variables_formdef.fields
|
||||
try:
|
||||
fields = self._formdef.workflow.variables_formdef.fields
|
||||
except AttributeError:
|
||||
fields = []
|
||||
data = self._formdef.workflow_options or {}
|
||||
for field in fields:
|
||||
# change field IDs as options are stored in data with their
|
||||
# varnames, not id.
|
||||
field.id = field.varname or field.id
|
||||
if hasattr(field, 'default_value') and data.get(field.varname) is None:
|
||||
data[field.varname] = field.default_value
|
||||
if isinstance(field.default_value, str):
|
||||
data[field.varname] = field.convert_value_from_str(field.default_value)
|
||||
else:
|
||||
data[field.varname] = field.default_value
|
||||
super().__init__(fields, data)
|
||||
|
||||
def inspect_keys(self):
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
import datetime
|
||||
import uuid
|
||||
|
||||
import freezegun
|
||||
from django.utils.timezone import localtime
|
||||
from quixote import get_publisher, get_session
|
||||
|
||||
from wcs import wf
|
||||
|
@ -91,9 +93,13 @@ class WorkflowTests(XmlStorableObject):
|
|||
# mark formdata as running workflow tests
|
||||
formdata.workflow_test = True
|
||||
|
||||
formdata.frozen_receipt_time = formdata.receipt_time
|
||||
self.reset_formdata_test_attributes(formdata)
|
||||
|
||||
with freezegun.freeze_time(formdata.receipt_time) as frozen_datetime:
|
||||
formdata.frozen_datetime = frozen_datetime
|
||||
self._run(formdata)
|
||||
|
||||
def _run(self, formdata):
|
||||
formdata.perform_workflow()
|
||||
for action in self.actions:
|
||||
status = formdata.get_status()
|
||||
|
@ -538,15 +544,9 @@ class SkipTime(WorkflowTestAction):
|
|||
if previous_trace:
|
||||
self.seconds = (trace.timestamp - previous_trace.timestamp).total_seconds()
|
||||
|
||||
def rewind(self, formdata):
|
||||
def rewind_time(timestamp):
|
||||
return timestamp - datetime.timedelta(seconds=self.seconds)
|
||||
|
||||
formdata.receipt_time = rewind_time(formdata.receipt_time)
|
||||
formdata.evolution[-1].time = rewind_time(formdata.evolution[-1].time)
|
||||
|
||||
def perform(self, formdata):
|
||||
self.rewind(formdata)
|
||||
formdata.frozen_datetime.tick(self.seconds)
|
||||
|
||||
self.apply_jumps(formdata)
|
||||
self.apply_global_actions_timeout(formdata)
|
||||
|
||||
|
@ -562,7 +562,7 @@ class SkipTime(WorkflowTestAction):
|
|||
|
||||
delay = wf.jump.get_min_jumps_delay(jump_actions)
|
||||
|
||||
if formdata.last_update_time > formdata.frozen_receipt_time - datetime.timedelta(seconds=delay):
|
||||
if formdata.last_update_time > localtime() - datetime.timedelta(seconds=delay):
|
||||
return
|
||||
|
||||
for jump_action in jump_actions:
|
||||
|
|
Loading…
Reference in New Issue