diff --git a/packages/api/package.json b/packages/api/package.json index 0da5f742b..469586434 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -124,7 +124,7 @@ "@types/chai-as-promised": "^7.1.5", "@types/chai-string": "^1.4.2", "@types/cookie": "^0.4.0", - "@types/cookie-parser": "^1.4.2", + "@types/cookie-parser": "^1.4.7", "@types/csv-stringify": "^3.1.0", "@types/diff-match-patch": "^1.0.32", "@types/dompurify": "^2.0.4", diff --git a/packages/api/src/jobs/create_digest.ts b/packages/api/src/jobs/create_digest.ts index 1e06132c0..bab980480 100644 --- a/packages/api/src/jobs/create_digest.ts +++ b/packages/api/src/jobs/create_digest.ts @@ -1,6 +1,6 @@ import { logger } from '../utils/logger' -export const CREATE_DIGEST_JOB = 'CREATE_DIGEST_JOB' +export const CREATE_DIGEST_JOB = 'create-digest' export interface CreateDigestJobData { userId: string diff --git a/packages/api/src/queue-processor.ts b/packages/api/src/queue-processor.ts index 2670e2777..86712a67b 100644 --- a/packages/api/src/queue-processor.ts +++ b/packages/api/src/queue-processor.ts @@ -96,6 +96,9 @@ export const getBackendQueue = async (): Promise => { return backendQueue } +export const createJobId = (jobName: string, userId: string) => + `${jobName}_${userId}_${JOB_VERSION}` + export const getJob = async (jobId: string) => { const queue = await getBackendQueue() if (!queue) { diff --git a/packages/api/src/routers/digest_router.ts b/packages/api/src/routers/digest_router.ts new file mode 100644 index 000000000..b54c73ceb --- /dev/null +++ b/packages/api/src/routers/digest_router.ts @@ -0,0 +1,69 @@ +import cors from 'cors' +import express from 'express' +import { CREATE_DIGEST_JOB } from '../jobs/create_digest' +import { createJobId, getJob } from '../queue-processor' +import { findActiveUser } from '../services/user' +import { getClaimsByToken, getTokenByRequest } from '../utils/auth' +import { corsConfig } from '../utils/corsConfig' +import { enqueueCreateDigest } from '../utils/createTask' +import { logger } from '../utils/logger' + +export function digestRouter() { + const router = express.Router() + + // v1 version of create digest api + router.post( + '/v1', + cors(corsConfig), + async (req: express.Request, res) => { + const token = getTokenByRequest(req) + + let userId: string + try { + // get claims from token + const claims = await getClaimsByToken(token) + if (!claims) { + logger.info('Token not found') + return res.sendStatus(401) + } + + // get user by uid from claims + userId = claims.uid + } catch (error) { + logger.info('Error while getting claims from token', error) + return res.sendStatus(401) + } + + const user = await findActiveUser(userId) + if (!user) { + logger.info(`User not found: ${userId}`) + return res.sendStatus(401) + } + + try { + // check if job is already in queue + // if yes then return 409 conflict + // else enqueue job + const jobId = createJobId(userId, CREATE_DIGEST_JOB) + const existingJob = await getJob(jobId) + if (existingJob) { + logger.info(`Job already in queue: ${jobId}`) + return res.sendStatus(409) + } + + // enqueue job and return job id + const result = await enqueueCreateDigest({ + userId, + }) + + // return job id + return res.status(200).send(result) + } catch (error) { + logger.error('Error while enqueuing create digest task', error) + return res.sendStatus(500) + } + } + ) + + return router +} diff --git a/packages/api/src/utils/auth.ts b/packages/api/src/utils/auth.ts index 49c5fe9ff..c3269aec8 100644 --- a/packages/api/src/utils/auth.ts +++ b/packages/api/src/utils/auth.ts @@ -124,8 +124,7 @@ export const getTokenByRequest = (req: express.Request): string | undefined => { return ( req.header(OmnivoreAuthorizationHeader) || req.headers.authorization || - // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access - (req.cookies?.auth as string) + (req.cookies.auth as string | undefined) ) } diff --git a/packages/api/src/utils/createTask.ts b/packages/api/src/utils/createTask.ts index d8fd2bbf5..7a8a2d23b 100644 --- a/packages/api/src/utils/createTask.ts +++ b/packages/api/src/utils/createTask.ts @@ -49,7 +49,7 @@ import { UPDATE_HIGHLIGHT_JOB, UPDATE_LABELS_JOB, } from '../jobs/update_db' -import { getBackendQueue, JOB_VERSION } from '../queue-processor' +import { createJobId, getBackendQueue, JOB_VERSION } from '../queue-processor' import { redisDataSource } from '../redis_data_source' import { signFeatureToken } from '../services/features' import { OmnivoreAuthorizationHeader } from './auth' @@ -867,7 +867,7 @@ export const enqueueCreateDigest = async ( throw new Error('No queue found') } - const jobId = `create-digest-${data.userId}` + const jobId = createJobId(CREATE_DIGEST_JOB, data.userId) const job = await queue.add(CREATE_DIGEST_JOB, data, { jobId, // dedupe by userId removeOnComplete: true, diff --git a/yarn.lock b/yarn.lock index db12191a9..034c6ee5c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7767,10 +7767,10 @@ dependencies: "@types/node" "*" -"@types/cookie-parser@^1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.2.tgz#e4d5c5ffda82b80672a88a4281aaceefb1bd9df5" - integrity sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg== +"@types/cookie-parser@^1.4.7": + version "1.4.7" + resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.7.tgz#c874471f888c72423d78d2b3c32d1e8579cf3c8f" + integrity sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw== dependencies: "@types/express" "*"