diff --git a/packages/api/src/elastic/recommendation.ts b/packages/api/src/elastic/recommendation.ts index 3f2aaccce..511b3fae1 100644 --- a/packages/api/src/elastic/recommendation.ts +++ b/packages/api/src/elastic/recommendation.ts @@ -7,13 +7,16 @@ export const addRecommendation = async ( recommendation: Recommendation ): Promise => { try { - const userId = ctx.uid // check if the page is already recommended to the group const existingPage = await getPageByParam({ - userId, + userId: ctx.uid, url: page.url, }) if (existingPage) { + if (existingPage.recommendedBy?.includes(recommendation)) { + return existingPage._id + } + // update recommendedBy in the existing page const recommendedBy = (existingPage.recommendedBy || []).concat( recommendation @@ -30,10 +33,17 @@ export const addRecommendation = async ( } // create a new page - const newPage = { + const newPage: Page = { ...page, + id: '', recommendedBy: [recommendation], - userId, + userId: ctx.uid, + readingProgressPercent: 0, + readingProgressAnchorIndex: 0, + sharedAt: new Date(), + highlights: [], + readAt: undefined, + labels: [], } return createPage(newPage, ctx) diff --git a/packages/api/src/resolvers/recommendations/index.ts b/packages/api/src/resolvers/recommendations/index.ts index cd74fadbb..9e92501e6 100644 --- a/packages/api/src/resolvers/recommendations/index.ts +++ b/packages/api/src/resolvers/recommendations/index.ts @@ -23,6 +23,7 @@ import { Group } from '../../entity/groups/group' import { In } from 'typeorm' import { getPageByParam } from '../../elastic/pages' import { enqueueRecommendation } from '../../utils/createTask' +import { env } from '../../env' export const createGroupResolver = authorized< CreateGroupSuccess, @@ -129,7 +130,7 @@ export const recommendResolver = authorized< RecommendSuccess, RecommendError, MutationRecommendArgs ->(async (_, { input }, { claims: { uid }, log }) => { +>(async (_, { input }, { claims: { uid }, log, signToken }) => { log.info('Recommend', { input, labels: { @@ -151,6 +152,7 @@ export const recommendResolver = authorized< const groups = await getRepository(Group).find({ where: { id: In(input.groupIds) }, + relations: ['members', 'members.user'], }) if (groups.length === 0) { return { @@ -165,16 +167,23 @@ export const recommendResolver = authorized< } } + const exp = Math.floor(Date.now() / 1000) + 60 * 60 * 24 // 1 day + const auth = (await signToken({ uid, exp }, env.server.jwtSecret)) as string const taskNames = await Promise.all( groups .map((group) => group.members - .filter((member) => member.id !== uid) + .filter((member) => member.user.id !== uid) .map((member) => - enqueueRecommendation(member.id, page.id, { - ...group, - recommendedAt: new Date(), - }) + enqueueRecommendation( + member.user.id, + page.id, + { + ...group, + recommendedAt: new Date(), + }, + auth + ) ) ) .flat() diff --git a/packages/api/src/routers/page_router.ts b/packages/api/src/routers/page_router.ts index 6edb936a6..da74925fc 100644 --- a/packages/api/src/routers/page_router.ts +++ b/packages/api/src/routers/page_router.ts @@ -163,21 +163,17 @@ export function pageRouter() { } const claims = jwt.decode(token) as Claims - const { - userId: recommendedUserId, - pageId, - recommendation, - } = req.body as { + const { userId, pageId, recommendation } = req.body as { userId: string pageId: string recommendation: Recommendation } - if (!recommendedUserId || !pageId || !recommendation) { + if (!userId || !pageId || !recommendation) { return res.status(400).send({ errorCode: 'BAD_DATA' }) } const ctx = { - uid: recommendedUserId, + uid: userId, pubsub: createPubSubClient(), } diff --git a/packages/api/src/utils/createTask.ts b/packages/api/src/utils/createTask.ts index 562a0e854..66ade68e5 100644 --- a/packages/api/src/utils/createTask.ts +++ b/packages/api/src/utils/createTask.ts @@ -27,6 +27,7 @@ const createHttpTaskWithToken = async ({ payload, priority = 'high', scheduleTime, + requestHeaders, }: { project: string queue?: string @@ -36,6 +37,7 @@ const createHttpTaskWithToken = async ({ payload: unknown priority?: 'low' | 'high' scheduleTime?: number + requestHeaders?: Record }): Promise< [ protos.google.cloud.tasks.v2.ITask, @@ -71,6 +73,7 @@ const createHttpTaskWithToken = async ({ url: taskHandlerUrl, headers: { 'Content-Type': 'application/json', + ...requestHeaders, }, body, ...(serviceAccountEmail @@ -409,7 +412,8 @@ export const enqueueTextToSpeech = async ({ export const enqueueRecommendation = async ( userId: string, pageId: string, - recommendation: Recommendation + recommendation: Recommendation, + authToken: string ): Promise => { const { GOOGLE_CLOUD_PROJECT } = process.env const payload = { @@ -418,15 +422,29 @@ export const enqueueRecommendation = async ( recommendation, } + const headers = { + Authorization: authToken, + } // If there is no Google Cloud Project Id exposed, it means that we are in local environment if (env.dev.isLocal || !GOOGLE_CLOUD_PROJECT) { - return nanoid() + // Calling the handler function directly. + setTimeout(() => { + axios + .post(env.queue.recommendationTaskHandlerUrl, payload, { + headers, + }) + .catch((error) => { + logger.error(error) + }) + }, 0) + return '' } const createdTasks = await createHttpTaskWithToken({ project: GOOGLE_CLOUD_PROJECT, payload, taskHandlerUrl: env.queue.recommendationTaskHandlerUrl, + requestHeaders: headers, }) if (!createdTasks || !createdTasks[0].name) {