Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MDS-6273] Project file deletion #3343

Merged
merged 10 commits into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 3 additions & 8 deletions services/common/src/components/documents/DocumentTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,18 +82,13 @@ export const DocumentTable: FC<DocumentTableProps> = ({
const isMinimalView: boolean = view === "minimal";

const parseDocuments = (docs: any[]): MineDocument[] => {
let parsedDocs: MineDocument[];
if (docs.length && docs[0] instanceof MineDocument) {
parsedDocs = docs;
return docs;
} else {
parsedDocs = docs.map((doc) => new MineDocument(doc));
return docs.map((doc) => new MineDocument(doc));
}
return parsedDocs.map((doc) => {
doc.setAllowedActions(userRoles);
return doc;
});
};

const [documents, setDocuments] = useState<MineDocument[]>(parseDocuments(props.documents ?? []));

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ import { SystemFlagEnum } from "@mds/common/constants/enums";
import { getSystemFlag } from "@mds/common/redux/selectors/authenticationSelectors";
import { FormContext } from "../forms/FormWrapper";
import { ProjectSummaryFormComponentProps } from "./ProjectSummaryForm";
import { areAuthEnvFieldsDisabled, areDocumentFieldsDisabled } from "../projects/projectUtils";
import { areAuthEnvFieldsDisabled, areDocumentFieldsDisabled, isDocumentDeletionEnabled } from "../projects/projectUtils";
import { removeDocumentFromProjectSummary } from "@mds/common/redux/actionCreators/projectActionCreator";

const RenderEMAPermitCommonSections = ({ code, isAmendment, index, isDisabled }) => {
const dispatch = useDispatch();
Expand All @@ -79,11 +80,27 @@ const RenderEMAPermitCommonSections = ({ code, isAmendment, index, isDisabled })

const projectSummaryDocumentTypesHash = useSelector(getProjectSummaryDocumentTypesHash);
const docFieldsDisabled = areDocumentFieldsDisabled(systemFlag, status_code);
const { isEditMode } = useContext(FormContext);
const deletionEnabled = isDocumentDeletionEnabled(systemFlag, status_code);

const onChange = (value) => {
setShowExemptionSection(value);
};

const onDeleteDocument = (event, key: string) => {
const document = tableDocuments.find( (doc) => key === doc.key);
if(document){
dispatch(
removeDocumentFromProjectSummary(
project_guid,
project_summary_guid,
document.mine_document_guid
)).then( () => {
removeAmendmentDocument(tableDocuments.indexOf(document),document.category,document.document_manager_guid)
})
}
}

const removeAmendmentDocument = (
amendmentDocumentsIndex: number,
category: string,
Expand Down Expand Up @@ -231,6 +248,7 @@ const RenderEMAPermitCommonSections = ({ code, isAmendment, index, isDisabled })
documents={tableDocuments}
documentParent="project summary authorization"
documentColumns={documentColumns}
removeDocument={deletionEnabled && isEditMode ? onDeleteDocument : undefined}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe("DocumentUpload", () => {
initialValues={MOCK.PROJECT_SUMMARY}
onSubmit={() => { }}
>
<DocumentUpload docFieldsDisabled={false} />
<DocumentUpload docFieldsDisabled={false} fieldsDisabled={false}/>
</FormWrapper>
</ReduxWrapper>
);
Expand Down
49 changes: 34 additions & 15 deletions services/common/src/components/projectSummary/DocumentUpload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import SpatialDocumentTable from "../documents/spatial/SpatialDocumentTable";
import { FormContext } from "../forms/FormWrapper";
import { useFeatureFlag } from "@mds/common/providers/featureFlags/useFeatureFlag";
import { Feature, IProjectSummaryForm } from "../..";
import { removeDocumentFromProjectSummary } from "@mds/common/redux/actionCreators/projectActionCreator";

const RenderOldDocuments = ({
documents,
Expand Down Expand Up @@ -67,9 +68,10 @@ const RenderOldDocuments = ({

interface DocumentUploadProps {
docFieldsDisabled: boolean;
deleteEnabled: boolean;
}

export const DocumentUpload: FC<DocumentUploadProps> = ({ docFieldsDisabled }) => {
export const DocumentUpload: FC<DocumentUploadProps> = ({ docFieldsDisabled, deleteEnabled }) => {
const dispatch = useDispatch();
const {
spatial_documents = [],
Expand Down Expand Up @@ -145,29 +147,45 @@ export const DocumentUpload: FC<DocumentUploadProps> = ({ docFieldsDisabled }) =
}
};

const removeFile = (document) => {
if (document.project_summary_document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SPATIAL) {
const newSpatialDocuments = [...spatial_documents].filter(
(file) => document.document_manager_guid !== file.document_manager_guid
);
dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "spatial_documents", newSpatialDocuments));
} else if (document.project_summary_document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SUPPORTING) {
const newSupportDocuments = [...support_documents].filter(
(file) => document.document_manager_guid !== file.document_manager_guid
);
dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "support_documents", newSupportDocuments));
}
}

const onRemoveFile = (err, fileItem) => {
if (err) {
console.log(err);
}

if (fileItem.serverId) {
const document_type_code = documents.find(
removeFile(documents.find(
(file) => fileItem.serverId === file.document_manager_guid
)?.project_summary_document_type_code;
if (document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SPATIAL) {
const newSpatialDocuments = [...spatial_documents].filter(
(file) => fileItem.serverId !== file.document_manager_guid
);
dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "spatial_documents", newSpatialDocuments));
} else if (document_type_code === PROJECT_SUMMARY_DOCUMENT_TYPE_CODE.SUPPORTING) {
const newSupportDocuments = [...support_documents].filter(
(file) => fileItem.serverId !== file.document_manager_guid
);
dispatch(change(FORM.ADD_EDIT_PROJECT_SUMMARY, "support_documents", newSupportDocuments));
}
));
}
};

const onDeleteDocument = (event, key: string) => {
const document = documents.find( (doc) => key === doc.mine_document_guid);
if(document){
dispatch(
removeDocumentFromProjectSummary(
project_guid,
project_summary_guid,
document.mine_document_guid
)).then( () => {
removeFile(document);
})
}
}

const downloadIRTTemplate = (url) => {
const anchor = document.createElement("a");
anchor.href = url;
Expand Down Expand Up @@ -283,6 +301,7 @@ export const DocumentUpload: FC<DocumentUploadProps> = ({ docFieldsDisabled }) =
documents={support_documents}
documentParent="project summary"
documentColumns={documentColumns}
removeDocument={deleteEnabled && isEditMode ? onDeleteDocument : undefined}
/>
</>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const ProjectSummaryFileUpload: FC<WrappedFieldProps & ProjectSummaryFile
}

useEffect(() => {
if (existingFiles.length === 0) {
if (existingFiles.length === 0 || props.documents.length < existingFiles.length) {
setExistingFiles(props.documents);
}
}, [props.documents]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { ProjectManagement } from "./ProjectManagement";
import { getSystemFlag } from "@mds/common/redux/selectors/authenticationSelectors";
import { SystemFlagEnum } from "../..";
import { formatProjectPayload } from "@mds/common/utils/helpers";
import { areAuthFieldsDisabled, areDocumentFieldsDisabled, areFieldsDisabled } from "../projects/projectUtils";
import { areAuthFieldsDisabled, areDocumentFieldsDisabled, areFieldsDisabled, isDocumentDeletionEnabled } from "../projects/projectUtils";

interface ProjectSummaryFormProps {
initialValues: IProjectSummary;
Expand Down Expand Up @@ -104,6 +104,7 @@ export const ProjectSummaryForm: FC<ProjectSummaryFormProps> = ({
const fieldsDisabled = areFieldsDisabled(systemFlag, status_code, confirmation_of_submission);
const docFieldsDisabled = areDocumentFieldsDisabled(systemFlag, status_code);
const authFieldsDisabled = areAuthFieldsDisabled(systemFlag, status_code, confirmation_of_submission);
const deleteEnabled = isDocumentDeletionEnabled(systemFlag, status_code);

const handleTransformPayload = (valuesFromForm: any) => {
return formatProjectPayload(valuesFromForm, { projectSummaryAuthorizationTypesArray });
Expand All @@ -128,7 +129,7 @@ export const ProjectSummaryForm: FC<ProjectSummaryFormProps> = ({
"representing-agent": <Agent fieldsDisabled={fieldsDisabled} />,
"mine-components-and-offsite-infrastructure": <FacilityOperator fieldsDisabled={fieldsDisabled} />,
"purpose-and-authorization": <AuthorizationsInvolved fieldsDisabled={authFieldsDisabled} />,
"document-upload": <DocumentUpload docFieldsDisabled={docFieldsDisabled} />,
"document-upload": <DocumentUpload docFieldsDisabled={docFieldsDisabled} deleteEnabled={deleteEnabled} />,
"application-summary": <ApplicationSummary fieldsDisabled={fieldsDisabled} />,
declaration: <Declaration />,
}[tab]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ describe("ProjectSummaryForm components disable accurately accoring to functions
<Agent fieldsDisabled={fieldsDisabled} />
<FacilityOperator fieldsDisabled={fieldsDisabled} />
<AuthorizationsInvolved fieldsDisabled={authFieldsDisabled} />
<DocumentUpload docFieldsDisabled={docFieldsDisabled} />
<DocumentUpload docFieldsDisabled={docFieldsDisabled} fieldsDisabled={fieldsDisabled}/>
<ApplicationSummary fieldsDisabled={fieldsDisabled} />
<Declaration />
</FormWrapper>
Expand Down
4 changes: 4 additions & 0 deletions services/common/src/components/projects/projectUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ export const areAuthEnvFieldsDisabled = memoize((systemFlag: SystemFlagEnum, pro
return envDisabled;
}, (systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => `${systemFlag}_${projectSummaryStatusCode}`);

export const isDocumentDeletionEnabled = memoize((systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => {
return systemFlag === SystemFlagEnum.ms && projectSummaryStatusCode == PROJECT_STATUS_CODES.DFT;
}, (systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => `${systemFlag}_${projectSummaryStatusCode}`);

export const areDocumentFieldsDisabled = memoize((systemFlag: SystemFlagEnum, projectSummaryStatusCode: string) => {
// Return false (enabled) if status = "" => "Not Started"
const isStatusInEnum = (<any>Object).values(PROJECT_STATUS_CODES).includes(projectSummaryStatusCode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export const removeDocumentFromProjectSummary = (
)
.then((response: AxiosResponse<string>) => {
notification.success({
message: "Successfully deleted project description document.",
message: "Successfully deleted project document.",
duration: 10,
});
dispatch(success(NetworkReducerTypes.REMOVE_DOCUMENT_FROM_PROJECT_SUMMARY));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from werkzeug.exceptions import NotFound
from werkzeug.exceptions import NotFound, Forbidden
from flask_restx import Resource
from app.extensions import api

from app.api.utils.access_decorators import (requires_any_of, MINE_ADMIN, EDIT_PROJECT_SUMMARIES)
from app.api.utils.access_decorators import (requires_any_of, MINE_ADMIN, EDIT_PROJECT_SUMMARIES,MINESPACE_PROPONENT)
from app.api.utils.resources_mixins import UserMixin

from app.api.mines.documents.models.mine_document import MineDocument
Expand All @@ -12,7 +12,7 @@
class ProjectSummaryUploadedDocumentResource(Resource, UserMixin):
@api.doc(description='Delete a document from a project description.')
@api.response(204, 'Successfully deleted.')
@requires_any_of([MINE_ADMIN, EDIT_PROJECT_SUMMARIES])
@requires_any_of([MINE_ADMIN, EDIT_PROJECT_SUMMARIES, MINESPACE_PROPONENT])
def delete(self, project_guid, project_summary_guid, mine_document_guid):
project_summary = ProjectSummary.find_by_project_summary_guid(project_summary_guid)
mine_document = MineDocument.find_by_mine_document_guid(mine_document_guid)
Expand All @@ -21,10 +21,20 @@ def delete(self, project_guid, project_summary_guid, mine_document_guid):
raise NotFound('Project Description not found.')
if mine_document is None:
raise NotFound('Mine document not found.')

if mine_document not in project_summary.mine_documents:

for auth in project_summary.authorizations:
for doc in auth.amendment_documents:
if doc.mine_document == mine_document:
if project_summary.status_code != "DFT":
raise Forbidden('Cannot delete document unless project application is in draft state')
doc.delete()
mine_document.delete()
return None, 204

raise NotFound('Mine document not found on Project Description.')

project_summary.mine_documents.remove(mine_document)
project_summary.save()

return None, 204
16 changes: 15 additions & 1 deletion services/core-api/tests/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
from app.api.projects.project_summary.models.project_summary_contact import ProjectSummaryContact
from app.api.projects.project_summary.models.project_summary_authorization import ProjectSummaryAuthorization
from app.api.projects.project_summary.models.project_summary_document_xref import ProjectSummaryDocumentXref
from app.api.projects.project_summary.models.project_summary_authorization_document_xref import ProjectSummaryAuthorizationDocumentXref
from app.api.projects.information_requirements_table.models.information_requirements_table import InformationRequirementsTable
from app.api.projects.information_requirements_table.models.information_requirements_table_document_xref import InformationRequirementsTableDocumentXref
from app.api.projects.project_decision_package.models.project_decision_package_document_xref import ProjectDecisionPackageDocumentXref
Expand Down Expand Up @@ -380,6 +381,20 @@ class Params:
project_summary_id = factory.SelfAttribute('project_summary.project_summary_id')
project_summary_document_type_code = factory.LazyFunction(RandomProjectSummaryDocumentTypeCode)

class ProjectSummaryAuthorizationDocumentFactory(BaseFactory):

class Meta:
model = ProjectSummaryAuthorizationDocumentXref

class Params:
project_summary = factory.SubFactory('tests.factories.ProjectSummaryFactory')
project_summary_authorization = factory.SubFactory('tests.factories.ProjectSummaryAuthorizationFactory')
mine_document = factory.SubFactory(MineDocumentFactory,mine_guid=factory.SelfAttribute('..project_summary.mine_guid'))

project_summary_authorization_document_xref_guid = GUID
project_summary_authorization_guid = factory.SelfAttribute('project_summary_authorization.project_summary_authorization_guid')
mine_document_guid = factory.SelfAttribute('mine_document.mine_document_guid')
project_summary_document_type_code = factory.LazyFunction(RandomProjectSummaryDocumentTypeCode)

class InformationRequirementsTableDocumentFactory(BaseFactory):

Expand Down Expand Up @@ -1413,7 +1428,6 @@ class Params:
existing_permits_authorizations = []
deleted_ind = False


class EMLIContactTypeFactory(BaseFactory):

class Meta:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import uuid

from tests.factories import (ProjectSummaryFactory, MineFactory, MineDocumentFactory,
ProjectSummaryDocumentFactory)
ProjectSummaryAuthorizationDocumentFactory,ProjectSummaryAuthorizationFactory)


# DELETE
Expand All @@ -19,6 +19,38 @@ def test_delete_file(test_client, db_session, auth_headers):
assert delete_resp.status_code == 204
assert len(project_summary.documents) == document_count - 1

def test_delete_amendment_file(test_client, db_session, auth_headers):
project_summary = ProjectSummaryFactory()
project_summary.status_code = 'DFT'
project_summary_authorization = ProjectSummaryAuthorizationFactory(project_summary=project_summary)
project_summary.authorizations.append(project_summary_authorization)
amendment_document = ProjectSummaryAuthorizationDocumentFactory(project_summary=project_summary,project_summary_authorization=project_summary_authorization)

document_count = len(project_summary_authorization.amendment_documents)
assert amendment_document.mine_document_guid is not None

delete_resp = test_client.delete(
f'/projects/{project_summary.project_guid}/project-summaries/{project_summary.project_summary_guid}/documents/{amendment_document.mine_document_guid}',
headers=auth_headers['full_auth_header'])
assert delete_resp.status_code == 204
assert len(project_summary_authorization.amendment_documents) == document_count - 1


def test_delete_amendment_not_in_draft(test_client, db_session, auth_headers):
project_summary = ProjectSummaryFactory()
project_summary.status_code = 'APR'
project_summary_authorization = ProjectSummaryAuthorizationFactory(project_summary=project_summary)
project_summary.authorizations.append(project_summary_authorization)
amendment_document = ProjectSummaryAuthorizationDocumentFactory(project_summary=project_summary,project_summary_authorization=project_summary_authorization)

document_count = len(project_summary_authorization.amendment_documents)
assert amendment_document.mine_document_guid is not None

delete_resp = test_client.delete(
f'/projects/{project_summary.project_guid}/project-summaries/{project_summary.project_summary_guid}/documents/{amendment_document.mine_document_guid}',
headers=auth_headers['full_auth_header'])
assert delete_resp.status_code == 403
assert len(project_summary_authorization.amendment_documents) == document_count

def test_delete_file_not_on_project_summary(test_client, db_session, auth_headers):
project_summary = ProjectSummaryFactory()
Expand Down
4 changes: 4 additions & 0 deletions services/minespace-web/src/styles/components/Tables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@
font-size: 16px;
}

.ant-dropdown-menu-item:hover, .ant-dropdown-menu-item button:hover{
cursor: pointer;
}

@include screen-md {
.ant-table table {
min-width: 100%;
Expand Down
Loading