0001-add-test-tools-in-formdata-inspect-view-23685.patch
tests/test_backoffice_pages.py | ||
---|---|---|
3727 | 3727 |
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200) |
3728 | 3728 |
assert re.findall('New Function.*(deleted)', resp.body) |
3729 | 3729 | |
3730 |
# test tools |
|
3731 |
resp = login(get_app(pub)).get('%sinspect' % formdata.get_url(backoffice=True), status=200) |
|
3732 |
assert "Test tool" in resp.body |
|
3733 | ||
3734 |
resp.form['test_mode'] = 'condition' |
|
3735 | ||
3736 |
resp.form['condition$type'] = 'python' |
|
3737 |
resp.form['condition$value_python'] = 'len(form_name) == 10' # "form title" |
|
3738 |
resp = resp.form.submit() |
|
3739 |
assert 'Condition result' in resp.body |
|
3740 |
assert 'result-true' in resp.body |
|
3741 |
assert '<code>True</code>' in resp.body |
|
3742 |
resp.form['condition$value_python'] = 'len(form_name) == 5' |
|
3743 |
resp = resp.form.submit() |
|
3744 |
assert 'Condition result' in resp.body |
|
3745 |
assert 'result-false' in resp.body |
|
3746 |
assert '<code>False</code>' in resp.body |
|
3747 |
resp.form['condition$value_python'] = 'form_do_not_exist == 3' |
|
3748 |
resp = resp.form.submit() |
|
3749 |
assert 'Condition result' not in resp.body |
|
3750 |
assert 'Failed to evaluate condition' in resp.body |
|
3751 |
assert 'NameError' in resp.body |
|
3752 | ||
3753 |
resp.form['condition$type'] = 'django' |
|
3754 |
resp.form['condition$value_django'] = 'form_name|length == 10' |
|
3755 |
resp = resp.form.submit() |
|
3756 |
assert 'Condition result' in resp.body |
|
3757 |
assert 'result-true' in resp.body |
|
3758 |
resp.form['condition$type'] = 'django' |
|
3759 |
resp.form['condition$value_django'] = 'form_name|length == 5' |
|
3760 |
resp = resp.form.submit() |
|
3761 |
assert 'Condition result' in resp.body |
|
3762 |
assert 'result-false' in resp.body |
|
3763 |
resp.form['condition$type'] = 'django' |
|
3764 |
resp.form['condition$value_django'] = 'foo bar' |
|
3765 |
resp = resp.form.submit() |
|
3766 |
assert 'Condition result' not in resp.body |
|
3767 |
assert 'syntax error' in resp.body |
|
3768 |
resp.form['condition$value_python'] = None |
|
3769 |
resp.form['condition$value_django'] = None |
|
3770 | ||
3771 |
resp.form['test_mode'] = 'template' |
|
3772 |
resp.form['template'] = '{{ form_name }}' |
|
3773 |
resp = resp.form.submit() |
|
3774 |
assert 'Template rendering' in resp.body |
|
3775 |
assert '<div class="testtool-result">form title</div>' in resp.body |
|
3776 |
assert 'HTML Source' not in resp.body |
|
3777 |
resp.form['template'] = '<p>{{ form_name }}</p>' |
|
3778 |
resp = resp.form.submit() |
|
3779 |
assert 'Template rendering' in resp.body |
|
3780 |
assert '<p>form title</p>' in resp.body |
|
3781 |
assert 'HTML Source' in resp.body |
|
3782 |
resp.form['template'] = '{% for x in 1 %}ok{% endfor %}' |
|
3783 |
resp = resp.form.submit() |
|
3784 |
assert 'Failed to evaluate template' in resp.body |
|
3785 |
assert 'TypeError' in resp.body |
|
3786 |
resp.form['template'] = '{% for x in 1 %}ok{% end %}' |
|
3787 |
resp = resp.form.submit() |
|
3788 |
assert 'syntax error' in resp.body |
|
3789 |
assert 'Invalid block tag' in resp.body |
|
3790 |
resp.form['template'] = '' |
|
3791 | ||
3792 |
resp.form['test_mode'] = 'html_template' |
|
3793 |
resp.form['html_template'] = '<p>{{ form_name }}</p>' |
|
3794 |
resp = resp.form.submit() |
|
3795 |
resp = resp.form.submit() |
|
3796 |
assert 'Template rendering' in resp.body |
|
3797 |
assert '<p>form title</p>' in resp.body |
|
3798 |
assert 'HTML Source' in resp.body |
|
3799 |
resp.form['html_template'] = '{% for x in 1 %}ok{% endfor %}' |
|
3800 |
resp = resp.form.submit() |
|
3801 |
assert 'Failed to evaluate HTML template' in resp.body |
|
3802 |
assert 'TypeError' in resp.body |
|
3803 |
resp.form['html_template'] = '{% for x in 1 %}ok{% end %}' |
|
3804 |
resp = resp.form.submit() |
|
3805 |
assert 'syntax error' in resp.body |
|
3806 |
assert 'Invalid block tag' in resp.body |
|
3807 | ||
3730 | 3808 |
def test_workflow_jump_previous(pub): |
3731 | 3809 |
user = create_user(pub) |
3732 | 3810 |
create_environment(pub) |
wcs/backoffice/management.py | ||
---|---|---|
32 | 32 |
from quixote.directory import Directory |
33 | 33 |
from quixote.html import TemplateIO, htmltext, htmlescape |
34 | 34 | |
35 |
from qommon import _, ngettext |
|
35 |
from qommon import _, ngettext, ezt
|
|
36 | 36 |
from qommon.admin.emails import EmailsDirectory |
37 | 37 |
from qommon.admin.menu import command_icon |
38 | 38 |
from qommon.backoffice.menu import html_top |
... | ... | |
50 | 50 |
Intersects, ILike, FtsMatch, Contains, Null) |
51 | 51 | |
52 | 52 |
from wcs.api_utils import get_user_from_api_query_string |
53 |
from wcs.conditions import Condition |
|
53 | 54 |
from wcs.forms.backoffice import FormDefUI |
54 | 55 |
from wcs.forms.common import FormStatusPage |
55 | 56 |
from wcs.admin.settings import UserFieldsFormDef |
... | ... | |
57 | 58 |
from wcs.formdata import FormData |
58 | 59 |
from wcs.formdef import FormDef |
59 | 60 |
from wcs.roles import logged_users_role, Role |
60 |
from wcs.workflows import get_role_translation |
|
61 |
from wcs.workflows import get_role_translation, template_on_formdata
|
|
61 | 62 | |
62 | 63 |
from .submission import FormFillPage |
63 | 64 | |
... | ... | |
2237 | 2238 |
self.formdef.workflow.id, _('Workflow Definition')) |
2238 | 2239 |
r += htmltext('</span>') |
2239 | 2240 |
r += htmltext('</div>') |
2241 | ||
2242 |
form = Form(use_tokens=False) |
|
2243 |
form.add(SingleSelectWidget, 'test_mode', |
|
2244 |
options=[ |
|
2245 |
(None, ('Choose a testing tool'), None), |
|
2246 |
('condition', _('Condition'), 'condition'), |
|
2247 |
('template', '%s / %s' % (_('Template'), _('Django Expression')), 'template'), |
|
2248 |
('html_template', _('HTML Template (wysiwyg)'), 'html_template'), |
|
2249 |
# TODO: ODT/RTF tester |
|
2250 |
], attrs={'data-dynamic-display-parent': 'true'}) |
|
2251 |
form.add(ConditionWidget, 'condition', |
|
2252 |
attrs={ |
|
2253 |
'data-dynamic-display-child-of': 'test_mode', |
|
2254 |
'data-dynamic-display-value': 'condition' |
|
2255 |
}) |
|
2256 |
form.add(WysiwygTextWidget, 'html_template', |
|
2257 |
validation_function=ComputedExpressionWidget.validate_template, |
|
2258 |
attrs={ |
|
2259 |
'data-dynamic-display-child-of': 'test_mode', |
|
2260 |
'data-dynamic-display-value': 'html_template' |
|
2261 |
}) |
|
2262 |
form.add(TextWidget, 'template', |
|
2263 |
validation_function=ComputedExpressionWidget.validate_template, |
|
2264 |
attrs={ |
|
2265 |
'data-dynamic-display-child-of': 'test_mode', |
|
2266 |
'data-dynamic-display-value': 'template' |
|
2267 |
}) |
|
2268 |
form.add_submit('submit', _('Process'), |
|
2269 |
attrs={ |
|
2270 |
'data-dynamic-display-child-of': 'test_mode', |
|
2271 |
'data-dynamic-display-value-in': 'condition|html_template|template' |
|
2272 |
}) |
|
2273 |
r += htmltext('<div id="tester" class="section foldable %s">') % ( |
|
2274 |
'folded' if not form.is_submitted() else '') |
|
2275 |
r += htmltext('<h2>Test tool</h2>') |
|
2276 |
r += htmltext('<div>') |
|
2277 |
r += form.render() |
|
2278 | ||
2279 |
if form.is_submitted() and not form.has_errors(): |
|
2280 |
# show test result |
|
2281 |
test_mode = form.get_widget('test_mode').parse() |
|
2282 |
if test_mode == 'condition': |
|
2283 |
condition = Condition(form.get_widget('condition').parse()) |
|
2284 |
condition.log_errors = False |
|
2285 |
condition.record_errors = False |
|
2286 |
try: |
|
2287 |
result = condition.unsafe_evaluate() |
|
2288 |
except Exception as exception: |
|
2289 |
r += htmltext('<div class="errornotice">') |
|
2290 |
r += htmltext('<p>%s</p>') % _('Failed to evaluate condition') |
|
2291 |
r += htmltext('<p>%s <code>%s: %s</code></p>') % ( |
|
2292 |
_('Error message:'), exception.__class__.__name__, str(exception)) |
|
2293 |
r += htmltext('</div>') |
|
2294 |
else: |
|
2295 |
r += htmltext('<h3>%s</h3>') % _('Condition result') |
|
2296 |
r += htmltext('<div class="testtool-result">') |
|
2297 |
r += htmltext('<p><span class="result-%s">%s</span>') % ( |
|
2298 |
str(bool(result)).lower(), ('True') if result else _('False')) |
|
2299 |
if condition.type == 'python': |
|
2300 |
r += htmltext(' — %s <strong><code>%r</code></strong> ' |
|
2301 |
'<span class="type">(%r)</span>') % ( |
|
2302 |
_('Python actual result is'), result, type(result)) |
|
2303 |
r += htmltext('</p>') |
|
2304 |
r += htmltext('</div>') |
|
2305 |
elif test_mode == 'template': |
|
2306 |
try: |
|
2307 |
template = form.get_widget('template').parse() or '' |
|
2308 |
result = template_on_formdata(self.filled, template, raises=True) |
|
2309 |
except Exception as exception: |
|
2310 |
r += htmltext('<div class="errornotice">') |
|
2311 |
r += htmltext('<p>%s</p>') % _('Failed to evaluate template') |
|
2312 |
r += htmltext('<p>%s <code>%s: %s</code></p>') % ( |
|
2313 |
_('Error message:'), exception.__class__.__name__, str(exception)) |
|
2314 |
else: |
|
2315 |
r += htmltext('<h3>%s</h3>') % _('Template rendering') |
|
2316 |
if result and result[0] == '<': # seems to be HTML |
|
2317 |
r += htmltext('<div class="testtool-result">') |
|
2318 |
r += htmltext(result) |
|
2319 |
r += htmltext('</div>') |
|
2320 |
r += htmltext('<h3>%s</h3>') % _('HTML Source') |
|
2321 |
r += htmltext('<pre class="testtool-result">%s</pre>') % result |
|
2322 |
else: |
|
2323 |
r += htmltext('<div class="testtool-result">%s</div>') % result |
|
2324 |
elif test_mode == 'html_template': |
|
2325 |
try: |
|
2326 |
html_template = form.get_widget('html_template').parse() or '' |
|
2327 |
result = template_on_formdata(self.filled, html_template, raises=True, |
|
2328 |
ezt_format=ezt.FORMAT_HTML) |
|
2329 |
except Exception as exception: |
|
2330 |
r += htmltext('<div class="errornotice">') |
|
2331 |
r += htmltext('<p>%s</p>') % _('Failed to evaluate HTML template') |
|
2332 |
r += htmltext('<p>%s <code>%s: %s</code></p>') % ( |
|
2333 |
_('Error message:'), exception.__class__.__name__, str(exception)) |
|
2334 |
r += htmltext('</div>') |
|
2335 |
else: |
|
2336 |
r += htmltext('<h3>%s</h3>') % _('Template rendering') |
|
2337 |
r += htmltext('<div class="testtool-result">') |
|
2338 |
r += htmltext(result) |
|
2339 |
r += htmltext('</div>') |
|
2340 |
r += htmltext('<h3>%s</h3>') % _('HTML Source') |
|
2341 |
r += htmltext('<pre class="testtool-result">%s</pre>') % result |
|
2342 |
r += htmltext('</div></div>') |
|
2343 | ||
2240 | 2344 |
r += htmltext('<ul class="biglist form-inspector">') |
2241 | 2345 |
r += htmltext(' <li><h3>%s</h3></li>') % _('Substitution variables') |
2242 | 2346 |
substvars = self.filled.get_static_substitution_variables() |
wcs/conditions.py | ||
---|---|---|
45 | 45 |
return get_publisher().substitutions.get_context_variables( |
46 | 46 |
mode='%s-condition' % self.type) |
47 | 47 | |
48 |
def evaluate(self): |
|
48 |
def unsafe_evaluate(self):
|
|
49 | 49 |
if not self.type or not self.value: |
50 | 50 |
return True |
51 | 51 |
local_variables = self.get_data() |
52 |
return getattr(self, 'evaluate_' + self.type)(local_variables) |
|
53 | ||
54 |
def evaluate(self): |
|
52 | 55 |
try: |
53 |
return getattr(self, 'evaluate_' + self.type)(local_variables)
|
|
56 |
return self.unsafe_evaluate()
|
|
54 | 57 |
except Exception as e: |
55 | 58 |
if self.log_errors: |
56 | 59 |
get_logger().warn('failed to evaluate %r (%r)', self, e) |
wcs/qommon/static/css/dc2/admin.css | ||
---|---|---|
1567 | 1567 |
position: absolute; |
1568 | 1568 |
} |
1569 | 1569 | |
1570 |
div.testtool-result, pre.testtool-result { |
|
1571 |
padding: 0.6em; |
|
1572 |
background: #ddd; |
|
1573 |
border: 1px solid #888; |
|
1574 |
} |
|
1575 | ||
1576 |
div.testtool-result span.type { |
|
1577 |
font-size: 80%; |
|
1578 |
color: #888; |
|
1579 |
padding-left: 1em; |
|
1580 |
} |
|
1581 | ||
1582 |
div.testtool-result span.result-true { |
|
1583 |
padding: 5px; |
|
1584 |
background: lightgreen; |
|
1585 |
} |
|
1586 | ||
1587 |
div.testtool-result span.result-false { |
|
1588 |
padding: 5px; |
|
1589 |
background: red; |
|
1590 |
color: white; |
|
1591 |
} |
|
1592 | ||
1570 | 1593 |
ul#evolutions li div.msg li { |
1571 | 1594 |
margin: 1em 0; |
1572 | 1595 |
} |
1573 |
- |