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

Bug Fixes: delete project attachment, delete survey #1023

Merged
merged 7 commits into from
Apr 28, 2023
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PROJECT_ROLE, SYSTEM_ROLE } from '../../../../../constants/roles';
import { getDBConnection } from '../../../../../database/db';
import { authorizeRequestHandler } from '../../../../../request-handlers/security/authorization';
import { AttachmentService } from '../../../../../services/attachment-service';
import { HistoryPublishService } from '../../../../../services/history-publish-service';
import { deleteFileFromS3 } from '../../../../../utils/file-utils';
import { getLogger } from '../../../../../utils/logger';
import { attachmentApiDocObject } from '../../../../../utils/shared-api-docs';
Expand Down Expand Up @@ -103,13 +104,16 @@ export function deleteAttachment(): RequestHandler {
await connection.open();

const attachmentService = new AttachmentService(connection);
const historyPublishService = new HistoryPublishService(connection);

let deleteResult: { key: string };
if (req.body.attachmentType === ATTACHMENT_TYPE.REPORT) {
await historyPublishService.deleteProjectReportAttachmentPublishRecord(Number(req.params.attachmentId));
await attachmentService.deleteProjectReportAttachmentAuthors(Number(req.params.attachmentId));

deleteResult = await attachmentService.deleteProjectReportAttachment(Number(req.params.attachmentId));
} else {
await historyPublishService.deleteProjectAttachmentPublishRecord(Number(req.params.attachmentId));
deleteResult = await attachmentService.deleteProjectAttachment(Number(req.params.attachmentId));
}

Expand Down
38 changes: 38 additions & 0 deletions api/src/repositories/history-publish-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -623,6 +623,44 @@ export class HistoryPublishRepository extends BaseRepository {
await this.connection.sql(sqlStatement);
}

/**
* Deletes a record from `project_attachment_publish` for a given attachment id.
*
* @param {number} projectAttachmentId
* @return {*} {Promise<void>}
* @memberof HistoryPublishRepository
*/
async deleteProjectAttachmentPublishRecord(projectAttachmentId: number): Promise<void> {
const sqlStatement = SQL`
delete
from
project_attachment_publish
where
project_attachment_id = ${projectAttachmentId};
`;

await this.connection.sql(sqlStatement);
}

/**
* Deletes a record from `project_report_publish` for a given attachment id.
*
* @param {number} projectAttachmentId
* @return {*} {Promise<void>}
* @memberof HistoryPublishRepository
*/
async deleteProjectReportAttachmentPublishRecord(projectAttachmentId: number): Promise<void> {
const sqlStatement = SQL`
delete
from
project_report_publish
where
project_report_attachment_id = ${projectAttachmentId};
`;

await this.connection.sql(sqlStatement);
}

/**
* Gets the count of unpublished survey attachments
*
Expand Down
22 changes: 22 additions & 0 deletions api/src/services/history-publish-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,28 @@ export class HistoryPublishService extends DBService {
return this.historyRepository.deleteSurveyReportAttachmentPublishRecord(surveyReportAttachmentId);
}

/**
* Deletes a record from `project_attachment_publish` for a given attachment id.
*
* @param {number} surveyAttachmentId
* @return {*} {Promise<void>}
* @memberof HistoryPublishService
*/
async deleteProjectAttachmentPublishRecord(surveyAttachmentId: number): Promise<void> {
return this.historyRepository.deleteProjectAttachmentPublishRecord(surveyAttachmentId);
}

/**
* Deletes a record from `project_report_publish` for a given attachment id.
*
* @param {number} surveyReportAttachmentId
* @return {*} {Promise<void>}
* @memberof HistoryPublishService
*/
async deleteProjectReportAttachmentPublishRecord(surveyReportAttachmentId: number): Promise<void> {
return this.historyRepository.deleteProjectReportAttachmentPublishRecord(surveyReportAttachmentId);
}

/**
* Returns true if a given survey has any unpublished attachments and false if no unpublished attachments are found
*
Expand Down
27 changes: 18 additions & 9 deletions app/src/features/surveys/view/SurveyHeader.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { cleanup, fireEvent, render, waitFor } from '@testing-library/react';
import { SYSTEM_ROLE } from 'constants/roles';
import { AuthStateContext, IAuthState } from 'contexts/authStateContext';
import { DialogContextProvider } from 'contexts/dialogContext';
import { IProjectContext, ProjectContext } from 'contexts/projectContext';
import { ISurveyContext, SurveyContext } from 'contexts/surveyContext';
import SurveyHeader from 'features/surveys/view/SurveyHeader';
import { createMemoryHistory } from 'history';
Expand Down Expand Up @@ -81,15 +82,23 @@ describe('SurveyHeader', () => {

const renderComponent = (authState: any) => {
return render(
<SurveyContext.Provider value={mockSurveyContext}>
<AuthStateContext.Provider value={authState as IAuthState}>
<DialogContextProvider>
<Router history={history}>
<SurveyHeader />
</Router>
</DialogContextProvider>
</AuthStateContext.Provider>
</SurveyContext.Provider>
<ProjectContext.Provider
value={
({
projectId: 1,
surveysListDataLoader: ({ refresh: jest.fn() } as unknown) as DataLoader<any, any, any>
} as unknown) as IProjectContext
}>
<SurveyContext.Provider value={mockSurveyContext}>
<AuthStateContext.Provider value={authState as IAuthState}>
<DialogContextProvider>
<Router history={history}>
<SurveyHeader />
</Router>
</DialogContextProvider>
</AuthStateContext.Provider>
</SurveyContext.Provider>
</ProjectContext.Provider>
);
};

Expand Down
4 changes: 4 additions & 0 deletions app/src/features/surveys/view/SurveyHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { DeleteSurveyI18N } from 'constants/i18n';
import { PROJECT_ROLE, SYSTEM_ROLE } from 'constants/roles';
import { AuthStateContext } from 'contexts/authStateContext';
import { DialogContext } from 'contexts/dialogContext';
import { ProjectContext } from 'contexts/projectContext';
import { SurveyContext } from 'contexts/surveyContext';
import { APIError } from 'hooks/api/useAxios';
import { useBiohubApi } from 'hooks/useBioHubApi';
Expand Down Expand Up @@ -61,6 +62,8 @@ const useStyles = makeStyles((theme: Theme) => ({
*/
const SurveyHeader = () => {
const surveyContext = useContext(SurveyContext);
const projectContext = useContext(ProjectContext);

const surveyWithDetails = surveyContext.surveyDataLoader.data;

const classes = useStyles();
Expand Down Expand Up @@ -124,6 +127,7 @@ const SurveyHeader = () => {
showDeleteErrorDialog({ open: true });
return;
}
projectContext.surveysListDataLoader.refresh(projectContext.projectId);

history.push(`/admin/projects/${surveyContext.projectId}/surveys`);
} catch (error) {
Expand Down
89 changes: 89 additions & 0 deletions database/src/migrations/20230427160000_api_delete_survey.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { Knex } from 'knex';

/**
* Apply biohub release changes.
*
* @export
* @param {Knex} knex
* @return {*} {Promise<void>}
*/
export async function up(knex: Knex): Promise<void> {
await knex.raw(`set search_path=biohub;

CREATE OR REPLACE PROCEDURE api_delete_survey(p_survey_id integer)
LANGUAGE plpgsql
SECURITY DEFINER
AS $procedure$
-- *******************************************************************
-- Procedure: api_delete_survey
-- Purpose: deletes a survey and dependencies
--
-- MODIFICATION HISTORY
-- Person Date Comments
-- ---------------- ----------- --------------------------------------
-- [email protected]
-- 2021-06-18 initial release
-- [email protected]
-- 2021-06-21 added occurrence submission delete
-- [email protected]
-- 2021-09-21 added survey summary submission delete
-- [email protected]
-- 2022-08-28 added survey_vantage, survey_spatial_component, survey delete
-- [email protected]
-- 2022-09-07 changes to permit model
-- [email protected]
-- 2022-10-05 1.3.0 model changes
-- [email protected]
-- 2022-10-05 1.5.0 model changes, drop concept of occurrence deletion for published data
-- [email protected]
-- 2023-03-14 1.7.0 model changes
-- [email protected]
-- 2023-03-15 added missing publish tables to survey delete
curtisupshall marked this conversation as resolved.
Show resolved Hide resolved
-- *******************************************************************
declare

begin
with occurrence_submissions as (select occurrence_submission_id from occurrence_submission where survey_id = p_survey_id)
, submission_spatial_components as (select submission_spatial_component_id from submission_spatial_component
where occurrence_submission_id in (select occurrence_submission_id from occurrence_submissions))
delete from spatial_transform_submission where submission_spatial_component_id in (select submission_spatial_component_id from submission_spatial_components);
delete from submission_spatial_component where occurrence_submission_id in (select occurrence_submission_id from occurrence_submission where survey_id = p_survey_id);

with occurrence_submissions as (select occurrence_submission_id from occurrence_submission where survey_id = p_survey_id)
, submission_statuses as (select submission_status_id from submission_status
where occurrence_submission_id in (select occurrence_submission_id from occurrence_submissions))
delete from submission_message where submission_status_id in (select submission_status_id from submission_statuses);
delete from submission_status where occurrence_submission_id in (select occurrence_submission_id from occurrence_submission where survey_id = p_survey_id);

delete from occurrence_submission_publish where occurrence_submission_id in (select occurrence_submission_id from occurrence_submission where survey_id = p_survey_id);

delete from occurrence_submission where survey_id = p_survey_id;

delete from survey_summary_submission_publish where survey_summary_submission_id in (select survey_summary_submission_id from survey_summary_submission where survey_id = p_survey_id);
delete from survey_summary_submission_message where survey_summary_submission_id in (select survey_summary_submission_id from survey_summary_submission where survey_id = p_survey_id);
delete from survey_summary_submission where survey_id = p_survey_id;
delete from survey_proprietor where survey_id = p_survey_id;
delete from survey_attachment_publish where survey_attachment_id in (select survey_attachment_id from survey_attachment where survey_id = p_survey_id);
delete from survey_attachment where survey_id = p_survey_id;
delete from survey_report_author where survey_report_attachment_id in (select survey_report_attachment_id from survey_report_attachment where survey_id = p_survey_id);
delete from survey_report_publish where survey_report_attachment_id in (select survey_report_attachment_id from survey_report_attachment where survey_id = p_survey_id);
delete from survey_report_attachment where survey_id = p_survey_id;
delete from study_species where survey_id = p_survey_id;
delete from survey_funding_source where survey_id = p_survey_id;
delete from survey_vantage where survey_id = p_survey_id;
delete from survey_spatial_component where survey_id = p_survey_id;
delete from survey_metadata_publish where survey_id = p_survey_id;

delete from permit where survey_id = p_survey_id;
delete from survey where survey_id = p_survey_id;

exception
when others THEN
raise;
end;
$procedure$;`);
}

export async function down(knex: Knex): Promise<void> {
await knex.raw(``);
}