diff --git a/.gitignore b/.gitignore index 4e6b47f9e9..7caa96df00 100644 --- a/.gitignore +++ b/.gitignore @@ -157,3 +157,6 @@ helm/**/charts # Vite(st) temporary config files vite.config.**s.timestamp-* vitest.config.**s.timestamp-* + +# Local file attachments +bc_obps/test_media/* diff --git a/bc_obps/reporting/api/__init__.py b/bc_obps/reporting/api/__init__.py index 4c7a459f04..02d97ea290 100644 --- a/bc_obps/reporting/api/__init__.py +++ b/bc_obps/reporting/api/__init__.py @@ -18,4 +18,4 @@ from .report_activity import save_report_activity_data, load_report_activity_data from .report_facilities import get_report_facility_list_by_version_id from .report_verification import get_report_verification_by_version_id, save_report_verification -from .attachments import save_report_attachments +from .report_attachments import load_report_attachments, download_report_attachment_file diff --git a/bc_obps/reporting/api/attachments.py b/bc_obps/reporting/api/report_attachments.py similarity index 75% rename from bc_obps/reporting/api/attachments.py rename to bc_obps/reporting/api/report_attachments.py index 2de08615e3..1b7503c9d2 100644 --- a/bc_obps/reporting/api/attachments.py +++ b/bc_obps/reporting/api/report_attachments.py @@ -6,7 +6,6 @@ from ninja import File, Form, UploadedFile from registration.decorators import handle_http_errors from reporting.constants import EMISSIONS_REPORT_TAGS -from reporting.models import report_version from reporting.models.report_attachment import ReportAttachment from reporting.schema.generic import Message from reporting.schema.report_attachment import ReportAttachmentOut @@ -22,6 +21,7 @@ auth=authorize("approved_industry_user"), ) @handle_http_errors() +@transaction.atomic() def save_report_attachments( request: HttpRequest, report_version_id: int, @@ -29,15 +29,13 @@ def save_report_attachments( files: List[UploadedFile] = File(...), ) -> Literal[200]: - print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~") - for f in files: - print(f) - print("~~~") - for n in file_types: - print(n) - for index, file_type in enumerate(file_types): - ReportAttachment.objects.filter(report_version_id=report_version_id, attachment_type=file_type).delete() + + report_attachment = ReportAttachment.objects.get(report_version_id=report_version_id, attachment_type=file_type) + + # Delete file from storage then from db + report_attachment.attachment.delete() + report_attachment.delete() attachment = ReportAttachment( report_version_id=report_version_id, @@ -50,7 +48,13 @@ def save_report_attachments( return 200 -@router.get("report-version/{report_version_id}/attachments") +@router.get( + "report-version/{report_version_id}/attachments", + response={200: List[ReportAttachmentOut], custom_codes_4xx: Message}, + tags=EMISSIONS_REPORT_TAGS, + description="""Returns the list of file attachments for a report version.""", + auth=authorize("approved_industry_user"), +) def load_report_attachments( request: HttpRequest, report_version_id: int, @@ -58,7 +62,9 @@ def load_report_attachments( return ReportAttachment.objects.filter(report_version_id=report_version_id) -@router.get("report-version/{report_version_id}/attachments/{file_id}") +@router.get( + "report-version/{report_version_id}/attachments/{file_id}", +) def download_report_attachment_file(request: HttpRequest, report_version_id: int, file_id: int): file = ReportAttachment.objects.get(id=file_id, report_version_id=report_version_id) diff --git a/bc_obps/reporting/models/report_attachment.py b/bc_obps/reporting/models/report_attachment.py index bf9f7e63bd..168a10cb41 100644 --- a/bc_obps/reporting/models/report_attachment.py +++ b/bc_obps/reporting/models/report_attachment.py @@ -1,5 +1,5 @@ from django.db import models -from django.db.models import Q, CharField, FileField, ForeignKey +from django.db.models import CharField, FileField, ForeignKey from registration.models.time_stamped_model import TimeStampedModel from reporting.models.report_version import ReportVersion diff --git a/bc_obps/reporting/schema/report_attachment.py b/bc_obps/reporting/schema/report_attachment.py index ab182d096e..eb9cd6d192 100644 --- a/bc_obps/reporting/schema/report_attachment.py +++ b/bc_obps/reporting/schema/report_attachment.py @@ -1,9 +1,16 @@ -from ninja import Schema +import os +from ninja import ModelSchema from reporting.models.report_attachment import ReportAttachment -class ReportAttachmentOut(Schema): +class ReportAttachmentOut(ModelSchema): + + file_name: str + + @staticmethod + def resolve_file_name(obj): + return os.path.basename(obj.attachment.name) class Meta: model = ReportAttachment - fields = ['id', 'attachment', 'attachment_type'] + fields = ['id', 'attachment_type'] diff --git a/bc_obps/test_media/report_attachments/2024/OBPS_application_architecture.pdf b/bc_obps/test_media/report_attachments/2024/OBPS_application_architecture.pdf deleted file mode 100644 index f0e16cfb1d..0000000000 Binary files a/bc_obps/test_media/report_attachments/2024/OBPS_application_architecture.pdf and /dev/null differ diff --git a/bc_obps/test_media/report_attachments/2024/ReportPreview.pdf b/bc_obps/test_media/report_attachments/2024/ReportPreview.pdf deleted file mode 100644 index 43064a3e3a..0000000000 Binary files a/bc_obps/test_media/report_attachments/2024/ReportPreview.pdf and /dev/null differ diff --git a/bciers/apps/reporting/src/app/bceidbusiness/industry_user/reports/[version_id]/attachments/page.tsx b/bciers/apps/reporting/src/app/bceidbusiness/industry_user/reports/[version_id]/attachments/page.tsx index 2d6c46cf12..99d98e47e1 100644 --- a/bciers/apps/reporting/src/app/bceidbusiness/industry_user/reports/[version_id]/attachments/page.tsx +++ b/bciers/apps/reporting/src/app/bceidbusiness/industry_user/reports/[version_id]/attachments/page.tsx @@ -1,4 +1,4 @@ -import Attachments from "@reporting/src/app/components/attachments/Attachments"; +import AttachmentsPage from "@reporting/src/app/components/attachments/AttachmentsPage"; import defaultPageFactory from "@reporting/src/app/utils/defaultPageFactory"; -export default defaultPageFactory(Attachments); +export default defaultPageFactory(AttachmentsPage); diff --git a/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/attachments/page.tsx b/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/attachments/page.tsx index 2d6c46cf12..99d98e47e1 100644 --- a/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/attachments/page.tsx +++ b/bciers/apps/reporting/src/app/bceidbusiness/industry_user_admin/reports/[version_id]/attachments/page.tsx @@ -1,4 +1,4 @@ -import Attachments from "@reporting/src/app/components/attachments/Attachments"; +import AttachmentsPage from "@reporting/src/app/components/attachments/AttachmentsPage"; import defaultPageFactory from "@reporting/src/app/utils/defaultPageFactory"; -export default defaultPageFactory(Attachments); +export default defaultPageFactory(AttachmentsPage); diff --git a/bciers/apps/reporting/src/app/components/attachments/AttachmentElement.tsx b/bciers/apps/reporting/src/app/components/attachments/AttachmentElement.tsx index 36515588e0..07b8a0e3ab 100644 --- a/bciers/apps/reporting/src/app/components/attachments/AttachmentElement.tsx +++ b/bciers/apps/reporting/src/app/components/attachments/AttachmentElement.tsx @@ -1,20 +1,23 @@ import { ChangeEvent, MutableRefObject, useRef, useState } from "react"; +import { UploadedAttachment } from "./types"; interface Props { - value?: string; + uploadedAttachment?: UploadedAttachment; accept?: string; title: string; onFileChange: (file: File | undefined) => void; } const AttachmentElement: React.FC = ({ - value, + uploadedAttachment, accept = "application/pdf", title, onFileChange, }) => { const hiddenFileInput = useRef() as MutableRefObject; - const [currentValue, setCurrentValue] = useState(value); + const [currentValue, setCurrentValue] = useState( + uploadedAttachment?.file_name, + ); const [currentFile, setCurrentFile] = useState(); const handleClick = () => { @@ -31,7 +34,6 @@ const AttachmentElement: React.FC = ({ if (evt.target.files.length > 0) { const file = evt.target.files[0]; - setCurrentFile(file); setCurrentValue(file.name); onFileChange(file); @@ -63,9 +65,10 @@ const AttachmentElement: React.FC = ({ {currentFile || currentValue ? ( ) : ( diff --git a/bciers/apps/reporting/src/app/components/attachments/Attachments.tsx b/bciers/apps/reporting/src/app/components/attachments/Attachments.tsx deleted file mode 100644 index 6d6d6e0f06..0000000000 --- a/bciers/apps/reporting/src/app/components/attachments/Attachments.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { Suspense } from "react"; -import { HasReportVersion } from "../../utils/defaultPageFactory"; -import AttachmentsForm from "./AttachmentsForm"; - -const Attachments: React.FC = ({ version_id }) => { - return ; -}; - -export default Attachments; diff --git a/bciers/apps/reporting/src/app/components/attachments/AttachmentsForm.tsx b/bciers/apps/reporting/src/app/components/attachments/AttachmentsForm.tsx index 7b547a6ed7..7e7989376c 100644 --- a/bciers/apps/reporting/src/app/components/attachments/AttachmentsForm.tsx +++ b/bciers/apps/reporting/src/app/components/attachments/AttachmentsForm.tsx @@ -6,10 +6,18 @@ import postAttachments from "@bciers/actions/api/postAttachments"; import MultiStepWrapperWithTaskList from "./MultiStepWrapperWithTaskList"; import AttachmentElement from "./AttachmentElement"; import { useState } from "react"; +import { UploadedAttachment } from "./types"; -interface Props extends HasReportVersion {} +interface Props extends HasReportVersion { + uploaded_attachments: { + [attachment_type: string]: UploadedAttachment; + }; +} -const AttachmentsForm: React.FC = ({ version_id }) => { +const AttachmentsForm: React.FC = ({ + version_id, + uploaded_attachments, +}) => { const taskListElements = getSignOffAndSubmitSteps(version_id); const [files, setFiles] = useState<{ [filename: string]: File }>({}); @@ -51,10 +59,12 @@ const AttachmentsForm: React.FC = ({ version_id }) => { handleChange("verification_statement", file)} + uploadedAttachment={uploaded_attachments.verification_statement} /> handleChange("wci_352_362", file)} + uploadedAttachment={uploaded_attachments.wci_352_362} /> diff --git a/bciers/apps/reporting/src/app/components/attachments/AttachmentsPage.tsx b/bciers/apps/reporting/src/app/components/attachments/AttachmentsPage.tsx new file mode 100644 index 0000000000..404d03134b --- /dev/null +++ b/bciers/apps/reporting/src/app/components/attachments/AttachmentsPage.tsx @@ -0,0 +1,21 @@ +import { HasReportVersion } from "../../utils/defaultPageFactory"; +import AttachmentsForm from "./AttachmentsForm"; +import getAttachments from "@bciers/actions/api/getAttachments"; +import { UploadedAttachment } from "./types"; + +const AttachmentsPage: React.FC = async ({ version_id }) => { + const uploaded_attachments: UploadedAttachment[] = + await getAttachments(version_id); + console.log("!~!!!!@@~~~~~~~~~~~~~~~~~~~~~~~~```", uploaded_attachments); + const uploaded_attachments_dict = Object.fromEntries( + uploaded_attachments.map((a) => [a.attachment_type, a]), + ); + return ( + + ); +}; + +export default AttachmentsPage; diff --git a/bciers/apps/reporting/src/app/components/attachments/types.ts b/bciers/apps/reporting/src/app/components/attachments/types.ts new file mode 100644 index 0000000000..bb9b25738e --- /dev/null +++ b/bciers/apps/reporting/src/app/components/attachments/types.ts @@ -0,0 +1,5 @@ +export interface UploadedAttachment { + id: number; + file_name: string; + attachment_type: string; +} diff --git a/bciers/libs/actions/src/api/getAttachments.ts b/bciers/libs/actions/src/api/getAttachments.ts new file mode 100644 index 0000000000..92abd569db --- /dev/null +++ b/bciers/libs/actions/src/api/getAttachments.ts @@ -0,0 +1,7 @@ +import { actionHandler } from "@bciers/actions"; + +// 🛠️ Function to fetch a contact by id +export default async function getAttachments(report_version_id: number) { + const endpoint = `reporting/report-version/${report_version_id}/attachments`; + return actionHandler(endpoint, "GET", ""); +} diff --git a/erd_diagrams/erd_reporting.md b/erd_diagrams/erd_reporting.md index 0018648fa9..a2f01bffcf 100644 --- a/erd_diagrams/erd_reporting.md +++ b/erd_diagrams/erd_reporting.md @@ -31,7 +31,10 @@ ReportVersion { DateTimeField archived_at ForeignKey report BooleanField is_latest_submitted +<<<<<<< HEAD CharField report_type +======= +>>>>>>> 49d11b96b (chore: removing pdf files) CharField status } ReportPersonResponsible { @@ -312,6 +315,21 @@ ReportProduct { FloatField quantity_sold_during_period FloatField quantity_throughput_during_period } +<<<<<<< HEAD +======= +ReportAttachment { + BigAutoField id + ForeignKey created_by + DateTimeField created_at + ForeignKey updated_by + DateTimeField updated_at + ForeignKey archived_by + DateTimeField archived_at + ForeignKey report_version + FileField attachment + CharField attachment_type +} +>>>>>>> 49d11b96b (chore: removing pdf files) Report }|--|| User : created_by Report }|--|| User : updated_by Report }|--|| User : archived_by @@ -424,3 +442,10 @@ ReportProduct }|--|| User : archived_by ReportProduct }|--|| ReportVersion : report_version ReportProduct }|--|| FacilityReport : facility_report ReportProduct }|--|| RegulatedProduct : product +<<<<<<< HEAD +======= +ReportAttachment }|--|| User : created_by +ReportAttachment }|--|| User : updated_by +ReportAttachment }|--|| User : archived_by +ReportAttachment }|--|| ReportVersion : report_version +>>>>>>> 49d11b96b (chore: removing pdf files)