wcs/wcs/admin/tests.py

925 lines
34 KiB
Python

# w.c.s. - web application for online forms
# Copyright (C) 2005-2022 Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.
import collections
import copy
import json
from django.template.loader import render_to_string
from django.utils.timezone import now
from quixote import get_publisher, get_request, get_response, get_session, redirect
from quixote.directory import Directory
from quixote.html import TemplateIO, htmltext
from wcs.admin.workflow_tests import WorkflowTestsDirectory
from wcs.api import posted_json_data_to_formdata_data
from wcs.backoffice.management import FormBackofficeEditPage, FormBackOfficeStatusPage
from wcs.backoffice.pagination import pagination_links
from wcs.forms.common import FormStatusPage
from wcs.qommon import _, misc, template
from wcs.qommon.afterjobs import AfterJob
from wcs.qommon.errors import TraversalError
from wcs.qommon.form import (
FileWidget,
Form,
RadiobuttonsWidget,
SingleSelectWidget,
StringWidget,
TextWidget,
UrlWidget,
WidgetDict,
)
from wcs.sql_criterias import Equal, Null, StrictNotEqual
from wcs.testdef import TestDef, TestError, TestResult, WebserviceResponse
from wcs.workflow_tests import WorkflowTestError
from wcs.workflow_traces import WorkflowTrace
class TestEditPage(FormBackofficeEditPage):
filling_templates = ['wcs/backoffice/testdata_filling.html']
edit_mode_submit_label = _('Save data')
edit_mode_cancel_url = '..'
def __init__(self, objectdef, testdef, filled, **kwargs):
self.formdef_class = objectdef.__class__
super().__init__(objectdef.url_name, **kwargs)
self.testdef = testdef
self.edited_data = filled
self.edited_data.data['edited_testdef_id'] = self.testdef.id
get_request().is_in_backoffice_forced_value = self.testdef.is_in_backoffice
self._q_exports.append(('mark-as-failing', 'mark_as_failing'))
self._q_exports.append(('change-submission-mode', 'change_submission_mode'))
def _q_index(self):
get_response().breadcrumb.append(('edit-data/', _('Edit data')))
return super()._q_index()
def create_form(self, *args, **kwargs):
# FormBackofficeEditPage.create_form is relevant only for forms, skip it for cards
if self.testdef.object_type == 'formdefs':
form = super().create_form(*args, **kwargs)
else:
form = super(FormBackofficeEditPage, self).create_form(*args, **kwargs)
return form
def modify_filling_context(self, context, *args, **kwargs):
super().modify_filling_context(context, *args, **kwargs)
form = context['html_form']
if form.get_submit() == 'submit':
self.testdef.expected_error = None
get_response().filter['sidebar'] = self.get_test_sidebar(form)
def get_test_sidebar(self, form):
context = {'testdef': self.testdef, 'mark_as_failing_form': self.get_mark_as_failing_form(form)}
return render_to_string('wcs/backoffice/test_edit_sidebar.html', context=context)
def get_mark_as_failing_form(self, form):
errors = form.global_error_messages or []
if not errors and not form.has_errors():
return
for widget in form.widgets:
if not hasattr(widget, 'field'):
continue
if widget.field.key in TestDef.ignored_field_types:
continue
if widget.is_hidden:
continue
widget = TestDef.get_error_widget(widget)
if widget:
errors.append(widget.error)
if len(errors) != 1:
return
form = Form(enctype='multipart/form-data', action='mark-as-failing', use_tokens=False)
form.add_hidden('error', errors[0])
form.test_error = errors[0]
magictoken = get_request().form.get('magictoken')
form.add_hidden('magictoken', magictoken)
form.add_submit('submit', _('Mark as failing'))
return form
def mark_as_failing(self):
if not get_request().get_method() == 'POST':
raise TraversalError()
magictoken = get_request().form.get('magictoken')
edited_data = self.get_transient_formdata(magictoken)
testdef = TestDef.create_from_formdata(self.formdef, edited_data)
self.testdef.data = testdef.data
self.testdef.expected_error = get_request().form.get('error')
self.testdef.store()
return redirect('..')
def change_submission_mode(self):
self.testdef.is_in_backoffice = not self.testdef.is_in_backoffice
self.testdef.store()
return redirect('.')
class TestPage(FormBackOfficeStatusPage):
_q_extra_exports = [
'delete',
'export',
'edit',
('edit-data', 'edit_data'),
'duplicate',
('workflow', 'workflow_tests'),
('webservice-responses', 'webservice_responses'),
]
def __init__(self, component, objectdef):
try:
self.testdef = TestDef.get(component)
except KeyError:
raise TraversalError()
filled = self.testdef.build_formdata(objectdef, include_fields=True)
super().__init__(objectdef, filled)
self.workflow_tests = WorkflowTestsDirectory(self.testdef, self.formdef)
self.webservice_responses = WebserviceResponseDirectory(self.testdef)
@property
def edit_data(self):
return TestEditPage(self.formdef, update_breadcrumbs=False, testdef=self.testdef, filled=self.filled)
def _q_index(self):
get_response().add_javascript(['select2.js'])
return super()._q_index()
def _q_traverse(self, path):
get_response().breadcrumb.append((str(self.testdef.id) + '/', str(self.testdef)))
return super(FormStatusPage, self)._q_traverse(path)
def should_fold_summary(self, mine, request_user):
return False
def get_extra_context_bar(self, parent=None):
return render_to_string('wcs/backoffice/test_sidebar.html', context={})
def status(self):
r = TemplateIO(html=True)
r += htmltext('<div id="appbar">')
r += htmltext('<h2>%s</h2>') % self.testdef
r += htmltext('<span class="actions">')
r += htmltext('<a href="edit-data/">%s</a>') % _('Edit data')
if get_publisher().has_site_option('enable-workflow-tests'):
r += htmltext('<a href="workflow/">%s</a>') % _('Workflow tests')
r += htmltext('</span>')
r += htmltext('</div>')
if self.testdef.expected_error:
r += htmltext('<div class="infonotice"><p>%s</p></div>') % (
_('This test is expected to fail on error "%s".') % self.testdef.expected_error
)
if self.testdef.data['fields']:
r += self.receipt(always_include_user=True, mine=False)
else:
r += htmltext('<div class="infonotice"><p>%s</p></div>') % _('This test is empty.')
return r.getvalue()
def delete(self):
form = Form(enctype='multipart/form-data')
form.add_submit('delete', _('Delete'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('delete', _('Delete')))
r = TemplateIO(html=True)
r += htmltext('<h2>%s %s</h2>') % (_('Deleting Test:'), self.testdef)
r += form.render()
return r.getvalue()
else:
TestDef.remove_object(self.testdef.id)
return redirect('..')
def export(self):
return misc.xml_response(
self.testdef, filename='test-%s.wcs' % misc.simplify(self.testdef.name), include_id=False
)
def edit(self):
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'name', title=_('Name'), required=True, size=50, value=self.testdef.name)
user_options = [('', '---', '')] + [
(x.id, str(x), x.id) for x in get_publisher().user_class.select(order_by='name')
]
form.add(
SingleSelectWidget,
'user',
title=_('User'),
value=self.testdef.data['user'].get('id', '') if self.testdef.data['user'] else '',
options=user_options,
**{'data-autocomplete': 'true'},
)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('edit', _('Edit test')))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % (_('Edit test'))
r += form.render()
return r.getvalue()
else:
self.testdef.name = form.get_widget('name').parse()
user_id = form.get_widget('user').parse()
if user_id:
user = get_publisher().user_class.get(user_id)
self.testdef.data['user'] = user.get_json_export_dict()
else:
self.testdef.data['user'] = None
self.testdef.store()
return redirect('.')
def duplicate(self):
form = Form(enctype='multipart/form-data')
name_widget = form.add(StringWidget, 'name', title=_('Name'), required=True, size=30)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted():
original_name = self.testdef.name
new_name = '%s %s' % (original_name, _('(copy)'))
names = [x.name for x in TestDef.select_for_objectdef(self.formdef)]
no = 2
while new_name in names:
new_name = _('%(name)s (copy %(no)d)') % {'name': original_name, 'no': no}
no += 1
name_widget.set_value(new_name)
if not form.is_submitted() or form.has_errors():
get_response().set_title(_('Duplicate test'))
r = TemplateIO(html=True)
get_response().breadcrumb.append(('duplicate', _('Duplicate')))
r += htmltext('<h2>%s</h2>') % _('Duplicate test')
r += form.render()
return r.getvalue()
self.testdef.name = form.get_widget('name').parse()
self.testdef = TestDef.import_from_xml_tree(self.testdef.export_to_xml(), self.formdef)
self.testdef.store()
return redirect(self.testdef.get_admin_url())
class TestsDirectory(Directory):
_q_exports = ['', 'new', ('import', 'p_import'), 'results']
section = 'tests'
def __init__(self, objectdef):
self.objectdef = objectdef
self.results = TestResultsDirectory(objectdef)
def _q_traverse(self, path):
last_page_path, last_page_label = get_response().breadcrumb.pop()
last_page_label = misc.ellipsize(last_page_label, 15, '')
get_response().breadcrumb.append((last_page_path, last_page_label))
get_response().breadcrumb.append(('tests/', _('Tests')))
return super()._q_traverse(path)
def _q_lookup(self, component):
return TestPage(component, self.objectdef)
def _q_index(self):
context = {
'testdefs': TestDef.select_for_objectdef(self.objectdef),
'has_deprecated_fields': any(
x.key in ('table', 'table-select', 'tablerows', 'ranked-items') for x in self.objectdef.fields
),
'has_sidebar': True,
}
get_response().add_javascript(['popup.js'])
get_response().set_title(_('Tests'))
return template.QommonTemplateResponse(
templates=['wcs/backoffice/tests.html'], context=context, is_django_native=True
)
def new(self):
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'name', title=_('Name'), required=True, size=50)
formdata_options = [
(
x.id,
'%s - %s - %s'
% (x.id_display, x.user or _('Unknown User'), misc.localstrftime(x.receipt_time)),
)
for x in self.objectdef.data_class().select(
[StrictNotEqual('status', 'draft'), Null('anonymised')], order_by='-receipt_time'
)
]
if formdata_options:
creation_options = [
('empty', _('Fill data manually'), 'empty'),
('formdata', _('Import data from form'), 'formdata'),
]
if get_publisher().has_site_option('enable-workflow-tests'):
creation_options.append(
('formdata-wf', _('Import data from form (and initialise workflow tests)'), 'formdata-wf')
)
form.add(
RadiobuttonsWidget,
'creation_mode',
options=creation_options,
value='empty',
attrs={'data-dynamic-display-parent': 'true'},
)
form.add(
SingleSelectWidget,
'formdata',
required=False,
options=formdata_options,
hint=_('Form is only used for initial data alimentation, no link is kept with created test.'),
attrs={
'data-dynamic-display-child-of': 'creation_mode',
'data-dynamic-display-value-in': 'formdata|formdata-wf',
},
**{'data-autocomplete': 'true'},
)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('new', _('New')))
get_response().set_title(_('New test'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('New test')
r += form.render()
return r.getvalue()
creation_mode_widget = form.get_widget('creation_mode')
if not creation_mode_widget or creation_mode_widget.parse() == 'empty':
testdef = TestDef.create_from_formdata(self.objectdef, self.objectdef.data_class()())
testdef.name = form.get_widget('name').parse()
testdef.agent_id = get_session().user
testdef.store()
return redirect(testdef.get_admin_url() + 'edit-data/')
else:
formdata_id = form.get_widget('formdata').parse()
formdata = self.objectdef.data_class().get(formdata_id)
testdef = TestDef.create_from_formdata(
self.objectdef,
formdata,
add_workflow_tests=bool(creation_mode_widget.parse() == 'formdata-wf'),
)
testdef.name = form.get_widget('name').parse()
testdef.agent_id = get_session().user
testdef.store()
return redirect(testdef.get_admin_url())
def p_import(self):
form = Form(enctype='multipart/form-data')
form.add(FileWidget, 'file', title=_('File'), required=True)
form.add_submit('submit', _('Import Test'))
form.add_submit('cancel', _('Cancel'))
if form.get_submit() == 'cancel':
return redirect('.')
if form.is_submitted() and not form.has_errors():
try:
return self.import_submit(form)
except ValueError:
pass
get_response().breadcrumb.append(('import', _('Import')))
get_response().set_title(_('Import Test'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('Import Test')
r += htmltext('<p>%s</p>') % _(
'You can add a new test or update an existing one by importing a JSON file.'
)
r += form.render()
return r.getvalue()
def import_submit(self, form):
fp = form.get_widget('file').parse().fp
try:
testdef = TestDef.import_from_xml(fp, self.objectdef)
except ValueError as e:
form.set_error('file', _('Invalid File'))
raise e
get_session().message = ('info', _('Test "%s" has been successfully imported.') % testdef.name)
return redirect('.')
class TestResultDetailPage(Directory):
_q_exports = ['', 'inspect', ('inspect-tool', 'inspect_tool')]
def __init__(self, component, test_result, formdef):
self.result_index = component
self.formdef = formdef
try:
self.result = test_result.results[int(component)]
except (KeyError, ValueError):
raise TraversalError()
try:
self.testdef = TestDef.get(self.result['id'])
except KeyError:
self.testdef = None
def _q_traverse(self, path):
get_response().breadcrumb.append(
(str(self.result_index) + '/', _('Details of %(test_name)s') % {'test_name': self.result['name']})
)
return super()._q_traverse(path)
def _q_index(self):
context = {
'result': self.result['details'],
'test_name': self.result['name'],
'testdef': self.testdef,
'workflow_test_action': self.get_workflow_test_action(
self.result['details']['workflow_test_action_uuid']
),
'error_field': self.get_error_field(self.result['details'].get('error_field_id')),
}
for request in self.result['details'].get('sent_requests', []):
if request['webservice_response_id']:
try:
request['webservice_response'] = [
x
for x in self.testdef.get_webservice_responses()
if x.id == request['webservice_response_id']
][0]
except IndexError:
pass
return template.QommonTemplateResponse(
templates=['wcs/backoffice/test-result-detail.html'],
context=context,
is_django_native=True,
)
def get_workflow_test_action(self, action_uuid):
if not action_uuid or not self.testdef:
return
try:
action = [x for x in self.testdef.workflow_tests.actions if x.uuid == action_uuid][0]
except IndexError:
return
action.url = self.testdef.get_admin_url() + 'workflow/#%s' % action.id
return action
def get_error_field(self, field_id):
if not field_id:
return
try:
field = [x for x in self.formdef.fields if x.id == field_id][0]
except IndexError:
return
field.url = self.formdef.get_field_admin_url(field)
return field
def inspect(self):
formdata_json = json.loads(self.result['formdata'])
formdata = self.import_formdata_from_json(formdata_json)
return FormBackOfficeStatusPage(self.formdef, formdata).inspect()
def inspect_tool(self):
formdata_json = json.loads(self.result['formdata'])
formdata = self.import_formdata_from_json(formdata_json)
return FormBackOfficeStatusPage(self.formdef, formdata).inspect_tool()
def import_formdata_from_json(self, formdata_json):
formdata = self.formdef.data_class()()
formdata.receipt_time = formdata_json['receipt_time']
formdata.user_id = formdata_json.get('user', {}).get('id')
formdata.digests = formdata_json['digests']
formdata.backoffice_submission = formdata_json['submission']['backoffice']
formdata.submission_channel = formdata_json['submission']['channel']
formdata.submission_agent_id = formdata_json['submission'].get('agent', {}).get('id')
formdata.geolocations = formdata_json.get('geolocations')
formdata.criticality_level = formdata_json['criticality_level']
formdata.anonymised = formdata_json['anonymised']
formdata.workflow_data = formdata_json.get('workflow', {}).get('data', {})
formdata.set_auto_fields()
# load fields
formdata.data = posted_json_data_to_formdata_data(self.formdef, formdata_json['fields'])
# load backoffice fields if any
if 'fields' in (formdata_json.get('workflow') or {}):
backoffice_data_dict = posted_json_data_to_formdata_data(
self.formdef, formdata_json['workflow']['fields']
)
formdata.data.update(backoffice_data_dict)
# set status
formdata.status = formdata_json['workflow']['real_status']['id']
formdata.workflow_traces = [
WorkflowTrace.import_from_json_dict(x) for x in formdata_json['workflow_traces']
]
def get_workflow_traces():
return formdata.workflow_traces
formdata.get_workflow_traces = get_workflow_traces
return formdata
class TestResultPage(Directory):
_q_exports = ['']
def __init__(self, component, objectdef):
try:
self.test_result = TestResult.get(component)
except KeyError:
raise TraversalError()
self.objectdef = objectdef
def _q_traverse(self, path):
get_response().breadcrumb.append(
(str(self.test_result.id) + '/', _('Result #%s') % self.test_result.id)
)
return super()._q_traverse(path)
def _q_lookup(self, component):
return TestResultDetailPage(component, self.test_result, self.objectdef)
def _q_index(self):
get_response().add_javascript(['popup.js'])
testdefs = TestDef.select_for_objectdef(self.objectdef)
testdefs_by_id = {x.id: x for x in testdefs}
for test in self.test_result.results:
test['has_details'] = any(x for x in test['details'].values())
if test['id'] in testdefs_by_id:
test['url'] = testdefs_by_id[test['id']].get_admin_url()
return template.QommonTemplateResponse(
templates=['wcs/backoffice/test-result.html'],
context={'test_result': self.test_result},
is_django_native=True,
)
class TestResultsDirectory(Directory):
_q_exports = ['', 'run']
section = 'test_results'
def __init__(self, objectdef):
self.objectdef = objectdef
def _q_traverse(self, path):
get_response().breadcrumb.append(('results/', _('Test results')))
get_response().set_title('%s - %s' % (self.objectdef.name, _('Test results')))
return super()._q_traverse(path)
def _q_lookup(self, component):
return TestResultPage(component, self.objectdef)
def _q_index(self):
criterias = [
Equal('object_type', self.objectdef.get_table_name()),
Equal('object_id', self.objectdef.id),
]
offset = misc.get_int_or_400(get_request().form.get('offset', 0))
limit = misc.get_int_or_400(get_request().form.get('limit', 25))
total_count = TestResult.count(criterias)
context = {
'test_results': TestResult.select(criterias, offset=offset, limit=limit, order_by='-id'),
'has_testdefs': bool(TestDef.count(criterias)),
'pagination_links': pagination_links(offset, limit, total_count, load_js=False),
}
return template.QommonTemplateResponse(
templates=['wcs/backoffice/test-results.html'], context=context, is_django_native=True
)
def run(self):
test_result = TestsAfterJob.run_tests(self.objectdef, _('Manual run.'))
return redirect(test_result.get_admin_url())
class TestsAfterJob(AfterJob):
def __init__(self, objectdef, reason, snapshot=None, **kwargs):
super().__init__(
objectdef_class=objectdef.__class__,
objectdef_id=objectdef.id,
reason=reason,
snapshot_id=snapshot.id if snapshot else None,
**kwargs,
)
def execute(self):
try:
objectdef = self.kwargs['objectdef_class'].get(self.kwargs['objectdef_id'])
except KeyError:
return
reason = self.kwargs['reason']
result = self.run_tests(objectdef, reason)
if result and self.kwargs['snapshot_id'] is not None:
snapshot = get_publisher().snapshot_class.get(self.kwargs['snapshot_id'])
snapshot.test_result_id = result.id
snapshot.store()
@staticmethod
def run_tests(objectdef, reason):
testdefs = TestDef.select_for_objectdef(objectdef)
if not testdefs:
return
for test in testdefs:
try:
test.run(objectdef)
except WorkflowTestError as e:
test.error = _('Workflow error: %s') % e
test.exception = e
except TestError as e:
test.error = str(e)
test.exception = e
formdata_json = test.formdata.get_json_export_dict()
formdata_json['criticality_level'] = test.formdata.criticality_level
formdata_json['anonymised'] = test.formdata.anonymised
formdata_json['workflow_traces'] = [x.get_json_export_dict() for x in test.formdata.workflow_traces]
test_result = TestResult()
test_result.object_type = objectdef.get_table_name()
test_result.object_id = objectdef.id
test_result.timestamp = now()
test_result.success = not any(hasattr(test, 'error') for test in testdefs)
test_result.reason = str(reason)
test_result.results = [
{
'id': test.id,
'name': str(test),
'error': getattr(test, 'error', None),
'formdata': json.dumps(formdata_json, cls=misc.JSONEncoder),
'details': {
'recorded_errors': test.recorded_errors,
'missing_required_fields': test.missing_required_fields,
'sent_requests': test.sent_requests,
'workflow_test_action_uuid': test.exception.action_uuid if test.exception else None,
'error_details': test.exception.details if test.exception else None,
'error_field_id': test.exception.field_id if test.exception else None,
},
}
for test in testdefs
]
test_result.results.sort(key=lambda x: not bool(x['error']))
test_result.store()
return test_result
class WebserviceResponsePage(Directory):
_q_exports = ['', 'delete', 'duplicate']
def __init__(self, component, testdef):
self.testdef = testdef
try:
self.webservice_response = [x for x in testdef.get_webservice_responses() if x.id == component][0]
except IndexError:
raise TraversalError()
def _q_index(self):
form = Form(enctype='multipart/form-data')
form.add(
StringWidget, 'name', size=50, title=_('Name'), required=True, value=self.webservice_response.name
)
form.add(
UrlWidget,
'url',
title=_('URL'),
required=True,
value=self.webservice_response.url,
size=80,
)
def validate_json(value):
try:
json.loads(value)
except ValueError as e:
raise ValueError(_('Invalid JSON: %s') % e)
form.add(
TextWidget,
'payload',
title=_('Response payload (JSON)'),
required=True,
value=self.webservice_response.payload,
validation_function=validate_json,
)
form.add(
RadiobuttonsWidget,
'status_code',
title=_('Response status code'),
required=True,
options=[200, 204, 400, 401, 403, 404, 500, 502, 503],
value=self.webservice_response.status_code,
extra_css_class='widget-inline-radio',
)
form.add(
WidgetDict,
'qs_data',
title=_('Restrict to query string data'),
value=self.webservice_response.qs_data or {},
element_value_type=StringWidget,
allow_empty_values=True,
value_for_empty_value='',
)
methods = collections.OrderedDict(
[
('', _('Any')),
('GET', _('GET')),
('POST', _('POST (JSON)')),
('PUT', _('PUT (JSON)')),
('PATCH', _('PATCH (JSON)')),
('DELETE', _('DELETE (JSON)')),
]
)
form.add(
RadiobuttonsWidget,
'method',
title=_('Restrict to method'),
options=list(methods.items()),
value=self.webservice_response.method,
attrs={'data-dynamic-display-parent': 'true'},
extra_css_class='widget-inline-radio',
)
form.add(
WidgetDict,
'post_data',
title=_('Restrict to POST data'),
value=self.webservice_response.post_data or {},
element_value_type=StringWidget,
allow_empty_values=True,
value_for_empty_value='',
attrs={
'data-dynamic-display-child-of': 'method',
'data-dynamic-display-value-in': '|'.join(
[
str(_(methods['POST'])),
str(_(methods['PUT'])),
str(_(methods['PATCH'])),
str(_(methods['DELETE'])),
]
),
},
)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
form.add_media()
if form.get_widget('cancel').parse():
return redirect('.')
if form.get_submit() != 'submit' or form.has_errors():
get_response().breadcrumb.append(('edit', _('Edit webservice response')))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % (_('Edit webservice response'))
r += form.render()
return r.getvalue()
self.webservice_response.name = form.get_widget('name').parse()
self.webservice_response.payload = form.get_widget('payload').parse()
self.webservice_response.url = form.get_widget('url').parse()
self.webservice_response.status_code = form.get_widget('status_code').parse()
self.webservice_response.qs_data = form.get_widget('qs_data').parse()
self.webservice_response.method = form.get_widget('method').parse()
self.webservice_response.post_data = form.get_widget('post_data').parse()
self.webservice_response.store()
return redirect('..')
def delete(self):
form = Form(enctype='multipart/form-data')
form.add_submit('delete', _('Delete'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('delete', _('Delete')))
r = TemplateIO(html=True)
r += htmltext('<h2>%s %s</h2>') % (_('Deleting:'), self.webservice_response)
r += form.render()
return r.getvalue()
self.webservice_response.remove_self()
return redirect('..')
def duplicate(self):
new_webservice_response = copy.deepcopy(self.webservice_response)
new_webservice_response.id = None
new_webservice_response.name = '%s %s' % (new_webservice_response.name, _('(copy)'))
new_webservice_response.store()
return redirect('..')
class WebserviceResponseDirectory(Directory):
_q_exports = ['', 'new']
def __init__(self, testdef):
self.testdef = testdef
def _q_traverse(self, path):
get_response().breadcrumb.append(('webservice-responses/', _('Webservice responses')))
return super()._q_traverse(path)
def _q_lookup(self, component):
return WebserviceResponsePage(component, self.testdef)
def _q_index(self):
context = {
'webservice_responses': self.testdef.get_webservice_responses(),
'has_sidebar': True,
}
get_response().add_javascript(['popup.js'])
get_response().set_title(_('Webservice responses'))
return template.QommonTemplateResponse(
templates=['wcs/backoffice/test-webservice-responses.html'],
context=context,
is_django_native=True,
)
def new(self):
form = Form(enctype='multipart/form-data')
form.add(StringWidget, 'name', title=_('Name'), required=True, size=50)
form.add_submit('submit', _('Submit'))
form.add_submit('cancel', _('Cancel'))
if form.get_widget('cancel').parse():
return redirect('.')
if not form.is_submitted() or form.has_errors():
get_response().breadcrumb.append(('new', _('New')))
get_response().set_title(_('New webservice response'))
r = TemplateIO(html=True)
r += htmltext('<h2>%s</h2>') % _('New webservice response')
r += form.render()
return r.getvalue()
webservice_response = WebserviceResponse()
webservice_response.testdef_id = self.testdef.id
webservice_response.name = form.get_widget('name').parse()
webservice_response.store()
return redirect(self.testdef.get_admin_url() + 'webservice-responses/%s/' % webservice_response.id)