import { getAlbumDetails, getAlbumsWithTracks, createAlbum, updateAlbum, deleteAlbum, } from '../../services/album.js'; import photosRoutes from './photos.js'; import teasersRoutes from './teasers.js'; /** * 앨범 라우트 * GET: 공개, POST/PUT/DELETE: 인증 필요 */ export default async function albumsRoutes(fastify) { const { db } = fastify; // 하위 라우트 등록 fastify.register(photosRoutes); fastify.register(teasersRoutes); // ==================== GET (공개) ==================== /** * GET /api/albums */ fastify.get('/', { schema: { tags: ['albums'], summary: '전체 앨범 목록 조회', }, }, async () => { return await getAlbumsWithTracks(db); }); /** * GET /api/albums/by-name/:albumName/track/:trackTitle */ fastify.get('/by-name/:albumName/track/:trackTitle', { schema: { tags: ['albums'], summary: '앨범명과 트랙명으로 트랙 조회', }, }, async (request, reply) => { const albumName = decodeURIComponent(request.params.albumName); const trackTitle = decodeURIComponent(request.params.trackTitle); const [albums] = await db.query( 'SELECT * FROM albums WHERE folder_name = ? OR title = ?', [albumName, albumName] ); if (albums.length === 0) { return reply.code(404).send({ error: '앨범을 찾을 수 없습니다.' }); } const album = albums[0]; const [tracks] = await db.query( 'SELECT * FROM album_tracks WHERE album_id = ? AND title = ?', [album.id, trackTitle] ); if (tracks.length === 0) { return reply.code(404).send({ error: '트랙을 찾을 수 없습니다.' }); } const track = tracks[0]; const [otherTracks] = await db.query( 'SELECT id, track_number, title, is_title_track, duration FROM album_tracks WHERE album_id = ? ORDER BY track_number', [album.id] ); return { ...track, album: { id: album.id, title: album.title, folder_name: album.folder_name, cover_thumb_url: album.cover_thumb_url, cover_medium_url: album.cover_medium_url, release_date: album.release_date, album_type: album.album_type, }, otherTracks, }; }); /** * GET /api/albums/by-name/:name */ fastify.get('/by-name/:name', { schema: { tags: ['albums'], summary: '앨범명으로 앨범 조회', }, }, async (request, reply) => { const name = decodeURIComponent(request.params.name); const [albums] = await db.query( 'SELECT * FROM albums WHERE folder_name = ? OR title = ?', [name, name] ); if (albums.length === 0) { return reply.code(404).send({ error: '앨범을 찾을 수 없습니다.' }); } return getAlbumDetails(db, albums[0]); }); /** * GET /api/albums/:id */ fastify.get('/:id', { schema: { tags: ['albums'], summary: 'ID로 앨범 조회', }, }, async (request, reply) => { const [albums] = await db.query('SELECT * FROM albums WHERE id = ?', [ request.params.id, ]); if (albums.length === 0) { return reply.code(404).send({ error: '앨범을 찾을 수 없습니다.' }); } return getAlbumDetails(db, albums[0]); }); // ==================== POST/PUT/DELETE (인증 필요) ==================== /** * POST /api/albums */ fastify.post('/', { schema: { tags: ['albums'], summary: '앨범 생성', security: [{ bearerAuth: [] }], }, preHandler: [fastify.authenticate], }, async (request, reply) => { const parts = request.parts(); let data = null; let coverBuffer = null; for await (const part of parts) { if (part.type === 'file' && part.fieldname === 'cover') { coverBuffer = await part.toBuffer(); } else if (part.fieldname === 'data') { data = JSON.parse(part.value); } } if (!data) { return reply.code(400).send({ error: '데이터가 필요합니다.' }); } const { title, album_type, release_date, folder_name } = data; if (!title || !album_type || !release_date || !folder_name) { return reply.code(400).send({ error: '필수 필드를 모두 입력해주세요.' }); } return await createAlbum(db, data, coverBuffer); }); /** * PUT /api/albums/:id */ fastify.put('/:id', { schema: { tags: ['albums'], summary: '앨범 수정', security: [{ bearerAuth: [] }], }, preHandler: [fastify.authenticate], }, async (request, reply) => { const { id } = request.params; const parts = request.parts(); let data = null; let coverBuffer = null; for await (const part of parts) { if (part.type === 'file' && part.fieldname === 'cover') { coverBuffer = await part.toBuffer(); } else if (part.fieldname === 'data') { data = JSON.parse(part.value); } } if (!data) { return reply.code(400).send({ error: '데이터가 필요합니다.' }); } const result = await updateAlbum(db, id, data, coverBuffer); if (!result) { return reply.code(404).send({ error: '앨범을 찾을 수 없습니다.' }); } return result; }); /** * DELETE /api/albums/:id */ fastify.delete('/:id', { schema: { tags: ['albums'], summary: '앨범 삭제', security: [{ bearerAuth: [] }], }, preHandler: [fastify.authenticate], }, async (request, reply) => { const { id } = request.params; const result = await deleteAlbum(db, id); if (!result) { return reply.code(404).send({ error: '앨범을 찾을 수 없습니다.' }); } return result; }); }