Skip to content

Commit

Permalink
[BE] ✨ : 여정 삭제 api 구현 (#275)
Browse files Browse the repository at this point in the history
* swagger 설정

* gitaction test

* cancle 로직 구현(아직 완성x)

* ✨ 삭제 api 구현

* ✨ Object id 예외 처리

Object id 에 맞지 않는 형식에 대한 decorator 제작

* ♻️ IsObjectId 데코레이터에 따른 dto 수정

* ♻️ Journey 관련 swagger 수정
  • Loading branch information
twoo1999 authored Dec 10, 2023
1 parent 99ddcd3 commit cfd2059
Show file tree
Hide file tree
Showing 11 changed files with 168 additions and 27 deletions.
26 changes: 26 additions & 0 deletions BE/musicspot/src/common/decorator/objectId.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
} from 'class-validator';
import { is1DArray, is2DArray } from '../util/coordinate.util';
import mongoose from 'mongoose';

export function IsObjectId(validationOptions?: ValidationOptions) {
return function (object: Object, propertyName: string) {
registerDecorator({
name: 'isObjectId',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(receiveValue: string, args: ValidationArguments) {
if (!mongoose.Types.ObjectId.isValid(receiveValue)) {
return false;
}
return true;
},
},
});
};
}
2 changes: 1 addition & 1 deletion BE/musicspot/src/filters/exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class AllExceptionFilter implements ExceptionFilter {
const req = ctx.getRequest();
const res = ctx.getResponse();
const err = exception;
console.log(err);
console.log(err.message);
const { status, response } = err;
let json = {
method: req.method,
Expand Down
51 changes: 37 additions & 14 deletions BE/musicspot/src/journey/controller/journey.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Get,
Query,
Param,
Delete,
} from '@nestjs/common';
import { JourneyService } from '../service/journey.service';

Expand All @@ -33,6 +34,7 @@ import {
RecordJourneyResDTO,
} from '../dto/journeyRecord/journeyRecord.dto';
import { StartJourneyResDTO } from '../dto/journeyStart/journeyStart.dto';
import { DeleteJourneyReqDTO } from '../dto/journeyDelete.dto';

@Controller('journey')
@ApiTags('journey 관련 API')
Expand Down Expand Up @@ -125,20 +127,6 @@ export class JourneyController {
return await this.journeyService.checkJourney(checkJourneyDTO);
}

// @ApiOperation({
// summary: '여정 조회 API',
// description: '해당 범위 내의 여정들을 반환합니다.',
// })
// @ApiCreatedResponse({
// description: '범위에 있는 여정의 기록들을 반환',
// type: CheckJourneyResDTO,
// })
// @Post('check')
// @UsePipes(ValidationPipe) //유효성 체크
// async checkPost(@Body() checkJourneyDTO: CheckJourneyReqDTO) {
// return await this.journeyService.checkJourney(checkJourneyDTO);
// }

@ApiOperation({
summary: '최근 여정 조회 API',
description: '진행 중인 여정이 있었는 지 확인',
Expand All @@ -152,8 +140,43 @@ export class JourneyController {
return await this.journeyService.loadLastJourney(userId);
}

@ApiOperation({
summary: '여정 조회 API',
description: 'journey id를 통해 여정을 조회',
})
@ApiCreatedResponse({
description: 'journey id에 해당하는 여정을 반환',
type: [Journey],
})
@Get(':journeyId')
async getJourneyById(@Param('journeyId') journeyId: string) {
return await this.journeyService.getJourneyById(journeyId);
}

@ApiOperation({
summary: '여정 삭제 api',
description: 'journey id에 따른 여정 삭제',
})
@ApiCreatedResponse({
description: '삭제된 여정을 반환',
type: Journey,
})
@Delete('')
async deleteJourneyById(@Body() deleteJourneyDto: DeleteJourneyReqDTO) {
return await this.journeyService.deleteJourneyById(deleteJourneyDto);
}
}

// @ApiOperation({
// summary: '여정 조회 API',
// description: '해당 범위 내의 여정들을 반환합니다.',
// })
// @ApiCreatedResponse({
// description: '범위에 있는 여정의 기록들을 반환',
// type: CheckJourneyResDTO,
// })
// @Post('check')
// @UsePipes(ValidationPipe) //유효성 체크
// async checkPost(@Body() checkJourneyDTO: CheckJourneyReqDTO) {
// return await this.journeyService.checkJourney(checkJourneyDTO);
// }
9 changes: 6 additions & 3 deletions BE/musicspot/src/journey/dto/journeyCheck/journeyCheck.dto.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsNotEmpty, IsString, IsUUID } from 'class-validator';
import { IsArray, IsNotEmpty, IsUUID } from 'class-validator';
import { UUID } from 'crypto';
import { IsCoordinate } from 'src/common/decorator/coordinate.decorator';

export class CheckJourneyReqDTO {
@IsNotEmpty()
@ApiProperty({
example: '655efda2fdc81cae36d20650',
example: 'ACB46D2C-44D7-444F-84C5-4EF7E81E12E',
description: '유저 id',
required: true,
})
Expand All @@ -22,7 +22,10 @@ export class CheckJourneyReqDTO {
required: true,
})
@IsNotEmpty()
@IsArray()
@IsCoordinate({
message:
'위치 좌표는 2개의 숫자와 각각의 범위를 만족해야합니다.(-90~90 , -180~180)',
})
readonly minCoordinate: number[];

@ApiProperty({
Expand Down
53 changes: 53 additions & 0 deletions BE/musicspot/src/journey/dto/journeyDelete.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsDateString } from 'class-validator';
import { UUID } from 'crypto';
export class DeleteJourneyReqDTO {
@ApiProperty({
example: 'ab4068ef-95ed-40c3-be6d-3db35df866b9',
description: '사용자 id',
required: true,
})
@IsString()
readonly userId: UUID;

@ApiProperty({
example: '6574c8adb08b3d712827385f',
description: '여정 id',
required: true,
})
@IsString()
readonly journeyId: string;
}

export class DeleteJourneyResDTO {
@ApiProperty({
example: [37.555946, 126.972384],
description: '위치 좌표',
required: true,
})
readonly coordinate: number[];

@ApiProperty({
example: '2023-11-22T12:00:00Z',
description: 'timestamp',
required: true,
})
@IsDateString()
readonly startTimestamp: string;

@ApiProperty({
example: '656f4b55b11c27334d1fd347',
description: '저장한 journey id',
required: true,
})
@IsString()
readonly journeyId: string;

// @ApiProperty({
// example: '[email protected]',
// description: '이메일',
// required: true,
// })
// @IsString()
// readonly email: string;
}
10 changes: 7 additions & 3 deletions BE/musicspot/src/journey/dto/journeyEnd/journeyEnd.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@ import {
} from '../../../common/decorator/coordinate.decorator';
import { Type } from 'class-transformer';
import { SongDTO } from '../song/song.dto';
import { IsObjectId } from 'src/common/decorator/objectId.decorator';

export class EndJourneyReqDTO {
@ApiProperty({
example: '655efda2fdc81cae36d20650',
description: '여정 id',
required: true,
})
@IsString()
@IsObjectId({ message: 'ObjectId 형식만 유효합니다.' })
readonly journeyId: string;

@ApiProperty({
Expand All @@ -31,12 +32,15 @@ export class EndJourneyReqDTO {
description: '위치 좌표',
required: true,
})
@IsCoordinates()
@IsCoordinates({
message:
'위치 좌표 배열은 2차원 배열이고 각각의 배열은 숫자 2개와 범위를 만족해야합니다.(-90~90, -180~180)',
})
readonly coordinates: number[][];

@ApiProperty({
example: '2023-11-22T12:00:00Z',
description: 'timestamp',
description: '종료 timestamp',
required: true,
})
@IsDateString()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
IsCoordinate,
IsCoordinates,
} from '../../../common/decorator/coordinate.decorator';
import { IsObjectId } from 'src/common/decorator/objectId.decorator';
export class RecordJourneyResDTO {
@ApiProperty({
example: [
Expand All @@ -23,7 +24,7 @@ export class RecordJourneyReqDTO {
description: '여정 id',
required: true,
})
@IsString()
@IsObjectId({ message: 'ObjectId 형식만 유효합니다.' })
readonly journeyId: string;

@ApiProperty({
Expand Down
6 changes: 3 additions & 3 deletions BE/musicspot/src/journey/dto/journeyStart/journeyStart.dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsString, IsDateString, IsArray } from 'class-validator';
import { IsString, IsDateString, IsArray, IsUUID } from 'class-validator';
import { IsCoordinate } from '../../../common/decorator/coordinate.decorator';
import { UUID } from 'crypto';
export class StartJourneyReqDTO {
Expand All @@ -16,7 +16,7 @@ export class StartJourneyReqDTO {

@ApiProperty({
example: '2023-11-22T12:00:00Z',
description: 'timestamp',
description: '시작 timestamp',
required: true,
})
@IsDateString()
Expand All @@ -27,7 +27,7 @@ export class StartJourneyReqDTO {
description: '사용자 id',
required: true,
})
@IsString()
@IsUUID()
readonly userId: UUID;

// @ApiProperty({
Expand Down
3 changes: 3 additions & 0 deletions BE/musicspot/src/journey/schema/journey.schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { HydratedDocument } from 'mongoose';
import { ApiProperty } from '@nestjs/swagger';
import { Song } from './song.schema';
import { JourneyMetadata } from './journeyMetadata.schema';
import { IsDefined, ValidateNested } from 'class-validator';

export type JourneyDocument = HydratedDocument<Journey>;

Expand Down Expand Up @@ -39,9 +40,11 @@ export class Journey {
@Prop({ type: [[Number]] })
coordinates?: number[][];

@ApiProperty({ description: '메타데이터', type: JourneyMetadata })
@Prop({ type: JourneyMetadata })
journeyMetadata?: JourneyMetadata;

@ApiProperty({ description: '음악 정보', type: Song })
@Prop({ type: Song })
song?: Song;
}
Expand Down
29 changes: 28 additions & 1 deletion BE/musicspot/src/journey/service/journey.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Model } from 'mongoose';
import mongoose, { Model } from 'mongoose';
import { InjectModel } from '@nestjs/mongoose';
import { Injectable } from '@nestjs/common';

Expand All @@ -22,6 +22,8 @@ import { EndJourneyReqDTO } from '../dto/journeyEnd/journeyEnd.dto';
import { CheckJourneyReqDTO } from '../dto/journeyCheck/journeyCheck.dto';
import { RecordJourneyReqDTO } from '../dto/journeyRecord/journeyRecord.dto';
import { is1DArray } from 'src/common/util/coordinate.util';
import { DeleteJourneyReqDTO } from '../dto/journeyDelete.dto';
import { checkPrimeSync } from 'crypto';

@Injectable()
export class JourneyService {
Expand Down Expand Up @@ -239,4 +241,29 @@ export class JourneyService {
})
.lean();
}

async deleteJourneyById(deletedJourneyDto: DeleteJourneyReqDTO) {
const { userId, journeyId } = deletedJourneyDto;

const deletedJourney = await this.journeyModel
.findOneAndDelete({
_id: journeyId,
})
.lean();
if (!deletedJourney) {
throw new JourneyNotFoundException();
}

const deletedUserData = await this.userModel.findOneAndUpdate(
{ userId },
{ $pull: { journeys: new mongoose.Types.ObjectId(journeyId) } },
{ new: true },
);

if (!deletedUserData) {
throw new UserNotFoundException();
}

return deletedJourney;
}
}
3 changes: 2 additions & 1 deletion BE/musicspot/src/spot/dto/recordSpot.dto.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsArray, IsDateString, IsString, IsUrl } from 'class-validator';
import { IsCoordinate } from '../../common/decorator/coordinate.decorator';
import { IsObjectId } from 'src/common/decorator/objectId.decorator';

export class RecordSpotReqDTO {
@ApiProperty({
example: '655efda2fdc81cae36d20650',
description: '여정 id',
required: true,
})
@IsString()
@IsObjectId({ message: 'ObjectId 형식만 유효합니다.' })
readonly journeyId: string;

@ApiProperty({
Expand Down

0 comments on commit cfd2059

Please sign in to comment.