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