backend: Refactor bulk delete recordings to accept recording IDs from query parameters and improve validation handling

This commit is contained in:
Carlos Santos 2025-03-21 17:26:14 +01:00
parent 831f1dce0f
commit ddbc80b0e3
2 changed files with 9 additions and 10 deletions

View File

@ -46,13 +46,14 @@ export const getRecordings = async (req: Request, res: Response) => {
export const bulkDeleteRecordings = async (req: Request, res: Response) => { export const bulkDeleteRecordings = async (req: Request, res: Response) => {
const logger = container.get(LoggerService); const logger = container.get(LoggerService);
const recordingService = container.get(RecordingService); const recordingService = container.get(RecordingService);
const recordingIds = req.body.recordingIds; const { recordingIds } = req.query;
logger.info(`Deleting recordings: ${recordingIds}`); logger.info(`Deleting recordings: ${recordingIds}`);
try { try {
// TODO: Check role to determine if the request is from an admin or a participant // TODO: Check role to determine if the request is from an admin or a participant
const { deleted, notDeleted } = await recordingService.bulkDeleteRecordings(recordingIds); const recordingIdsArray = (recordingIds as string).split(',');
const { deleted, notDeleted } = await recordingService.bulkDeleteRecordings(recordingIdsArray);
return res.status(200).json({ deleted, notDeleted }); return res.status(200).json({ deleted, notDeleted });
} catch (error) { } catch (error) {
@ -113,7 +114,7 @@ export const deleteRecording = async (req: Request, res: Response) => {
try { try {
// TODO: Check role to determine if the request is from an admin or a participant // TODO: Check role to determine if the request is from an admin or a participant
await recordingService.deleteRecording(recordingId); await recordingService.deleteRecording(recordingId);
return res.status(204); return res.status(204).send();
} catch (error) { } catch (error) {
if (error instanceof OpenViduMeetError) { if (error instanceof OpenViduMeetError) {
logger.error(`Error deleting recording: ${error.message}`); logger.error(`Error deleting recording: ${error.message}`);

View File

@ -6,7 +6,7 @@ const sanitizeId = (val: string): string => {
return val return val
.trim() // Remove leading and trailing spaces .trim() // Remove leading and trailing spaces
.replace(/\s+/g, '-') // Replace spaces with hyphens .replace(/\s+/g, '-') // Replace spaces with hyphens
.replace(/[^a-zA-Z0-9-]/g, ''); // Remove special characters (only allow alphanumeric and hyphens) .replace(/[^a-zA-Z0-9_-]/g, ''); // Remove special characters (allow alphanumeric, hyphens and underscores)
}; };
const nonEmptySanitizedString = (fieldName: string) => const nonEmptySanitizedString = (fieldName: string) =>
@ -30,8 +30,7 @@ export const BulkDeleteRecordingsSchema = z.object({
recordingIds: z.preprocess( recordingIds: z.preprocess(
(arg) => { (arg) => {
if (typeof arg === 'string') { if (typeof arg === 'string') {
// Si se recibe un string con valores separados por comas, // If the argument is a string, it is expected to be a comma-separated list of recording IDs.
// se divide en array, eliminando espacios en blanco y valores vacíos.
return arg return arg
.split(',') .split(',')
.map((s) => s.trim()) .map((s) => s.trim())
@ -41,6 +40,7 @@ export const BulkDeleteRecordingsSchema = z.object({
return arg; return arg;
}, },
z.array(nonEmptySanitizedString('recordingId')) z.array(nonEmptySanitizedString('recordingId'))
.default([])
) )
}); });
@ -69,7 +69,7 @@ export const withValidStartRecordingRequest = (req: Request, res: Response, next
}; };
export const withValidRecordingIdRequest = (req: Request, res: Response, next: NextFunction) => { export const withValidRecordingIdRequest = (req: Request, res: Response, next: NextFunction) => {
const { success, error, data } = GetRecordingSchema.safeParse(req.params.recordingId); const { success, error, data } = GetRecordingSchema.safeParse({ recordingId: req.params.recordingId });
if (!success) { if (!success) {
return rejectRequest(res, error); return rejectRequest(res, error);
@ -101,7 +101,7 @@ export const withValidRecordingBulkDeleteRequest = (req: Request, res: Response,
return rejectRequest(res, error); return rejectRequest(res, error);
} }
req.query.recordingIds = data.recordingIds; req.query.recordingIds = data.recordingIds.join(',');
next(); next();
}; };
@ -112,8 +112,6 @@ const rejectRequest = (res: Response, error: z.ZodError) => {
message: error.message message: error.message
})); }));
console.log(errors);
return res.status(422).json({ return res.status(422).json({
error: 'Unprocessable Entity', error: 'Unprocessable Entity',
message: 'Invalid request body', message: 'Invalid request body',