1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-08-08 05:18:37 +02:00

Webui admin controller bugfix & factorisation

Implements a new exception class for webui : HttpErrors that uses a new template : errors.html to display multiples errors
This commit is contained in:
Yann 2016-11-17 15:05:18 +01:00
commit 4df8bdea89
3 changed files with 129 additions and 85 deletions

View file

@ -47,5 +47,25 @@ class HttpException(Exception):
return HttpException.STATUS_STR[status_fam][status_code]
##@brief Render multiple errors
class HttpErrors(HttpException):
def __init__(self, errors, title = None, status_code = 400):
super().__init__(status_code = status_code, tpl = 'errors.html',
custom = title)
self.errors = errors
def render(self, request):
from .interface.template.loader import TemplateLoader
loader = TemplateLoader()
tpl_vars = {
'status_code': self.status_code,
'errors': self.errors,
'title': self.custom }
response = Response(
loader.render_to_response(self.tpl, template_vars = tpl_vars),
mimetype = 'text/html')
response.status_code = self.status_code
return response

View file

@ -6,7 +6,9 @@ from lodel.context import LodelContext
LodelContext.expose_modules(globals(), {
'lodel.leapi.exceptions': [],
'lodel.logger': 'logger',
'lodel.leapi.datahandlers.base_classes': ['MultipleRef']})
'lodel.leapi.datahandlers.base_classes': ['MultipleRef'],
'lodel.leapi.exceptions': ['LeApiDataCheckErrors'],
'lodel.exceptions': ['LodelExceptions']})
from ...client import WebUiClient
import leapi_dyncode as dyncode
@ -37,54 +39,20 @@ def admin_update(request):
# return get_response('users/signin.html')
msg=''
# If the form has been submitted
if request.method == 'POST':
error = None
datas = list()
classname = request.form['classname']
logger.warning('Composed uids broken here')
uid = request.form['uid']
datas = process_form(request)
if not(datas is False):
if 'lodel_id' not in datas:
raise HttpException(400)
target_leo = dyncode.Object.name2class(datas['classname'])
leo = target_leo.get_from_uid(datas['lodel_id'])
try:
target_leo = dyncode.Object.name2class(classname)
except LeApiError:
classname = None
if classname is None or target_leo.is_abstract():
raise HttpException(400, custom = "Bad classname given")
leo_to_update = target_leo.get_from_uid(uid)
errors = dict()
for fieldname, value in request.form.items():
#We want to drop 2 input named 'classname' and 'uid'
if len(fieldname) > 12:
#Other input names are : field_input_FIELDNAME
#Extract the fieldname
fieldname = fieldname[12:]
try:
dh = leo_to_update.data_handler(fieldname)
except NameError as e:
errors[fieldname] = e
continue
#Multiple ref list preparation
if issubclass(dh.__class__, MultipleRef):
value=[spl for spl in [
v.strip() for v in value.split(LIST_SEPARATOR)]
if len(spl) > 0]
elif len(value.strip()) == 0:
value = None
try:
leo_to_update.set_data(fieldname, value)
except Exception as e:
errors[fieldname] = e
continue
if len(errors) > 0:
custom_msg = '<h1>Errors in datas</h1><ul>'
for fname, error in errors.items():
custom_msg += '<li>%s : %s</li>' % (
fname, error)
custom_msg += '</ul>'
raise HttpException(400, custom = custom_msg)
leo_to_update.update()
leo.update(
{ f:datas[f] for f in datas if f not in ('classname', 'lodel_id')})
except LeApiDataCheckErrors as e:
raise HttpErrors(
title='Form validation errors', errors = e._exceptions)
# Display of the form with the object's values to be updated
if 'classname' in request.GET:
@ -134,45 +102,25 @@ def admin_create(request):
# temporary, the acl will be more restrictive
#if WebUiClient.is_anonymous():
# return get_response('users/signin.html')
classname = None
# If the form has been submitted
if request.method == 'POST':
error = None
datas = list()
classname = request.form['classname']
try:
target_leo = dyncode.Object.name2class(classname)
except LeApiError:
classname = None
if classname is None or target_leo.is_abstract():
datas = process_form(request)
if not(datas is False):
target_leo = dyncode.Object.name2class(datas['classname'])
if 'lodel_id' in datas:
raise HttpException(400)
fieldnames = target_leo.fieldnames()
fields = dict()
for in_put, in_value in request.form.items():
# The classname is handled by the datasource, we are not allowed to modify it
# both are hidden in the form, to identify the object here
if in_put != 'classname' and in_value != '':
dhl = target_leo.data_handler(in_put[12:])
if dhl.is_reference() and in_value != '' and not dhl.is_singlereference():
logger.info(in_value)
in_value.replace(" ","")
in_value=in_value.split(',')
in_value=list(in_value)
fields[in_put[12:]] = in_value
if in_value == '':
fields[in_put[12:]] = None
# Insertion in the database of the values corresponding to a new object
new_uid = target_leo.insert(fields)
# reurn to the form with a confirmation or error message
if not new_uid is None:
msg = 'Successfull creation';
try:
new_uid = target_leo.insert(
{ f:datas[f] for f in datas if f != 'classname'})
except LeApiDataCheckErrors as e:
raise HttpErrors(
title='Form validation errors', errors = e._exceptions)
if new_uid is None:
raise HttpException(400, "Creation fails")
else:
msg = 'Oops something wrong happened...object not saved'
return get_response('admin/admin_create.html', target=target_leo, msg = msg)
return get_response(
'admin/admin_create.html', target=target_leo,
msg = "Created with uid %s" % new_uid)
# Display of an empty form
if 'classname' in request.GET:
# We need the class to create an object in
@ -320,4 +268,62 @@ def search_object(request):
# TODO The get method must be implemented here
return get_response('admin/admin_search.html', my_classes = dyncode.dynclasses)
##@brief Process a form POST and return the posted datas
#@param request : the request object
#@return a dict with datas as value and fieldname as key
def process_form(request):
if request.method != 'POST':
return False
res = dict()
errors = dict()
#Fetch concerned LeObject
if 'classname' not in request.form:
logger.error("Received a form without classname !")
raise HttpException(400)
res['classname'] = classname = request.form['classname']
try:
target_leo = dyncode.Object.name2class(classname)
except LeApiError:
logger.error(
"Received a form with an invalid leo name : '%s'" % classname)
raise HttpException(400, "No leobject named '%s'" % classname)
if target_leo.is_abstract():
logger.error(
"Received a form with an abstract leo : '%s'" % classname)
raise HttpException(400, '%s is abstract' % classname)
#Process input fields
for fieldname, value in request.form.items():
if fieldname == 'classname':
continue
elif fieldname == 'uid':
fieldname = 'lodel_id' #wow
elif fieldname.startswith('field_input_'):
fieldname = fieldname[12:]
try:
dh = target_leo.data_handler(fieldname)
except NameError as e:
errors[fieldname] = e
continue
if dh.is_reference() and not dh.is_singlereference():
#Converting multiple references fields
value = value.strip()
if len(value) == 0:
#handling default value for empty string
if hasattr(dh, 'default'):
value = dh.default
else:
#if not explicit default value, enforcing default as
#an empty list
value = []
else:
value = [ v.strip() for v in value.split(LIST_SEPARATOR) ]
else:
#Handling default value for empty string
if len(value.strip()) == 0 and hasattr(dh, 'default'):
value = dh.default
res[fieldname] = value
if len(errors) > 0:
del(res)
raise HttpErrors(errors, title="Form validation error")
return res

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<head>
<title>{{status_code}} {{status_str}}</title>
</head>
<body>
{% if title is not none %}
<h1>{{title}}</h1>
{% else %}
<h1>{{status_code}} {{status_str}}</h1>
{% endif %}
<ul>
{% for k, v in errors.items() %}
<li><strong>{{k}}</strong> : {{v}}</li>
{% endfor %}
</ul>
</body>
</html>