0001-admin-protect-datasources-in-use-from-deletion-or-sl.patch
tests/test_admin_pages.py | ||
---|---|---|
4800 | 4800 |
data_source.data_source = {'type': 'formula', 'value': '[]'} |
4801 | 4801 |
data_source.store() |
4802 | 4802 | |
4803 |
FormDef.wipe() |
|
4803 | 4804 |
app = login(get_app(pub)) |
4804 | 4805 |
resp = app.get('/backoffice/settings/data-sources/1/') |
4805 | 4806 | |
... | ... | |
4855 | 4856 |
resp = resp.follow() |
4856 | 4857 |
assert NamedDataSource.count() == 0 |
4857 | 4858 | |
4859 |
def test_data_sources_in_use_delete(pub): |
|
4860 |
create_superuser(pub) |
|
4861 |
NamedDataSource.wipe() |
|
4862 |
category = NamedDataSource(name='foobar') |
|
4863 |
category.store() |
|
4864 | ||
4865 |
FormDef.wipe() |
|
4866 |
formdef = FormDef() |
|
4867 |
formdef.name = 'form title' |
|
4868 |
formdef.fields = [ |
|
4869 |
fields.ItemField(id='0', label='string', type='item', |
|
4870 |
data_source={'type': 'foobar'}), |
|
4871 |
] |
|
4872 |
formdef.store() |
|
4873 | ||
4874 |
app = login(get_app(pub)) |
|
4875 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4876 |
resp = resp.click(href='delete') |
|
4877 |
assert 'This datasource is still used in some formularies.' in resp.text |
|
4878 |
assert 'delete-button' not in resp.text |
|
4879 | ||
4880 |
formdef.fields = [] |
|
4881 |
formdef.store() |
|
4882 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4883 |
resp = resp.click(href='delete') |
|
4884 |
assert 'delete-button' in resp.text |
|
4885 | ||
4858 | 4886 |
def test_data_sources_edit_slug(pub): |
4859 | 4887 |
create_superuser(pub) |
4860 | 4888 |
NamedDataSource.wipe() |
... | ... | |
4889 | 4917 |
resp = resp.forms[0].submit('submit') |
4890 | 4918 |
assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/' |
4891 | 4919 | |
4920 |
def test_data_sources_in_use_edit_slug(pub): |
|
4921 |
create_superuser(pub) |
|
4922 |
NamedDataSource.wipe() |
|
4923 |
data_source = NamedDataSource(name='foobar') |
|
4924 |
data_source.data_source = {'type': 'formula', 'value': '[]'} |
|
4925 |
data_source.store() |
|
4926 |
assert NamedDataSource.get(1).slug == 'foobar' |
|
4927 | ||
4928 |
FormDef.wipe() |
|
4929 |
formdef = FormDef() |
|
4930 |
formdef.name = 'form title' |
|
4931 |
formdef.fields = [ |
|
4932 |
fields.ItemField(id='0', label='string', type='item', |
|
4933 |
data_source={'type': 'foobar'}), |
|
4934 |
] |
|
4935 |
formdef.store() |
|
4936 | ||
4937 |
app = login(get_app(pub)) |
|
4938 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4939 |
resp = resp.click(href='edit') |
|
4940 |
assert 'form_slug' not in resp.text |
|
4941 | ||
4942 |
formdef.fields = [] |
|
4943 |
formdef.store() |
|
4944 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4945 |
resp = resp.click(href='edit') |
|
4946 |
assert 'form_slug' in resp.text |
|
4947 | ||
4892 | 4948 |
def test_wscalls_new(pub): |
4893 | 4949 |
create_superuser(pub) |
4894 | 4950 |
NamedWsCall.wipe() |
tests/test_datasource.py | ||
---|---|---|
477 | 477 |
assert data_sources.get_structured_items({'type': 'foobar'}) == [ |
478 | 478 |
{'id': '1', 'text': 'foo'}, {'id': '2', 'text': 'bar'}] |
479 | 479 |
assert urlopen.call_count == 3 |
480 | ||
481 |
def test_named_datasource_in_formdef(): |
|
482 |
from wcs.formdef import FormDef |
|
483 |
from wcs.carddef import CardDef |
|
484 |
from wcs.wf.form import WorkflowFormFieldsFormDef |
|
485 |
from wcs.workflows import (Workflow, WorkflowBackofficeFieldsFormDef, |
|
486 |
WorkflowVariablesFieldsFormDef) |
|
487 |
class NotWidget(object): |
|
488 |
data_source={'type': 'foobar'} |
|
489 | ||
490 |
datasource = NamedDataSource(name='foobar') |
|
491 |
datasource.data_source = {'type': 'json', 'value': 'http://whatever/'} |
|
492 |
datasource.store() |
|
493 | ||
494 |
wf = Workflow('foo') |
|
495 |
for formdef in [FormDef(), CardDef(), |
|
496 |
WorkflowFormFieldsFormDef(item=None), |
|
497 |
WorkflowVariablesFieldsFormDef(wf), |
|
498 |
WorkflowVariablesFieldsFormDef(wf)]: |
|
499 |
assert not datasource.is_used_in_formdef(formdef) |
|
500 |
formdef.fields = [ |
|
501 |
fields.ItemField(id='0', label='string', type='item', |
|
502 |
data_source={'type': 'foobar'}), |
|
503 |
] |
|
504 |
assert datasource.is_used_in_formdef(formdef) |
|
505 |
formdef.fields = [NotWidget()] |
|
506 |
assert not datasource.is_used_in_formdef(formdef) |
wcs/admin/data_sources.py | ||
---|---|---|
25 | 25 |
from ..qommon.backoffice.menu import html_top |
26 | 26 |
from wcs.data_sources import (NamedDataSource, DataSourceSelectionWidget, |
27 | 27 |
get_structured_items) |
28 |
from wcs.formdef import FormDef |
|
28 |
from wcs.formdef import FormDef, get_formdefs_of_all_kinds
|
|
29 | 29 | |
30 | 30 |
class NamedDataSourceUI(object): |
31 | 31 |
def __init__(self, datasource): |
... | ... | |
33 | 33 |
if self.datasource is None: |
34 | 34 |
self.datasource = NamedDataSource() |
35 | 35 | |
36 |
def is_used(self): |
|
37 |
for formdef in get_formdefs_of_all_kinds(ignore_errors=True, ignore_migration=True): |
|
38 |
if self.datasource.is_used_in_formdef(formdef): |
|
39 |
return True |
|
40 |
return False |
|
41 | ||
36 | 42 |
def get_form(self): |
37 | 43 |
form = Form(enctype='multipart/form-data', |
38 | 44 |
advanced_label=_('Additional options')) |
... | ... | |
78 | 84 |
'data-dynamic-display-child-of': 'data_source$type', |
79 | 85 |
'data-dynamic-display-value': 'json', |
80 | 86 |
}) |
81 |
if self.datasource.slug: |
|
87 |
if self.datasource.slug and not self.is_used():
|
|
82 | 88 |
form.add(StringWidget, 'slug', |
83 | 89 |
value=self.datasource.slug, |
84 | 90 |
title=_('Identifier'), |
85 |
hint=_('Beware it is risky to change it'), |
|
86 | 91 |
required=True, advanced=True, |
87 | 92 |
) |
88 | 93 |
form.add_submit('submit', _('Submit')) |
... | ... | |
135 | 140 |
def usage_in_formdefs(self): |
136 | 141 |
formdefs = [] |
137 | 142 |
for formdef in FormDef.select(ignore_errors=True, ignore_migration=True, order_by='name'): |
138 |
for field in (formdef.fields or []): |
|
139 |
data_source = getattr(field, 'data_source', None) |
|
140 |
if not data_source: |
|
141 |
continue |
|
142 |
if data_source.get('type') == self.datasource.slug: |
|
143 |
formdefs.append(formdef) |
|
144 |
break |
|
145 |
else: |
|
146 |
continue |
|
143 |
if self.datasource.is_used_in_formdef(formdef): |
|
144 |
formdefs.append(formdef) |
|
147 | 145 |
return formdefs |
148 | 146 | |
149 | 147 |
def preview_block(self): |
... | ... | |
199 | 197 | |
200 | 198 |
def delete(self): |
201 | 199 |
form = Form(enctype='multipart/form-data') |
202 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
200 |
if not self.datasource_ui.is_used(): |
|
201 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
203 | 202 |
'You are about to irrevocably delete this data source.'))) |
204 |
form.add_submit('delete', _('Submit')) |
|
203 |
form.add_submit('delete', _('Submit')) |
|
204 |
else: |
|
205 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
206 |
'This datasource is still used in some formularies.'))) |
|
205 | 207 |
form.add_submit('cancel', _('Cancel')) |
206 | 208 |
if form.get_widget('cancel').parse(): |
207 | 209 |
return redirect('..') |
wcs/data_sources.py | ||
---|---|---|
419 | 419 |
def humanized_cache_duration(self): |
420 | 420 |
return seconds2humanduration(int(self.cache_duration)) |
421 | 421 | |
422 |
def is_used_in_formdef(self, formdef): |
|
423 |
from .fields import WidgetField |
|
424 |
for field in (f for f in formdef.fields or [] if isinstance(f, WidgetField)): |
|
425 |
data_source = getattr(field, 'data_source', None) |
|
426 |
if not data_source: |
|
427 |
continue |
|
428 |
if data_source.get('type') == self.slug: |
|
429 |
return True |
|
430 |
return False |
|
431 | ||
422 | 432 | |
423 | 433 |
class DataSourcesSubstitutionProxy(object): |
424 | 434 |
def __getattr__(self, attr): |
425 |
- |