0001-workflows-allow-interactive-actions-in-global-action.patch
tests/backoffice_pages/test_all.py | ||
---|---|---|
846 | 846 |
assert 'session_user=admin' in content |
847 | 847 | |
848 | 848 | |
849 |
def test_backoffice_multi_actions_interactive(pub): |
|
850 |
create_superuser(pub) |
|
851 |
create_environment(pub) |
|
852 |
formdef = FormDef.get_by_urlname('form-title') |
|
853 | ||
854 |
app = login(get_app(pub)) |
|
855 |
resp = app.get('/backoffice/management/form-title/') |
|
856 |
assert 'id="multi-actions"' in resp.text # always there |
|
857 | ||
858 |
workflow = Workflow.get_default_workflow() |
|
859 |
workflow.id = '2' |
|
860 |
action = workflow.add_global_action('FOOBAR') |
|
861 | ||
862 |
form_action = action.add_action('form') |
|
863 |
form_action.varname = 'blah' |
|
864 |
form_action.formdef = WorkflowFormFieldsFormDef(item=form_action) |
|
865 |
form_action.formdef.fields.append( |
|
866 |
fields.StringField(id='1', label='Test', varname='test', type='string', required=True) |
|
867 |
) |
|
868 |
register_comment = action.add_action('register-comment') |
|
869 |
register_comment.comment = 'HELLO {{ form_workflow_form_blah_var_test }}' |
|
870 | ||
871 |
trigger = action.triggers[0] |
|
872 |
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar'] |
|
873 |
workflow.store() |
|
874 | ||
875 |
formdef.workflow_id = workflow.id |
|
876 |
formdef.store() |
|
877 | ||
878 |
resp = app.get('/backoffice/management/form-title/?limit=20') |
|
879 |
assert 'id="multi-actions"' in resp.text |
|
880 |
for checkbox in resp.forms[0].fields['select[]'][1:6]: |
|
881 |
checkbox.checked = True |
|
882 |
resp = resp.forms[0].submit('button-action-1') |
|
883 |
assert '/actions/' in resp.location |
|
884 |
resp = resp.follow() |
|
885 |
resp = resp.follow() # back to form listing |
|
886 |
assert 'Error: empty action' in resp.text |
|
887 | ||
888 |
form_action.by = trigger.roles |
|
889 |
workflow.store() |
|
890 | ||
891 |
resp = app.get('/backoffice/management/form-title/?limit=20') |
|
892 |
ids = [] |
|
893 |
for checkbox in resp.forms[0].fields['select[]'][1:6]: |
|
894 |
ids.append(checkbox._value) |
|
895 |
checkbox.checked = True |
|
896 | ||
897 |
resp = resp.forms[0].submit('button-action-1') |
|
898 |
assert '/actions/' in resp.location |
|
899 |
resp = resp.follow() |
|
900 |
assert '5 selected forms' in resp.text |
|
901 |
resp = resp.form.submit('submit') |
|
902 |
assert resp.pyquery('#form_error_fblah_1').text() == 'required field' |
|
903 |
resp.form['fblah_1'] = 'GLOBAL INTERACTIVE ACTION' |
|
904 |
resp = resp.form.submit('submit') |
|
905 | ||
906 |
assert '?job=' in resp.location |
|
907 |
resp = resp.follow() |
|
908 |
assert 'Executing task "FOOBAR" on forms' in resp.text |
|
909 |
assert '>completed<' in resp.text |
|
910 |
assert ( |
|
911 |
resp.pyquery.find('[data-redirect-auto]').attr['href'] |
|
912 |
== '/backoffice/management/form-title/?limit=20' |
|
913 |
) |
|
914 |
for id in ids: |
|
915 |
pub.substitutions.reset() |
|
916 |
pub.substitutions.feed(formdef.data_class().get(id)) |
|
917 |
context = pub.substitutions.get_context_variables(mode='lazy') |
|
918 |
assert context['form_number_raw'] == id |
|
919 |
assert context['form_workflow_form_blah_var_test'].get_value() == 'GLOBAL INTERACTIVE ACTION' |
|
920 | ||
921 | ||
849 | 922 |
def test_backoffice_map(pub): |
850 | 923 |
create_user(pub) |
851 | 924 |
create_environment(pub) |
... | ... | |
1072 | 1145 |
assert resp.text.count('WORKFLOW COMMENT') == 2 |
1073 | 1146 | |
1074 | 1147 | |
1148 |
def test_backoffice_global_interactive_action(pub): |
|
1149 |
create_user(pub) |
|
1150 | ||
1151 |
formdef = FormDef() |
|
1152 |
formdef.name = 'test global action' |
|
1153 |
formdef.fields = [] |
|
1154 | ||
1155 |
workflow = Workflow.get_default_workflow() |
|
1156 |
workflow.id = '2' |
|
1157 |
action = workflow.add_global_action('FOOBAR') |
|
1158 | ||
1159 |
display = action.add_action('displaymsg') |
|
1160 |
display.message = 'This is a message' |
|
1161 |
display.to = [] |
|
1162 | ||
1163 |
form_action = action.add_action('form') |
|
1164 |
form_action.varname = 'blah' |
|
1165 |
form_action.formdef = WorkflowFormFieldsFormDef(item=form_action) |
|
1166 |
form_action.formdef.fields.append( |
|
1167 |
fields.StringField(id='1', label='Test', varname='test', type='string', required=True) |
|
1168 |
) |
|
1169 |
register_comment = action.add_action('register-comment') |
|
1170 |
register_comment.comment = 'HELLO {{ form_workflow_form_blah_var_test }}' |
|
1171 |
trigger = action.triggers[0] |
|
1172 |
trigger.roles = [x.id for x in pub.role_class.select() if x.name == 'foobar'] |
|
1173 | ||
1174 |
workflow.store() |
|
1175 |
formdef.workflow_id = workflow.id |
|
1176 |
formdef.workflow_roles = {'_receiver': 1} |
|
1177 |
formdef.store() |
|
1178 | ||
1179 |
formdata = formdef.data_class()() |
|
1180 |
formdata.just_created() |
|
1181 |
formdata.store() |
|
1182 | ||
1183 |
app = login(get_app(pub)) |
|
1184 |
resp = app.get(formdata.get_url(backoffice=True)) |
|
1185 |
assert 'button-action-1' in resp.form.fields |
|
1186 |
resp = resp.form.submit('button-action-1') |
|
1187 |
resp = resp.follow() # -> error, empty action |
|
1188 |
resp = resp.follow() # -> back to form |
|
1189 |
assert 'Error: empty action' in resp.text |
|
1190 | ||
1191 |
form_action.by = trigger.roles |
|
1192 |
workflow.store() |
|
1193 | ||
1194 |
resp = app.get(formdata.get_url(backoffice=True)) |
|
1195 |
resp = resp.form.submit('button-action-1') |
|
1196 |
resp = resp.follow() |
|
1197 |
assert 'This is a message' in resp.text |
|
1198 |
resp = resp.form.submit('submit') |
|
1199 |
assert resp.pyquery('#form_error_fblah_1').text() == 'required field' |
|
1200 |
resp.form['fblah_1'] = 'GLOBAL INTERACTIVE ACTION' |
|
1201 |
resp = resp.form.submit('submit') |
|
1202 |
assert resp.location == formdata.get_url(backoffice=True) |
|
1203 |
resp = resp.follow() |
|
1204 | ||
1205 |
assert 'HELLO GLOBAL INTERACTIVE ACTION' in resp.text |
|
1206 | ||
1207 | ||
1075 | 1208 |
def test_backoffice_submission_context(pub): |
1076 | 1209 |
user = create_user(pub) |
1077 | 1210 |
create_environment(pub) |
tests/backoffice_pages/test_carddata.py | ||
---|---|---|
13 | 13 |
from wcs.categories import CardDefCategory |
14 | 14 |
from wcs.formdef import FormDef |
15 | 15 |
from wcs.qommon.http_request import HTTPRequest |
16 |
from wcs.wf.form import WorkflowFormFieldsFormDef |
|
16 | 17 |
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef |
17 | 18 | |
18 | 19 |
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login |
... | ... | |
1142 | 1143 |
assert 'Add another Child' not in resp |
1143 | 1144 |
assert resp.text.count('/backoffice/data/adult/add/?_popup=1') == 1 |
1144 | 1145 |
assert '/backoffice/data/child/add/?_popup=1' not in resp |
1146 | ||
1147 | ||
1148 |
def test_backoffice_card_global_interactive_action(pub): |
|
1149 |
user = create_user(pub) |
|
1150 | ||
1151 |
workflow = CardDef.get_default_workflow() |
|
1152 |
workflow.id = None |
|
1153 |
action = workflow.add_global_action('FOOBAR') |
|
1154 | ||
1155 |
display = action.add_action('displaymsg') |
|
1156 |
display.message = 'This is a message' |
|
1157 |
display.to = [] |
|
1158 | ||
1159 |
form_action = action.add_action('form') |
|
1160 |
form_action.varname = 'blah' |
|
1161 |
form_action.formdef = WorkflowFormFieldsFormDef(item=form_action) |
|
1162 |
form_action.formdef.fields.append( |
|
1163 |
fields.StringField(id='1', label='Test', varname='test', type='string', required=True) |
|
1164 |
) |
|
1165 |
register_comment = action.add_action('register-comment') |
|
1166 |
register_comment.comment = 'HELLO {{ form_workflow_form_blah_var_test }}' |
|
1167 |
trigger = action.triggers[0] |
|
1168 |
trigger.roles = [user.roles[0]] |
|
1169 | ||
1170 |
workflow.store() |
|
1171 | ||
1172 |
CardDef.wipe() |
|
1173 |
carddef = CardDef() |
|
1174 |
carddef.name = 'foo' |
|
1175 |
carddef.fields = [] |
|
1176 |
carddef.workflow_id = workflow.id |
|
1177 |
carddef.workflow_roles = {'_editor': user.roles[0]} |
|
1178 |
carddef.store() |
|
1179 | ||
1180 |
carddef.data_class().wipe() |
|
1181 |
carddata = carddef.data_class()() |
|
1182 |
carddata.data = {} |
|
1183 |
carddata.just_created() |
|
1184 |
carddata.store() |
|
1185 | ||
1186 |
app = login(get_app(pub)) |
|
1187 |
resp = app.get(carddata.get_url(backoffice=True)) |
|
1188 |
assert 'button-action-1' in resp.form.fields |
|
1189 |
resp = resp.form.submit('button-action-1') |
|
1190 |
resp = resp.follow() # -> error, empty action |
|
1191 |
resp = resp.follow() # -> back to form |
|
1192 |
assert 'Error: empty action' in resp.text |
|
1193 | ||
1194 |
form_action.by = trigger.roles |
|
1195 |
workflow.store() |
|
1196 | ||
1197 |
resp = app.get(carddata.get_url(backoffice=True)) |
|
1198 |
resp = resp.form.submit('button-action-1') |
|
1199 |
resp = resp.follow() |
|
1200 |
assert 'This is a message' in resp.text |
|
1201 |
resp = resp.form.submit('submit') |
|
1202 |
assert resp.pyquery('#form_error_fblah_1').text() == 'required field' |
|
1203 |
resp.form['fblah_1'] = 'GLOBAL INTERACTIVE ACTION' |
|
1204 |
resp = resp.form.submit('submit') |
|
1205 |
assert resp.location == carddata.get_url(backoffice=True) |
|
1206 |
resp = resp.follow() |
|
1207 | ||
1208 |
assert 'HELLO GLOBAL INTERACTIVE ACTION' in resp.text |
tests/form_pages/test_all.py | ||
---|---|---|
9752 | 9752 |
app = get_app(pub) |
9753 | 9753 |
resp = app.get('/test/go-to-backoffice') |
9754 | 9754 |
assert resp.location.endswith('/backoffice/forms/%s/' % formdef.id) |
9755 | ||
9756 | ||
9757 |
def test_global_interactive_action(pub): |
|
9758 |
user = create_user(pub) |
|
9759 | ||
9760 |
formdef = FormDef() |
|
9761 |
formdef.name = 'test global action' |
|
9762 |
formdef.fields = [] |
|
9763 | ||
9764 |
workflow = Workflow.get_default_workflow() |
|
9765 |
workflow.id = '2' |
|
9766 |
action = workflow.add_global_action('FOOBAR') |
|
9767 | ||
9768 |
display = action.add_action('displaymsg') |
|
9769 |
display.message = 'This is a message' |
|
9770 |
display.to = [] |
|
9771 | ||
9772 |
form_action = action.add_action('form') |
|
9773 |
form_action.varname = 'blah' |
|
9774 |
form_action.formdef = WorkflowFormFieldsFormDef(item=form_action) |
|
9775 |
form_action.formdef.fields.append( |
|
9776 |
fields.StringField(id='1', label='Test', varname='test', type='string', required=True) |
|
9777 |
) |
|
9778 |
register_comment = action.add_action('register-comment') |
|
9779 |
register_comment.comment = 'HELLO {{ form_workflow_form_blah_var_test }}' |
|
9780 |
trigger = action.triggers[0] |
|
9781 |
trigger.roles = ['_submitter'] |
|
9782 | ||
9783 |
workflow.store() |
|
9784 |
formdef.workflow_id = workflow.id |
|
9785 |
formdef.workflow_roles = {'_receiver': 1} |
|
9786 |
formdef.store() |
|
9787 | ||
9788 |
formdata = formdef.data_class()() |
|
9789 |
formdata.user_id = user.id |
|
9790 |
formdata.just_created() |
|
9791 |
formdata.perform_workflow() |
|
9792 |
formdata.store() |
|
9793 | ||
9794 |
app = login(get_app(pub), username='foo', password='foo') |
|
9795 |
resp = app.get(formdata.get_url(backoffice=False)) |
|
9796 |
assert 'button-action-1' in resp.form.fields |
|
9797 |
resp = resp.form.submit('button-action-1') |
|
9798 |
resp = resp.follow() # -> error, empty action |
|
9799 |
resp = resp.follow() # -> back to form |
|
9800 |
assert 'Error: empty action' in resp.text |
|
9801 | ||
9802 |
form_action.by = trigger.roles |
|
9803 |
workflow.store() |
|
9804 | ||
9805 |
resp = app.get(formdata.get_url(backoffice=False)) |
|
9806 |
resp = resp.form.submit('button-action-1') |
|
9807 |
resp = resp.follow() |
|
9808 |
assert 'This is a message' in resp.text |
|
9809 |
resp = resp.form.submit('submit') |
|
9810 |
assert resp.pyquery('#form_error_fblah_1').text() == 'required field' |
|
9811 |
resp.form['fblah_1'] = 'GLOBAL INTERACTIVE ACTION' |
|
9812 |
resp = resp.form.submit('submit') |
|
9813 |
assert resp.location == formdata.get_url(backoffice=False) |
|
9814 |
resp = resp.follow() |
|
9815 | ||
9816 |
assert 'HELLO GLOBAL INTERACTIVE ACTION' in resp.text |
tests/workflow/test_all.py | ||
---|---|---|
3025 | 3025 |
display_message.parent = st1 |
3026 | 3026 | |
3027 | 3027 |
display_message.message = 'test' |
3028 |
assert display_message.get_message(formdata) == 'test'
|
|
3028 |
assert display_message.get_message(formdata) == '<p>test</p>'
|
|
3029 | 3029 | |
3030 | 3030 |
display_message.message = '{{ number }}' |
3031 |
assert display_message.get_message(formdata) == str(formdata.id)
|
|
3031 |
assert display_message.get_message(formdata) == '<p>%s</p>' % formdata.id
|
|
3032 | 3032 | |
3033 | 3033 |
display_message.message = '[number]' |
3034 |
assert display_message.get_message(formdata) == str(formdata.id)
|
|
3034 |
assert display_message.get_message(formdata) == '<p>%s</p>' % formdata.id
|
|
3035 | 3035 | |
3036 | 3036 |
display_message.message = '{{ bar }}' |
3037 |
assert display_message.get_message(formdata) == 'Foobar'
|
|
3037 |
assert display_message.get_message(formdata) == '<p>Foobar</p>'
|
|
3038 | 3038 | |
3039 | 3039 |
display_message.message = '[bar]' |
3040 |
assert display_message.get_message(formdata) == 'Foobar'
|
|
3040 |
assert display_message.get_message(formdata) == '<p>Foobar</p>'
|
|
3041 | 3041 | |
3042 | 3042 |
# makes sure the string is correctly escaped for HTML |
3043 | 3043 |
display_message.message = '{{ foo }}' |
3044 |
assert display_message.get_message(formdata) == '1 < 3'
|
|
3044 |
assert display_message.get_message(formdata) == '<p>1 < 3</p>'
|
|
3045 | 3045 |
display_message.message = '[foo]' |
3046 |
assert display_message.get_message(formdata) == '1 < 3'
|
|
3046 |
assert display_message.get_message(formdata) == '<p>1 < 3</p>'
|
|
3047 | 3047 | |
3048 | 3048 | |
3049 | 3049 |
def test_workflow_display_message_to(pub): |
... | ... | |
3072 | 3072 | |
3073 | 3073 |
display_message.message = 'all' |
3074 | 3074 |
display_message.to = None |
3075 |
assert display_message.get_message(formdata) == 'all'
|
|
3076 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['all']
|
|
3075 |
assert display_message.get_message(formdata) == '<p>all</p>'
|
|
3076 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>all</p>']
|
|
3077 | 3077 | |
3078 | 3078 |
display_message.message = 'to-role' |
3079 | 3079 |
display_message.to = [role.id] |
... | ... | |
3086 | 3086 |
assert display_message.get_message(formdata) == '' |
3087 | 3087 |
assert formdata.get_workflow_messages(user=pub._request._user) == [] |
3088 | 3088 |
user.roles = [role.id] |
3089 |
assert display_message.get_message(formdata) == 'to-role'
|
|
3090 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['to-role']
|
|
3089 |
assert display_message.get_message(formdata) == '<p>to-role</p>'
|
|
3090 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>to-role</p>']
|
|
3091 | 3091 | |
3092 | 3092 |
user.roles = [] |
3093 | 3093 |
display_message.message = 'to-submitter' |
... | ... | |
3095 | 3095 |
assert display_message.get_message(formdata) == '' |
3096 | 3096 |
assert formdata.get_workflow_messages(user=pub._request._user) == [] |
3097 | 3097 |
formdata.user_id = user.id |
3098 |
assert display_message.get_message(formdata) == 'to-submitter'
|
|
3099 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['to-submitter']
|
|
3098 |
assert display_message.get_message(formdata) == '<p>to-submitter</p>'
|
|
3099 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>to-submitter</p>']
|
|
3100 | 3100 | |
3101 | 3101 |
display_message.message = 'to-role-or-submitter' |
3102 | 3102 |
display_message.to = [role.id, '_submitter'] |
3103 |
assert display_message.get_message(formdata) == 'to-role-or-submitter'
|
|
3104 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['to-role-or-submitter']
|
|
3103 |
assert display_message.get_message(formdata) == '<p>to-role-or-submitter</p>'
|
|
3104 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>to-role-or-submitter</p>']
|
|
3105 | 3105 |
formdata.user_id = None |
3106 | 3106 |
assert display_message.get_message(formdata) == '' |
3107 | 3107 |
assert formdata.get_workflow_messages(user=pub._request._user) == [] |
3108 | 3108 |
user.roles = [role.id] |
3109 |
assert display_message.get_message(formdata) == 'to-role-or-submitter'
|
|
3110 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['to-role-or-submitter']
|
|
3109 |
assert display_message.get_message(formdata) == '<p>to-role-or-submitter</p>'
|
|
3110 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>to-role-or-submitter</p>']
|
|
3111 | 3111 |
formdata.user_id = user.id |
3112 |
assert display_message.get_message(formdata) == 'to-role-or-submitter'
|
|
3113 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['to-role-or-submitter']
|
|
3112 |
assert display_message.get_message(formdata) == '<p>to-role-or-submitter</p>'
|
|
3113 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>to-role-or-submitter</p>']
|
|
3114 | 3114 | |
3115 | 3115 |
display_message.to = [role2.id] |
3116 | 3116 |
assert display_message.get_message(formdata) == '' |
... | ... | |
3120 | 3120 |
display_message2 = st1.add_action('displaymsg') |
3121 | 3121 |
display_message2.message = 'd2' |
3122 | 3122 |
display_message2.to = [role.id, '_submitter'] |
3123 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['d2']
|
|
3123 |
assert formdata.get_workflow_messages(user=pub._request._user) == ['<p>d2</p>']
|
|
3124 | 3124 |
user.roles = [role.id, role2.id] |
3125 |
assert 'd1' in formdata.get_workflow_messages(user=pub._request._user)
|
|
3126 |
assert 'd2' in formdata.get_workflow_messages(user=pub._request._user)
|
|
3125 |
assert '<p>d1</p>' in formdata.get_workflow_messages(user=pub._request._user)
|
|
3126 |
assert '<p>d2</p>' in formdata.get_workflow_messages(user=pub._request._user)
|
|
3127 | 3127 | |
3128 | 3128 | |
3129 | 3129 |
def test_workflow_display_message_line_details(pub): |
wcs/admin/workflows.py | ||
---|---|---|
702 | 702 |
available_items.sort(key=lambda x: misc.simplify(x.description)) |
703 | 703 | |
704 | 704 |
for category, category_label in categories: |
705 |
options = [(x.key, x.description) for x in available_items if x.category == category] |
|
705 |
options = [ |
|
706 |
(x.key, x(parent=self.status).description) for x in available_items if x.category == category |
|
707 |
] |
|
706 | 708 |
form.add( |
707 | 709 |
SingleSelectWidget, |
708 | 710 |
'action-%s' % category, |
wcs/backoffice/data_management.py | ||
---|---|---|
114 | 114 |
'map', |
115 | 115 |
'geojson', |
116 | 116 |
'add', |
117 |
'actions', |
|
117 | 118 |
('export-spreadsheet', 'export_spreadsheet'), |
118 | 119 |
('save-view', 'save_view'), |
119 | 120 |
('delete-view', 'delete_view'), |
wcs/backoffice/management.py | ||
---|---|---|
764 | 764 |
'export', |
765 | 765 |
'map', |
766 | 766 |
'geojson', |
767 |
'actions', |
|
767 | 768 |
('export-spreadsheet', 'export_spreadsheet'), |
768 | 769 |
('filter-options', 'filter_options'), |
769 | 770 |
('save-view', 'save_view'), |
... | ... | |
795 | 796 |
if update_breadcrumbs: |
796 | 797 |
get_response().breadcrumb.append((view.get_url_slug() + '/', view.title)) |
797 | 798 |
self.set_default_view() |
799 |
from wcs.forms.actions import ActionsDirectory |
|
800 | ||
801 |
self.actions = ActionsDirectory() |
|
798 | 802 | |
799 | 803 |
def set_default_view(self): |
800 | 804 |
if not get_request(): |
... | ... | |
2215 | 2219 |
'receipt_time', [Contains('id', [int(x) for x in item_ids])] |
2216 | 2220 |
) |
2217 | 2221 | |
2222 |
if action['action'].is_interactive(): |
|
2223 |
return redirect( |
|
2224 |
action['action'].get_global_interactive_form_url(formdef=self.formdef, ids=item_ids) |
|
2225 |
) |
|
2226 | ||
2218 | 2227 |
job = get_response().add_after_job( |
2219 | 2228 |
MassActionAfterJob( |
2220 | 2229 |
label=_('Executing task "%s" on forms') % action['action'].name, |
wcs/carddef.py | ||
---|---|---|
26 | 26 |
from wcs.categories import CardDefCategory |
27 | 27 |
from wcs.formdef import FormDef, FormDefDoesNotExist, get_formdefs_of_all_kinds |
28 | 28 | |
29 |
from .qommon import _, force_text, misc |
|
29 |
from .qommon import _, force_text, misc, pgettext_lazy
|
|
30 | 30 |
from .qommon.storage import ElementEqual, ElementILike, Equal, Null, StrictNotEqual |
31 | 31 | |
32 | 32 |
if not hasattr(types, 'ClassType'): |
... | ... | |
46 | 46 |
xml_root_node = 'carddef' |
47 | 47 |
verbose_name = _('Card model') |
48 | 48 |
verbose_name_plural = _('Card models') |
49 |
item_name = pgettext_lazy('item', 'card') |
|
50 |
item_name_plural = pgettext_lazy('item', 'cards') |
|
49 | 51 | |
50 | 52 |
confirmation = False |
51 | 53 |
wcs/formdata.py | ||
---|---|---|
672 | 672 |
wf_status = self.get_visible_status(user=user) |
673 | 673 |
if not wf_status: |
674 | 674 |
return [] |
675 |
messages = [] |
|
676 |
for item in wf_status.items: |
|
677 |
if not item.check_condition(self): |
|
678 |
continue |
|
679 |
if hasattr(item, 'get_message'): |
|
680 |
message = item.get_message(self, position=position) |
|
681 |
if message: |
|
682 |
messages.append(message) |
|
683 |
return messages |
|
675 |
return wf_status.get_messages(formdata=self, position=position) |
|
684 | 676 | |
685 | 677 |
def get_status(self, status=None): |
686 | 678 |
if not status: |
wcs/formdef.py | ||
---|---|---|
38 | 38 |
from . import data_sources, fields |
39 | 39 |
from .categories import Category |
40 | 40 |
from .formdata import FormData |
41 |
from .qommon import PICKLE_KWARGS, _, force_str, get_cfg |
|
41 |
from .qommon import PICKLE_KWARGS, _, force_str, get_cfg, pgettext_lazy
|
|
42 | 42 |
from .qommon.admin.emails import EmailsDirectory |
43 | 43 |
from .qommon.cron import CronJob |
44 | 44 |
from .qommon.form import Form, HtmlWidget, UploadedFile |
... | ... | |
126 | 126 |
backoffice_section = 'forms' |
127 | 127 |
verbose_name = _('Form') |
128 | 128 |
verbose_name_plural = _('Forms') |
129 |
item_name = pgettext_lazy('item', 'form') |
|
130 |
item_name_plural = pgettext_lazy('item', 'forms') |
|
129 | 131 | |
130 | 132 |
name = None |
131 | 133 |
description = None |
wcs/forms/actions.py | ||
---|---|---|
14 | 14 |
# You should have received a copy of the GNU General Public License |
15 | 15 |
# along with this program; if not, see <http://www.gnu.org/licenses/>. |
16 | 16 | |
17 |
from quixote import get_publisher, redirect |
|
17 |
from quixote import get_publisher, get_request, get_response, get_session, redirect
|
|
18 | 18 |
from quixote.directory import Directory |
19 | 19 |
from quixote.errors import PublishError |
20 | 20 | |
21 | 21 |
from wcs.carddef import CardDef |
22 | 22 |
from wcs.formdef import FormDef |
23 | 23 |
from wcs.forms.common import FormTemplateMixin |
24 |
from wcs.qommon import _, errors, misc, template |
|
25 |
from wcs.qommon.afterjobs import AfterJob |
|
26 |
from wcs.qommon.backoffice.menu import html_top as backoffice_html_top |
|
27 |
from wcs.qommon.form import Form |
|
28 |
from wcs.qommon.http_request import HTTPRequest |
|
24 | 29 |
from wcs.wf.jump import jump_and_perform |
25 | ||
26 |
from ..qommon import _, errors, misc, template |
|
27 |
from ..qommon.form import Form |
|
30 |
from wcs.workflows import perform_items |
|
28 | 31 | |
29 | 32 | |
30 | 33 |
class MissingOrExpiredToken(PublishError): |
... | ... | |
45 | 48 |
token = get_publisher().token_class.get(component) |
46 | 49 |
except KeyError: |
47 | 50 |
raise MissingOrExpiredToken() |
48 |
if token.type != 'action': |
|
49 |
raise errors.TraversalError() |
|
50 |
return ActionDirectory(token) |
|
51 |
if token.type == 'action': |
|
52 |
return ActionDirectory(token) |
|
53 |
if token.type == 'global-interactive-action': |
|
54 |
return GlobalInteractiveActionDirectory(token) |
|
55 |
raise errors.TraversalError() |
|
51 | 56 | |
52 | 57 | |
53 | 58 |
class ActionDirectory(Directory, FormTemplateMixin): |
... | ... | |
108 | 113 |
return template.QommonTemplateResponse( |
109 | 114 |
templates=list(self.get_formdef_template_variants(self.templates)), context=context |
110 | 115 |
) |
116 | ||
117 | ||
118 |
class GlobalInteractiveActionDirectory(Directory, FormTemplateMixin): |
|
119 |
_q_exports = [''] |
|
120 | ||
121 |
def __init__(self, token): |
|
122 |
self.token = token |
|
123 |
formdef_type = self.token.context.get('form_type', 'formdef') |
|
124 |
if formdef_type == 'carddef': |
|
125 |
formdef_class = CardDef |
|
126 |
elif formdef_type == 'formdef': |
|
127 |
formdef_class = FormDef |
|
128 |
else: |
|
129 |
raise errors.TraversalError() |
|
130 | ||
131 |
self.formdef = formdef_class.get_by_urlname(self.token.context['form_slug']) |
|
132 | ||
133 |
try: |
|
134 |
self.formdata = self.formdef.data_class().get(self.token.context['form_ids'][0]) |
|
135 |
except KeyError: |
|
136 |
raise MissingFormdata() |
|
137 | ||
138 |
self.action = None |
|
139 |
for action in self.formdef.workflow.global_actions or []: |
|
140 |
if action.id == self.token.context['action_id']: |
|
141 |
self.action = action |
|
142 |
break |
|
143 |
else: |
|
144 |
raise MissingOrExpiredToken() |
|
145 | ||
146 |
def _q_index(self): |
|
147 |
if get_request().is_in_backoffice(): |
|
148 |
if isinstance(self.formdef, CardDef): |
|
149 |
section = 'data_management' |
|
150 |
else: |
|
151 |
section = 'management' |
|
152 |
get_response().breadcrumb.append(('', self.action.name)) |
|
153 |
backoffice_html_top(section, title=self.formdef.name) |
|
154 |
template_name = 'wcs/backoffice/global-interactive-action.html' |
|
155 |
else: |
|
156 |
template.html_top(title=self.formdef.name) |
|
157 |
template_name = 'wcs/global-interactive-action.html' |
|
158 |
form = self.action.get_action_form(self.formdata, user=get_request().user) |
|
159 |
if not form: |
|
160 |
# empty form, nothing to do |
|
161 |
get_session().message = ('error', _('Error: empty action')) |
|
162 |
return redirect(self.token.context['return_url']) |
|
163 |
if not form.is_submitted() or form.has_errors(): |
|
164 |
messages = self.action.get_messages() |
|
165 |
context = { |
|
166 |
'html_form': form, |
|
167 |
'action': self.action, |
|
168 |
'ids': self.token.context['form_ids'], |
|
169 |
'formdata': self.formdata, |
|
170 |
'workflow_messages': messages, |
|
171 |
} |
|
172 |
return template.QommonTemplateResponse(templates=[template_name], context=context) |
|
173 | ||
174 |
if len(self.token.context['form_ids']) > 1: |
|
175 |
# mass action |
|
176 |
job = get_response().add_after_job( |
|
177 |
GlobalInteractiveMassActionAfterJob( |
|
178 |
label=_('Executing task "%s" on forms') % self.action.name, |
|
179 |
formdef=self.formdef, |
|
180 |
request_form=get_request().form, |
|
181 |
user_id=get_request().user.id, |
|
182 |
action_id=self.action.id, |
|
183 |
item_ids=self.token.context['form_ids'], |
|
184 |
return_url=self.token.context['return_url'], |
|
185 |
) |
|
186 |
) |
|
187 |
job.store() |
|
188 |
self.token.remove_self() |
|
189 |
return redirect(job.get_processing_url()) |
|
190 | ||
191 |
get_publisher().substitutions.reset() |
|
192 |
get_publisher().substitutions.feed(get_publisher()) |
|
193 |
get_publisher().substitutions.feed(self.formdata) |
|
194 |
status = self.formdata.status |
|
195 |
url = self.action.handle_form(form, self.formdata, user=get_request().user) |
|
196 |
if self.formdata.status == status: |
|
197 |
# if there's no status change run non-interactive items from global ction |
|
198 |
url = ( |
|
199 |
perform_items( |
|
200 |
self.action.items, self.formdata, event=('global-interactive-action', self.action.id) |
|
201 |
) |
|
202 |
or url |
|
203 |
) |
|
204 |
if not url: |
|
205 |
url = self.formdata.get_url(backoffice=bool(get_request().is_in_backoffice())) |
|
206 |
self.token.remove_self() |
|
207 |
return redirect(url) |
|
208 | ||
209 | ||
210 |
class GlobalInteractiveMassActionAfterJob(AfterJob): |
|
211 |
def __init__(self, formdef, **kwargs): |
|
212 |
super().__init__(formdef_class=formdef.__class__, formdef_id=formdef.id, **kwargs) |
|
213 | ||
214 |
def execute(self): |
|
215 |
self.total_count = len(self.kwargs['item_ids']) |
|
216 | ||
217 |
# restore request form |
|
218 |
publisher = get_publisher() |
|
219 |
req = HTTPRequest(None, {'SERVER_NAME': publisher.tenant.hostname, 'SCRIPT_NAME': ''}) |
|
220 |
req.form = self.kwargs['request_form'] |
|
221 | ||
222 |
formdef = self.kwargs['formdef_class'].get(self.kwargs['formdef_id']) |
|
223 |
data_class = formdef.data_class() |
|
224 | ||
225 |
for action in formdef.workflow.global_actions or []: |
|
226 |
if action.id == self.kwargs['action_id']: |
|
227 |
break |
|
228 |
else: |
|
229 |
# maybe action got removed from workflow? |
|
230 |
return |
|
231 | ||
232 |
user = publisher.user_class.get(self.kwargs['user_id']) |
|
233 |
for item_id in self.kwargs['item_ids']: |
|
234 |
publisher._set_request(req) |
|
235 |
publisher.substitutions.reset() |
|
236 |
publisher.substitutions.feed(get_publisher()) |
|
237 |
formdata = data_class.get(item_id) |
|
238 |
publisher.substitutions.feed(formdata) |
|
239 | ||
240 |
status = formdata.status |
|
241 |
form = action.get_action_form(formdata, user=user) |
|
242 |
form.method = 'get' |
|
243 |
action.handle_form(form, formdata, user=user) |
|
244 |
# reset request to avoid emails being created as afterjobs |
|
245 |
publisher._set_request(None) |
|
246 |
if formdata.status == status: |
|
247 |
# if there's no status change run non-interactive items from global ction |
|
248 |
perform_items(action.items, formdata, event=('global-interactive-action', action.id)) |
|
249 |
self.increment_count() |
|
250 | ||
251 |
def done_action_url(self): |
|
252 |
return self.kwargs['return_url'] |
|
253 | ||
254 |
def done_action_label(self): |
|
255 |
return _('Back to Listing') |
|
256 | ||
257 |
def done_button_attributes(self): |
|
258 |
return {'data-redirect-auto': 'true'} |
wcs/forms/common.py | ||
---|---|---|
226 | 226 |
else: |
227 | 227 |
r += htmltext('<div class="workflow-messages %s">' % position) |
228 | 228 |
for workflow_message in workflow_messages: |
229 |
if workflow_message.startswith('<'): |
|
230 |
r += htmltext(workflow_message) |
|
231 |
else: |
|
232 |
r += htmltext('<p>%s</p>' % workflow_message) |
|
229 |
r += htmltext(workflow_message) |
|
233 | 230 |
r += htmltext('</div>') |
234 | 231 |
return r.getvalue() |
235 | 232 |
return '' |
wcs/templates/wcs/backoffice/global-interactive-action.html | ||
---|---|---|
1 |
{% extends "wcs/backoffice/base.html" %} |
|
2 |
{% load i18n %} |
|
3 | ||
4 |
{% block appbar-title %}{{ action.name }} - |
|
5 |
{% if ids|length == 1 %} |
|
6 |
{{ formdata.formdef.item_name }} - {{ formdata.id_display }} |
|
7 |
{% else %} |
|
8 |
{% blocktrans with len=ids|length item_name=formdata.formdef.item_name_plural %}{{ len }} selected {{ item_name }}{% endblocktrans %} |
|
9 |
{% endif %} |
|
10 |
{% endblock %} |
|
11 | ||
12 |
{% block content %} |
|
13 |
{% include "wcs/includes/global-interactive-action.html" %} |
|
14 |
{% endblock %} |
wcs/templates/wcs/global-interactive-action.html | ||
---|---|---|
1 |
{% extends template_base %} |
|
2 | ||
3 |
{% block body %} |
|
4 |
{% include "wcs/includes/global-interactive-action.html" %} |
|
5 |
{% endblock %} |
wcs/templates/wcs/includes/global-interactive-action.html | ||
---|---|---|
1 |
{% if workflow_messages %} |
|
2 |
<div class="workflow-messages"> |
|
3 |
{% for message in workflow_messages %}{{ message|safe }}{% endfor %} |
|
4 |
</div> |
|
5 |
{% endif %} |
|
6 |
{{ html_form.render|safe }} |
wcs/wf/attachment.py | ||
---|---|---|
92 | 92 |
category = 'interaction' |
93 | 93 |
endpoint = False |
94 | 94 |
waitpoint = True |
95 |
ok_in_global_action = False
|
|
95 |
ok_in_global_action = True
|
|
96 | 96 | |
97 | 97 |
title = None |
98 | 98 |
display_title = True |
... | ... | |
128 | 128 |
else: |
129 | 129 |
return _('not completed') |
130 | 130 | |
131 |
def is_interactive(self): |
|
132 |
return True |
|
133 | ||
131 | 134 |
def fill_form(self, form, formdata, user, **kwargs): |
132 | 135 |
if self.display_title: |
133 | 136 |
title = self.title or _('Upload File') |
wcs/wf/choice.py | ||
---|---|---|
25 | 25 |
WidgetList, |
26 | 26 |
WysiwygTextWidget, |
27 | 27 |
) |
28 |
from wcs.workflows import WorkflowStatus, WorkflowStatusJumpItem, register_item_class |
|
28 |
from wcs.workflows import WorkflowGlobalAction, WorkflowStatus, WorkflowStatusJumpItem, register_item_class
|
|
29 | 29 | |
30 | 30 | |
31 | 31 |
class ChoiceWorkflowStatusItem(WorkflowStatusJumpItem): |
32 |
description = _('Manual Jump') |
|
33 | 32 |
key = 'choice' |
34 | 33 |
endpoint = False |
35 | 34 |
waitpoint = True |
36 |
ok_in_global_action = False
|
|
35 |
ok_in_global_action = True
|
|
37 | 36 | |
38 | 37 |
label = None |
39 | 38 |
identifier = None |
... | ... | |
42 | 41 |
require_confirmation = False |
43 | 42 |
ignore_form_errors = False |
44 | 43 | |
44 |
@property |
|
45 |
def description(self): |
|
46 |
if isinstance(self.parent, WorkflowGlobalAction): |
|
47 |
return _('Manual Jump (interactive)') |
|
48 |
else: |
|
49 |
return _('Manual Jump') |
|
50 | ||
45 | 51 |
def get_label(self): |
46 | 52 |
expression = self.get_expression(self.label, allow_python=False, allow_ezt=False) |
47 | 53 |
if expression['type'] == 'text': |
... | ... | |
83 | 89 |
if self.get_expression(self.label, allow_python=False, allow_ezt=False)['type'] != 'text': |
84 | 90 |
yield self.label |
85 | 91 | |
92 |
def is_interactive(self): |
|
93 |
return True |
|
94 | ||
86 | 95 |
def fill_form(self, form, formdata, user, **kwargs): |
87 | 96 |
label = self.compute(self.label, allow_python=False, allow_ezt=False) |
88 | 97 |
if not label: |
wcs/wf/comment.py | ||
---|---|---|
52 | 52 |
category = 'interaction' |
53 | 53 |
endpoint = False |
54 | 54 |
waitpoint = True |
55 |
ok_in_global_action = False
|
|
55 |
ok_in_global_action = True
|
|
56 | 56 | |
57 | 57 |
required = False |
58 | 58 |
varname = None |
... | ... | |
68 | 68 |
else: |
69 | 69 |
return _('not completed') |
70 | 70 | |
71 |
def is_interactive(self): |
|
72 |
return True |
|
73 | ||
71 | 74 |
def fill_form(self, form, formdata, user, **kwargs): |
72 | 75 |
if 'comment' not in [x.name for x in form.widgets]: |
73 | 76 |
if self.label is None: |
wcs/wf/display_message.py | ||
---|---|---|
22 | 22 |
from wcs.qommon import _, ezt, misc |
23 | 23 |
from wcs.qommon.form import ComputedExpressionWidget, SingleSelectWidget, TextWidget, WidgetListOfRoles |
24 | 24 |
from wcs.qommon.template import Template |
25 |
from wcs.workflows import WorkflowStatusItem, register_item_class |
|
25 |
from wcs.workflows import WorkflowGlobalAction, WorkflowStatusItem, register_item_class
|
|
26 | 26 | |
27 | 27 | |
28 | 28 |
class DisplayMessageWorkflowStatusItem(WorkflowStatusItem): |
... | ... | |
30 | 30 |
key = 'displaymsg' |
31 | 31 |
category = 'interaction' |
32 | 32 |
support_substitution_variables = True |
33 |
ok_in_global_action = False
|
|
33 |
ok_in_global_action = True
|
|
34 | 34 | |
35 | 35 |
to = None |
36 | 36 |
position = 'top' |
... | ... | |
38 | 38 |
message = None |
39 | 39 | |
40 | 40 |
def get_line_details(self): |
41 |
in_global_action = isinstance(self.parent, WorkflowGlobalAction) |
|
41 | 42 |
parts = [] |
42 |
if self.position == 'top': |
|
43 |
if in_global_action: |
|
44 |
pass |
|
45 |
elif self.position == 'top': |
|
43 | 46 |
parts.append(_('top of page')) |
44 | 47 |
elif self.position == 'bottom': |
45 | 48 |
parts.append(_('bottom of page')) |
... | ... | |
53 | 56 |
yield from super().get_computed_strings() |
54 | 57 |
yield self.message |
55 | 58 | |
56 |
def get_message(self, filled, position='top'):
|
|
57 |
if not (self.message and self.position == position and filled.is_for_current_user(self.to)):
|
|
59 |
def get_message(self, formdata, position='top'):
|
|
60 |
if not self.message:
|
|
58 | 61 |
return '' |
62 |
if formdata and not formdata.is_for_current_user(self.to): |
|
63 |
return '' |
|
64 | ||
65 |
in_global_action = isinstance(self.parent, WorkflowGlobalAction) |
|
66 |
if self.position != position and not in_global_action: |
|
67 |
return |
|
59 | 68 | |
60 |
dict = copy.copy(get_publisher().substitutions.get_context_variables('lazy')) |
|
61 |
dict['date'] = misc.localstrftime(filled.receipt_time) |
|
62 |
dict['number'] = filled.id |
|
63 |
handling_role = filled.get_handling_role() |
|
64 |
if handling_role and handling_role.details: |
|
65 |
dict['receiver'] = handling_role.details.replace('\n', '<br />') |
|
69 |
if formdata: |
|
70 |
ctx = copy.copy(get_publisher().substitutions.get_context_variables('lazy')) |
|
71 |
ctx['date'] = misc.localstrftime(formdata.receipt_time) |
|
72 |
ctx['number'] = formdata.id |
|
73 |
handling_role = formdata.get_handling_role() |
|
74 |
if handling_role and handling_role.details: |
|
75 |
ctx['receiver'] = handling_role.details.replace('\n', '<br />') |
|
76 |
else: |
|
77 |
ctx = get_publisher().substitutions.get_context_variables('lazy') |
|
66 | 78 | |
67 | 79 |
message = self.message |
68 | 80 |
if self.level: |
69 | 81 |
message = '<div class="%snotice">%s</div>' % (self.level, message) |
82 |
elif not message.startswith('<'): |
|
83 |
message = '<p>%s</p>' % message |
|
70 | 84 | |
71 | 85 |
try: |
72 |
return Template(message, ezt_format=ezt.FORMAT_HTML).render(dict)
|
|
86 |
return Template(message, ezt_format=ezt.FORMAT_HTML).render(ctx)
|
|
73 | 87 |
except Exception as e: |
74 | 88 |
get_publisher().record_error( |
75 | 89 |
error_summary=_('Error in template of workflow message (%s)') % e, exception=e, notify=True |
... | ... | |
78 | 92 | |
79 | 93 |
def add_parameters_widgets(self, form, parameters, prefix='', formdef=None, **kwargs): |
80 | 94 |
super().add_parameters_widgets(form, parameters, prefix=prefix, formdef=formdef, **kwargs) |
95 |
in_global_action = isinstance(self.parent, WorkflowGlobalAction) |
|
81 | 96 |
if 'message' in parameters: |
82 | 97 |
form.add( |
83 | 98 |
TextWidget, |
... | ... | |
102 | 117 |
('error', _('Error')), |
103 | 118 |
], |
104 | 119 |
) |
105 |
if 'position' in parameters: |
|
120 |
if 'position' in parameters and not in_global_action:
|
|
106 | 121 |
form.add( |
107 | 122 |
SingleSelectWidget, |
108 | 123 |
'%sposition' % prefix, |
wcs/wf/export_to_model.py | ||
---|---|---|
263 | 263 |
else: |
264 | 264 |
return _('no model set') |
265 | 265 | |
266 |
def is_interactive(self): |
|
267 |
return bool(self.method == 'interactive') |
|
268 | ||
266 | 269 |
def fill_form(self, form, formdata, user, **kwargs): |
267 | 270 |
if self.method != 'interactive': |
268 | 271 |
return |
wcs/wf/form.py | ||
---|---|---|
112 | 112 |
description = _('Form') |
113 | 113 |
key = 'form' |
114 | 114 |
category = 'interaction' |
115 |
ok_in_global_action = False
|
|
115 |
ok_in_global_action = True
|
|
116 | 116 |
endpoint = False |
117 | 117 |
waitpoint = True |
118 | 118 | |
... | ... | |
251 | 251 |
# already prefixed |
252 | 252 |
pass |
253 | 253 | |
254 |
def is_interactive(self): |
|
255 |
return True |
|
256 | ||
254 | 257 |
def fill_form(self, form, formdata, user, displayed_fields=None, **kwargs): |
255 | 258 |
if not self.formdef: |
256 | 259 |
return |
wcs/workflows.py | ||
---|---|---|
414 | 414 |
'global-action': _('Global action'), |
415 | 415 |
'global-action-timeout': _('Global action timeout'), |
416 | 416 |
'global-api-trigger': _('API Trigger'), |
417 |
'global-interactive-action': _('Global action (interactive)'), |
|
417 | 418 |
'global-external-workflow': _('Trigger by external workflow'), |
418 | 419 |
'json-import-created': _('Created (by JSON import)'), |
419 | 420 |
'timeout-jump': _('Timeout jump'), |
... | ... | |
1730 | 1731 |
for action in self.items or []: |
1731 | 1732 |
yield from action.get_dependencies() |
1732 | 1733 | |
1734 |
def get_action_form(self, filled, user, displayed_fields=None): |
|
1735 |
form = Form(enctype='multipart/form-data', use_tokens=False) |
|
1736 |
form.attrs['id'] = 'wf-actions' |
|
1737 |
for item in self.items: |
|
1738 |
if not item.check_auth(filled, user): |
|
1739 |
continue |
|
1740 |
if not item.check_condition(filled): |
|
1741 |
continue |
|
1742 |
item.fill_form(form, filled, user, displayed_fields=displayed_fields) |
|
1743 | ||
1744 |
if form.widgets or form.submit_widgets: |
|
1745 |
return form |
|
1746 |
else: |
|
1747 |
return None |
|
1748 | ||
1749 |
def get_active_items(self, form, filled, user): |
|
1750 |
for item in self.items: |
|
1751 |
if hasattr(item, 'by'): |
|
1752 |
for role in item.by or []: |
|
1753 |
if role == logged_users_role().id: |
|
1754 |
break |
|
1755 |
if role == '_submitter': |
|
1756 |
if filled.is_submitter(user): |
|
1757 |
break |
|
1758 |
continue |
|
1759 |
if user is None: |
|
1760 |
continue |
|
1761 |
if filled.get_function_roles(role).intersection(user.get_roles()): |
|
1762 |
break |
|
1763 |
else: |
|
1764 |
continue |
|
1765 |
if not item.check_condition(filled): |
|
1766 |
continue |
|
1767 |
yield item |
|
1768 | ||
1769 |
def get_messages(self, formdata=None, position='top'): |
|
1770 |
messages = [] |
|
1771 |
for item in self.items or []: |
|
1772 |
if not hasattr(item, 'get_message'): |
|
1773 |
continue |
|
1774 |
if not item.check_condition(formdata): |
|
1775 |
continue |
|
1776 |
message = item.get_message(formdata, position=position) |
|
1777 |
if message: |
|
1778 |
messages.append(message) |
|
1779 |
return messages |
|
1780 | ||
1781 |
def handle_form(self, form, filled, user, evo): |
|
1782 |
evo.time = time.localtime() |
|
1783 |
if user: |
|
1784 |
if filled.is_submitter(user): |
|
1785 |
evo.who = '_submitter' |
|
1786 |
else: |
|
1787 |
evo.who = user.id |
|
1788 |
if not filled.evolution: |
|
1789 |
filled.evolution = [] |
|
1790 | ||
1791 |
for item in self.get_active_items(form, filled, user): |
|
1792 |
next_url = item.submit_form(form, filled, user, evo) |
|
1793 |
if next_url is True: |
|
1794 |
break |
|
1795 |
if next_url: |
|
1796 |
if not form.has_errors(): |
|
1797 |
if evo.parts or evo.status or evo.comment or evo.status: |
|
1798 |
# add evolution entry only if there's some content |
|
1799 |
# within, i.e. do not register anything in the case of |
|
1800 |
# a single edit action (where the evolution should be |
|
1801 |
# appended only after successful edit). |
|
1802 |
filled.evolution.append(evo) |
|
1803 |
if evo.status: |
|
1804 |
filled.status = evo.status |
|
1805 |
filled.store() |
|
1806 |
return next_url |
|
1807 | ||
1808 |
return next_url |
|
1809 | ||
1733 | 1810 | |
1734 | 1811 |
class WorkflowGlobalAction(SerieOfActionsMixin): |
1735 | 1812 |
id = None |
... | ... | |
1747 | 1824 |
del odict['parent'] |
1748 | 1825 |
return odict |
1749 | 1826 | |
1827 |
def is_interactive(self): |
|
1828 |
for item in self.items or []: |
|
1829 |
if item.is_interactive(): |
|
1830 |
return True |
|
1831 |
return False |
|
1832 | ||
1833 |
def get_global_interactive_form_url(self, formdef=None, ids=None): |
|
1834 |
token = get_publisher().token_class(size=32) |
|
1835 |
token.type = 'global-interactive-action' |
|
1836 |
token.context = { |
|
1837 |
'action_id': self.id, |
|
1838 |
'form_slug': formdef.slug, |
|
1839 |
'form_type': formdef.xml_root_node, |
|
1840 |
'form_ids': ids, |
|
1841 |
'return_url': get_request().get_path_query(), |
|
1842 |
} |
|
1843 |
token.store() |
|
1844 |
if get_request().is_in_backoffice(): |
|
1845 |
return formdef.get_url(backoffice=True) + 'actions/%s/#' % token.id |
|
1846 |
else: |
|
1847 |
return '/actions/%s/#' % token.id |
|
1848 | ||
1849 |
def handle_form(self, form, filled, user): |
|
1850 |
evo = Evolution() |
|
1851 |
url = super().handle_form(form, filled, user, evo) |
|
1852 |
if isinstance(url, str): |
|
1853 |
return url |
|
1854 |
filled.evolution.append(evo) |
|
1855 |
if evo.status: |
|
1856 |
filled.status = evo.status |
|
1857 |
filled.store() |
|
1858 | ||
1750 | 1859 |
def get_admin_url(self): |
1751 | 1860 |
return '%sglobal-actions/%s/' % (self.parent.get_admin_url(), self.id) |
1752 | 1861 | |
... | ... | |
1866 | 1975 |
return changed |
1867 | 1976 | |
1868 | 1977 |
def get_action_form(self, filled, user, displayed_fields=None): |
1869 |
form = Form(enctype='multipart/form-data', use_tokens=False) |
|
1870 |
form.attrs['id'] = 'wf-actions' |
|
1871 |
for item in self.items: |
|
1872 |
if not item.check_auth(filled, user): |
|
1873 |
continue |
|
1874 |
if not item.check_condition(filled): |
|
1875 |
continue |
|
1876 |
item.fill_form(form, filled, user, displayed_fields=displayed_fields) |
|
1978 |
form = super().get_action_form(filled, user, displayed_fields=displayed_fields) |
|
1979 |
if form is None: |
|
1980 |
form = Form(enctype='multipart/form-data', use_tokens=False) |
|
1981 |
form.attrs['id'] = 'wf-actions' |
|
1877 | 1982 | |
1878 | 1983 |
for action in filled.formdef.workflow.get_global_actions_for_user(filled, user): |
1879 | 1984 |
form.add_submit('button-action-%s' % action.id, action.name) |
... | ... | |
1888 | 1993 |
else: |
1889 | 1994 |
return None |
1890 | 1995 | |
1891 |
def get_active_items(self, form, filled, user): |
|
1892 |
for item in self.items: |
|
1893 |
if hasattr(item, 'by'): |
|
1894 |
for role in item.by or []: |
|
1895 |
if role == logged_users_role().id: |
|
1896 |
break |
|
1897 |
if role == '_submitter': |
|
1898 |
if filled.is_submitter(user): |
|
1899 |
break |
|
1900 |
continue |
|
1901 |
if user is None: |
|
1902 |
continue |
|
1903 |
if filled.get_function_roles(role).intersection(user.get_roles()): |
|
1904 |
break |
|
1905 |
else: |
|
1906 |
continue |
|
1907 |
if not item.check_condition(filled): |
|
1908 |
continue |
|
1909 |
yield item |
|
1910 | ||
1911 | 1996 |
def get_admin_url(self): |
1912 | 1997 |
return self.parent.get_admin_url() + 'status/%s/' % self.id |
1913 | 1998 | |
... | ... | |
1919 | 2004 |
# check for global actions |
1920 | 2005 |
for action in filled.formdef.workflow.get_global_actions_for_user(filled, user): |
1921 | 2006 |
if 'button-action-%s' % action.id in get_request().form: |
2007 |
if action.is_interactive(): |
|
2008 |
return action.get_global_interactive_form_url(formdef=filled.formdef, ids=[filled.id]) |
|
1922 | 2009 |
url = filled.perform_global_action(action.id, user, event_name='global-action-button') |
1923 | 2010 |
if url: |
1924 | 2011 |
return url |
1925 | 2012 |
return |
1926 | 2013 | |
1927 | 2014 |
evo = Evolution() |
1928 |
evo.time = time.localtime() |
|
1929 |
if user: |
|
1930 |
if filled.is_submitter(user): |
|
1931 |
evo.who = '_submitter' |
|
1932 |
else: |
|
1933 |
evo.who = user.id |
|
1934 |
if not filled.evolution: |
|
1935 |
filled.evolution = [] |
|
1936 | ||
1937 |
for item in self.get_active_items(form, filled, user): |
|
1938 |
next_url = item.submit_form(form, filled, user, evo) |
|
1939 |
if next_url is True: |
|
1940 |
break |
|
1941 |
if next_url: |
|
1942 |
if not form.has_errors(): |
|
1943 |
if evo.parts or evo.status or evo.comment or evo.status: |
|
1944 |
# add evolution entry only if there's some content |
|
1945 |
# within, i.e. do not register anything in the case of |
|
1946 |
# a single edit action (where the evolution should be |
|
1947 |
# appended only after successful edit). |
|
1948 |
filled.evolution.append(evo) |
|
1949 |
if evo.status: |
|
1950 |
filled.status = evo.status |
|
1951 |
filled.store() |
|
1952 |
return next_url |
|
1953 | ||
2015 |
url = super().handle_form(form, filled, user, evo) |
|
2016 |
if isinstance(url, str): |
|
2017 |
return url |
|
1954 | 2018 |
if form.has_errors(): |
1955 | 2019 |
return |
1956 | 2020 | |
... | ... | |
2046 | 2110 |
self.require_confirmation = action.require_confirmation |
2047 | 2111 |
self.action = action |
2048 | 2112 | |
2113 |
def is_interactive(self): |
|
2114 |
return False |
|
2115 | ||
2049 | 2116 |
for action in self.items or []: |
2050 | 2117 |
if not isinstance(action, ChoiceWorkflowStatusItem): |
2051 | 2118 |
continue |
... | ... | |
2159 | 2226 |
directory_class = None |
2160 | 2227 |
support_substitution_variables = False |
2161 | 2228 | |
2229 |
def __init__(self, parent=None): |
|
2230 |
self.parent = parent |
|
2231 | ||
2162 | 2232 |
@classmethod |
2163 | 2233 |
def init(cls): |
2164 | 2234 |
pass |
... | ... | |
2232 | 2302 |
def fill_form(self, form, formdata, user, **kwargs): |
2233 | 2303 |
pass |
2234 | 2304 | |
2305 |
def is_interactive(self): |
|
2306 |
return False |
|
2307 | ||
2235 | 2308 |
def evaluate_live_form(self, form, formdata, user): |
2236 | 2309 |
pass |
2237 | 2310 | |
2238 |
- |