Commit 1a400b57 authored by Tomáš Peterka's avatar Tomáš Peterka

[renderjs_iu] Dialogs have customizable error message via HTTP500 JSON-encoded response

parent 8db4de0a
...@@ -3,6 +3,7 @@ Generic method called when submitting a form in dialog mode. ...@@ -3,6 +3,7 @@ Generic method called when submitting a form in dialog mode.
Responsible for validating form data and redirecting to the form action. Responsible for validating form data and redirecting to the form action.
""" """
from Products.ERP5Type.Log import log, DEBUG, INFO, WARNING from Products.ERP5Type.Log import log, DEBUG, INFO, WARNING
import json
# XXX We should not use meta_type properly, # XXX We should not use meta_type properly,
# XXX We need to discuss this problem.(yusei) # XXX We need to discuss this problem.(yusei)
...@@ -14,10 +15,17 @@ def isFieldType(field, type_name): ...@@ -14,10 +15,17 @@ def isFieldType(field, type_name):
from Products.Formulator.Errors import FormValidationError, ValidationError from Products.Formulator.Errors import FormValidationError, ValidationError
from ZTUtils import make_query from ZTUtils import make_query
def failWithMessage(message, request=None):
response = request.RESPONSE if request is not None else context.REQUEST.RESPONSE
response.setStatus(500)
response.setHeader("Content-type", "application/json; charset=utf-8")
return json.dumps({"portal_status_message": str(message)})
# Kato: I do not understand why we throw away REQUEST from parameters (hidden in **kw) # Kato: I do not understand why we throw away REQUEST from parameters (hidden in **kw)
# and use container.REQUEST just to introduce yet another global state # and use container.REQUEST just to introduce yet another global state. Maybe because
# because REUQEST from arguments is a different instance than container.REQUEST! # container.REQUEST is used in other places.
request = container.REQUEST # Well, REQUEST from arguments is a different instance than container.REQUEST so it will create problems...
request = kw.get('REQUEST', None) or container.REQUEST
# request.form holds POST data thus containing 'field_' + field.id items # request.form holds POST data thus containing 'field_' + field.id items
# such as 'field_your_some_field' # such as 'field_your_some_field'
...@@ -81,25 +89,6 @@ if dialog_method == 'Folder_delete': ...@@ -81,25 +89,6 @@ if dialog_method == 'Folder_delete':
selection_name=kw['selection_name'], selection_name=kw['selection_name'],
md5_object_uid_list=kw['md5_object_uid_list']) md5_object_uid_list=kw['md5_object_uid_list'])
def handleFormError(form, validation_errors):
"""Return correctly rendered form with all errors assigned to its fields."""
field_errors = form.ErrorFields(validation_errors)
# Pack errors into the request
request.set('field_errors', field_errors)
# Make sure editors are pushed back as values into the REQUEST object
for f in form.get_fields():
field_id = f.id
if request.has_key(field_id):
value = request.get(field_id)
if callable(value):
value(request)
if silent_mode:
return context.ERP5Document_getHateoas(form=form, REQUEST=request, mode='form'), 'form'
request.RESPONSE.setStatus(400)
return context.ERP5Document_getHateoas(form=form, REQUEST=request, mode='form')
form = getattr(context, dialog_id) form = getattr(context, dialog_id)
# form can be a python script that returns the form # form can be a python script that returns the form
...@@ -124,19 +113,25 @@ try: ...@@ -124,19 +113,25 @@ try:
# Form is OK, it's just this field - style so we return back form-wide error # Form is OK, it's just this field - style so we return back form-wide error
# for which we don't have support out-of-the-box thus we manually craft it # for which we don't have support out-of-the-box thus we manually craft it
# XXX TODO: Form-wide validation errors # XXX TODO: Form-wide validation errors
return handleFormError( return failWithMessage(
form, translate('Only ODT, ODS, Hal and HalRestricted skins are allowed for reports '\
FormValidationError([
ValidationError(
error_key=None,
field=form.get_field('your_portal_skin'),
error_text=translate(
'Only ODT, ODS, Hal and HalRestricted skins are allowed for reports '\
'in Preferences - User Interface - Report Style')) 'in Preferences - User Interface - Report Style'))
], {}))
except FormValidationError as validation_errors: except FormValidationError as validation_errors:
return handleFormError(form, validation_errors) # Pack errors into the request
field_errors = form.ErrorFields(validation_errors)
request.set('field_errors', field_errors)
# Make sure editors are pushed back as values into the REQUEST object
for f in form.get_fields():
field_id = f.id
if request.has_key(field_id):
value = request.get(field_id)
if callable(value):
value(request)
if kw.get('silent_mode', False): return context.ERP5Document_getHateoas(form=form, REQUEST=request, mode='form'), 'form'
request.RESPONSE.setStatus(400)
return context.ERP5Document_getHateoas(form=form, REQUEST=request, mode='form')
MARKER = [] # A recognisable default value. Use with 'is', not '=='. MARKER = [] # A recognisable default value. Use with 'is', not '=='.
listbox_id_list = [] # There should not be more than one listbox - but this give us a way to check. listbox_id_list = [] # There should not be more than one listbox - but this give us a way to check.
...@@ -218,16 +213,9 @@ if dialog_method != update_method and clean_kw.get('deferred_style', 0): ...@@ -218,16 +213,9 @@ if dialog_method != update_method and clean_kw.get('deferred_style', 0):
# Limit Reports in Deferred style to known working styles # Limit Reports in Deferred style to known working styles
if request_form.get('your_portal_skin', None) not in ("ODT", "ODS"): if request_form.get('your_portal_skin', None) not in ("ODT", "ODS"):
# RJS own validation - deferred option works here only with ODS/ODT skins # RJS own validation - deferred option works here only with ODS/ODT skins
return handleFormError( return failWithMessage(
form, translate('Deferred reports are possible only with preference '\
FormValidationError([
ValidationError(
error_key=None,
field=form.get_field('your_deferred_style'),
error_text=translate(
'Deferred reports are possible only with preference '\
'"Report Style" set to "ODT" or "ODS"')) '"Report Style" set to "ODT" or "ODS"'))
], {}))
# If the action form has report_view as it's method, it # If the action form has report_view as it's method, it
if page_template != 'report_view': if page_template != 'report_view':
......
...@@ -86,7 +86,7 @@ def ensureSerializable(obj): ...@@ -86,7 +86,7 @@ def ensureSerializable(obj):
obj[key] = ensureSerializable(obj[key]) obj[key] = ensureSerializable(obj[key])
# throw away date's type information and later reconstruct as Zope's DateTime # throw away date's type information and later reconstruct as Zope's DateTime
if isinstance(obj, DateTime): if isinstance(obj, DateTime):
return obj.ISO() return obj.ISO() + ' ' + obj.timezone() # ISO with timezone
if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)): if isinstance(obj, (datetime.datetime, datetime.date, datetime.time)):
return obj.isoformat() return obj.isoformat()
# let us believe that iterables don't contain other unserializable objects # let us believe that iterables don't contain other unserializable objects
......
...@@ -341,7 +341,7 @@ ...@@ -341,7 +341,7 @@
.push(undefined, function (error) { .push(undefined, function (error) {
if (error.target !== undefined) { if (error.target !== undefined) {
var error_text = 'Encountered an unknown error. Try to resubmit', var error_text = 'Encountered an unknown error. Try to resubmit',
promise; promise_queue = new RSVP.Queue();
// if we know what the error was, try to precise it for the user // if we know what the error was, try to precise it for the user
if (error.target.status === 400) { if (error.target.status === 400) {
error_text = 'Input data has errors'; error_text = 'Input data has errors';
...@@ -349,9 +349,21 @@ ...@@ -349,9 +349,21 @@
error_text = 'You do not have the permissions to edit the object'; error_text = 'You do not have the permissions to edit the object';
} else if (error.target.status === 0) { } else if (error.target.status === 0) {
error_text = 'Document was not saved! Resubmit when you are online or the document accessible'; error_text = 'Document was not saved! Resubmit when you are online or the document accessible';
} else if (error.target.status === 500 && error.target.response.type === "application/json") {
promise_queue
.push(function () {
return jIO.util.readBlobAsText(error.target.response);
})
.push(function (response_text) {
var response = JSON.parse(response_text.target.result);
error_text = response.portal_status_message;
});
} }
// display translated error_text to user // display translated error_text to user
promise = form_gadget.notifySubmitted() promise_queue
.push(function () {
return form_gadget.notifySubmitted();
})
.push(function () { .push(function () {
return form_gadget.translate(error_text); return form_gadget.translate(error_text);
}) })
...@@ -364,7 +376,7 @@ ...@@ -364,7 +376,7 @@
// if server validation of form data failed (indicated by response code 400) // if server validation of form data failed (indicated by response code 400)
// we parse out field errors and display them to the user // we parse out field errors and display them to the user
if (error.target.status === 400) { if (error.target.status === 400) {
promise promise_queue
.push(function () { .push(function () {
// when the server-side validation returns the error description // when the server-side validation returns the error description
if (error.target.responseType === "blob") { if (error.target.responseType === "blob") {
...@@ -377,7 +389,7 @@ ...@@ -377,7 +389,7 @@
return form_gadget.displayFormulatorValidationError(JSON.parse(event.target.result)); return form_gadget.displayFormulatorValidationError(JSON.parse(event.target.result));
}); });
} }
return promise; return promise_queue;
} }
throw error; throw error;
}); });
......
...@@ -230,7 +230,7 @@ ...@@ -230,7 +230,7 @@
</item> </item>
<item> <item>
<key> <string>serial</string> </key> <key> <string>serial</string> </key>
<value> <string>963.65326.20561.44834</string> </value> <value> <string>965.3172.8117.46779</string> </value>
</item> </item>
<item> <item>
<key> <string>state</string> </key> <key> <string>state</string> </key>
...@@ -248,7 +248,7 @@ ...@@ -248,7 +248,7 @@
</tuple> </tuple>
<state> <state>
<tuple> <tuple>
<float>1512740130.49</float> <float>1516875722.83</float>
<string>UTC</string> <string>UTC</string>
</tuple> </tuple>
</state> </state>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment