Skip to content

Commit

Permalink
Merge pull request #1305 from GSA-TTS/main
Browse files Browse the repository at this point in the history
2023-06-21 b7283a3 main -> prod
  • Loading branch information
asteel-gsa authored Jun 21, 2023
2 parents e07ae03 + b7283a3 commit 4dc2be4
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 80 deletions.
3 changes: 3 additions & 0 deletions backend/audit/fixtures/excel.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Fixtures for use with Excel spreadsheet handling.
"""
from collections import namedtuple
from django.conf import settings

Expand Down
49 changes: 14 additions & 35 deletions backend/audit/templates/audit/submission-progress.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,51 +129,37 @@ <h1 class="border-base-light margin-top-0">{{ auditee_name | default_if_none:''
<p class="margin-0">Sample description text, lorem ipsum, various questionably accurate latin phrases.</p>
</div>
</li>
<!-- Findings text workbook -->
<!-- Audit findings workbook -->
<li class="usa-icon-list__item padding-bottom-2">
<div class="usa-icon-list__icon {% if findings_text_workbook.completed == True %}text-green{% else %}text-base{% endif %}">
<div class="usa-icon-list__icon {% if audit_findings_workbook.completed == True %}text-green{% else %}text-base{% endif %}">
<svg class="usa-icon margin-right-2" aria-hidden="true" role="img">
{% if findings_text_workbook.completed == True %}
{% if audit_findings_workbook.completed == True %}
<use xlink:href="/static/img/sprite.svg#check_circle"></use>
{% else %}
<use xlink:href="/static/img/sprite.svg#radio_button_unchecked"></use>
{% endif %}
</svg>
</div>
<div class="usa-icon-list__content {% if findings_text_workbook.created is True %} text-green {% else %} text-base-dark {% endif %}">
{% if federal_awards_workbook.completed == True %}
<a class="usa-link text-bold"
href="/report_submission/audit-findings-text/{{ report_id | default_if_none:'' }}">Upload the Findings Text workbook</a>
{% else %}
<svg class="usa-icon margin-right-05" aria-hidden="true" role="img">
<use xlink:href="/static/img/sprite.svg#lock_outline"></use>
</svg>
<span class="text-base">Upload the Findings Text workbook</span>
{% endif %}
<div class="usa-icon-list__content {% if audit_findings_workbook.created is True %} text-green {% else %} text-base-dark {% endif %}">
<a class="usa-link text-bold"
href="/report_submission/audit-findings/{{ report_id | default_if_none:'' }}">Upload the Audit Findings workbook</a>
<p class="margin-0">Sample description text, lorem ipsum, various questionably accurate latin phrases.</p>
</div>
</li>
<!-- Audit findings workbook -->
<!-- Findings text workbook -->
<li class="usa-icon-list__item padding-bottom-2">
<div class="usa-icon-list__icon {% if audit_findings_workbook.completed == True %}text-green{% else %}text-base{% endif %}">
<div class="usa-icon-list__icon {% if findings_text_workbook.completed == True %}text-green{% else %}text-base{% endif %}">
<svg class="usa-icon margin-right-2" aria-hidden="true" role="img">
{% if audit_findings_workbook.completed == True %}
{% if findings_text_workbook.completed == True %}
<use xlink:href="/static/img/sprite.svg#check_circle"></use>
{% else %}
<use xlink:href="/static/img/sprite.svg#radio_button_unchecked"></use>
{% endif %}
</svg>
</div>
<div class="usa-icon-list__content {% if audit_findings_workbook.created is True %} text-green {% else %} text-base-dark {% endif %}">
{% if federal_awards_workbook.completed == True %}
<a class="usa-link text-bold"
href="/report_submission/audit-findings/{{ report_id | default_if_none:'' }}">Upload the Audit Findings workbook</a>
{% else %}
<svg class="usa-icon margin-right-05" aria-hidden="true" role="img">
<use xlink:href="/static/img/sprite.svg#lock_outline"></use>
</svg>
<span class="text-base">Upload the Audit Findings workbook</span>
{% endif %}
<div class="usa-icon-list__content {% if findings_text_workbook.created is True %} text-green {% else %} text-base-dark {% endif %}">
<a class="usa-link text-bold"
href="/report_submission/audit-findings-text/{{ report_id | default_if_none:'' }}">Upload the Findings Text workbook</a>
<p class="margin-0">Sample description text, lorem ipsum, various questionably accurate latin phrases.</p>
</div>
</li>
Expand All @@ -189,15 +175,8 @@ <h1 class="border-base-light margin-top-0">{{ auditee_name | default_if_none:''
</svg>
</div>
<div class="usa-icon-list__content {% if CAP_workbook.created is True %} text-green {% else %} text-base-dark {% endif %}">
{% if federal_awards_workbook.completed == True %}
<a class="usa-link text-bold"
href="/report_submission/CAP/{{ report_id | default_if_none:'' }}">Upload the Corrective Action Plan (CAP) workbook</a>
{% else %}
<svg class="usa-icon margin-right-05" aria-hidden="true" role="img">
<use xlink:href="/static/img/sprite.svg#lock_outline"></use>
</svg>
<span class="text-base">Upload the Corrective Action Plan (CAP) workbook</span>
{% endif %}
<a class="usa-link text-bold"
href="/report_submission/CAP/{{ report_id | default_if_none:'' }}">Upload the Corrective Action Plan (CAP) workbook</a>
<p class="margin-0">Sample description text, lorem ipsum, various questionably accurate latin phrases.</p>
</div>
</li>
Expand Down
11 changes: 9 additions & 2 deletions backend/audit/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from django.urls import reverse
from django.utils.datastructures import MultiValueDictKeyError
from django.utils.decorators import method_decorator
from django.http import JsonResponse

from .fixtures.excel import FORM_SECTIONS

Expand Down Expand Up @@ -137,11 +138,17 @@ def post(self, request, *args, **kwargs):
logger.warn(f"no SingleAuditChecklist found with report ID {report_id}")
raise PermissionDenied()
except ValidationError as e:
# The good error, where bad rows/columns are sent back in the request.
# These come back as tuples:
# [(col1, row1, field1, link1, help-text1), (col2, row2, ...), ...]
logger.warn(f"{form_section} Excel upload failed validation: {e}")
raise BadRequest(e)
return JsonResponse({"errors": list(e), "type": "error_row"}, status=400)
except MultiValueDictKeyError:
logger.warn("no file found in request")
logger.warn("No file found in request")
raise BadRequest()
except KeyError as e:
logger.warn(f"Field error. Field: {e}")
return JsonResponse({"errors": str(e), "type": "error_field"}, status=400)


class ReadyForCertificationView(SingleAuditChecklistAccessRequiredMixin, generic.View):
Expand Down
4 changes: 2 additions & 2 deletions backend/cypress/e2e/check-ueid.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ describe('Create New Audit', () => {
interception.response.body.validueid,
'Failure API Response'
);
console.log('Response:' + interception.response.body.validueid);
// console.log('Response:' + interception.response.body.validueid);
});
});

Expand All @@ -377,7 +377,7 @@ describe('Create New Audit', () => {
interception.response.body.validueid,
'Succcessful API Response'
);
console.log('Response:' + interception.response.body.validueid);
// console.log('Response:' + interception.response.body.validueid);
});
cy.url().should('include', '/report_submission/accessandsubmission');
});
Expand Down
2 changes: 1 addition & 1 deletion backend/cypress/e2e/display-submissions.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ describe('Display my audit submissions', () => {
).as('hasNoData');
cy.visit('/submissions/');
cy.wait('@hasNoData').then((interception) => {
console.log(interception);
// console.log(interception);
cy.get('.usa-table-container')
.should('have.attr', 'class')
.and('contain', 'display-none');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
{% extends "base.html" %}
{% load static %}
{% block content %}
<header class="usa-header usa-header-basic bg-primary-darker">
<div class="usa-nav-container">
<div class="usa-navbar bg-primary-darker text-white width-full flex">
<p class="margin-left-2">
<a href="/" class="text-gray-10">My audit submissions</a> »
<a href="/audit/submission-progress/{{ report_id }}" class="text-gray-10">{{ auditee_name | default_if_none:'' }}</a> »
<span class="text-bold">{{ view_name }}</span>
</p>
</div>
</div>
</header>
<header class="usa-header usa-header-basic bg-primary-darker">
<div class="usa-nav-container">
<div class="usa-navbar bg-primary-darker text-white width-full flex">
<p class="margin-left-2">
<a href="/" class="text-gray-10">My audit submissions</a> »
<a href="/audit/submission-progress/{{ report_id }}"
class="text-gray-10">{{ auditee_name | default_if_none:'' }}</a> »
<span class="text-bold">{{ view_name }}</span>
</p>
</div>
</div>
</header>
<div class="grid-container margin-top-6">
<div class="grid-row grid-gap">
<div class="grid-col grid-gap">
{% comment %} {% include "../sidenav.html" %} {% endcomment %}
<form class="usa-form usa-form--large"
id="{{ view_id }}"
Expand All @@ -39,12 +40,14 @@ <h4 class="usa-process-list__heading">Upload completed worksheet</h4>
accept=".xlsx"/>
</div>
{% if already_submitted %}
<p class="text-green" id="already-submitted">A file has already been uploaded for this section. A successful reupload will overwrite your previous submission.</p>
<p class="text-green" id="already-submitted">
A file has already been uploaded for this section. A successful reupload will overwrite your previous submission.
</p>
{% endif %}
<p hidden id="info_box"></p>
<button class="usa-button" id="continue" disabled="disabled">Continue to next section</button>
<button class="usa-button" id="continue" disabled="disabled">Return to Report Home</button>
</fieldset>
</form>
<div hidden id="info_box" class="grid-row margin-bottom-6"></div>
</div>
</div>
{% include "audit-metadata.html" %}
Expand Down
2 changes: 1 addition & 1 deletion backend/report_submission/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def post(self, request, *args, **kwargs):
SingleAuditChecklist.objects.filter(pk=sac.id).update(**update)

return redirect(
"/report_submission/federal-awards/{}".format(report_id)
"/audit/submission-progress/{report_id}".format(report_id=report_id)
)
except SingleAuditChecklist.DoesNotExist:
raise PermissionDenied("You do not have access to this audit.")
Expand Down
91 changes: 67 additions & 24 deletions backend/static/js/upload-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,66 @@ const already_submitted = document.getElementById(`already-submitted`);
Function definitions
*/
// Disable/enable "Continue" button
function setContinueButtonDisabled(disabled) {
function setFormDisabled(shouldDisable) {
const submitButton = document.getElementById('continue');
submitButton.disabled = disabled;
submitButton.disabled = shouldDisable;
}

// Print helpful error info to page & console on unsuccessful upload
function handleUploadErrors(error) {
function handleErrorOnUpload(error) {
if (typeof error.text === 'function') {
error.text().then((errorMessage) => {
console.error(
'Error when sending excel file.\n',
JSON.parse(errorMessage)
);
info_box.innerHTML =
'Error when uploading file. See the console for more information.';
'Error when uploading file. See the console for more information, or contact an administrator.';
});
} else if (error.name === 'AbortError') {
console.error(`Timeout - Response took longer than expected.\n`, error);
info_box.innerHTML = `Timeout - Response took longer than expected.`;
} else console.error(`Unexpected error.\n`, error);
info_box.innerHTML = `Timeout - Response took longer than expected. Try again later.`;
} else {
info_box.innerHTML =
'Error when uploading file. Ensure you have uploaded the correct template, or contact an administrator.';
console.error(`Unexpected error.\n`, error);
}
}

function get_error_table(data) {
var rows_html = '';
var row_array = [];
for (let i = 0; i < data.errors.length; i++) {
// Convert given string-tuples into arrays:
// "(col, row...)" -> [col, row, ...]
row_array = data.errors[i];
row_array = JSON.parse(
row_array.replaceAll('(', '[').replaceAll(')', ']').replaceAll(`'`, `"`)
);

rows_html += `
<tr>
<td class="text-center">${row_array[0]}${row_array[1]}</td>
<td>${row_array[2]}</td>
<td>${row_array[3]['text']}.</td>
</tr>`;
// <a class="usa-link" href="${row_array[3]["link"]}">Link</a>
}
const validationTable = `<p>Error on validation. Check the following cells for errors, and re-upload.
Common errors include incorrect data types or missing information.</p>
<table class="usa-table usa-table--striped">
<thead>
<tr>
<th scope="col">Cell</th>
<th scope="col">Field</th>
<th scope="col">Help Text</th>
</tr>
</thead>
<tbody>
${rows_html}
</tbody>
</table>`;
return validationTable;
}

// On file upload, send it off for verification.
Expand All @@ -61,37 +101,42 @@ function attachFileUploadHandler() {
info_box.hidden = false;
info_box.innerHTML = 'Validating your file...';

const currentURL = new URL(window.location.href);
const current_url = new URL(window.location.href);
const report_submission_url =
UPLOAD_URLS[currentURL.pathname.split('/')[2]];
UPLOAD_URLS[current_url.pathname.split('/')[2]];
if (!report_submission_url) throw 'No upload URL available.';
if (!e.target.files[0]) throw 'No file selected.';
if (e.target.files[0].name.split('.').pop() !== 'xlsx')
throw 'File type not accepted.';

var data = new FormData();
data.append('FILES', e.target.files[0]);
data.append('filename', e.target.files[0].name);
data.append('sac_id', sac_id);
var body = new FormData();
body.append('FILES', e.target.files[0]);
body.append('filename', e.target.files[0].name);
body.append('sac_id', sac_id);

fetch(`/audit/excel/${report_submission_url}/${sac_id}`, {
method: 'POST',
body: data,
body: body,
})
.then((response) => {
if (response.status == 200) {
.then((res) => {
if (res.status == 200) {
info_box.innerHTML =
'File successfully validated! Your work has been saved.';
setContinueButtonDisabled(false);
setFormDisabled(false);
} else {
// TODO: Handle helpful validation errors here
console.error('Error when validating excel file.\n', response);
info_box.innerHTML =
'Error on validation. See the console for more information.';
res.json().then((data) => {
if (data.type === 'error_row') {
info_box.innerHTML = get_error_table(data);
} else if (data.type === 'error_field') {
info_box.innerHTML = `Field Error: ${res.errors}`;
} else {
throw new Error('Returned error type is missing!');
}
});
}
})
.catch((error) => {
handleUploadErrors(error);
handleErrorOnUpload(error);
});
} catch (error) {
info_box.innerHTML = `Error when sending excel file.\n ${error}`;
Expand All @@ -108,9 +153,7 @@ function attachEventHandlers() {
function init() {
attachEventHandlers();

already_submitted
? setContinueButtonDisabled(false)
: setContinueButtonDisabled(true);
already_submitted ? setFormDisabled(false) : setFormDisabled(true);
}

init();

0 comments on commit 4dc2be4

Please sign in to comment.