Files
retivo/apps/server/src/routes/albums.ts
2026-10-05 20:38:28 +02:00

61 lines
2.2 KiB
TypeScript

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) });
}),
);