/** * Checks the playlist request bodies, for the playlist routes to answer a 400. * * @module */ import type { CreatePlaylistRequest, ReorderPlaylistRequest, UpdatePlaylistRequest, } from "../../shared/playlist.ts"; import { VALIDATION } from "../../shared/validation.ts"; /** Checks that `categoryIds`, when `o` has it, is a list of strings. */ function hasValidCategoryIds(o: Record): boolean { return !("categoryIds" in o) || (Array.isArray(o.categoryIds) && o.categoryIds.every((id) => typeof id === "string")); } /** Checks that `title` isn't blank and, trimmed, fits the limit. */ function isValidTitle(title: string): boolean { const trimmed = title.trim(); return trimmed.length > 0 && trimmed.length <= VALIDATION.PLAYLIST_TITLE_MAX; } /** * Checks whether `obj` is a {@link CreatePlaylistRequest} with a title that * isn't blank, and a title and description within the `VALIDATION` limits. A * null description passes. Whether its category ids name playlist categories * is the playlist service's to check. */ export function isCreatePlaylistRequest( obj: unknown, ): obj is CreatePlaylistRequest { if ( !obj || typeof obj !== "object" || !("title" in obj) || typeof obj.title !== "string" || !("isPublic" in obj) || typeof obj.isPublic !== "boolean" ) return false; const o = obj as Record; if (!isValidTitle(o.title as string)) return false; if ( "description" in o && typeof o.description !== "string" && o.description !== null ) return false; if ( typeof o.description === "string" && (o.description as string).length > VALIDATION.PLAYLIST_DESCRIPTION_MAX ) return false; return hasValidCategoryIds(o); } /** * Checks whether `obj` is an {@link UpdatePlaylistRequest} whose title, if * given, isn't blank, with a title and description within the `VALIDATION` * limits. */ export function isUpdatePlaylistRequest( obj: unknown, ): obj is UpdatePlaylistRequest { if (!obj || typeof obj !== "object") return false; const o = obj as Record; // Its format is changeSlug's check, which says what is wrong. if ("slug" in o && typeof o.slug !== "string") return false; if ("title" in o) { if (typeof o.title !== "string") return false; if (!isValidTitle(o.title as string)) return false; } if ( "description" in o && typeof o.description !== "string" && o.description !== null ) return false; if ( typeof o.description === "string" && (o.description as string).length > VALIDATION.PLAYLIST_DESCRIPTION_MAX ) return false; if ("isPublic" in o && typeof o.isPublic !== "boolean") return false; return hasValidCategoryIds(o); } /** * Checks whether `obj` is a {@link ReorderPlaylistRequest}. Whether its ids * match the playlist is `reorderPlaylist`'s to check. */ export function isReorderPlaylistRequest( obj: unknown, ): obj is ReorderPlaylistRequest { return !!obj && typeof obj === "object" && "dumpIds" in obj && Array.isArray(obj.dumpIds) && (obj.dumpIds as unknown[]).every((id) => typeof id === "string"); }