Commit 4326453e authored by Pierre Dittgen's avatar Pierre Dittgen

Display fix actions instead of errors

parent 33a81aa6
......@@ -36,3 +36,7 @@ body {
.table .thead-light th.table-warning {
background-color: #ffeeba;
}
div.actions ul li p {
margin-bottom: 0;
}
......@@ -88,26 +88,29 @@
</div>
</div>
{% if report.error_count > 0 %}
{% if report.table.errors.structure %}
<h3 class="my-4">Erreurs de structure</h3>
<ul class="structure_errors">
{# Non-column errors #}
{% for err in report.table.errors.structure %}
{% if not err.in_column_comp %}
<li>{{ err.content | safe }}</li>
{% endif %}
{% endfor %}
{# Column errors #}
{% for err in report.table.errors.structure %}
{% if err.in_column_comp %}
<li>{{ err.content | safe }}</li>
{% endif %}
{% endfor %}
</ul>
<p class="text-muted">Les colonnes du fichier ont été remaniées selon l'ordre dicté par le schema.</p>
{% endif %}
{% if report.repair_actions %}
<div class="row my-4 actions">
<div class="col-lg-12 card">
<div class="card-body">
<div class="alert alert-danger">
<h4>Structure du fichier invalide</h4>
</div>
<p>
Afin de vous permettre de visualiser les erreurs de contenu potentiellement présentes
dans le fichier envoyé, la structure de votre fichier a été automatiquement remaniée :
</p>
<ul>
{% for action in report.repair_actions %}
<li>{{ action | commonmark2html | safe}}</li>
{% endfor %}
</ul>
<p>
Il vous appartient d'apporter ces modifications sur votre fichier pour rendre sa structure
valide selon le schéma.
</p>
</div>
</div>
</div>
{% endif %}
</div>
......
......@@ -195,6 +195,124 @@ def improve_errors(errors):
return list(map(improve_err, errors))
def compute_repair_actions(structure_errors):
"""Turn structure errors into repair action informations
"""
def handle_blank_headers(error_list, position_code, action_list, func=None, singular_msg_tpl="", plural_msg_tpl=""):
"""Factors code for blank-header errors
Warning: error_list parameter is modified in place
"""
blank_headers = [err for err in error_list
if err['code'] == 'blank-header' and err['message-data'].get('position') == position_code]
if blank_headers:
if func is None:
blank_headers_nb = len(blank_headers)
if blank_headers_nb == 1:
action_list.append(singular_msg_tpl)
else:
action_list.append(plural_msg_tpl.format(blank_headers_nb))
else:
func(action_list, blank_headers, singular_msg_tpl, plural_msg_tpl)
for err in blank_headers:
error_list.remove(err)
def handle_extra_duplicate_and_missing_errs(error_list, err_code, action_list, singular_msg_tpl, plural_msg_tpl):
"""Factors code for missing headers, extra headers and duplicate headers
Warning: error_list parameter is modified in place
"""
header_errors = [err for err in error_list if err['code'] == err_code]
col_names = ["`{}`".format(err['message-data']['column-name']) for err in header_errors]
if header_errors:
if len(header_errors) == 1:
action_list.append(singular_msg_tpl.format(col_names[0]))
else:
action_list.append(plural_msg_tpl.format(', '.join(col_names)))
for err in header_errors:
error_list.remove(err)
# No error, no info!
if not structure_errors:
return []
# keep a list of processed errors
pending_error_list = structure_errors.copy()
# action informations
action_list = []
# Leading blank headers
handle_blank_headers(pending_error_list, 'leading', action_list,
singular_msg_tpl='1 colonne sans en-tête avant les données a été supprimée',
plural_msg_tpl='{} colonnes sans en-tête avant les données ont été supprimées')
# inside empty header
def handle_in_blank_headers(action_list, error_list, singular_msg_tpl, plural_msg_tpl):
def add_msg(action_list, columns_nb, before, after, singular_msg_tpl, plural_msg_tpl):
if columns_nb == 1:
action_list.append(singular_msg_tpl.format(before, after))
else:
action_list.append(plural_msg_tpl.format(columns_nb, before, after))
before, after = None, None
columns_nb = 0
for err in sorted(error_list, key=lambda elt: elt['message-data']['column-number']):
before_header_name = err['message-data']['before-header-name']
after_header_name = err['message-data']['after-header-name']
if before_header_name == before and after_header_name == after:
columns_nb += 1
else:
if before is not None:
add_msg(action_list, columns_nb, before, after, singular_msg_tpl, plural_msg_tpl)
before = before_header_name
after = after_header_name
columns_nb = 1
add_msg(action_list, columns_nb, before, after, singular_msg_tpl, plural_msg_tpl)
handle_blank_headers(pending_error_list, 'in', action_list,
func=handle_in_blank_headers,
singular_msg_tpl='1 colonne sans en-tête (située entre les colonnes **{}** et **{}**) a été supprimée',
plural_msg_tpl='{} colonnes sans en-tête (situées entre les colonnes **{}** et **{}**) ont été supprimées')
# trailing empty headers
handle_blank_headers(pending_error_list, 'trailing', action_list,
singular_msg_tpl='1 colonne sans en-tête après les données a été supprimée',
plural_msg_tpl='{} colonnes sans en-tête après les données ont été supprimées')
# wrong-headers-order
wrong_headers_order = [err for err in pending_error_list if err['code'] == 'wrong-headers-order']
if wrong_headers_order:
action_list.append("L'ordre des colonnes du fichier a été rétabli")
pending_error_list = [err for err in pending_error_list if err not in wrong_headers_order]
# extra-headers
handle_extra_duplicate_and_missing_errs(pending_error_list,
'extra-header', action_list,
"La colonne {} inconnue du schéma a été rejetée après les données",
"Les colonnes {} inconnues du schéma ont été rejetées après les données")
# duplicate-header
handle_extra_duplicate_and_missing_errs(pending_error_list,
'duplicate-header', action_list,
"La colonne {} déjà rencontrée dans le fichier a été rejetée après les données",
"Les colonnes {} déjà rencontrées dans le fichier ont été rejetées après les données")
# missing-header
handle_extra_duplicate_and_missing_errs(pending_error_list,
'missing-header', action_list,
"La colonne {} absente du fichier a été ajoutée avec un contenu vide",
"Les colonnes {} absentes du fichier ont été ajoutées avec un contenu vide")
# unhandled errors (it may normally not happened)
for err in pending_error_list:
action_list.append('err: [{}] {}'.format(err['code'], err['message']))
return action_list
def create_validata_ui_report(validata_core_report, schema_dict):
""" Creates an error report easier to handle and display in templates:
- only one table
......@@ -270,6 +388,8 @@ def create_validata_ui_report(validata_core_report, schema_dict):
rows[-1]['errors']['row'] = err
report['table']['errors']['body_by_rows'] = rows
report['repair_actions'] = compute_repair_actions(report['table']['errors']['structure'])
# Sort by error names in statistics
stats = report['table']['error-stats']
code_title_map = messages.ERROR_MESSAGE_DEFAULT_TITLE
......
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