Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BE] ✨ : coordinate 양식 수정에 따른 journey entity 및 비지니스 로직 수정 #365

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name: Music Spot Project

on:
push:
branches: ["BE/release"]
branches: ["main"]
jobs:
build:
runs-on: ubuntu-latest
Expand Down
38 changes: 38 additions & 0 deletions BE/musicspot/src/common/decorator/coordinate.v2.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
registerDecorator,
ValidationOptions,
ValidationArguments,
} from 'class-validator';
import { isLinestring, isPointString } from '../util/coordinate.v2.util';

export function IsCoordinateV2(validationOptions?: ValidationOptions) {
return function (object: object, propertyName: string) {
registerDecorator({
name: 'isCoordinateV2',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(receiveValue: string, args: ValidationArguments) {
return isPointString(receiveValue);
},
},
});
};
}

export function IsCoordinatesV2(validationOptions?: ValidationOptions) {
return function (object: object, propertyName: string) {
registerDecorator({
name: 'isCoordinatesV2',
target: object.constructor,
propertyName: propertyName,
options: validationOptions,
validator: {
validate(receiveValue: string, args: ValidationArguments) {
return isLinestring(receiveValue);
},
},
});
};
}
62 changes: 62 additions & 0 deletions BE/musicspot/src/common/util/coordinate.v2.util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export const isPointString = (pointString: string): boolean => {
const regex = /^\d+.\d+\s\d+.\d+$/;
if (!pointString.match(regex)) {
return false;
}
if (!isCorrectCoordinateRange(pointString)) {
return false;
}
return true;
};

export const isLinestring = (lineString: string): boolean => {
const regex: RegExp =
/^\d+.\d+\s\d+.\d+,(\d+.\d+\s\d+.\d+,)*\d+.\d+\s\d+.\d+$/;
console.log(':ASD');
if (!lineString.match(regex)) {
return false;
}

const points = lineString.split(',');
for (let i = 0; i < points.length; i++) {
if (!isCorrectCoordinateRange(points[i])) {
return false;
}
}
return true;
};

export const isCorrectCoordinateRange = (pointString: string): boolean => {
const [lat, lon] = pointString.split(' ').map((str) => Number(str));
if (lat > 90 || lat < -90) {
return false;
}
if (lon > 180 || lon < -180) {
return false;
}

return true;
};

export const parseCoordinateFromDtoToGeoV2 = (coordinate: string): string => {
// coordinate = 1 2
return `POINT(${coordinate})`;
};

export const parseCoordinateFromGeoToDtoV2 = (coordinate: string): string => {
// coordinate = 'POINT(1 2)'

const pointLen = 'POINT('.length;
return coordinate.slice(pointLen, -1);
};

export const parseCoordinatesFromDtoToGeoV2 = (coordinates: string): string => {
// coordinates = 1 2,3 4
return `LINESTRING(${coordinates})`;
};

export const parseCoordinatesFromGeoToDtoV2 = (coordinates: string): string => {
// coordinates = 'LINESTRING(1 2,3 4)'
const pointLen = 'LINESTRING'.length;
return coordinates.slice(pointLen, -1);
};
35 changes: 32 additions & 3 deletions BE/musicspot/src/journey/controller/journey.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ import { DeleteJourneyReqDTO } from '../dto/journeyDelete.dto';

import { Journey } from '../entities/journey.entity';
import { LastJourneyResDTO } from '../dto/journeyLast.dto';
import {
StartJourneyReqDTOV2,
StartJourneyResDTOV2,
} from '../dto/v2/startJourney.v2.dto';
import {
EndJourneyReqDTOV2,
EndJourneyResDTOV2,
} from '../dto/v2/endJourney.v2.dto';

@Controller('journey')
@ApiTags('journey 관련 API')
Expand All @@ -50,18 +58,25 @@ export class JourneyController {
description: '생성된 여정 데이터를 반환',
type: StartJourneyResDTO,
})
@Post('start')
@Post('/start')
async create(@Body() startJourneyDTO: StartJourneyReqDTO) {
return await this.journeyService.insertJourneyData(startJourneyDTO);
}

@Version('2')
@ApiOperation({
summary: '여정 시작 API',
summary: '여정 시작 API(V2)',
description: '여정 기록을 시작합니다.',
})
@ApiCreatedResponse({
description: '생성된 여정 데이터를 반환',
type: StartJourneyResDTO,
type: StartJourneyResDTOV2,
})
@Post('start')
async createV2(@Body() startJourneyDTO: StartJourneyReqDTOV2) {
return await this.journeyService.insertJourneyDataV2(startJourneyDTO);
}

@ApiOperation({
summary: '여정 종료 API',
description: '여정을 종료합니다.',
Expand All @@ -75,6 +90,20 @@ export class JourneyController {
return await this.journeyService.end(endJourneyReqDTO);
}

@Version('2')
@ApiOperation({
summary: '여정 종료 API(V2)',
description: '여정을 종료합니다.',
})
@ApiCreatedResponse({
description: '여정 종료 정보 반환',
type: EndJourneyResDTOV2,
})
@Post('end')
async endV2(@Body() endJourneyReqDTO: EndJourneyReqDTOV2) {
return await this.journeyService.endV2(endJourneyReqDTO);
}

@ApiOperation({
summary: '여정 좌표 기록API',
description: '여정의 좌표를 기록합니다.',
Expand Down
88 changes: 88 additions & 0 deletions BE/musicspot/src/journey/dto/v2/endJourney.v2.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { ApiProperty } from '@nestjs/swagger';
import {
IsString,
IsDateString,
IsNumber,
IsObject,
} from 'class-validator';
import { IsCoordinatesV2 } from '../../../common/decorator/coordinate.v2.decorator';

export class EndJourneyReqDTOV2 {
@ApiProperty({
example: 20,
description: '여정 id',
required: true,
})
@IsNumber()
readonly journeyId: number;

@ApiProperty({
example: '37.555946 126.972384,37.555946 126.972384',
description: '위치 좌표',
required: true,
})
@IsCoordinatesV2({
message:
'잘못된 coordinates 형식입니다. Ex) 37.555946 126.972384,37.555946 126.972384',
})
readonly coordinates: string;

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

@ApiProperty({
example: '여정 제목',
description: '여정 제목',
required: true,
})
@IsString()
readonly title: string;

@IsObject()
@ApiProperty({
description: '노래 정보',
required: true,
})
readonly song: object;
}

export class EndJourneyResDTOV2 {
@ApiProperty({
example: 20,
description: '여정 id',
required: true,
})
readonly journeyId: number;

@ApiProperty({
example: '37.555946 126.972384,37.555946 126.972384',
description: '위치 좌표',
required: true,
})
readonly coordinates: string;

@ApiProperty({
example: '2023-11-22T15:30:00.000+09:00',
description: '여정 종료 시간',
required: true,
})
readonly endTimestamp: string;

@ApiProperty({
example: 2,
description: '기록된 coordinate 수',
required: true,
})
readonly numberOfCoordinates: number;

@ApiProperty({
description: '노래 정보',
required: true,
})
readonly song: object;
}
35 changes: 35 additions & 0 deletions BE/musicspot/src/journey/dto/v2/startJourney.v2.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ApiProperty } from '@nestjs/swagger';
import { IsDateString, IsUUID } from 'class-validator';
import { UUID } from 'crypto';

export class StartJourneyReqDTOV2 {
@ApiProperty({
example: 'ab4068ef-95ed-40c3-be6d-3db35df866b9',
description: '사용자 id',
required: true,
})
@IsUUID()
readonly userId: UUID;

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

export class StartJourneyResDTOV2 {
@ApiProperty({
example: 20,
description: '저장한 journey id',
})
readonly journeyId: number;

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