0001-cards-empty-digest-template-when-datasource-custom-v.patch
tests/test_cards_admin_pages.py | ||
---|---|---|
137 | 137 |
resp = resp.form.submit('submit').follow() |
138 | 138 | |
139 | 139 | |
140 |
def test_card_digest_template(pub, studio): |
|
141 |
create_superuser(pub) |
|
142 | ||
143 |
CardDef.wipe() |
|
144 |
carddef = CardDef() |
|
145 |
carddef.name = 'foo' |
|
146 |
carddef.fields = [ |
|
147 |
fields.StringField(id='1', label='Test', type='string', varname='foo'), |
|
148 |
] |
|
149 |
carddef.digest_template = 'X{{ form_var_foo }}Y' |
|
150 |
carddef.store() |
|
151 |
carddef.data_class().wipe() |
|
152 |
carddata = carddef.data_class()() |
|
153 |
carddata.data = {'1': 'bar'} |
|
154 |
carddata.store() |
|
155 | ||
156 |
custom_view = pub.custom_view_class() |
|
157 |
custom_view.title = 'card view' |
|
158 |
custom_view.formdef = carddef |
|
159 |
custom_view.columns = {'list': [{'id': 'id'}]} |
|
160 |
custom_view.filters = {'filter-1': True, 'filter-1-value': 'FOO'} |
|
161 |
custom_view.visibility = 'datasource' |
|
162 |
custom_view.store() |
|
163 | ||
164 |
# carddef not used in formdef, it's ok to empty digest_template |
|
165 |
FormDef.wipe() |
|
166 | ||
167 |
app = login(get_app(pub)) |
|
168 |
resp = app.get('/backoffice/cards/%s/options/templates' % carddef.id) |
|
169 |
resp.form['digest_template'] = '' |
|
170 |
resp = resp.form.submit().follow() |
|
171 |
carddef = CardDef.get(carddef.id) |
|
172 |
assert carddef.digest_template is None |
|
173 |
assert 'Existing cards will be updated in the background.' in resp.text |
|
174 | ||
175 |
carddef.digest_template = '{{ form_var_foo }}' |
|
176 |
carddef.store() |
|
177 | ||
178 |
# a formdef using the carddef as datasource |
|
179 |
FormDef.wipe() |
|
180 |
formdef = FormDef() |
|
181 |
formdef.name = 'test card def on data source' |
|
182 |
formdef.fields = [ |
|
183 |
fields.ItemField(id='1', label='item', data_source={'type': 'carddef:foo'}) |
|
184 |
] |
|
185 |
formdef.store() |
|
186 | ||
187 |
# carddef used in formdef, can not empty digest_template |
|
188 |
resp = app.get('/backoffice/cards/%s/options/templates' % carddef.id) |
|
189 |
resp.form['digest_template'] = '' |
|
190 |
resp = resp.form.submit() |
|
191 |
assert 'Can not empty digest template: this card model is used as data source in some forms.' in resp.text |
|
192 |
carddef = CardDef.get(carddef.id) |
|
193 |
assert carddef.digest_template is not None |
|
194 | ||
195 |
# error: not stored, and no after jobs |
|
196 |
resp = app.get('/backoffice/cards/%s/' % carddef.id) |
|
197 |
assert 'Existing cards will be updated in the background.' not in resp.text |
|
198 | ||
199 | ||
140 | 200 |
def test_card_custom_view_data_source(pub, studio): |
141 | 201 |
user = create_superuser(pub) |
142 | 202 |
Role.wipe() |
wcs/admin/forms.py | ||
---|---|---|
40 | 40 |
from wcs.qommon.afterjobs import AfterJob |
41 | 41 | |
42 | 42 |
from wcs.formdef import FormDef, FormdefImportError, FormdefImportRecoverableError |
43 |
from wcs.carddef import CardDef |
|
43 | 44 |
from wcs.categories import Category |
44 | 45 |
from wcs.roles import Role, logged_users_role, get_user_roles |
45 | 46 |
from wcs.workflows import Workflow |
... | ... | |
279 | 280 |
for formdata in self.formdef.data_class().select(order_by='id'): |
280 | 281 |
formdata.store() |
281 | 282 |
job = get_response().add_after_job(N_('Updating digests'), update) |
282 |
get_session().message = ('info', |
|
283 |
_('Existing forms will be updated in the background.')) |
|
283 |
if isinstance(self.formdef, CardDef): |
|
284 |
get_session().message = ('info', |
|
285 |
_('Existing cards will be updated in the background.')) |
|
286 |
else: |
|
287 |
get_session().message = ('info', |
|
288 |
_('Existing forms will be updated in the background.')) |
|
284 | 289 |
return result |
285 | 290 | |
286 | 291 |
def handle(self, form, title): |
... | ... | |
302 | 307 |
for attr in attrs: |
303 | 308 |
widget = form.get_widget(attr) |
304 | 309 |
if widget: |
310 |
if hasattr(self, 'clean_%s' % attr): |
|
311 |
has_error = getattr(self, 'clean_%s' % attr)(form) |
|
312 |
if has_error: |
|
313 |
continue |
|
305 | 314 |
if attr == 'geoloc_label': |
306 | 315 |
if widget.parse(): |
307 | 316 |
self.formdef.geolocations = {'base': widget.parse()} |
... | ... | |
312 | 321 |
if getattr(self.formdef, attr, None) != new_value: |
313 | 322 |
self.changed = True |
314 | 323 |
setattr(self.formdef, attr, new_value) |
315 |
self.formdef.store(comment=_('Changed "%s" parameters') % title) |
|
316 |
return redirect('..') |
|
324 |
if not form.has_errors(): |
|
325 |
self.formdef.store(comment=_('Changed "%s" parameters') % title) |
|
326 |
return redirect('..') |
|
317 | 327 | |
318 | 328 |
html_top('forms', title=self.formdef.name) |
319 | 329 |
r = TemplateIO(html=True) |
... | ... | |
321 | 331 |
r += form.render() |
322 | 332 |
return r.getvalue() |
323 | 333 | |
334 |
def clean_digest_template(self, form): |
|
335 |
if not isinstance(self.formdef, CardDef): |
|
336 |
return False |
|
337 | ||
338 |
widget = form.get_widget('digest_template') |
|
339 |
new_value = widget.parse() |
|
340 |
if new_value: |
|
341 |
return False |
|
342 | ||
343 |
if any(self.formdef.usage_in_formdefs()): |
|
344 |
widget.set_error(_('Can not empty digest template: this card model is used as data source in some forms.')) |
|
345 |
return True |
|
346 | ||
347 |
return False |
|
348 | ||
324 | 349 | |
325 | 350 |
class WorkflowRoleDirectory(Directory): |
326 | 351 |
def __init__(self, formdef): |
wcs/backoffice/cards.py | ||
---|---|---|
27 | 27 |
from ..qommon.storage import NotEqual, Null |
28 | 28 | |
29 | 29 |
from wcs.carddef import CardDef |
30 |
from wcs.formdef import get_formdefs_of_all_kinds |
|
31 | 30 |
from wcs.roles import Role |
32 | 31 |
from wcs.workflows import Workflow |
33 | 32 |
from wcs.admin.forms import FormsDirectory, FormDefPage, FormDefUI, html_top |
... | ... | |
167 | 166 |
r += self.get_preview() |
168 | 167 |
r += htmltext('</div>') |
169 | 168 | |
170 |
formdefs = self.usage_in_formdefs()
|
|
169 |
formdefs = list(self.formdef.usage_in_formdefs())
|
|
171 | 170 |
if formdefs: |
171 |
formdefs.sort(key=lambda x: x.name.lower()) |
|
172 | 172 |
r += htmltext('<div class="bo-block">') |
173 | 173 |
r += htmltext('<h3>%s</h3>') % _('Forms') |
174 | 174 |
r += htmltext('<p>%s ') % _('This card model is used as data source in the following forms:') |
... | ... | |
177 | 177 |
r += htmltext('</div>') |
178 | 178 |
return r.getvalue() |
179 | 179 | |
180 |
def usage_in_formdefs(self): |
|
181 |
def is_used_in_formdef(formdef): |
|
182 |
for field in formdef.fields or []: |
|
183 |
data_source = getattr(field, 'data_source', None) |
|
184 |
if not (data_source and data_source.get('type')): |
|
185 |
continue |
|
186 |
data_source_id = 'carddef:%s' % self.formdef.url_name |
|
187 |
if data_source.get('type') == data_source_id: |
|
188 |
return True |
|
189 |
if data_source.get('type').startswith('%s:' % data_source_id): |
|
190 |
# custom view |
|
191 |
return True |
|
192 |
return False |
|
193 | ||
194 |
formdefs = [] |
|
195 |
for formdef in get_formdefs_of_all_kinds(): |
|
196 |
if is_used_in_formdef(formdef): |
|
197 |
formdefs.append(formdef) |
|
198 |
formdefs.sort(key=lambda x: x.name.lower()) |
|
199 |
return formdefs |
|
200 | ||
201 | 180 |
def duplicate(self): |
202 | 181 |
response = super(CardDefPage, self).duplicate() |
203 | 182 |
self.formdefui.formdef.disabled = False |
wcs/carddef.py | ||
---|---|---|
22 | 22 |
from .qommon.storage import Contains, Equal, NotEqual, ILike |
23 | 23 | |
24 | 24 |
from wcs.carddata import CardData |
25 |
from wcs.formdef import FormDef |
|
25 |
from wcs.formdef import FormDef, get_formdefs_of_all_kinds
|
|
26 | 26 | |
27 | 27 |
if not hasattr(types, 'ClassType'): |
28 | 28 |
types.ClassType = type |
... | ... | |
209 | 209 |
if order_by is None: |
210 | 210 |
items.sort(key=lambda x: misc.simplify(x['text'])) |
211 | 211 |
return items |
212 | ||
213 |
def usage_in_formdefs(self): |
|
214 |
def is_used_in_formdef(formdef): |
|
215 |
for field in formdef.fields or []: |
|
216 |
data_source = getattr(field, 'data_source', None) |
|
217 |
if not (data_source and data_source.get('type')): |
|
218 |
continue |
|
219 |
data_source_id = 'carddef:%s' % self.url_name |
|
220 |
if data_source.get('type') == data_source_id: |
|
221 |
return True |
|
222 |
if data_source.get('type').startswith('%s:' % data_source_id): |
|
223 |
# custom view |
|
224 |
return True |
|
225 |
return False |
|
226 | ||
227 |
for formdef in get_formdefs_of_all_kinds(): |
|
228 |
if is_used_in_formdef(formdef): |
|
229 |
yield formdef |
|
212 |
- |