Skip to content

Commit

Permalink
Add support for submitting reports to BioHub
Browse files Browse the repository at this point in the history
  • Loading branch information
NickPhura committed Jan 22, 2024
1 parent 2b61993 commit d12f517
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 67 deletions.
64 changes: 55 additions & 9 deletions api/src/models/biohub-create.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { FeatureCollection } from 'geojson';
import { ISurveyAttachment } from '../repositories/attachment-repository';
import { ATTACHMENT_TYPE } from '../constants/attachments';
import { ISurveyAttachment, ISurveyReportAttachment } from '../repositories/attachment-repository';
import { ObservationRecord } from '../repositories/observation-repository';
import { getLogger } from '../utils/logger';
import { GetSurveyData, GetSurveyPurposeAndMethodologyData } from './survey-view';
Expand Down Expand Up @@ -70,20 +71,20 @@ export class PostSurveyObservationToBiohubObject implements BioHubSubmissionFeat
}

/**
* Object to be sent to Biohub API for creating an artifact.
* Object to be sent to Biohub API for creating an artifact (for a SIMS attachment).
*
* @export
* @class PostSurveyArtifactsToBiohubObject
* @class PostSurveyAttachmentsToBiohubObject
* @implements {BioHubSubmissionFeature}
*/
export class PostSurveyArtifactsToBiohubObject implements BioHubSubmissionFeature {
export class PostSurveyAttachmentsToBiohubObject implements BioHubSubmissionFeature {
id: string;
type: string;
properties: Record<string, any>;
child_features: BioHubSubmissionFeature[];

constructor(attachmentRecord: ISurveyAttachment) {
defaultLog.debug({ label: 'PostSurveyArtifactsToBiohubObject', message: 'params', attachmentRecord });
defaultLog.debug({ label: 'PostSurveyAttachmentsToBiohubObject', message: 'params', attachmentRecord });

this.id = attachmentRecord.uuid;
this.type = BiohubFeatureType.ARTIFACT;
Expand All @@ -99,6 +100,37 @@ export class PostSurveyArtifactsToBiohubObject implements BioHubSubmissionFeatur
}
}

/**
* Object to be sent to Biohub API for creating an artifact (for a SIMS report attachment).
*
* @export
* @class PostSurveyReportAttachmentsToBiohubObject
* @implements {BioHubSubmissionFeature}
*/
export class PostSurveyReportAttachmentsToBiohubObject implements BioHubSubmissionFeature {
id: string;
type: string;
properties: Record<string, any>;
child_features: BioHubSubmissionFeature[];

constructor(reportAttachmentRecord: ISurveyReportAttachment) {
defaultLog.debug({ label: 'PostSurveyReportAttachmentsToBiohubObject', message: 'params', reportAttachmentRecord });

this.id = reportAttachmentRecord.uuid;
this.type = BiohubFeatureType.ARTIFACT;
this.properties = {
artifact_id: reportAttachmentRecord.survey_report_attachment_id,
filename: reportAttachmentRecord.file_name,
file_type: ATTACHMENT_TYPE.REPORT,
file_size: reportAttachmentRecord.file_size,
title: reportAttachmentRecord.title,
description: reportAttachmentRecord.description,
year_published: reportAttachmentRecord.year_published
};
this.child_features = [];
}
}

/**
* Object to be sent to Biohub API for creating a survey.
*
Expand All @@ -116,15 +148,22 @@ export class PostSurveyToBiohubObject implements BioHubSubmissionFeature {
surveyData: GetSurveyData,
observationRecords: ObservationRecord[],
surveyGeometry: FeatureCollection,
surveyAttachments: ISurveyAttachment[]
surveyAttachments: ISurveyAttachment[],
surveyReports: ISurveyReportAttachment[]
) {
defaultLog.debug({ label: 'PostSurveyToBiohubObject', message: 'params', surveyData });

const observationFeatures = observationRecords.map(
(observation) => new PostSurveyObservationToBiohubObject(observation)
);

const artifactFeatures = surveyAttachments.map((artifact) => new PostSurveyArtifactsToBiohubObject(artifact));
const attachmentFeatures = surveyAttachments.map(
(attachment) => new PostSurveyAttachmentsToBiohubObject(attachment)
);

const reportAttachmentFeatures = surveyReports.map(
(attachment) => new PostSurveyReportAttachmentsToBiohubObject(attachment)
);

this.id = surveyData.uuid;
this.type = BiohubFeatureType.DATASET;
Expand All @@ -138,7 +177,7 @@ export class PostSurveyToBiohubObject implements BioHubSubmissionFeature {
revision_count: surveyData.revision_count,
geometry: surveyGeometry
};
this.child_features = [...observationFeatures, ...artifactFeatures];
this.child_features = [...observationFeatures, ...reportAttachmentFeatures, ...attachmentFeatures];
}
}

Expand All @@ -155,6 +194,7 @@ export class PostSurveySubmissionToBioHubObject implements BioHubSubmission {
observationRecords: ObservationRecord[],
surveyGeometry: FeatureCollection,
surveyAttachments: ISurveyAttachment[],
surveyReports: ISurveyReportAttachment[],
submissionComment: string
) {
defaultLog.debug({ label: 'PostSurveySubmissionToBioHubObject' });
Expand All @@ -163,7 +203,13 @@ export class PostSurveySubmissionToBioHubObject implements BioHubSubmission {
this.name = surveyData.survey_name;
this.description = GetSurveyPurposeAndMethodologyData.additional_details;
this.comment = submissionComment;
this.content = new PostSurveyToBiohubObject(surveyData, observationRecords, surveyGeometry, surveyAttachments);
this.content = new PostSurveyToBiohubObject(
surveyData,
observationRecords,
surveyGeometry,
surveyAttachments,
surveyReports
);
}
}

Expand Down
3 changes: 2 additions & 1 deletion api/src/models/project-survey-attachments.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { default as dayjs } from 'dayjs';
import { getLogger } from '../utils/logger';
import { SurveySupplementaryData } from './survey-view';
import { ATTACHMENT_TYPE } from '../constants/attachments';

const defaultLog = getLogger('models/project-survey-attachments');

Expand Down Expand Up @@ -28,7 +29,7 @@ export class GetAttachmentsWithSupplementalData {
attachment.project_attachment_id ||
attachment.project_report_attachment_id;
this.fileName = attachment.file_name;
this.fileType = attachment.file_type || 'Report';
this.fileType = attachment.file_type || ATTACHMENT_TYPE.REPORT;
this.lastModified = dayjs(attachment.update_date || attachment.create_date).toISOString();
this.size = attachment.file_size;
this.status = attachment.status;
Expand Down
113 changes: 83 additions & 30 deletions api/src/services/platform-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { URL } from 'url';
import { IDBConnection } from '../database/db';
import { ApiError, ApiErrorType, ApiGeneralError } from '../errors/api-error';
import { PostSurveySubmissionToBioHubObject } from '../models/biohub-create';
import { ISurveyAttachment } from '../repositories/attachment-repository';
import { ISurveyAttachment, ISurveyReportAttachment } from '../repositories/attachment-repository';
import { getFileFromS3 } from '../utils/file-utils';
import { getLogger } from '../utils/logger';
import { AttachmentService } from './attachment-service';
Expand All @@ -16,7 +16,7 @@ import { KeycloakService } from './keycloak-service';
import { ObservationService } from './observation-service';
import { SurveyService } from './survey-service';

const defaultLog = getLogger('services/platform-repository');
const defaultLog = getLogger('services/platform-service');

export interface IArtifact {
/**
Expand All @@ -43,8 +43,8 @@ export interface IArtifact {

const getBackboneIntakeEnabled = () => process.env.BACKBONE_INTAKE_ENABLED === 'true' || false;
const getBackboneApiHost = () => process.env.BACKBONE_API_HOST || '';
const getBackboneArtifactIntakePath = () => process.env.BACKBONE_ARTIFACT_INTAKE_PATH || '/api/artifact/intake';
const getBackboneSurveyIntakePath = () => process.env.BACKBONE_DATASET_INTAKE_PATH || '/api/submission/intake';
const getBackboneArtifactIntakePath = () => process.env.BACKBONE_ARTIFACT_INTAKE_PATH || '';
const getBackboneSurveyIntakePath = () => process.env.BACKBONE_DATASET_INTAKE_PATH || '';

export class PlatformService extends DBService {
attachmentService: AttachmentService;
Expand All @@ -62,7 +62,7 @@ export class PlatformService extends DBService {
*
* @param {number} surveyId
* @param {{ submissionComment: string }} data
* @return {*} {Promise<{ submission_uuid: number }>}
* @return {*} {Promise<{ submission_uuid: string }>}
* @memberof PlatformService
*/
async submitSurveyToBioHub(
Expand All @@ -77,7 +77,7 @@ export class PlatformService extends DBService {

const keycloakService = new KeycloakService();

// Get keycloak token for BioHub service account
// Get keycloak token for SIMS service client account
const token = await keycloakService.getKeycloakServiceToken();

// Create intake url
Expand All @@ -86,10 +86,14 @@ export class PlatformService extends DBService {
// Get survey attachments
const surveyAttachments = await this.attachmentService.getSurveyAttachments(surveyId);

// Get survey report attachments
const surveyReportAttachments = await this.attachmentService.getSurveyReportAttachments(surveyId);

// Generate survey data package
const surveyDataPackage = await this._generateSurveyDataPackage(
surveyId,
surveyAttachments,
surveyReportAttachments,
data.submissionComment
);

Expand All @@ -108,18 +112,22 @@ export class PlatformService extends DBService {
throw new ApiError(ApiErrorType.UNKNOWN, 'Failed to submit survey ID to Biohub');
}

// Submit survey attachments to BioHub
await this._submitSurveyAttachmentsToBioHub(
surveyDataPackage.id,
surveyAttachments,
response.data.artifact_upload_keys
);
await Promise.all([
// Submit survey attachments to BioHub
this._submitSurveyAttachmentsToBioHub(
surveyDataPackage.id,
surveyAttachments,
response.data.artifact_upload_keys
),
// Submit survey report attachments to BioHub
this._submitSurveyReportAttachmentsToBioHub(
surveyDataPackage.id,
surveyReportAttachments,
response.data.artifact_upload_keys
)
]);

// Insert publish history record

// NOTE: this is a temporary solution to get the submission_uuid into the publish history table
// the submission_uuid is not returned from the survey intake endpoint, so we are using the submission_uuid
// as a temporary solution
await this.historyPublishService.insertSurveyMetadataPublishRecord({
survey_id: surveyId,
submission_uuid: response.data.submission_uuid
Expand All @@ -133,13 +141,15 @@ export class PlatformService extends DBService {
*
* @param {number} surveyId
* @param {ISurveyAttachment[]} surveyAttachments
* @param {ISurveyReportAttachment[]} surveyReportAttachments
* @param {string} submissionComment
* @return {*} {Promise<PostSurveySubmissionToBioHubObject>}
* @memberof PlatformService
*/
async _generateSurveyDataPackage(
surveyId: number,
surveyAttachments: ISurveyAttachment[],
surveyReportAttachments: ISurveyReportAttachment[],
submissionComment: string
): Promise<PostSurveySubmissionToBioHubObject> {
const observationService = new ObservationService(this.connection);
Expand All @@ -163,6 +173,7 @@ export class PlatformService extends DBService {
surveyObservations,
geometryFeatureCollection,
surveyAttachments,
surveyReportAttachments,
submissionComment
);

Expand All @@ -173,17 +184,18 @@ export class PlatformService extends DBService {
* Submit survey attachments submission to BioHub.
*
* @param {string} submissionUUID
* @param {ISurveyAttachment[]} surveyAttachments
* @return {*} {Promise<{ survey_attachment_publish_id: number }[]>}
* @param {ISurveyReportAttachment[]} surveyReportAttachments
* @param {{ artifact_filename: string; artifact_upload_key: number }[]} artifact_upload_keys
* @return {*} {Promise<{ survey_report_publish_id: number }[]>}
* @memberof PlatformService
*/
async _submitSurveyAttachmentsToBioHub(
submissionUUID: string,
surveyAttachments: ISurveyAttachment[],
artifact_upload_keys: { artifact_filename: string; artifact_upload_key: number }[]
): Promise<void> {
): Promise<{ survey_attachment_publish_id: number }[]> {
// Submit survey attachments to BioHub
await Promise.all(
return Promise.all(
// Loop through survey attachments
surveyAttachments.map(async (attachment) => {
// Get artifact_upload_key for attachment
Expand All @@ -204,15 +216,7 @@ export class PlatformService extends DBService {
artifact_upload_key: artifactUploadKey,
data: s3File.Body as Buffer,
fileName: attachment.file_name,
mimeType: s3File.ContentType || mime.getType(attachment.file_name) || attachment.file_type

// metadata: {
// file_name: attachment.file_name,
// file_size: attachment.file_size,
// file_type: attachment.file_type,
// title: attachment.title,
// description: attachment.description
// }
mimeType: s3File.ContentType || mime.getType(attachment.file_name) || 'application/octet-stream'
};

// Submit artifact to BioHub
Expand All @@ -225,8 +229,57 @@ export class PlatformService extends DBService {
});
})
);
}

/**
* Submit survey report attachments submission to BioHub.
*
* @param {string} submissionUUID
* @param {ISurveyReportAttachment[]} surveyReportAttachments
* @param {{ artifact_filename: string; artifact_upload_key: number }[]} artifact_upload_keys
* @return {*} {Promise<{ survey_report_publish_id: number }[]>}
* @memberof PlatformService
*/
async _submitSurveyReportAttachmentsToBioHub(
submissionUUID: string,
surveyReportAttachments: ISurveyReportAttachment[],
artifact_upload_keys: { artifact_filename: string; artifact_upload_key: number }[]
): Promise<{ survey_report_publish_id: number }[]> {
// Submit survey attachments to BioHub
return Promise.all(
// Loop through survey report attachments
surveyReportAttachments.map(async (attachment) => {
// Get artifact_upload_key for attachment
const artifactUploadKey = artifact_upload_keys.find(
(artifact) => artifact.artifact_filename === attachment.file_name
)?.artifact_upload_key;

// Throw error if artifact_upload_key is not found
if (!artifactUploadKey) {
throw new ApiError(ApiErrorType.UNKNOWN, 'Failed to submit survey report attachment to Biohub');
}

// return attachmentArtifactPublishRecords;
const s3File = await getFileFromS3(attachment.key);

// Build artifact object
const artifact = {
submission_uuid: submissionUUID,
artifact_upload_key: artifactUploadKey,
data: s3File.Body as Buffer,
fileName: attachment.file_name,
mimeType: s3File.ContentType || mime.getType(attachment.file_name) || 'application/octet-stream'
};

// Submit artifact to BioHub
const { artifact_uuid } = await this._submitArtifactFeatureToBioHub(artifact);

// Insert publish history record
return this.historyPublishService.insertSurveyReportPublishRecord({
artifact_uuid,
survey_report_attachment_id: attachment.survey_report_attachment_id
});
})
);
}

/**
Expand Down
Loading

0 comments on commit d12f517

Please sign in to comment.