import { Router } from "express"; import { and, asc, eq } from "drizzle-orm"; import { z } from "zod"; import { db } from "../db/index.js"; import { trackWith } from "../db/queries.js"; import { albums, artists, tracks } from "../db/schema.js"; import { HttpError, asyncHandler, assertUuid, notFound, parseBody } from "../lib/http.js"; import { hasPerm } from "../lib/permissions.js"; import { albumDTO, trackDTO } from "../lib/presenters.js"; import { requireAuth } from "../middleware/auth.js"; export const albumsRouter = Router(); albumsRouter.get( "/albums/:id", requireAuth, asyncHandler(async (req, res) => { const id = assertUuid(req.params.id); const [album] = await db.select().from(albums).where(eq(albums.id, id)).limit(1); if (!album) throw notFound("Альбом не найден"); let artist = null; if (album.artistId) { [artist] = await db.select().from(artists).where(eq(artists.id, album.artistId)).limit(1); } const rows = await db.query.tracks.findMany({ where: and(eq(tracks.albumId, id), eq(tracks.status, "approved")), with: trackWith, orderBy: [asc(tracks.discNumber), asc(tracks.trackNumber), asc(tracks.title)], }); res.json({ album: albumDTO({ ...album, artist: artist ?? null }), tracks: rows.map((t) => trackDTO(t as never)), canEdit: hasPerm(req.user, "canManageLibrary"), }); }), ); const patchSchema = z.object({ title: z.string().min(1).max(300).optional(), artistId: z.string().uuid().nullable().optional(), releaseDate: z.string().nullable().optional(), coverUrl: z.string().nullable().optional(), }); albumsRouter.patch( "/albums/:id", requireAuth, asyncHandler(async (req, res) => { if (!hasPerm(req.user, "canManageLibrary")) throw new HttpError(403, "Нет прав"); const id = assertUuid(req.params.id); const data = parseBody(patchSchema, req.body); await db.update(albums).set({ ...data, updatedAt: new Date() }).where(eq(albums.id, id)); const [album] = await db.select().from(albums).where(eq(albums.id, id)).limit(1); if (!album) throw notFound("Альбом не найден"); res.json({ album: albumDTO(album) }); }), );