From 1e381f4517c54db12b0abf6fba6c02fa5b88a77d Mon Sep 17 00:00:00 2001 From: JustMichael Date: Sat, 30 Mar 2024 19:55:58 +0000 Subject: [PATCH] fix(requests): adding a request would fail due to failed query --- pkg/api/src/api/routes/request.ts | 54 ++++++++-------- pkg/api/src/services/requests/display.ts | 82 ++++++++++++------------ pkg/api/src/services/requests/process.ts | 71 +++++++++++--------- 3 files changed, 110 insertions(+), 97 deletions(-) diff --git a/pkg/api/src/api/routes/request.ts b/pkg/api/src/api/routes/request.ts index 748c79852..648e6e6de 100644 --- a/pkg/api/src/api/routes/request.ts +++ b/pkg/api/src/api/routes/request.ts @@ -66,8 +66,10 @@ const getRequestMinified = async (ctx: Context) => { }), ); } catch (err) { - logger.log('error', `ROUTE: Error getting requests`); - logger.log({ level: 'error', message: err }); + logger.error(`ROUTE: Error getting requests`, err); + ctx.status = StatusCodes.INTERNAL_SERVER_ERROR; + ctx.body = {}; + return; } ctx.status = StatusCodes.OK; @@ -75,20 +77,24 @@ const getRequestMinified = async (ctx: Context) => { }; const addRequest = async (ctx: Context) => { - const {body} = ctx.request; + const { body } = ctx.request; + const { request } = body; - const {request} = body; - const process = await new ProcessRequest(request, ctx.state.user).new(); - - ctx.status = StatusCodes.OK; - ctx.body = process; + try { + ctx.status = StatusCodes.OK; + ctx.body = await new ProcessRequest(request, ctx.state.user).new(); + } catch (err) { + logger.error(`ROUTE: Error adding request`, err); + ctx.status = StatusCodes.INTERNAL_SERVER_ERROR; + ctx.body = {}; + } }; const removeRequest = async (ctx: Context) => { - const {body} = ctx.request; + const { body } = ctx.request; - const {request} = body; - const {reason} = body; + const { request } = body; + const { reason } = body; const process = new ProcessRequest(request, ctx.state.user); await process.archive(false, true, reason); @@ -112,14 +118,11 @@ const removeRequest = async (ctx: Context) => { }), ); new Mailer().mail( - `Your request was ${request.approved ? 'removed' : 'denied'} for ${ - request.title + `Your request was ${request.approved ? 'removed' : 'denied'} for ${request.title }`, - `Your request was ${request.approved ? 'removed' : 'denied'} for ${ - request.title + `Your request was ${request.approved ? 'removed' : 'denied'} for ${request.title }`, - `Unfortunately your request could not be processed.${ - reason ? ` This is because - ${reason}.` : '' + `Unfortunately your request could not be processed.${reason ? ` This is because - ${reason}.` : '' } Thanks for your request anyway!`, `https://image.tmdb.org/t/p/w500${request.thumb}`, emails, @@ -131,12 +134,12 @@ const removeRequest = async (ctx: Context) => { }; const updateRequest = async (ctx: Context) => { - const {body} = ctx.request; + const { body } = ctx.request; - const {request} = body; - const {servers} = body; - const {approved} = body.request; - const {manualStatus} = body.request; + const { request } = body; + const { servers } = body; + const { approved } = body.request; + const { manualStatus } = body.request; if (manualStatus === '5') { new ProcessRequest(request, ctx.state.user).archive(true, false, false); @@ -207,8 +210,7 @@ const updateRequest = async (ctx: Context) => { ctx.status = StatusCodes.OK; ctx.body = {}; } catch (err) { - logger.log('error', `ROUTE: Error updating requests`); - logger.log({ level: 'error', message: err }); + logger.error(`ROUTE: Error updating requests`, err); ctx.status = StatusCodes.INTERNAL_SERVER_ERROR; ctx.body = {}; @@ -216,7 +218,7 @@ const updateRequest = async (ctx: Context) => { }; const getArchivedRequestById = async (ctx: Context) => { - const {id} = ctx.params; + const { id } = ctx.params; ctx.status = StatusCodes.OK; ctx.body = await getArchive(id); @@ -234,4 +236,4 @@ export default (app: Router) => { app.use(routes.routes()); app.use(routes.allowedMethods()); -}; \ No newline at end of file +}; diff --git a/pkg/api/src/services/requests/display.ts b/pkg/api/src/services/requests/display.ts index 8994a9da8..259be078d 100644 --- a/pkg/api/src/services/requests/display.ts +++ b/pkg/api/src/services/requests/display.ts @@ -35,7 +35,7 @@ export const getRequests = async (user = false, all = false) => { if (request.type === 'movie' && request.radarrId.length > 0) { for (let i = 0; i < Object.keys(request.radarrId).length; i++) { const radarrIds = request.radarrId[i]; - const rId = parseInt(radarrIds[Object.keys(radarrIds)[0]]); + const rId = parseInt(radarrIds[Object.keys(radarrIds)[0]], 10); const serverUuid = Object.keys(radarrIds)[0]; const instance = instances.find((i) => i.id === serverUuid); @@ -66,7 +66,7 @@ export const getRequests = async (user = false, all = false) => { if (request.type === 'tv' && request.sonarrId.length > 0) { for (let i = 0; i < Object.keys(request.sonarrId).length; i++) { const sonarrIds = request.sonarrId[i]; - const sId = parseInt(sonarrIds[Object.keys(sonarrIds)[0]]); + const sId = parseInt(sonarrIds[Object.keys(sonarrIds)[0]], 10); const serverUuid = Object.keys(sonarrIds)[0]; const instance = instances.find((i) => i.id === serverUuid); @@ -207,30 +207,30 @@ function reqState(req, children) { step: 4, }; } - const airDate = element.info.firstAired; - if (!airDate) - return { - status: 'blue', - message: 'Awaiting Info', - step: 3, - }; - diff = Math.ceil( - new Date(airDate).getTime() - new Date().getTime(), - ); - if (diff > 0) { - return { - status: 'blue', - message: `${calcDate(diff)}`, - step: 3, - }; - } - if (element.info.episodeFileCount > 0) { - return { - status: 'blue', - message: 'Partially Downloaded', - step: 3, - }; - } + const airDate = element.info.firstAired; + if (!airDate) + return { + status: 'blue', + message: 'Awaiting Info', + step: 3, + }; + diff = Math.ceil( + new Date(airDate).getTime() - new Date().getTime(), + ); + if (diff > 0) { + return { + status: 'blue', + message: `${calcDate(diff)}`, + step: 3, + }; + } + if (element.info.episodeFileCount > 0) { + return { + status: 'blue', + message: 'Partially Downloaded', + step: 3, + }; + } } @@ -241,7 +241,7 @@ function reqState(req, children) { if (element.info.inCinemas) { diff = Math.ceil( new Date(element.info.inCinemas).getTime() - - new Date().getTime(), + new Date().getTime(), ); if (diff > 0) { return { @@ -261,18 +261,18 @@ function reqState(req, children) { }; } } else if (element.info.inCinemas) { - diff = Math.ceil( - new Date().getTime() - - new Date(element.info.inCinemas).getTime(), - ); - if (cinemaWindow(diff)) { - return { - status: 'cinema', - message: 'In Cinemas', - step: 3, - }; - } + diff = Math.ceil( + new Date().getTime() - + new Date(element.info.inCinemas).getTime(), + ); + if (cinemaWindow(diff)) { + return { + status: 'cinema', + message: 'In Cinemas', + step: 3, + }; } + } } if (element.info.status === 'announced') { @@ -332,9 +332,9 @@ function calcDate(diff) { months -= years * 12; let message = '~'; - message += years ? `${years }y ` : ''; - message += months ? `${months }m ` : ''; - message += days ? `${days }d` : ''; + message += years ? `${years}y ` : ''; + message += months ? `${months}m ` : ''; + message += days ? `${days}d` : ''; if (years) message = '> 1y'; return message; diff --git a/pkg/api/src/services/requests/process.ts b/pkg/api/src/services/requests/process.ts index ee2dbab88..aab7243a3 100644 --- a/pkg/api/src/services/requests/process.ts +++ b/pkg/api/src/services/requests/process.ts @@ -73,7 +73,7 @@ export default class ProcessRequest { return out; } - async existing() { + async existing(): Promise<{ message: string; user: string; request: any; } | undefined> { if (!this.user) { throw new Error('user required'); } @@ -99,6 +99,7 @@ export default class ProcessRequest { } if (this.request.type === 'tv') { const existingSeasons = requestDb.seasons || {}; + // eslint-disable-next-line no-restricted-syntax for (const [k, _v] of this.request.seasons) { existingSeasons[k] = true; } @@ -130,11 +131,15 @@ export default class ProcessRequest { const profile = this.user.profileId ? await Profile.findById(this.user.profileId).exec() : false; - let autoApprove = profile - ? this.request.type === 'movie' - ? profile.autoApprove - : profile.autoApproveTv - : false; + let autoApprove = false; + + if (profile) { + if (this.request.type === 'movie') { + autoApprove = profile.autoApprove ?? false; + } else { + autoApprove = profile.autoApproveTv ?? false; + } + } if (this.user.role === UserRole.Admin) { autoApprove = true; @@ -200,38 +205,41 @@ export default class ProcessRequest { 'REQ: Pending Request Matched on custom filter, setting default', { label: 'requests.process' }, ); + // eslint-disable-next-line no-restricted-syntax for (const [k, _v] of filterMatch) { - const filter = filterMatch[k]; - pending[filter.server] = { - path: filter.path, - profile: filter.profile, - tag: filter.tag, + const matchedFilter = filterMatch[k]; + pending[matchedFilter.server] = { + path: matchedFilter.path, + profile: matchedFilter.profile, + tag: matchedFilter.tag, }; } } else if (this.request.type === 'movie') { const instances = await GetAllDownloaders(DownloaderType.Radarr); + // eslint-disable-next-line no-restricted-syntax for (const instance of instances) { if (!instance.id) { - continue; + return; } if (profile.radarr && profile.radarr[instance.id]) { pending[instance.id] = { - path: instance.path.location, - profile: instance.profile.name, + path: instance.path, + profile: instance.profile, tag: false, }; } } } else { const instances = await GetAllDownloaders(DownloaderType.Sonarr); + // eslint-disable-next-line no-restricted-syntax for (const instance of instances) { if (!instance.id) { - continue; + return; } if (profile.sonarr && profile.sonarr[instance.id]) { pending[instance.id] = { - path: instance.path.location, - profile: instance.profile.name, + path: instance.path, + profile: instance.profile, tag: false, }; } @@ -264,19 +272,21 @@ export default class ProcessRequest { ); logger.debug('REQ: Sending to DVR', { label: 'requests.process' }); if (this.request.type === 'movie') { + // eslint-disable-next-line no-restricted-syntax for (const match of filterMatch) { const instance = instances.find((i) => i.id === match.server); if (!instance) { - continue; + return; } new Radarr(instance).manualAdd(this.request, match); } } else { + // eslint-disable-next-line no-restricted-syntax for (const match of filterMatch) { const instance = instances.find((i) => i.id === match.server); if (!instance) { - continue; + return; } new Sonarr(instance).addShow({ id: match.server }, this.request); @@ -288,24 +298,26 @@ export default class ProcessRequest { // If profile is set use arrs from profile if (profile) { if (profile.radarr && this.request.type === 'movie') { + // eslint-disable-next-line no-restricted-syntax for (const [k, _v] of profile.radarr) { const active = profile.radarr[k]; if (active) { const instance = instances.find((i) => i.id === k); if (!instance) { - continue; + return; } new Radarr(instance).processRequest(this.request.id); } } } if (profile.sonarr && this.request.type === 'tv') { + // eslint-disable-next-line no-restricted-syntax for (const [k, _v] of profile.sonarr) { const active = profile.sonarr[k]; if (active) { const instance = instances.find((i) => i.id === k); if (!instance) { - continue; + return; } new Sonarr(instance).addShow({ id: k }, this.request); } @@ -318,6 +330,7 @@ export default class ProcessRequest { const sonarrs = instances.filter( (i) => i.type === DownloaderType.Sonarr, ); + // eslint-disable-next-line no-restricted-syntax for (const instance of sonarrs) { new Sonarr(instance).addShow(false, this.request); } @@ -326,6 +339,7 @@ export default class ProcessRequest { const radarrs = instances.filter( (i) => i.type === DownloaderType.Radarr, ); + // eslint-disable-next-line no-restricted-syntax for (const instance of radarrs) { new Radarr(instance).processRequest(this.request.id); } @@ -337,14 +351,14 @@ export default class ProcessRequest { if (this.request) { const instances = await GetAllDownloaders(); if (this.request.radarrId.length > 0 && this.request.type === 'movie') { - for (let i = 0; i < Object.keys(this.request.radarrId).length; i++) { + for (let i = 0; i < Object.keys(this.request.radarrId).length; i += 1) { const radarrIds = this.request.radarrId[i]; const rId = radarrIds[Object.keys(radarrIds)[0]]; const serverUuid = Object.keys(radarrIds)[0]; - const instance = instances.find((i) => i.id === serverUuid); + const instance = instances.find((j) => j.id === serverUuid); if (!instance) { - continue; + return; } const server = new Radarr(instance); @@ -363,7 +377,7 @@ export default class ProcessRequest { } } if (this.request.sonarrId.length > 0 && this.request.type === 'tv') { - for (let i = 0; i < Object.keys(this.request.sonarrId).length; i++) { + for (let i = 0; i < Object.keys(this.request.sonarrId).length; i += 1) { const sonarrIds = this.request.sonarrId[i]; const sId = sonarrIds[Object.keys(sonarrIds)[0]]; const serverUuid = Object.keys(sonarrIds)[0]; @@ -431,10 +445,7 @@ export default class ProcessRequest { throw new Error('user required'); } - const user = await UserModel.findOne({ - id: this.user.id, - }); - + const user = await UserModel.findById(this.user.id); if (!user) throw new Error('user required'); if (user.role === UserRole.Admin) return 'admin'; @@ -482,7 +493,7 @@ export default class ProcessRequest { { useFindAndModify: false }, ) .exec() - .then((_data) => { + .then(() => { logger.debug(`REQ: Request ${oldReq.title} Archived!`, { label: 'requests.process', });