-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #286 from VineetBala-AOT/develop
Adding the EAO documents page
- Loading branch information
Showing
13 changed files
with
492 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
submit-api/src/submit_api/models/queries/submitted_document.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
# Copyright © 2024 Province of British Columbia | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
"""Model to handle all complex operations related to Submitted Documents.""" | ||
|
||
from sqlalchemy import cast, or_, String | ||
from submit_api.models.account_project import AccountProject | ||
from submit_api.models.account_project_search_options import DocumentSearchOptions | ||
from submit_api.models.db import db | ||
from submit_api.models.item import Item | ||
from submit_api.models.package import Package | ||
from submit_api.models.project import Project | ||
from submit_api.models.submission import Submission, SubmissionType | ||
from submit_api.models.submitted_document import SubmittedDocument | ||
|
||
|
||
class DocumentQueries: | ||
"""Query module for complex document queries.""" | ||
|
||
@classmethod | ||
def get_filtered_documents(cls, search_options: DocumentSearchOptions = None): | ||
"""Get all documents.""" | ||
session = db.session | ||
|
||
query = session.query( | ||
Project.name.label("project_name"), | ||
SubmittedDocument.id, | ||
SubmittedDocument.name, | ||
SubmittedDocument.url, | ||
Item.status, | ||
# TODO once document version is captured this logic needs to be revisited | ||
(cast(Submission.major_version, String) + "." + | ||
cast(Submission.minor_version, String)).label("version"), | ||
Package.submitted_on | ||
) | ||
|
||
# Apply joins step by step | ||
query = query.join(AccountProject, AccountProject.project_id == Project.id) | ||
query = query.join( | ||
Package, Package.account_project_id == AccountProject.id) | ||
query = query.join(Item, Item.package_id == Package.id) | ||
query = query.join(Submission, Submission.item_id == Item.id) | ||
query = query.join( | ||
SubmittedDocument, SubmittedDocument.id == Submission.submitted_document_id) | ||
|
||
# Apply filtering conditions | ||
query = query.filter(Submission.type == SubmissionType.DOCUMENT) | ||
|
||
# Apply search filters if provided | ||
if search_options and any(bool(search_option) for search_option in search_options.__dict__.values()): | ||
query = cls.filter_by_search_criteria(query, search_options) | ||
|
||
return query.all() | ||
|
||
@classmethod | ||
def filter_by_search_criteria(cls, document_query, search_options: DocumentSearchOptions): | ||
"""Apply various filters based on search options.""" | ||
|
||
if search_options.search_text: | ||
document_query = cls._filter_by_search_text(document_query, search_options.search_text) | ||
|
||
@classmethod | ||
def _filter_by_search_text(cls, query, search_text): | ||
"""Filter by search text across package name.""" | ||
return query.filter( | ||
or_( | ||
Package.name.ilike(f"%{search_text}%"), | ||
Project.name.ilike(f"%{search_text}%") | ||
) | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
64 changes: 64 additions & 0 deletions
64
submit-api/src/submit_api/resources/staff/submitted_document.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Copyright © 2024 Province of British Columbia | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the 'License'); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an 'AS IS' BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
"""API endpoints for managing a document resource.""" | ||
|
||
from http import HTTPStatus | ||
from flask import request | ||
|
||
from flask_restx import Namespace, Resource, cors | ||
|
||
from submit_api.auth import auth | ||
from submit_api.models.account_project_search_options import DocumentSearchOptions | ||
from submit_api.resources.apihelper import Api as ApiHelper | ||
from submit_api.schemas.submission import SubmittedDocumentByProjectSchema | ||
from submit_api.services.submitted_document_service import DocumentService | ||
from submit_api.utils.roles import EpicSubmitRole | ||
from submit_api.utils.util import cors_preflight | ||
|
||
|
||
API = Namespace("documents", description="Endpoints for Submitted Document Management") | ||
"""Custom exception messages | ||
""" | ||
|
||
document_list_model = ApiHelper.convert_ma_schema_to_restx_model( | ||
API, SubmittedDocumentByProjectSchema(), "Document" | ||
) | ||
|
||
|
||
@cors_preflight("GET, OPTIONS") | ||
@API.route( | ||
"", | ||
methods=["GET", "OPTIONS"], | ||
) | ||
class AccountDocuments(Resource): | ||
"""Resource for managing submitted documents.""" | ||
|
||
@staticmethod | ||
@ApiHelper.swagger_decorators(API, endpoint_description="Get submitted documents") | ||
@API.response( | ||
code=HTTPStatus.OK, model=document_list_model, description="Get documents" | ||
) | ||
@API.response(HTTPStatus.BAD_REQUEST, "Bad Request") | ||
@auth.has_one_of_roles([EpicSubmitRole.EAO_VIEW.value]) | ||
@cors.crossdomain(origin="*") | ||
def get(): | ||
"""Get all submitted documents.""" | ||
args = request.args | ||
search_text = args.get('search_text') | ||
search_options = DocumentSearchOptions( | ||
search_text=search_text, | ||
) | ||
|
||
documents = DocumentService.get_all_documents(search_options) | ||
return SubmittedDocumentByProjectSchema(many=True).dump(documents), HTTPStatus.OK |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
submit-api/src/submit_api/services/submitted_document_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
"""Service for submitted document management.""" | ||
|
||
from submit_api.models.account_project_search_options import DocumentSearchOptions | ||
from submit_api.models.queries.submitted_document import DocumentQueries | ||
|
||
|
||
class DocumentService: | ||
"""Submitted document management service.""" | ||
|
||
@classmethod | ||
def get_all_documents(cls, search_options: DocumentSearchOptions = None): | ||
"""Get all documents.""" | ||
return DocumentQueries.get_filtered_documents(search_options) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { TableHead, TableRow } from "@mui/material"; | ||
import { BCDesignTokens } from "epic.theme"; | ||
import { SubmitTableHeadCell } from "@/components/Shared/Table/common"; | ||
|
||
export default function DocumentTableHead() { | ||
return ( | ||
<TableHead | ||
sx={{ | ||
border: 0, | ||
".MuiTableCell-root": { | ||
p: BCDesignTokens.layoutPaddingXsmall, | ||
}, | ||
}} | ||
> | ||
<TableRow> | ||
<SubmitTableHeadCell | ||
sx={{ | ||
width: "20%", | ||
}} | ||
> | ||
Project | ||
</SubmitTableHeadCell> | ||
<SubmitTableHeadCell | ||
align="left" | ||
sx={{ | ||
width: "45%", | ||
}} | ||
> | ||
Document Name | ||
</SubmitTableHeadCell> | ||
<SubmitTableHeadCell | ||
align="left" | ||
sx={{ | ||
width: "5%", | ||
}} | ||
> | ||
Version | ||
</SubmitTableHeadCell> | ||
<SubmitTableHeadCell | ||
align="left" | ||
sx={{ | ||
width: "10%", | ||
}} | ||
> | ||
Submission Date | ||
</SubmitTableHeadCell> | ||
<SubmitTableHeadCell | ||
align="center" | ||
sx={{ | ||
width: "15%", | ||
}} | ||
> | ||
Status | ||
</SubmitTableHeadCell> | ||
<SubmitTableHeadCell | ||
align="left" | ||
sx={{ | ||
width: "5%", | ||
}} | ||
> | ||
Actions | ||
</SubmitTableHeadCell> | ||
</TableRow> | ||
</TableHead> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
import { useState } from "react"; | ||
import dateUtils from "@/utils/dateUtils"; | ||
import { Link as MuiLink, Typography } from "@mui/material"; | ||
import { BCDesignTokens } from "epic.theme"; | ||
import { SubmittedDocument } from "@/models/Submission"; | ||
import { SubmissionStatusChip } from "../SubmissionStatusChip"; | ||
import { SubmitTableCell } from "@/components/Shared/Table/common"; | ||
import { TableRow } from "@mui/material"; | ||
import { getObjectFromS3 } from "@/components/Shared/Table/utils"; | ||
import { notify } from "@/components/Shared/Snackbar/snackbarStore"; | ||
|
||
interface DocumentRowProps { | ||
submittedDocument: SubmittedDocument; | ||
} | ||
|
||
export default function DocumentTableRow({ submittedDocument }: DocumentRowProps) { | ||
const { name, url } = submittedDocument; | ||
|
||
const [pendingGetObject, setPendingGetObject] = useState(false) | ||
|
||
const downloadDocument = async () => { | ||
try { | ||
if (pendingGetObject) return; | ||
setPendingGetObject(true); | ||
await getObjectFromS3({ name, url }); | ||
} catch (e) { | ||
notify.error("Failed to download document"); | ||
} finally { | ||
setPendingGetObject(false); | ||
} | ||
}; | ||
|
||
const openDocument = () => { | ||
downloadDocument(); | ||
}; | ||
|
||
return ( | ||
<> | ||
<TableRow> | ||
<SubmitTableCell align="left"> | ||
{submittedDocument.project_name ?? ""} | ||
</SubmitTableCell> | ||
<SubmitTableCell> | ||
<Typography | ||
variant="body1" | ||
color="inherit" | ||
sx={{ | ||
overflow: "clip", | ||
textOverflow: "ellipsis", | ||
cursor: "pointer", | ||
mx: 0.5, | ||
}} | ||
> | ||
<MuiLink onClick={openDocument}>{submittedDocument.name}</MuiLink> | ||
</Typography> | ||
</SubmitTableCell> | ||
<SubmitTableCell align="right"> | ||
{submittedDocument.version ?? ""} | ||
</SubmitTableCell> | ||
<SubmitTableCell align="center"> | ||
{dateUtils.formatDate(submittedDocument.submitted_on)} | ||
</SubmitTableCell> | ||
<SubmitTableCell | ||
align="right" | ||
sx={{ | ||
pr: BCDesignTokens.layoutPaddingSmall, | ||
}} | ||
> | ||
<SubmissionStatusChip status={submittedDocument.status ?? ""} /> | ||
</SubmitTableCell> | ||
<SubmitTableCell align="center"> | ||
{''} | ||
</SubmitTableCell> | ||
</TableRow> | ||
</> | ||
); | ||
} |
Oops, something went wrong.