diff --git a/desci-server/src/controllers/doi/mint.ts b/desci-server/src/controllers/doi/mint.ts index 25b1f888f..44976ac81 100644 --- a/desci-server/src/controllers/doi/mint.ts +++ b/desci-server/src/controllers/doi/mint.ts @@ -1,5 +1,4 @@ import { DoiStatus } from '@prisma/client'; -import sgMail from '@sendgrid/mail'; import { Request, Response, NextFunction } from 'express'; import _ from 'lodash'; @@ -8,9 +7,9 @@ import { BadRequestError } from '../../core/ApiError.js'; import { SuccessMessageResponse, SuccessResponse } from '../../core/ApiResponse.js'; import { MintError } from '../../core/doi/error.js'; import { logger as parentLogger } from '../../logger.js'; +import { EmailTypes, sendEmail } from '../../services/email.js'; import { getTargetDpidUrl } from '../../services/fixDpid.js'; import { crossRefClient, doiService } from '../../services/index.js'; -import { DoiMintedEmailHtml } from '../../templates/emails/utils/emailRenderer.js'; import { DiscordChannel, discordNotify, DiscordNotifyType } from '../../utils/discordUtils.js'; import { ensureUuidEndsWithDot } from '../../utils.js'; @@ -64,12 +63,6 @@ export const handleCrossrefNotificationCallback = async ( return; } - // if (submission.status === DoiStatus.SUCCESS) { - // logger.trace({ payload: req.payload }, 'Crossref Notifiication: submission '); - // new SuccessMessageResponse().send(res); - // return; - // } - await doiService.updateSubmission({ id: submission.id }, { notification: req.payload }); logger.info('SUBMISSION UPDATED'); @@ -102,32 +95,16 @@ export const handleCrossrefNotificationCallback = async ( }); if (!node.owner.email) return; - const message = { - to: node.owner.email, - from: 'no-reply@desci.com', - subject: 'DOI Registration successful 🎉', - text: `Hello ${node.owner.name}, You DOI registration for the research object ${node.title} has been completed. Here is your DOI: ${process.env.CROSSREF_DOI_URL}/${submission.uniqueDoi}`, - html: DoiMintedEmailHtml({ - dpid: submission.dpid, - userName: node.owner.name.split(' ')?.[0] ?? '', - dpidPath: `${process.env.DAPP_URL}/dpid/${submission.dpid}`, + sendEmail({ + type: EmailTypes.DoiMinted, + payload: { + name: node.owner.name, doi: submission.uniqueDoi, - doiLink: `${process.env.CROSSREF_DOI_URL}/${submission.uniqueDoi}`, - nodeTitle: node.title, - }), - }; - - try { - logger.info({ members: message, NODE_ENV: process.env.NODE_ENV }, 'DOI MINTED EMAIL'); - if (process.env.NODE_ENV === 'production') { - const response = await sgMail.send(message); - logger.info(response, '[EMAIL]:: Response'); - } else { - logger.info({ nodeEnv: process.env.NODE_ENV }, message.subject); - } - } catch (err) { - logger.info({ err }, '[ERROR]:: DOI MINTED EMAIL'); - } + dpid: submission.dpid, + to: node.owner.email, + title: node.title, + }, + }); } else { logger.info('ERROR CREATING DOI'); await doiService.updateSubmission( diff --git a/desci-server/src/services/crossRef/client.ts b/desci-server/src/services/crossRef/client.ts index 85de49225..a4ca0f018 100644 --- a/desci-server/src/services/crossRef/client.ts +++ b/desci-server/src/services/crossRef/client.ts @@ -353,8 +353,9 @@ class CrossRefClient { logger.info({ result }, 'PAYLOAD'); const doi_batch_diagnostic = result?.elements?.[0]; const batch_data = doi_batch_diagnostic.elements?.find((el) => el.name === 'batch_data'); + // const record_diagnostic = doi_batch_diagnostic.elements?.find((el) => el.name === 'record_diagnostic'); const success = batch_data?.elements?.find((element) => element.name === 'success_count'); - const isSuccess = success?.elements?.[0]?.text === '1'; + const isSuccess = Number(success?.elements?.[0]?.text) > 0; return { success: isSuccess, failure: !isSuccess }; } else { // handle json response diff --git a/desci-server/src/services/email.ts b/desci-server/src/services/email.ts new file mode 100644 index 000000000..858ca27d3 --- /dev/null +++ b/desci-server/src/services/email.ts @@ -0,0 +1,71 @@ +import sgMail from '@sendgrid/mail'; + +import { logger as parentLogger } from '../logger.js'; +import { DoiMintedEmailHtml } from '../templates/emails/utils/emailRenderer.js'; + +export enum EmailTypes { + DoiMinted, + DOI_REGISTRATION_REQUESTED, +} + +type DoiRegisteredPayload = { + type: EmailTypes.DoiMinted; + payload: { to: string; name: string; title: string; dpid: string; doi: string }; +}; + +type DoiRequestedPayload = { + type: EmailTypes.DOI_REGISTRATION_REQUESTED; + payload: { to: string; subject: string; name: string }; +}; + +export type EmailProps = DoiRegisteredPayload | DoiRequestedPayload; + +const logger = parentLogger.child({ module: 'EmailService' }); + +export function assertNever(value: never) { + console.error('Unknown value', value); + throw Error('Not Possible'); +} + +async function sendDoiRegisteredEmail({ to, name, title, dpid, doi }: DoiRegisteredPayload['payload']) { + const message = { + to, + from: 'no-reply@desci.com', + subject: 'DOI Registration successful 🎉', + text: `Hello ${name}, You DOI registration for the research object ${title} has been completed. Here is your DOI: ${process.env.CROSSREF_DOI_URL}/${doi}`, + html: DoiMintedEmailHtml({ + dpid, + doi, + nodeTitle: title, + userName: name.split(' ')?.[0] ?? '', + dpidPath: `${process.env.DAPP_URL}/dpid/${dpid}`, + doiLink: `${process.env.CROSSREF_DOI_URL}/${doi}`, + }), + }; + + try { + if (process.env.NODE_ENV === 'production') { + const response = await sgMail.send(message); + logger.trace(response, '[EMAIL]:: Response'); + } else { + logger.info({ nodeEnv: process.env.NODE_ENV }, message.subject); + } + } catch (err) { + logger.error({ err }, '[ERROR]:: DOI MINTED EMAIL'); + } +} + +async function sendDoiRequested(payload: DoiRequestedPayload['payload']) { + // +} + +export const sendEmail = async (props: EmailProps) => { + switch (props.type) { + case EmailTypes.DoiMinted: + return sendDoiRegisteredEmail(props.payload); + case EmailTypes.DOI_REGISTRATION_REQUESTED: + return sendDoiRequested(props.payload); + default: + assertNever(props); + } +}; diff --git a/desci-server/src/workers/doiSubmissionQueue.ts b/desci-server/src/workers/doiSubmissionQueue.ts index 1b574247a..7cd93f753 100644 --- a/desci-server/src/workers/doiSubmissionQueue.ts +++ b/desci-server/src/workers/doiSubmissionQueue.ts @@ -1,6 +1,8 @@ import { CronJob } from 'cron'; +import { prisma } from '../client.js'; import { logger as parentLogger } from '../logger.js'; +import { EmailTypes, sendEmail } from '../services/email.js'; import { doiService } from '../services/index.js'; import { DiscordChannel, discordNotify, DiscordNotifyType } from '../utils/discordUtils.js'; import { asyncMap } from '../utils.js'; @@ -36,6 +38,24 @@ export const onTick = async () => { message: `DOI: https://doi.org/${job.uniqueDoi} DPID: ${job.dpid}`, }); + + const node = await prisma.node.findFirst({ + where: { uuid: job.uuid }, + include: { owner: { select: { email: true, name: true } } }, + }); + + if (node.owner.email) { + sendEmail({ + type: EmailTypes.DoiMinted, + payload: { + name: node.owner.name, + doi: job.uniqueDoi, + dpid: job.dpid, + to: node.owner.email, + title: node.title, + }, + }); + } } return { doi: job.uniqueDoi, jobId: job.id, isResolved }; });