Skip to content

Commit

Permalink
Merge pull request #437 from desci-labs/develop
Browse files Browse the repository at this point in the history
promote main
  • Loading branch information
hubsmoke authored Jul 17, 2024
2 parents 3c9206c + ca7b456 commit c9b02c3
Show file tree
Hide file tree
Showing 23 changed files with 335 additions and 87 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@ node-modules/
node_modules/*
.idea
.composedbRuntimeDefinition.json
openalex-importer
2 changes: 1 addition & 1 deletion desci-contracts/subgraph/subgraph.sepoliaProd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ dataSources:
name: DeSciNodes
network: sepolia
source:
address: "0xB954B4F1c01DcA2508278C4426EaF895f4133aDF"
address: "0x1fA4c72680af35FE1eb7345509E39498be6Ce03b"
abi: ResearchObjectMigrated
startBlock: 5530308
mapping:
Expand Down
4 changes: 3 additions & 1 deletion desci-media-isolated/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ NODE_ENV=development

PORT=7771

IPFS_GATEWAY=http://host.docker.internal:5420/v1/ipfs
IPFS_GATEWAY=http://host.docker.internal:5420/v1/ipfs

DPID_RESOLVER_URL=https://dev-beta.dpid.org
2 changes: 2 additions & 0 deletions desci-media-isolated/kubernetes/deployment_dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ spec:
value: '7771'
- name: IPFS_GATEWAY
value: 'https://ipfs.desci.com/ipfs'
- name: DPID_RESOLVER_URL
value: 'https://dev-beta.dpid.org'
resources:
limits:
cpu: '4'
Expand Down
14 changes: 9 additions & 5 deletions desci-media-isolated/kubernetes/deployment_prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,19 @@ spec:
- containerPort: 7771
name: api
env:
- name: NODE_ENV
value: 'production'
- name: PORT
value: '7771'
- name: IPFS_GATEWAY
value: 'http://host.docker.internal:5420/v1/ipfs'
value: 'https://ipfs.desci.com/ipfs'
- name: DPID_RESOLVER_URL
value: 'https://beta.dpid.org'
resources:
limits:
cpu: '0.5'
memory: 2Gi
cpu: '4'
memory: 4Gi
requests:
cpu: 250m
memory: 1Gi
cpu: '1'
memory: 2Gi
serviceAccountName: 'default'
2 changes: 2 additions & 0 deletions desci-media-isolated/kubernetes/deployment_staging.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ spec:
value: '7771'
- name: IPFS_GATEWAY
value: 'http://host.docker.internal:5420/v1/ipfs'
- name: DPID_RESOLVER_URL
value: 'https://dev-beta.dpid.org'
resources:
limits:
cpu: '0.5'
Expand Down
4 changes: 3 additions & 1 deletion desci-media-isolated/src/services/pdf.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ export class PdfManipulationService {
/*
* Header
*/
const dpidResolverUrl = process.env.DPID_RESOLVER_URL ?? 'https://beta.dpid.org';

const licenseStartsWithVowel = startsWithVowel(license);
const nodeUrl = usingDoi ? `https://doi.org/${doi}` : `https://beta.dpid.org/${dpid}`;
const nodeUrl = usingDoi ? `https://doi.org/${doi}` : `${dpidResolverUrl}/${dpid}`;
const topHeader = `Research object ${nodeUrl}, this version posted ${publishDate}. The copyright holder for this research object (which was not certified by peer review) is the author/funder, who has granted DeSci Labs a non-exclsuive license to display the research object in perpetuity. It is made available under a${
licenseStartsWithVowel ? 'n' : ''
} ${license} license.`;
Expand Down
4 changes: 2 additions & 2 deletions desci-server/kubernetes/deployment_prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ spec:
export CROSSREF_METADATA_API={{ .Data.CROSSREF_METADATA_API }}
export CROSSREF_ADMIN_API={{ .Data.CROSSREF_ADMIN_API }}
export CROSSREF_NOTIFY_ENDPOINT={{ .Data.CROSSREF_NOTIFY_ENDPOINT }}
export AUTOMATED_METADATA_API={{ .Data.AUTOMATED_METADATA_API }}
export AUTOMATED_METADATA_API_KEY={{ .Data.AUTOMATED_METADATA_API_KEY }}
export AUTOMATED_METADATA_API="{{ .Data.AUTOMATED_METADATA_API }}"
export AUTOMATED_METADATA_API_KEY="{{ .Data.AUTOMATED_METADATA_API_KEY }}"
export IGNORE_LINE=0;
export DEBUG_TEST=0;
echo "appfinish";
Expand Down
1 change: 1 addition & 0 deletions desci-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
"url-safe-base64": "1.2.0",
"uuid": "^8.3.2",
"ws": "^8.15.0",
"xml-js": "^1.6.11",
"yauzl": "^2.10.0",
"zod": "^3.22.4"
},
Expand Down
36 changes: 18 additions & 18 deletions desci-server/src/controllers/attestations/recommendations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,27 @@ const logger = parentLogger.child({ module: 'Recommendations' });

export const getAllRecommendations = async (_req: Request, res: Response, _next: NextFunction) => {
const attestations = await attestationService.getRecommendedAttestations();
const communityEntries = _(attestations)
.groupBy((x) => x.desciCommunityId)
.map((value, key) => ({
community: value[0].desciCommunity.name,
communityId: key,
attestations: value.map((attestation) => ({
id: attestation.id,
communityId: value[0].attestation.community.id,
communityName: value[0].attestation.community.name,
attestationId: attestation.attestationId,
attestationVersionId: attestation.attestationVersionId,
required: attestation.required,
createdAt: attestation.createdAt,
name: attestation.attestationVersion.name,
description: attestation.attestationVersion.description,
image_url: attestation.attestationVersion.image_url,
const attestationEntries = _(attestations)
.groupBy((x) => x.attestationId)
.map((value, _) => ({
attestationId: value[0].attestationId,
attestationVersionId: value[0].attestationVersionId,
required: value[0].required,
createdAt: value[0].createdAt,
name: value[0].attestationVersion.name,
description: value[0].attestationVersion.description,
image_url: value[0].attestationVersion.image_url,
communities: value.map((entry) => ({
communityId: entry.desciCommunityId,
communityName: entry.desciCommunity.name,
image_url: entry.desciCommunity.image_url,
})),
}))
.value();
.value()
.sort((entryA, entryB) => entryB.communities.length - entryA.communities.length);

return new SuccessResponse(communityEntries).send(res);
logger.info({ attestationEntries }, 'getAllRecommendations');
return new SuccessResponse(attestationEntries).send(res);
};

export const getCommunityRecommendations = async (req: Request, res: Response, _next: NextFunction) => {
Expand Down
10 changes: 10 additions & 0 deletions desci-server/src/controllers/auth/magic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import jwt from 'jsonwebtoken';
import { prisma as prismaClient } from '../../client.js';
import { logger } from '../../logger.js';
import { magicLinkRedeem, sendMagicLink } from '../../services/auth.js';
import { contributorService } from '../../services/Contributors.js';
import { saveInteraction } from '../../services/interactionLog.js';
import { checkIfUserAcceptedTerms, connectOrcidToUserIfPossible } from '../../services/user.js';
import { sendCookie } from '../../utils/sendCookie.js';
Expand Down Expand Up @@ -52,6 +53,15 @@ export const magic = async (req: Request, res: Response, next: NextFunction) =>
email,
},
});

if (user.email) {
// Inherits existing user contribution entries that were made with the same email
const inheritedContributions = await contributorService.updateContributorEntriesForNewUser({
email: user.email,
userId: user.id,
});
logger.trace({ inheritedContributions: inheritedContributions?.count, user, email });
}
}

try {
Expand Down
101 changes: 73 additions & 28 deletions desci-server/src/controllers/doi/mint.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { DoiStatus } from '@prisma/client';
import sgMail from '@sendgrid/mail';
import { Request, Response, NextFunction } from 'express';
import _ from 'lodash';

Expand All @@ -14,6 +15,7 @@ import {
logger as parentLogger,
prisma,
} from '../../internal.js';
import { DoiMintedEmailHtml } from '../../templates/emails/utils/emailRenderer.js';

export const mintDoi = async (req: Request, res: Response, _next: NextFunction) => {
const { uuid } = req.params;
Expand Down Expand Up @@ -52,41 +54,84 @@ export const handleCrossrefNotificationCallback = async (

if (!submission) {
logger.error({ payload: req.payload }, 'Crossref Notifiication: pending submission not found');
throw new NotFoundError('submission not found');
// throw new NotFoundError('submission not found');
new SuccessMessageResponse().send(res);
return;
}

if (submission.status === DoiStatus.SUCCESS) {
new SuccessMessageResponse().send(res);
return;
}

await doiService.updateSubmission({ id: submission.id }, { notification: req.payload });
logger.info('SUBMISSION UPDATED');

new SuccessMessageResponse().send(res);

// check retrieve url to get submission result
const response = await crossRefClient.retrieveSubmission(req.payload.retrieveUrl);
try {
// check retrieve url to get submission result
const response = await crossRefClient.retrieveSubmission(req.payload.retrieveUrl);

logger.info({ response, submission }, 'CREATE DOI CALLBACK RESPONSE');
if (response.success) {
logger.info('CREATE DOI ');
const doiRecord = await prisma.doiRecord.create({
data: {
uuid: submission.uuid,
dpid: submission.dpid,
doi: submission.uniqueDoi,
},
});
await doiService.updateSubmission(
{ id: submission.id },
{
status: DoiStatus.SUCCESS,
doiRecordId: doiRecord.id,
},
);
} else {
logger.info('ERROR CREATING DOI');
await doiService.updateSubmission(
{ id: submission.id },
{ status: response.failure ? DoiStatus.FAILED : DoiStatus.PENDING },
);
}
logger.info({ response, submission }, 'CREATE DOI CALLBACK RESPONSE');
if (response.success) {
logger.info({ response, submission }, 'CREATE DOI ');

// TODO: email authors about the submission status
const doiRecord = await prisma.doiRecord.create({
data: {
uuid: submission.uuid,
dpid: submission.dpid,
doi: submission.uniqueDoi,
},
});
await doiService.updateSubmission(
{ id: submission.id },
{
status: DoiStatus.SUCCESS,
doiRecordId: doiRecord.id,
},
);

// Send Notification Email Node author about the submission status
const node = await prisma.node.findFirst({
where: { uuid: submission.uuid },
include: { owner: { select: { email: true, name: true } } },
});

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}`,
doi: `${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');
}
} else {
logger.info('ERROR CREATING DOI');
await doiService.updateSubmission(
{ id: submission.id },
{ status: response.failure ? DoiStatus.FAILED : DoiStatus.PENDING },
);
}
} catch (error) {
logger.error({ error }, 'Error updating DOI submission');
}
};
19 changes: 10 additions & 9 deletions desci-server/src/controllers/nodes/checkNodeAccess.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { ResearchObjectV1, ResearchObjectV1Dpid } from '@desci-labs/desci-models';
import { NodeCover } from '@prisma/client';
import type { Request, Response } from 'express';

import { prisma } from '../../client.js';
import { resolveNodeManifest } from '../../internal.js';
import { logger as parentLogger } from '../../logger.js';
import { decodeBase64UrlSafeToHex, ensureUuidEndsWithDot, randomUUID64 } from '../../utils.js';
import { IndexedResearchObject, getIndexedResearchObjects } from '../../theGraph.js';
import { ResearchObjectV1, ResearchObjectV1Dpid } from '@desci-labs/desci-models';
import { NodeCover } from '@prisma/client';
import { PRIV_SHARE_CONTRIBUTION_PREFIX } from '../../services/Contributors.js';
import { decodeBase64UrlSafeToHex, ensureUuidEndsWithDot, randomUUID64 } from '../../utils.js';

const logger = parentLogger.child({
module: 'NODE::checkNodeAccess',
Expand Down Expand Up @@ -44,19 +43,21 @@ type GetCheckNodeAccessErrorResponse = {
};

export const checkNodeAccess = async (
req: Request<any, any, any>,
req: Request<any, any, any, { g?: string; shareId?: string }>,
res: Response<GetCheckNodeAccessResponse | GetCheckNodeAccessErrorResponse>,
) => {
const owner = (req as any).user;
const ipfsQuery = req.query.g;
const { shareId } = req.query;

logger.info({
body: req.body,
user: (req as any).user,
ipfsQuery,
shareId,
});

let node = await prisma.node.findFirst({
const node = await prisma.node.findFirst({
select: {
uuid: true,
id: true,
Expand All @@ -78,12 +79,12 @@ export const checkNodeAccess = async (
res.status(404).send({ ok: false, message: 'Node not found' });
return;
}

const privSharedNode = owner
// debugger;
const privSharedNode = !!shareId
? await prisma.privateShare.findFirst({
where: {
memo: `${PRIV_SHARE_CONTRIBUTION_PREFIX}${owner?.email}`,
nodeUUID: node.uuid,
shareId: shareId,
},
})
: undefined;
Expand Down
4 changes: 2 additions & 2 deletions desci-server/src/services/Attestation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ export class AttestationService {
image_url: true,
},
},
desciCommunity: { select: { name: true, hidden: true } },
desciCommunity: { select: { name: true, hidden: true, image_url: true } },
},
where: {
desciCommunity: {
Expand Down Expand Up @@ -874,7 +874,7 @@ export class AttestationService {
EXISTS
(SELECT *
from "CommunityEntryAttestation" c1
where t1."attestationId" = c1."attestationId" and t1."attestationVersionId" = c1."attestationVersionId" and c1."desciCommunityId" = ${communityId})
where t1."attestationId" = c1."attestationId" and t1."attestationVersionId" = c1."attestationVersionId" and c1."desciCommunityId" = ${communityId} )
GROUP BY
t1.id
`) as CommunityRadarNode[];
Expand Down
4 changes: 2 additions & 2 deletions desci-server/src/services/Communities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export class CommunityService {
EXISTS
(SELECT *
from "CommunityEntryAttestation" c1
where t1."attestationId" = c1."attestationId" and t1."attestationVersionId" = c1."attestationVersionId" and c1."desciCommunityId" = ${communityId})
where t1."attestationId" = c1."attestationId" and t1."attestationVersionId" = c1."attestationVersionId" and c1."desciCommunityId" = ${communityId} and c1."required" = true)
GROUP BY
t1.id
`) as CommunityRadarNode[];
Expand Down Expand Up @@ -180,7 +180,7 @@ export class CommunityService {
EXISTS
(SELECT *
from "CommunityEntryAttestation" c1
where t1."attestationId" = c1."attestationId" and t1."attestationVersionId" = c1."attestationVersionId" and c1."desciCommunityId" = ${communityId})
where t1."attestationId" = c1."attestationId" and t1."attestationVersionId" = c1."attestationVersionId" and c1."desciCommunityId" = ${communityId} and c1."required" = true)
GROUP BY
t1.id
`) as CommunityRadarNode[];
Expand Down
Loading

0 comments on commit c9b02c3

Please sign in to comment.