From 612292dada7c430e1ead1417ae21b33de0c7ab4b Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 10:58:19 +0300 Subject: [PATCH 01/46] added StatesGuard to providers --- src/app.module.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app.module.ts b/src/app.module.ts index 738a6c1..1d152d0 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -14,6 +14,7 @@ import { RolesGuard } from './shared/roles.guard'; import { TaskModule } from './task/task.module'; import { DrawModule } from './draw/draw.module'; import { FactionModule } from './faction/faction.module'; +import { StatesGuard } from './shared/states.guard'; @Module({ imports: [ @@ -40,6 +41,10 @@ import { FactionModule } from './faction/faction.module'; provide: APP_GUARD, useClass: RolesGuard, }, + { + provide: APP_GUARD, + useClass: StatesGuard, + }, ], }) export class AppModule { -- GitLab From e32f2386daed18009ab282b3d2166666c0bad92a Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 10:58:57 +0300 Subject: [PATCH 02/46] added GameStates guard --- src/draw/draw.controller.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/draw/draw.controller.ts b/src/draw/draw.controller.ts index 21306d7..10b8361 100644 --- a/src/draw/draw.controller.ts +++ b/src/draw/draw.controller.ts @@ -11,7 +11,7 @@ import { import { AuthGuard } from '../shared/auth.guard'; import { DrawService } from './draw.service'; -import { Roles } from '../shared/roles.decorator'; +import { Roles, GameStates } from '../shared/guard.decorator'; /* DrawController @@ -27,6 +27,7 @@ export class DrawController { @Put('mapdrawing/:id') @UsePipes(new ValidationPipe()) @Roles('admin', 'factionleader') + @GameStates('CREATED', 'STARTED') async draw(@Param('id') gameId, @Body() data) { return this.drawService.draw(gameId, data); } -- GitLab From 2fb3d2cc8c0a39ac1358e9dbcbc3c12b92319888 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 10:59:38 +0300 Subject: [PATCH 03/46] fixed import url --- src/faction/faction.controller.ts | 2 +- src/task/task.controller.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/faction/faction.controller.ts b/src/faction/faction.controller.ts index dec9308..734e9d8 100644 --- a/src/faction/faction.controller.ts +++ b/src/faction/faction.controller.ts @@ -21,7 +21,7 @@ import { JoinGameGroupDTO, } from './faction.dto'; import { FactionService } from './faction.service'; -import { Roles } from '../shared/roles.decorator'; +import { Roles } from '../shared/guard.decorator'; @Controller('faction') export class FactionController { diff --git a/src/task/task.controller.ts b/src/task/task.controller.ts index 2cb030f..acadbda 100644 --- a/src/task/task.controller.ts +++ b/src/task/task.controller.ts @@ -2,7 +2,7 @@ import { Controller, Post, Body, UsePipes, Get, Param } from '@nestjs/common'; import { TaskService } from './task.service'; import { CreateTaskDTO, EditTaskDTO } from './task.dto'; -import { Roles } from '../shared/roles.decorator'; +import { Roles } from '../shared/guard.decorator'; import { ValidationPipe } from '../shared/validation.pipe'; import { User } from '../user/user.decorator'; -- GitLab From 1b355c6e98efdbd0819683e6776906e26fa8c740 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 11:00:49 +0300 Subject: [PATCH 04/46] filename roles.* -> guard.* --- src/shared/{roles.decorator.ts => guard.decorator.ts} | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) rename src/shared/{roles.decorator.ts => guard.decorator.ts} (53%) diff --git a/src/shared/roles.decorator.ts b/src/shared/guard.decorator.ts similarity index 53% rename from src/shared/roles.decorator.ts rename to src/shared/guard.decorator.ts index 0d14223..b299d6d 100644 --- a/src/shared/roles.decorator.ts +++ b/src/shared/guard.decorator.ts @@ -1,3 +1,6 @@ import { SetMetadata } from '@nestjs/common'; -export const Roles = (...roles: string[]) => SetMetadata('roles', roles); \ No newline at end of file +export const Roles = (...roles: string[]) => SetMetadata('roles', roles); + +export const GameStates = (...states: string[]) => + SetMetadata('states', states); -- GitLab From cbcf068cb645424e2a0f33204950beb25131c076 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 11:01:02 +0300 Subject: [PATCH 05/46] added guard for gamestate --- src/shared/states.guard.ts | 46 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/shared/states.guard.ts diff --git a/src/shared/states.guard.ts b/src/shared/states.guard.ts new file mode 100644 index 0000000..fb8a18f --- /dev/null +++ b/src/shared/states.guard.ts @@ -0,0 +1,46 @@ +import { + Injectable, + CanActivate, + ExecutionContext, + HttpException, + HttpStatus, +} from '@nestjs/common'; +import { Reflector } from '@nestjs/core'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { GameEntity } from '../game/game.entity'; + +@Injectable() +export class StatesGuard implements CanActivate { + constructor( + private readonly reflector: Reflector, + @InjectRepository(GameEntity) + private gameRepository: Repository<GameEntity>, + ) {} + + async canActivate(context: ExecutionContext): Promise<boolean> { + // get game states that are allowed access, identified by @GameStates('state') decorators in controllers + const states = this.reflector.get<string[]>('states', context.getHandler()); + console.log(states); + if (!states) { + return true; + } + const request = context.switchToHttp().getRequest(); + const gameId = request.params.id; + const gameRef = await this.gameRepository.findOne({ + id: gameId, + }); + // check that the gameState matches the criteria + if (gameRef && states.includes(gameRef.state)) { + return true; + } else { + throw new HttpException( + `Game is set to ${ + gameRef.state + }, operation only valid in states ${states.join(', ')}`, + HttpStatus.BAD_REQUEST, + ); + } + } +} -- GitLab From 21cbd659143dfb48a9228ff71b6dbebd2e03366d Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 11:01:26 +0300 Subject: [PATCH 06/46] added path&service for modifying gamestate --- src/game/game.controller.ts | 12 ++++++++++-- src/game/game.service.ts | 14 +++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts index 015baf9..f18eada 100644 --- a/src/game/game.controller.ts +++ b/src/game/game.controller.ts @@ -14,9 +14,9 @@ import { import { GameService } from './game.service'; import { AuthGuard } from '../shared/auth.guard'; import { User } from '../user/user.decorator'; -import { GameDTO, FlagboxEventDTO } from './game.dto'; +import { GameDTO, FlagboxEventDTO, GameStateDTO } from './game.dto'; import { ValidationPipe } from '../shared/validation.pipe'; -import { Roles } from '../shared/roles.decorator'; +import { Roles, GameStates } from '../shared/guard.decorator'; import { GameEntity } from './game.entity'; @Controller('game') @@ -32,11 +32,19 @@ export class GameController { @Put('edit/:id') @Roles('admin') + @GameStates('CREATED') @UsePipes(new ValidationPipe()) async editGame(@Param('id') id: string, @Body() body: GameDTO) { return this.gameservice.editGame(id, body); } + @Put('edit-state/:id') + @Roles('admin') + @UsePipes(new ValidationPipe()) + async updateGameState(@Param('id') id: string, @Body() body: GameStateDTO) { + return this.gameservice.updateGameStatus(body); + } + @Get('listgames') async listGames() { return this.gameservice.listGames(); diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 573bb22..e6b3d60 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -8,7 +8,7 @@ import { ObjectivePointEntity, ObjectivePoint_HistoryEntity, } from './game.entity'; -import { GameDTO, FlagboxEventDTO } from './game.dto'; +import { GameDTO, FlagboxEventDTO, GameStateDTO } from './game.dto'; import { PersonEntity } from '../user/user.entity'; import { FactionEntity } from '../faction/faction.entity'; import { NotificationGateway } from '../notifications/notifications.gateway'; @@ -39,6 +39,7 @@ export class GameService { } // else add the game to the database const game = await this.gameRepository.create(gameData); + game.state = 'CREATED'; await this.gameRepository.insert(game); // add gamePerson with role admin to the game const gamePerson = await this.game_PersonRepository.create({ @@ -112,6 +113,17 @@ export class GameService { }; } + async updateGameStatus(game: GameStateDTO) { + const updatedGame = await this.gameRepository.create(game); + await this.gameRepository.save(updatedGame); + // notify players about game state change + this.notificationGateway.server.emit(game.id, 'event update'); + return { + code: 200, + message: 'State was updated', + }; + } + async listFactions(game: GameEntity) { return this.factionRepository.find({ game }); } -- GitLab From dd64c997c98c33100599f0ecd5195f1c59209e83 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 11:01:36 +0300 Subject: [PATCH 07/46] added GameStateDTO --- src/game/game.dto.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts index 913b6c0..d41704a 100644 --- a/src/game/game.dto.ts +++ b/src/game/game.dto.ts @@ -9,6 +9,8 @@ import { Max, ValidateNested, Allow, + IsUUID, + IsIn, } from 'class-validator'; import { ObjectivePointEntity } from './game.entity'; @@ -68,6 +70,13 @@ export class newGameDTO { enddate: string; } +export class GameStateDTO { + @IsUUID('4') + id: string; + @IsIn(['CREATED', 'STARTED', 'PAUSED', 'ENDED']) + state: string; +} + export class FlagboxDTO { @IsString() @IsNotEmpty() -- GitLab From 695a876584546a662976000c12b46cee032a1088 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 11:01:45 +0300 Subject: [PATCH 08/46] added state to GameEntity --- src/game/game.entity.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/game/game.entity.ts b/src/game/game.entity.ts index 5f019e8..5ff35d5 100644 --- a/src/game/game.entity.ts +++ b/src/game/game.entity.ts @@ -25,6 +25,7 @@ export class GameEntity { @Column('json') center: CenterDTO; @Column({ type: 'json', nullable: true }) map: JSON; @Column({ type: 'json', nullable: true }) nodesettings?: NodeSettingsDTO; + @Column('text') state: string; @Column('timestamp') startdate: Timestamp; @Column('timestamp') enddate: Timestamp; -- GitLab From e4f076b2b96afd3ef376566edb1570bb0cd47fb0 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 13:11:59 +0300 Subject: [PATCH 09/46] added onDelete --- src/draw/coordinate.entity.ts | 4 +++- src/faction/faction.entity.ts | 12 +++++++++--- src/game/game.entity.ts | 12 +++++++++--- src/task/task.entity.ts | 8 ++++++-- 4 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/draw/coordinate.entity.ts b/src/draw/coordinate.entity.ts index 9cee16c..8f5c4e1 100644 --- a/src/draw/coordinate.entity.ts +++ b/src/draw/coordinate.entity.ts @@ -17,7 +17,9 @@ export class MapDrawingEntity { @Column({ type: 'json', nullable: true }) data: JSON; - @ManyToOne(type => FactionEntity, faction => faction.mapDrawings) + @ManyToOne(type => FactionEntity, faction => faction.mapDrawings, { + onDelete: 'CASCADE', + }) faction: FactionEntity; @ManyToOne(type => GameEntity, gameEntity => gameEntity.id) gameId: GameEntity; diff --git a/src/faction/faction.entity.ts b/src/faction/faction.entity.ts index 42f3aca..8bc7548 100644 --- a/src/faction/faction.entity.ts +++ b/src/faction/faction.entity.ts @@ -26,11 +26,15 @@ export class FactionEntity { @Column({ type: 'text' }) factionPassword: string; - @OneToMany(type => Game_PersonEntity, game_persons => game_persons.faction) + @OneToMany(type => Game_PersonEntity, game_persons => game_persons.faction, { + onDelete: 'SET NULL', + }) game_persons: Game_PersonEntity[]; @ManyToOne(type => GameEntity, game => game.factions) game: GameEntity; - @OneToMany(type => MapDrawingEntity, mapDrawings => mapDrawings.faction) + @OneToMany(type => MapDrawingEntity, mapDrawings => mapDrawings.faction, { + onDelete: 'CASCADE', + }) mapDrawings: MapDrawingEntity[]; factionObject() { @@ -102,6 +106,8 @@ export class GameGroupEntity { onDelete: 'CASCADE', }) players: Game_PersonEntity[]; - @ManyToOne(type => FactionEntity, faction => faction.factionId) + @ManyToOne(type => FactionEntity, faction => faction.factionId, { + onDelete: 'CASCADE', + }) faction: FactionEntity; } diff --git a/src/game/game.entity.ts b/src/game/game.entity.ts index 5ff35d5..c4f4e55 100644 --- a/src/game/game.entity.ts +++ b/src/game/game.entity.ts @@ -56,7 +56,9 @@ export class GameEntity { export class Game_PersonEntity { @PrimaryGeneratedColumn('uuid') gamepersonId: string; @Column({ type: 'text', nullable: true }) role: string; - @ManyToOne(type => FactionEntity, faction => faction.game_persons) + @ManyToOne(type => FactionEntity, faction => faction.game_persons, { + onDelete: 'SET NULL', + }) faction: FactionEntity; @ManyToOne(type => GameEntity, game => game.id) game: GameEntity; @@ -90,9 +92,13 @@ export class ObjectivePoint_HistoryEntity { @PrimaryGeneratedColumn('uuid') oP_HistoryId: string; @Column({ type: 'timestamp' }) oP_HistoryTimestamp: Timestamp; @Column('float') action: number; - @ManyToOne(type => FactionEntity, factionEntity => factionEntity.factionId) + @ManyToOne(type => FactionEntity, factionEntity => factionEntity.factionId, { + onDelete: 'CASCADE', + }) capture: FactionEntity; - @ManyToOne(type => FactionEntity, factionentity => factionentity.factionId) + @ManyToOne(type => FactionEntity, factionentity => factionentity.factionId, { + onDelete: 'CASCADE', + }) owner: FactionEntity; @ManyToOne( type => ObjectivePointEntity, diff --git a/src/task/task.entity.ts b/src/task/task.entity.ts index 85ee3c2..c8f7d62 100644 --- a/src/task/task.entity.ts +++ b/src/task/task.entity.ts @@ -16,9 +16,13 @@ export class TaskEntity { @Column({ type: 'text' }) taskDescription: string; @Column({ type: 'bool' }) taskIsActive: boolean; - @ManyToOne(type => FactionEntity, faction => faction.factionId) + @ManyToOne(type => FactionEntity, faction => faction.factionId, { + onDelete: 'CASCADE', + }) faction: FactionEntity; - @ManyToOne(type => FactionEntity, faction => faction.factionId) + @ManyToOne(type => FactionEntity, faction => faction.factionId, { + onDelete: 'CASCADE', + }) taskWinner: FactionEntity; @ManyToOne(type => GameEntity, game => game.id) @JoinColumn({ name: 'taskGame' }) -- GitLab From ecf9e6ea79fa5a79f7d33f5625351f65928a7f83 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 13:12:19 +0300 Subject: [PATCH 10/46] added optional factionId --- src/faction/faction.dto.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/faction/faction.dto.ts b/src/faction/faction.dto.ts index a5b9f04..0b65c47 100644 --- a/src/faction/faction.dto.ts +++ b/src/faction/faction.dto.ts @@ -7,14 +7,18 @@ import { IsNumber, Min, Max, + IsOptional, } from 'class-validator'; import { GameEntity } from '../game/game.entity'; -import { RoleValidation } from '../shared/custom-validation'; +import { RoleValidation, Uuid } from '../shared/custom-validation'; import { GameDTO } from '../game/game.dto'; import { FactionEntity, GameGroupEntity } from './faction.entity'; export class FactionDTO { + @IsOptional() + @IsUUID('4') + factionId?: string; @IsString() @IsNotEmpty() @Length(2, 31) -- GitLab From fa0faa538f9d721be03d1c76b6c20f6097dd011a Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 13:14:07 +0300 Subject: [PATCH 11/46] editgame faction bug wip --- src/game/game.controller.ts | 1 + src/game/game.dto.ts | 3 ++ src/game/game.service.ts | 59 ++++++++++++++++++++++--------------- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts index f18eada..7cd7a4f 100644 --- a/src/game/game.controller.ts +++ b/src/game/game.controller.ts @@ -35,6 +35,7 @@ export class GameController { @GameStates('CREATED') @UsePipes(new ValidationPipe()) async editGame(@Param('id') id: string, @Body() body: GameDTO) { + body.id = id; return this.gameservice.editGame(id, body); } diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts index d41704a..c09f42a 100644 --- a/src/game/game.dto.ts +++ b/src/game/game.dto.ts @@ -11,6 +11,7 @@ import { Allow, IsUUID, IsIn, + IsOptional, } from 'class-validator'; import { ObjectivePointEntity } from './game.entity'; @@ -20,6 +21,8 @@ import { CenterDTO, NodeSettingsDTO } from './game.json.dto'; import { Type } from 'class-transformer'; export class GameDTO { + @IsOptional() + id: string; @IsString() @IsNotEmpty() @Length(3, 30) diff --git a/src/game/game.service.ts b/src/game/game.service.ts index e6b3d60..8295866 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -55,32 +55,41 @@ export class GameService { } // edit already created game - async editGame(id: string, gameData: GameDTO) { + async editGame(id, gameData: GameDTO) { // checks if a game with the same name exists already if ( await this.gameRepository.findOne({ name: gameData.name, id: Not(id) }) ) { - throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST); + throw new HttpException( + 'Game with the same name already exists', + HttpStatus.BAD_REQUEST, + ); } // update game entry in db + let factions = await this.factionRepository.find({ game: id }); const updatedGame = await this.gameRepository.create(gameData); - updatedGame['id'] = id; const gameId = await this.gameRepository.save(updatedGame); - - // get all the factions that are associated with the game to deny duplicate entries - const factions = await this.factionRepository.find({ game: gameId }); - const factionNames = factions.map(({ factionName }) => factionName); - // add the factions to db + // delete removed factions + // update/insert factions if (gameData.factions) { - gameData.factions.map(async faction => { - if (!Object.values(factionNames).includes(faction.factionName)) { - let name = await this.factionRepository.create({ - ...faction, - game: gameId, - }); - await this.factionRepository.insert(name); + const factionNames = gameData.factions.map( + ({ factionName }) => factionName, + ); + const factionIds = gameData.factions.map(({ factionId }) => factionId); + factions.map(async faction => { + if (!factionNames.includes(faction.factionName)) { + await this.factionRepository.delete(faction); } }); + gameData.factions.map(async faction => { + let name = await this.factionRepository.create({ + ...faction, + game: gameId, + }); + await this.factionRepository.save(name); + }); + } else { + await this.factionRepository.delete({ game: id }); } // get old flagboxes to deny duplicate entries @@ -114,14 +123,18 @@ export class GameService { } async updateGameStatus(game: GameStateDTO) { - const updatedGame = await this.gameRepository.create(game); - await this.gameRepository.save(updatedGame); - // notify players about game state change - this.notificationGateway.server.emit(game.id, 'event update'); - return { - code: 200, - message: 'State was updated', - }; + const updatedGame = await this.gameRepository.findOne({ id: game.id }); + if (updatedGame) { + updatedGame.state = game.state; + await this.gameRepository.save(updatedGame); + // notify players about game state change + this.notificationGateway.server.emit(game.id, 'event update'); + return { + code: 200, + message: 'State was updated', + }; + } + throw new HttpException("Game doesn't exist", HttpStatus.BAD_REQUEST); } async listFactions(game: GameEntity) { -- GitLab From 35885d31820c12f73f72290455e3bcee033fe351 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 19:53:32 +0300 Subject: [PATCH 12/46] added optional uuid for flagboxDTO --- src/game/game.dto.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts index c09f42a..7b912b4 100644 --- a/src/game/game.dto.ts +++ b/src/game/game.dto.ts @@ -81,6 +81,9 @@ export class GameStateDTO { } export class FlagboxDTO { + @IsOptional() + @IsUUID('4') + objectivePointId: string; @IsString() @IsNotEmpty() @Length(7) -- GitLab From b88c2a0df2c1af18e6b96d330304f68143dcacc3 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Thu, 4 Jul 2019 19:53:52 +0300 Subject: [PATCH 13/46] fixed gamedit bug with duplicate factions/flagboxes --- src/game/game.service.ts | 51 ++++++++++++++++++++++------------------ 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 8295866..624ae20 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -65,22 +65,27 @@ export class GameService { HttpStatus.BAD_REQUEST, ); } - // update game entry in db + + // get factions that have been added previously let factions = await this.factionRepository.find({ game: id }); + // get flagboxes that have been added previously + let flagboxes = await this.objectivePointRepository.find({ + game: id, + }); + console.log(flagboxes); + // update game entry in db const updatedGame = await this.gameRepository.create(gameData); const gameId = await this.gameRepository.save(updatedGame); - // delete removed factions - // update/insert factions + // iterate factions if any were added if (gameData.factions) { - const factionNames = gameData.factions.map( - ({ factionName }) => factionName, - ); const factionIds = gameData.factions.map(({ factionId }) => factionId); + // delete all existing factions that are not in submitted data factions.map(async faction => { - if (!factionNames.includes(faction.factionName)) { + if (!factionIds.includes(faction.factionId)) { await this.factionRepository.delete(faction); } }); + // create / update factions present in the submitted data gameData.factions.map(async faction => { let name = await this.factionRepository.create({ ...faction, @@ -89,29 +94,29 @@ export class GameService { await this.factionRepository.save(name); }); } else { + // if no factions are present in data, delete all factions associated with the game await this.factionRepository.delete({ game: id }); } - // get old flagboxes to deny duplicate entries - const flagboxes = await this.objectivePointRepository.find({ - game: gameId, - }); - const flagboxIds = flagboxes.map( - ({ objectivePointDescription }) => objectivePointDescription, - ); // insert the flagboxes to db if (gameData.objective_points) { - gameData.objective_points.map(async flagbox => { - if ( - !Object.values(flagboxIds).includes(flagbox.objectivePointDescription) - ) { - let newFlagbox = await this.objectivePointRepository.create({ - ...flagbox, - game: gameId, - }); - await this.objectivePointRepository.insert(newFlagbox); + const flagboxIds = gameData.objective_points.map( + ({ objectivePointId }) => objectivePointId, + ); + flagboxes.map(async flagbox => { + if (!flagboxIds.includes(flagbox.objectivePointDescription)) { + await this.objectivePointRepository.delete(flagbox); } }); + gameData.objective_points.map(async flagbox => { + let newFlagbox = await this.objectivePointRepository.create({ + ...flagbox, + game: gameId, + }); + await this.objectivePointRepository.save(newFlagbox); + }); + } else { + await this.objectivePointRepository.delete({ game: id }); } // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY -- GitLab From fb6cceab71f6e6f014fa052142192ffd3e574016 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 08:15:42 +0300 Subject: [PATCH 14/46] added error for duplicate data --- src/game/game.service.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 624ae20..a6c20c4 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -66,13 +66,29 @@ export class GameService { ); } + // check for duplicate names in gameData + const factionNames = gameData.factions.map( + ({ factionName }) => factionName, + ); + const flagboxNodeIds = gameData.objective_points.map( + ({ objectivePointDescription }) => objectivePointDescription, + ); + if ( + new Set(factionNames).size !== factionNames.length || + new Set(flagboxNodeIds).size !== flagboxNodeIds.length + ) { + throw new HttpException( + 'No duplicate names allowed!', + HttpStatus.BAD_REQUEST, + ); + } + // get factions that have been added previously let factions = await this.factionRepository.find({ game: id }); // get flagboxes that have been added previously let flagboxes = await this.objectivePointRepository.find({ game: id, }); - console.log(flagboxes); // update game entry in db const updatedGame = await this.gameRepository.create(gameData); const gameId = await this.gameRepository.save(updatedGame); -- GitLab From 27729f77136c7c26791de424f48fadedf37dde5e Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 09:12:51 +0300 Subject: [PATCH 15/46] added TrackingModule --- src/app.module.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/app.module.ts b/src/app.module.ts index 1d152d0..6bf82e3 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -5,16 +5,17 @@ import { Connection } from 'typeorm'; import { AppController } from './app.controller'; import { AppService } from './app.service'; -import { UserModule } from './user/user.module'; -import { HttpErrorFilter } from './shared/http-error.filter'; -import { LoggingInterceptor } from './shared/logging.interceptor'; -import { NotificationModule } from './notifications/notifications.module'; -import { GameModule } from './game/game.module'; -import { RolesGuard } from './shared/roles.guard'; -import { TaskModule } from './task/task.module'; import { DrawModule } from './draw/draw.module'; import { FactionModule } from './faction/faction.module'; +import { GameModule } from './game/game.module'; +import { NotificationModule } from './notifications/notifications.module'; +import { RolesGuard } from './shared/roles.guard'; +import { LoggingInterceptor } from './shared/logging.interceptor'; import { StatesGuard } from './shared/states.guard'; +import { HttpErrorFilter } from './shared/http-error.filter'; +import { TaskModule } from './task/task.module'; +import { TrackingModule } from './tracking/tracking.module'; +import { UserModule } from './user/user.module'; @Module({ imports: [ @@ -25,6 +26,7 @@ import { StatesGuard } from './shared/states.guard'; TaskModule, DrawModule, FactionModule, + TrackingModule, ], controllers: [AppController], providers: [ -- GitLab From 903574f16d52041397fb6e002ce69040da146e92 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 09:13:08 +0300 Subject: [PATCH 16/46] merged Tracking --- src/draw/draw.service.ts | 3 +- src/tracking/tracking.controller.ts | 33 +++++++++++++++ src/tracking/tracking.dto.ts | 8 ++++ src/tracking/tracking.entity.ts | 10 +++++ src/tracking/tracking.module.ts | 14 +++++++ src/tracking/tracking.service.ts | 63 +++++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 src/tracking/tracking.controller.ts create mode 100644 src/tracking/tracking.dto.ts create mode 100644 src/tracking/tracking.entity.ts create mode 100644 src/tracking/tracking.module.ts create mode 100644 src/tracking/tracking.service.ts diff --git a/src/draw/draw.service.ts b/src/draw/draw.service.ts index 97556e6..ffa48d4 100644 --- a/src/draw/draw.service.ts +++ b/src/draw/draw.service.ts @@ -18,7 +18,8 @@ export class DrawService { if (data.mapDrawingId == null || data.mapDrawingId == '') { // luo uuden instanssin. - return this.mapDrawingRepository.insert(drawing)[0]; + const mapDrawing = await this.mapDrawingRepository.insert(drawing); + return mapDrawing.identifiers; } else { //päivittää mapDrawingin return await this.mapDrawingRepository.save(drawing); diff --git a/src/tracking/tracking.controller.ts b/src/tracking/tracking.controller.ts new file mode 100644 index 0000000..fdd8fb8 --- /dev/null +++ b/src/tracking/tracking.controller.ts @@ -0,0 +1,33 @@ +import { + Controller, + Post, + Param, + UseGuards, + UsePipes, + Body, +} from '@nestjs/common'; + +import { TrackingService } from './tracking.service'; +import { TrackingDTO } from './tracking.dto'; +import { User } from '../user/user.decorator'; +import { Roles, GameStates } from '../shared/guard.decorator'; +import { ValidationPipe } from '../shared/validation.pipe'; + +@Controller('tracking') +export class TrackingController { + constructor(private trackingservice: TrackingService) {} + + // inserts tracking data to the database + // :id is the id of the game + @Post('location/:id') + @Roles('soldier') + @GameStates('started') + @UsePipes(new ValidationPipe()) + async trackLocation( + @User('id') userId, + @Param('id') id, + @Body() trackdata: TrackingDTO, + ) { + return this.trackingservice.trackLocation(userId, id, trackdata); + } +} diff --git a/src/tracking/tracking.dto.ts b/src/tracking/tracking.dto.ts new file mode 100644 index 0000000..8dc949c --- /dev/null +++ b/src/tracking/tracking.dto.ts @@ -0,0 +1,8 @@ +import { Game_PersonEntity } from '../game/game.entity'; +import { Allow } from 'class-validator'; + +export class TrackingDTO { + @Allow() + data: JSON; + gamepersonId: Game_PersonEntity; +} diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts new file mode 100644 index 0000000..b312391 --- /dev/null +++ b/src/tracking/tracking.entity.ts @@ -0,0 +1,10 @@ +import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; +import { Game_PersonEntity } from '../game/game.entity'; + +@Entity('Tracking') +export class TrackingEntity { + @PrimaryGeneratedColumn('uuid') id: string; + @Column({ type: 'json', nullable: true }) data: JSON; + @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId) + gamepersonId: Game_PersonEntity; +} diff --git a/src/tracking/tracking.module.ts b/src/tracking/tracking.module.ts new file mode 100644 index 0000000..45b167f --- /dev/null +++ b/src/tracking/tracking.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { TrackingController } from './tracking.controller'; +import { TrackingService } from './tracking.service'; +import { TrackingEntity } from './tracking.entity'; +import { Game_PersonEntity } from '../game/game.entity'; + +@Module({ + imports: [TypeOrmModule.forFeature([TrackingEntity, Game_PersonEntity])], + controllers: [TrackingController], + providers: [TrackingService], +}) +export class TrackingModule {} diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts new file mode 100644 index 0000000..6dc01c1 --- /dev/null +++ b/src/tracking/tracking.service.ts @@ -0,0 +1,63 @@ +import { Injectable, HttpStatus, HttpException } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { Game_PersonEntity } from '../game/game.entity'; +import { TrackingEntity } from './tracking.entity'; +import { TrackingDTO } from './tracking.dto'; + +@Injectable() +export class TrackingService { + constructor( + @InjectRepository(TrackingEntity) + private trackingrepository: Repository<TrackingEntity>, + @InjectRepository(Game_PersonEntity) + private gamepersonrepository: Repository<Game_PersonEntity>, + ) {} + + async trackLocation(personId, gameId, trackdata: TrackingDTO) { + // find player + let gameperson = await this.gamepersonrepository.findOne({ + game: gameId, + person: personId, + }); + if (!gameperson) { + throw new HttpException( + 'You have not joined this game', + HttpStatus.BAD_REQUEST, + ); + } + let trackedperson = await this.trackingrepository.findOne({ + gamepersonId: gameperson, + }); + + // if player has pushed tracking data, update entry + if (trackedperson) { + //add coordinates + trackedperson.data['geometry']['coordinates'].push( + await this.mapFunction(trackdata.data['geometry']['coordinates']), + ); + //add timestamp + trackedperson.data['geometry']['properties']['time'].push( + new Date(Date.now()), + ); + + return await this.trackingrepository.save(trackedperson); + } else { + // first entry will be empty + // initialize coordinates + trackdata.data['geometry']['coordinates'] = []; + // initialize timestamp + trackdata.data['geometry']['properties']['time'] = []; + trackedperson = await this.trackingrepository.create(trackdata); + trackedperson.gamepersonId = gameperson; + return await this.trackingrepository.save(trackedperson); + } + } + + private async mapFunction(data): Promise<Number> { + return await data.map(type => { + return type; + }); + } +} -- GitLab From 0cb15cee4394e74d42bd9f2a4b53de586b1c4a26 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 09:13:24 +0300 Subject: [PATCH 17/46] added GameStates Guard --- src/faction/faction.controller.ts | 19 ++++++++++++++----- src/game/game.controller.ts | 1 + 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/faction/faction.controller.ts b/src/faction/faction.controller.ts index 734e9d8..98fcc85 100644 --- a/src/faction/faction.controller.ts +++ b/src/faction/faction.controller.ts @@ -21,7 +21,7 @@ import { JoinGameGroupDTO, } from './faction.dto'; import { FactionService } from './faction.service'; -import { Roles } from '../shared/guard.decorator'; +import { Roles, GameStates } from '../shared/guard.decorator'; @Controller('faction') export class FactionController { @@ -30,6 +30,7 @@ export class FactionController { // takes gameId from the url to verify user role @Post('create-group/:id') @Roles('soldier') + @GameStates('CREATED') @UsePipes(new ValidationPipe()) async createGroup( @User('id') person, @@ -50,6 +51,7 @@ export class FactionController { // takes gameId from the url to verify user role @Put('join-group/:id') @Roles('soldier') + @GameStates('CREATED') async joinGroup( @User('id') person, @Param('id') id, @@ -66,17 +68,24 @@ export class FactionController { // param game ID is passed to @Roles @Put('promote/:id') - @UseGuards(new AuthGuard()) - @UsePipes(new ValidationPipe()) @Roles('admin') + @GameStates('CREATED') + @UsePipes(new ValidationPipe()) promotePlayer(@Param('id') game, @Body() body: PromotePlayerDTO) { return this.factionservice.promotePlayer(body); } - @Put('join-faction') + // used to join a faction + // :id is the id of the game, and is needed for GameStates to check the state of the game + @Put('join-faction/:id') @UseGuards(new AuthGuard()) + @GameStates('CREATED') @UsePipes(new ValidationPipe()) - joinFaction(@User('id') person, @Body() data: JoinFactionDTO) { + joinFaction( + @User('id') person, + @Param('id') game, + @Body() data: JoinFactionDTO, + ) { return this.factionservice.joinFaction(person, data); } } diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts index 7cd7a4f..24d42bb 100644 --- a/src/game/game.controller.ts +++ b/src/game/game.controller.ts @@ -70,6 +70,7 @@ export class GameController { } @Post('flag/:id') + @GameStates('STARTED') async flagboxEvent(@Param('id') id: string, @Body() data: FlagboxEventDTO) { return this.gameservice.flagboxEvent(id, data); } -- GitLab From c4d3d1e11a767b5b76e6a2ba6828c02407615ab6 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 09:13:34 +0300 Subject: [PATCH 18/46] removed console.log --- src/shared/states.guard.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared/states.guard.ts b/src/shared/states.guard.ts index fb8a18f..4a4b5d4 100644 --- a/src/shared/states.guard.ts +++ b/src/shared/states.guard.ts @@ -22,7 +22,6 @@ export class StatesGuard implements CanActivate { async canActivate(context: ExecutionContext): Promise<boolean> { // get game states that are allowed access, identified by @GameStates('state') decorators in controllers const states = this.reflector.get<string[]>('states', context.getHandler()); - console.log(states); if (!states) { return true; } -- GitLab From 64532327beeaa689085aea5cc5ac0e0045a526cd Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 09:30:45 +0300 Subject: [PATCH 19/46] set correct GameStates --- src/tracking/tracking.controller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tracking/tracking.controller.ts b/src/tracking/tracking.controller.ts index fdd8fb8..9451cdc 100644 --- a/src/tracking/tracking.controller.ts +++ b/src/tracking/tracking.controller.ts @@ -21,7 +21,7 @@ export class TrackingController { // :id is the id of the game @Post('location/:id') @Roles('soldier') - @GameStates('started') + @GameStates('STARTED') @UsePipes(new ValidationPipe()) async trackLocation( @User('id') userId, -- GitLab From 18e42bf5c5a570520d1a72ec61f47fdd1ef57c3c Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 13:14:20 +0300 Subject: [PATCH 20/46] added response codes, appended relations --- src/task/task.service.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/task/task.service.ts b/src/task/task.service.ts index abada37..7719ebe 100644 --- a/src/task/task.service.ts +++ b/src/task/task.service.ts @@ -40,6 +40,7 @@ export class TaskService { 'new task', ); return { + code: 201, message: 'Task added', }; } @@ -63,6 +64,7 @@ export class TaskService { task.taskIsActive = false; await this.taskRepository.save(task); return { + code: 201, message: 'Task updated and closed', }; } @@ -78,21 +80,19 @@ export class TaskService { if (gamePerson.role == 'admin') { return await this.taskRepository.find({ where: { taskGame: taskGame }, - relations: ['faction'], + relations: ['faction', 'taskWinner'], }); } else { return await this.taskRepository.find({ - relations: ['faction'], + relations: ['faction', 'taskWinner'], where: [ { taskGame: taskGame, faction: gamePerson.faction.factionId, - taskIsActive: true, }, { taskGame: taskGame, faction: null, - taskIsActive: true, }, ], }); -- GitLab From c5a17c37bd3f370257ff7ae2de833996dfaa9eae Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 13:49:17 +0300 Subject: [PATCH 21/46] added path&service for verifying faction --- src/faction/faction.controller.ts | 7 +++++++ src/faction/faction.service.ts | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/faction/faction.controller.ts b/src/faction/faction.controller.ts index 98fcc85..7574d82 100644 --- a/src/faction/faction.controller.ts +++ b/src/faction/faction.controller.ts @@ -88,4 +88,11 @@ export class FactionController { ) { return this.factionservice.joinFaction(person, data); } + + // check if person belongs to a faction in a game + @Get('check-faction/:id') + @UseGuards(new AuthGuard()) + checkFaction(@User('id') userId, @Param('id') gameId) { + return this.factionservice.verifyUser(userId, gameId); + } } diff --git a/src/faction/faction.service.ts b/src/faction/faction.service.ts index 76242df..e6bec65 100644 --- a/src/faction/faction.service.ts +++ b/src/faction/faction.service.ts @@ -129,4 +129,19 @@ export class FactionService { }); return members; } + + async verifyUser(person, game) { + const gameperson = await this.game_PersonRepository.findOne({ + where: { person, game }, + relations: ['faction'], + }); + if (gameperson) { + return { + code: 200, + message: gameperson, + }; + } else { + throw new HttpException('No faction was found', HttpStatus.BAD_REQUEST); + } + } } -- GitLab From 7b38a20d79856ea601d542f9fb8eb760d220da76 Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 14:10:27 +0300 Subject: [PATCH 22/46] added DTOs for draw --- src/draw/draw.controller.ts | 7 ++++--- src/draw/draw.service.ts | 27 +++++++++++++++++---------- src/draw/mapdrawing.dto.ts | 33 +++++++++++++++++---------------- 3 files changed, 38 insertions(+), 29 deletions(-) diff --git a/src/draw/draw.controller.ts b/src/draw/draw.controller.ts index 10b8361..26f6cf8 100644 --- a/src/draw/draw.controller.ts +++ b/src/draw/draw.controller.ts @@ -12,6 +12,7 @@ import { import { AuthGuard } from '../shared/auth.guard'; import { DrawService } from './draw.service'; import { Roles, GameStates } from '../shared/guard.decorator'; +import { MapDrawingDTO, ReturnDrawingsDTO } from './mapdrawing.dto'; /* DrawController @@ -25,17 +26,17 @@ export class DrawController { constructor(private drawService: DrawService) {} @Put('mapdrawing/:id') - @UsePipes(new ValidationPipe()) @Roles('admin', 'factionleader') @GameStates('CREATED', 'STARTED') - async draw(@Param('id') gameId, @Body() data) { + @UsePipes(new ValidationPipe()) + async draw(@Param('id') gameId, @Body() data: MapDrawingDTO) { return this.drawService.draw(gameId, data); } @Get('map/:id') @UseGuards(new AuthGuard()) @UsePipes(new ValidationPipe()) - async drawMap(@Param('id') id, @Body() data) { + async drawMap(@Param('id') id, @Body() data: ReturnDrawingsDTO) { return this.drawService.drawMap(id, data); } } diff --git a/src/draw/draw.service.ts b/src/draw/draw.service.ts index ffa48d4..d5ddf23 100644 --- a/src/draw/draw.service.ts +++ b/src/draw/draw.service.ts @@ -3,6 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { MapDrawingEntity } from '../draw/coordinate.entity'; +import { MapDrawingDTO, ReturnDrawingsDTO } from './mapdrawing.dto'; @Injectable() export class DrawService { @@ -11,11 +12,9 @@ export class DrawService { private mapDrawingRepository: Repository<MapDrawingEntity>, ) {} - async draw(gameId, data: MapDrawingEntity) { + async draw(gameId, data: MapDrawingDTO) { data['gameId'] = gameId; - const drawing = await this.mapDrawingRepository.create(data); - if (data.mapDrawingId == null || data.mapDrawingId == '') { // luo uuden instanssin. const mapDrawing = await this.mapDrawingRepository.insert(drawing); @@ -27,13 +26,21 @@ export class DrawService { } // draw map based on game and - async drawMap(id, data: MapDrawingEntity) { - data['gameId'] = id; - data['drawingIsActive'] = true; - // get faction - const mapDrawings = await this.mapDrawingRepository.create(data); - + async drawMap(id, data: ReturnDrawingsDTO) { // return mapdrawings with given faction and gameid - return await this.mapDrawingRepository.find(mapDrawings); + return await this.mapDrawingRepository.find({ + where: [ + { + gameId: id, + faction: data.factionId, + drawingIsActive: true, + }, + { + gameId: id, + faction: null, + drawingIsActive: true, + }, + ], + }); } } diff --git a/src/draw/mapdrawing.dto.ts b/src/draw/mapdrawing.dto.ts index 03eca2d..98b2d5a 100644 --- a/src/draw/mapdrawing.dto.ts +++ b/src/draw/mapdrawing.dto.ts @@ -1,26 +1,27 @@ -import { IsUUID } from 'class-validator'; +import { IsUUID, IsOptional, IsBoolean, Allow } from 'class-validator'; -import { GameDTO } from '../game/game.dto'; -import { GameEntity, Game_PersonEntity } from '../game/game.entity'; import { FactionEntity } from '../faction/faction.entity'; -import { FactionDTO } from '../faction/faction.dto'; -import { MapDrawingEntity } from '../draw/coordinate.entity'; +import { GameEntity } from 'src/game/game.entity'; export class MapDrawingDTO { + @IsOptional() + @IsUUID('4') + mapDrawingId: string; + @Allow() data: JSON; - gameId: GameDTO; - faction?: FactionDTO; - isActive?: boolean; - validUntil?: string; + @IsOptional() + @IsUUID('4') + gameId: GameEntity; + @IsOptional() + @IsUUID('4') + faction?: FactionEntity; + @IsBoolean() + drawingIsActive?: boolean; + drawingValidTill?: string; } -export class DrawMapDTO { +export class ReturnDrawingsDTO { + @IsOptional() @IsUUID('4') - mapDrawingId: MapDrawingEntity; - - gameId: GameEntity; factionId: FactionEntity; - - gamepersonId: Game_PersonEntity; - data: JSON; } -- GitLab From e408ac59d443f843b0cb066a41b5d71f41a5c9a8 Mon Sep 17 00:00:00 2001 From: Samuli Virtapohja <l4721@student.jamk.fi> Date: Fri, 5 Jul 2019 15:32:31 +0300 Subject: [PATCH 23/46] baselogic for factionleader and admin added --- src/tracking/tracking.controller.ts | 8 ++++++++ src/tracking/tracking.entity.ts | 3 +++ src/tracking/tracking.service.ts | 17 +++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/tracking/tracking.controller.ts b/src/tracking/tracking.controller.ts index 9451cdc..8049173 100644 --- a/src/tracking/tracking.controller.ts +++ b/src/tracking/tracking.controller.ts @@ -5,6 +5,7 @@ import { UseGuards, UsePipes, Body, + Get, } from '@nestjs/common'; import { TrackingService } from './tracking.service'; @@ -30,4 +31,11 @@ export class TrackingController { ) { return this.trackingservice.trackLocation(userId, id, trackdata); } + + @Get('players/:id') + @Roles('admin', 'factionleader') + @GameStates('STARTED', 'PAUSED') + async getPlayerLocations(@User('id') userId, @Param('id') gameId) { + return this.trackingservice.getPlayers(userId, gameId); + } } diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts index b312391..e208b95 100644 --- a/src/tracking/tracking.entity.ts +++ b/src/tracking/tracking.entity.ts @@ -1,5 +1,6 @@ import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; import { Game_PersonEntity } from '../game/game.entity'; +import { FactionEntity } from 'src/faction/faction.entity'; @Entity('Tracking') export class TrackingEntity { @@ -7,4 +8,6 @@ export class TrackingEntity { @Column({ type: 'json', nullable: true }) data: JSON; @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId) gamepersonId: Game_PersonEntity; + @ManyToOne(type => FactionEntity, faction => faction.factionId) + faction: FactionEntity; } diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts index 6dc01c1..0d6994c 100644 --- a/src/tracking/tracking.service.ts +++ b/src/tracking/tracking.service.ts @@ -5,6 +5,7 @@ import { Repository } from 'typeorm'; import { Game_PersonEntity } from '../game/game.entity'; import { TrackingEntity } from './tracking.entity'; import { TrackingDTO } from './tracking.dto'; +import { FactionEntity } from '../faction/faction.entity'; @Injectable() export class TrackingService { @@ -55,6 +56,22 @@ export class TrackingService { } } + // get player data while game is running + async getPlayers(userId, gameId) { + // get gameperson + const gameperson = await this.gamepersonrepository.findOne({ + where: { person: userId, game: gameId }, + relations: ['faction'], + }); + + // if faction is not null, user is factionleader + if (gameperson.faction) { + return 'factionleader'; + } else { + return 'admin'; + } + } + private async mapFunction(data): Promise<Number> { return await data.map(type => { return type; -- GitLab From 4b1e2eee7691513caa311d3fe69a288d6f6f9253 Mon Sep 17 00:00:00 2001 From: Samuli Virtapohja <l4721@student.jamk.fi> Date: Fri, 5 Jul 2019 16:10:09 +0300 Subject: [PATCH 24/46] weekend --- src/tracking/tracking.entity.ts | 4 +++- src/tracking/tracking.service.ts | 10 ++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts index e208b95..f399824 100644 --- a/src/tracking/tracking.entity.ts +++ b/src/tracking/tracking.entity.ts @@ -1,5 +1,5 @@ import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; -import { Game_PersonEntity } from '../game/game.entity'; +import { Game_PersonEntity, GameEntity } from '../game/game.entity'; import { FactionEntity } from 'src/faction/faction.entity'; @Entity('Tracking') @@ -10,4 +10,6 @@ export class TrackingEntity { gamepersonId: Game_PersonEntity; @ManyToOne(type => FactionEntity, faction => faction.factionId) faction: FactionEntity; + @ManyToOne(type => GameEntity, game => game.id) + game: GameEntity; } diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts index 0d6994c..cb44c4f 100644 --- a/src/tracking/tracking.service.ts +++ b/src/tracking/tracking.service.ts @@ -64,10 +64,16 @@ export class TrackingService { relations: ['faction'], }); - // if faction is not null, user is factionleader + // if user , user is factionleader if (gameperson.faction) { - return 'factionleader'; + const playerdata = await this.trackingrepository.find({ + where: { faction: gameperson.faction }, + }); + return playerdata; } else { + const playerdata = await this.trackingrepository.find({ + where: { game: gameId }, + }); return 'admin'; } } -- GitLab From fddc4648a35282fd515b6734946bc4123926697e Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:39:44 +0300 Subject: [PATCH 25/46] added ScoreModule --- src/app.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app.module.ts b/src/app.module.ts index 2c2773b..f2c7b77 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -18,6 +18,7 @@ import { UserModule } from './user/user.module'; import { DrawModule } from './draw/draw.module'; import { FactionModule } from './faction/faction.module'; import { GameModule } from './game/game.module'; +import { ScoreModule } from './score/score.module'; @Module({ imports: [ @@ -29,6 +30,7 @@ import { GameModule } from './game/game.module'; DrawModule, FactionModule, TrackingModule, + ScoreModule, ], controllers: [AppController], providers: [ -- GitLab From 3606028ba573cfd1dd197acbc47a0b69ca2c5d4e Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:39:53 +0300 Subject: [PATCH 26/46] fixed import url --- src/draw/mapdrawing.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/draw/mapdrawing.dto.ts b/src/draw/mapdrawing.dto.ts index 98b2d5a..f7e7c78 100644 --- a/src/draw/mapdrawing.dto.ts +++ b/src/draw/mapdrawing.dto.ts @@ -1,7 +1,7 @@ import { IsUUID, IsOptional, IsBoolean, Allow } from 'class-validator'; import { FactionEntity } from '../faction/faction.entity'; -import { GameEntity } from 'src/game/game.entity'; +import { GameEntity } from '../game/game.entity'; export class MapDrawingDTO { @IsOptional() -- GitLab From d884e55fcf4b7ded1f33d515f3faef4f1055e3a8 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:40:06 +0300 Subject: [PATCH 27/46] moved score entity --- src/faction/faction.entity.ts | 10 ---------- src/score/score.entity.ts | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 src/score/score.entity.ts diff --git a/src/faction/faction.entity.ts b/src/faction/faction.entity.ts index 8bc7548..ba2fff0 100644 --- a/src/faction/faction.entity.ts +++ b/src/faction/faction.entity.ts @@ -83,16 +83,6 @@ export class FP_HistoryEntity { faction_PowerUp: Faction_PowerUpEntity; } -@Entity('Score') -export class ScoreEntity { - @PrimaryGeneratedColumn('uuid') scoreId: string; - @Column({ type: 'float' }) score: number; - @Column({ type: 'timestamp' }) scoreTimeStamp: Timestamp; - - @ManyToOne(type => FactionEntity, factionName => factionName.factionId) - faction: FactionEntity; -} - @Entity('GameGroup') export class GameGroupEntity { @PrimaryGeneratedColumn('uuid') id: string; diff --git a/src/score/score.entity.ts b/src/score/score.entity.ts new file mode 100644 index 0000000..58c8ec3 --- /dev/null +++ b/src/score/score.entity.ts @@ -0,0 +1,19 @@ +import { + Entity, + PrimaryGeneratedColumn, + Column, + ManyToOne, + Timestamp, + CreateDateColumn, +} from 'typeorm'; +import { FactionEntity } from '../faction/faction.entity'; + +@Entity('Score') +export class ScoreEntity { + @PrimaryGeneratedColumn('uuid') scoreId: string; + @Column({ type: 'float' }) score: number; + @CreateDateColumn({ type: 'timestamp' }) scoreTimeStamp: Timestamp; + + @ManyToOne(type => FactionEntity, factionName => factionName.factionId) + faction: string; +} -- GitLab From 4f4bc29c10f6b6bea971b064176cac70655d6406 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:40:38 +0300 Subject: [PATCH 28/46] updated flagbox owner logic --- src/game/game.dto.ts | 2 +- src/game/game.service.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts index 7b912b4..266a8b1 100644 --- a/src/game/game.dto.ts +++ b/src/game/game.dto.ts @@ -100,7 +100,7 @@ export class FlagboxEventDTO { @IsNumber() @Min(0) @Max(3) - owner: number; // owner = 0, => first entry in faction db, owner = 1, => second entry etc + owner: number; // owner = 0, => no owner, owner = 1, => first entry in faction db @IsNumber() @Min(0) @Max(3) diff --git a/src/game/game.service.ts b/src/game/game.service.ts index a6c20c4..64ae650 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -210,9 +210,10 @@ export class GameService { const eventUpdate = await this.objectivePoint_HistoryRepository.create({ oP_HistoryTimestamp: data.oP_HistoryTimestamp, action: data.action, - capture: factionRef[data.capture], - owner: factionRef[data.owner], - objective_point: objectiveRef, + // -1 as 0 means null + capture: data.capture !== 0 ? factionRef[data.capture - 1] : null, + owner: data.owner !== 0 ? factionRef[data.owner - 1] : null, + objective_point: objectiveRef.objectivePointId, }); await this.objectivePoint_HistoryRepository.insert(eventUpdate); // send flagbox event to flagbox subscribers -- GitLab From 7e4b891d378cfeddfb7fa35f2081dcec49274b95 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:40:58 +0300 Subject: [PATCH 29/46] documentation update --- src/shared/states.guard.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shared/states.guard.ts b/src/shared/states.guard.ts index 4a4b5d4..9e85e94 100644 --- a/src/shared/states.guard.ts +++ b/src/shared/states.guard.ts @@ -19,6 +19,8 @@ export class StatesGuard implements CanActivate { private gameRepository: Repository<GameEntity>, ) {} + // Checks the state for gameId and grants access if it matches the criteria + // allowed states are CREATED, STARTED, PAUSED, ENDED async canActivate(context: ExecutionContext): Promise<boolean> { // get game states that are allowed access, identified by @GameStates('state') decorators in controllers const states = this.reflector.get<string[]>('states', context.getHandler()); -- GitLab From 5222e2a9d336ba0dc38bd4290dfc9b77f75a503f Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:41:22 +0300 Subject: [PATCH 30/46] ObjectivePointEntity -> string --- src/game/game.entity.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/game/game.entity.ts b/src/game/game.entity.ts index c4f4e55..761a14b 100644 --- a/src/game/game.entity.ts +++ b/src/game/game.entity.ts @@ -104,5 +104,5 @@ export class ObjectivePoint_HistoryEntity { type => ObjectivePointEntity, objective_point => objective_point.objectivePointId, ) - objective_point: ObjectivePointEntity; + objective_point: string; } -- GitLab From 464925e2c3e9a7f95df4f1ad947ce5e508e005f8 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Fri, 5 Jul 2019 19:41:32 +0300 Subject: [PATCH 31/46] fixed score --- src/score/score.controller.ts | 29 +++++++++++ src/score/score.dto.ts | 10 ++++ src/score/score.module.ts | 25 ++++++++++ src/score/score.service.ts | 94 +++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 src/score/score.controller.ts create mode 100644 src/score/score.dto.ts create mode 100644 src/score/score.module.ts create mode 100644 src/score/score.service.ts diff --git a/src/score/score.controller.ts b/src/score/score.controller.ts new file mode 100644 index 0000000..554e061 --- /dev/null +++ b/src/score/score.controller.ts @@ -0,0 +1,29 @@ +import { Controller, Post, UsePipes, Body, Param, Get } from '@nestjs/common'; + +import { ValidationPipe } from '../shared/validation.pipe'; +import { ScoreService } from './score.service'; +import { ScoreDTO } from './score.dto'; +import { GameEntity } from '../game/game.entity'; +import { Roles, GameStates } from '../shared/guard.decorator'; + +@Controller('score') +export class ScoreController { + constructor(private scoreService: ScoreService) {} + + // adds score manually to Faction + // :id is gameId + @Post('add-score/:id') + @Roles('admin') + @GameStates('STARTED') + @UsePipes(new ValidationPipe()) + async addingScore(@Body() data: ScoreDTO, @Param('id') gameId: GameEntity) { + return this.scoreService.addScore(data, gameId); + } + + // temporary scoreTick path, :id is gameId + @Get('tick-score/:id') + @GameStates('STARTED') + async scoreTick(@Param('id') gameId: GameEntity) { + return this.scoreService.scoreTick(gameId); + } +} diff --git a/src/score/score.dto.ts b/src/score/score.dto.ts new file mode 100644 index 0000000..99955f5 --- /dev/null +++ b/src/score/score.dto.ts @@ -0,0 +1,10 @@ +import { IsNumber, Min, Max, IsUUID } from 'class-validator'; + +export class ScoreDTO { + @IsNumber() + @Min(1) + @Max(99) + score: number; + @IsUUID('4') + faction: string; +} diff --git a/src/score/score.module.ts b/src/score/score.module.ts new file mode 100644 index 0000000..7f7601d --- /dev/null +++ b/src/score/score.module.ts @@ -0,0 +1,25 @@ +import { Module } from '@nestjs/common'; +import { TypeOrmModule } from '@nestjs/typeorm'; + +import { ScoreController } from './score.controller'; +import { ScoreService } from './score.service'; +import { FactionEntity } from '../faction/faction.entity'; +import { + ObjectivePointEntity, + ObjectivePoint_HistoryEntity, +} from '../game/game.entity'; +import { ScoreEntity } from './score.entity'; + +@Module({ + imports: [ + TypeOrmModule.forFeature([ + ScoreEntity, + ObjectivePointEntity, + ObjectivePoint_HistoryEntity, + FactionEntity, + ]), + ], + controllers: [ScoreController], + providers: [ScoreService], +}) +export class ScoreModule {} diff --git a/src/score/score.service.ts b/src/score/score.service.ts new file mode 100644 index 0000000..0ecea91 --- /dev/null +++ b/src/score/score.service.ts @@ -0,0 +1,94 @@ +import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; +import { InjectRepository } from '@nestjs/typeorm'; +import { Repository } from 'typeorm'; + +import { FactionEntity } from '../faction/faction.entity'; +import { ScoreDTO } from './score.dto'; +import { + ObjectivePoint_HistoryEntity, + ObjectivePointEntity, + GameEntity, +} from '../game/game.entity'; +import { ScoreEntity } from './score.entity'; +import { map } from 'rxjs/operators'; + +@Injectable() +export class ScoreService { + constructor( + @InjectRepository(ScoreEntity) + private scoreRepository: Repository<ScoreEntity>, + @InjectRepository(ObjectivePointEntity) + private flagRepository: Repository<ObjectivePointEntity>, + @InjectRepository(ObjectivePoint_HistoryEntity) + private flagHistoryRepository: Repository<ObjectivePoint_HistoryEntity>, + @InjectRepository(FactionEntity) + private factionRepository: Repository<FactionEntity>, + ) {} + + async addScore(scoreData: ScoreDTO, gameId: GameEntity) { + // check if faction exists + const faction = await this.factionRepository.findOne({ + factionId: scoreData.faction, + }); + if (!faction) { + throw new HttpException('Faction was not found', HttpStatus.BAD_REQUEST); + } + // get the previous score and add it, if it exists + let lastScore = await this.scoreRepository.findOne({ + where: { faction: scoreData.faction }, + order: { scoreTimeStamp: 'DESC' }, + }); + if (lastScore) { + scoreData.score += lastScore.score; + } + // add the score for Faction + const newScore = await this.scoreRepository.create(scoreData); + await this.scoreRepository.insert(newScore); + return { + code: 201, + message: 'Score updated!', + }; + } + + async scoreTick(gameId) { + // get game's flagboxes + const flagboxes = await this.flagRepository.find({ game: gameId }); + // create an array of DTOs for adding score + let scoreData = []; + await Promise.all( + flagboxes.map(async box => { + // get the newest entry in history + let current = await this.flagHistoryRepository.findOne({ + where: { objective_point: box.objectivePointId }, + relations: ['owner'], + order: { oP_HistoryTimestamp: 'DESC' }, + }); + // if result was found, add score to the owner + if (current.owner) { + let index = await scoreData.findIndex( + i => i.faction === current.owner.factionId, + ); + index !== -1 + ? await (scoreData[index]['score'] += box.objectivePointMultiplier) + : await scoreData.push({ + score: box.objectivePointMultiplier, + faction: current.owner.factionId, + }); + } + }), + ); + scoreData.map(async data => { + await this.addScore(data, gameId); + }); + return { + code: 200, + message: 'Scores added', + }; + } +} // + +// Hae kaikki Objective pointit +// aja map funktio pelin objective pointteihin +// jokaisella objective point ID:llä hae historystä +// relaatio, missä uusin timestamp +// katso uusimmista history entrystä omistaja -- GitLab From 2fc46a052188e3e91a1f048a8ba64f0f4c2eadf5 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 14:44:24 +0300 Subject: [PATCH 32/46] added delete-task path&service --- src/task/task.controller.ts | 23 ++++++++++++++++++++--- src/task/task.service.ts | 15 ++++++++++++++- 2 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/task/task.controller.ts b/src/task/task.controller.ts index acadbda..8283ba5 100644 --- a/src/task/task.controller.ts +++ b/src/task/task.controller.ts @@ -1,7 +1,15 @@ -import { Controller, Post, Body, UsePipes, Get, Param } from '@nestjs/common'; +import { + Controller, + Post, + Body, + UsePipes, + Get, + Param, + Delete, +} from '@nestjs/common'; import { TaskService } from './task.service'; -import { CreateTaskDTO, EditTaskDTO } from './task.dto'; +import { CreateTaskDTO, EditTaskDTO, DeleteTaskDTO } from './task.dto'; import { Roles } from '../shared/guard.decorator'; import { ValidationPipe } from '../shared/validation.pipe'; import { User } from '../user/user.decorator'; @@ -28,7 +36,16 @@ export class TaskController { return this.taskService.editTask(data); } - // lists all the tasks for the game if user has game_person entry + // deletes a created task if the user has admin role in the game + // :id is the id of the game + @Delete('delete-task/:id') + @Roles('admin') + @UsePipes(new ValidationPipe()) + async deleteTask(@Param('id') id: string, @Body() data: DeleteTaskDTO) { + return this.taskService.deleteTask(data); + } + + // lists all the tasks for the game if the user has game_person entry // :id is the id of the game @Get('get-tasks/:id') @Roles('soldier', 'factionleader', 'admin') diff --git a/src/task/task.service.ts b/src/task/task.service.ts index 7719ebe..cf4fe3f 100644 --- a/src/task/task.service.ts +++ b/src/task/task.service.ts @@ -3,7 +3,7 @@ import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { TaskEntity } from './task.entity'; -import { CreateTaskDTO, EditTaskDTO } from './task.dto'; +import { CreateTaskDTO, EditTaskDTO, DeleteTaskDTO } from './task.dto'; import { FactionEntity } from '../faction/faction.entity'; import { Game_PersonEntity } from '../game/game.entity'; import { NotificationGateway } from '../notifications/notifications.gateway'; @@ -69,6 +69,18 @@ export class TaskService { }; } + async deleteTask(data: DeleteTaskDTO) { + const task = await this.taskRepository.findOne({ taskId: data.taskId }); + if (task) { + await this.taskRepository.delete({ taskId: task.taskId }); + return { + code: 200, + message: 'Task deleted', + }; + } + throw new HttpException('Task not found', HttpStatus.BAD_REQUEST); + } + async fetchTasks(user, taskGame) { const gamePerson = await this.gamePersonRepository.findOne({ where: { @@ -95,6 +107,7 @@ export class TaskService { faction: null, }, ], + order: { taskIsActive: 'DESC' }, }); } } -- GitLab From bd94e15195c0a0199768fb54aaa89953f64668e4 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 14:44:32 +0300 Subject: [PATCH 33/46] added delete-task dto --- src/task/task.dto.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/task/task.dto.ts b/src/task/task.dto.ts index a8830d7..a1576e7 100644 --- a/src/task/task.dto.ts +++ b/src/task/task.dto.ts @@ -36,3 +36,8 @@ export class EditTaskDTO { @IsUUID('4') taskGame: GameEntity; } + +export class DeleteTaskDTO { + @IsUUID('4') + taskId: string; +} -- GitLab From dcc8354bfaf392d6507762ecb6630225a0ea10ee Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 15:22:37 +0300 Subject: [PATCH 34/46] added onDelete --- src/draw/coordinate.entity.ts | 20 ++++++++++++++++--- src/faction/faction.entity.ts | 18 ++++++++--------- src/game/game.entity.ts | 23 ++++++++++++++-------- src/notifications/notification.entity.ts | 25 +++++++++++++++++------- src/score/score.entity.ts | 4 +++- src/task/task.entity.ts | 4 +++- src/tracking/tracking.entity.ts | 4 +++- 7 files changed, 68 insertions(+), 30 deletions(-) diff --git a/src/draw/coordinate.entity.ts b/src/draw/coordinate.entity.ts index 8f5c4e1..ef5447f 100644 --- a/src/draw/coordinate.entity.ts +++ b/src/draw/coordinate.entity.ts @@ -21,7 +21,9 @@ export class MapDrawingEntity { onDelete: 'CASCADE', }) faction: FactionEntity; - @ManyToOne(type => GameEntity, gameEntity => gameEntity.id) + @ManyToOne(type => GameEntity, gameEntity => gameEntity.id, { + onDelete: 'CASCADE', + }) gameId: GameEntity; } @@ -30,8 +32,20 @@ export class Game_Person_MapDrawingEntity { @PrimaryGeneratedColumn('uuid') GPmapDrawingId: string; @Column({ type: 'timestamp' }) GPCTimeStamp: Timestamp; - @ManyToOne(type => Game_PersonEntity, game_person => game_person.gamepersonId) + @ManyToOne( + type => Game_PersonEntity, + game_person => game_person.gamepersonId, + { + onDelete: 'CASCADE', + }, + ) game_person: Game_PersonEntity; - @ManyToOne(type => MapDrawingEntity, map_drawing => map_drawing.mapDrawingId) + @ManyToOne( + type => MapDrawingEntity, + map_drawing => map_drawing.mapDrawingId, + { + onDelete: 'CASCADE', + }, + ) map_drawing: MapDrawingEntity; } diff --git a/src/faction/faction.entity.ts b/src/faction/faction.entity.ts index ba2fff0..3aa74cf 100644 --- a/src/faction/faction.entity.ts +++ b/src/faction/faction.entity.ts @@ -26,15 +26,13 @@ export class FactionEntity { @Column({ type: 'text' }) factionPassword: string; - @OneToMany(type => Game_PersonEntity, game_persons => game_persons.faction, { - onDelete: 'SET NULL', - }) + @OneToMany(type => Game_PersonEntity, game_persons => game_persons.faction) game_persons: Game_PersonEntity[]; - @ManyToOne(type => GameEntity, game => game.factions) - game: GameEntity; - @OneToMany(type => MapDrawingEntity, mapDrawings => mapDrawings.faction, { + @ManyToOne(type => GameEntity, game => game.factions, { onDelete: 'CASCADE', }) + game: GameEntity; + @OneToMany(type => MapDrawingEntity, mapDrawings => mapDrawings.faction) mapDrawings: MapDrawingEntity[]; factionObject() { @@ -47,7 +45,7 @@ export class FactionEntity { } } -@Entity('PowerUp') +/* @Entity('PowerUp') export class PowerUpEntity { @PrimaryGeneratedColumn('uuid') powerUpId: string; @Column({ type: 'text' }) powerUpName: string; @@ -55,7 +53,9 @@ export class PowerUpEntity { @Column({ type: 'int' }) amount: number; @Column({ type: 'time' }) cooldown: string; - @OneToMany(type => FactionEntity, factions => factions.factionId) + @OneToMany(type => FactionEntity, factions => factions.factionId, { + onDelete: 'CASCADE', + }) factions: Faction_PowerUpEntity[]; } @@ -81,7 +81,7 @@ export class FP_HistoryEntity { faction_PowerUp => faction_PowerUp.histories, ) faction_PowerUp: Faction_PowerUpEntity; -} +} */ @Entity('GameGroup') export class GameGroupEntity { diff --git a/src/game/game.entity.ts b/src/game/game.entity.ts index 761a14b..7ae6e29 100644 --- a/src/game/game.entity.ts +++ b/src/game/game.entity.ts @@ -57,19 +57,19 @@ export class Game_PersonEntity { @PrimaryGeneratedColumn('uuid') gamepersonId: string; @Column({ type: 'text', nullable: true }) role: string; @ManyToOne(type => FactionEntity, faction => faction.game_persons, { - onDelete: 'SET NULL', + onDelete: 'CASCADE', }) faction: FactionEntity; - @ManyToOne(type => GameEntity, game => game.id) + @ManyToOne(type => GameEntity, game => game.id, { + onDelete: 'CASCADE', + }) game: GameEntity; @ManyToOne(type => PersonEntity, person => person.id) person: PersonEntity; - @OneToOne(type => GameGroupEntity, group => group.leader, { - onDelete: 'CASCADE', - }) + @OneToOne(type => GameGroupEntity, group => group.leader) leaderGroup: GameGroupEntity; @ManyToOne(type => GameGroupEntity, group => group.players, { - onDelete: 'CASCADE', + onDelete: 'NO ACTION', }) @JoinColumn({ name: 'group' }) group: GameGroupEntity; @@ -81,9 +81,13 @@ export class ObjectivePointEntity { @Column({ type: 'text' }) objectivePointDescription: string; @Column({ type: 'float' }) objectivePointMultiplier: number; - @ManyToOne(type => MapDrawingEntity, coordinate => coordinate.data) + @ManyToOne(type => MapDrawingEntity, coordinate => coordinate.data, { + onDelete: 'CASCADE', + }) coordinate: MapDrawingEntity; - @ManyToOne(type => GameEntity, game => game.objective_points) + @ManyToOne(type => GameEntity, game => game.objective_points, { + onDelete: 'CASCADE', + }) game: GameEntity; } @@ -103,6 +107,9 @@ export class ObjectivePoint_HistoryEntity { @ManyToOne( type => ObjectivePointEntity, objective_point => objective_point.objectivePointId, + { + onDelete: 'CASCADE', + }, ) objective_point: string; } diff --git a/src/notifications/notification.entity.ts b/src/notifications/notification.entity.ts index 3f87816..3df76ac 100644 --- a/src/notifications/notification.entity.ts +++ b/src/notifications/notification.entity.ts @@ -1,11 +1,22 @@ -import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn } from "typeorm"; +import { + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + ManyToOne, +} from 'typeorm'; + +import { GameEntity } from '../game/game.entity'; // temporary table for warning notifications @Entity('Notifications') export class NotificationEntity { - @PrimaryGeneratedColumn('uuid') id: string; - @Column({type: 'text'}) message: string; - @CreateDateColumn() issued: Date; - // TODO: - // when game creation has been implemented, add logic so that the notifications are tied to games -} \ No newline at end of file + @PrimaryGeneratedColumn('uuid') id: string; + @Column({ type: 'text' }) message: string; + @CreateDateColumn() issued: Date; + + @ManyToOne(type => GameEntity, game => game.id, { + onDelete: 'CASCADE', + }) + game: GameEntity; +} diff --git a/src/score/score.entity.ts b/src/score/score.entity.ts index 58c8ec3..6ca9ab7 100644 --- a/src/score/score.entity.ts +++ b/src/score/score.entity.ts @@ -14,6 +14,8 @@ export class ScoreEntity { @Column({ type: 'float' }) score: number; @CreateDateColumn({ type: 'timestamp' }) scoreTimeStamp: Timestamp; - @ManyToOne(type => FactionEntity, factionName => factionName.factionId) + @ManyToOne(type => FactionEntity, factionName => factionName.factionId, { + onDelete: 'CASCADE', + }) faction: string; } diff --git a/src/task/task.entity.ts b/src/task/task.entity.ts index c8f7d62..f1c1cf1 100644 --- a/src/task/task.entity.ts +++ b/src/task/task.entity.ts @@ -24,7 +24,9 @@ export class TaskEntity { onDelete: 'CASCADE', }) taskWinner: FactionEntity; - @ManyToOne(type => GameEntity, game => game.id) + @ManyToOne(type => GameEntity, game => game.id, { + onDelete: 'CASCADE', + }) @JoinColumn({ name: 'taskGame' }) taskGame: GameEntity; } diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts index b312391..cabe141 100644 --- a/src/tracking/tracking.entity.ts +++ b/src/tracking/tracking.entity.ts @@ -5,6 +5,8 @@ import { Game_PersonEntity } from '../game/game.entity'; export class TrackingEntity { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'json', nullable: true }) data: JSON; - @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId) + @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId, { + onDelete: 'CASCADE', + }) gamepersonId: Game_PersonEntity; } -- GitLab From 01da9d6fb9d452fe9e00ce6585ecd59a6b68fb91 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 15:22:49 +0300 Subject: [PATCH 35/46] added delete-game path --- src/game/game.controller.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts index 24d42bb..8d7494b 100644 --- a/src/game/game.controller.ts +++ b/src/game/game.controller.ts @@ -9,6 +9,7 @@ import { Put, UseInterceptors, ClassSerializerInterceptor, + Delete, } from '@nestjs/common'; import { GameService } from './game.service'; @@ -39,6 +40,13 @@ export class GameController { return this.gameservice.editGame(id, body); } + @Delete('delete/:id') + @Roles('admin') + @GameStates('CREATED') + async deleteGame(@Param('id') id: string) { + return this.gameservice.deleteGame(id); + } + @Put('edit-state/:id') @Roles('admin') @UsePipes(new ValidationPipe()) -- GitLab From 4aa0c47ca783f5e6dd9311a663d0ff413c41d3a3 Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 16:10:19 +0300 Subject: [PATCH 36/46] added socket-notifs --- src/game/game.service.ts | 6 ++++-- src/score/score.service.ts | 4 +++- src/task/task.service.ts | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 64ae650..5027c6e 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -149,7 +149,9 @@ export class GameService { updatedGame.state = game.state; await this.gameRepository.save(updatedGame); // notify players about game state change - this.notificationGateway.server.emit(game.id, 'event update'); + this.notificationGateway.server.emit(game.id, { + type: 'gamestate-update', + }); return { code: 200, message: 'State was updated', @@ -217,7 +219,7 @@ export class GameService { }); await this.objectivePoint_HistoryRepository.insert(eventUpdate); // send flagbox event to flagbox subscribers - this.notificationGateway.server.emit('flagbox', 'event update'); + this.notificationGateway.server.emit(gameId, { type: 'flagbox-event' }); return { code: 201, message: 'OK', diff --git a/src/score/score.service.ts b/src/score/score.service.ts index 0ecea91..9dad4e9 100644 --- a/src/score/score.service.ts +++ b/src/score/score.service.ts @@ -10,7 +10,7 @@ import { GameEntity, } from '../game/game.entity'; import { ScoreEntity } from './score.entity'; -import { map } from 'rxjs/operators'; +import { NotificationGateway } from '../notifications/notifications.gateway'; @Injectable() export class ScoreService { @@ -23,6 +23,7 @@ export class ScoreService { private flagHistoryRepository: Repository<ObjectivePoint_HistoryEntity>, @InjectRepository(FactionEntity) private factionRepository: Repository<FactionEntity>, + private notificationGateway: NotificationGateway, ) {} async addScore(scoreData: ScoreDTO, gameId: GameEntity) { @@ -80,6 +81,7 @@ export class ScoreService { scoreData.map(async data => { await this.addScore(data, gameId); }); + this.notificationGateway.server.emit(gameId, { type: 'score-update' }); return { code: 200, message: 'Scores added', diff --git a/src/task/task.service.ts b/src/task/task.service.ts index cf4fe3f..eedef60 100644 --- a/src/task/task.service.ts +++ b/src/task/task.service.ts @@ -36,8 +36,8 @@ export class TaskService { // notify subscribers about a new task // if faction was set it notifies only faction members, else everyone this.notificationGateway.server.emit( - task.faction != null ? task.faction.toString() : 'global', - 'new task', + task.faction != null ? task.faction.toString() : task.taskGame.toString(), + { type: 'task-update' }, ); return { code: 201, -- GitLab From 7d7e44bf5e351c8f7562b170b2025cecb3ac1a8f Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 16:10:35 +0300 Subject: [PATCH 37/46] added notificationDTO --- src/notifications/notification.dto.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/notifications/notification.dto.ts diff --git a/src/notifications/notification.dto.ts b/src/notifications/notification.dto.ts new file mode 100644 index 0000000..807af14 --- /dev/null +++ b/src/notifications/notification.dto.ts @@ -0,0 +1,12 @@ +import { IsString, Length, IsUUID, IsIn } from 'class-validator'; + +export class NotificationdDTO { + // alert is for serious messages, note is for smaller updates on a situation + @IsIn(['alert', 'note']) + type: string; + @IsString() + @Length(0, 63) + message: string; + @IsUUID('4') + game: string; +} -- GitLab From 095178e006fc9c35c2e144643ff51478914dcc8c Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 16:11:20 +0300 Subject: [PATCH 38/46] added column type --- src/notifications/notification.entity.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/notifications/notification.entity.ts b/src/notifications/notification.entity.ts index 3df76ac..f9d5dca 100644 --- a/src/notifications/notification.entity.ts +++ b/src/notifications/notification.entity.ts @@ -12,11 +12,12 @@ import { GameEntity } from '../game/game.entity'; @Entity('Notifications') export class NotificationEntity { @PrimaryGeneratedColumn('uuid') id: string; + @Column('text') type: string; @Column({ type: 'text' }) message: string; @CreateDateColumn() issued: Date; @ManyToOne(type => GameEntity, game => game.id, { onDelete: 'CASCADE', }) - game: GameEntity; + game: string; } -- GitLab From 97cbe2b8abb8965db452b08dc0317ae97f5dc9cf Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 16:11:44 +0300 Subject: [PATCH 39/46] tied notifications to gameIds --- src/notifications/notifications.gateway.ts | 28 ++++++++++++++-------- src/notifications/notifications.module.ts | 3 ++- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/notifications/notifications.gateway.ts b/src/notifications/notifications.gateway.ts index c301148..5e952d6 100644 --- a/src/notifications/notifications.gateway.ts +++ b/src/notifications/notifications.gateway.ts @@ -6,12 +6,15 @@ import { OnGatewayConnection, OnGatewayDisconnect, } from '@nestjs/websockets'; -import { Logger } from '@nestjs/common'; +import { Logger, UsePipes } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Server, Socket } from 'socket.io'; import { Repository } from 'typeorm'; import { NotificationEntity } from './notification.entity'; +import { GameEntity } from '../game/game.entity'; +import { NotificationdDTO } from './notification.dto'; +import { ValidationPipe } from '../shared/validation.pipe'; @WebSocketGateway() export class NotificationGateway @@ -20,6 +23,8 @@ export class NotificationGateway //create references to tables as repositories @InjectRepository(NotificationEntity) private notificationRepository: Repository<NotificationEntity>, + @InjectRepository(GameEntity) + private gameRepository: Repository<GameEntity>, ) {} @WebSocketServer() server: Server; @@ -40,14 +45,17 @@ export class NotificationGateway } // notifications for when game needs to be paused / stopped - @SubscribeMessage('shutItDown') - async handleMessage(client: Socket, text: string) { - this.logger.log(text); - // send the message to all clients listening to warningToPlayers branch - this.server.emit('warningToPlayers', text); - // create entity properties - const message = await this.notificationRepository.create({ message: text }); - // insert created entity NOTE: insert method doesn't check for duplicates. - await this.notificationRepository.insert(message); + @SubscribeMessage('game-info') + @UsePipes(new ValidationPipe()) + async handleMessage(client: Socket, data: NotificationdDTO) { + // check if the game exists and is either started or paused + const game = await this.gameRepository.findOne({ id: data.game }); + if (game && ['STARTED', 'PAUSED'].includes(game.state)) { + // send the message to all clients listening to gameId branch + this.server.emit(data.game, data); + // create entry for notification in db + const message = await this.notificationRepository.create(data); + await this.notificationRepository.insert(message); + } } } diff --git a/src/notifications/notifications.module.ts b/src/notifications/notifications.module.ts index 194c5c3..41e2fca 100644 --- a/src/notifications/notifications.module.ts +++ b/src/notifications/notifications.module.ts @@ -3,9 +3,10 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { NotificationGateway } from './notifications.gateway'; import { NotificationEntity } from './notification.entity'; +import { GameEntity } from '../game/game.entity'; @Module({ - imports: [TypeOrmModule.forFeature([NotificationEntity])], + imports: [TypeOrmModule.forFeature([NotificationEntity, GameEntity])], providers: [NotificationGateway], exports: [NotificationGateway], }) -- GitLab From 6882961c37fcf2d9282b206a4b2cd365b50e04cd Mon Sep 17 00:00:00 2001 From: Ronnie Friman <L4168@student.jamk.fi> Date: Sat, 6 Jul 2019 16:11:54 +0300 Subject: [PATCH 40/46] import notificationModule --- src/score/score.module.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/score/score.module.ts b/src/score/score.module.ts index 7f7601d..c04486f 100644 --- a/src/score/score.module.ts +++ b/src/score/score.module.ts @@ -9,6 +9,7 @@ import { ObjectivePoint_HistoryEntity, } from '../game/game.entity'; import { ScoreEntity } from './score.entity'; +import { NotificationModule } from '../notifications/notifications.module'; @Module({ imports: [ @@ -18,6 +19,7 @@ import { ScoreEntity } from './score.entity'; ObjectivePoint_HistoryEntity, FactionEntity, ]), + NotificationModule, ], controllers: [ScoreController], providers: [ScoreService], -- GitLab From f9b2e98e73e56873e8f745c68ff68fc3d48c7f40 Mon Sep 17 00:00:00 2001 From: Samuli Virtapohja <l4721@student.jamk.fi> Date: Mon, 8 Jul 2019 10:27:00 +0300 Subject: [PATCH 41/46] add get players --- src/faction/faction.controller.ts | 2 +- src/tracking/tracking.service.ts | 31 ++++++++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/src/faction/faction.controller.ts b/src/faction/faction.controller.ts index 98fcc85..82e29d3 100644 --- a/src/faction/faction.controller.ts +++ b/src/faction/faction.controller.ts @@ -79,7 +79,7 @@ export class FactionController { // :id is the id of the game, and is needed for GameStates to check the state of the game @Put('join-faction/:id') @UseGuards(new AuthGuard()) - @GameStates('CREATED') + @GameStates('CREATED', 'STARTED') @UsePipes(new ValidationPipe()) joinFaction( @User('id') person, diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts index cb44c4f..fb4eab0 100644 --- a/src/tracking/tracking.service.ts +++ b/src/tracking/tracking.service.ts @@ -19,8 +19,8 @@ export class TrackingService { async trackLocation(personId, gameId, trackdata: TrackingDTO) { // find player let gameperson = await this.gamepersonrepository.findOne({ - game: gameId, - person: personId, + where: { game: gameId, person: personId }, + relations: ['faction'], }); if (!gameperson) { throw new HttpException( @@ -51,6 +51,8 @@ export class TrackingService { // initialize timestamp trackdata.data['geometry']['properties']['time'] = []; trackedperson = await this.trackingrepository.create(trackdata); + trackedperson.faction = gameperson.faction; + trackedperson.game = gameId; trackedperson.gamepersonId = gameperson; return await this.trackingrepository.save(trackedperson); } @@ -64,18 +66,33 @@ export class TrackingService { relations: ['faction'], }); - // if user , user is factionleader + let playerdata; + // get playerdata if (gameperson.faction) { - const playerdata = await this.trackingrepository.find({ + playerdata = await this.trackingrepository.find({ where: { faction: gameperson.faction }, + relations: ['faction', 'gamepersonId'], }); - return playerdata; } else { - const playerdata = await this.trackingrepository.find({ + playerdata = await this.trackingrepository.find({ where: { game: gameId }, + relations: ['faction', 'gamepersonId'], }); - return 'admin'; } + + // parse data + const currentdata = await Promise.all( + playerdata.map(async player => { + return { + gamepersonId: player['gamepersonId']['gamepersonId'], + gamepersonRole: player['gamepersonId']['role'], + factionId: player['faction']['factionId'], + coordinates: player['data']['geometry']['coordinates'].pop(), + }; + }), + ); + + return currentdata; } private async mapFunction(data): Promise<Number> { -- GitLab From 903e1f202fc0add9c6b8674922bd70a59ce2701d Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Mon, 8 Jul 2019 13:06:18 +0300 Subject: [PATCH 42/46] fix join-faction bug --- src/faction/faction.service.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/faction/faction.service.ts b/src/faction/faction.service.ts index e6bec65..014188e 100644 --- a/src/faction/faction.service.ts +++ b/src/faction/faction.service.ts @@ -35,7 +35,12 @@ export class FactionService { person: person, }); //check if user is already in a faction - if (await this.game_PersonRepository.findOne(gameperson)) { + if ( + await this.game_PersonRepository.findOne({ + person: person, + game: faction.game, + }) + ) { throw new HttpException( 'You have already joined faction!', HttpStatus.BAD_REQUEST, -- GitLab From e1d08665a71fc3f93e79628f3662979ba5a907aa Mon Sep 17 00:00:00 2001 From: L4168 <L4168@student.jamk.fi> Date: Mon, 8 Jul 2019 13:23:40 +0300 Subject: [PATCH 43/46] removed codes from response objects --- src/faction/faction.service.ts | 3 --- src/game/game.service.ts | 5 ----- src/score/score.service.ts | 2 -- src/task/task.service.ts | 3 --- 4 files changed, 13 deletions(-) diff --git a/src/faction/faction.service.ts b/src/faction/faction.service.ts index 014188e..67edef1 100644 --- a/src/faction/faction.service.ts +++ b/src/faction/faction.service.ts @@ -99,7 +99,6 @@ export class FactionService { await this.game_PersonRepository.save(gamePerson); return { - code: 201, message: 'created new group', }; } @@ -119,7 +118,6 @@ export class FactionService { gamePerson.group = data.groupId; await this.game_PersonRepository.save(gamePerson); return { - code: 200, message: 'Joined group', }; } @@ -142,7 +140,6 @@ export class FactionService { }); if (gameperson) { return { - code: 200, message: gameperson, }; } else { diff --git a/src/game/game.service.ts b/src/game/game.service.ts index 5027c6e..3f6506b 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -49,7 +49,6 @@ export class GameService { }); await this.game_PersonRepository.insert(gamePerson); return { - code: 201, message: 'New game added', }; } @@ -138,7 +137,6 @@ export class GameService { // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY return { - code: 200, message: 'Game updated', }; } @@ -153,7 +151,6 @@ export class GameService { type: 'gamestate-update', }); return { - code: 200, message: 'State was updated', }; } @@ -168,7 +165,6 @@ export class GameService { // TODO: Delete factions from Faction table associated with the deleted game await this.gameRepository.delete({ id }); return { - code: 200, message: 'Game deleted', }; } @@ -221,7 +217,6 @@ export class GameService { // send flagbox event to flagbox subscribers this.notificationGateway.server.emit(gameId, { type: 'flagbox-event' }); return { - code: 201, message: 'OK', }; } diff --git a/src/score/score.service.ts b/src/score/score.service.ts index 9dad4e9..aed5535 100644 --- a/src/score/score.service.ts +++ b/src/score/score.service.ts @@ -46,7 +46,6 @@ export class ScoreService { const newScore = await this.scoreRepository.create(scoreData); await this.scoreRepository.insert(newScore); return { - code: 201, message: 'Score updated!', }; } @@ -83,7 +82,6 @@ export class ScoreService { }); this.notificationGateway.server.emit(gameId, { type: 'score-update' }); return { - code: 200, message: 'Scores added', }; } diff --git a/src/task/task.service.ts b/src/task/task.service.ts index eedef60..d79338e 100644 --- a/src/task/task.service.ts +++ b/src/task/task.service.ts @@ -40,7 +40,6 @@ export class TaskService { { type: 'task-update' }, ); return { - code: 201, message: 'Task added', }; } @@ -64,7 +63,6 @@ export class TaskService { task.taskIsActive = false; await this.taskRepository.save(task); return { - code: 201, message: 'Task updated and closed', }; } @@ -74,7 +72,6 @@ export class TaskService { if (task) { await this.taskRepository.delete({ taskId: task.taskId }); return { - code: 200, message: 'Task deleted', }; } -- GitLab From 8e92a18ed6c34d3770c0907a55598d22d4ebde63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Syd=C3=A4nmaa?= <L4072@student.jamk.fi> Date: Tue, 9 Jul 2019 08:12:47 +0300 Subject: [PATCH 44/46] getScore works --- src/score/score.controller.ts | 7 +++++++ src/score/score.service.ts | 25 +++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/src/score/score.controller.ts b/src/score/score.controller.ts index 554e061..73fda22 100644 --- a/src/score/score.controller.ts +++ b/src/score/score.controller.ts @@ -26,4 +26,11 @@ export class ScoreController { async scoreTick(@Param('id') gameId: GameEntity) { return this.scoreService.scoreTick(gameId); } + + // shows scores, :id is gameId + @Get('get-score/:id') + @GameStates('STARTED') + async getScores(@Param('id') gameId: GameEntity) { + return this.scoreService.getScores(gameId); + } } diff --git a/src/score/score.service.ts b/src/score/score.service.ts index 9dad4e9..625ca7a 100644 --- a/src/score/score.service.ts +++ b/src/score/score.service.ts @@ -87,6 +87,31 @@ export class ScoreService { message: 'Scores added', }; } + + async getScores(gameId: GameEntity) { + // find games factions + const factions = await this.factionRepository.find({ + where: {game: gameId,}, + relations: ['game'], + }); + let scores = []; + await Promise.all( + factions.map(async factionNow => { + let score = await this.scoreRepository.findOne({ + where: {faction: factionNow}, + relations: ['faction'], + order: {scoreTimeStamp: 'DESC'}, + }); + //if score was found, put info to scores array + if (score.faction) { + let index = await scores.findIndex( + i => i.faction === score.faction, + ); + scores.push(score); + } + })) + return scores; + } } // // Hae kaikki Objective pointit -- GitLab From 6c3eba9eec50359d0d795ffc4fd91fc5510a0e34 Mon Sep 17 00:00:00 2001 From: Samuli Virtapohja <l4721@student.jamk.fi> Date: Tue, 9 Jul 2019 10:23:35 +0300 Subject: [PATCH 45/46] change tracking format --- src/tracking/tracking.controller.ts | 2 +- src/tracking/tracking.service.ts | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tracking/tracking.controller.ts b/src/tracking/tracking.controller.ts index 8049173..35b4cdb 100644 --- a/src/tracking/tracking.controller.ts +++ b/src/tracking/tracking.controller.ts @@ -29,7 +29,7 @@ export class TrackingController { @Param('id') id, @Body() trackdata: TrackingDTO, ) { - return this.trackingservice.trackLocation(userId, id, trackdata); + return this.trackingservice.trackLocation(userId, id, trackdata[0]); } @Get('players/:id') diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts index fb4eab0..532e7a7 100644 --- a/src/tracking/tracking.service.ts +++ b/src/tracking/tracking.service.ts @@ -39,9 +39,7 @@ export class TrackingService { await this.mapFunction(trackdata.data['geometry']['coordinates']), ); //add timestamp - trackedperson.data['geometry']['properties']['time'].push( - new Date(Date.now()), - ); + trackedperson.data['properties']['time'].push(new Date(Date.now())); return await this.trackingrepository.save(trackedperson); } else { @@ -49,7 +47,7 @@ export class TrackingService { // initialize coordinates trackdata.data['geometry']['coordinates'] = []; // initialize timestamp - trackdata.data['geometry']['properties']['time'] = []; + trackdata.data['properties']['time'] = []; trackedperson = await this.trackingrepository.create(trackdata); trackedperson.faction = gameperson.faction; trackedperson.game = gameId; -- GitLab From e144ac5272dfe31984c4b0eebf7063ca03ed7b78 Mon Sep 17 00:00:00 2001 From: Samuli Virtapohja <l4721@student.jamk.fi> Date: Tue, 9 Jul 2019 13:34:21 +0300 Subject: [PATCH 46/46] reformat trackdata, change getplayers --- src/tracking/geo.dto.ts | 14 ++++++++++++++ src/tracking/tracking.controller.ts | 5 +++-- src/tracking/tracking.dto.ts | 10 ++++++---- src/tracking/tracking.entity.ts | 4 +++- src/tracking/tracking.service.ts | 29 +++++++++++++++-------------- 5 files changed, 41 insertions(+), 21 deletions(-) create mode 100644 src/tracking/geo.dto.ts diff --git a/src/tracking/geo.dto.ts b/src/tracking/geo.dto.ts new file mode 100644 index 0000000..352faf7 --- /dev/null +++ b/src/tracking/geo.dto.ts @@ -0,0 +1,14 @@ +import { IsNumber, Min, Max, Allow } from 'class-validator'; + +export class GeoDTO { + @IsNumber() + @Min(-90) + @Max(90) + lat: number; + @IsNumber() + @Min(-180) + @Max(180) + lng: number; + @Allow() + time: number; +} diff --git a/src/tracking/tracking.controller.ts b/src/tracking/tracking.controller.ts index 35b4cdb..ca0e79e 100644 --- a/src/tracking/tracking.controller.ts +++ b/src/tracking/tracking.controller.ts @@ -13,6 +13,7 @@ import { TrackingDTO } from './tracking.dto'; import { User } from '../user/user.decorator'; import { Roles, GameStates } from '../shared/guard.decorator'; import { ValidationPipe } from '../shared/validation.pipe'; +import { GeoDTO } from './geo.dto'; @Controller('tracking') export class TrackingController { @@ -27,9 +28,9 @@ export class TrackingController { async trackLocation( @User('id') userId, @Param('id') id, - @Body() trackdata: TrackingDTO, + @Body() trackdata: GeoDTO, ) { - return this.trackingservice.trackLocation(userId, id, trackdata[0]); + return this.trackingservice.trackLocation(userId, id, trackdata); } @Get('players/:id') diff --git a/src/tracking/tracking.dto.ts b/src/tracking/tracking.dto.ts index 8dc949c..81cc715 100644 --- a/src/tracking/tracking.dto.ts +++ b/src/tracking/tracking.dto.ts @@ -1,8 +1,10 @@ import { Game_PersonEntity } from '../game/game.entity'; -import { Allow } from 'class-validator'; +import { Allow, ValidateNested } from 'class-validator'; +import { GeoDTO } from './geo.dto'; +import { Type } from 'class-transformer'; export class TrackingDTO { - @Allow() - data: JSON; - gamepersonId: Game_PersonEntity; + @ValidateNested() + @Type(() => GeoDTO) + data: GeoDTO; } diff --git a/src/tracking/tracking.entity.ts b/src/tracking/tracking.entity.ts index 7af1ca4..c2699a0 100644 --- a/src/tracking/tracking.entity.ts +++ b/src/tracking/tracking.entity.ts @@ -1,11 +1,13 @@ import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm'; import { Game_PersonEntity, GameEntity } from '../game/game.entity'; import { FactionEntity } from 'src/faction/faction.entity'; +import { GeoDTO } from './geo.dto'; @Entity('Tracking') export class TrackingEntity { @PrimaryGeneratedColumn('uuid') id: string; - @Column({ type: 'json', nullable: true }) data: JSON; + @Column({ type: 'json', nullable: true }) data: GeoDTO[]; + @ManyToOne(type => Game_PersonEntity, person => person.gamepersonId, { onDelete: 'CASCADE', }) diff --git a/src/tracking/tracking.service.ts b/src/tracking/tracking.service.ts index 532e7a7..9941256 100644 --- a/src/tracking/tracking.service.ts +++ b/src/tracking/tracking.service.ts @@ -6,6 +6,8 @@ import { Game_PersonEntity } from '../game/game.entity'; import { TrackingEntity } from './tracking.entity'; import { TrackingDTO } from './tracking.dto'; import { FactionEntity } from '../faction/faction.entity'; +import { NotificationGateway } from 'src/notifications/notifications.gateway'; +import { GeoDTO } from './geo.dto'; @Injectable() export class TrackingService { @@ -16,7 +18,7 @@ export class TrackingService { private gamepersonrepository: Repository<Game_PersonEntity>, ) {} - async trackLocation(personId, gameId, trackdata: TrackingDTO) { + async trackLocation(personId, gameId, trackdata: GeoDTO) { // find player let gameperson = await this.gamepersonrepository.findOne({ where: { game: gameId, person: personId }, @@ -34,25 +36,24 @@ export class TrackingService { // if player has pushed tracking data, update entry if (trackedperson) { + trackdata['time'] = Date.now(); //add coordinates - trackedperson.data['geometry']['coordinates'].push( - await this.mapFunction(trackdata.data['geometry']['coordinates']), - ); + trackedperson.data.push(trackdata); //add timestamp - trackedperson.data['properties']['time'].push(new Date(Date.now())); - - return await this.trackingrepository.save(trackedperson); + await this.trackingrepository.save(trackedperson); + return { code: 201, message: 'Location updated!' }; } else { // first entry will be empty - // initialize coordinates - trackdata.data['geometry']['coordinates'] = []; - // initialize timestamp - trackdata.data['properties']['time'] = []; - trackedperson = await this.trackingrepository.create(trackdata); + trackdata['time'] = Date.now(); + // initialize data + trackedperson = await this.trackingrepository.create(trackedperson); + trackedperson.data = [trackdata]; trackedperson.faction = gameperson.faction; trackedperson.game = gameId; trackedperson.gamepersonId = gameperson; - return await this.trackingrepository.save(trackedperson); + await this.trackingrepository.save(trackedperson); + + return { code: 201, message: 'Entry Created!' }; } } @@ -85,7 +86,7 @@ export class TrackingService { gamepersonId: player['gamepersonId']['gamepersonId'], gamepersonRole: player['gamepersonId']['role'], factionId: player['faction']['factionId'], - coordinates: player['data']['geometry']['coordinates'].pop(), + coordinates: player['data'].pop(), }; }), ); -- GitLab