Compare commits
8 Commits
0732ebb1d0
...
a802c4e05d
Author | SHA1 | Date |
---|---|---|
Frédéric Péters | a802c4e05d | |
Frédéric Péters | 9e46be8374 | |
Frédéric Péters | d952842d9c | |
Frédéric Péters | a91472510e | |
Frédéric Péters | a130f1d862 | |
Frédéric Péters | 1b976a36a7 | |
Frédéric Péters | 4ba3ebf6b4 | |
Frédéric Péters | f6e228b438 |
|
@ -2652,6 +2652,92 @@ def test_block_prefill_full_block_email(pub):
|
|||
}
|
||||
|
||||
|
||||
def test_block_prefill_full_block_card_item(pub):
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
CardDef.wipe()
|
||||
create_user(pub)
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Test'
|
||||
carddef.fields = [
|
||||
fields.StringField(id='0', label='blah', varname='blah'),
|
||||
]
|
||||
carddef.digest_templates = {'default': '{{ form_var_blah|upper }}'}
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'0': 'bar'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
block = BlockDef()
|
||||
block.name = 'foobar'
|
||||
block.fields = [
|
||||
fields.ItemField(
|
||||
id='123',
|
||||
required=False,
|
||||
hint='-----',
|
||||
label='Test',
|
||||
varname='plop',
|
||||
data_source={'type': 'carddef:test'},
|
||||
),
|
||||
]
|
||||
block.digest_template = '{{block_var_plop}}'
|
||||
block.store()
|
||||
|
||||
formdef = FormDef()
|
||||
formdef.name = 'form title'
|
||||
formdef.fields = [
|
||||
fields.PageField(id='0', label='1st page'),
|
||||
fields.PageField(id='2', label='2nd page'),
|
||||
fields.BlockField(
|
||||
id='1',
|
||||
label='test',
|
||||
block_slug='foobar',
|
||||
max_items=5,
|
||||
prefill={
|
||||
'type': 'string',
|
||||
'value': '{% block_value plop="1" %}',
|
||||
},
|
||||
),
|
||||
]
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
|
||||
app = get_app(pub)
|
||||
login(app, username='foo', password='foo')
|
||||
resp = app.get(formdef.get_url())
|
||||
resp = resp.form.submit('submit') # -> page 2
|
||||
assert resp.form['f1$element0$f123'].value == '1'
|
||||
resp = resp.form.submit('submit') # validation
|
||||
resp = resp.form.submit('submit') # done
|
||||
assert formdef.data_class().select()[0].data == {
|
||||
'1': {
|
||||
'data': [
|
||||
{'123': '1', '123_display': 'BAR', '123_structured': {'blah': 'bar', 'id': 1, 'text': 'BAR'}}
|
||||
],
|
||||
'schema': {'123': 'item'},
|
||||
},
|
||||
'1_display': 'BAR',
|
||||
}
|
||||
|
||||
# prefill with unknown value
|
||||
pub.loggederror_class.wipe()
|
||||
formdef.fields[2].prefill['value'] = '{% block_value plop="123" %}'
|
||||
formdef.store()
|
||||
formdef.data_class().wipe()
|
||||
resp = app.get(formdef.get_url())
|
||||
resp = resp.form.submit('submit') # -> page 2
|
||||
assert not resp.form['f1$element0$f123'].value
|
||||
assert pub.loggederror_class.count() == 1
|
||||
assert (
|
||||
pub.loggederror_class.select()[0].summary
|
||||
== 'invalid value when creating block: unknown card value (\'123\')'
|
||||
)
|
||||
|
||||
|
||||
def test_block_titles_and_empty_block_on_summary_page(pub, emails):
|
||||
FormDef.wipe()
|
||||
BlockDef.wipe()
|
||||
|
|
|
@ -631,6 +631,107 @@ def test_form_page_item_with_variable_data_source_prefill(pub):
|
|||
assert not resp.pyquery('#form_error_f2').text()
|
||||
|
||||
|
||||
def test_form_page_item_with_card_with_custom_id_prefill(pub):
|
||||
create_user(pub)
|
||||
CardDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Test'
|
||||
carddef.fields = [
|
||||
fields.StringField(id='0', label='blah', varname='blah'),
|
||||
]
|
||||
carddef.digest_templates = {'default': '{{ form_var_blah|upper }}'}
|
||||
carddef.id_template = '{{ form_var_blah }}'
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'0': 'bar'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddata2 = carddef.data_class()()
|
||||
carddata2.data = {'0': 'foo'}
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
formdef.fields = [
|
||||
fields.ItemField(
|
||||
id='2',
|
||||
label='item',
|
||||
varname='item',
|
||||
required=False,
|
||||
data_source={'type': 'carddef:test'},
|
||||
prefill={'type': 'string', 'value': 'foo'},
|
||||
),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert [x.attrib['value'] for x in resp.pyquery('#form_f2 option')] == ['bar', 'foo']
|
||||
assert resp.form['f2'].value == 'foo'
|
||||
assert not resp.pyquery('#form_error_f2').text()
|
||||
|
||||
|
||||
def test_form_page_block_with_item_with_card_with_custom_id_prefill(pub):
|
||||
create_user(pub)
|
||||
CardDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Test'
|
||||
carddef.fields = [
|
||||
fields.StringField(id='0', label='blah', varname='blah'),
|
||||
]
|
||||
carddef.digest_templates = {'default': 'card {{ form_var_blah }}'}
|
||||
carddef.id_template = '{{ form_var_blah }}'
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata1 = carddef.data_class()()
|
||||
carddata1.data = {'0': 'bar'}
|
||||
carddata1.just_created()
|
||||
carddata1.store()
|
||||
|
||||
carddata2 = carddef.data_class()()
|
||||
carddata2.data = {'0': 'foo'}
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
|
||||
BlockDef.wipe()
|
||||
block = BlockDef()
|
||||
block.name = 'foobar'
|
||||
block.fields = [
|
||||
fields.ItemField(
|
||||
id='123',
|
||||
label='item',
|
||||
varname='item',
|
||||
required=False,
|
||||
data_source={'type': 'carddef:test'},
|
||||
),
|
||||
]
|
||||
block.store()
|
||||
|
||||
formdef = create_formdef()
|
||||
formdef.data_class().wipe()
|
||||
formdef.fields = [
|
||||
fields.BlockField(
|
||||
id='2',
|
||||
label='test',
|
||||
block_slug='foobar',
|
||||
varname='foobar',
|
||||
prefill={'type': 'string', 'value': '{% block_value item="foo" %}'},
|
||||
),
|
||||
]
|
||||
formdef.store()
|
||||
|
||||
resp = get_app(pub).get('/test/')
|
||||
assert [x.attrib['value'] for x in resp.pyquery('#form_f2__element0__f123 option')] == ['bar', 'foo']
|
||||
assert resp.form['f2$element0$f123'].value == 'foo'
|
||||
assert not resp.pyquery('.widget-with-error')
|
||||
|
||||
|
||||
def test_form_page_item_with_computed_field_variable_data_source_prefill(pub):
|
||||
create_user(pub)
|
||||
formdef = create_formdef()
|
||||
|
|
|
@ -62,3 +62,24 @@ def test_import_blockdef_multiple_errors(pub):
|
|||
assert excinfo.value.details == (
|
||||
'Unknown datasources: carddef:foo:unknown, carddef:unknown, foobar; Unknown field types: foobaz'
|
||||
)
|
||||
|
||||
|
||||
def test_import_blockdef_post_conditions(pub):
|
||||
BlockDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'foo'
|
||||
carddef.fields = []
|
||||
carddef.store()
|
||||
|
||||
blockdef = BlockDef()
|
||||
blockdef.name = 'foo'
|
||||
blockdef.fields = []
|
||||
blockdef.post_conditions = [
|
||||
{'condition': {'type': 'django', 'value': 'blah1'}, 'error_message': 'bar1'},
|
||||
{'condition': {'type': 'django', 'value': 'blah2'}, 'error_message': 'bar2'},
|
||||
]
|
||||
|
||||
export = ET.tostring(export_to_indented_xml(blockdef))
|
||||
blockdef2 = BlockDef.import_from_xml(io.BytesIO(export))
|
||||
assert blockdef.post_conditions == blockdef2.post_conditions
|
||||
|
|
|
@ -1119,6 +1119,117 @@ def test_edit_carddata_targeting_itself(pub):
|
|||
assert carddata.status == 'wf-%s' % st2.id
|
||||
|
||||
|
||||
def test_edit_carddata_auto_targeting_custom_id(pub):
|
||||
CardDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Foo Card'
|
||||
carddef.fields = [
|
||||
StringField(id='0', label='foo', varname='foo'),
|
||||
StringField(id='1', label='slug', varname='slug'),
|
||||
]
|
||||
carddef.id_template = 'card_{{form_var_slug}}'
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata = carddef.data_class()()
|
||||
carddata.data = {'0': 'foo', '1': 'foo'}
|
||||
carddata.store()
|
||||
carddata.just_created()
|
||||
carddata.store()
|
||||
assert carddata.identifier == 'card_foo'
|
||||
|
||||
carddef2 = CardDef()
|
||||
carddef2.name = 'Bar Card'
|
||||
carddef2.fields = [
|
||||
ItemField(id='1', label='card', varname='card', data_source={'type': 'carddef:%s' % carddef.url_name})
|
||||
]
|
||||
carddef2.store()
|
||||
|
||||
card_wf = Workflow(name='Card workflow')
|
||||
st1 = card_wf.add_status('Status1')
|
||||
st2 = card_wf.add_status('Status2')
|
||||
|
||||
edit = st1.add_action('edit_carddata', id='_edit')
|
||||
edit.formdef_slug = carddef.url_name
|
||||
edit.target_mode = 'all'
|
||||
edit.mappings = [Mapping(field_id='0', expression='bar')]
|
||||
|
||||
jump = st1.add_action('jump', '_jump')
|
||||
jump.status = st2.id
|
||||
|
||||
card_wf.store()
|
||||
|
||||
carddef2.workflow = card_wf
|
||||
carddef2.store()
|
||||
|
||||
carddata2 = carddef2.data_class()()
|
||||
carddata2.data = {
|
||||
'1': 'card_foo',
|
||||
}
|
||||
carddata2.store()
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
carddata2.perform_workflow()
|
||||
|
||||
carddata.refresh_from_storage()
|
||||
assert carddata.data['0'] == 'bar'
|
||||
|
||||
|
||||
def test_edit_carddata_manual_targeting_custom_id(pub):
|
||||
CardDef.wipe()
|
||||
|
||||
carddef = CardDef()
|
||||
carddef.name = 'Foo Card'
|
||||
carddef.fields = [
|
||||
StringField(id='0', label='foo', varname='foo'),
|
||||
StringField(id='1', label='slug', varname='slug'),
|
||||
]
|
||||
carddef.id_template = 'card_{{form_var_slug}}'
|
||||
carddef.store()
|
||||
carddef.data_class().wipe()
|
||||
|
||||
carddata = carddef.data_class()()
|
||||
carddata.data = {'0': 'foo', '1': 'foo'}
|
||||
carddata.store()
|
||||
carddata.just_created()
|
||||
carddata.store()
|
||||
assert carddata.identifier == 'card_foo'
|
||||
|
||||
carddef2 = CardDef()
|
||||
carddef2.name = 'Bar Card'
|
||||
carddef2.fields = []
|
||||
carddef2.store()
|
||||
|
||||
card_wf = Workflow(name='Card workflow')
|
||||
st1 = card_wf.add_status('Status1')
|
||||
st2 = card_wf.add_status('Status2')
|
||||
|
||||
edit = st1.add_action('edit_carddata', id='_edit')
|
||||
edit.formdef_slug = carddef.url_name
|
||||
edit.target_mode = 'manual'
|
||||
edit.target_id = 'card_foo'
|
||||
edit.mappings = [Mapping(field_id='0', expression='bar')]
|
||||
|
||||
jump = st1.add_action('jump', '_jump')
|
||||
jump.status = st2.id
|
||||
|
||||
card_wf.store()
|
||||
|
||||
carddef2.workflow = card_wf
|
||||
carddef2.store()
|
||||
|
||||
carddata2 = carddef2.data_class()()
|
||||
carddata2.data = {}
|
||||
carddata2.store()
|
||||
carddata2.just_created()
|
||||
carddata2.store()
|
||||
carddata2.perform_workflow()
|
||||
|
||||
carddata.refresh_from_storage()
|
||||
assert carddata.data['0'] == 'bar'
|
||||
|
||||
|
||||
def test_edit_carddata_from_created_object(pub):
|
||||
FormDef.wipe()
|
||||
CardDef.wipe()
|
||||
|
|
|
@ -24,7 +24,7 @@ from contextlib import contextmanager
|
|||
from quixote import get_publisher, get_request, get_response
|
||||
from quixote.html import htmltag, htmltext
|
||||
|
||||
from . import data_sources, fields
|
||||
from . import conditions, data_sources, fields
|
||||
from .categories import BlockCategory
|
||||
from .formdata import FormData
|
||||
from .qommon import _, misc
|
||||
|
@ -435,6 +435,21 @@ class BlockSubWidget(CompositeWidget):
|
|||
all_lists = False
|
||||
if widget_value.get(widget.field.id) not in empty_values:
|
||||
empty = False
|
||||
|
||||
if not empty and self.block.post_conditions:
|
||||
error_messages = []
|
||||
with self.block.visibility_context(value, self.index):
|
||||
for i, post_condition in enumerate(self.block.post_conditions):
|
||||
condition = post_condition.get('condition')
|
||||
error_message = post_condition.get('error_message')
|
||||
try:
|
||||
if not conditions.Condition(condition, record_errors=False).evaluate():
|
||||
error_messages.append(error_message)
|
||||
except RuntimeError:
|
||||
error_messages.append(error_message)
|
||||
if error_messages:
|
||||
self.set_error(' '.join(error_messages))
|
||||
|
||||
if empty and not all_lists and not get_publisher().keep_all_block_rows_mode:
|
||||
value = None
|
||||
for widget in self.get_widgets(): # reset "required" errors
|
||||
|
@ -528,6 +543,10 @@ class BlockWidget(WidgetList):
|
|||
self._parse(request)
|
||||
if self.required and self.value is None:
|
||||
self.set_error(_(self.REQUIRED_ERROR))
|
||||
for widget in self.widgets:
|
||||
# do not mark individual rows as required
|
||||
if widget.error == self.REQUIRED_ERROR:
|
||||
widget.clear_error()
|
||||
return self.value
|
||||
|
||||
def add_media(self):
|
||||
|
|
|
@ -19,7 +19,7 @@ from quixote import get_publisher, get_request, get_session
|
|||
from wcs.formdata import FormData
|
||||
|
||||
from .qommon import _
|
||||
from .sql_criterias import Equal, Null, StrictNotEqual
|
||||
from .sql_criterias import Equal
|
||||
|
||||
|
||||
class CardData(FormData):
|
||||
|
@ -39,20 +39,6 @@ class CardData(FormData):
|
|||
|
||||
formdef = property(get_formdef)
|
||||
|
||||
@classmethod
|
||||
def get_by_id(cls, value):
|
||||
try:
|
||||
return cls.select(
|
||||
[
|
||||
StrictNotEqual('status', 'draft'),
|
||||
Null('anonymised'),
|
||||
cls._formdef.get_by_id_criteria(value),
|
||||
],
|
||||
limit=1,
|
||||
)[0]
|
||||
except IndexError:
|
||||
raise KeyError(value)
|
||||
|
||||
def get_data_source_structured_item(
|
||||
self, digest_key='default', group_by=None, with_related_urls=False, with_files_urls=False
|
||||
):
|
||||
|
|
|
@ -28,6 +28,7 @@ from wcs.qommon.ods import NS as OD_NS
|
|||
from wcs.qommon.ods import clean_text as od_clean_text
|
||||
|
||||
from .base import SetValueError, WidgetField
|
||||
from .item import UnknownCardValueError
|
||||
|
||||
|
||||
class MissingBlockFieldError(Exception):
|
||||
|
@ -67,7 +68,11 @@ class BlockRowValue:
|
|||
sub_field.set_value(row_data, sub_value)
|
||||
return row_data
|
||||
|
||||
row_data = make_row_data(self.attributes)
|
||||
try:
|
||||
row_data = make_row_data(self.attributes)
|
||||
except UnknownCardValueError as e:
|
||||
get_publisher().record_error(_('invalid value when creating block: %s') % str(e), exception=e)
|
||||
return None
|
||||
|
||||
current_block_value = data.get(field.id)
|
||||
if not self.check_current_value(current_block_value):
|
||||
|
|
|
@ -32,7 +32,7 @@ from quixote.errors import RequestError
|
|||
from quixote.html import htmltext
|
||||
from quixote.http_request import Upload
|
||||
|
||||
from wcs.sql_criterias import And, Contains, Equal, Intersects
|
||||
from wcs.sql_criterias import And, Contains, Equal, Intersects, Null, StrictNotEqual
|
||||
|
||||
from .qommon import _, misc
|
||||
from .qommon.evalutils import make_datetime
|
||||
|
@ -365,7 +365,10 @@ class FormData(StorableObject):
|
|||
def get_by_id(cls, value):
|
||||
if cls._formdef.id_template:
|
||||
try:
|
||||
return cls.select([Equal('id_display', str(value))], limit=1)[0]
|
||||
return cls.select(
|
||||
[StrictNotEqual('status', 'draft'), Null('anonymised'), Equal('id_display', str(value))],
|
||||
limit=1,
|
||||
)[0]
|
||||
except IndexError:
|
||||
raise KeyError(value)
|
||||
return cls.get(value)
|
||||
|
@ -1932,7 +1935,7 @@ class FormData(StorableObject):
|
|||
if object_type:
|
||||
# workflow action
|
||||
try:
|
||||
yield objectdef.data_class().get(target_id)
|
||||
yield objectdef.data_class().get_by_id(target_id)
|
||||
except KeyError:
|
||||
# linked object may be missing
|
||||
pass
|
||||
|
@ -1952,7 +1955,7 @@ class FormData(StorableObject):
|
|||
_('%s - not found') % origin,
|
||||
)
|
||||
else:
|
||||
yield (_objectdef.data_class().get(target_id), origin)
|
||||
yield (_objectdef.data_class().get_by_id(target_id), origin)
|
||||
except ValueError:
|
||||
pass
|
||||
except KeyError:
|
||||
|
|
|
@ -4,8 +4,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: wcs 0\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-03-08 11:14+0100\n"
|
||||
"PO-Revision-Date: 2024-03-08 11:14+0100\n"
|
||||
"POT-Creation-Date: 2024-03-12 09:34+0100\n"
|
||||
"PO-Revision-Date: 2024-03-12 09:34+0100\n"
|
||||
"Last-Translator: Thomas Noël <tnoel@entrouvert.com>\n"
|
||||
"Language-Team: french\n"
|
||||
"Language: fr\n"
|
||||
|
@ -2570,7 +2570,9 @@ msgstr "Importer les données depuis une demande"
|
|||
|
||||
#: admin/tests.py
|
||||
msgid "Import data from form (and initialise workflow tests)"
|
||||
msgstr "Importer les données depuis une demande (et initialiser les tests de workflow)"
|
||||
msgstr ""
|
||||
"Importer les données depuis une demande (et initialiser les tests de "
|
||||
"workflow)"
|
||||
|
||||
#: admin/tests.py
|
||||
msgid ""
|
||||
|
@ -5446,6 +5448,11 @@ msgstr "La valeur doit contenir un ou plusieurs noms valides."
|
|||
msgid "Missing block field: %s"
|
||||
msgstr "Bloc de champ manquant : %s"
|
||||
|
||||
#: fields/block.py
|
||||
#, python-format
|
||||
msgid "invalid value when creating block: %s"
|
||||
msgstr "valeur invalide pour la création du bloc : %s"
|
||||
|
||||
#: fields/block.py
|
||||
#, python-format
|
||||
msgid "Field Block (%s)"
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block widget-content %}
|
||||
{% if not widget.readonly and widget.error %}<div class="error"><p>{{ widget.error }}</p></div>{% endif %}
|
||||
{% for subwidget in widget.get_widgets %}
|
||||
{% if widget.readonly and not subwidget.field.include_in_validation_page %}<div style="display: none">{% endif %}
|
||||
{{ subwidget.render|safe }}
|
||||
|
|
|
@ -267,7 +267,7 @@ class ExternalWorkflowGlobalAction(WorkflowStatusItem):
|
|||
return
|
||||
|
||||
try:
|
||||
yield objectdef.data_class().get(target_id)
|
||||
yield objectdef.data_class().get_by_id(target_id)
|
||||
except KeyError as e:
|
||||
# use custom error message depending on target type
|
||||
get_publisher().record_error(
|
||||
|
|
Loading…
Reference in New Issue