Files
channels-seerr/server/routes/blocklist.ts
Conlan Kreher 33a5d9a9ac refactor: rename blacklist to blocklist (#2157)
Signed-off-by: 0xsysr3ll <0xsysr3ll@pm.me>
Co-authored-by: fallenbagel <98979876+Fallenbagel@users.noreply.github.com>
Co-authored-by: 0xsysr3ll <0xsysr3ll@pm.me>
Co-authored-by: gauthier-th <mail@gauthierth.fr>
2026-02-14 14:31:45 +01:00

187 lines
5.0 KiB
TypeScript

import { MediaType } from '@server/constants/media';
import { getRepository } from '@server/datasource';
import { Blocklist } from '@server/entity/Blocklist';
import Media from '@server/entity/Media';
import type { BlocklistResultsResponse } from '@server/interfaces/api/blocklistInterfaces';
import { Permission } from '@server/lib/permissions';
import logger from '@server/logger';
import { isAuthenticated } from '@server/middleware/auth';
import { Router } from 'express';
import { EntityNotFoundError, QueryFailedError } from 'typeorm';
import { z } from 'zod';
const blocklistRoutes = Router();
export const blocklistAdd = z.object({
tmdbId: z.coerce.number(),
mediaType: z.nativeEnum(MediaType),
title: z.coerce.string().optional(),
user: z.coerce.number(),
});
const blocklistGet = z.object({
take: z.coerce.number().int().positive().default(25),
skip: z.coerce.number().int().nonnegative().default(0),
search: z.string().optional(),
filter: z.enum(['all', 'manual', 'blocklistedTags']).optional(),
});
blocklistRoutes.get(
'/',
isAuthenticated([Permission.MANAGE_BLOCKLIST, Permission.VIEW_BLOCKLIST], {
type: 'or',
}),
async (req, res, next) => {
const { take, skip, search, filter } = blocklistGet.parse(req.query);
try {
let query = getRepository(Blocklist)
.createQueryBuilder('blocklist')
.leftJoinAndSelect('blocklist.user', 'user')
.where('1 = 1'); // Allow use of andWhere later
switch (filter) {
case 'manual':
query = query.andWhere('blocklist.blocklistedTags IS NULL');
break;
case 'blocklistedTags':
query = query.andWhere('blocklist.blocklistedTags IS NOT NULL');
break;
}
if (search) {
query = query.andWhere('blocklist.title like :title', {
title: `%${search}%`,
});
}
const [blocklistedItems, itemsCount] = await query
.orderBy('blocklist.createdAt', 'DESC')
.take(take)
.skip(skip)
.getManyAndCount();
return res.status(200).json({
pageInfo: {
pages: Math.ceil(itemsCount / take),
pageSize: take,
results: itemsCount,
page: Math.ceil(skip / take) + 1,
},
results: blocklistedItems,
} as BlocklistResultsResponse);
} catch (error) {
logger.error('Something went wrong while retrieving blocklisted items', {
label: 'Blocklist',
errorMessage: error.message,
});
return next({
status: 500,
message: 'Unable to retrieve blocklisted items.',
});
}
}
);
blocklistRoutes.get(
'/:id',
isAuthenticated([Permission.MANAGE_BLOCKLIST], {
type: 'or',
}),
async (req, res, next) => {
try {
const blocklisteRepository = getRepository(Blocklist);
const blocklistItem = await blocklisteRepository.findOneOrFail({
where: { tmdbId: Number(req.params.id) },
});
return res.status(200).send(blocklistItem);
} catch (e) {
if (e instanceof EntityNotFoundError) {
return next({
status: 401,
message: e.message,
});
}
return next({ status: 500, message: e.message });
}
}
);
blocklistRoutes.post(
'/',
isAuthenticated([Permission.MANAGE_BLOCKLIST], {
type: 'or',
}),
async (req, res, next) => {
try {
const values = blocklistAdd.parse(req.body);
await Blocklist.addToBlocklist({
blocklistRequest: values,
});
return res.status(201).send();
} catch (error) {
if (!(error instanceof Error)) {
return;
}
if (error instanceof QueryFailedError) {
switch (error.driverError.errno) {
case 19:
return next({ status: 412, message: 'Item already blocklisted' });
default:
logger.warn('Something wrong with data blocklist', {
tmdbId: req.body.tmdbId,
mediaType: req.body.mediaType,
label: 'Blocklist',
});
return next({ status: 409, message: 'Something wrong' });
}
}
return next({ status: 500, message: error.message });
}
}
);
blocklistRoutes.delete(
'/:id',
isAuthenticated([Permission.MANAGE_BLOCKLIST], {
type: 'or',
}),
async (req, res, next) => {
try {
const blocklisteRepository = getRepository(Blocklist);
const blocklistItem = await blocklisteRepository.findOneOrFail({
where: { tmdbId: Number(req.params.id) },
});
await blocklisteRepository.remove(blocklistItem);
const mediaRepository = getRepository(Media);
const mediaItem = await mediaRepository.findOneOrFail({
where: { tmdbId: Number(req.params.id) },
});
await mediaRepository.remove(mediaItem);
return res.status(204).send();
} catch (e) {
if (e instanceof EntityNotFoundError) {
return next({
status: 401,
message: e.message,
});
}
return next({ status: 500, message: e.message });
}
}
);
export default blocklistRoutes;