Skip to content

Commit

Permalink
Merge pull request #611 from desci-labs/develop
Browse files Browse the repository at this point in the history
promote main
  • Loading branch information
hubsmoke authored Oct 31, 2024
2 parents 2573cd6 + 54763cb commit 122c279
Show file tree
Hide file tree
Showing 11 changed files with 291 additions and 47 deletions.
43 changes: 10 additions & 33 deletions desci-server/src/controllers/doi/mint.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { DoiStatus } from '@prisma/client';
import sgMail from '@sendgrid/mail';
import { Request, Response, NextFunction } from 'express';
import _ from 'lodash';

Expand All @@ -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';

Expand Down Expand Up @@ -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');

Expand Down Expand Up @@ -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(
Expand Down
2 changes: 2 additions & 0 deletions desci-server/src/controllers/nodes/doi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
import { NextFunction, Response } from 'express';
import { Request } from 'express';
import _ from 'lodash';
import { v4 as uuidv4 } from 'uuid';
import { z } from 'zod';

import { BadRequestError, NotFoundError, UnProcessableRequestError } from '../../core/ApiError.js';
Expand Down Expand Up @@ -182,6 +183,7 @@ export const automateManuscriptDoi = async (req: RequestWithNode, res: Response,
actions.push({
type: 'Set Contributors',
contributors: authors.map((author) => ({
id: uuidv4(),
name: author.name,
role: ResearchObjectV1AuthorRole.AUTHOR,
...(author.affiliations.length > 0 && { organizations: author.affiliations }),
Expand Down
2 changes: 1 addition & 1 deletion desci-server/src/routes/v1/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ router.post('/distribution', preparePublishPackage);
router.post('/distribution/preview', [ensureUser], frontmatterPreview);

// Doi api routes
router.get('/:identifier/doi', [ensureUser], asyncHandler(retrieveNodeDoi));
router.get('/:identifier/doi', [], asyncHandler(retrieveNodeDoi));
router.post(
'/:uuid/automate-metadata',
[ensureUser, ensureNodeAccess, validate(automateMetadataSchema)],
Expand Down
2 changes: 2 additions & 0 deletions desci-server/src/services/AutomatedMetadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DocumentId } from '@automerge/automerge-repo';
import { ManifestActions, ResearchObjectV1Author, ResearchObjectV1AuthorRole } from '@desci-labs/desci-models';
import axios from 'axios';
import FormData from 'form-data';
import { v4 as uuidv4 } from 'uuid';

import { logger as parentLogger } from '../logger.js';
import { ONE_DAY_TTL, getFromCache, setToCache } from '../redisClient.js';
Expand Down Expand Up @@ -314,6 +315,7 @@ export class AutomatedMetadataClient {
contributors: metadata.authors.map(
(author) =>
({
id: uuidv4(),
name: author.name,
role: ResearchObjectV1AuthorRole.AUTHOR,
...(author.affiliations.length > 0 && { organizations: author.affiliations }),
Expand Down
3 changes: 2 additions & 1 deletion desci-server/src/services/crossRef/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
71 changes: 71 additions & 0 deletions desci-server/src/services/email.ts
Original file line number Diff line number Diff line change
@@ -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);
}
};
20 changes: 20 additions & 0 deletions desci-server/src/workers/doiSubmissionQueue.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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 };
});
Expand Down
17 changes: 17 additions & 0 deletions nodes-lib/.vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Nodes Lib Tests",
"type": "node",
"request": "attach",
"restart": true,
"port": 9229,
"address": "localhost",
"localRoot": "${workspaceFolder}"
}
]
}
Loading

0 comments on commit 122c279

Please sign in to comment.