From 68345f1638d448be7140e2d4eb5afa3206631181 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 20:19:16 +0900 Subject: [PATCH 1/8] =?UTF-8?q?feat=20:=20=EC=9D=8C=EC=95=85=20=EC=9E=A5?= =?UTF-8?q?=EB=A5=B4=20enum=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/constants.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/server/src/constants.ts b/server/src/constants.ts index d5110d9..a994751 100644 --- a/server/src/constants.ts +++ b/server/src/constants.ts @@ -2,3 +2,14 @@ export const fileSize: Record = { MUSIC_FILE_LIMIT_SIZE: 1024 * 1024 * 50, IMAGE_FILE_LIMIT_SIZE: 1024 * 1024 * 5, }; + +export enum Genres { + 'hip-hop' = 'hip-hop', + 'acoustic' = 'acoustic', + 'ballade' = 'ballade', + 'r&b' = 'r&b', + 'jazz' = 'jazz', + 'rock' = 'rock', + 'dance' = 'dance', + 'etc' = 'etc', +} From dd1474041ec160420d60f747e488d8a0b5fe5cd6 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 20:20:09 +0900 Subject: [PATCH 2/8] =?UTF-8?q?feat=20:=20=EC=9D=8C=EC=95=85=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=8B=9C=20body=EC=97=90=20=EB=8B=B4?= =?UTF-8?q?=EC=95=84=20=EC=98=AC=20DTO=20genre=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 제목 길이 50 으로 제한 둠 * genre의 타입은 enum 변수 --- server/src/dto/musicCreate.dto.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/server/src/dto/musicCreate.dto.ts b/server/src/dto/musicCreate.dto.ts index c8cef7a..030ddc3 100644 --- a/server/src/dto/musicCreate.dto.ts +++ b/server/src/dto/musicCreate.dto.ts @@ -1,8 +1,10 @@ -import { IsNotEmpty, IsString } from 'class-validator'; +import { IsNotEmpty, IsString, MaxLength } from 'class-validator'; +import { Genres } from 'src/constants'; export class MusicCreateDto { @IsNotEmpty() @IsString() + @MaxLength(50, { message: '글자 수가 50을 넘어갔습니다.' }) title: string; @IsNotEmpty() @@ -12,4 +14,8 @@ export class MusicCreateDto { @IsNotEmpty() @IsString() file: string; + + @IsNotEmpty() + @IsString() + genre: Genres; } From 0e29ba0342e0c6f4169b884d918a8ee237ecfe6f Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 20:20:41 +0900 Subject: [PATCH 3/8] =?UTF-8?q?feat=20:=20=EC=9D=8C=EC=95=85=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=EC=97=90=20=EC=9E=A5=EB=A5=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/entity/music.entity.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/server/src/entity/music.entity.ts b/server/src/entity/music.entity.ts index 6b52675..1eb69ac 100644 --- a/server/src/entity/music.entity.ts +++ b/server/src/entity/music.entity.ts @@ -8,6 +8,7 @@ import { PrimaryGeneratedColumn, } from 'typeorm'; import { User } from './user.entity'; +import { Genres } from 'src/constants'; @Entity({ name: 'music' }) export class Music extends BaseEntity { @@ -26,6 +27,9 @@ export class Music extends BaseEntity { @Column() musicFile: string; + @Column() + genre: Genres; + @CreateDateColumn() created_at: Date; From d66fc95b94e002739d1aa55072a4bb7ad054e6fe Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 20:24:56 +0900 Subject: [PATCH 4/8] =?UTF-8?q?feat=20:=20=EC=9D=8C=EC=95=85=20=EC=9E=A5?= =?UTF-8?q?=EB=A5=B4,=20=EC=B5=9C=EA=B7=BC=20=EC=97=85=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=20=EC=9D=8C=EC=95=85=2010=EA=B0=9C=20=EB=B0=98=ED=99=98=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * /musics/recent-uploads 로 최근 업로드 된 음악 10개 반환 * /musics/genre로 음악 장르만 반환 --- server/src/music/music.controller.ts | 14 ++++++++++++++ server/src/music/music.service.ts | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/server/src/music/music.controller.ts b/server/src/music/music.controller.ts index b3785dc..def0211 100644 --- a/server/src/music/music.controller.ts +++ b/server/src/music/music.controller.ts @@ -36,4 +36,18 @@ export class MusicController { throw new HttpException('WRONG TOKEN', HTTP_STATUS_CODE['WRONG TOKEN']); } } + + @Get('recent-uploads') + async getRecentMusics() { + const musics = await this.musicService.getRecentMusic(); + + return { musics }; + } + + @Get('genre') + getGenres() { + const genreName: string[] = Object.keys(Genres); + + return { genres: genreName }; + } } diff --git a/server/src/music/music.service.ts b/server/src/music/music.service.ts index 1f8db9a..9692653 100644 --- a/server/src/music/music.service.ts +++ b/server/src/music/music.service.ts @@ -24,6 +24,16 @@ export class MusicService { }); this.musicRepository.save(newMusic); + async getRecentMusic() { + try { + const musics = await this.musicRepository.find({ + order: { + created_at: 'DESC', + }, + take: 10, + }); + + return musics; } catch { throw new HttpException('SERVER ERROR', HTTP_STATUS_CODE.SERVER_ERROR); } From dc8f7eaf5fe722cdd5a262ab79e8d173db73c0c3 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 20:25:49 +0900 Subject: [PATCH 5/8] =?UTF-8?q?feat=20:=20=EC=9D=8C=EC=95=85=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=8B=9C=20=EC=9E=A5=EB=A5=B4=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 서비스 부분에 지정된 장르가 맞는지 확인하는 로직 추가 --- server/src/httpStatusCode.enum.ts | 1 + server/src/music/music.controller.ts | 7 ++++++- server/src/music/music.service.ts | 29 +++++++++++++++++++++++++++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/server/src/httpStatusCode.enum.ts b/server/src/httpStatusCode.enum.ts index 760cc08..801c398 100644 --- a/server/src/httpStatusCode.enum.ts +++ b/server/src/httpStatusCode.enum.ts @@ -4,4 +4,5 @@ export enum HTTP_STATUS_CODE { 'DUPLICATED_NICKNAME' = 409, 'WRONG TOKEN' = 401, 'SERVER_ERROR' = 500, + 'NOT_EXIST_GENRE' = 400, } diff --git a/server/src/music/music.controller.ts b/server/src/music/music.controller.ts index def0211..1d9c25d 100644 --- a/server/src/music/music.controller.ts +++ b/server/src/music/music.controller.ts @@ -5,6 +5,7 @@ import { HttpCode, HttpException, Post, + Get, UseGuards, UsePipes, ValidationPipe, @@ -13,6 +14,7 @@ import { MusicService } from './music.service'; import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum'; import { MusicCreateDto } from 'src/dto/musicCreate.dto'; import { AuthGuard } from '@nestjs/passport'; +import { Genres } from 'src/constants'; @Controller('musics') export class MusicController { @@ -22,7 +24,10 @@ export class MusicController { @UsePipes(ValidationPipe) @UseGuards(AuthGuard()) @HttpCode(HTTP_STATUS_CODE.SUCCESS) - async upload(@Body() musicCreateDto: MusicCreateDto, @Req() req) { + async upload( + @Body() musicCreateDto: MusicCreateDto, + @Req() req, + ): Promise<{ userId: string }> { try { const userId = req.user.user_id; diff --git a/server/src/music/music.service.ts b/server/src/music/music.service.ts index 9692653..1f449d0 100644 --- a/server/src/music/music.service.ts +++ b/server/src/music/music.service.ts @@ -4,6 +4,7 @@ import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { MusicCreateDto } from 'src/dto/musicCreate.dto'; import { Music } from 'src/entity/music.entity'; +import { Genres } from 'src/constants'; @Injectable() export class MusicService { @@ -12,18 +13,44 @@ export class MusicService { @InjectRepository(Music) private musicRepository: Repository, ) {} + isValidGenre(genre: string) { + if (Object.values(Genres).includes(genre as Genres)) { + return true; + } + + return false; + } + createMusic(musicCreateDto: MusicCreateDto, user_id: string) { try { - const { title, cover, file: musicFile } = musicCreateDto; + const { title, cover, file: musicFile, genre } = musicCreateDto; + + if (!this.isValidGenre(genre)) { + throw new HttpException( + 'NOT_EXIST_GENRE', + HTTP_STATUS_CODE.NOT_EXIST_GENRE, + ); + } + const newMusic: Music = this.musicRepository.create({ title, cover, musicFile, created_at: new Date(), + genre, user_id, }); this.musicRepository.save(newMusic); + } catch (err) { + if (err instanceof HttpException) { + throw err; + } + + throw new HttpException('SERVER ERROR', HTTP_STATUS_CODE.SERVER_ERROR); + } + } + async getRecentMusic() { try { const musics = await this.musicRepository.find({ From 4e0297acb1d5dc5daef737db560a6bd10099dd8b Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 21:22:10 +0900 Subject: [PATCH 6/8] =?UTF-8?q?fix=20:=20music=EC=99=80=20user=20=EA=B0=84?= =?UTF-8?q?=20=EB=A7=A4=ED=95=91=20=EA=B4=80=EA=B3=84=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 사용자: 음악 => 일대다 관계 --- server/src/entity/music.entity.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/entity/music.entity.ts b/server/src/entity/music.entity.ts index 1eb69ac..84d6748 100644 --- a/server/src/entity/music.entity.ts +++ b/server/src/entity/music.entity.ts @@ -6,6 +6,7 @@ import { OneToOne, JoinColumn, PrimaryGeneratedColumn, + ManyToOne, } from 'typeorm'; import { User } from './user.entity'; import { Genres } from 'src/constants'; @@ -33,7 +34,7 @@ export class Music extends BaseEntity { @CreateDateColumn() created_at: Date; - @OneToOne(() => User) + @ManyToOne(() => User) @JoinColumn({ name: 'user_id' }) user_id: string; } From 2dd9bc47850cb056dac83ac84706a41556753950 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 21:22:25 +0900 Subject: [PATCH 7/8] =?UTF-8?q?chore=20:=20=EC=84=B1=EA=B3=B5(200)=20?= =?UTF-8?q?=EC=83=81=ED=83=9C=20=EC=BD=94=EB=93=9C=20=EB=8D=B0=EC=BD=94?= =?UTF-8?q?=EB=A0=88=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server/src/music/music.controller.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/src/music/music.controller.ts b/server/src/music/music.controller.ts index 1d9c25d..22076a5 100644 --- a/server/src/music/music.controller.ts +++ b/server/src/music/music.controller.ts @@ -43,6 +43,7 @@ export class MusicController { } @Get('recent-uploads') + @HttpCode(HTTP_STATUS_CODE.SUCCESS) async getRecentMusics() { const musics = await this.musicService.getRecentMusic(); @@ -50,6 +51,7 @@ export class MusicController { } @Get('genre') + @HttpCode(HTTP_STATUS_CODE.SUCCESS) getGenres() { const genreName: string[] = Object.keys(Genres); From b8d9af76d7737499dce62fb13a8ab55a8c780026 Mon Sep 17 00:00:00 2001 From: Seokyung Lim Date: Thu, 16 Nov 2023 23:49:04 +0900 Subject: [PATCH 8/8] =?UTF-8?q?refactor=20:=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 상태 코드 메시지 변경 * Upload, Music 모듈 함수 반환 타입 지정 * 장르 반환 API명 변경 --- server/src/entity/music.entity.ts | 1 - server/src/httpStatusCode.enum.ts | 2 +- server/src/music/music.controller.ts | 7 ++++--- server/src/music/music.service.ts | 8 ++++---- server/src/upload/upload.controller.ts | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/server/src/entity/music.entity.ts b/server/src/entity/music.entity.ts index 84d6748..9486049 100644 --- a/server/src/entity/music.entity.ts +++ b/server/src/entity/music.entity.ts @@ -3,7 +3,6 @@ import { Entity, CreateDateColumn, BaseEntity, - OneToOne, JoinColumn, PrimaryGeneratedColumn, ManyToOne, diff --git a/server/src/httpStatusCode.enum.ts b/server/src/httpStatusCode.enum.ts index 801c398..6a94129 100644 --- a/server/src/httpStatusCode.enum.ts +++ b/server/src/httpStatusCode.enum.ts @@ -4,5 +4,5 @@ export enum HTTP_STATUS_CODE { 'DUPLICATED_NICKNAME' = 409, 'WRONG TOKEN' = 401, 'SERVER_ERROR' = 500, - 'NOT_EXIST_GENRE' = 400, + 'BAD_REQUEST' = 400, } diff --git a/server/src/music/music.controller.ts b/server/src/music/music.controller.ts index 22076a5..17148f7 100644 --- a/server/src/music/music.controller.ts +++ b/server/src/music/music.controller.ts @@ -15,6 +15,7 @@ import { HTTP_STATUS_CODE } from 'src/httpStatusCode.enum'; import { MusicCreateDto } from 'src/dto/musicCreate.dto'; import { AuthGuard } from '@nestjs/passport'; import { Genres } from 'src/constants'; +import { Music } from 'src/entity/music.entity'; @Controller('musics') export class MusicController { @@ -44,15 +45,15 @@ export class MusicController { @Get('recent-uploads') @HttpCode(HTTP_STATUS_CODE.SUCCESS) - async getRecentMusics() { + async getRecentMusics(): Promise<{ musics: Music[] }> { const musics = await this.musicService.getRecentMusic(); return { musics }; } - @Get('genre') + @Get('genres') @HttpCode(HTTP_STATUS_CODE.SUCCESS) - getGenres() { + getGenres(): { genres: string[] } { const genreName: string[] = Object.keys(Genres); return { genres: genreName }; diff --git a/server/src/music/music.service.ts b/server/src/music/music.service.ts index 1f449d0..1cfb3d5 100644 --- a/server/src/music/music.service.ts +++ b/server/src/music/music.service.ts @@ -13,7 +13,7 @@ export class MusicService { @InjectRepository(Music) private musicRepository: Repository, ) {} - isValidGenre(genre: string) { + isValidGenre(genre: string): boolean { if (Object.values(Genres).includes(genre as Genres)) { return true; } @@ -21,14 +21,14 @@ export class MusicService { return false; } - createMusic(musicCreateDto: MusicCreateDto, user_id: string) { + createMusic(musicCreateDto: MusicCreateDto, user_id: string): void { try { const { title, cover, file: musicFile, genre } = musicCreateDto; if (!this.isValidGenre(genre)) { throw new HttpException( 'NOT_EXIST_GENRE', - HTTP_STATUS_CODE.NOT_EXIST_GENRE, + HTTP_STATUS_CODE.BAD_REQUEST, ); } @@ -51,7 +51,7 @@ export class MusicService { } } - async getRecentMusic() { + async getRecentMusic(): Promise { try { const musics = await this.musicRepository.find({ order: { diff --git a/server/src/upload/upload.controller.ts b/server/src/upload/upload.controller.ts index 2de9f20..86f1357 100644 --- a/server/src/upload/upload.controller.ts +++ b/server/src/upload/upload.controller.ts @@ -28,7 +28,7 @@ export class UploadController { }), ) file: Express.Multer.File, - ) { + ): Promise<{ url: string }> { const { url } = await this.uploadService.uploadMusic(file); return { url }; } @@ -45,7 +45,7 @@ export class UploadController { }), ) file: Express.Multer.File, - ) { + ): Promise<{ url: string }> { const { url } = await this.uploadService.uploadImage(file); return { url }; }