0002-formdata-store-data-history-62800.patch
tests/form_pages/test_all.py | ||
---|---|---|
9129 | 9129 |
'1_display': 'un', |
9130 | 9130 |
'1_structured': {'id': '1', 'text': 'un', 'more': 'foo'}, |
9131 | 9131 |
} |
9132 |
assert '2020-04-18' in formdata.evolution[0].parts[0].content
|
|
9132 |
assert '2020-04-18' in formdata.evolution[0].parts[1].content
|
|
9133 | 9133 | |
9134 | 9134 | |
9135 | 9135 |
def test_exclude_self_condition(pub): |
tests/form_pages/test_formdata.py | ||
---|---|---|
21 | 21 |
from wcs.wf.create_formdata import Mapping |
22 | 22 |
from wcs.wf.export_to_model import transform_to_pdf |
23 | 23 |
from wcs.wf.form import WorkflowFormFieldsFormDef |
24 |
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef |
|
24 |
from wcs.workflows import ContentSnapshotPart, Workflow, WorkflowBackofficeFieldsFormDef
|
|
25 | 25 |
from wcs.wscalls import NamedWsCall |
26 | 26 | |
27 | 27 |
from ..utilities import clean_temporary_pub, create_temporary_pub, get_app, login |
... | ... | |
292 | 292 |
assert bo1.get_content() == b'foobar' |
293 | 293 | |
294 | 294 |
# but nothing in history |
295 |
for evo in formdata.evolution: |
|
296 |
assert not evo.parts |
|
295 |
assert len(formdata.evolution) == 2 |
|
296 |
assert len(formdata.evolution[0].parts) == 1 |
|
297 |
assert isinstance(formdata.evolution[0].parts[0], ContentSnapshotPart) |
|
298 |
assert formdata.evolution[1].parts is None |
|
297 | 299 | |
298 | 300 | |
299 | 301 |
def test_formdata_attachment_file_options(pub): |
... | ... | |
1456 | 1458 |
assert 'The form has been recorded and: XbarY' in resp.text |
1457 | 1459 | |
1458 | 1460 |
formdata = formdef.data_class().select()[0] |
1459 |
assert formdata.evolution[0].parts[0].content == 'Hello bar World'
|
|
1461 |
assert formdata.evolution[0].parts[1].content == 'Hello bar World'
|
|
1460 | 1462 | |
1461 | 1463 |
# check with publisher variable in named webservice call |
1462 | 1464 |
if not pub.site_options.has_section('variables'): |
... | ... | |
1481 | 1483 |
assert 'The form has been recorded and: XbarY' in resp.text |
1482 | 1484 | |
1483 | 1485 |
formdata = formdef.data_class().select()[0] |
1484 |
assert formdata.evolution[0].parts[0].content == 'Hello bar World'
|
|
1486 |
assert formdata.evolution[0].parts[1].content == 'Hello bar World'
|
|
1485 | 1487 | |
1486 | 1488 | |
1487 | 1489 |
def test_formdata_named_wscall_in_conditions(http_requests, pub): |
... | ... | |
1607 | 1609 |
assert 'The form has been recorded' in resp.text |
1608 | 1610 | |
1609 | 1611 |
formdata = formdef.data_class().select()[0] |
1610 |
assert formdata.evolution[0].parts[0].content == 'Hello World'
|
|
1611 |
assert formdata.evolution[0].parts[0].to is None
|
|
1612 |
assert formdata.evolution[0].parts[1].content == 'Hello World'
|
|
1613 |
assert formdata.evolution[0].parts[1].to is None
|
|
1612 | 1614 |
resp = app.get('/test/%s/' % formdata.id) |
1613 | 1615 |
resp.status_int = 200 |
1614 | 1616 |
assert resp.html.find('div', {'id': 'evolution-log'}).find('p').text == 'Hello World' |
... | ... | |
1627 | 1629 |
assert 'The form has been recorded' in resp.text |
1628 | 1630 | |
1629 | 1631 |
formdata = formdef.data_class().select()[0] |
1630 |
assert formdata.evolution[0].parts[0].content == 'Hello World'
|
|
1631 |
assert formdata.evolution[0].parts[0].to == [role1.id]
|
|
1632 |
assert formdata.evolution[0].parts[1].content == 'Hello World'
|
|
1633 |
assert formdata.evolution[0].parts[1].to == [role1.id]
|
|
1632 | 1634 |
resp = app.get('/test/%s/' % formdata.id) |
1633 | 1635 |
resp.status_int = 200 |
1634 | 1636 |
assert not resp.html.find('div', {'id': 'evolution-log'}).find('p') |
... | ... | |
1647 | 1649 |
assert 'The form has been recorded' in resp.text |
1648 | 1650 | |
1649 | 1651 |
formdata = formdef.data_class().select()[0] |
1650 |
assert formdata.evolution[0].parts[0].content == 'Hello World'
|
|
1651 |
assert formdata.evolution[0].parts[0].to == [role2.id]
|
|
1652 |
assert formdata.evolution[0].parts[1].content == 'Hello World'
|
|
1653 |
assert formdata.evolution[0].parts[1].to == [role2.id]
|
|
1652 | 1654 |
resp = app.get('/test/%s/' % formdata.id) |
1653 | 1655 |
resp.status_int = 200 |
1654 | 1656 |
assert resp.html.find('div', {'id': 'evolution-log'}).find('p').text == 'Hello World' |
tests/test_content_snapshots.py | ||
---|---|---|
1 |
import json |
|
2 |
import os |
|
3 | ||
4 |
import pytest |
|
5 |
from webtest import Upload |
|
6 | ||
7 |
from wcs import fields |
|
8 |
from wcs.api_access import ApiAccess |
|
9 |
from wcs.carddef import CardDef |
|
10 |
from wcs.formdef import FormDef |
|
11 |
from wcs.qommon.http_request import HTTPRequest |
|
12 |
from wcs.qommon.ident.password_accounts import PasswordAccount |
|
13 |
from wcs.wf.backoffice_fields import SetBackofficeFieldsWorkflowStatusItem |
|
14 |
from wcs.wf.create_formdata import Mapping |
|
15 |
from wcs.workflows import ContentSnapshotPart, Workflow, WorkflowBackofficeFieldsFormDef |
|
16 | ||
17 |
from .utilities import clean_temporary_pub, create_temporary_pub, get_app, login |
|
18 | ||
19 | ||
20 |
@pytest.fixture |
|
21 |
def pub(emails): |
|
22 |
pub = create_temporary_pub() |
|
23 | ||
24 |
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'}) |
|
25 |
pub.set_app_dir(req) |
|
26 |
pub.cfg['identification'] = {'methods': ['password']} |
|
27 |
pub.cfg['language'] = {'language': 'en'} |
|
28 |
pub.write_cfg() |
|
29 |
with open(os.path.join(pub.app_dir, 'site-options.cfg'), 'w') as fd: |
|
30 |
fd.write( |
|
31 |
''' |
|
32 |
[api-secrets] |
|
33 |
coucou = 1234 |
|
34 |
''' |
|
35 |
) |
|
36 | ||
37 |
return pub |
|
38 | ||
39 | ||
40 |
def teardown_module(module): |
|
41 |
clean_temporary_pub() |
|
42 | ||
43 | ||
44 |
@pytest.fixture |
|
45 |
def role(pub): |
|
46 |
pub.role_class.wipe() |
|
47 |
role = pub.role_class(name='foobar') |
|
48 |
role.store() |
|
49 |
return role |
|
50 | ||
51 | ||
52 |
@pytest.fixture |
|
53 |
def user(pub, role): |
|
54 |
pub.user_class.wipe() |
|
55 |
user = pub.user_class() |
|
56 |
user.name = 'Jean Darmette' |
|
57 |
user.email = 'jean.darmette@triffouilis.fr' |
|
58 |
user.name_identifiers = ['0123456789'] |
|
59 |
user.roles = [role.id] |
|
60 |
user.store() |
|
61 | ||
62 |
account = PasswordAccount(id='admin') |
|
63 |
account.set_password('admin') |
|
64 |
account.user_id = user.id |
|
65 |
account.store() |
|
66 | ||
67 |
return user |
|
68 | ||
69 | ||
70 |
@pytest.fixture |
|
71 |
def access(pub, role): |
|
72 |
ApiAccess.wipe() |
|
73 |
access = ApiAccess() |
|
74 |
access.name = 'test' |
|
75 |
access.access_identifier = 'test' |
|
76 |
access.access_key = '12345' |
|
77 |
access.roles = [role] |
|
78 |
access.store() |
|
79 |
return access |
|
80 | ||
81 | ||
82 |
def test_formdata_create_and_edit_and_bo_field(pub, user): |
|
83 |
FormDef.wipe() |
|
84 |
formdef = FormDef() |
|
85 |
formdef.name = 'test' |
|
86 |
formdef.fields = [ |
|
87 |
fields.StringField(id='1', label='string', varname='foo'), |
|
88 |
] |
|
89 |
formdef.store() |
|
90 |
formdef.data_class().wipe() |
|
91 | ||
92 |
Workflow.wipe() |
|
93 |
workflow = Workflow(name='test') |
|
94 |
workflow.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(workflow) |
|
95 |
workflow.backoffice_fields_formdef.fields = [ |
|
96 |
fields.StringField(id='bo1', label='bo field 1', type='string', varname='plop'), |
|
97 |
] |
|
98 |
st1 = workflow.add_status('Status1', 'st1') |
|
99 |
setbo = st1.add_action('set-backoffice-fields') |
|
100 |
setbo.fields = [{'field_id': 'bo1', 'value': '{{ form_var_foo }}'}] |
|
101 |
setbo2 = st1.add_action('set-backoffice-fields') |
|
102 |
setbo2.fields = [{'field_id': 'bo1', 'value': '{{ "foo"|add:form_var_plop }}'}] |
|
103 |
jump = st1.add_action('jump') |
|
104 |
jump.status = 'st2' |
|
105 | ||
106 |
st2 = workflow.add_status('Status2', 'st2') |
|
107 | ||
108 |
editable = st2.add_action('editable', id='_editable') |
|
109 |
editable.by = ['_submitter'] |
|
110 |
editable.status = st1.id |
|
111 |
workflow.store() |
|
112 | ||
113 |
formdef.workflow_id = workflow.id |
|
114 |
formdef.store() |
|
115 |
formdef.data_class().wipe() |
|
116 | ||
117 |
app = login(get_app(pub)) |
|
118 |
resp = app.get('/test/') |
|
119 |
resp.form['f1'] = 'bar' |
|
120 |
resp = resp.form.submit('submit') # -> validation |
|
121 |
resp = resp.form.submit('submit').follow() # -> submitted |
|
122 |
assert 'The form has been recorded' in resp.text |
|
123 | ||
124 |
data_id = formdef.data_class().select()[0].id |
|
125 |
resp = app.get('/test/%s/' % data_id) |
|
126 |
assert 'button_editable-button' in resp.text |
|
127 | ||
128 |
resp = resp.form.submit('button_editable') |
|
129 |
resp = resp.follow() |
|
130 |
assert resp.form['f1'].value == 'bar' |
|
131 |
resp.form['f1'].value = 'baz' |
|
132 |
resp = resp.form.submit('submit').follow() # -> saved |
|
133 | ||
134 |
formdata = formdef.data_class().get(data_id) |
|
135 |
assert isinstance(formdata.evolution[0].parts[0], ContentSnapshotPart) |
|
136 |
# creation, submit |
|
137 |
assert formdata.evolution[0].parts[0].formdef_type == 'formdef' |
|
138 |
assert formdata.evolution[0].parts[0].formdef_id == str(formdef.id) |
|
139 |
assert formdata.evolution[0].parts[0].old_data == {} |
|
140 |
assert formdata.evolution[0].parts[0].new_data == {'1': 'bar', 'bo1': None} |
|
141 |
dt1 = formdata.evolution[0].parts[0].datetime |
|
142 |
# creation, bo field first action |
|
143 |
assert formdata.evolution[0].parts[1].formdef_type == 'formdef' |
|
144 |
assert formdata.evolution[0].parts[1].formdef_id == str(formdef.id) |
|
145 |
assert formdata.evolution[0].parts[1].old_data == {'1': 'bar'} |
|
146 |
assert formdata.evolution[0].parts[1].new_data == {'1': 'bar', 'bo1': 'bar'} |
|
147 |
dt2 = formdata.evolution[0].parts[1].datetime |
|
148 |
assert dt2 > dt1 |
|
149 |
# creation, bo field second action |
|
150 |
assert formdata.evolution[0].parts[2].formdef_type == 'formdef' |
|
151 |
assert formdata.evolution[0].parts[2].formdef_id == str(formdef.id) |
|
152 |
assert formdata.evolution[0].parts[2].old_data == {'1': 'bar', 'bo1': 'bar'} |
|
153 |
assert formdata.evolution[0].parts[2].new_data == {'1': 'bar', 'bo1': 'foobar'} |
|
154 |
dt3 = formdata.evolution[0].parts[2].datetime |
|
155 |
assert dt3 > dt2 |
|
156 |
# update, submit |
|
157 |
assert formdata.evolution[1].parts[0].formdef_type == 'formdef' |
|
158 |
assert formdata.evolution[1].parts[0].formdef_id == str(formdef.id) |
|
159 |
assert formdata.evolution[1].parts[0].old_data == {'1': 'bar', 'bo1': 'foobar'} |
|
160 |
assert formdata.evolution[1].parts[0].new_data == {'1': 'baz', 'bo1': 'foobar'} |
|
161 |
dt4 = formdata.evolution[1].parts[0].datetime |
|
162 |
assert dt4 > dt3 |
|
163 |
# update, bo field first action |
|
164 |
assert formdata.evolution[2].parts[0].formdef_type == 'formdef' |
|
165 |
assert formdata.evolution[2].parts[0].formdef_id == str(formdef.id) |
|
166 |
assert formdata.evolution[2].parts[0].old_data == {'1': 'baz', 'bo1': 'foobar'} |
|
167 |
assert formdata.evolution[2].parts[0].new_data == {'1': 'baz', 'bo1': 'baz'} |
|
168 |
dt5 = formdata.evolution[2].parts[0].datetime |
|
169 |
assert dt5 > dt4 |
|
170 |
# update, bo field second action |
|
171 |
assert formdata.evolution[2].parts[1].formdef_type == 'formdef' |
|
172 |
assert formdata.evolution[2].parts[1].formdef_id == str(formdef.id) |
|
173 |
assert formdata.evolution[2].parts[1].old_data == {'1': 'baz', 'bo1': 'baz'} |
|
174 |
assert formdata.evolution[2].parts[1].new_data == {'1': 'baz', 'bo1': 'foobaz'} |
|
175 |
dt6 = formdata.evolution[2].parts[1].datetime |
|
176 |
assert dt6 > dt5 |
|
177 | ||
178 | ||
179 |
def test_backoffice_formdata_submission(pub, user): |
|
180 |
FormDef.wipe() |
|
181 |
formdef = FormDef() |
|
182 |
formdef.name = 'form title' |
|
183 |
formdef.fields = [ |
|
184 |
fields.StringField(id='1', label='String', type='string'), |
|
185 |
] |
|
186 |
formdef.workflow_roles = {'_receiver': user.roles[0]} |
|
187 |
formdef.backoffice_submission_roles = user.roles[:] |
|
188 |
formdef.store() |
|
189 | ||
190 |
app = login(get_app(pub)) |
|
191 |
resp = app.get('/backoffice/submission/form-title/') |
|
192 |
resp.form['f1'] = 'test submission' |
|
193 |
resp = resp.form.submit('submit') # -> validation |
|
194 |
resp = resp.form.submit('submit').follow() # -> submitted |
|
195 |
assert 'The form has been recorded' in resp.text |
|
196 | ||
197 |
formdata = formdef.data_class().select()[0] |
|
198 |
assert isinstance(formdata.evolution[0].parts[0], ContentSnapshotPart) |
|
199 |
assert formdata.evolution[0].parts[0].formdef_type == 'formdef' |
|
200 |
assert formdata.evolution[0].parts[0].formdef_id == str(formdef.id) |
|
201 |
assert formdata.evolution[0].parts[0].old_data == {} |
|
202 |
assert formdata.evolution[0].parts[0].new_data == {'1': 'test submission'} |
|
203 | ||
204 | ||
205 |
def test_backoffice_carddata_add_edit(pub, user): |
|
206 |
CardDef.wipe() |
|
207 |
carddef = CardDef() |
|
208 |
carddef.name = 'test' |
|
209 |
carddef.fields = [ |
|
210 |
fields.StringField(id='1', label='string', varname='foo'), |
|
211 |
] |
|
212 |
carddef.backoffice_submission_roles = user.roles |
|
213 |
carddef.workflow_roles = { |
|
214 |
'_viewer': user.roles[0], |
|
215 |
'_editor': user.roles[0], |
|
216 |
} |
|
217 |
carddef.store() |
|
218 |
carddef.data_class().wipe() |
|
219 | ||
220 |
Workflow.wipe() |
|
221 |
workflow = Workflow(name='test') |
|
222 |
workflow.roles = { |
|
223 |
'_viewer': 'Viewer', |
|
224 |
'_editor': 'Editor', |
|
225 |
} |
|
226 |
st1 = workflow.add_status('Status1', 'st1') |
|
227 |
jump = st1.add_action('jump') |
|
228 |
jump.status = 'st2' |
|
229 |
st2 = workflow.add_status('Status2', 'st2') |
|
230 |
editable = st2.add_action('editable', id='_editable') |
|
231 |
editable.by = ['_editor'] |
|
232 |
editable.status = st1.id |
|
233 |
workflow.store() |
|
234 | ||
235 |
carddef.workflow_id = workflow.id |
|
236 |
carddef.store() |
|
237 |
carddef.data_class().wipe() |
|
238 | ||
239 |
app = login(get_app(pub)) |
|
240 |
resp = app.get('/backoffice/data/test/add/') |
|
241 |
resp.form['f1'] = 'foo' |
|
242 |
resp = resp.form.submit('submit').follow() |
|
243 |
assert 'button_editable-button' in resp.text |
|
244 | ||
245 |
resp = resp.form.submit('button_editable') |
|
246 |
resp = resp.follow() |
|
247 |
resp.form['f1'].value = 'bar' |
|
248 |
resp = resp.form.submit('submit').follow() |
|
249 | ||
250 |
carddata = carddef.data_class().select()[0] |
|
251 |
# creation |
|
252 |
assert isinstance(carddata.evolution[0].parts[0], ContentSnapshotPart) |
|
253 |
assert carddata.evolution[0].parts[0].formdef_type == 'carddef' |
|
254 |
assert carddata.evolution[0].parts[0].formdef_id == str(carddef.id) |
|
255 |
assert carddata.evolution[0].parts[0].old_data == {} |
|
256 |
assert carddata.evolution[0].parts[0].new_data == {'1': 'foo'} |
|
257 |
dt1 = carddata.evolution[0].parts[0].datetime |
|
258 |
# update |
|
259 |
assert isinstance(carddata.evolution[1].parts[0], ContentSnapshotPart) |
|
260 |
assert carddata.evolution[1].parts[0].formdef_type == 'carddef' |
|
261 |
assert carddata.evolution[1].parts[0].formdef_id == str(carddef.id) |
|
262 |
assert carddata.evolution[1].parts[0].old_data == {'1': 'foo'} |
|
263 |
assert carddata.evolution[1].parts[0].new_data == {'1': 'bar'} |
|
264 |
dt2 = carddata.evolution[1].parts[0].datetime |
|
265 |
assert dt2 > dt1 |
|
266 | ||
267 | ||
268 |
def test_backoffice_card_import_csv(pub, user): |
|
269 |
CardDef.wipe() |
|
270 |
carddef = CardDef() |
|
271 |
carddef.name = 'test' |
|
272 |
carddef.fields = [ |
|
273 |
fields.StringField(id='1', label='Test'), |
|
274 |
fields.StringField(id='2', label='Test2'), |
|
275 |
] |
|
276 |
carddef.workflow_roles = {'_editor': user.roles[0]} |
|
277 |
carddef.backoffice_submission_roles = user.roles |
|
278 |
carddef.store() |
|
279 |
carddef.data_class().wipe() |
|
280 | ||
281 |
app = login(get_app(pub)) |
|
282 | ||
283 |
resp = app.get(carddef.get_url()) |
|
284 |
resp = resp.click('Import data from a file') |
|
285 |
data = [b'Test,Test2'] |
|
286 |
data.append(b'data,foo') |
|
287 | ||
288 |
resp.forms[0]['file'] = Upload('test.csv', b'\n'.join(data), 'text/csv') |
|
289 |
resp = resp.forms[0].submit().follow() |
|
290 |
assert 'Importing data into cards' in resp |
|
291 |
assert carddef.data_class().count() == 1 |
|
292 |
carddata = carddef.data_class().select()[0] |
|
293 |
assert isinstance(carddata.evolution[-1].parts[0], ContentSnapshotPart) |
|
294 |
assert carddata.evolution[0].parts[0].formdef_type == 'carddef' |
|
295 |
assert carddata.evolution[0].parts[0].formdef_id == str(carddef.id) |
|
296 |
assert carddata.evolution[0].parts[0].old_data == {} |
|
297 |
assert carddata.evolution[0].parts[0].new_data == {'1': 'data', '2': 'foo'} |
|
298 | ||
299 | ||
300 |
def test_backoffice_card_import_json(pub, user): |
|
301 |
CardDef.wipe() |
|
302 |
carddef = CardDef() |
|
303 |
carddef.name = 'test' |
|
304 |
carddef.fields = [ |
|
305 |
fields.StringField(id='1', label='Test', varname='string'), |
|
306 |
] |
|
307 |
carddef.workflow_roles = {'_editor': user.roles[0]} |
|
308 |
carddef.backoffice_submission_roles = user.roles |
|
309 |
carddef.store() |
|
310 |
carddef.data_class().wipe() |
|
311 | ||
312 |
app = login(get_app(pub)) |
|
313 |
resp = app.get(carddef.get_url()) |
|
314 |
resp = resp.click('Import data from a file') |
|
315 |
data = { |
|
316 |
'data': [ |
|
317 |
{ |
|
318 |
'fields': { |
|
319 |
'string': 'a string', |
|
320 |
} |
|
321 |
} |
|
322 |
] |
|
323 |
} |
|
324 |
resp.forms[0]['file'] = Upload('test.json', json.dumps(data).encode(), 'application/json') |
|
325 |
resp = resp.forms[0].submit() |
|
326 |
assert '/backoffice/processing?job=' in resp.location |
|
327 |
resp = resp.follow() |
|
328 | ||
329 |
carddata = carddef.data_class().select()[0] |
|
330 |
assert isinstance(carddata.evolution[-1].parts[0], ContentSnapshotPart) |
|
331 |
assert carddata.evolution[-1].parts[0].formdef_type == 'carddef' |
|
332 |
assert carddata.evolution[-1].parts[0].formdef_id == str(carddef.id) |
|
333 |
assert carddata.evolution[-1].parts[0].old_data == {} |
|
334 |
assert carddata.evolution[-1].parts[0].new_data == {'1': 'a string'} |
|
335 | ||
336 | ||
337 |
def test_workflow_formdata_create(pub): |
|
338 |
FormDef.wipe() |
|
339 |
pub.tracking_code_class.wipe() |
|
340 | ||
341 |
target_formdef = FormDef() |
|
342 |
target_formdef.name = 'target form' |
|
343 |
target_formdef.fields = [ |
|
344 |
fields.StringField(id='0', label='string', varname='string'), |
|
345 |
] |
|
346 |
target_formdef.store() |
|
347 | ||
348 |
wf = Workflow(name='create-formdata') |
|
349 |
wf.possible_status = Workflow.get_default_workflow().possible_status[:] |
|
350 |
create = wf.possible_status[1].add_action('create_formdata', id='_create', prepend=True) |
|
351 |
create.formdef_slug = target_formdef.url_name |
|
352 |
create.label = 'create a new linked form' |
|
353 |
create.varname = 'resubmitted' |
|
354 |
create.mappings = [ |
|
355 |
Mapping(field_id='0', expression='{{ form_var_foo }}'), |
|
356 |
] |
|
357 |
wf.store() |
|
358 | ||
359 |
source_formdef = FormDef() |
|
360 |
source_formdef.name = 'source form' |
|
361 |
source_formdef.fields = [ |
|
362 |
fields.StringField(id='0', label='string', varname='foo'), |
|
363 |
] |
|
364 |
source_formdef.workflow_id = wf.id |
|
365 |
source_formdef.store() |
|
366 | ||
367 |
formdata = source_formdef.data_class()() |
|
368 |
formdata.data = {'0': 'foobar'} |
|
369 |
formdata.just_created() |
|
370 |
formdata.store() |
|
371 | ||
372 |
formdata.perform_workflow() |
|
373 |
assert target_formdef.data_class().count() == 1 |
|
374 |
created_formdata = target_formdef.data_class().select()[0] |
|
375 |
assert isinstance(created_formdata.evolution[0].parts[0], ContentSnapshotPart) |
|
376 |
assert created_formdata.evolution[0].parts[0].formdef_type == 'formdef' |
|
377 |
assert created_formdata.evolution[0].parts[0].formdef_id == str(target_formdef.id) |
|
378 |
assert created_formdata.evolution[0].parts[0].old_data == {} |
|
379 |
assert created_formdata.evolution[0].parts[0].new_data == {'0': 'foobar'} |
|
380 | ||
381 | ||
382 |
def test_workflow_carddata_create(pub): |
|
383 |
CardDef.wipe() |
|
384 |
FormDef.wipe() |
|
385 | ||
386 |
carddef = CardDef() |
|
387 |
carddef.name = 'My card' |
|
388 |
carddef.fields = [ |
|
389 |
fields.StringField(id='1', label='string'), |
|
390 |
] |
|
391 |
carddef.store() |
|
392 | ||
393 |
wf = Workflow(name='create-carddata') |
|
394 |
wf.possible_status = Workflow.get_default_workflow().possible_status[:] |
|
395 |
create = wf.possible_status[1].add_action('create_carddata', id='_create', prepend=True) |
|
396 |
create.label = 'Create CardDef' |
|
397 |
create.varname = 'mycard' |
|
398 |
create.formdef_slug = carddef.url_name |
|
399 |
create.mappings = [ |
|
400 |
Mapping(field_id='1', expression='{{ form_var_string }}'), |
|
401 |
] |
|
402 |
wf.store() |
|
403 | ||
404 |
formdef = FormDef() |
|
405 |
formdef.name = 'source form' |
|
406 |
formdef.fields = [ |
|
407 |
fields.StringField(id='1', label='string', varname='string'), |
|
408 |
] |
|
409 |
formdef.workflow_id = wf.id |
|
410 |
formdef.store() |
|
411 | ||
412 |
formdata = formdef.data_class()() |
|
413 |
formdata.data = {'1': 'foobar'} |
|
414 |
formdata.just_created() |
|
415 |
formdata.store() |
|
416 | ||
417 |
formdata.perform_workflow() |
|
418 |
assert carddef.data_class().count() == 1 |
|
419 |
carddata = carddef.data_class().select()[0] |
|
420 |
assert isinstance(carddata.evolution[-1].parts[0], ContentSnapshotPart) |
|
421 |
assert carddata.evolution[-1].parts[0].formdef_type == 'carddef' |
|
422 |
assert carddata.evolution[-1].parts[0].formdef_id == str(carddef.id) |
|
423 |
assert carddata.evolution[-1].parts[0].old_data == {} |
|
424 |
assert carddata.evolution[-1].parts[0].new_data == {'1': 'foobar'} |
|
425 | ||
426 | ||
427 |
def test_workflow_carddata_edit(pub): |
|
428 |
FormDef.wipe() |
|
429 |
CardDef.wipe() |
|
430 | ||
431 |
# carddef |
|
432 |
carddef = CardDef() |
|
433 |
carddef.name = 'Model 1' |
|
434 |
carddef.fields = [ |
|
435 |
fields.StringField(id='1', label='string', varname='string'), |
|
436 |
] |
|
437 |
carddef.store() |
|
438 |
carddef.data_class().wipe() |
|
439 | ||
440 |
carddata = carddef.data_class()() |
|
441 |
carddata.data = { |
|
442 |
'1': 'foobar', |
|
443 |
} |
|
444 |
carddata.just_created() |
|
445 |
carddata.store() |
|
446 | ||
447 |
# formdef workflow that will update carddata |
|
448 |
wf = Workflow(name='update') |
|
449 |
st1 = wf.add_status('New', 'st1') |
|
450 |
jump = st1.add_action('jump', id='_jump') |
|
451 |
jump.by = ['_submitter', '_receiver'] |
|
452 |
jump.status = 'st2' |
|
453 |
st2 = wf.add_status('Update card', 'st2') |
|
454 |
edit = st2.add_action('edit_carddata', id='edit') |
|
455 |
edit.formdef_slug = carddef.url_name |
|
456 |
edit.target_mode = 'manual' |
|
457 |
edit.target_id = '{{ form_var_card }}' |
|
458 |
edit.mappings = [ |
|
459 |
Mapping(field_id='1', expression='{{ form_var_foo }}'), |
|
460 |
] |
|
461 |
wf.store() |
|
462 | ||
463 |
# associated formdef |
|
464 |
formdef = FormDef() |
|
465 |
formdef.name = 'Update' |
|
466 |
formdef.fields = [ |
|
467 |
fields.StringField(id='1', label='string', varname='card'), |
|
468 |
fields.StringField(id='2', label='string', varname='foo'), |
|
469 |
] |
|
470 |
formdef.workflow = wf |
|
471 |
formdef.store() |
|
472 | ||
473 |
formdata = formdef.data_class()() |
|
474 |
formdata.data = { |
|
475 |
'1': str(carddata.id), |
|
476 |
'2': 'foobaz', |
|
477 |
} |
|
478 |
formdata.just_created() |
|
479 |
formdata.store() |
|
480 |
formdata.perform_workflow() |
|
481 |
carddata.refresh_from_storage() |
|
482 |
# creation |
|
483 |
assert isinstance(carddata.evolution[0].parts[0], ContentSnapshotPart) |
|
484 |
assert carddata.evolution[0].parts[0].formdef_type == 'carddef' |
|
485 |
assert carddata.evolution[0].parts[0].formdef_id == str(carddef.id) |
|
486 |
assert carddata.evolution[0].parts[0].old_data == {} |
|
487 |
assert carddata.evolution[0].parts[0].new_data == {'1': 'foobar'} |
|
488 |
dt1 = carddata.evolution[0].parts[0].datetime |
|
489 |
# update |
|
490 |
assert isinstance(carddata.evolution[1].parts[0], ContentSnapshotPart) |
|
491 |
assert carddata.evolution[1].parts[0].formdef_type == 'carddef' |
|
492 |
assert carddata.evolution[1].parts[0].formdef_id == str(carddef.id) |
|
493 |
assert carddata.evolution[1].parts[0].old_data == {'1': 'foobar'} |
|
494 |
assert carddata.evolution[1].parts[0].new_data == {'1': 'foobaz'} |
|
495 |
dt2 = carddata.evolution[1].parts[0].datetime |
|
496 |
assert dt2 > dt1 |
|
497 | ||
498 | ||
499 |
def test_workflow_set_backoffice_field(http_requests, pub): |
|
500 |
Workflow.wipe() |
|
501 |
FormDef.wipe() |
|
502 |
wf = Workflow(name='xxx') |
|
503 |
wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(wf) |
|
504 |
wf.backoffice_fields_formdef.fields = [ |
|
505 |
fields.StringField(id='bo1', label='1st backoffice field', type='string', varname='backoffice_blah'), |
|
506 |
] |
|
507 |
st1 = wf.add_status('Status1') |
|
508 |
wf.store() |
|
509 | ||
510 |
formdef = FormDef() |
|
511 |
formdef.name = 'baz' |
|
512 |
formdef.fields = [ |
|
513 |
fields.StringField(id='0', label='String', type='string', varname='string'), |
|
514 |
] |
|
515 |
formdef.workflow_id = wf.id |
|
516 |
formdef.store() |
|
517 | ||
518 |
formdata = formdef.data_class()() |
|
519 |
formdata.data = {'0': 'HELLO'} |
|
520 |
formdata.just_created() |
|
521 |
formdata.store() |
|
522 |
pub.substitutions.feed(formdata) |
|
523 | ||
524 |
item = SetBackofficeFieldsWorkflowStatusItem() |
|
525 |
item.fields = [{'field_id': 'bo1', 'value': '{{ form_var_string }}'}] |
|
526 |
item.parent = st1 |
|
527 | ||
528 |
item.perform(formdata) |
|
529 |
formdata.refresh_from_storage() |
|
530 |
# creation |
|
531 |
assert isinstance(formdata.evolution[-1].parts[0], ContentSnapshotPart) |
|
532 |
assert formdata.evolution[-1].parts[0].formdef_type == 'formdef' |
|
533 |
assert formdata.evolution[-1].parts[0].formdef_id == str(formdef.id) |
|
534 |
assert formdata.evolution[-1].parts[0].old_data == {} |
|
535 |
assert formdata.evolution[-1].parts[0].new_data == { |
|
536 |
'0': 'HELLO', |
|
537 |
} |
|
538 |
dt1 = formdata.evolution[-1].parts[0].datetime |
|
539 |
# bo action |
|
540 |
assert isinstance(formdata.evolution[-1].parts[1], ContentSnapshotPart) |
|
541 |
assert formdata.evolution[-1].parts[1].formdef_type == 'formdef' |
|
542 |
assert formdata.evolution[-1].parts[1].formdef_id == str(formdef.id) |
|
543 |
assert formdata.evolution[-1].parts[1].old_data == { |
|
544 |
'0': 'HELLO', |
|
545 |
} |
|
546 |
assert formdata.evolution[-1].parts[1].new_data == { |
|
547 |
'0': 'HELLO', |
|
548 |
'bo1': 'HELLO', |
|
549 |
} |
|
550 |
dt2 = formdata.evolution[-1].parts[1].datetime |
|
551 |
assert dt2 > dt1 |
|
552 | ||
553 | ||
554 |
def test_api_form_submit(pub, user, access, role): |
|
555 |
app = get_app(pub) |
|
556 |
app.set_authorization(('Basic', ('test', '12345'))) |
|
557 | ||
558 |
FormDef.wipe() |
|
559 |
formdef = FormDef() |
|
560 |
formdef.name = 'test' |
|
561 |
formdef.fields = [ |
|
562 |
fields.StringField(id='1', label='foobar', varname='foobar'), |
|
563 |
] |
|
564 |
formdef.backoffice_submission_roles = [role.id] |
|
565 |
formdef.store() |
|
566 |
data_class = formdef.data_class() |
|
567 | ||
568 |
payload = { |
|
569 |
'data': { |
|
570 |
'foobar': 'xxx', |
|
571 |
} |
|
572 |
} |
|
573 |
resp = app.post_json( |
|
574 |
'/api/formdefs/test/submit', |
|
575 |
payload, |
|
576 |
) |
|
577 |
assert resp.json['err'] == 0 |
|
578 |
formdata = data_class.get(resp.json['data']['id']) |
|
579 |
assert isinstance(formdata.evolution[0].parts[0], ContentSnapshotPart) |
|
580 |
assert formdata.evolution[0].parts[0].formdef_type == 'formdef' |
|
581 |
assert formdata.evolution[0].parts[0].formdef_id == str(formdef.id) |
|
582 |
assert formdata.evolution[0].parts[0].old_data == {} |
|
583 |
assert formdata.evolution[0].parts[0].new_data == {'1': 'xxx'} |
|
584 | ||
585 | ||
586 |
def test_api_formdata_edit(pub, user, access, role): |
|
587 |
app = get_app(pub) |
|
588 |
app.set_authorization(('Basic', ('test', '12345'))) |
|
589 | ||
590 |
FormDef.wipe() |
|
591 |
formdef = FormDef() |
|
592 |
formdef.name = 'test' |
|
593 |
formdef.fields = [ |
|
594 |
fields.StringField(id='0', label='foobar', varname='foobar'), |
|
595 |
] |
|
596 |
Workflow.wipe() |
|
597 |
workflow = Workflow(name='foo') |
|
598 |
workflow.possible_status = Workflow.get_default_workflow().possible_status[:] |
|
599 |
workflow.store() |
|
600 |
formdef.workflow_id = workflow.id |
|
601 |
formdef.workflow_roles = {'_receiver': role.id} |
|
602 |
formdef.store() |
|
603 |
formdef.data_class().wipe() |
|
604 |
formdata = formdef.data_class()() |
|
605 |
formdata.data = { |
|
606 |
'0': 'foo@localhost', |
|
607 |
} |
|
608 |
formdata.user_id = user.id |
|
609 |
formdata.just_created() |
|
610 |
formdata.status = 'wf-new' |
|
611 |
formdata.evolution[-1].status = 'wf-new' |
|
612 |
formdata.store() |
|
613 | ||
614 |
wfedit = workflow.possible_status[1].add_action('editable', id='_wfedit') |
|
615 |
wfedit.by = [user.roles[0]] |
|
616 |
workflow.store() |
|
617 | ||
618 |
app.post_json( |
|
619 |
'/api/forms/test/%s/' % formdata.id, |
|
620 |
{'data': {'0': 'bar@localhost'}}, |
|
621 |
) |
|
622 |
formdata.refresh_from_storage() |
|
623 |
# creation |
|
624 |
assert isinstance(formdata.evolution[-1].parts[0], ContentSnapshotPart) |
|
625 |
assert formdata.evolution[-1].parts[0].formdef_type == 'formdef' |
|
626 |
assert formdata.evolution[-1].parts[0].formdef_id == str(formdef.id) |
|
627 |
assert formdata.evolution[-1].parts[0].old_data == {} |
|
628 |
assert formdata.evolution[-1].parts[0].new_data == {'0': 'foo@localhost'} |
|
629 |
dt1 = formdata.evolution[-1].parts[0].datetime |
|
630 |
# update |
|
631 |
assert isinstance(formdata.evolution[-1].parts[1], ContentSnapshotPart) |
|
632 |
assert formdata.evolution[-1].parts[1].formdef_type == 'formdef' |
|
633 |
assert formdata.evolution[-1].parts[1].formdef_id == str(formdef.id) |
|
634 |
assert formdata.evolution[-1].parts[1].old_data == {'0': 'foo@localhost'} |
|
635 |
assert formdata.evolution[-1].parts[1].new_data == {'0': 'bar@localhost'} |
|
636 |
dt2 = formdata.evolution[-1].parts[1].datetime |
|
637 |
assert dt2 > dt1 |
|
638 | ||
639 | ||
640 |
def test_api_card_import_csv(pub, user, access, role): |
|
641 |
app = get_app(pub) |
|
642 |
app.set_authorization(('Basic', ('test', '12345'))) |
|
643 | ||
644 |
CardDef.wipe() |
|
645 |
carddef = CardDef() |
|
646 |
carddef.name = 'test' |
|
647 |
carddef.fields = [ |
|
648 |
fields.StringField(id='0', label='foobar', varname='foo'), |
|
649 |
fields.StringField(id='1', label='foobar2', varname='foo2'), |
|
650 |
] |
|
651 |
carddef.workflow_roles = {'_viewer': role.id} |
|
652 |
carddef.backoffice_submission_roles = [role.id] |
|
653 |
carddef.digest_templates = {'default': 'bla {{ form_var_foo }} xxx'} |
|
654 |
carddef.store() |
|
655 | ||
656 |
carddef.data_class().wipe() |
|
657 | ||
658 |
resp = app.put( |
|
659 |
'/api/cards/test/import-csv', |
|
660 |
params=b'foobar;foobar2\nfirst entry;plop\n', |
|
661 |
headers={'content-type': 'text/csv'}, |
|
662 |
) |
|
663 |
assert resp.json == {'err': 0} |
|
664 |
assert carddef.data_class().count() == 1 |
|
665 |
carddata = carddef.data_class().select()[0] |
|
666 |
assert isinstance(carddata.evolution[0].parts[0], ContentSnapshotPart) |
|
667 |
assert carddata.evolution[0].parts[0].formdef_type == 'carddef' |
|
668 |
assert carddata.evolution[0].parts[0].formdef_id == str(carddef.id) |
|
669 |
assert carddata.evolution[0].parts[0].old_data == {} |
|
670 |
assert carddata.evolution[0].parts[0].new_data == {'0': 'first entry', '1': 'plop'} |
|
671 | ||
672 | ||
673 |
def test_api_card_import_json(pub, user, access, role): |
|
674 |
app = get_app(pub) |
|
675 |
app.set_authorization(('Basic', ('test', '12345'))) |
|
676 | ||
677 |
CardDef.wipe() |
|
678 |
carddef = CardDef() |
|
679 |
carddef.name = 'test' |
|
680 |
carddef.fields = [ |
|
681 |
fields.StringField(id='0', label='foobar', varname='foo'), |
|
682 |
] |
|
683 |
carddef.workflow_roles = {'_viewer': role.id} |
|
684 |
carddef.backoffice_submission_roles = [role.id] |
|
685 |
carddef.store() |
|
686 | ||
687 |
carddef.data_class().wipe() |
|
688 | ||
689 |
data = { |
|
690 |
'data': [ |
|
691 |
{ |
|
692 |
'fields': { |
|
693 |
'foo': 'bar', |
|
694 |
} |
|
695 |
}, |
|
696 |
] |
|
697 |
} |
|
698 |
resp = app.put_json( |
|
699 |
'/api/cards/test/import-json', |
|
700 |
data, |
|
701 |
) |
|
702 |
assert resp.json == {'err': 0} |
|
703 |
assert carddef.data_class().count() == 1 |
|
704 |
carddata = carddef.data_class().select()[0] |
|
705 |
assert isinstance(carddata.evolution[0].parts[0], ContentSnapshotPart) |
|
706 |
assert carddata.evolution[0].parts[0].formdef_type == 'carddef' |
|
707 |
assert carddata.evolution[0].parts[0].formdef_id == str(carddef.id) |
|
708 |
assert carddata.evolution[0].parts[0].old_data == {} |
|
709 |
assert carddata.evolution[0].parts[0].new_data == {'0': 'bar'} |
|
710 | ||
711 | ||
712 |
def test_api_card_submit(pub, user, access, role): |
|
713 |
app = get_app(pub) |
|
714 |
app.set_authorization(('Basic', ('test', '12345'))) |
|
715 | ||
716 |
CardDef.wipe() |
|
717 |
carddef = CardDef() |
|
718 |
carddef.name = 'test' |
|
719 |
carddef.fields = [ |
|
720 |
fields.StringField(id='1', label='foobar', varname='foobar'), |
|
721 |
] |
|
722 |
carddef.backoffice_submission_roles = [role.id] |
|
723 |
carddef.store() |
|
724 |
data_class = carddef.data_class() |
|
725 | ||
726 |
payload = { |
|
727 |
'data': { |
|
728 |
'foobar': 'xxx', |
|
729 |
} |
|
730 |
} |
|
731 |
resp = app.post_json( |
|
732 |
'/api/cards/test/submit', |
|
733 |
payload, |
|
734 |
) |
|
735 |
assert resp.json['err'] == 0 |
|
736 |
carddata = data_class.get(resp.json['data']['id']) |
|
737 |
assert isinstance(carddata.evolution[0].parts[0], ContentSnapshotPart) |
|
738 |
assert carddata.evolution[0].parts[0].formdef_type == 'carddef' |
|
739 |
assert carddata.evolution[0].parts[0].formdef_id == str(carddef.id) |
|
740 |
assert carddata.evolution[0].parts[0].old_data == {} |
|
741 |
assert carddata.evolution[0].parts[0].new_data == {'1': 'xxx'} |
tests/workflow/test_all.py | ||
---|---|---|
73 | 73 |
from wcs.workflows import ( |
74 | 74 |
AbortActionException, |
75 | 75 |
AttachmentEvolutionPart, |
76 |
ContentSnapshotPart, |
|
76 | 77 |
Workflow, |
77 | 78 |
WorkflowBackofficeFieldsFormDef, |
78 | 79 |
WorkflowCriticalityLevel, |
... | ... | |
1343 | 1344 |
assert len(subdir) == 4 |
1344 | 1345 |
assert len(os.listdir(os.path.join(get_publisher().app_dir, 'attachments', subdir))) == 1 |
1345 | 1346 | |
1346 |
assert len(formdata.evolution[-1].parts) == 2
|
|
1347 |
assert isinstance(formdata.evolution[-1].parts[0], AttachmentEvolutionPart)
|
|
1348 |
assert formdata.evolution[-1].parts[0].orig_filename == upload.orig_filename
|
|
1347 |
assert len(formdata.evolution[-1].parts) == 4
|
|
1348 |
assert isinstance(formdata.evolution[-1].parts[0], ContentSnapshotPart)
|
|
1349 |
assert isinstance(formdata.evolution[-1].parts[1], ContentSnapshotPart)
|
|
1349 | 1350 | |
1350 |
assert isinstance(formdata.evolution[-1].parts[1], JournalEvolutionPart) |
|
1351 |
assert len(formdata.evolution[-1].parts[1].content) > 0 |
|
1352 |
comment_view = str(formdata.evolution[-1].parts[1].view()) |
|
1351 |
assert isinstance(formdata.evolution[-1].parts[2], AttachmentEvolutionPart) |
|
1352 |
assert formdata.evolution[-1].parts[2].orig_filename == upload.orig_filename |
|
1353 | ||
1354 |
assert isinstance(formdata.evolution[-1].parts[3], JournalEvolutionPart) |
|
1355 |
assert len(formdata.evolution[-1].parts[3].content) > 0 |
|
1356 |
comment_view = str(formdata.evolution[-1].parts[3].view()) |
|
1353 | 1357 |
assert comment_view == '<p>%s</p>' % comment_text |
1354 | 1358 | |
1355 | 1359 |
if os.path.exists(os.path.join(get_publisher().app_dir, 'attachments')): |
... | ... | |
1422 | 1426 |
register_commenter.comment = 'all' |
1423 | 1427 |
register_commenter.to = None |
1424 | 1428 |
register_commenter.perform(formdata) |
1425 |
assert len(formdata.evolution[-1].parts) == 1
|
|
1429 |
assert len(formdata.evolution[-1].parts) == 2
|
|
1426 | 1430 |
assert display_parts() == ['<p>all</p>'] |
1427 | 1431 | |
1428 | 1432 |
register_commenter.comment = 'to-role' |
1429 | 1433 |
register_commenter.to = [role.id] |
1430 | 1434 |
register_commenter.perform(formdata) |
1431 |
assert len(formdata.evolution[-1].parts) == 2
|
|
1435 |
assert len(formdata.evolution[-1].parts) == 3
|
|
1432 | 1436 |
assert len(display_parts()) == 1 |
1433 | 1437 |
pub._request._user = user |
1434 | 1438 |
assert display_parts() == ['<p>all</p>'] |
... | ... | |
1439 | 1443 |
register_commenter.comment = 'to-submitter' |
1440 | 1444 |
register_commenter.to = ['_submitter'] |
1441 | 1445 |
register_commenter.perform(formdata) |
1442 |
assert len(formdata.evolution[-1].parts) == 3
|
|
1446 |
assert len(formdata.evolution[-1].parts) == 4
|
|
1443 | 1447 |
assert display_parts() == ['<p>all</p>'] |
1444 | 1448 |
formdata.user_id = user.id |
1445 | 1449 |
assert display_parts() == ['<p>all</p>', '<p>to-submitter</p>'] |
... | ... | |
1447 | 1451 |
register_commenter.comment = 'to-role-or-submitter' |
1448 | 1452 |
register_commenter.to = [role.id, '_submitter'] |
1449 | 1453 |
register_commenter.perform(formdata) |
1450 |
assert len(formdata.evolution[-1].parts) == 4
|
|
1454 |
assert len(formdata.evolution[-1].parts) == 5
|
|
1451 | 1455 |
assert display_parts() == ['<p>all</p>', '<p>to-submitter</p>', '<p>to-role-or-submitter</p>'] |
1452 | 1456 |
formdata.user_id = None |
1453 | 1457 |
assert display_parts() == ['<p>all</p>'] |
... | ... | |
1464 | 1468 |
register_commenter.comment = 'd1' |
1465 | 1469 |
register_commenter.to = [role2.id] |
1466 | 1470 |
register_commenter.perform(formdata) |
1467 |
assert len(formdata.evolution[-1].parts) == 5
|
|
1471 |
assert len(formdata.evolution[-1].parts) == 6
|
|
1468 | 1472 |
assert display_parts() == [ |
1469 | 1473 |
'<p>all</p>', |
1470 | 1474 |
'<p>to-role</p>', |
... | ... | |
1476 | 1480 |
register_commenter2.to = [role.id, '_submitter'] |
1477 | 1481 |
user.roles = [role.id, role2.id] |
1478 | 1482 |
register_commenter2.perform(formdata) |
1479 |
assert len(formdata.evolution[-1].parts) == 6
|
|
1483 |
assert len(formdata.evolution[-1].parts) == 7
|
|
1480 | 1484 |
assert '<p>d1</p>' in [str(x) for x in display_parts()] |
1481 | 1485 |
assert '<p>d2</p>' in [str(x) for x in display_parts()] |
1482 | 1486 | |
... | ... | |
1547 | 1551 |
register_commenter.to = [role.id, '_submitter'] |
1548 | 1552 |
register_commenter.perform(formdata) |
1549 | 1553 | |
1550 |
assert len(formdata.evolution[-1].parts) == 8
|
|
1554 |
assert len(formdata.evolution[-1].parts) == 9
|
|
1551 | 1555 | |
1552 | 1556 |
assert user.roles == [] |
1553 | 1557 |
assert len(display_parts()) == 2 |
... | ... | |
2192 | 2196 |
assert fbo1.get_content().startswith(b'<?xml') |
2193 | 2197 |
# nothing else is stored |
2194 | 2198 |
assert formdata.workflow_data is None |
2195 |
assert not formdata.evolution[-1].parts
|
|
2199 |
assert isinstance(formdata.evolution[-1].parts[0], ContentSnapshotPart)
|
|
2196 | 2200 | |
2197 | 2201 |
# store in backoffice file field + varname |
2198 | 2202 |
formdata = formdef.data_class()() |
... | ... | |
3673 | 3677 |
item.perform(formdata) |
3674 | 3678 | |
3675 | 3679 |
assert formdata.evolution[-1].parts[-1].base_filename == 'template.odt' |
3676 |
with zipfile.ZipFile(formdata.evolution[-1].parts[0].get_file_path(), mode='r') as zfile:
|
|
3680 |
with zipfile.ZipFile(formdata.evolution[-1].parts[-1].get_file_path(), mode='r') as zfile:
|
|
3677 | 3681 |
zinfo = zfile.getinfo('Pictures/10000000000000320000003276E9D46581B55C88.jpg') |
3678 | 3682 |
# check the image has been replaced by the one from the formdata |
3679 | 3683 |
assert zinfo.file_size == len(image_data) |
... | ... | |
3688 | 3692 | |
3689 | 3693 |
item.perform(formdata) |
3690 | 3694 | |
3691 |
with zipfile.ZipFile(formdata.evolution[-1].parts[0].get_file_path(), mode='r') as zfile:
|
|
3695 |
with zipfile.ZipFile(formdata.evolution[-1].parts[-1].get_file_path(), mode='r') as zfile:
|
|
3692 | 3696 |
zinfo = zfile.getinfo('Pictures/10000000000000320000003276E9D46581B55C88.jpg') |
3693 | 3697 |
# check the original image has been left |
3694 | 3698 |
assert zinfo.file_size == 580 |
... | ... | |
3732 | 3736 |
item.perform(formdata) |
3733 | 3737 | |
3734 | 3738 |
assert formdata.evolution[-1].parts[-1].base_filename == 'template.odt' |
3735 |
with zipfile.ZipFile(formdata.evolution[-1].parts[0].get_file_path(), mode='r') as zfile:
|
|
3739 |
with zipfile.ZipFile(formdata.evolution[-1].parts[-1].get_file_path(), mode='r') as zfile:
|
|
3736 | 3740 |
# base template use a jpg images and export_to_model does not rename it |
3737 | 3741 |
# event when content is PNG, but it still works inside LibreOffice |
3738 | 3742 |
# which ignores the filename extension. |
... | ... | |
3839 | 3843 |
item.convert_to_pdf = False |
3840 | 3844 |
item.perform(formdata) |
3841 | 3845 | |
3842 |
with open(formdata.evolution[0].parts[0].get_file_path(), 'rb') as fd:
|
|
3846 |
with open(formdata.evolution[0].parts[-1].get_file_path(), 'rb') as fd:
|
|
3843 | 3847 |
with zipfile.ZipFile(fd) as zout: |
3844 | 3848 |
new_content = zout.read('content.xml') |
3845 | 3849 |
assert b'>foo-export-to-template-with-django<' in new_content |
... | ... | |
3848 | 3852 |
formdef.store() |
3849 | 3853 |
item.perform(formdata) |
3850 | 3854 | |
3851 |
with open(formdata.evolution[0].parts[1].get_file_path(), 'rb') as fd: |
|
3855 |
with open(formdata.evolution[0].parts[-1].get_file_path(), 'rb') as fd:
|
|
3852 | 3856 |
with zipfile.ZipFile(fd) as zout: |
3853 | 3857 |
new_content = zout.read('content.xml') |
3854 | 3858 |
assert b'>Name with a \' simple quote<' in new_content |
... | ... | |
3857 | 3861 |
formdef.store() |
3858 | 3862 |
item.perform(formdata) |
3859 | 3863 | |
3860 |
with open(formdata.evolution[0].parts[2].get_file_path(), 'rb') as fd:
|
|
3864 |
with open(formdata.evolution[0].parts[-1].get_file_path(), 'rb') as fd:
|
|
3861 | 3865 |
with zipfile.ZipFile(fd) as zout: |
3862 | 3866 |
new_content = zout.read('content.xml') |
3863 | 3867 |
assert b'>A <> name<' in new_content |
... | ... | |
3994 | 3998 |
item.convert_to_pdf = False |
3995 | 3999 |
item.perform(formdata) |
3996 | 4000 | |
3997 |
with open(formdata.evolution[0].parts[0].get_file_path(), 'rb') as fd:
|
|
4001 |
with open(formdata.evolution[0].parts[-1].get_file_path(), 'rb') as fd:
|
|
3998 | 4002 |
with zipfile.ZipFile(fd) as zout: |
3999 | 4003 |
new_content = force_text(zout.read('content.xml')) |
4000 | 4004 |
# section content has been removed |
... | ... | |
4018 | 4022 |
assert 'XfooY, Xfoo2Y' in new_content |
4019 | 4023 | |
4020 | 4024 |
if filename == 'template-form-details-no-styles.odt': |
4021 |
with open(formdata.evolution[0].parts[0].get_file_path(), 'rb') as fd:
|
|
4025 |
with open(formdata.evolution[0].parts[-1].get_file_path(), 'rb') as fd:
|
|
4022 | 4026 |
with zipfile.ZipFile(fd) as zout: |
4023 | 4027 |
new_styles = force_text(zout.read('styles.xml')) |
4024 | 4028 |
assert 'Field_20_Label' in new_styles |
... | ... | |
4964 | 4968 |
# carddef workflow, with global action to increment a counter in its |
4965 | 4969 |
# backoffice fields. |
4966 | 4970 |
carddef_wf = Workflow(name='Carddef Workflow') |
4971 |
carddef_wf.add_status('New') |
|
4967 | 4972 |
carddef_wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(carddef_wf) |
4968 | 4973 |
carddef_wf.backoffice_fields_formdef.fields = [ |
4969 | 4974 |
StringField(id='bo0', varname='bo', type='string', label='bo variable'), |
... | ... | |
4988 | 4993 |
# and sample carddata |
4989 | 4994 |
carddata = carddef.data_class()() |
4990 | 4995 |
carddata.data = {'0': 'Text'} |
4996 |
carddata.just_created() |
|
4991 | 4997 |
carddata.store() |
4992 | 4998 | |
4993 | 4999 |
# formdef workflow that will trigger the global action |
... | ... | |
5048 | 5054 | |
5049 | 5055 |
# carddef workflow, with global action to set a value in a backoffice field |
5050 | 5056 |
carddef_wf = Workflow(name='Carddef Workflow') |
5057 |
carddef_wf.add_status('New') |
|
5051 | 5058 |
carddef_wf.backoffice_fields_formdef = WorkflowBackofficeFieldsFormDef(carddef_wf) |
5052 | 5059 |
carddef_wf.backoffice_fields_formdef.fields = [ |
5053 | 5060 |
StringField(id='bo0', varname='bo', type='string', label='bo variable'), |
... | ... | |
5072 | 5079 |
# and sample carddata |
5073 | 5080 |
carddata = carddef.data_class()() |
5074 | 5081 |
carddata.data = {'0': 'Text'} |
5082 |
carddata.just_created() |
|
5075 | 5083 |
carddata.store() |
5076 | 5084 | |
5077 | 5085 |
# formdef workflow that will trigger the global action |
... | ... | |
5149 | 5157 |
for i in range(1, 4): |
5150 | 5158 |
carddata = carddef.data_class()() |
5151 | 5159 |
carddata.data = {'0': 'Text %s' % i} |
5160 |
carddata.just_created() |
|
5152 | 5161 |
carddata.store() |
5153 | 5162 | |
5154 | 5163 |
# formdef workflow that will trigger the global action |
wcs/api.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 |
import copy |
|
17 | 18 |
import datetime |
18 | 19 |
import json |
19 | 20 |
import re |
... | ... | |
40 | 41 |
from wcs.qommon import get_cfg |
41 | 42 |
from wcs.qommon.afterjobs import AfterJob |
42 | 43 |
from wcs.roles import logged_users_role |
44 |
from wcs.workflows import ContentSnapshotPart |
|
43 | 45 | |
44 | 46 |
from .backoffice.data_management import CardPage as BackofficeCardPage |
45 | 47 |
from .backoffice.management import FormPage as BackofficeFormPage |
... | ... | |
174 | 176 |
if 'data' not in json_input: |
175 | 177 |
raise RequestError('missing data entry in payload') |
176 | 178 |
data = posted_json_data_to_formdata_data(self.formdef, json_input['data']) |
179 |
old_data = copy.deepcopy(self.formdata.data) |
|
177 | 180 |
self.formdata.data.update(data) |
178 | 181 |
self.formdata.store() |
179 | 182 | |
180 | 183 |
if item.status: |
181 | 184 |
self.formdata.jump_status(item.status) |
182 | 185 |
self.formdata.perform_workflow(event=('api-post-edit-action', item.id)) |
186 |
evo = self.formdata.evolution[-1] |
|
187 |
evo.add_part(ContentSnapshotPart(formdata=self.formdata, old_data=old_data)) |
|
188 |
self.formdata.store() |
|
183 | 189 | |
184 | 190 |
return json.dumps({'err': 0, 'data': {'id': str(self.formdata.id)}}) |
185 | 191 |
wcs/formdata.py | ||
---|---|---|
492 | 492 |
return None |
493 | 493 | |
494 | 494 |
def just_created(self): |
495 |
from wcs.workflows import ContentSnapshotPart |
|
496 | ||
495 | 497 |
self.receipt_time = time.localtime() |
496 | 498 |
self.status = 'wf-%s' % self.formdef.workflow.possible_status[0].id |
497 | 499 |
# we add the initial status to the history, this makes it more readable |
... | ... | |
502 | 504 |
evo.time = self.receipt_time |
503 | 505 |
evo.status = self.status |
504 | 506 |
self.evolution = [evo] |
507 |
evo.add_part(ContentSnapshotPart(formdata=self, old_data={})) |
|
505 | 508 | |
506 | 509 |
def set_auto_fields(self, *args, **kwargs): |
507 | 510 |
fields = {} |
... | ... | |
760 | 763 |
return None |
761 | 764 | |
762 | 765 |
def jump_status(self, status_id, user_id=None): |
763 |
from wcs.workflows import ActionsTracingEvolutionPart |
|
766 |
from wcs.workflows import ActionsTracingEvolutionPart, ContentSnapshotPart
|
|
764 | 767 | |
765 | 768 |
if status_id == '_previous': |
766 | 769 |
previous_status = self.pop_previous_marked_status() |
... | ... | |
777 | 780 |
and self.evolution[-1].status == status |
778 | 781 |
and not self.evolution[-1].comment |
779 | 782 |
and not [ |
780 |
x for x in self.evolution[-1].parts or [] if not isinstance(x, ActionsTracingEvolutionPart) |
|
783 |
x |
|
784 |
for x in self.evolution[-1].parts or [] |
|
785 |
if not isinstance(x, (ActionsTracingEvolutionPart, ContentSnapshotPart)) |
|
781 | 786 |
] |
782 | 787 |
): |
783 | 788 |
# if status do not change and last evolution is empty, |
wcs/forms/root.py | ||
---|---|---|
43 | 43 |
from wcs.qommon.storage import Equal, NothingToUpdate |
44 | 44 |
from wcs.roles import logged_users_role |
45 | 45 |
from wcs.variables import LazyFormDef |
46 |
from wcs.workflows import Workflow, WorkflowBackofficeFieldsFormDef, WorkflowStatusItem |
|
46 |
from wcs.workflows import ContentSnapshotPart, Workflow, WorkflowBackofficeFieldsFormDef, WorkflowStatusItem
|
|
47 | 47 | |
48 | 48 |
from ..qommon import _, emails, errors, get_cfg, misc, ngettext, template |
49 | 49 |
from ..qommon.admin.emails import EmailsDirectory |
... | ... | |
1647 | 1647 |
for k, v in self.edited_data.data.items(): |
1648 | 1648 |
if k.startswith(WorkflowBackofficeFieldsFormDef.field_prefix): |
1649 | 1649 |
new_data[k] = v |
1650 |
old_data = copy.deepcopy(self.edited_data.data) |
|
1650 | 1651 |
self.edited_data.data = new_data |
1651 | 1652 |
if getattr(self, 'selected_user_id', None): |
1652 | 1653 |
# user selection in backoffice |
1653 | 1654 |
self.edited_data.user_id = self.selected_user_id |
1655 |
evo = self.edited_data.evolution[-1] |
|
1656 |
evo.add_part(ContentSnapshotPart(formdata=self.edited_data, old_data=old_data)) |
|
1654 | 1657 |
self.edited_data.store() |
1655 | 1658 |
# remove previous vars and formdata from substitution variables |
1656 | 1659 |
self.clean_submission_context() |
wcs/wf/backoffice_fields.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 |
import copy |
|
17 | 18 |
import xml.etree.ElementTree as ET |
18 | 19 | |
19 | 20 |
from quixote import get_publisher |
... | ... | |
21 | 22 | |
22 | 23 |
from wcs.fields import SetValueError, WidgetField |
23 | 24 |
from wcs.wf.profile import FieldNode |
24 |
from wcs.workflows import WorkflowStatusItem, register_item_class |
|
25 |
from wcs.workflows import ContentSnapshotPart, WorkflowStatusItem, register_item_class
|
|
25 | 26 | |
26 | 27 |
from ..qommon import _ |
27 | 28 |
from ..qommon.form import ( |
... | ... | |
137 | 138 |
def perform(self, formdata): |
138 | 139 |
if not self.fields: |
139 | 140 |
return |
141 | ||
142 |
old_data = copy.deepcopy(formdata.data) |
|
140 | 143 |
for field in self.fields: |
141 | 144 |
try: |
142 | 145 |
formdef_field = [ |
... | ... | |
203 | 206 |
# and backoffice field values can be used in subsequent fields. |
204 | 207 |
formdata.store() |
205 | 208 | |
209 |
evo = formdata.evolution[-1] |
|
210 |
evo.add_part(ContentSnapshotPart(formdata=formdata, old_data=old_data)) |
|
211 |
formdata.store() |
|
212 | ||
206 | 213 |
def fields_export_to_xml(self, item, charset, include_id=False): |
207 | 214 |
if not self.fields: |
208 | 215 |
return |
wcs/wf/edit_carddata.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 |
import copy |
|
18 |
import time |
|
19 | ||
17 | 20 |
from quixote import get_publisher |
18 | 21 | |
22 |
from wcs.formdata import Evolution |
|
19 | 23 |
from wcs.qommon import _ |
20 | 24 |
from wcs.wf.create_carddata import CreateCarddataWorkflowStatusItem |
21 | 25 |
from wcs.wf.external_workflow import ExternalWorkflowGlobalAction |
22 |
from wcs.workflows import register_item_class |
|
26 |
from wcs.workflows import ContentSnapshotPart, register_item_class
|
|
23 | 27 | |
24 | 28 | |
25 | 29 |
class EditCarddataWorkflowStatusItem(CreateCarddataWorkflowStatusItem, ExternalWorkflowGlobalAction): |
... | ... | |
49 | 53 |
formdata.store() |
50 | 54 | |
51 | 55 |
for target_data in self.iter_target_datas(formdata, carddef): |
56 |
old_data = copy.deepcopy(target_data.data) |
|
52 | 57 |
self.apply_mappings(dest=target_data, src=formdata) |
53 | 58 |
with get_publisher().substitutions.freeze(): |
59 |
evo = Evolution() |
|
60 |
evo.time = time.localtime() |
|
61 |
evo.status = target_data.status |
|
62 |
target_data.evolution.append(evo) |
|
63 |
evo.add_part(ContentSnapshotPart(formdata=target_data, old_data=old_data)) |
|
54 | 64 |
target_data.store() |
55 | 65 | |
56 | 66 |
# update local object as it may have modified itself |
wcs/workflows.py | ||
---|---|---|
16 | 16 | |
17 | 17 |
import base64 |
18 | 18 |
import collections |
19 |
import copy |
|
19 | 20 |
import datetime |
20 | 21 |
import glob |
21 | 22 |
import itertools |
... | ... | |
27 | 28 |
from importlib import import_module |
28 | 29 | |
29 | 30 |
from django.utils.encoding import force_text |
31 |
from django.utils.timezone import now |
|
30 | 32 |
from quixote import get_publisher, get_request, get_response |
31 | 33 |
from quixote.html import TemplateIO, htmltext |
32 | 34 | |
... | ... | |
452 | 454 |
return real_action |
453 | 455 | |
454 | 456 | |
457 |
class ContentSnapshotPart(EvolutionPart): |
|
458 |
def __init__(self, formdata, old_data): |
|
459 |
self.datetime = now() |
|
460 |
self.formdef_type = formdata.formdef.xml_root_node |
|
461 |
self.formdef_id = formdata.formdef.id |
|
462 |
self.old_data = old_data |
|
463 |
self.new_data = copy.deepcopy(formdata.data) |
|
464 | ||
465 | ||
455 | 466 |
class DuplicateGlobalActionNameError(Exception): |
456 | 467 |
pass |
457 | 468 | |
458 |
- |