0001-formdef-add-internal-identifier-attribute-separated-.patch
tests/test_admin_pages.py | ||
---|---|---|
328 | 328 |
assert resp.location == 'http://example.net/backoffice/forms/1/' |
329 | 329 |
resp = resp.follow() |
330 | 330 |
assert FormDef.get(1).name == 'new title' |
331 |
assert FormDef.get(1).url_name == 'new-title' |
|
331 |
assert FormDef.get(1).url_name == 'form-title' |
|
332 |
assert FormDef.get(1).internal_identifier == 'new-title' |
|
332 | 333 | |
333 | 334 |
def test_form_category(pub): |
334 | 335 |
create_superuser(pub) |
... | ... | |
745 | 746 |
resp = resp.forms[0].submit() |
746 | 747 |
assert FormDef.count() == 1 |
747 | 748 | |
748 |
# import the same formdef a second time, make sure the urlname is not
|
|
749 |
# reused |
|
749 |
# import the same formdef a second time, make sure url name and internal
|
|
750 |
# identifier are not reused
|
|
750 | 751 |
resp = app.get('/backoffice/forms/') |
751 | 752 |
resp = resp.click(href='import') |
752 | 753 |
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) |
... | ... | |
754 | 755 |
assert FormDef.count() == 2 |
755 | 756 |
assert FormDef.get(1).url_name == 'form-title' |
756 | 757 |
assert FormDef.get(2).url_name == 'form-title-1' |
758 |
assert FormDef.get(1).internal_identifier == 'form-title' |
|
759 |
assert FormDef.get(2).internal_identifier == 'form-title-1' |
|
757 | 760 | |
758 |
# import a formdef with an url_name that doesn't match its title,
|
|
759 |
# it should be updated to match.
|
|
761 |
# import a formdef with an url name that doesn't match its title,
|
|
762 |
# it should be kept intact.
|
|
760 | 763 |
formdef.url_name = 'xxx-other-form-title' |
761 | 764 |
formdef_xml = ET.tostring(formdef.export_to_xml(include_id=True)) |
762 | 765 | |
... | ... | |
764 | 767 |
resp = resp.click(href='import') |
765 | 768 |
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) |
766 | 769 |
resp = resp.forms[0].submit() |
767 |
assert FormDef.get(3).url_name == 'form-title-2' |
|
770 |
assert FormDef.get(3).url_name == 'xxx-other-form-title' |
|
771 |
assert FormDef.get(3).internal_identifier == 'form-title-2' |
|
768 | 772 | |
769 | 773 |
# import an invalid file |
770 | 774 |
resp = app.get('/backoffice/forms/') |
... | ... | |
1418 | 1422 | |
1419 | 1423 |
app = login(get_app(pub)) |
1420 | 1424 |
resp = app.get('/backoffice/forms/%s/' % formdef_id) |
1421 |
resp = resp.click(href='overwrite') |
|
1425 |
resp = resp.click(href='overwrite', index=0)
|
|
1422 | 1426 |
resp.forms[0]['file'] = Upload('formdef.wcs', formdef_xml) |
1423 | 1427 |
resp = resp.forms[0].submit() |
1424 | 1428 |
assert 'The form removes and changes fields' in resp.body |
tests/test_formdef.py | ||
---|---|---|
1 |
import cPickle |
|
1 | 2 |
import datetime |
2 | 3 |
import json |
3 | 4 |
import sys |
... | ... | |
9 | 10 |
from quixote import cleanup |
10 | 11 |
from wcs import formdef |
11 | 12 |
from wcs.formdef import FormDef |
13 |
from wcs.qommon.http_request import HTTPRequest |
|
12 | 14 |
from wcs.workflows import Workflow |
13 | 15 |
from wcs.fields import StringField, FileField, DateField, ItemField |
14 | 16 | |
15 |
from utilities import create_temporary_pub |
|
17 |
from utilities import create_temporary_pub, clean_temporary_pub
|
|
16 | 18 | |
17 |
def setup_module(module): |
|
18 |
cleanup() |
|
19 |
def pytest_generate_tests(metafunc): |
|
20 |
if 'pub' in metafunc.fixturenames: |
|
21 |
metafunc.parametrize('pub', ['pickle', 'sql'], indirect=True) |
|
19 | 22 | |
20 |
global pub |
|
21 | ||
22 |
pub = create_temporary_pub() |
|
23 |
@pytest.fixture |
|
24 |
def pub(request): |
|
25 |
pub = create_temporary_pub(sql_mode=(request.param == 'sql')) |
|
26 |
req = HTTPRequest(None, {'SCRIPT_NAME': '/', 'SERVER_NAME': 'example.net'}) |
|
27 |
pub.set_app_dir(req) |
|
23 | 28 |
pub.cfg['language'] = {'language': 'en'} |
29 |
pub.write_cfg() |
|
30 | ||
31 |
return pub |
|
24 | 32 | |
25 | 33 |
def teardown_module(module): |
26 |
shutil.rmtree(pub.APP_DIR)
|
|
34 |
clean_temporary_pub()
|
|
27 | 35 | |
28 | 36 | |
29 |
def test_is_disabled(): |
|
37 |
def test_is_disabled(pub):
|
|
30 | 38 |
formdef = FormDef() |
31 | 39 |
assert not formdef.is_disabled() |
32 | 40 | |
... | ... | |
34 | 42 |
assert formdef.is_disabled() |
35 | 43 | |
36 | 44 | |
37 |
def test_is_disabled_publication_date(): |
|
45 |
def test_is_disabled_publication_date(pub):
|
|
38 | 46 |
formdef = FormDef() |
39 | 47 | |
40 | 48 |
formdef.publication_date = '%s-%02d-%02d' % (datetime.datetime.today() - datetime.timedelta(1)).timetuple()[:3] |
... | ... | |
44 | 52 |
assert formdef.is_disabled() |
45 | 53 | |
46 | 54 | |
47 |
def test_is_disabled_expiration_date(): |
|
55 |
def test_is_disabled_expiration_date(pub):
|
|
48 | 56 |
formdef = FormDef() |
49 | 57 | |
50 | 58 |
formdef.expiration_date = '%s-%02d-%02d' % (datetime.datetime.today() - datetime.timedelta(1)).timetuple()[:3] |
... | ... | |
54 | 62 |
assert not formdef.is_disabled() |
55 | 63 | |
56 | 64 | |
57 |
def test_is_disabled_publication_datetime(): |
|
65 |
def test_is_disabled_publication_datetime(pub):
|
|
58 | 66 |
formdef = FormDef() |
59 | 67 | |
60 | 68 |
formdef.publication_date = '%s-%02d-%02d %02d:%02d' % ( |
... | ... | |
66 | 74 |
assert formdef.is_disabled() |
67 | 75 | |
68 | 76 | |
69 |
def test_is_disabled_expiration_datetime(): |
|
77 |
def test_is_disabled_expiration_datetime(pub):
|
|
70 | 78 |
formdef = FormDef() |
71 | 79 | |
72 | 80 |
formdef.expiration_date = '%s-%02d-%02d %02d:%02d' % ( |
... | ... | |
77 | 85 |
datetime.datetime.now() + datetime.timedelta(hours=1)).timetuple()[:5] |
78 | 86 |
assert not formdef.is_disabled() |
79 | 87 | |
80 |
def test_title_change(): |
|
88 |
def test_title_change(pub):
|
|
81 | 89 |
formdef = FormDef() |
82 | 90 |
formdef.name = 'foo' |
83 | 91 |
formdef.store() |
84 | 92 |
assert FormDef.get(formdef.id).name == 'foo' |
85 | 93 |
assert FormDef.get(formdef.id).url_name == 'foo' |
94 |
assert FormDef.get(formdef.id).internal_identifier == 'foo' |
|
86 | 95 | |
87 | 96 |
formdef.name = 'bar' |
88 | 97 |
formdef.store() |
89 | 98 |
assert FormDef.get(formdef.id).name == 'bar' |
90 |
assert FormDef.get(formdef.id).url_name == 'bar' |
|
99 |
assert FormDef.get(formdef.id).url_name == 'foo' |
|
100 |
assert FormDef.get(formdef.id).internal_identifier == 'bar' |
|
91 | 101 | |
92 |
# makes sure the url_name doesn't change if there are submitted forms
|
|
102 |
# makes sure the internal_name doesn't change if there are submitted forms
|
|
93 | 103 |
formdef.data_class()().store() |
94 | 104 |
formdef.name = 'baz' |
95 | 105 |
formdef.store() |
96 | 106 |
assert FormDef.get(formdef.id).name == 'baz' |
97 |
assert FormDef.get(formdef.id).url_name == 'bar' # didn't change
|
|
107 |
assert FormDef.get(formdef.id).internal_identifier == 'bar' # didn't change
|
|
98 | 108 | |
99 |
def test_substitution_variables(): |
|
109 |
def test_substitution_variables(pub):
|
|
100 | 110 |
formdef = FormDef() |
101 | 111 |
formdef.name = 'foo' |
102 | 112 |
formdef.store() |
... | ... | |
121 | 131 |
assert formdef.get_substitution_variables()['form_option_bar'] == 'Bar' |
122 | 132 |
assert formdef.get_substitution_variables()['form_option_bar_raw'] == 'bar' |
123 | 133 | |
124 |
def test_schema_with_date_variable(): |
|
134 |
def test_schema_with_date_variable(pub):
|
|
125 | 135 |
FormDef.wipe() |
126 | 136 |
formdef = FormDef() |
127 | 137 |
formdef.name = 'foo' |
... | ... | |
137 | 147 |
formdef.workflow_options = {'foo': time.gmtime(time.mktime((2016, 4, 2, 0, 0, 0, 0, 0, 0)))} |
138 | 148 |
assert json.loads(formdef.export_to_json())['options']['foo'].startswith('2016-04') |
139 | 149 | |
140 |
def test_substitution_variables_object(): |
|
150 |
def test_substitution_variables_object(pub):
|
|
141 | 151 |
formdef = FormDef() |
142 | 152 |
formdef.name = 'foo' |
143 | 153 |
formdef.store() |
... | ... | |
157 | 167 |
with pytest.raises(AttributeError): |
158 | 168 |
assert substs.foobar |
159 | 169 | |
160 |
def test_file_field_migration(): |
|
170 |
def test_file_field_migration(pub):
|
|
161 | 171 |
pub.cfg['filetypes'] = {1: |
162 | 172 |
{'mimetypes': [ |
163 | 173 |
'application/pdf', |
... | ... | |
185 | 195 |
assert formdef.fields[0].document_type['mimetypes'] == ['image/*', 'application/pdf,application/vnd.oasis.opendocument.text,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document,application/vnd.oasis.opendocument.spreadsheet,application/vnd.ms-excel,application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] |
186 | 196 |
assert formdef.fields[1].document_type['label'] == 'Image files' |
187 | 197 |
assert formdef.fields[0].document_type['label'] == 'Image files, Documents' |
198 | ||
199 |
def test_internal_identifier_migration(pub): |
|
200 |
FormDef.wipe() |
|
201 |
formdef = FormDef() |
|
202 |
formdef.name = 'foo' |
|
203 |
formdef.fields = [] |
|
204 |
formdef.store() |
|
205 | ||
206 |
obj = cPickle.load(open(formdef.get_object_filename())) |
|
207 |
del obj.internal_identifier |
|
208 |
cPickle.dump(obj, open(formdef.get_object_filename(), 'w')) |
|
209 |
assert cPickle.load(open(formdef.get_object_filename())).internal_identifier is None |
|
210 |
assert FormDef.get(formdef.id, ignore_migration=True).internal_identifier is None |
|
211 | ||
212 |
formdef = FormDef.get(formdef.id) |
|
213 |
assert formdef.internal_identifier == 'foo' |
tests/test_sql.py | ||
---|---|---|
569 | 569 | |
570 | 570 |
formdef.name = 'tests2' |
571 | 571 |
formdef.store() |
572 |
assert formdef.url_name == 'tests2'
|
|
572 |
assert formdef.url_name == 'tests' |
|
573 | 573 | |
574 | 574 |
formdef.name = 'tests' |
575 | 575 |
formdef.store() |
wcs/admin/forms.py | ||
---|---|---|
949 | 949 |
return redirect('.') |
950 | 950 | |
951 | 951 |
def overwrite_by_formdef(self, new_formdef): |
952 |
# keep current formdef id, url_name and sql table name |
|
952 |
# keep current formdef id, url_name, internal identifier and sql table name
|
|
953 | 953 |
new_formdef.id = self.formdef.id |
954 |
new_formdef.internal_identifier = self.formdef.internal_identifier |
|
954 | 955 |
new_formdef.url_name = self.formdef.url_name |
955 | 956 |
new_formdef.table_name = self.formdef.table_name |
956 | 957 |
# keep currently assigned category and workflow |
... | ... | |
1552 | 1553 |
form.set_error('file', msg) |
1553 | 1554 |
raise ValueError() |
1554 | 1555 | |
1555 |
formdef.url_name = None # a new one will be set in .store()
|
|
1556 |
formdef.internal_identifier = None # a new one will be set in .store()
|
|
1556 | 1557 |
formdef.disabled = True |
1557 | 1558 |
formdef.store() |
1558 | 1559 |
get_session().message = ('info', |
wcs/formdef.py | ||
---|---|---|
69 | 69 |
description = None |
70 | 70 |
keywords = None |
71 | 71 |
url_name = None |
72 |
internal_identifier = None # mostly for pickle |
|
72 | 73 |
table_name = None # for SQL only |
73 | 74 |
fields = None |
74 | 75 |
category_id = None |
... | ... | |
101 | 102 | |
102 | 103 |
# declarations for serialization |
103 | 104 |
TEXT_ATTRIBUTES = ['name', 'url_name', 'description', 'keywords', |
104 |
'publication_date', 'expiration_date', |
|
105 |
'publication_date', 'expiration_date', 'internal_identifier',
|
|
105 | 106 |
'disabled_redirection',] |
106 | 107 |
BOOLEAN_ATTRIBUTES = ['discussion', 'detailed_emails', 'disabled', |
107 | 108 |
'only_allow_one', 'enable_tracking_codes', 'confirmation', |
... | ... | |
204 | 205 |
changed = True |
205 | 206 |
break |
206 | 207 | |
208 |
if not self.internal_identifier: |
|
209 |
self.internal_identifier = self.url_name |
|
210 |
changed = True |
|
211 | ||
207 | 212 |
for f in self.fields or []: |
208 | 213 |
changed |= f.migrate() |
209 | 214 | |
... | ... | |
238 | 243 |
actions = sql.do_formdef_tables(self) |
239 | 244 |
else: |
240 | 245 |
cls = new.classobj(self.url_name.title(), (FormData,), |
241 |
{'_names': 'form-%s' % self.url_name,
|
|
246 |
{'_names': 'form-%s' % self.internal_identifier,
|
|
242 | 247 |
'_formdef': self}) |
243 | 248 |
actions = [] |
244 | 249 |
setattr(sys.modules['formdef'], self.url_name.title(), cls) |
... | ... | |
264 | 269 |
suffix_no = 0 |
265 | 270 |
while True: |
266 | 271 |
try: |
267 |
formdef = self.get_by_urlname(new_url_name, ignore_migration=True)
|
|
272 |
obj = self.get_on_index(new_url_name, 'url_name', ignore_migration=True)
|
|
268 | 273 |
except KeyError: |
269 | 274 |
break |
270 |
if formdef.id == self.id:
|
|
275 |
if obj.id == self.id:
|
|
271 | 276 |
break |
272 | 277 |
suffix_no += 1 |
273 | 278 |
new_url_name = '%s-%s' % (base_new_url_name, suffix_no) |
274 | 279 |
return new_url_name |
275 | 280 | |
281 |
def get_new_internal_identifier(self): |
|
282 |
new_internal_identifier = simplify(self.name) |
|
283 |
base_new_internal_identifier = new_internal_identifier |
|
284 |
suffix_no = 0 |
|
285 |
while True: |
|
286 |
try: |
|
287 |
formdef = self.get_by_urlname(new_internal_identifier, ignore_migration=True) |
|
288 |
except KeyError: |
|
289 |
break |
|
290 |
if formdef.id == self.id: |
|
291 |
break |
|
292 |
suffix_no += 1 |
|
293 |
new_internal_identifier = '%s-%s' % (base_new_internal_identifier, suffix_no) |
|
294 |
return new_internal_identifier |
|
295 | ||
276 | 296 |
@classmethod |
277 | 297 |
def get_new_id(cls, create=False): |
278 | 298 |
keys = cls.keys() |
... | ... | |
303 | 323 |
sql.formdef_wipe() |
304 | 324 | |
305 | 325 |
def store(self): |
306 |
new_url_name = self.get_new_url_name() |
|
307 |
if not self.url_name: |
|
308 |
self.url_name = new_url_name |
|
309 |
if new_url_name != self.url_name: |
|
310 |
# title changed, url will be changed only if the formdef is |
|
311 |
# currently being imported (self.id is None) or if there are not |
|
312 |
# yet any submitted forms |
|
313 |
data_class = self.data_class() |
|
314 |
if self.id is None or data_class().count() == 0: |
|
315 |
self.url_name = new_url_name |
|
326 |
if self.url_name is None: |
|
327 |
# set url name if it's not yet there |
|
328 |
self.url_name = self.get_new_url_name() |
|
329 |
new_internal_identifier = self.get_new_internal_identifier() |
|
330 |
if not self.internal_identifier: |
|
331 |
self.internal_identifier = new_internal_identifier |
|
332 |
if new_internal_identifier != self.internal_identifier: |
|
333 |
# title changed, internal identifier will be changed only if |
|
334 |
# the formdef is currently being imported (self.id is None) |
|
335 |
# or if there are not yet any submitted forms |
|
336 |
if self.id is None or self.data_class().count() == 0: |
|
337 |
self.internal_identifier = new_internal_identifier |
|
316 | 338 |
self.last_modification_time = time.localtime() |
317 | 339 |
if get_request() and get_request().user: |
318 | 340 |
self.last_modification_user_id = str(get_request().user.id) |
... | ... | |
846 | 868 |
formdef = cls.import_from_xml_tree(tree, charset=charset, |
847 | 869 |
include_id=include_id) |
848 | 870 | |
871 |
if formdef.url_name: |
|
872 |
try: |
|
873 |
obj = cls.get_on_index(formdef.url_name, 'url_name', ignore_migration=True) |
|
874 |
except KeyError: |
|
875 |
pass |
|
876 |
else: |
|
877 |
formdef.url_name = formdef.get_new_url_name() |
|
878 | ||
849 | 879 |
# fix max_field_id if necessary |
850 | 880 |
if formdef.max_field_id is not None: |
851 | 881 |
max_field_id = max([lax_int(x.id) for x in formdef.fields]) |
wcs/sql.py | ||
---|---|---|
762 | 762 |
def do_global_views(conn, cur): |
763 | 763 |
# recreate global views |
764 | 764 |
from wcs.formdef import FormDef |
765 |
view_names = [get_formdef_view_name(x) for x in FormDef.select()] |
|
765 |
view_names = [get_formdef_view_name(x) for x in FormDef.select(ignore_migration=True)]
|
|
766 | 766 | |
767 | 767 |
cur.execute('''SELECT table_name FROM information_schema.views |
768 | 768 |
WHERE table_schema = 'public' |
769 |
- |