Skip to content

Commit

Permalink
send email on manuscript action
Browse files Browse the repository at this point in the history
  • Loading branch information
AkosuaA committed Jan 27, 2025
1 parent 961ae1f commit d7d1d79
Show file tree
Hide file tree
Showing 7 changed files with 1,106 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,15 @@ import {
Environment,
FetchManuscriptByIdQuery,
FetchManuscriptByIdQueryVariables,
FetchManuscriptNotificationDetailsQuery,
FetchManuscriptNotificationDetailsQueryVariables,
FetchManuscriptsByTeamIdQuery,
FetchManuscriptsQuery,
FetchManuscriptsQueryVariables,
FETCH_MANUSCRIPTS,
FETCH_MANUSCRIPTS_BY_TEAM_ID,
FETCH_MANUSCRIPT_BY_ID,
FETCH_MANUSCRIPT_NOTIFICATION_DETAILS,
getLinkAsset,
getLinkAssets,
getLinkEntities,
Expand All @@ -28,15 +31,22 @@ import {
ManuscriptLifecycle,
manuscriptLifecycles,
manuscriptMapStatus,
manuscriptNotificationMapping,
ManuscriptResubmitDataObject,
ManuscriptStatus,
ManuscriptType,
manuscriptTypes,
ManuscriptUpdateAction,
ManuscriptUpdateDataObject,
ManuscriptVersion,
QuickCheckDetails,
QuickCheckDetailsObject,
TemplateName,
} from '@asap-hub/model';
import { parseUserDisplayName } from '@asap-hub/server-common';
import { origin } from '../../config';
import { cleanArray } from '../../utils/clean-array';
import { getCommaAndString } from '../../utils/text';

import { ManuscriptDataProvider } from '../types';
import { Discussion, parseGraphQLDiscussion } from './discussion.data-provider';
Expand Down Expand Up @@ -235,6 +245,104 @@ export class ManuscriptContentfulDataProvider
return manuscriptVersionEntry.sys.id;
}

private async sendEmailNotification(
action: ManuscriptUpdateAction,
manuscriptId: string,
): Promise<void> {
const { manuscripts } = await this.contentfulClient.request<
FetchManuscriptNotificationDetailsQuery,
FetchManuscriptNotificationDetailsQueryVariables
>(FETCH_MANUSCRIPT_NOTIFICATION_DETAILS, { id: manuscriptId });

const versionData = manuscripts?.versionsCollection?.items[0];

if (!manuscripts || !versionData) {
return;
}

const contributingTeams = cleanArray(versionData.teamsCollection?.items)
.map((team) => team?.displayName || '')
.filter(Boolean);
const submittingTeam = manuscripts.teamsCollection?.items[0];

const notificationData: TemplateModel = {
manuscript: {
title: manuscripts.title || '',
type: versionData.type || '',
id: getManuscriptVersionUID({
version: {
type: versionData.type,
count: versionData.count,
lifecycle: versionData.lifecycle,
},
teamIdCode: submittingTeam?.teamId || '',
grantId: submittingTeam?.grantId || '',
manuscriptCount: manuscripts.count || 0,
}),
},
teams: getCommaAndString(contributingTeams),
submittingTeam: {
name: submittingTeam?.displayName || '',
workspaceLink: `${origin}/teams/${submittingTeam?.sys.id}/workspace`,
},
};

const contributingAuthors = [
...(versionData.firstAuthorsCollection?.items.map(
(firstAuthor) => firstAuthor?.email,
) || []),
...(versionData.additionalAuthorsCollection?.items.map(
(additionalAuthor) => additionalAuthor?.email,
) || []),
...(versionData.correspondingAuthorCollection?.items.map(
(correspondingAuthor) => correspondingAuthor?.email,
) || []),
];

const teamLeaders = versionData.teamsCollection?.items.map((team) => {
const activeMemberships =
team?.linkedFrom?.teamMembershipCollection?.items
.filter(
(membership) =>
!membership?.inactiveSinceDate &&
!membership?.linkedFrom?.usersCollection?.items[0]
?.alumniSinceDate,
)
.map((membership) => ({
email: membership?.linkedFrom?.usersCollection?.items[0]?.email,
role: membership?.role,
}));

return activeMemberships
?.filter(
(member) =>
member.role === 'Project Manager' ||
member.role === 'Lead PI (Core Leadership)',
)
.map((member) => member.email);
});

const recipients = [
...new Set([...contributingAuthors, ...(teamLeaders || [])]),
].join(',');

const templateDetails = manuscriptNotificationMapping[action];
if (templateDetails.grantee)
dummySendEmail({
from: '[email protected]',
to: recipients,
templateName: templateDetails.grantee,
templateModel: notificationData,
});
if (templateDetails.open_science_team)
dummySendEmail({
from: '[email protected]',
to: '[email protected]',
templateName: templateDetails.open_science_team,
templateModel: notificationData,
});
}

async create(input: ManuscriptCreateDataObject): Promise<string> {
const environment = await this.getRestClient();

Expand Down Expand Up @@ -269,6 +377,11 @@ export class ManuscriptContentfulDataProvider

await manuscriptEntry.publish();

await this.sendEmailNotification(
'manuscript_submitted',
manuscriptEntry.sys.id,
);

return manuscriptEntry.sys.id;
}

Expand Down Expand Up @@ -304,6 +417,11 @@ export class ManuscriptContentfulDataProvider
teams: getLinkEntities(version.teams),
status: 'Manuscript Resubmitted',
});

await this.sendEmailNotification(
'manuscript_resubmitted',
manuscriptEntry.sys.id,
);
}

async update(
Expand All @@ -323,6 +441,12 @@ export class ManuscriptContentfulDataProvider
statusUpdatedBy: getLinkEntity(userId),
statusUpdatedAt: new Date(),
});
const statusUpdateAction = getStatusUpdateAction(manuscriptData.status);
if (statusUpdateAction)
await this.sendEmailNotification(
statusUpdateAction,
manuscriptEntry.sys.id,
);
}

if ('versions' in manuscriptData && manuscriptData.versions?.[0]) {
Expand Down Expand Up @@ -709,3 +833,106 @@ export const getManuscriptVersionUID = ({
'0',
)}-${manuscriptTypeCode}-${lifecycleCode}-${version.count}`;
};

const getStatusUpdateAction = (
status: ManuscriptStatus | undefined,
): ManuscriptUpdateAction | null => {
switch (status) {
case "Waiting for Grantee's Reply":
return 'status_changed_waiting_for_grantee_reply';
case 'Review Compliance Report':
return 'status_changed_review_compliance_report';
case 'Submit Final Publication':
return 'status_changed_submit_final_publication';
case 'Addendum Required':
return 'status_changed_addendum_required';
case 'Compliant':
return 'status_changed_compliant';
case 'Closed (other)':
return 'status_changed_closed_other';
default:
return null;
}
};
const dummySendEmail = ({
from,
to,
templateName,
templateModel,
}: {
from: string;
to: string;
templateName: TemplateName;
templateModel: TemplateModel;
}) => {
const templates = {
'Waiting for Report (Grantees)': `Waiting for Report (Grantees):
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
'Waiting for Report (OS Team)': `Waiting for Report (OS Team):
[submitting Team] - ${templateModel.submittingTeam.name}
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}
[link to Team's workspace] - ${templateModel.submittingTeam.workspaceLink}`,
'Manuscript Re-Submitted (For Grantees)': `Manuscript Re-Submitted (For Grantees):
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
'Manuscript Re-Submitted (For OS Team)': `Manuscript Re-Submitted (For OS Team):
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}`,
'Waiting for Grantee Reply': `Waiting for Grantee Reply:
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
'Review Compliance Report': `Review Compliance Report:
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
'Submit Final Publication': `Submit Final Publication:
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
'Addendum Required': `Addendum Required:
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
Compliant: `Compliant:
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[manuscript type] - ${templateModel.manuscript.type}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
'Closed (Other)': `Closed (Other):
[manuscript title] - ${templateModel.manuscript.title}
[manuscript ID] - ${templateModel.manuscript.id}
[Team Names mentioned in the Manuscript] - ${templateModel.teams}`,
};

// eslint-disable-next-line no-console
console.log('FROM: ', from);
// eslint-disable-next-line no-console
console.log('TO: ', to);

// eslint-disable-next-line no-console
console.log(templates[templateName]);
};

type TemplateModel = {
manuscript: {
title: string;
type: string;
id: string;
};
teams: string;
submittingTeam: {
name: string;
workspaceLink: string;
};
};
15 changes: 15 additions & 0 deletions apps/crn-server/src/utils/text.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export const getCommaAndString = (array: string[]): string => {
const [last, ...head] = array.reverse().map((v) => v.trim());

switch (array.length) {
case 0: {
return '';
}
case 1: {
return `${last}`;
}
default: {
return `${head.reverse().join(', ')} and ${last}`;
}
}
};
15 changes: 15 additions & 0 deletions apps/crn-server/test/utils/text.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getCommaAndString } from '../../src/utils/text';

it('getCommaAndString separates items in array with commas (except last)', () => {
expect(getCommaAndString([])).toEqual('');
expect(getCommaAndString([''])).toEqual('');
expect(getCommaAndString(['one'])).toEqual('one');
expect(getCommaAndString(['one', 'two'])).toEqual('one and two');
expect(getCommaAndString(['one', 'two', 'three'])).toEqual(
'one, two and three',
);
expect(getCommaAndString([' one ', ' two '])).toEqual('one and two');
expect(getCommaAndString(['one lab', 'two labs', 'three labs'])).toEqual(
'one lab, two labs and three labs',
);
});
Loading

0 comments on commit d7d1d79

Please sign in to comment.