From 5b727acde6374331c645e364781dffdd1d3a605a Mon Sep 17 00:00:00 2001 From: twoo1999 Date: Fri, 9 Feb 2024 03:41:46 +0900 Subject: [PATCH 1/4] =?UTF-8?q?:recycle:=20git=20action=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit live 및 develop 서버 분리에 따른 서버 분리 필요 --- .github/workflows/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index 4f218f1..971edd4 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -3,7 +3,7 @@ name: Music Spot Project on: push: - branches: ["BE/release"] + branches: ["main"] jobs: build: runs-on: ubuntu-latest From ee3b66a2be29e061ab16a377eca0447091d50889 Mon Sep 17 00:00:00 2001 From: twoo1999 Date: Fri, 9 Feb 2024 03:49:09 +0900 Subject: [PATCH 2/4] =?UTF-8?q?:sparkles:=20(V2)=20journey=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20util=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit geo data 양식 수정([[1,2],[1,2]] -> 1 2,1 2)에 따른 util 함수 변경 --- .../decorator/coordinate.v2.decorator.ts | 38 ++++++++++++ .../src/common/util/coordinate.v2.util.ts | 62 +++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 BE/musicspot/src/common/decorator/coordinate.v2.decorator.ts create mode 100644 BE/musicspot/src/common/util/coordinate.v2.util.ts diff --git a/BE/musicspot/src/common/decorator/coordinate.v2.decorator.ts b/BE/musicspot/src/common/decorator/coordinate.v2.decorator.ts new file mode 100644 index 0000000..87ef53c --- /dev/null +++ b/BE/musicspot/src/common/decorator/coordinate.v2.decorator.ts @@ -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); + }, + }, + }); + }; +} diff --git a/BE/musicspot/src/common/util/coordinate.v2.util.ts b/BE/musicspot/src/common/util/coordinate.v2.util.ts new file mode 100644 index 0000000..3734a74 --- /dev/null +++ b/BE/musicspot/src/common/util/coordinate.v2.util.ts @@ -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); +}; From 127e9cbadf63d77d94a3908af4a3b9f8ec2da668 Mon Sep 17 00:00:00 2001 From: twoo1999 Date: Fri, 9 Feb 2024 03:50:51 +0900 Subject: [PATCH 3/4] =?UTF-8?q?:sparkles:=20(V2)=20journey=20dto=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit geo data 양식 수정([[1,2],[1,2]] -> 1 2,1 2)에 따른 journey dto 수정 - startJourney.v2.dto.ts - coordinate 제거 - endJourney.v2.dto.ts - coordinates 양식 수정 --- .../src/journey/dto/v2/endJourney.v2.dto.ts | 88 +++++++++++++++++++ .../src/journey/dto/v2/startJourney.v2.dto.ts | 35 ++++++++ 2 files changed, 123 insertions(+) create mode 100644 BE/musicspot/src/journey/dto/v2/endJourney.v2.dto.ts create mode 100644 BE/musicspot/src/journey/dto/v2/startJourney.v2.dto.ts diff --git a/BE/musicspot/src/journey/dto/v2/endJourney.v2.dto.ts b/BE/musicspot/src/journey/dto/v2/endJourney.v2.dto.ts new file mode 100644 index 0000000..7d42f02 --- /dev/null +++ b/BE/musicspot/src/journey/dto/v2/endJourney.v2.dto.ts @@ -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; +} diff --git a/BE/musicspot/src/journey/dto/v2/startJourney.v2.dto.ts b/BE/musicspot/src/journey/dto/v2/startJourney.v2.dto.ts new file mode 100644 index 0000000..88b6452 --- /dev/null +++ b/BE/musicspot/src/journey/dto/v2/startJourney.v2.dto.ts @@ -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; +} From 3d8fccad37fd413ac447f802b827179322bce2e5 Mon Sep 17 00:00:00 2001 From: twoo1999 Date: Fri, 9 Feb 2024 03:51:38 +0900 Subject: [PATCH 4/4] =?UTF-8?q?:sparkles:=20(V2)=20coordinate=20=EC=96=91?= =?UTF-8?q?=EC=8B=9D=20=EC=88=98=EC=A0=95=EC=97=90=20=EB=94=B0=EB=A5=B8=20?= =?UTF-8?q?controller=20=EB=B0=8F=20service=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../journey/controller/journey.controller.ts | 35 +- .../src/journey/service/journey.service.ts | 426 +++++++++++------- 2 files changed, 291 insertions(+), 170 deletions(-) diff --git a/BE/musicspot/src/journey/controller/journey.controller.ts b/BE/musicspot/src/journey/controller/journey.controller.ts index f29a917..e069871 100644 --- a/BE/musicspot/src/journey/controller/journey.controller.ts +++ b/BE/musicspot/src/journey/controller/journey.controller.ts @@ -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') @@ -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: '여정을 종료합니다.', @@ -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: '여정의 좌표를 기록합니다.', diff --git a/BE/musicspot/src/journey/service/journey.service.ts b/BE/musicspot/src/journey/service/journey.service.ts index 072869a..f46bd65 100644 --- a/BE/musicspot/src/journey/service/journey.service.ts +++ b/BE/musicspot/src/journey/service/journey.service.ts @@ -1,191 +1,283 @@ -import { Injectable } from "@nestjs/common"; -import { JourneyRepository } from "../repository/journey.repository"; -import { StartJourneyReqDTO, StartJourneyResDTO } from '../dto/journeyStart/journeyStart.dto'; +import { Injectable } from '@nestjs/common'; +import { JourneyRepository } from '../repository/journey.repository'; +import { + StartJourneyReqDTO, + StartJourneyResDTO, +} from '../dto/journeyStart/journeyStart.dto'; import { JourneyNotFoundException, coordinateNotCorrectException, } from '../../filters/journey.exception'; -import { EndJourneyReqDTO, EndJourneyResDTO } from '../dto/journeyEnd/journeyEnd.dto'; -import { RecordJourneyReqDTO, RecordJourneyResDTO } from '../dto/journeyRecord/journeyRecord.dto'; -import { is1DArray, parseCoordinateFromGeoToDto, parseCoordinatesFromGeoToDto } from 'src/common/util/coordinate.util'; +import { + EndJourneyReqDTO, + EndJourneyResDTO, +} from '../dto/journeyEnd/journeyEnd.dto'; +import { + RecordJourneyReqDTO, + RecordJourneyResDTO, +} from '../dto/journeyRecord/journeyRecord.dto'; +import { + is1DArray, + parseCoordinateFromGeoToDto, + parseCoordinatesFromGeoToDto, +} from 'src/common/util/coordinate.util'; import { DeleteJourneyReqDTO } from '../dto/journeyDelete.dto'; import { UserRepository } from 'src/user/repository/user.repository'; import { Journey } from '../entities/journey.entity'; -import { makePresignedUrl } from "src/common/s3/objectStorage"; -import { parse } from "path"; +import { makePresignedUrl } from 'src/common/s3/objectStorage'; +import { parse } from 'path'; +import { + StartJourneyReqDTOV2, + StartJourneyResDTOV2, +} from '../dto/v2/startJourney.v2.dto'; +import { EndJourneyReqDTOV2 } from '../dto/v2/endJourney.v2.dto'; @Injectable() -export class JourneyService{ - constructor(private journeyRepository: JourneyRepository, private userRepository: UserRepository){} - - async insertJourneyData(startJourneyDTO:StartJourneyReqDTO){ - const startPoint = startJourneyDTO.coordinate.join(' '); - const lineStringOfCoordinates = `LINESTRING(${startPoint}, ${startPoint})` - - const returnedData = await this.journeyRepository.save({...startJourneyDTO, coordinates: lineStringOfCoordinates}) - - const [parsedCoordinate] = parseCoordinatesFromGeoToDto(returnedData.coordinates) - - const returnData:StartJourneyResDTO = { - journeyId : returnedData.journeyId, - coordinate : parsedCoordinate, - startTimestamp : returnedData.startTimestamp, - } - - return returnData; +export class JourneyService { + constructor( + private journeyRepository: JourneyRepository, + private userRepository: UserRepository, + ) {} + + async insertJourneyData(startJourneyDTO: StartJourneyReqDTO) { + const startPoint = startJourneyDTO.coordinate.join(' '); + const lineStringOfCoordinates = `LINESTRING(${startPoint}, ${startPoint})`; + + const returnedData = await this.journeyRepository.save({ + ...startJourneyDTO, + coordinates: lineStringOfCoordinates, + }); + + const [parsedCoordinate] = parseCoordinatesFromGeoToDto( + returnedData.coordinates, + ); + + const returnData: StartJourneyResDTO = { + journeyId: returnedData.journeyId, + coordinate: parsedCoordinate, + startTimestamp: returnedData.startTimestamp, + }; + + return returnData; + } + + async insertJourneyDataV2(startJourneyDTO: StartJourneyReqDTOV2) { + const returnedData = await this.journeyRepository.save(startJourneyDTO); + + const returnData: StartJourneyResDTOV2 = { + journeyId: returnedData.journeyId, + startTimestamp: returnedData.startTimestamp, + }; + + return returnData; + } + + async end(endJourneyDTO: EndJourneyReqDTO) { + const { coordinates, journeyId, song, title, endTimestamp } = endJourneyDTO; + const coordinatesLen = coordinates.length; + const originData = await this.journeyRepository.findOne({ + where: { journeyId }, + }); + if (!originData) { + throw new JourneyNotFoundException(); } - async end(endJourneyDTO: EndJourneyReqDTO){ - const {coordinates, journeyId, song, title, endTimestamp} = endJourneyDTO; - const coordinatesLen = coordinates.length; - const originData = await this.journeyRepository.findOne({where:{journeyId}}) - if(!originData){ - throw new JourneyNotFoundException(); - } - - - const originCoordinates =originData.coordinates; - const newCoordinates = originData.coordinates = originCoordinates.slice(0, -1) + ',' +endJourneyDTO.coordinates.map((item)=> `${item[0]} ${item[1]}`).join(',') + ')' - const newJourneyData = {...originData, ...endJourneyDTO, song : JSON.stringify(song), coordinates: newCoordinates}; - - const returnedDate = await this.journeyRepository.save(newJourneyData); - - const parsedCoordinates = parseCoordinatesFromGeoToDto(returnedDate.coordinates) - const returnData:EndJourneyResDTO = { - journeyId : returnedDate.journeyId, - coordinates : parsedCoordinates.slice(parsedCoordinates.length-coordinatesLen), - endTimestamp : returnedDate.endTimestamp, - numberOfCoordinates : parsedCoordinates.length, - song : JSON.parse(returnedDate.song) - } - - return returnData + const originCoordinates = originData.coordinates; + const newCoordinates = (originData.coordinates = + originCoordinates.slice(0, -1) + + ',' + + endJourneyDTO.coordinates + .map((item) => `${item[0]} ${item[1]}`) + .join(',') + + ')'); + const newJourneyData = { + ...originData, + ...endJourneyDTO, + song: JSON.stringify(song), + coordinates: newCoordinates, + }; + + const returnedDate = await this.journeyRepository.save(newJourneyData); + + const parsedCoordinates = parseCoordinatesFromGeoToDto( + returnedDate.coordinates, + ); + const returnData: EndJourneyResDTO = { + journeyId: returnedDate.journeyId, + coordinates: parsedCoordinates.slice( + parsedCoordinates.length - coordinatesLen, + ), + endTimestamp: returnedDate.endTimestamp, + numberOfCoordinates: parsedCoordinates.length, + song: JSON.parse(returnedDate.song), + }; + + return returnData; + } + async endV2(endJourneyDTO: EndJourneyReqDTOV2) { + const { coordinates, journeyId, song } = endJourneyDTO; + const coordinatesLen: number = coordinates.split(',').length; + const originalData = await this.journeyRepository.findOne({ + where: { journeyId }, + }); + if (!originalData) { + throw new JourneyNotFoundException(); } + const newCoordinates = `LINESTRING(${coordinates})`; + const newJourneyData = { + ...originalData, + ...endJourneyDTO, + song: JSON.stringify(song), + coordinates: newCoordinates, + }; + + const returnedDate = await this.journeyRepository.save(newJourneyData); + + const parsedCoordinates = parseCoordinatesFromGeoToDto( + returnedDate.coordinates, + ); + const returnData: EndJourneyResDTO = { + journeyId: returnedDate.journeyId, + coordinates: parsedCoordinates.slice( + parsedCoordinates.length - coordinatesLen, + ), + endTimestamp: returnedDate.endTimestamp, + numberOfCoordinates: parsedCoordinates.length, + song: JSON.parse(returnedDate.song), + }; + + return returnData; + } + async pushCoordianteToJourney(recordJourneyDTO: RecordJourneyReqDTO) { + const { journeyId, coordinates } = recordJourneyDTO; + const coordinateLen = coordinates.length; + const originData = await this.journeyRepository.findOne({ + where: { journeyId }, + }); + if (!originData) { + throw new JourneyNotFoundException(); + } + const originCoordinates = originData.coordinates; + + originData.coordinates = + originCoordinates.slice(0, -1) + + ',' + + recordJourneyDTO.coordinates + .map((item) => `${item[0]} ${item[1]}`) + .join(',') + + ')'; + const returnedData = await this.journeyRepository.save(originData); + + const updatedCoordinate = parseCoordinatesFromGeoToDto( + returnedData.coordinates, + ); + const len = updatedCoordinate.length; + + return { coordinates: updatedCoordinate.slice(len - coordinateLen) }; + } + + async getJourneyByCoordinationRange(checkJourneyDTO) { + let { userId, minCoordinate, maxCoordinate } = checkJourneyDTO; + if (!(Array.isArray(minCoordinate) && Array.isArray(maxCoordinate))) { + throw new coordinateNotCorrectException(); + } - async pushCoordianteToJourney(recordJourneyDTO: RecordJourneyReqDTO) { - - const {journeyId, coordinates} = recordJourneyDTO; - const coordinateLen = coordinates.length; - const originData = await this.journeyRepository.findOne({where:{journeyId}}); - if(!originData){ - throw new JourneyNotFoundException(); - } - const originCoordinates =originData.coordinates; - - - originData.coordinates = originCoordinates.slice(0, -1) + ',' +recordJourneyDTO.coordinates.map((item)=> `${item[0]} ${item[1]}`).join(',') + ')' - const returnedData = await this.journeyRepository.save(originData) - - const updatedCoordinate = parseCoordinatesFromGeoToDto(returnedData.coordinates); - const len = updatedCoordinate.length; + minCoordinate = minCoordinate.map((item) => Number(item)); + maxCoordinate = maxCoordinate.map((item) => Number(item)); - - return {coordinates:updatedCoordinate.slice(len-coordinateLen)} - + if (!(is1DArray(minCoordinate) && is1DArray(maxCoordinate))) { + throw new coordinateNotCorrectException(); + } + const coordinatesRange = { + xMinCoordinate: minCoordinate[0], + yMinCoordinate: minCoordinate[1], + xMaxCoordinate: maxCoordinate[0], + yMaxCoordinate: maxCoordinate[1], + }; + const returnedData = await this.journeyRepository.manager + .createQueryBuilder(Journey, 'journey') + .leftJoinAndSelect('journey.spots', 'spot') + .where( + `st_within(coordinates, ST_PolygonFromText('POLYGON((:xMinCoordinate :yMinCoordinate, :xMaxCoordinate :yMinCoordinate, :xMaxCoordinate :yMaxCoordinate, :xMinCoordinate :yMaxCoordinate, :xMinCoordinate :yMinCoordinate))'))`, + coordinatesRange, + ) + .where('userId = :userId', { userId }) + .getMany(); + + return returnedData.map((data) => { + return this.parseJourneyFromEntityToDto(data); + }); + } + + async getLastJourneyByUserId(userId) { + const journeys = await this.journeyRepository.manager + .createQueryBuilder(Journey, 'journey') + .where({ userId }) + .leftJoinAndSelect('journey.spots', 'spot') + .getMany(); + + if (!journeys) { + return { + journey: null, + isRecording: false, + }; } + const journeyLen = journeys.length; + const lastJourneyData = journeys[journeyLen - 1]; - - async getJourneyByCoordinationRange(checkJourneyDTO) { - let { userId, minCoordinate, maxCoordinate } = checkJourneyDTO; - if (!(Array.isArray(minCoordinate) && Array.isArray(maxCoordinate))) { - throw new coordinateNotCorrectException(); - } - - minCoordinate = minCoordinate.map((item) => Number(item)); - maxCoordinate = maxCoordinate.map((item) => Number(item)); - - if (!(is1DArray(minCoordinate) && is1DArray(maxCoordinate))) { - throw new coordinateNotCorrectException(); - } - const coordinatesRange = { - xMinCoordinate : minCoordinate[0], - yMinCoordinate : minCoordinate[1], - xMaxCoordinate : maxCoordinate[0], - yMaxCoordinate : maxCoordinate[1] - } - const returnedData = await this.journeyRepository.manager - .createQueryBuilder(Journey, "journey") - .leftJoinAndSelect("journey.spots", "spot") - .where(`st_within(coordinates, ST_PolygonFromText('POLYGON((:xMinCoordinate :yMinCoordinate, :xMaxCoordinate :yMinCoordinate, :xMaxCoordinate :yMaxCoordinate, :xMinCoordinate :yMaxCoordinate, :xMinCoordinate :yMinCoordinate))'))`, coordinatesRange) - .where('userId = :userId', {userId}) - .getMany(); - - return returnedData.map(data =>{ - return this.parseJourneyFromEntityToDto(data) - }) + if (lastJourneyData.title) { + return { journey: null, isRecording: false }; } - async getLastJourneyByUserId(userId){ - const journeys = await this.journeyRepository.manager - .createQueryBuilder(Journey, "journey") - .where({userId}) - .leftJoinAndSelect("journey.spots", "spot") - .getMany() - - if(!journeys){ + return { + journey: this.parseJourneyFromEntityToDto(lastJourneyData), + isRecording: true, + }; + } + + async getJourneyById(journeyId) { + const returnedData = await this.journeyRepository.manager + .createQueryBuilder(Journey, 'journey') + .where({ journeyId }) + .leftJoinAndSelect('journey.spots', 'spot') + .getOne(); + return this.parseJourneyFromEntityToDto(returnedData); + } + + parseJourneyFromEntityToDto(journey) { + const { + journeyId, + coordinates, + startTimestamp, + endTimestamp, + song, + title, + spots, + } = journey; + return { + journeyId, + coordinates: parseCoordinatesFromGeoToDto(coordinates), + title, + journeyMetadata: { + startTimestamp: journey.startTimestamp, + endTimestamp: journey.endTimestamp, + }, + song: JSON.parse(song), + spots: journey.spots.map((spot) => { return { - journey : null, - isRecording: false + ...spot, + coordinate: parseCoordinateFromGeoToDto(spot.coordinate), + photoUrl: makePresignedUrl(spot.photoKey), }; - } - - const journeyLen = journeys.length; - const lastJourneyData = journeys[journeyLen-1]; - - if(lastJourneyData.title){ - return {journey:null, isRecording : false} - } - - - return { - journey : this.parseJourneyFromEntityToDto(lastJourneyData), - isRecording : true - - - } - - - } - - async getJourneyById(journeyId) { - const returnedData = await this.journeyRepository.manager - .createQueryBuilder(Journey, "journey") - .where({journeyId}) - .leftJoinAndSelect("journey.spots", "spot") - .getOne() - return this.parseJourneyFromEntityToDto(returnedData); - - - } - - parseJourneyFromEntityToDto(journey){ - const {journeyId, coordinates, startTimestamp, endTimestamp, song, title, spots} = journey; - return { - journeyId, - coordinates : parseCoordinatesFromGeoToDto(coordinates), - title, - journeyMetadata : {startTimestamp : journey.startTimestamp, endTimestamp : journey.endTimestamp}, - song : JSON.parse(song), - spots : journey.spots.map(spot =>{ - return { - ...spot, - coordinate : parseCoordinateFromGeoToDto(spot.coordinate), - photoUrl : makePresignedUrl(spot.photoKey) - } - }) - - } - } - - async deleteJourneyById(deletedJourneyDto: DeleteJourneyReqDTO){ - const {journeyId} = deletedJourneyDto; - return await this.journeyRepository.delete({journeyId}) - } - + }), + }; + } + + async deleteJourneyById(deletedJourneyDto: DeleteJourneyReqDTO) { + const { journeyId } = deletedJourneyDto; + return await this.journeyRepository.delete({ journeyId }); + } } - - -