Commit b5eb2cc3 authored by Tomáš Peterka's avatar Tomáš Peterka

[hal_json] Restrict Reports in callDialogMethod for skins Hal and OOx

parent 510617cd
...@@ -6,26 +6,25 @@ from Products.ERP5Type.Log import log, DEBUG, INFO, WARNING ...@@ -6,26 +6,25 @@ from Products.ERP5Type.Log import log, DEBUG, INFO, WARNING
# 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)
def isListBox(field): def isFieldType(field, type_name):
if field.meta_type=='ListBox': if field.meta_type == 'ProxyField':
return True field = field.getRecursiveTemplateField()
elif field.meta_type=='ProxyField': return field.meta_type == type_name
template_field = field.getRecursiveTemplateField()
if template_field.meta_type=='ListBox': from Products.Formulator.Errors import FormValidationError, ValidationError
return True
return False
from Products.Formulator.Errors import FormValidationError
from ZTUtils import make_query from ZTUtils import make_query
request = REQUEST request = REQUEST
if REQUEST is None: if REQUEST is None:
request = container.REQUEST request = container.REQUEST
# request.form holds POST data thus containing 'field_' + field.id items
# such as 'field_your_some_field'
request_form = request.form request_form = request.form
error_message = '' error_message = ''
translate = context.Base_translateString
# Make this script work alike wether called from another script or by a request # Make this script work alike no matter if called by a script or a request
kw.update(request_form) kw.update(request_form)
# Exceptions for UI # Exceptions for UI
...@@ -63,6 +62,7 @@ if dialog_method == 'Base_editRelation': ...@@ -63,6 +62,7 @@ if dialog_method == 'Base_editRelation':
listbox_uid=kw.get('listbox_uid', None), listbox_uid=kw.get('listbox_uid', None),
saved_form_data=kw['saved_form_data']) saved_form_data=kw['saved_form_data'])
# Exception for create relation # Exception for create relation
# Not used in new UI - relation field implemented using JIO calls from JS
if dialog_method == 'Base_createRelation': if dialog_method == 'Base_createRelation':
return context.Base_createRelation(form_id=kw['form_id'], return context.Base_createRelation(form_id=kw['form_id'],
selection_name=kw['list_selection_name'], selection_name=kw['list_selection_name'],
...@@ -80,6 +80,25 @@ if dialog_method == 'Folder_delete': ...@@ -80,6 +80,25 @@ 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
...@@ -95,54 +114,54 @@ try: ...@@ -95,54 +114,54 @@ try:
request.set('editable_mode', 1) request.set('editable_mode', 1)
form.validate_all_to_request(request) form.validate_all_to_request(request)
request.set('editable_mode', editable_mode) request.set('editable_mode', editable_mode)
except FormValidationError, 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 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')
# Use REQUEST.redirect if possible. It will not be possible if at least one of these is true : default_skin = context.getPortalObject().portal_skins.getDefaultSkin()
# * we got an import_file, allowed_styles = ("ODT", "ODS", "Hal", "HalRestricted")
# * we got a listbox if getattr(getattr(context, dialog_method), 'pt', None) == "report_view" and \
# * a value is None or [] or (), because this is not supported by make_query request.get('your_portal_skin', default_skin) not in allowed_styles:
can_redirect = 1 # RJS own validation - only ODS/ODT and Hal* skins work for reports
# 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
# XXX TODO: Form-wide validation errors
return handleFormError(
form,
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'))
], {}))
except FormValidationError as validation_errors:
return handleFormError(form, validation_errors)
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.
file_id_list = [] # For uploaded files. file_id_list = [] # For uploaded files.
for field in form.get_fields(): for field in form.get_fields():
k = field.id field_id = field.id
v = request.get(k, MARKER) field_value = request.get(field_id, MARKER)
if v is not MARKER:
if isListBox(field): if field_value is not MARKER:
listbox_id_list.append(k) if isFieldType(field, "ListBox"):
elif can_redirect and (v in (None, [], ()) or hasattr(v, 'read')) : # If we cannot redirect, useless to test it again listbox_id_list.append(field_id)
can_redirect = 0
# Cleanup my_ and your_ prefixes if present
# Cleanup my_ and your_ prefixes if field_id.startswith("my_") or field_id.startswith("your_"):
splitted = k.split('_', 1) _, field_name = field_id.split('_', 1)
if len(splitted) == 2 and splitted[0] in ('my', 'your'): if hasattr(field_value, 'as_dict'):
if hasattr(v, 'as_dict'): # This is an encapsulated editor - convert it
# This is an encapsulated editor kw.update(field_value.as_dict())
# convert it
kw.update(v.as_dict())
else: else:
kw[splitted[1]] = request_form[splitted[1]] = v kw[field_name] = request_form[field_name] = field_value
else: else:
kw[k] = request_form[k] = v kw[field_id] = request_form[field_id] = field_value
if len(listbox_id_list): if len(listbox_id_list):
can_redirect = 0
# Warn if there are more than one listbox in form ... # Warn if there are more than one listbox in form ...
if len(listbox_id_list) > 1: if len(listbox_id_list) > 1:
log('Base_callDialogMethod', 'There are %s listboxes in form %s.' % (len(listbox_id_list), form.id)) log('Base_callDialogMethod', 'There are %s listboxes in form %s.' % (len(listbox_id_list), form.id))
...@@ -183,11 +202,8 @@ if listbox_uid is not None and kw.has_key('list_selection_name'): ...@@ -183,11 +202,8 @@ if listbox_uid is not None and kw.has_key('list_selection_name'):
selected_uids = context.portal_selections.updateSelectionCheckedUidList( selected_uids = context.portal_selections.updateSelectionCheckedUidList(
kw['list_selection_name'], kw['list_selection_name'],
listbox_uid, uids) listbox_uid, uids)
# Remove unused parameter # Remove empty values for make_query.
clean_kw = {} clean_kw = dict((k, v) for k, v in kw.items() if v not in (None, [], ()))
for k, v in kw.items() :
if v not in (None, [], ()) :
clean_kw[k] = kw[k]
# Handle deferred style, unless we are executing the update action # Handle deferred style, unless we are executing the update action
if dialog_method != update_method and clean_kw.get('deferred_style', 0): if dialog_method != update_method and clean_kw.get('deferred_style', 0):
...@@ -195,8 +211,23 @@ if dialog_method != update_method and clean_kw.get('deferred_style', 0): ...@@ -195,8 +211,23 @@ if dialog_method != update_method and clean_kw.get('deferred_style', 0):
# XXX Hardcoded Deferred style name # XXX Hardcoded Deferred style name
clean_kw['portal_skin'] = 'Deferred' clean_kw['portal_skin'] = 'Deferred'
dialog_form = getattr(context, dialog_method) page_template = getattr(getattr(context, dialog_method), 'pt', None)
page_template = getattr(dialog_form, 'pt', None)
if page_template == 'report_view':
# Limit Reports in Deferred style to known working styles
if request_form.get('your_portal_skin', None) not in ("ODT", "ODS"):
# RJS own validation - deferred option works here only with ODS/ODT skins
return handleFormError(
form,
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"'))
], {}))
# 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':
# use simple wrapper # use simple wrapper
...@@ -205,14 +236,13 @@ if dialog_method != update_method and clean_kw.get('deferred_style', 0): ...@@ -205,14 +236,13 @@ if dialog_method != update_method and clean_kw.get('deferred_style', 0):
request.set('deferred_style_dialog_method', dialog_method) request.set('deferred_style_dialog_method', dialog_method)
dialog_method = 'Base_activateSimpleView' dialog_method = 'Base_activateSimpleView'
url_params_string = make_query(clean_kw) url_params_string = make_query(clean_kw)
# XXX: We always redirect in report mode to make sure portal_skin # Never redirect in JSON style - do as much as possible here.
# parameter is taken into account by SkinTool. # At this point the 'dialog_method' should point to a form (if we are in report)
# If url is too long, we do not redirect to avoid crash. # if we are not in Deferred mode - then it points to `Base_activateSimpleView`
# XXX: 2000 is an arbitrary value resulted from trial and error.
if (not(can_redirect) or len(url_params_string) > 2000): if True:
if dialog_method != update_method: if dialog_method != update_method:
# When we are not executing the update action, we have to change the skin # When we are not executing the update action, we have to change the skin
# manually, # manually,
...@@ -222,6 +252,7 @@ if (not(can_redirect) or len(url_params_string) > 2000): ...@@ -222,6 +252,7 @@ if (not(can_redirect) or len(url_params_string) > 2000):
request.set('portal_skin', new_skin_name) request.set('portal_skin', new_skin_name)
deferred_portal_skin = clean_kw.get('deferred_portal_skin') deferred_portal_skin = clean_kw.get('deferred_portal_skin')
if deferred_portal_skin: if deferred_portal_skin:
# has to be either ODS or ODT because only those contain `form_list`
request.set('deferred_portal_skin', deferred_portal_skin) request.set('deferred_portal_skin', deferred_portal_skin)
# and to cleanup formulator's special key in request # and to cleanup formulator's special key in request
# XXX unless we are in Folder_modifyWorkflowStatus which validates again ! # XXX unless we are in Folder_modifyWorkflowStatus which validates again !
...@@ -230,15 +261,28 @@ if (not(can_redirect) or len(url_params_string) > 2000): ...@@ -230,15 +261,28 @@ if (not(can_redirect) or len(url_params_string) > 2000):
if str(key).startswith('field') or str(key).startswith('subfield'): if str(key).startswith('field') or str(key).startswith('subfield'):
request.form.pop(key, None) request.form.pop(key, None)
# If we cannot redirect, then call the form directly. # now get dialog_method after skin re-selection and dialog_method mingling
dialog_form = getattr(context, dialog_method) dialog_form = getattr(context, dialog_method)
# XXX: this is a hack that should not be needed anymore with the new listbox. # XXX: this is a hack that should not be needed anymore with the new listbox.
# set the URL in request, so that we can immediatly call method # set the URL in request, so that we can immediatly call method
# that depend on it (eg. Show All). This is really related to # that depend on it (eg. Show All). This is really related to
# current ListBox implementation which edit Selection's last_url # current ListBox implementation which edit Selection's last_url
# with the content of REQUEST.URL # with the content of REQUEST.URL
request.set('URL', '%s/%s' % (context.absolute_url(), dialog_method)) request.set('URL', '%s/%s' % (context.absolute_url(), dialog_method))
# RJS: If we are in deferred mode - call the form directly and return
# dialog method is now `Base_activateSimpleView` - the only script in
# deferred portal_skins folder
if clean_kw.get('deferred_style', 0):
return dialog_form(**kw) # deferred form should return redirect with a message
# RJS: If skin selection is different than Hal* then ERP5Document_getHateoas
# does not exist and we call form method directly
if clean_kw.get("portal_skin", context.getPortalObject().portal_skins.getDefaultSkin()) not in ("Hal", "HalRestricted"):
return dialog_form(**kw) return dialog_form(**kw)
dialog_method = getattr(context, dialog_method) return context.ERP5Document_getHateoas(REQUEST=request, form=dialog_form, mode="form")
return dialog_method(**clean_kw)
# XXX If somebody knows in which case this gets executed ... please tell me.
return getattr(context, dialog_method)(**kw)
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