Skip to content

Commit

Permalink
update radar and feed apis with new impl
Browse files Browse the repository at this point in the history
  • Loading branch information
shadrach-tayo committed Jan 9, 2025
1 parent 540bf90 commit 6b14995
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 17 deletions.
36 changes: 35 additions & 1 deletion desci-server/src/controllers/communities/feed.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { NextFunction, Request, Response } from 'express';
import _ from 'lodash';
import z from 'zod';

import { NotFoundError } from '../../core/ApiError.js';
import { SuccessResponse } from '../../core/ApiResponse.js';
import { logger as parentLogger } from '../../logger.js';
import { getCommunityFeedSchema } from '../../routes/v1/communities/schema.js';
import { attestationService } from '../../services/Attestation.js';
import { communityService } from '../../services/Communities.js';
import { asyncMap } from '../../utils.js';

import { resolveLatestNode } from './util.js';
import { getCommunityNodeDetails, resolveLatestNode } from './util.js';

const logger = parentLogger.child({ module: 'communities/feed.ts' });

Expand Down Expand Up @@ -46,6 +48,38 @@ export const getCommunityFeed = async (req: Request, res: Response, next: NextFu
return new SuccessResponse(data).send(res);
};

export const listCommunityFeed = async (req: Request, res: Response, next: NextFunction) => {
const { query, params } = await getCommunityFeedSchema.parseAsync(req);
const limit = 20;
const page = Math.max(Math.max((query.cursor ?? 0) - 1, 0), 0);
const offset = limit * page;

const curatedNodes = await communityService.listCommunityCuratedFeed({
communityId: parseInt(params.communityId.toString()),
offset,
limit,
});
logger.trace({ offset, page, cursor: query.cursor }, 'Feed');
// THIS is necessary because the engagement signal returned from getcuratedNodes
// accounts for only engagements on community selected attestations
const entries = await asyncMap(curatedNodes, async (entry) => {
const engagements = await attestationService.getNodeEngagementSignalsByUuid(entry.nodeUuid);
return {
...entry,
engagements,
verifiedEngagements: {
reactions: entry.reactions,
annotations: entry.annotations,
verifications: entry.verifications,
},
};
});

const data = await Promise.all(entries.map(getCommunityNodeDetails));
// logger.info({ count: data.length, page: offset }, 'listCommunityFeed');
return new SuccessResponse({ count: data.length, cursor: page + 1, data }).send(res);
};

export const getCommunityDetails = async (req: Request, res: Response, next: NextFunction) => {
const community = await communityService.findCommunityByNameOrSlug(req.params.communityName as string);

Expand Down
25 changes: 15 additions & 10 deletions desci-server/src/controllers/communities/radar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import _ from 'lodash';

import { SuccessResponse } from '../../core/ApiResponse.js';
import { logger as parentLogger } from '../../logger.js';
import { getCommunityFeedSchema } from '../../routes/v1/communities/schema.js';
import { attestationService } from '../../services/Attestation.js';
import { communityService } from '../../services/Communities.js';
import { asyncMap } from '../../utils.js';

import { resolveLatestNode } from './util.js';
import { getCommunityNodeDetails, resolveLatestNode } from './util.js';

const logger = parentLogger.child({ module: 'GET COMMUNITY RADAR' });
export const getCommunityRadar = async (req: Request, res: Response, next: NextFunction) => {
Expand Down Expand Up @@ -62,15 +63,20 @@ export const getCommunityRadar = async (req: Request, res: Response, next: NextF
};

export const listCommunityRadar = async (req: Request, res: Response, next: NextFunction) => {
const { query, params } = await getCommunityFeedSchema.parseAsync(req);
const limit = 20;
const page = Math.max(Math.max((query.cursor ?? 0) - 1, 0), 0);
const offset = limit * page;

const communityRadar = await communityService.listCommunityRadar({
communityId: parseInt(req.params.communityId as string),
offset: 0,
limit: 20,
communityId: parseInt(params.communityId.toString()),
offset,
limit,
});
logger.info({ communityRadar }, 'Radar');
logger.trace({ offset, page, cursor: query.cursor }, 'Radar');
// THIS is necessary because the engagement signal returned from getCommunityRadar
// accounts for only engagements on community selected attestations
const nodes = await asyncMap(communityRadar, async (entry) => {
const entries = await asyncMap(communityRadar, async (entry) => {
const engagements = await attestationService.getNodeEngagementSignalsByUuid(entry.nodeUuid);
return {
...entry,
Expand All @@ -84,8 +90,7 @@ export const listCommunityRadar = async (req: Request, res: Response, next: Next
});

// rank nodes by sum of sum of verified and non verified signals

logger.info({ nodes }, 'CHECK Verification SignalS');

return new SuccessResponse(nodes).send(res);
const data = await Promise.all(entries.map(getCommunityNodeDetails));
// logger.trace({ count: data.length }, 'listCommunityRadar');
return new SuccessResponse({ count: data.length, cursor: page + 1, data }).send(res);
};
4 changes: 3 additions & 1 deletion desci-server/src/controllers/communities/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ResearchObjectV1 } from '@desci-labs/desci-models';
import { Node } from '@prisma/client';

import { CommunityRadarNode } from '../../services/Communities.js';
import { CommunityRadarNode, RadarEntry } from '../../services/Communities.js';

export type NodeRadarItem = {
NodeAttestation: CommunityRadarNode[];
Expand Down Expand Up @@ -46,3 +46,5 @@ export type NodeRadar = NodeRadarItem & {
verifications: number;
};
};

export type NodeRadarEntry = RadarEntry & { node?: Partial<Node & { versions: number }>; manifest?: ResearchObjectV1 };
60 changes: 60 additions & 0 deletions desci-server/src/controllers/communities/util.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { ResearchObjectV1 } from '@desci-labs/desci-models';
import { Node, NodeVersion } from '@prisma/client';
import axios from 'axios';
import _ from 'lodash';

import { prisma } from '../../client.js';
import { logger } from '../../logger.js';
import { RadarEntry } from '../../services/Communities.js';
import { NodeUuid } from '../../services/manifestRepo.js';
import repoService from '../../services/repoService.js';
import { IndexedResearchObject, getIndexedResearchObjects } from '../../theGraph.js';
Expand Down Expand Up @@ -68,6 +70,64 @@ export const resolveLatestNode = async (radar: Partial<NodeRadar>) => {
return radar;
};

export const getCommunityNodeDetails = async (
radar: RadarEntry & { node?: Partial<Node & { versions: number }>; manifest?: ResearchObjectV1 },
) => {
const uuid = ensureUuidEndsWithDot(radar.nodeUuid);

const discovery = await prisma.node.findFirst({
where: {
uuid,
isDeleted: false,
},
select: {
id: true,
manifestUrl: true,
ownerId: true,
uuid: true,
title: true,
NodeCover: true,
},
});

if (!discovery) {
logger.warn({ uuid }, 'uuid not found');
}

const selectAttributes: (keyof typeof discovery)[] = ['ownerId', 'NodeCover'];
const node: Partial<Node & { versions: number }> = _.pick(discovery, selectAttributes);
const publishedVersions =
(await prisma.$queryRaw`SELECT * from "NodeVersion" where "nodeId" = ${discovery.id} AND ("transactionId" IS NOT NULL or "commitId" IS NOT NULL) ORDER BY "createdAt" DESC`) as NodeVersion[];

// const nodeVersions = (await getNodeVersion
logger.info({ uuid: discovery.uuid, publishedVersions }, 'Resolve node');
node['versions'] = publishedVersions.length;
node['publishedDate'] = publishedVersions[0].createdAt;
node.manifestUrl = publishedVersions[0].manifestUrl;
radar.node = node;

let gatewayUrl = publishedVersions[0].manifestUrl;

try {
gatewayUrl = cleanupManifestUrl(gatewayUrl);
// logger.trace({ gatewayUrl, uuid }, 'transforming manifest');
const manifest = (await axios.get(gatewayUrl)).data;
radar.manifest = manifest;

// logger.info({ manifest }, '[SHOW API GET LAST PUBLISHED MANIFEST]');
} catch (err) {
const manifest = await repoService.getDraftManifest({
uuid: node.uuid as NodeUuid,
documentId: node.manifestDocumentId,
});
radar.manifest = manifest;
logger.error({ err, manifestUrl: discovery.manifestUrl, gatewayUrl }, 'nodes/show.ts: failed to preload manifest');
}

radar.node = { ...radar.node, ...node };
return radar;
};

export const getNodeVersion = async (uuid: string) => {
let indexingResults: { researchObjects: IndexedResearchObject[] };
try {
Expand Down
16 changes: 12 additions & 4 deletions desci-server/src/routes/v1/communities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import {
getCommunityRecommendations,
getValidatedAttestations,
} from '../../../controllers/attestations/recommendations.js';
import { getAllFeeds, getCommunityDetails, getCommunityFeed } from '../../../controllers/communities/feed.js';
import {
getAllFeeds,
getCommunityDetails,
getCommunityFeed,
listCommunityFeed,
} from '../../../controllers/communities/feed.js';
import { checkMemberGuard } from '../../../controllers/communities/guard.js';
import { listCommunities } from '../../../controllers/communities/list.js';
import { getCommunityRadar } from '../../../controllers/communities/radar.js';
import { getCommunityRadar, listCommunityRadar } from '../../../controllers/communities/radar.js';
import { ensureUser } from '../../../middleware/permissions.js';
import { validate } from '../../../middleware/validator.js';
import { asyncHandler } from '../../../utils/asyncHandler.js';
Expand All @@ -32,8 +37,11 @@ router.get(
asyncHandler(getValidatedAttestations),
);

router.get('/:communityId/feed', [validate(getCommunityFeedSchema)], asyncHandler(getCommunityFeed));
router.get('/:communityId/radar', [validate(getCommunityFeedSchema)], asyncHandler(getCommunityRadar));
// router.get('/:communityId/feed', [validate(getCommunityFeedSchema)], asyncHandler(getCommunityFeed));
// router.get('/:communityId/radar', [validate(getCommunityFeedSchema)], asyncHandler(getCommunityRadar));

router.get('/:communityId/feed', [validate(getCommunityFeedSchema)], asyncHandler(listCommunityFeed));
router.get('/:communityId/radar', [validate(getCommunityFeedSchema)], asyncHandler(listCommunityRadar));

router.post('/:communityId/memberGuard', [ensureUser, validate(memberGuardSchema)], asyncHandler(checkMemberGuard));

Expand Down
3 changes: 3 additions & 0 deletions desci-server/src/routes/v1/communities/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export const getCommunityFeedSchema = z.object({
params: z.object({
communityId: z.coerce.number(),
}),
query: z.object({
cursor: z.coerce.number().optional().default(0),
}),
});

export const memberGuardSchema = z.object({
Expand Down
2 changes: 1 addition & 1 deletion desci-server/src/services/Communities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ export class CommunityService {
verifications ASC,
cre."createdAt" DESC
LIMIT
${limit};
${limit}
OFFSET ${offset};
`;

Expand Down

0 comments on commit 6b14995

Please sign in to comment.