0001-workflows-add-live-conditions-to-workflow-form-actio.patch
tests/test_admin_pages.py | ||
---|---|---|
2586 | 2586 |
assert 'foobar' in resp.body |
2587 | 2587 |
resp = resp.click('Edit') |
2588 | 2588 |
assert not 'in_listing' in resp.form.fields.keys() |
2589 |
assert not 'condition$type' in resp.form.fields.keys()
|
|
2589 |
assert 'condition$type' in resp.form.fields.keys() |
|
2590 | 2590 |
resp = resp.form.submit('cancel') |
2591 | 2591 |
resp = resp.follow() |
2592 | 2592 |
resp = resp.click('Remove') |
tests/test_backoffice_pages.py | ||
---|---|---|
3620 | 3620 |
assert formdef.data_class().get(formdata.id).workflow_data == { |
3621 | 3621 |
'blah_var_str': 'blah', 'blah_var_radio': 'c', 'blah_var_radio_raw': 'c'} |
3622 | 3622 | |
3623 |
def test_backoffice_workflow_form_with_conditions(pub): |
|
3624 |
user = create_user(pub) |
|
3625 |
create_environment(pub) |
|
3626 | ||
3627 |
wf = Workflow.get_default_workflow() |
|
3628 |
wf.id = '2' |
|
3629 |
wf.store() |
|
3630 |
wf = Workflow.get(wf.id) |
|
3631 |
status = wf.get_status('new') |
|
3632 |
status.items = [] |
|
3633 |
display_form = FormWorkflowStatusItem() |
|
3634 |
display_form.id = '_display_form' |
|
3635 |
display_form.by = [user.roles[0]] |
|
3636 |
display_form.varname = 'blah' |
|
3637 |
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form) |
|
3638 |
display_form.formdef.fields = [ |
|
3639 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
3640 |
fields.StringField(id='2', label='Test2', varname='str2', type='string', required=True), |
|
3641 |
] |
|
3642 |
status.items.append(display_form) |
|
3643 |
display_form.parent = status |
|
3644 | ||
3645 |
wf.store() |
|
3646 |
formdef = FormDef.get_by_urlname('form-title') |
|
3647 |
formdef.workflow_id = wf.id |
|
3648 |
formdef.fields[0].varname = 'plop' |
|
3649 |
formdef.store() |
|
3650 | ||
3651 |
for formdata in formdef.data_class().select(): |
|
3652 |
if formdata.status == 'wf-new': |
|
3653 |
break |
|
3654 |
app = login(get_app(pub)) |
|
3655 |
resp = app.get(formdata.get_url(backoffice=True)) |
|
3656 |
assert 'f1' in resp.form.fields |
|
3657 |
assert 'f2' in resp.form.fields |
|
3658 | ||
3659 |
# check with static condition |
|
3660 |
display_form.formdef.fields = [ |
|
3661 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
3662 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
3663 |
type='string', required=True, |
|
3664 |
condition={'type': 'django', 'value': '0'}), |
|
3665 |
] |
|
3666 |
wf.store() |
|
3667 | ||
3668 |
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True)) |
|
3669 |
assert 'f1' in resp.form.fields |
|
3670 |
assert 'f2' not in resp.form.fields |
|
3671 | ||
3672 |
# check condition based on formdata |
|
3673 |
display_form.formdef.fields = [ |
|
3674 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
3675 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
3676 |
type='string', required=True, |
|
3677 |
condition={'type': 'django', 'value': 'form_var_plop'}), |
|
3678 |
] |
|
3679 |
wf.store() |
|
3680 | ||
3681 |
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True)) |
|
3682 |
assert 'f1' in resp.form.fields |
|
3683 |
assert 'f2' in resp.form.fields |
|
3684 | ||
3685 |
display_form.formdef.fields = [ |
|
3686 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
3687 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
3688 |
type='string', required=True, |
|
3689 |
condition={'type': 'django', 'value': 'form_var_plop != "xxx"'}), |
|
3690 |
] |
|
3691 |
wf.store() |
|
3692 | ||
3693 |
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True)) |
|
3694 |
assert 'f1' in resp.form.fields |
|
3695 |
assert 'f2' in resp.form.fields |
|
3696 | ||
3697 |
# check with live conditions |
|
3698 |
display_form.formdef.fields = [ |
|
3699 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
3700 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
3701 |
type='string', required=True, |
|
3702 |
condition={'type': 'django', 'value': 'blah_var_str == "xxx"'}), |
|
3703 |
] |
|
3704 |
wf.store() |
|
3705 | ||
3706 |
resp = login(get_app(pub)).get(formdata.get_url(backoffice=True)) |
|
3707 |
assert 'f1' in resp.form.fields |
|
3708 |
assert 'f2' in resp.form.fields |
|
3709 |
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true' |
|
3710 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none' |
|
3711 |
live_url = resp.html.find('form').attrs['data-live-url'] |
|
3712 |
resp.form['f1'] = '' |
|
3713 |
live_resp = app.post(live_url, params=resp.form.submit_fields()) |
|
3714 |
assert live_resp.json['result']['1']['visible'] |
|
3715 |
assert not live_resp.json['result']['2']['visible'] |
|
3716 | ||
3717 |
resp.form['f1'] = 'xxx' |
|
3718 |
live_resp = app.post(live_url, params=resp.form.submit_fields()) |
|
3719 |
assert live_resp.json['result']['1']['visible'] |
|
3720 |
assert live_resp.json['result']['2']['visible'] |
|
3721 | ||
3722 |
# check submit doesn't work |
|
3723 |
resp = resp.form.submit('submit') |
|
3724 |
assert 'There were errors processing your form.' in resp.body |
|
3725 | ||
3726 |
resp.form['f1'] = 'xxx2' |
|
3727 |
live_resp = app.post(live_url, params=resp.form.submit_fields()) |
|
3728 |
assert live_resp.json['result']['1']['visible'] |
|
3729 |
assert not live_resp.json['result']['2']['visible'] |
|
3730 | ||
3731 |
# check submit does work when second field is hidden |
|
3732 |
resp = resp.form.submit('submit').follow() |
|
3733 | ||
3734 |
assert formdef.data_class().get(formdata.id).workflow_data == {'blah_var_str': 'xxx2', 'blah_var_str2': None} |
|
3735 | ||
3623 | 3736 |
def test_backoffice_criticality_in_formdef_listing(pub): |
3624 | 3737 |
if not pub.is_using_postgresql(): |
3625 | 3738 |
pytest.skip('this requires SQL') |
tests/test_form_pages.py | ||
---|---|---|
6465 | 6465 |
assert 'You already started to fill this form.' in resp.body |
6466 | 6466 |
assert 'href="%s"' % draft.id in resp.body |
6467 | 6467 |
assert 'href="%s"' % draft2.id in resp.body |
6468 | ||
6469 |
def test_frontoffice_workflow_form_with_conditions(pub): |
|
6470 |
user = create_user(pub) |
|
6471 |
wf = Workflow.get_default_workflow() |
|
6472 |
wf.id = '2' |
|
6473 |
wf.store() |
|
6474 |
wf = Workflow.get(wf.id) |
|
6475 |
status = wf.get_status('new') |
|
6476 |
status.items = [] |
|
6477 |
display_form = FormWorkflowStatusItem() |
|
6478 |
display_form.id = '_display_form' |
|
6479 |
display_form.by = ['_submitter'] |
|
6480 |
display_form.varname = 'blah' |
|
6481 |
display_form.formdef = WorkflowFormFieldsFormDef(item=display_form) |
|
6482 |
display_form.formdef.fields = [ |
|
6483 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
6484 |
fields.StringField(id='2', label='Test2', varname='str2', type='string', required=True), |
|
6485 |
] |
|
6486 |
status.items.append(display_form) |
|
6487 |
display_form.parent = status |
|
6488 | ||
6489 |
wf.store() |
|
6490 |
formdef = create_formdef() |
|
6491 |
formdef.workflow_id = wf.id |
|
6492 |
formdef.fields = [fields.StringField(id='0', label='string', varname='plop')] |
|
6493 |
formdef.store() |
|
6494 | ||
6495 |
formdef.data_class().wipe() |
|
6496 | ||
6497 |
formdata = formdef.data_class()() |
|
6498 |
formdata.user_id = user.id |
|
6499 |
formdata.status = 'wf-new' |
|
6500 |
formdata.data = {'0': 'plop'} |
|
6501 |
formdata.store() |
|
6502 | ||
6503 |
app = login(get_app(pub), username='foo', password='foo') |
|
6504 |
resp = app.get(formdata.get_url(backoffice=False)) |
|
6505 |
assert 'f1' in resp.form.fields |
|
6506 |
assert 'f2' in resp.form.fields |
|
6507 | ||
6508 |
# check with static condition |
|
6509 |
display_form.formdef.fields = [ |
|
6510 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
6511 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
6512 |
type='string', required=True, |
|
6513 |
condition={'type': 'django', 'value': '0'}), |
|
6514 |
] |
|
6515 |
wf.store() |
|
6516 | ||
6517 |
resp = login(get_app(pub), username='foo', password='foo').get(formdata.get_url(backoffice=False)) |
|
6518 |
assert 'f1' in resp.form.fields |
|
6519 |
assert 'f2' not in resp.form.fields |
|
6520 | ||
6521 |
# check condition based on formdata |
|
6522 |
display_form.formdef.fields = [ |
|
6523 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
6524 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
6525 |
type='string', required=True, |
|
6526 |
condition={'type': 'django', 'value': 'form_var_plop'}), |
|
6527 |
] |
|
6528 |
wf.store() |
|
6529 | ||
6530 |
resp = login(get_app(pub), username='foo', password='foo').get(formdata.get_url(backoffice=False)) |
|
6531 |
assert 'f1' in resp.form.fields |
|
6532 |
assert 'f2' in resp.form.fields |
|
6533 | ||
6534 |
display_form.formdef.fields = [ |
|
6535 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
6536 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
6537 |
type='string', required=True, |
|
6538 |
condition={'type': 'django', 'value': 'form_var_plop != "xxx"'}), |
|
6539 |
] |
|
6540 |
wf.store() |
|
6541 | ||
6542 |
resp = login(get_app(pub), username='foo', password='foo').get(formdata.get_url(backoffice=False)) |
|
6543 |
assert 'f1' in resp.form.fields |
|
6544 |
assert 'f2' in resp.form.fields |
|
6545 | ||
6546 |
# check with live conditions |
|
6547 |
display_form.formdef.fields = [ |
|
6548 |
fields.StringField(id='1', label='Test', varname='str', type='string', required=True), |
|
6549 |
fields.StringField(id='2', label='Test2', varname='str2', |
|
6550 |
type='string', required=True, |
|
6551 |
condition={'type': 'django', 'value': 'blah_var_str == "xxx"'}), |
|
6552 |
] |
|
6553 |
wf.store() |
|
6554 | ||
6555 |
resp = login(get_app(pub), username='foo', password='foo').get(formdata.get_url(backoffice=False)) |
|
6556 |
assert 'f1' in resp.form.fields |
|
6557 |
assert 'f2' in resp.form.fields |
|
6558 |
assert resp.html.find('div', {'data-field-id': '1'}).attrs['data-live-source'] == 'true' |
|
6559 |
assert resp.html.find('div', {'data-field-id': '2'}).attrs.get('style') == 'display: none' |
|
6560 |
live_url = resp.html.find('form').attrs['data-live-url'] |
|
6561 |
resp.form['f1'] = '' |
|
6562 |
live_resp = app.post(live_url, params=resp.form.submit_fields()) |
|
6563 |
assert live_resp.json['result']['1']['visible'] |
|
6564 |
assert not live_resp.json['result']['2']['visible'] |
|
6565 | ||
6566 |
resp.form['f1'] = 'xxx' |
|
6567 |
live_resp = app.post(live_url, params=resp.form.submit_fields()) |
|
6568 |
assert live_resp.json['result']['1']['visible'] |
|
6569 |
assert live_resp.json['result']['2']['visible'] |
|
6570 | ||
6571 |
# check submit doesn't work |
|
6572 |
resp = resp.form.submit('submit') |
|
6573 |
assert 'There were errors processing your form.' in resp.body |
|
6574 | ||
6575 |
resp.form['f1'] = 'xxx2' |
|
6576 |
live_resp = app.post(live_url, params=resp.form.submit_fields()) |
|
6577 |
assert live_resp.json['result']['1']['visible'] |
|
6578 |
assert not live_resp.json['result']['2']['visible'] |
|
6579 | ||
6580 |
# check submit does work when second field is hidden |
|
6581 |
resp = resp.form.submit('submit').follow() |
|
6582 | ||
6583 |
assert formdef.data_class().get(formdata.id).workflow_data == {'blah_var_str': 'xxx2', 'blah_var_str2': None} |
wcs/fields.py | ||
---|---|---|
403 | 403 |
except RuntimeError: |
404 | 404 |
return True |
405 | 405 | |
406 |
def get_referenced_varnames(self, value): |
|
407 |
return re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)', value or '')
|
|
406 |
def get_referenced_varnames(self, formdef, value):
|
|
407 |
return re.findall(r'\b%s[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)' % formdef.var_prefix, value or '')
|
|
408 | 408 | |
409 |
def get_condition_varnames(self): |
|
410 |
return self.get_referenced_varnames(self.condition['value']) |
|
409 |
def get_condition_varnames(self, formdef):
|
|
410 |
return self.get_referenced_varnames(formdef, self.condition['value'])
|
|
411 | 411 | |
412 | 412 |
def has_live_conditions(self, formdef): |
413 |
varnames = self.get_condition_varnames() |
|
413 |
varnames = self.get_condition_varnames(formdef)
|
|
414 | 414 |
if not varnames: |
415 | 415 |
return False |
416 | 416 |
field_position = formdef.fields.index(self) |
wcs/formdata.py | ||
---|---|---|
525 | 525 |
last_seen_author = evolution_part.who or last_seen_author |
526 | 526 |
yield evolution_part |
527 | 527 | |
528 |
def get_workflow_form(self, user): |
|
528 |
def get_workflow_form(self, user, displayed_fields=None):
|
|
529 | 529 |
wf_status = self.get_status() |
530 | 530 |
if not wf_status: |
531 | 531 |
return None |
532 |
return wf_status.get_action_form(self, user) |
|
532 |
return wf_status.get_action_form(self, user, displayed_fields=displayed_fields)
|
|
533 | 533 | |
534 | 534 |
def handle_workflow_form(self, user, form): |
535 | 535 |
wf_status = self.get_status() |
... | ... | |
537 | 537 |
return None |
538 | 538 |
return wf_status.handle_form(form, self, user) |
539 | 539 | |
540 |
def evaluate_live_workflow_form(self, user, form): |
|
541 |
wf_status = self.get_status() |
|
542 |
if not wf_status: |
|
543 |
return None |
|
544 |
wf_status.evaluate_live_form(form, self, user) |
|
545 | ||
540 | 546 |
def pop_previous_marked_status(self): |
541 | 547 |
if not self.workflow_data or not '_markers_stack' in self.workflow_data: |
542 | 548 |
return None |
wcs/formdef.py | ||
---|---|---|
110 | 110 |
# store fields in a separate pickle chunk |
111 | 111 |
lightweight = True |
112 | 112 | |
113 |
# prefix for formdata variables |
|
114 |
var_prefix = 'form' |
|
115 | ||
113 | 116 |
# declarations for serialization |
114 | 117 |
TEXT_ATTRIBUTES = ['name', 'url_name', 'description', 'keywords', |
115 | 118 |
'publication_date', 'expiration_date', 'internal_identifier', |
... | ... | |
627 | 630 | |
628 | 631 |
return form |
629 | 632 | |
633 |
def set_live_condition_sources(self, form, fields): |
|
634 |
live_condition_fields = {} |
|
635 |
for field in fields: |
|
636 |
if field.condition: |
|
637 |
field.varnames = field.get_condition_varnames(formdef=self) |
|
638 |
for varname in field.varnames: |
|
639 |
if not varname in live_condition_fields: |
|
640 |
live_condition_fields[varname] = [] |
|
641 |
live_condition_fields[varname].append(field) |
|
642 |
if field.key == 'item' and field.data_source: |
|
643 |
real_data_source = data_sources.get_real(field.data_source) |
|
644 |
if real_data_source.get('type') != 'json': |
|
645 |
continue |
|
646 |
varnames = field.get_referenced_varnames( |
|
647 |
formdef=self, |
|
648 |
value=real_data_source.get('value')) |
|
649 |
for varname in varnames: |
|
650 |
if not varname in live_condition_fields: |
|
651 |
live_condition_fields[varname] = [] |
|
652 |
live_condition_fields[varname].append(field) |
|
653 |
if field.key == 'comment': |
|
654 |
for varname in field.get_referenced_varnames(formdef=self, value=field.label): |
|
655 |
if not varname in live_condition_fields: |
|
656 |
live_condition_fields[varname] = [] |
|
657 |
live_condition_fields[varname].append(field) |
|
658 | ||
659 |
for field in fields: |
|
660 |
if field.varname in live_condition_fields: |
|
661 |
form.get_widget('f%s' % field.id).live_condition_source = True |
|
662 | ||
630 | 663 |
def get_field_data(self, field, widget): |
631 | 664 |
d = {} |
632 | 665 |
d[field.id] = widget.parse() |
wcs/forms/common.py | ||
---|---|---|
21 | 21 |
from quixote.directory import Directory |
22 | 22 |
from quixote.html import TemplateIO, htmltext |
23 | 23 | |
24 |
from wcs import data_sources |
|
24 | 25 |
from wcs.api_utils import get_user_from_api_query_string, is_url_signed |
25 | 26 |
from wcs.fields import WidgetField, FileField |
26 | 27 |
from wcs.workflows import EditableWorkflowStatusItem |
... | ... | |
114 | 115 | |
115 | 116 | |
116 | 117 |
class FormStatusPage(Directory, FormTemplateMixin): |
117 |
_q_exports_orig = ['', 'download', 'json', 'action'] |
|
118 |
_q_exports_orig = ['', 'download', 'json', 'action', 'live']
|
|
118 | 119 |
_q_extra_exports = [] |
119 | 120 |
form_page_class = None |
120 | 121 | |
... | ... | |
238 | 239 |
get_logger().info('form %s - id: %s - view' % (self.formdef.name, self.filled.id)) |
239 | 240 | |
240 | 241 |
user = get_request().user |
241 |
form = self.filled.get_workflow_form(user) |
|
242 |
if form and form.is_submitted(): |
|
243 |
if not form.has_errors(): |
|
244 |
url = self.submit(form, comment_only = True) |
|
245 |
if not form.has_errors(): |
|
246 |
if url is None: |
|
247 |
url = get_request().get_frontoffice_url() |
|
248 |
response = get_response() |
|
249 |
response.set_status(303) |
|
250 |
response.headers[str('location')] = url |
|
251 |
response.content_type = 'text/plain' |
|
252 |
return "Your browser should redirect you" |
|
242 |
form = self.get_workflow_form(user) |
|
243 |
response = self.check_submitted_form(form) |
|
244 |
if response: |
|
245 |
return response |
|
253 | 246 | |
254 | 247 |
if form: |
255 | 248 |
form.add_media() |
... | ... | |
267 | 260 |
templates=list(self.get_formdef_template_variants(self.status_templates)), |
268 | 261 |
context=context) |
269 | 262 | |
263 |
def get_workflow_form(self, user): |
|
264 |
submitted_fields = [] |
|
265 |
form = self.filled.get_workflow_form(user, displayed_fields=submitted_fields) |
|
266 |
if form: |
|
267 |
form.attrs['data-live-url'] = self.filled.get_url() + 'live' |
|
268 |
if form and form.is_submitted(): |
|
269 |
with get_publisher().substitutions.temporary_feed(self.filled, force_mode='lazy'): |
|
270 |
# remove fields that could be required but are not visible |
|
271 |
self.filled.evaluate_live_workflow_form(user, form) |
|
272 |
get_publisher().substitutions.feed(self.filled) |
|
273 |
for field in submitted_fields: |
|
274 |
if not field.is_visible(self.filled.data, self.formdef) and 'f%s' % field.id in form._names: |
|
275 |
del form._names['f%s' % field.id] |
|
276 |
return form |
|
277 | ||
278 | ||
279 |
def check_submitted_form(self, form): |
|
280 |
if form and form.is_submitted() and not form.has_errors(): |
|
281 |
url = self.submit(form) |
|
282 |
if url is None: |
|
283 |
url = get_request().get_frontoffice_url() |
|
284 |
response = get_response() |
|
285 |
response.set_status(303) |
|
286 |
response.headers[str('location')] = url |
|
287 |
response.content_type = 'text/plain' |
|
288 |
return "Your browser should redirect you" |
|
289 | ||
290 | ||
270 | 291 |
def export_to_json(self, anonymise=False): |
271 | 292 |
get_response().set_content_type('application/json') |
272 | 293 |
return self.filled.export_to_json(anonymise=anonymise) |
... | ... | |
467 | 488 |
return redirect('./#lock-notice') |
468 | 489 | |
469 | 490 |
user = self.check_receiver() |
470 |
form = None |
|
471 | ||
472 |
try: |
|
473 |
form = self.filled.get_workflow_form(user) |
|
474 |
except: |
|
475 |
# XXX: probably because there are mixed forms, with and without |
|
476 |
# workflow; send a trace nevertheless. |
|
477 |
get_publisher().notify_of_exception(sys.exc_info(), context='[BACKOFFICE]') |
|
478 |
form = Form() |
|
479 | ||
480 |
if form and form.is_submitted() and not form.has_errors(): |
|
481 |
url = self.submit(form) |
|
491 |
form = self.get_workflow_form(user) |
|
492 |
response = self.check_submitted_form(form) |
|
493 |
if response: |
|
482 | 494 |
get_session().unmark_visited_object(object_key) |
483 |
if url is None: |
|
484 |
url = get_request().get_frontoffice_url() |
|
485 |
response = get_response() |
|
486 |
response.set_status(303) |
|
487 |
response.headers[str('location')] = url |
|
488 |
response.content_type = 'text/plain' |
|
489 |
return "Your browser should redirect you" |
|
495 |
return response |
|
490 | 496 | |
491 | 497 |
get_logger().info('form %s - id: %s - view status' % (self.formdef.name, self.filled.id)) |
492 | 498 |
get_response().add_javascript(['jquery.js', 'qommon.forms.js']) |
... | ... | |
566 | 572 |
r += htmltext('<a href="..">%s</a>') % _('Back to Listing') |
567 | 573 |
return r.getvalue() |
568 | 574 | |
569 |
def submit(self, form, comment_only = False):
|
|
575 |
def submit(self, form): |
|
570 | 576 |
current_status = self.filled.status |
571 | 577 |
user = get_request().user |
572 | 578 |
next_url = self.filled.handle_workflow_form(user, form) |
... | ... | |
612 | 618 |
file_url += file.base_filename |
613 | 619 |
return redirect(file_url) |
614 | 620 | |
621 |
@classmethod |
|
622 |
def live_process_fields(cls, form, formdata, displayed_fields): |
|
623 |
result = {} |
|
624 |
for field in displayed_fields: |
|
625 |
result[field.id] = {'visible': field.is_visible(formdata.data, formdata.formdef)} |
|
626 | ||
627 |
modified_field_varname = None |
|
628 |
for field in displayed_fields: |
|
629 |
if field.id == get_request().form.get('modified_field_id'): |
|
630 |
modified_field_varname = field.varname |
|
631 | ||
632 |
for field in displayed_fields: |
|
633 |
if field.key == 'item' and field.data_source: |
|
634 |
data_source = data_sources.get_object(field.data_source) |
|
635 |
if data_source.type != 'json': |
|
636 |
continue |
|
637 |
varnames = field.get_referenced_varnames( |
|
638 |
formdef=formdata.formdef, |
|
639 |
value=data_source.data_source.get('value')) |
|
640 |
if (modified_field_varname is None or modified_field_varname in varnames) and ( |
|
641 |
field.display_mode == 'autocomplete' and data_source.query_parameter): |
|
642 |
# computed earlier, in perform_more_widget_changes, when the field |
|
643 |
# was added to the form |
|
644 |
result[field.id]['source_url'] = field.url |
|
645 |
if modified_field_varname in varnames: |
|
646 |
result[field.id]['items'] = [ |
|
647 |
{'id': x[2], 'text': x[1]} for x in field.get_options(mode='lazy')] |
|
648 |
for widget in form.widgets: |
|
649 |
if not getattr(widget, 'field', None): |
|
650 |
continue |
|
651 |
if widget.field.key == 'comment': |
|
652 |
result[widget.field.id]['content'] = widget.content |
|
653 | ||
654 |
return json.dumps({'result': result}) |
|
655 | ||
656 |
def live(self): |
|
657 |
get_request().ignore_session = True |
|
658 |
# live evaluation of fields |
|
659 |
get_response().set_content_type('application/json') |
|
660 |
def result_error(reason): |
|
661 |
return json.dumps({'result': 'error', 'reason': reason}) |
|
662 | ||
663 |
session = get_session() |
|
664 |
if not session: |
|
665 |
return result_error('missing session') |
|
666 | ||
667 |
displayed_fields = [] |
|
668 |
user = get_request().user |
|
669 |
form = self.filled.get_workflow_form(user, displayed_fields=displayed_fields) |
|
670 |
self.filled.evaluate_live_workflow_form(user, form) |
|
671 |
get_publisher().substitutions.feed(self.filled) |
|
672 |
return self.live_process_fields(form, self.filled, displayed_fields) |
|
673 | ||
615 | 674 |
def _q_lookup(self, component): |
616 | 675 |
if component == 'files': |
617 | 676 |
self.check_receiver() |
wcs/forms/root.py | ||
---|---|---|
386 | 386 |
# always set additional attributes as they will be used for |
387 | 387 |
# "live prefill", regardless of existing data. |
388 | 388 |
form.get_widget('f%s' % field.id).prefill_attributes = field.get_prefill_attributes() |
389 |
if field.condition: |
|
390 |
field.varnames = field.get_condition_varnames() |
|
391 |
for varname in field.varnames: |
|
392 |
if not varname in live_condition_fields: |
|
393 |
live_condition_fields[varname] = [] |
|
394 |
live_condition_fields[varname].append(field) |
|
395 |
if field.key == 'item' and field.data_source: |
|
396 |
real_data_source = data_sources.get_real(field.data_source) |
|
397 |
if real_data_source.get('type') != 'json': |
|
398 |
continue |
|
399 |
varnames = re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)', |
|
400 |
real_data_source.get('value')) |
|
401 |
for varname in varnames: |
|
402 |
if not varname in live_condition_fields: |
|
403 |
live_condition_fields[varname] = [] |
|
404 |
live_condition_fields[varname].append(field) |
|
405 |
if field.key == 'comment': |
|
406 |
for varname in field.get_referenced_varnames(field.label): |
|
407 |
if not varname in live_condition_fields: |
|
408 |
live_condition_fields[varname] = [] |
|
409 |
live_condition_fields[varname].append(field) |
|
410 | 389 | |
411 |
for field in displayed_fields: |
|
412 |
if field.varname in live_condition_fields: |
|
413 |
form.get_widget('f%s' % field.id).live_condition_source = True |
|
390 |
self.formdef.set_live_condition_sources(form, displayed_fields) |
|
414 | 391 | |
415 | 392 |
self.html_top(self.formdef.name) |
416 | 393 | |
... | ... | |
1105 | 1082 |
displayed_fields=displayed_fields, |
1106 | 1083 |
transient_formdata=formdata) |
1107 | 1084 |
formdata.data.update(self.formdef.get_data(form)) |
1108 | ||
1109 |
result = {} |
|
1110 |
for field in displayed_fields: |
|
1111 |
result[field.id] = {'visible': field.is_visible(formdata.data, self.formdef)} |
|
1112 | ||
1113 |
modified_field_varname = None |
|
1114 |
for field in displayed_fields: |
|
1115 |
if field.id == get_request().form.get('modified_field_id'): |
|
1116 |
modified_field_varname = field.varname |
|
1117 | ||
1118 |
for field in displayed_fields: |
|
1119 |
if field.key == 'item' and field.data_source: |
|
1120 |
data_source = data_sources.get_object(field.data_source) |
|
1121 |
if data_source.type != 'json': |
|
1122 |
continue |
|
1123 |
varnames = re.findall(r'\bform[_\.]var[_\.]([a-zA-Z0-9_]+?)(?:_raw|\b)', |
|
1124 |
data_source.data_source.get('value')) |
|
1125 |
if (modified_field_varname is None or modified_field_varname in varnames) and ( |
|
1126 |
field.display_mode == 'autocomplete' and data_source.query_parameter): |
|
1127 |
# computed earlier, in perform_more_widget_changes, when the field |
|
1128 |
# was added to the form |
|
1129 |
result[field.id]['source_url'] = field.url |
|
1130 |
if modified_field_varname in varnames: |
|
1131 |
result[field.id]['items'] = [ |
|
1132 |
{'id': x[2], 'text': x[1]} for x in field.get_options(mode='lazy')] |
|
1133 |
for widget in form.widgets: |
|
1134 |
if not getattr(widget, 'field', None): |
|
1135 |
continue |
|
1136 |
if widget.field.key == 'comment': |
|
1137 |
result[widget.field.id]['content'] = widget.content |
|
1138 | ||
1139 |
return json.dumps({'result': result}) |
|
1085 |
return FormStatusPage.live_process_fields(form, formdata, displayed_fields) |
|
1140 | 1086 | |
1141 | 1087 |
def submitted(self, form, existing_formdata = None): |
1142 | 1088 |
if existing_formdata: # modifying |
... | ... | |
1678 | 1624 | |
1679 | 1625 | |
1680 | 1626 |
class PublicFormStatusPage(FormStatusPage): |
1681 |
_q_exports_orig = ['', 'download', 'status'] |
|
1627 |
_q_exports_orig = ['', 'download', 'status', 'live']
|
|
1682 | 1628 |
form_page_class = FormPage |
1683 | 1629 |
history_templates = ['wcs/front/formdata_history.html', 'wcs/formdata_history.html'] |
1684 | 1630 |
status_templates = ['wcs/front/formdata_status.html', 'wcs/formdata_status.html'] |
wcs/wf/attachment.py | ||
---|---|---|
100 | 100 |
else: |
101 | 101 |
return _('not completed') |
102 | 102 | |
103 |
def fill_form(self, form, formdata, user): |
|
103 |
def fill_form(self, form, formdata, user, **kwargs):
|
|
104 | 104 |
if self.display_title: |
105 | 105 |
title = self.title or _('Upload File') |
106 | 106 |
else: |
wcs/wf/export_to_model.py | ||
---|---|---|
207 | 207 |
else: |
208 | 208 |
return _('no model set') |
209 | 209 | |
210 |
def fill_form(self, form, formdata, user): |
|
210 |
def fill_form(self, form, formdata, user, **kwargs):
|
|
211 | 211 |
if not self.method == 'interactive': |
212 | 212 |
return |
213 | 213 |
label = self.label |
wcs/wf/form.py | ||
---|---|---|
56 | 56 | |
57 | 57 |
class WorkflowFormFieldDefPage(FieldDefPage): |
58 | 58 |
section = 'workflows' |
59 |
blacklisted_attributes = ['condition', 'in_listing']
|
|
59 |
blacklisted_attributes = ['in_listing'] |
|
60 | 60 | |
61 | 61 |
def get_deletion_extra_warning(self): |
62 | 62 |
return None |
... | ... | |
66 | 66 |
section = 'workflows' |
67 | 67 |
support_import = False |
68 | 68 |
blacklisted_types = ['page'] |
69 |
blacklisted_attributes = ['condition'] |
|
70 | 69 |
field_def_page_class = WorkflowFormFieldDefPage |
71 | 70 | |
72 | 71 | |
... | ... | |
154 | 153 |
return fields_directory |
155 | 154 |
return None |
156 | 155 | |
157 |
def fill_form(self, form, formdata, user): |
|
156 |
def fill_form(self, form, formdata, user, displayed_fields=None, **kwargs):
|
|
158 | 157 |
if not self.formdef: |
159 | 158 |
return |
160 |
self.formdef.add_fields_to_form(form) |
|
159 |
self.formdef.var_prefix = self.varname |
|
160 |
self.formdef.add_fields_to_form(form, displayed_fields=displayed_fields) |
|
161 | 161 |
form.add_submit('submit', _('Submit')) |
162 | 162 | |
163 | 163 |
# put varname in a form attribute so it can be used in templates to |
... | ... | |
167 | 167 |
formdata.feed_session() |
168 | 168 | |
169 | 169 |
req = get_request() |
170 |
self.formdef.set_live_condition_sources(form, self.formdef.fields) |
|
171 | ||
170 | 172 |
for field in self.formdef.fields: |
171 | 173 |
if ('f%s' % field.id) in req.form: |
172 | 174 |
continue |
... | ... | |
187 | 189 |
form.get_widget('f%s' % field.id).set_value(v) |
188 | 190 |
req.form['f%s' % field.id] = v |
189 | 191 | |
192 |
def evaluate_live_form(self, form, formdata, user): |
|
193 |
workflow_data = {} |
|
194 |
for k, v in get_dict_with_varnames( |
|
195 |
self.formdef.fields, self.formdef.get_data(form), |
|
196 |
varnames_only=True).items(): |
|
197 |
workflow_data['%s_%s' % (self.varname, k)] = v |
|
198 |
formdata.update_workflow_data(workflow_data) |
|
199 | ||
190 | 200 |
def submit_form(self, form, formdata, user, evo): |
191 | 201 |
if not self.formdef: |
192 | 202 |
return |
193 | 203 |
if form.get_submit() == 'submit' and not form.has_errors(): |
194 |
workflow_data = {} |
|
195 |
for k, v in get_dict_with_varnames( |
|
196 |
self.formdef.fields, self.formdef.get_data(form), |
|
197 |
varnames_only=True).items(): |
|
198 |
workflow_data['%s_%s' % (self.varname, k)] = v |
|
199 |
formdata.update_workflow_data(workflow_data) |
|
204 |
self.evaluate_live_form(form, formdata, user) |
|
200 | 205 |
formdata.store() |
201 | 206 | |
202 | 207 |
def get_parameters_view(self): |
wcs/wf/resubmit.py | ||
---|---|---|
46 | 46 |
else: |
47 | 47 |
return _('not completed') |
48 | 48 | |
49 |
def fill_form(self, form, formdata, user): |
|
49 |
def fill_form(self, form, formdata, user, **kwargs):
|
|
50 | 50 |
label = self.label |
51 | 51 |
if not label: |
52 | 52 |
label = _('Resubmit') |
wcs/workflows.py | ||
---|---|---|
1352 | 1352 |
return item |
1353 | 1353 |
raise KeyError() |
1354 | 1354 | |
1355 |
def get_action_form(self, filled, user): |
|
1355 |
def get_action_form(self, filled, user, displayed_fields=None):
|
|
1356 | 1356 |
form = Form(enctype='multipart/form-data', use_tokens=False) |
1357 | 1357 |
form.attrs['id'] = 'wf-actions' |
1358 | 1358 |
for item in self.items: |
... | ... | |
1360 | 1360 |
continue |
1361 | 1361 |
if not item.check_condition(filled): |
1362 | 1362 |
continue |
1363 |
item.fill_form(form, filled, user) |
|
1363 |
item.fill_form(form, filled, user, displayed_fields=displayed_fields)
|
|
1364 | 1364 | |
1365 | 1365 |
for action in filled.formdef.workflow.get_global_actions_for_user(filled, user): |
1366 | 1366 |
form.add_submit('button-action-%s' % action.id, action.name) |
... | ... | |
1372 | 1372 |
else: |
1373 | 1373 |
return None |
1374 | 1374 | |
1375 |
def handle_form(self, form, filled, user): |
|
1376 |
# check for global actions |
|
1377 |
for action in filled.formdef.workflow.get_global_actions_for_user(filled, user): |
|
1378 |
if 'button-action-%s' % action.id in get_request().form: |
|
1379 |
url = perform_items(action.items, filled) |
|
1380 |
if url: |
|
1381 |
return url |
|
1382 |
return |
|
1383 | ||
1384 |
evo = Evolution() |
|
1385 |
evo.time = time.localtime() |
|
1386 |
if user: |
|
1387 |
if filled.is_submitter(user): |
|
1388 |
evo.who = '_submitter' |
|
1389 |
else: |
|
1390 |
evo.who = user.id |
|
1391 |
if not filled.evolution: |
|
1392 |
filled.evolution = [] |
|
1393 | ||
1375 |
def get_active_items(self, form, filled, user): |
|
1394 | 1376 |
for item in self.items: |
1395 | 1377 |
if hasattr(item, 'by'): |
1396 | 1378 |
for role in item.by or []: |
... | ... | |
1410 | 1392 |
continue |
1411 | 1393 |
if not item.check_condition(filled): |
1412 | 1394 |
continue |
1395 |
yield item |
|
1396 | ||
1397 |
def evaluate_live_form(self, form, filled, user): |
|
1398 |
for item in self.get_active_items(form, filled, user): |
|
1399 |
item.evaluate_live_form(form, filled, user) |
|
1400 | ||
1401 |
def handle_form(self, form, filled, user): |
|
1402 |
# check for global actions |
|
1403 |
for action in filled.formdef.workflow.get_global_actions_for_user(filled, user): |
|
1404 |
if 'button-action-%s' % action.id in get_request().form: |
|
1405 |
url = perform_items(action.items, filled) |
|
1406 |
if url: |
|
1407 |
return url |
|
1408 |
return |
|
1409 | ||
1410 |
evo = Evolution() |
|
1411 |
evo.time = time.localtime() |
|
1412 |
if user: |
|
1413 |
if filled.is_submitter(user): |
|
1414 |
evo.who = '_submitter' |
|
1415 |
else: |
|
1416 |
evo.who = user.id |
|
1417 |
if not filled.evolution: |
|
1418 |
filled.evolution = [] |
|
1419 | ||
1420 |
for item in self.get_active_items(form, filled, user): |
|
1413 | 1421 |
next_url = item.submit_form(form, filled, user, evo) |
1414 | 1422 |
if next_url is True: |
1415 | 1423 |
break |
... | ... | |
1611 | 1619 |
def perform(self, formdata): |
1612 | 1620 |
pass |
1613 | 1621 | |
1614 |
def fill_form(self, form, formdata, user): |
|
1622 |
def fill_form(self, form, formdata, user, **kwargs): |
|
1623 |
pass |
|
1624 | ||
1625 |
def evaluate_live_form(self, form, formdata, user): |
|
1615 | 1626 |
pass |
1616 | 1627 | |
1617 | 1628 |
def submit_form(self, form, formdata, user, evo): |
... | ... | |
2005 | 2016 |
else: |
2006 | 2017 |
return _('not completed') |
2007 | 2018 | |
2008 |
def fill_form(self, form, formdata, user): |
|
2019 |
def fill_form(self, form, formdata, user, **kwargs):
|
|
2009 | 2020 |
if not 'comment' in [x.name for x in form.widgets]: |
2010 | 2021 |
if self.label is None: |
2011 | 2022 |
title = _('Comment') |
... | ... | |
2144 | 2155 |
else: |
2145 | 2156 |
return _('not completed') |
2146 | 2157 | |
2147 |
def fill_form(self, form, formdata, user): |
|
2158 |
def fill_form(self, form, formdata, user, **kwargs):
|
|
2148 | 2159 |
label = self.compute(self.label) |
2149 | 2160 |
if not label: |
2150 | 2161 |
return |
... | ... | |
2727 | 2738 |
else: |
2728 | 2739 |
return _('not completed') |
2729 | 2740 | |
2730 |
def fill_form(self, form, formdata, user): |
|
2741 |
def fill_form(self, form, formdata, user, **kwargs):
|
|
2731 | 2742 |
label = self.label |
2732 | 2743 |
if not label: |
2733 | 2744 |
label = _('Edit Form') |
2734 |
- |