0001-admin-protect-datasources-in-use-from-deletion-or-sl.patch
tests/test_admin_pages.py | ||
---|---|---|
4817 | 4817 |
data_source.data_source = {'type': 'formula', 'value': '[]'} |
4818 | 4818 |
data_source.store() |
4819 | 4819 | |
4820 |
FormDef.wipe() |
|
4820 | 4821 |
app = login(get_app(pub)) |
4821 | 4822 |
resp = app.get('/backoffice/settings/data-sources/1/') |
4822 | 4823 | |
... | ... | |
4872 | 4873 |
resp = resp.follow() |
4873 | 4874 |
assert NamedDataSource.count() == 0 |
4874 | 4875 | |
4876 |
def test_data_sources_in_use_delete(pub): |
|
4877 |
create_superuser(pub) |
|
4878 |
NamedDataSource.wipe() |
|
4879 |
category = NamedDataSource(name='foobar') |
|
4880 |
category.store() |
|
4881 | ||
4882 |
FormDef.wipe() |
|
4883 |
formdef = FormDef() |
|
4884 |
formdef.name = 'form title' |
|
4885 |
formdef.fields = [ |
|
4886 |
fields.ItemField(id='0', label='string', type='item', |
|
4887 |
data_source={'type': 'foobar'}), |
|
4888 |
] |
|
4889 |
formdef.store() |
|
4890 | ||
4891 |
app = login(get_app(pub)) |
|
4892 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4893 |
resp = resp.click(href='delete') |
|
4894 |
assert 'This datasource is still used, it cannot be deleted.' in resp.text |
|
4895 |
assert 'delete-button' not in resp.text |
|
4896 | ||
4897 |
formdef.fields = [] |
|
4898 |
formdef.store() |
|
4899 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4900 |
resp = resp.click(href='delete') |
|
4901 |
assert 'delete-button' in resp.text |
|
4902 | ||
4875 | 4903 |
def test_data_sources_edit_slug(pub): |
4876 | 4904 |
create_superuser(pub) |
4877 | 4905 |
NamedDataSource.wipe() |
... | ... | |
4906 | 4934 |
resp = resp.forms[0].submit('submit') |
4907 | 4935 |
assert resp.location == 'http://example.net/backoffice/settings/data-sources/1/' |
4908 | 4936 | |
4937 |
def test_data_sources_in_use_edit_slug(pub): |
|
4938 |
create_superuser(pub) |
|
4939 |
NamedDataSource.wipe() |
|
4940 |
data_source = NamedDataSource(name='foobar') |
|
4941 |
data_source.data_source = {'type': 'formula', 'value': '[]'} |
|
4942 |
data_source.store() |
|
4943 |
assert NamedDataSource.get(1).slug == 'foobar' |
|
4944 | ||
4945 |
FormDef.wipe() |
|
4946 |
formdef = FormDef() |
|
4947 |
formdef.name = 'form title' |
|
4948 |
formdef.fields = [ |
|
4949 |
fields.ItemField(id='0', label='string', type='item', |
|
4950 |
data_source={'type': 'foobar'}), |
|
4951 |
] |
|
4952 |
formdef.store() |
|
4953 | ||
4954 |
app = login(get_app(pub)) |
|
4955 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4956 |
resp = resp.click(href='edit') |
|
4957 |
assert 'form_slug' not in resp.text |
|
4958 | ||
4959 |
formdef.fields = [] |
|
4960 |
formdef.store() |
|
4961 |
resp = app.get('/backoffice/settings/data-sources/1/') |
|
4962 |
resp = resp.click(href='edit') |
|
4963 |
assert 'form_slug' in resp.text |
|
4964 | ||
4909 | 4965 |
def test_wscalls_new(pub): |
4910 | 4966 |
create_superuser(pub) |
4911 | 4967 |
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 |
datasource = NamedDataSource(name='foobar') |
|
484 |
datasource.data_source = {'type': 'json', 'value': 'http://whatever/'} |
|
485 |
datasource.store() |
|
486 |
assert datasource.slug == 'foobar' |
|
487 | ||
488 |
formdef = FormDef() |
|
489 |
assert not datasource.is_used_in_formdef(formdef) |
|
490 | ||
491 |
formdef.fields = [ |
|
492 |
fields.ItemField(id='0', label='string', type='item', |
|
493 |
data_source={'type': 'foobar'}), |
|
494 |
] |
|
495 |
assert datasource.is_used_in_formdef(formdef) |
|
496 | ||
497 |
datasource.slug = 'barfoo' |
|
498 |
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(): |
|
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')) |
... | ... | |
138 | 143 |
def usage_in_formdefs(self): |
139 | 144 |
formdefs = [] |
140 | 145 |
for formdef in FormDef.select(ignore_errors=True, ignore_migration=True, order_by='name'): |
141 |
for field in (formdef.fields or []): |
|
142 |
data_source = getattr(field, 'data_source', None) |
|
143 |
if not data_source: |
|
144 |
continue |
|
145 |
if data_source.get('type') == self.datasource.slug: |
|
146 |
formdefs.append(formdef) |
|
147 |
break |
|
148 |
else: |
|
149 |
continue |
|
146 |
if self.datasource.is_used_in_formdef(formdef): |
|
147 |
formdefs.append(formdef) |
|
150 | 148 |
return formdefs |
151 | 149 | |
152 | 150 |
def preview_block(self): |
... | ... | |
202 | 200 | |
203 | 201 |
def delete(self): |
204 | 202 |
form = Form(enctype='multipart/form-data') |
205 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
203 |
if not self.datasource_ui.is_used(): |
|
204 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
206 | 205 |
'You are about to irrevocably delete this data source.'))) |
207 |
form.add_submit('delete', _('Submit')) |
|
206 |
form.add_submit('delete', _('Submit')) |
|
207 |
else: |
|
208 |
form.widgets.append(HtmlWidget('<p>%s</p>' % _( |
|
209 |
'This datasource is still used, it cannot be deleted.'))) |
|
208 | 210 |
form.add_submit('cancel', _('Cancel')) |
209 | 211 |
if form.get_widget('cancel').parse(): |
210 | 212 |
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 formdef.fields or []: |
|
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 |
- |