Skip to content

Commit

Permalink
Merge pull request #4241 from GSA-TTS/main
Browse files Browse the repository at this point in the history
  • Loading branch information
jadudm authored Aug 29, 2024
2 parents 55a177c + 377d210 commit b085640
Show file tree
Hide file tree
Showing 15 changed files with 203 additions and 147 deletions.
11 changes: 8 additions & 3 deletions backend/audit/views/pre_dissemination_download_view.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect
from django.views.generic import View

Expand Down Expand Up @@ -33,7 +34,11 @@ def get(self, request, report_id):
)
i2d_data = intake_to_dissem.load_all()

filename = generate_presubmission_report(i2d_data)
download_url = get_download_url(filename)
filename, workbook_bytes = generate_presubmission_report(i2d_data)
response = HttpResponse(
workbook_bytes,
content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
response["Content-Disposition"] = f"attachment; filename={filename}"

return redirect(download_url)
return response
2 changes: 1 addition & 1 deletion backend/cypress/support/auditee-certification.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export function testAuditeeCertification() {
// 2. Sign and date, submit and go back to checklist
cy.get('#auditee_name').type('John Doe');
cy.get('#auditee_title').type('Auditee');
cy.get('.usa-date-picker__button').click();
cy.get('.usa-date-picker__button').trigger('click');
cy.get('.usa-date-picker__calendar__date--today').click();
cy.get('.usa-button').contains('Agree to auditee certification').click();
};
2 changes: 1 addition & 1 deletion backend/cypress/support/auditor-certification.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function testAuditorCertification() {
// 2. Sign and date, submit and go back to checklist
cy.get('#auditor_name').type('Jane Doe');
cy.get('#auditor_title').type('Auditor');
cy.get('.usa-date-picker__button').click();
cy.get('.usa-date-picker__button').trigger('click');
cy.get('.usa-date-picker__calendar__date--today').click();
cy.get('.usa-button').contains('Agree to auditor certification').click();
};
16 changes: 1 addition & 15 deletions backend/dissemination/api_versions.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

# These are API versions we want live.
live = {
"dissemination": ["api_v1_0_3", "api_v1_1_0", "api_v1_1_1"],
"dissemination": ["api_v1_0_3", "api_v1_1_0"],
"support": ["admin_api_v1_1_0"],
}

Expand Down Expand Up @@ -47,20 +47,6 @@ def exec_sql(location, version, filename):
curs.execute(sql)


def create_materialized_view(location):
"""
Create or recreate the dissemination_combined materialized view.
We only want this done once on startup, regardless of the API version.
"""
conn = connection(get_conn_string())
conn.autocommit = True
with conn.cursor() as curs:
path = f"{location}/sql/create_materialized_views.sql"
logger.info("EXEC SQL create_materialized_views.sql")
sql = open(path, "r").read()
curs.execute(sql)


def create_views(location, version):
exec_sql(location, version, "create_views.sql")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ class Command(BaseCommand):
"""

def handle(self, *args, **kwargs):
api_versions.create_materialized_view("dissemination")
api_versions.create_functions("dissemination")
api_versions.create_functions("support")
api_versions.create_live_views("dissemination")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,7 @@ def add_arguments(self, parser):
def handle(self, *args, **options):
path = "dissemination/sql"
if options["create"]:
# Other API views may rely on the materialized view. So, drop and recreate them.
api_versions.drop_live_views("dissemination")
api_versions.exec_sql_at_path(path, "create_materialized_views.sql")
api_versions.create_live_views("dissemination")
elif options["drop"]:
api_versions.exec_sql_at_path(path, "drop_materialized_views.sql")
elif options["refresh"]:
Expand Down
53 changes: 14 additions & 39 deletions backend/dissemination/summary_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,7 @@
import time
import openpyxl as pyxl

from boto3 import client as boto3_client
from botocore.client import ClientError, Config

from django.conf import settings
from fs.memoryfs import MemoryFS

from openpyxl.workbook.defined_name import DefinedName
from openpyxl.utils import quote_sheetname
Expand Down Expand Up @@ -606,40 +602,19 @@ def create_workbook(data, protect_sheets=False):
return (workbook, t1 - t0)


def persist_workbook(workbook):
def prepare_workbook_for_download(workbook):

t0 = time.time()
s3_client = boto3_client(
service_name="s3",
region_name=settings.AWS_S3_PRIVATE_REGION_NAME,
aws_access_key_id=settings.AWS_PRIVATE_ACCESS_KEY_ID,
aws_secret_access_key=settings.AWS_PRIVATE_SECRET_ACCESS_KEY,
endpoint_url=settings.AWS_S3_PRIVATE_INTERNAL_ENDPOINT,
config=Config(signature_version="s3v4"),
)
now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
filename = f"fac-summary-report-{now}.xlsx"

# Save the workbook directly to a BytesIO object
workbook_bytes = io.BytesIO()
workbook.save(workbook_bytes)
workbook_bytes.seek(0)

with MemoryFS() as mem_fs:
now = datetime.utcnow().strftime("%Y%m%d%H%M%S")
filename = f"fac-summary-report-{now}.xlsx"
s3_dir = "temp"

workbook_write_fp = mem_fs.openbin(filename, mode="w")
workbook.save(workbook_write_fp)
workbook_read_fp = mem_fs.openbin(filename, mode="r")
workbook_read_fp.seek(0)
content = workbook_read_fp.read()
workbook_bytes = io.BytesIO(content)

try:
s3_client.put_object(
Body=workbook_bytes,
Bucket=settings.AWS_PRIVATE_STORAGE_BUCKET_NAME,
Key=f"{s3_dir}/{filename}",
)
except ClientError:
logger.warn(f"Unable to put summary report file {filename} in S3!")
raise
t1 = time.time()
return (f"temp/{filename}", t1 - t0)
return (filename, workbook_bytes, t1 - t0)


def generate_summary_report(report_ids, include_private=False):
Expand All @@ -651,12 +626,12 @@ def generate_summary_report(report_ids, include_private=False):
data = separate_notes_single_fields_from_array_fields(data)
(workbook, tcw) = create_workbook(data)
insert_dissem_coversheet(workbook, bool(tribal_report_ids), include_private)
(filename, tpw) = persist_workbook(workbook)
(filename, workbook_bytes, tpw) = prepare_workbook_for_download(workbook)
t1 = time.time()
logger.info(
f"SUMMARY_REPORTS generate_summary_report\n\ttotal: {t1-t0} ttri: {ttri} tgrdd: {tgrdd} tcw: {tcw} tpw: {tpw}"
)
return filename
return (filename, workbook_bytes)


# Ignore performance profiling for the presub.
Expand All @@ -667,9 +642,9 @@ def generate_presubmission_report(i2d_data):
insert_precert_coversheet(workbook)
workbook.security.workbookPassword = str(uuid.uuid4())
workbook.security.lockStructure = True
(filename, _) = persist_workbook(workbook)
(filename, workbook_bytes, _) = prepare_workbook_for_download(workbook)

return filename
return (filename, workbook_bytes)


def separate_notes_single_fields_from_array_fields(data):
Expand Down
2 changes: 1 addition & 1 deletion backend/dissemination/test_summary_reports.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def test_generate_summary_report_returns_filename(self):
baker.make(FederalAward, report_id=g)
self.refresh_materialized_view()

filename = generate_summary_report(report_ids)
filename, _ = generate_summary_report(report_ids)

self.assertTrue(filename.startswith, "fac-summary-report-")
self.assertTrue(filename.endswith, ".xlsx")
Expand Down
Loading

0 comments on commit b085640

Please sign in to comment.