0001-general-add-support-for-backoffice-fields-8273.patch
tests/test_admin_pages.py | ||
---|---|---|
1556 | 1556 |
assert Workflow.get(1).variables_formdef.fields[0].key == 'string' |
1557 | 1557 |
assert Workflow.get(1).variables_formdef.fields[0].varname == '1*1*message' |
1558 | 1558 | |
1559 |
def test_workflows_backoffice_fields(pub): |
|
1560 |
create_superuser(pub) |
|
1561 |
create_role() |
|
1562 | ||
1563 |
Workflow.wipe() |
|
1564 |
workflow = Workflow(name='foo') |
|
1565 |
workflow.add_status(name='baz') |
|
1566 |
workflow.store() |
|
1567 | ||
1568 |
formdef = FormDef() |
|
1569 |
formdef.name = 'form title' |
|
1570 |
formdef.workflow_id = workflow.id |
|
1571 |
formdef.fields = [] |
|
1572 |
formdef.store() |
|
1573 | ||
1574 |
app = login(get_app(pub)) |
|
1575 |
resp = app.get('/backoffice/workflows/1/') |
|
1576 |
resp = resp.click('baz') |
|
1577 |
assert not 'Set Backoffice Field' in resp.body |
|
1578 | ||
1579 |
resp = app.get('/backoffice/workflows/1/') |
|
1580 |
resp = resp.click(href='backoffice-fields/') |
|
1581 |
assert resp.location == 'http://example.net/backoffice/workflows/1/backoffice-fields/fields/' |
|
1582 |
resp = resp.follow() |
|
1583 | ||
1584 |
# makes sure we can't add page fields |
|
1585 |
assert 'value="New Page"' not in resp.body |
|
1586 | ||
1587 |
# add a simple field |
|
1588 |
resp.forms[0]['label'] = 'foobar' |
|
1589 |
resp.forms[0]['type'] = 'Text (line)' |
|
1590 |
resp = resp.forms[0].submit() |
|
1591 |
assert resp.location == 'http://example.net/backoffice/workflows/1/backoffice-fields/fields/' |
|
1592 |
resp = resp.follow() |
|
1593 | ||
1594 |
# check it's been saved correctly |
|
1595 |
assert 'foobar' in resp.body |
|
1596 |
assert len(Workflow.get(1).backoffice_fields_formdef.fields) == 1 |
|
1597 |
assert Workflow.get(1).backoffice_fields_formdef.fields[0].id.startswith('bo') |
|
1598 |
assert Workflow.get(1).backoffice_fields_formdef.fields[0].key == 'string' |
|
1599 |
assert Workflow.get(1).backoffice_fields_formdef.fields[0].label == 'foobar' |
|
1600 | ||
1601 |
backoffice_field_id = Workflow.get(1).backoffice_fields_formdef.fields[0].id |
|
1602 |
formdef = FormDef.get(formdef.id) |
|
1603 |
data_class = formdef.data_class() |
|
1604 |
data_class.wipe() |
|
1605 |
formdata = data_class() |
|
1606 |
formdata.data = {backoffice_field_id: 'HELLO'} |
|
1607 |
formdata.status = 'wf-new' |
|
1608 |
formdata.store() |
|
1609 | ||
1610 |
assert data_class.get(formdata.id).data[backoffice_field_id] == 'HELLO' |
|
1611 | ||
1612 |
# check the "set backoffice field" action is now available |
|
1613 |
resp = app.get('/backoffice/workflows/1/') |
|
1614 |
resp = resp.click('baz') |
|
1615 |
resp.forms[0]['type'] = 'Set Backoffice Field' |
|
1616 |
resp = resp.forms[0].submit() |
|
1617 |
resp = resp.follow() |
|
1618 | ||
1619 |
resp = resp.click('Set Backoffice Field') |
|
1620 | ||
1559 | 1621 |
def test_workflows_functions(pub): |
1560 | 1622 |
create_superuser(pub) |
1561 | 1623 |
create_role() |
tests/test_backoffice_pages.py | ||
---|---|---|
20 | 20 |
from wcs.roles import Role |
21 | 21 |
from wcs.workflows import (Workflow, CommentableWorkflowStatusItem, |
22 | 22 |
ChoiceWorkflowStatusItem, EditableWorkflowStatusItem, |
23 |
JumpOnSubmitWorkflowStatusItem, WorkflowCriticalityLevel) |
|
23 |
JumpOnSubmitWorkflowStatusItem, WorkflowCriticalityLevel, |
|
24 |
WorkflowBackofficeFieldsFormDef) |
|
24 | 25 |
from wcs.wf.dispatch import DispatchWorkflowStatusItem |
25 | 26 |
from wcs.wf.wscall import WebserviceCallStatusItem |
26 | 27 |
from wcs.wf.register_comment import RegisterCommenterWorkflowStatusItem |
... | ... | |
2486 | 2487 |
assert (pq('[title="form_var_foo_str_but_non_utf8"]') |
2487 | 2488 |
.parents('li').children('div.value span') |
2488 | 2489 |
.text() == '\'\\xed\\xa0\\x00\'') |
2490 | ||
2491 |
def test_backoffice_fields(pub): |
|
2492 |
user = create_user(pub) |
|
2493 |
create_environment(pub) |
|
2494 | ||
2495 |
wf = Workflow(name='bo fields') |
|
2496 |
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) |
|
2497 |
wf.backoffice_fields_formdef.fields = [ |
|
2498 |
fields.StringField(id='bo1', label='1st backoffice field', |
|
2499 |
type='string', varname='backoffice_blah'), |
|
2500 |
] |
|
2501 |
st1 = wf.add_status('Status1') |
|
2502 |
wf.store() |
|
2503 | ||
2504 |
formdef = FormDef.get_by_urlname('form-title') |
|
2505 |
formdef.workflow_id = wf.id |
|
2506 |
formdef.store() |
|
2507 | ||
2508 |
formdata = formdef.data_class()() |
|
2509 |
formdata.data = {} |
|
2510 |
formdata.just_created() |
|
2511 |
formdata.store() |
|
2512 | ||
2513 |
app = login(get_app(pub)) |
|
2514 |
resp = app.get(formdata.get_url(backoffice=True)) |
|
2515 |
assert not 'Backoffice Data' in resp.body |
|
2516 |
assert not '1st backoffice field' in resp.body |
|
2517 | ||
2518 |
formdata.data = {'bo1': 'HELLO WORLD'} |
|
2519 |
formdata.store() |
|
2520 |
resp = app.get(formdata.get_url(backoffice=True)) |
|
2521 |
assert 'Backoffice Data' in resp.body |
|
2522 |
assert '1st backoffice field' in resp.body |
|
2523 |
assert 'HELLO WORLD' in resp.body |
tests/test_workflows.py | ||
---|---|---|
18 | 18 |
SendmailWorkflowStatusItem, SendSMSWorkflowStatusItem, |
19 | 19 |
DisplayMessageWorkflowStatusItem, |
20 | 20 |
AbortActionException, WorkflowCriticalityLevel, |
21 |
AttachmentEvolutionPart) |
|
21 |
AttachmentEvolutionPart, WorkflowBackofficeFieldsFormDef)
|
|
22 | 22 |
from wcs.wf.anonymise import AnonymiseWorkflowStatusItem |
23 | 23 |
from wcs.wf.criticality import ModifyCriticalityWorkflowStatusItem, MODE_INC, MODE_DEC, MODE_SET |
24 | 24 |
from wcs.wf.dispatch import DispatchWorkflowStatusItem |
... | ... | |
31 | 31 |
from wcs.wf.wscall import WebserviceCallStatusItem |
32 | 32 |
from wcs.wf.export_to_model import transform_to_pdf |
33 | 33 |
from wcs.wf.geolocate import GeolocateWorkflowStatusItem |
34 |
from wcs.wf.set_backoffice_field import SetBackofficeFieldWorkflowStatusItem |
|
34 | 35 | |
35 | 36 |
from utilities import (create_temporary_pub, MockSubstitutionVariables, emails, |
36 | 37 |
http_requests, clean_temporary_pub, sms_mocking) |
... | ... | |
1578 | 1579 |
item.fields = [{'field_id': 'plop', 'value': '=form_var_foo'}] |
1579 | 1580 |
item.perform(formdata) |
1580 | 1581 |
assert pub.user_class.get(user.id).form_data == {'3': 'Plop'} |
1582 | ||
1583 |
def test_set_backoffice_field(pub): |
|
1584 |
Workflow.wipe() |
|
1585 |
wf = Workflow(name='xxx') |
|
1586 |
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) |
|
1587 |
wf.backoffice_fields_formdef.fields = [ |
|
1588 |
StringField(id='bo1', label='1st backoffice field', |
|
1589 |
type='string', varname='backoffice_blah'), |
|
1590 |
] |
|
1591 |
st1 = wf.add_status('Status1') |
|
1592 |
wf.store() |
|
1593 | ||
1594 |
formdef = FormDef() |
|
1595 |
formdef.name = 'baz' |
|
1596 |
formdef.fields = [ |
|
1597 |
StringField(id='1', label='String', type='string', varname='string'), |
|
1598 |
] |
|
1599 |
formdef.workflow_id = wf.id |
|
1600 |
formdef.store() |
|
1601 | ||
1602 |
formdata = formdef.data_class()() |
|
1603 |
formdata.data = {'1': 'HELLO'} |
|
1604 |
formdata.just_created() |
|
1605 |
formdata.store() |
|
1606 |
pub.substitutions.feed(formdata) |
|
1607 | ||
1608 |
item = SetBackofficeFieldWorkflowStatusItem() |
|
1609 |
item.perform(formdata) |
|
1610 | ||
1611 |
item = SetBackofficeFieldWorkflowStatusItem() |
|
1612 |
item.field_id = 'bo1' |
|
1613 |
item.field_content = '=form_var_string' |
|
1614 |
item.perform(formdata) |
|
1615 | ||
1616 |
formdata = formdef.data_class().get(formdata.id) |
|
1617 |
assert formdata.data['bo1'] == 'HELLO' |
wcs/admin/workflows.py | ||
---|---|---|
832 | 832 |
return form |
833 | 833 | |
834 | 834 | |
835 |
class WorkflowBackofficeFieldDefPage(FieldDefPage): |
|
836 |
section = 'workflows' |
|
837 | ||
838 | ||
835 | 839 |
class WorkflowVariablesFieldsDirectory(FieldsDirectory): |
836 | 840 |
_q_exports = ['', 'update_order', 'new'] |
837 | 841 | |
... | ... | |
853 | 857 |
pass |
854 | 858 | |
855 | 859 | |
860 |
class WorkflowBackofficeFieldsDirectory(FieldsDirectory): |
|
861 |
_q_exports = ['', 'update_order', 'new'] |
|
862 | ||
863 |
section = 'workflows' |
|
864 |
field_def_page_class = WorkflowBackofficeFieldDefPage |
|
865 |
support_import = False |
|
866 |
blacklisted_types = ['page'] |
|
867 | ||
868 |
def index_top(self): |
|
869 |
r = TemplateIO(html=True) |
|
870 |
r += htmltext('<h2>%s - %s - %s</h2>') % (_('Workflow'), |
|
871 |
self.objectdef.name, _('Backoffice Fields')) |
|
872 |
r += get_session().display_message() |
|
873 |
if not self.objectdef.fields: |
|
874 |
r += htmltext('<p>%s</p>') % _('There are not yet any backoffice fields.') |
|
875 |
return r.getvalue() |
|
876 | ||
877 |
def index_bottom(self): |
|
878 |
pass |
|
879 | ||
880 | ||
856 | 881 |
class VariablesDirectory(Directory): |
857 | 882 |
_q_exports = ['', 'fields'] |
858 | 883 | |
... | ... | |
869 | 894 |
return Directory._q_traverse(self, path) |
870 | 895 | |
871 | 896 | |
897 |
class BackofficeFieldsDirectory(Directory): |
|
898 |
_q_exports = ['', 'fields'] |
|
899 | ||
900 |
def __init__(self, workflow): |
|
901 |
self.workflow = workflow |
|
902 | ||
903 |
def _q_index(self): |
|
904 |
return redirect('fields/') |
|
905 | ||
906 |
def _q_traverse(self, path): |
|
907 |
get_response().breadcrumb.append(('backoffice-fields/', _('Backoffice Fields'))) |
|
908 |
self.fields = WorkflowBackofficeFieldsDirectory( |
|
909 |
WorkflowBackofficeFieldsFormDef(self.workflow)) |
|
910 |
return Directory._q_traverse(self, path) |
|
911 | ||
912 | ||
913 | ||
872 | 914 |
class FunctionsDirectory(Directory): |
873 | 915 |
_q_exports = ['', 'new'] |
874 | 916 | |
... | ... | |
1266 | 1308 |
class WorkflowPage(Directory): |
1267 | 1309 |
_q_exports = ['', 'edit', 'delete', 'newstatus', ('status', 'status_dir'), 'update_order', |
1268 | 1310 |
'duplicate', 'export', 'svg', ('variables', 'variables_dir'), |
1311 |
('backoffice-fields', 'backoffice_fields_dir'), |
|
1269 | 1312 |
'update_actions_order', 'update_criticality_levels_order', |
1270 | 1313 |
('functions', 'functions_dir'), ('global-actions', 'global_actions_dir'), |
1271 | 1314 |
('criticality-levels', 'criticality_levels_dir'), |
... | ... | |
1280 | 1323 |
self.workflow_ui = WorkflowUI(self.workflow) |
1281 | 1324 |
self.status_dir = WorkflowStatusDirectory(self.workflow, html_top) |
1282 | 1325 |
self.variables_dir = VariablesDirectory(self.workflow) |
1326 |
self.backoffice_fields_dir = BackofficeFieldsDirectory(self.workflow) |
|
1283 | 1327 |
self.functions_dir = FunctionsDirectory(self.workflow) |
1284 | 1328 |
self.global_actions_dir = GlobalActionsDirectory(self.workflow, html_top) |
1285 | 1329 |
self.criticality_levels_dir = CriticalityLevelsDirectory(self.workflow) |
... | ... | |
1425 | 1469 |
r += htmltext('</ul>') |
1426 | 1470 |
r += htmltext('</div>') |
1427 | 1471 | |
1472 |
if not str(self.workflow.id).startswith('_'): |
|
1473 |
r += htmltext('<div class="bo-block">') |
|
1474 |
r += htmltext('<h3>%s') % _('Backoffice Fields') |
|
1475 |
r += htmltext(' <span class="change">(<a href="backoffice-fields/">%s</a>)</span></h3>') % _('change') |
|
1476 |
if self.workflow.backoffice_fields_formdef: |
|
1477 |
r += htmltext('<ul class="biglist">') |
|
1478 |
for field in self.workflow.backoffice_fields_formdef.fields: |
|
1479 |
r += htmltext('<li><a href="backoffice-fields/fields/%s/">%s') % ( |
|
1480 |
field.id, field.label) |
|
1481 |
if field.varname: |
|
1482 |
r += htmltext(' (<code>%s</code>)') % field.varname |
|
1483 |
r += htmltext('</a></li>') |
|
1484 |
r += htmltext('</ul>') |
|
1485 |
r += htmltext('</div>') |
|
1486 | ||
1428 | 1487 |
r += htmltext('</div>') # .splitcontent-right |
1429 | 1488 | |
1430 | 1489 |
r += htmltext('<br style="clear:both;"/>') |
wcs/backoffice/management.py | ||
---|---|---|
183 | 183 |
r += htmltext('<h2>%s</h2>') % self.user.display_name |
184 | 184 |
formdef = UserFieldsFormDef() |
185 | 185 |
r += htmltext('<div class="form">') |
186 |
for field in formdef.fields:
|
|
186 |
for field in formdef.get_all_fields():
|
|
187 | 187 |
if not hasattr(field, str('get_view_value')): |
188 | 188 |
continue |
189 | 189 |
value = self.user.form_data.get(field.id) |
... | ... | |
321 | 321 | |
322 | 322 |
formdef = UserFieldsFormDef() |
323 | 323 |
criteria_fields = [ILike('name', query), ILike('email', query)] |
324 |
for field in formdef.fields:
|
|
324 |
for field in formdef.get_all_fields():
|
|
325 | 325 |
if field.type in ('string', 'text', 'email'): |
326 | 326 |
criteria_fields.append(ILike('f%s' % field.id, query)) |
327 | 327 |
if get_publisher().is_using_postgresql(): |
... | ... | |
342 | 342 |
r += htmltext('<th data-field-sort-key="name"><span>%s</span></th>') % _('Name') |
343 | 343 |
if include_email_column: |
344 | 344 |
r += htmltext('<th data-field-sort-key="email"><span>%s</span></th>') % _('Email') |
345 |
for field in formdef.fields:
|
|
345 |
for field in formdef.get_all_fields():
|
|
346 | 346 |
if field.in_listing: |
347 | 347 |
r += htmltext('<th data-field-sort-key="f%s"><span>%s</span></th>') % ( |
348 | 348 |
field.id, field.label) |
... | ... | |
356 | 356 |
r += htmltext('<td>%s</td>') % (user.name or '') |
357 | 357 |
if include_email_column: |
358 | 358 |
r += htmltext('<td>%s</td>') % (user.email or '') |
359 |
for field in formdef.fields:
|
|
359 |
for field in formdef.get_all_fields():
|
|
360 | 360 |
if field.in_listing: |
361 | 361 |
r += htmltext('<td>%s</td>') % (user.form_data.get(field.id) or '') |
362 | 362 |
r += htmltext('</tr>') |
... | ... | |
1036 | 1036 |
fields.append(FakeField('submission_channel', 'submission_channel', _('Channel'))) |
1037 | 1037 |
fields.append(FakeField('time', 'time', _('Time'))) |
1038 | 1038 |
fields.append(FakeField('user-label', 'user-label', _('User Label'))) |
1039 |
fields.extend(self.formdef.fields)
|
|
1039 |
fields.extend(self.formdef.get_all_fields())
|
|
1040 | 1040 |
fields.append(FakeField('status', 'status', _('Status'))) |
1041 | 1041 |
fields.append(FakeField('anonymised', 'anonymised', _('Anonymised'))) |
1042 | 1042 | |
... | ... | |
1046 | 1046 |
field_ids = [x for x in get_request().form.keys()] |
1047 | 1047 |
if not field_ids or ignore_form: |
1048 | 1048 |
field_ids = ['id', 'time', 'user-label'] |
1049 |
for field in self.formdef.fields:
|
|
1049 |
for field in self.formdef.get_all_fields():
|
|
1050 | 1050 |
if hasattr(field, str('get_view_value')) and field.in_listing: |
1051 | 1051 |
field_ids.append(field.id) |
1052 | 1052 |
field_ids.append('status') |
... | ... | |
1636 | 1636 |
had_page = False |
1637 | 1637 |
last_page = None |
1638 | 1638 |
last_title = None |
1639 |
for f in self.formdef.fields:
|
|
1639 |
for f in self.formdef.get_all_fields():
|
|
1640 | 1640 |
if excluded_fields and f.id in excluded_fields: |
1641 | 1641 |
continue |
1642 | 1642 |
if f.type == 'page': |
wcs/formdef.py | ||
---|---|---|
292 | 292 |
rebuild_global_views=True) |
293 | 293 |
return t |
294 | 294 | |
295 |
def rebuild_views(self): |
|
295 |
def get_all_fields(self): |
|
296 |
workflow_fields = [] |
|
297 |
try: |
|
298 |
workflow_fields = self.workflow.backoffice_fields_formdef.fields |
|
299 |
except AttributeError: |
|
300 |
pass |
|
301 |
return (self.fields or []) + workflow_fields |
|
302 | ||
303 |
def rebuild(self): |
|
296 | 304 |
if get_publisher().is_using_postgresql(): |
297 | 305 |
import sql |
298 | 306 |
sql.do_formdef_tables(self, rebuild_views=True, |
wcs/forms/common.py | ||
---|---|---|
420 | 420 |
r += htmltext('<div class="field"><span class="label">%s</span>') % _('User name') |
421 | 421 |
r += htmltext('<span class="value">%s</span></div>') % user.display_name |
422 | 422 | |
423 |
r += self.display_fields(self.formdef.fields, form_url) |
|
424 | ||
425 |
if show_status and self.formdef.is_user_allowed_read_status_and_history( |
|
426 |
get_request().user, self.filled): |
|
427 |
wf_status = self.filled.get_visible_status() |
|
428 |
if wf_status: |
|
429 |
r += htmltext('<div><span class="label">%s</span> ') % _('Status') |
|
430 |
r += htmltext('<span class="value">%s</span></div>') % wf_status.name |
|
431 | ||
432 |
r += htmltext('</div>') # .dataview |
|
433 |
r += htmltext('</div>') # .bo-block |
|
434 | ||
435 |
return r.getvalue() |
|
436 | ||
437 |
def display_fields(self, fields, form_url=''): |
|
438 |
r = TemplateIO(html=True) |
|
423 | 439 |
on_page = False |
424 | 440 |
on_disabled_page = False |
425 |
for f in self.formdef.fields: |
|
426 | ||
441 |
for f in fields: |
|
427 | 442 |
if f.type == 'page': |
428 | 443 |
on_disabled_page = False |
429 | 444 |
if not f.is_visible(self.filled.data, self.formdef): |
... | ... | |
485 | 500 |
if on_page: |
486 | 501 |
r += htmltext('</div></div>') |
487 | 502 | |
488 |
if show_status and self.formdef.is_user_allowed_read_status_and_history( |
|
489 |
get_request().user, self.filled): |
|
490 |
wf_status = self.filled.get_visible_status() |
|
491 |
if wf_status: |
|
492 |
r += htmltext('<p><span class="label">%s</span> ') % _('Status') |
|
493 |
r += htmltext('<span class="value">%s</span></p>') % wf_status.name |
|
494 | ||
495 |
r += htmltext('</div>') # .dataview |
|
496 |
r += htmltext('</div>') # .bo-block |
|
497 | 503 |
return r.getvalue() |
498 | 504 | |
505 |
def backoffice_fields_section(self): |
|
506 |
backoffice_fields = self.formdef.workflow.get_backoffice_fields() |
|
507 |
if not backoffice_fields: |
|
508 |
return |
|
509 |
content = self.display_fields(backoffice_fields) |
|
510 |
if not len(content): |
|
511 |
return |
|
512 |
r = TemplateIO(html=True) |
|
513 |
r += htmltext('<div class="bo-block">') |
|
514 |
r += htmltext('<h2 class="foldable">%s</h2>') % _('Backoffice Data') |
|
515 |
r += htmltext('<div class="dataview">') |
|
516 |
r += content |
|
517 |
r += htmltext('</div>') |
|
518 |
r += htmltext('</div>') |
|
519 |
return r.getvalue() |
|
499 | 520 | |
500 | 521 |
def status(self): |
501 | 522 |
object_key = 'formdata-%s-%s' % (self.formdef.url_name, self.filled.id) |
... | ... | |
545 | 566 |
break |
546 | 567 | |
547 | 568 |
r += self.receipt(always_include_user=True, folded=folded) |
569 |
r += self.backoffice_fields_section() |
|
548 | 570 | |
549 | 571 |
r += self.history() |
550 | 572 |
wcs/sql.py | ||
---|---|---|
378 | 378 |
cur.execute('''ALTER TABLE %s ADD COLUMN criticality_level integer NOT NULL DEFAULT(0)''' % table_name) |
379 | 379 | |
380 | 380 |
# add new fields |
381 |
for field in formdef.fields:
|
|
381 |
for field in formdef.get_all_fields():
|
|
382 | 382 |
assert field.id is not None |
383 | 383 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
384 | 384 |
if sql_type is None: |
... | ... | |
461 | 461 |
from admin.settings import UserFieldsFormDef |
462 | 462 |
formdef = UserFieldsFormDef() |
463 | 463 | |
464 |
for field in formdef.fields:
|
|
464 |
for field in formdef.get_fields():
|
|
465 | 465 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
466 | 466 |
if sql_type is None: |
467 | 467 |
continue |
... | ... | |
602 | 602 |
view_fields = get_view_fields(formdef) |
603 | 603 | |
604 | 604 |
column_names = {} |
605 |
for field in formdef.fields:
|
|
605 |
for field in formdef.get_all_fields():
|
|
606 | 606 |
field_key = 'f%s' % field.id |
607 | 607 |
if field.type in ('page', 'title', 'subtitle', 'comment'): |
608 | 608 |
continue |
... | ... | |
900 | 900 | |
901 | 901 |
def get_sql_dict_from_data(self, data, formdef): |
902 | 902 |
sql_dict = {} |
903 |
for field in formdef.fields:
|
|
903 |
for field in formdef.get_all_fields():
|
|
904 | 904 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
905 | 905 |
if sql_type is None: |
906 | 906 |
continue |
... | ... | |
932 | 932 |
i = len(cls._table_static_fields) |
933 | 933 |
if formdef.geolocations: |
934 | 934 |
i += len(formdef.geolocations.keys()) |
935 |
for field in formdef.fields:
|
|
935 |
for field in formdef.get_all_fields():
|
|
936 | 936 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
937 | 937 |
if sql_type is None: |
938 | 938 |
continue |
... | ... | |
1220 | 1220 |
fts_strings = [str(self.id)] |
1221 | 1221 |
if self.tracking_code: |
1222 | 1222 |
fts_strings.append(self.tracking_code) |
1223 |
for field in self._formdef.fields:
|
|
1223 |
for field in self._formdef.get_all_fields():
|
|
1224 | 1224 |
if not self.data.get(field.id): |
1225 | 1225 |
continue |
1226 | 1226 |
value = None |
... | ... | |
1275 | 1275 |
@classmethod |
1276 | 1276 |
def get_data_fields(cls): |
1277 | 1277 |
data_fields = ['geoloc_%s' % x for x in (cls._formdef.geolocations or {}).keys()] |
1278 |
for field in cls._formdef.fields:
|
|
1278 |
for field in cls._formdef.get_all_fields():
|
|
1279 | 1279 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
1280 | 1280 |
if sql_type is None: |
1281 | 1281 |
continue |
... | ... | |
1492 | 1492 |
@classmethod |
1493 | 1493 |
def get_data_fields(cls): |
1494 | 1494 |
data_fields = [] |
1495 |
for field in cls.get_formdef().fields:
|
|
1495 |
for field in cls.get_formdef().get_all_fields():
|
|
1496 | 1496 |
sql_type = SQL_TYPE_MAPPING.get(field.key, 'varchar') |
1497 | 1497 |
if sql_type is None: |
1498 | 1498 |
continue |
wcs/wf/set_backoffice_field.py | ||
---|---|---|
1 |
# w.c.s. - web application for online forms |
|
2 |
# Copyright (C) 2005-2016 Entr'ouvert |
|
3 |
# |
|
4 |
# This program is free software; you can redistribute it and/or modify |
|
5 |
# it under the terms of the GNU General Public License as published by |
|
6 |
# the Free Software Foundation; either version 2 of the License, or |
|
7 |
# (at your option) any later version. |
|
8 |
# |
|
9 |
# This program is distributed in the hope that it will be useful, |
|
10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 |
# GNU General Public License for more details. |
|
13 |
# |
|
14 |
# You should have received a copy of the GNU General Public License |
|
15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
|
16 | ||
17 |
from quixote import get_publisher |
|
18 | ||
19 |
from qommon import get_logger |
|
20 |
from qommon.form import SingleSelectWidget, ComputedExpressionWidget |
|
21 |
from wcs.workflows import WorkflowStatusItem, register_item_class |
|
22 | ||
23 |
class SetBackofficeFieldWorkflowStatusItem(WorkflowStatusItem): |
|
24 |
description = N_('Set Backoffice Field') |
|
25 |
key = 'set-backoffice-field' |
|
26 | ||
27 |
field_id = None |
|
28 |
field_content = None |
|
29 | ||
30 |
@classmethod |
|
31 |
def is_available(cls, workflow=None): |
|
32 |
return bool(workflow and getattr(workflow.backoffice_fields_formdef, 'fields', None)) |
|
33 | ||
34 |
def get_parameters(self): |
|
35 |
return ('field_id', 'field_content') |
|
36 | ||
37 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None): |
|
38 |
if 'field_id' in parameters: |
|
39 |
fields = getattr(self.parent.parent.backoffice_fields_formdef, 'fields', []) |
|
40 |
options = [(str(x.id), x.label) for x in fields] |
|
41 |
if not options: |
|
42 |
options = [('', '')] |
|
43 |
form.add(SingleSelectWidget, '%sfield_id' % prefix, |
|
44 |
title=_('Field'), value=str(self.field_id), |
|
45 |
required=True, options=options) |
|
46 |
if 'field_content' in parameters: |
|
47 |
form.add(ComputedExpressionWidget, '%sfield_content' % prefix, size=50, |
|
48 |
title=_('Content'), value=self.field_content) |
|
49 | ||
50 |
def perform(self, formdata): |
|
51 |
if not (self.field_id and self.field_content): |
|
52 |
return |
|
53 |
try: |
|
54 |
formdata.data['%s' % self.field_id] = self.compute( |
|
55 |
self.field_content, raises=True) |
|
56 |
formdata.store() |
|
57 |
except: |
|
58 |
get_publisher().notify_of_exception(sys.exc_info()) |
|
59 | ||
60 | ||
61 |
register_item_class(SetBackofficeFieldWorkflowStatusItem) |
wcs/workflows.py | ||
---|---|---|
246 | 246 |
self.workflow.store() |
247 | 247 | |
248 | 248 | |
249 |
class WorkflowBackofficeFieldsFormDef(FormDef): |
|
250 |
'''Class to handle workflow backoffice fields, it loads and saves from/to |
|
251 |
the workflow object 'backoffice_fields_formdef' attribute.''' |
|
252 | ||
253 |
def __init__(self, workflow): |
|
254 |
self.id = None |
|
255 |
self.name = workflow.name |
|
256 |
self.workflow = workflow |
|
257 |
if workflow.backoffice_fields_formdef and workflow.backoffice_fields_formdef.fields: |
|
258 |
self.fields = self.workflow.backoffice_fields_formdef.fields |
|
259 |
self.max_field_id = max([lax_int(x.id) for x in self.fields or []]) |
|
260 |
else: |
|
261 |
self.fields = [] |
|
262 | ||
263 |
def get_new_field_id(self): |
|
264 |
if self.max_field_id is None: |
|
265 |
field_id = 1 |
|
266 |
else: |
|
267 |
field_id = self.max_field_id + 1 |
|
268 |
self.max_field_id = field_id |
|
269 |
return 'bo%s' % field_id |
|
270 | ||
271 |
def store(self): |
|
272 |
self.workflow.backoffice_fields_formdef = self |
|
273 |
self.workflow.store() |
|
274 | ||
275 | ||
249 | 276 |
class Workflow(StorableObject): |
250 | 277 |
_names = 'workflows' |
251 | 278 |
name = None |
252 | 279 |
possible_status = None |
253 | 280 |
roles = None |
254 | 281 |
variables_formdef = None |
282 |
backoffice_fields_formdef = None |
|
255 | 283 |
global_actions = None |
256 | 284 |
criticality_levels = None |
257 | 285 | |
... | ... | |
283 | 311 |
self.store() |
284 | 312 | |
285 | 313 |
def store(self): |
286 |
must_update_views = False
|
|
314 |
must_update = False |
|
287 | 315 |
if self.id: |
288 | 316 |
old_self = self.get(self.id, ignore_errors=True, ignore_migration=True) |
289 | 317 |
if old_self: |
290 | 318 |
old_endpoints = set([x.id for x in old_self.get_endpoint_status()]) |
291 | 319 |
if old_endpoints != set([x.id for x in self.get_endpoint_status()]): |
292 |
must_update_views = True
|
|
320 |
must_update = True |
|
293 | 321 |
old_criticality_levels = len(old_self.criticality_levels or [0]) |
294 | 322 |
if old_criticality_levels != len(self.criticality_levels or [0]): |
295 |
must_update_views = True |
|
323 |
must_update = True |
|
324 |
try: |
|
325 |
old_backoffice_fields = old_self.backoffice_fields_formdef.fields |
|
326 |
except AttributeError: |
|
327 |
old_backoffice_fields = [] |
|
328 |
try: |
|
329 |
new_backoffice_fields = self.backoffice_fields_formdef.fields |
|
330 |
except AttributeError: |
|
331 |
new_backoffice_fields = [] |
|
332 |
if len(old_backoffice_fields) != len(new_backoffice_fields): |
|
333 |
must_update = True |
|
334 |
elif self.backoffice_fields_formdef: |
|
335 |
must_update = True |
|
296 | 336 | |
297 | 337 |
self.last_modification_time = time.localtime() |
298 | 338 |
if get_request() and get_request().user: |
... | ... | |
301 | 341 |
self.last_modification_user_id = None |
302 | 342 |
StorableObject.store(self) |
303 | 343 | |
304 |
# instruct all related formdefs to update their security rules, and |
|
305 |
# their views if endpoints have changed. |
|
344 |
# instruct all related formdefs to update. |
|
306 | 345 |
for form in FormDef.select(lambda x: x.workflow_id == self.id, ignore_migration=True): |
307 | 346 |
form.data_class().rebuild_security() |
308 |
if must_update_views:
|
|
309 |
form.rebuild_views()
|
|
347 |
if must_update: |
|
348 |
form.rebuild() |
|
310 | 349 | |
311 | 350 |
@classmethod |
312 | 351 |
def get(cls, id, ignore_errors=False, ignore_migration=False): |
... | ... | |
337 | 376 |
return status |
338 | 377 |
raise KeyError() |
339 | 378 | |
379 |
def get_backoffice_fields(self): |
|
380 |
if self.backoffice_fields_formdef: |
|
381 |
return self.backoffice_fields_formdef.fields or [] |
|
382 |
return [] |
|
383 | ||
340 | 384 |
def add_global_action(self, name, id=None): |
341 | 385 |
if [x for x in self.global_actions if x.name == name]: |
342 | 386 |
raise DuplicateGlobalActionNameError() |
... | ... | |
472 | 516 |
for field in self.variables_formdef.fields: |
473 | 517 |
fields.append(field.export_to_xml(charset=charset, include_id=include_id)) |
474 | 518 | |
519 |
if self.backoffice_fields_formdef: |
|
520 |
variables = ET.SubElement(root, 'backoffice-fields') |
|
521 |
formdef = ET.SubElement(variables, 'formdef') |
|
522 |
ET.SubElement(formdef, 'name').text = '-' # required by formdef xml import |
|
523 |
fields = ET.SubElement(formdef, 'fields') |
|
524 |
for field in self.backoffice_fields_formdef.fields: |
|
525 |
fields.append(field.export_to_xml(charset=charset, include_id=include_id)) |
|
526 | ||
475 | 527 |
return root |
476 | 528 | |
477 | 529 |
@classmethod |
... | ... | |
543 | 595 |
imported_formdef = FormDef.import_from_xml_tree(formdef, include_id=True) |
544 | 596 |
workflow.variables_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) |
545 | 597 |
workflow.variables_formdef.fields = imported_formdef.fields |
598 | ||
599 |
variables = tree.find('backoffice-fields') |
|
600 |
if variables is not None: |
|
601 |
formdef = variables.find('backoffice-fields') |
|
602 |
imported_formdef = FormDef.import_from_xml_tree(formdef, include_id=True) |
|
603 |
workflow.backoffice_fields_formdef = WorkflowVariablesFieldsFormDef(workflow=workflow) |
|
604 |
workflow.backoffice_fields_formdef.fields = imported_formdef.fields |
|
605 | ||
546 | 606 |
return workflow |
547 | 607 | |
548 | 608 |
def get_list_of_roles(self, include_logged_in_users=True): |
... | ... | |
2230 | 2290 |
import wf.resubmit |
2231 | 2291 |
import wf.criticality |
2232 | 2292 |
import wf.profile |
2293 |
import wf.set_backoffice_field |
|
2233 | 2294 | |
2234 | 2295 |
from wf.export_to_model import ExportToModel |
2235 |
- |