From 0f66478a8e4e4f9ec43500c3c5095989b3abbc81 Mon Sep 17 00:00:00 2001
From: Samuli Virtapohja <l4721@student.jamk.fi>
Date: Fri, 28 Jun 2019 14:31:15 +0300
Subject: [PATCH] draw

---
 ormconfig.json                  |   8 +--
 package-lock.json               | 116 +-------------------------------
 src/draw/draw.controller.ts     |  32 ++++-----
 src/draw/draw.module.ts         |   9 ++-
 src/draw/draw.service.ts        |  43 ++++++------
 src/draw/mapdrawing.dto.ts      |  15 +++++
 src/game/game.controller.ts     |  16 +++--
 src/game/game.dto.ts            |  22 +++++-
 src/game/game.service.ts        |  10 +--
 src/shared/custom-validation.ts |  32 +++++++++
 10 files changed, 139 insertions(+), 164 deletions(-)
 create mode 100644 src/shared/custom-validation.ts

diff --git a/ormconfig.json b/ormconfig.json
index bb6b5fa..2e27168 100644
--- a/ormconfig.json
+++ b/ormconfig.json
@@ -1,10 +1,10 @@
 {
   "type": "postgres",
   "host": "localhost",
-  "port": 5432,
-  "username": "ehasa",
-  "password": "salasana",
-  "database": "ehasa",
+  "port": 5444,
+  "username": "postgres",
+  "password": "mysecretpassword",
+  "database": "test",
   "entities": ["src/**/*.entity{.ts,.js}"],
   "synchronize": true,
   "logging": true,
diff --git a/package-lock.json b/package-lock.json
index 53a606c..fd2af0d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1450,11 +1450,6 @@
       "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz",
       "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
     },
-    "bluebird": {
-      "version": "3.5.5",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
-      "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
-    },
     "body-parser": {
       "version": "1.19.0",
       "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
@@ -1906,15 +1901,6 @@
         "wrap-ansi": "^2.0.0"
       }
     },
-    "cls-bluebird": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz",
-      "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=",
-      "requires": {
-        "is-bluebird": "^1.0.2",
-        "shimmer": "^1.1.0"
-      }
-    },
     "co": {
       "version": "4.6.0",
       "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
@@ -2397,11 +2383,6 @@
       "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.2.0.tgz",
       "integrity": "sha512-HygQCKUBSFl8wKQZBSemMywRWcEDNidvNbjGVyZu3nbZ8qq9ubiPoGLMdRDpfSrpkkm9BXYFkpKxxFX38o/76w=="
     },
-    "dottie": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.1.tgz",
-      "integrity": "sha512-ch5OQgvGDK2u8pSZeSYAQaV/lczImd7pMJ7BcEPXmnFVjy4yJIzP6CsODJUTH8mg1tyH1Z2abOiuJO3DjZ/GBw=="
-    },
     "double-ended-queue": {
       "version": "2.1.0-0",
       "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz",
@@ -4020,11 +4001,6 @@
       "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
       "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
     },
-    "inflection": {
-      "version": "1.12.0",
-      "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz",
-      "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY="
-    },
     "inflight": {
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
@@ -4088,11 +4064,6 @@
         "binary-extensions": "^1.0.0"
       }
     },
-    "is-bluebird": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz",
-      "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI="
-    },
     "is-buffer": {
       "version": "1.1.6",
       "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
@@ -5145,7 +5116,8 @@
     "lodash": {
       "version": "4.17.11",
       "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
-      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
+      "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==",
+      "dev": true
     },
     "lodash.includes": {
       "version": "4.3.0",
@@ -5443,19 +5415,6 @@
         "minimist": "0.0.8"
       }
     },
-    "moment": {
-      "version": "2.24.0",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
-      "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
-    },
-    "moment-timezone": {
-      "version": "0.5.25",
-      "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.25.tgz",
-      "integrity": "sha512-DgEaTyN/z0HFaVcVbSyVCUU6HeFdnNC3vE4c9cgu2dgMTvjBUBdBzWfasTBmAW45u5OIMeCJtU8yNjM22DHucw==",
-      "requires": {
-        "moment": ">= 2.9.0"
-      }
-    },
     "ms": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
@@ -6553,14 +6512,6 @@
       "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
       "dev": true
     },
-    "retry-as-promised": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz",
-      "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==",
-      "requires": {
-        "any-promise": "^1.3.0"
-      }
-    },
     "rimraf": {
       "version": "2.6.3",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
@@ -6689,51 +6640,6 @@
         }
       }
     },
-    "sequelize": {
-      "version": "5.8.7",
-      "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-5.8.7.tgz",
-      "integrity": "sha512-1rubZM8fAyCt5ipyS+3HJ3Jbmb8WesLdPJ3jIbTD+78EbuPZILFEA5fK0mliVRBx7oM7oPULeVX0lxSRXBV1jw==",
-      "requires": {
-        "bluebird": "^3.5.0",
-        "cls-bluebird": "^2.1.0",
-        "debug": "^4.1.1",
-        "dottie": "^2.0.0",
-        "inflection": "1.12.0",
-        "lodash": "^4.17.11",
-        "moment": "^2.24.0",
-        "moment-timezone": "^0.5.21",
-        "retry-as-promised": "^3.1.0",
-        "semver": "^5.6.0",
-        "sequelize-pool": "^1.0.2",
-        "toposort-class": "^1.0.1",
-        "uuid": "^3.2.1",
-        "validator": "^10.11.0",
-        "wkx": "^0.4.6"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "4.1.1",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
-          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "validator": {
-          "version": "10.11.0",
-          "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz",
-          "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw=="
-        }
-      }
-    },
-    "sequelize-pool": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-1.0.2.tgz",
-      "integrity": "sha512-VMKl/gCCdIvB1gFZ7p+oqLFEyZEz3oMMYjkKvfEC7GoO9bBcxmfOOU9RdkoltfXGgBZFigSChihRly2gKtsh2w==",
-      "requires": {
-        "bluebird": "^3.5.3"
-      }
-    },
     "serve-static": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
@@ -6797,11 +6703,6 @@
       "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==",
       "dev": true
     },
-    "shimmer": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz",
-      "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="
-    },
     "signal-exit": {
       "version": "3.0.2",
       "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
@@ -7555,11 +7456,6 @@
         }
       }
     },
-    "toposort-class": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
-      "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg="
-    },
     "touch": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
@@ -8256,14 +8152,6 @@
         "string-width": "^2.1.1"
       }
     },
-    "wkx": {
-      "version": "0.4.6",
-      "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.6.tgz",
-      "integrity": "sha512-LHxXlzRCYQXA9ZHgs8r7Gafh0gVOE8o3QmudM1PIkOdkXXjW7Thcl+gb2P2dRuKgW8cqkitCRZkkjtmWzpHi7A==",
-      "requires": {
-        "@types/node": "*"
-      }
-    },
     "wordwrap": {
       "version": "0.0.3",
       "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
diff --git a/src/draw/draw.controller.ts b/src/draw/draw.controller.ts
index b271409..19b9d27 100644
--- a/src/draw/draw.controller.ts
+++ b/src/draw/draw.controller.ts
@@ -7,14 +7,17 @@ import {
   UsePipes,
   ValidationPipe,
   Body,
+  Delete,
 } from '@nestjs/common';
 import { AuthGuard } from 'src/shared/auth.guard';
 import { DrawService } from './draw.service';
-import { MapDrawingDTO } from './mapdrawing.dto';
+import { MapDrawingDTO, DrawMapDTO } from './mapdrawing.dto';
 import { Roles } from 'src/shared/roles.decorator';
 import { User } from 'src/user/user.decorator';
 import { FactionDTO } from 'src/game/game.dto';
 import { FactionEntity } from 'src/game/faction.entity';
+import { async } from 'rxjs/internal/scheduler/async';
+import { Game_PersonEntity } from 'src/game/game.entity';
 /*
       DrawController
   
@@ -26,25 +29,22 @@ import { FactionEntity } from 'src/game/faction.entity';
 export class DrawController {
   constructor(private drawService: DrawService) {}
 
-  @Put()
-  @UseGuards(new AuthGuard())
+  @Put('mapdrawing/:id')
   @UsePipes(new ValidationPipe())
-  async draw(@Body() data: MapDrawingDTO) {
-    try {
-      return this.drawService.draw(data);
-    } catch (error) {
-      return error.message;
-    }
+  @Roles('admin', 'factionleader')
+  async draw(@Param('id') gameId, @Body() data) {
+    return this.drawService.draw(gameId, data);
   }
 
-  @Get(':id')
+  @Get('map/:id')
   @UseGuards(new AuthGuard())
   @UsePipes(new ValidationPipe())
-  async drawMap(@Param('id') id: string, @Body() faction: FactionDTO) {
-    try {
-      return this.drawService.drawMap(id, faction);
-    } catch (error) {
-      return error.message;
-    }
+  async drawMap(@Param('id') id, @Body() data) {
+    return this.drawService.drawMap(id, data);
   }
+
+  @Put('location')
+  @UseGuards(new AuthGuard())
+  @UsePipes(new ValidationPipe())
+  async trackLocation() {}
 }
diff --git a/src/draw/draw.module.ts b/src/draw/draw.module.ts
index 34390bf..7f4ef3a 100644
--- a/src/draw/draw.module.ts
+++ b/src/draw/draw.module.ts
@@ -5,12 +5,19 @@ import { DrawController } from './draw.controller';
 import { DrawService } from './draw.service';
 import { MapDrawingEntity } from 'src/game/coordinate.entity';
 import { FactionEntity } from 'src/game/faction.entity';
+import { Game_PersonEntity } from 'src/game/game.entity';
 /*
 Draw
 - contains everything to do with mapdrawing data.
 */
 @Module({
-  imports: [TypeOrmModule.forFeature([MapDrawingEntity, FactionEntity])],
+  imports: [
+    TypeOrmModule.forFeature([
+      MapDrawingEntity,
+      FactionEntity,
+      Game_PersonEntity,
+    ]),
+  ],
   controllers: [DrawController],
   providers: [DrawService],
 })
diff --git a/src/draw/draw.service.ts b/src/draw/draw.service.ts
index f00c48d..2d983c5 100644
--- a/src/draw/draw.service.ts
+++ b/src/draw/draw.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
 import { InjectRepository } from '@nestjs/typeorm';
 import { MapDrawingEntity } from 'src/game/coordinate.entity';
 import { Repository } from 'typeorm';
-import { MapDrawingDTO } from './mapdrawing.dto';
+import { MapDrawingDTO, DrawMapDTO } from './mapdrawing.dto';
 import { Game_PersonEntity, GameEntity } from '../game/game.entity';
 import { GameDTO, FactionDTO } from 'src/game/game.dto';
 import { FactionEntity } from 'src/game/faction.entity';
@@ -14,30 +14,35 @@ export class DrawService {
     private mapDrawingRepository: Repository<MapDrawingEntity>,
     @InjectRepository(FactionEntity)
     private factionRepository: Repository<FactionEntity>,
+    @InjectRepository(Game_PersonEntity)
+    private game_personRepository: Repository<Game_PersonEntity>,
   ) {}
 
-  async draw(data: MapDrawingDTO) {
-    try {
-      return this.mapDrawingRepository.insert(data);
-    } catch (error) {
-      return error;
+  async draw(gameId, data: MapDrawingEntity) {
+    data['gameId'] = gameId;
+    const drawing = await this.mapDrawingRepository.create(data);
+
+    if (data.mapDrawingId == null || data.mapDrawingId == '') {
+      // luo uuden instanssin.
+      return this.mapDrawingRepository.insert(drawing)[0];
+    } else {
+      //päivittää mapDrawingin
+      return await this.mapDrawingRepository.save(drawing);
     }
   }
 
   // draw map based on game and
-  async drawMap(id: string, faction: FactionDTO) {
-    try {
-      // get faction
-      const factionInDb = await this.factionRepository.findOne({
-        where: { game: id, factionName: faction.factionName },
-      });
+  async drawMap(id, data: MapDrawingEntity) {
+    data['gameId'] = id;
+    data['drawingIsActive'] = true;
+    // get faction
+    const mapDrawings = await this.mapDrawingRepository.create(data);
 
-      // return mapdrawings with given faction and gameid
-      return this.mapDrawingRepository.find({
-        where: { gameId: id, faction: factionInDb },
-      });
-    } catch (error) {
-      return error;
-    }
+    // return mapdrawings with given faction and gameid
+    return await this.mapDrawingRepository.find(mapDrawings);
   }
+
+  // async trackLocation() {
+  //   return 'location';
+  // }
 }
diff --git a/src/draw/mapdrawing.dto.ts b/src/draw/mapdrawing.dto.ts
index f51937d..0e559fa 100644
--- a/src/draw/mapdrawing.dto.ts
+++ b/src/draw/mapdrawing.dto.ts
@@ -1,4 +1,8 @@
 import { GameDTO, FactionDTO } from '../game/game.dto';
+import { GameEntity, Game_PersonEntity } from 'src/game/game.entity';
+import { FactionEntity } from 'src/game/faction.entity';
+import { MapDrawingEntity } from 'src/game/coordinate.entity';
+import { IsUUID } from 'class-validator';
 
 export class MapDrawingDTO {
   data: JSON;
@@ -7,3 +11,14 @@ export class MapDrawingDTO {
   isActive?: boolean;
   validUntil?: string;
 }
+
+export class DrawMapDTO {
+  @IsUUID('4')
+  mapDrawingId: MapDrawingEntity;
+
+  gameId: GameEntity;
+  factionId: FactionEntity;
+
+  gamepersonId: Game_PersonEntity;
+  data: JSON;
+}
diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts
index 363bcbd..bd6551a 100644
--- a/src/game/game.controller.ts
+++ b/src/game/game.controller.ts
@@ -12,7 +12,13 @@ import {
 import { GameService } from './game.service';
 import { AuthGuard } from '../shared/auth.guard';
 import { User } from '../user/user.decorator';
-import { GameDTO, GameGroupDTO, FlagboxEventDTO } from './game.dto';
+import {
+  GameDTO,
+  GameGroupDTO,
+  FlagboxEventDTO,
+  JoinFactionDTO,
+  PromotePlayerDTO,
+} from './game.dto';
 import { ValidationPipe } from '../shared/validation.pipe';
 import { Roles } from '../shared/roles.decorator';
 
@@ -61,15 +67,17 @@ export class GameController {
   // param game ID is passed to @Roles
   @Put('promote/:id')
   @UseGuards(new AuthGuard())
+  @UsePipes(new ValidationPipe())
   @Roles('admin')
-  promotePlayer(@Param('id') game, @Body() body) {
+  promotePlayer(@Param('id') game, @Body() body: PromotePlayerDTO) {
     return this.gameservice.promotePlayer(body);
   }
 
   @Put('join-faction')
   @UseGuards(new AuthGuard())
-  joinFaction(@User('id') person, @Body() faction) {
-    return this.gameservice.joinFaction(person, faction);
+  @UsePipes(new ValidationPipe())
+  joinFaction(@User('id') person, @Body() data: JoinFactionDTO) {
+    return this.gameservice.joinFaction(person, data);
   }
 
   @Get('listgames')
diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts
index aa0bc49..df93b55 100644
--- a/src/game/game.dto.ts
+++ b/src/game/game.dto.ts
@@ -10,9 +10,13 @@ import {
   IsJSON,
   IsDateString,
   IsNumber,
+  IsUUID,
+  Validate,
 } from 'class-validator';
 import { Timestamp } from 'typeorm';
-import { ObjectivePointEntity } from './game.entity';
+import { ObjectivePointEntity, GameEntity } from './game.entity';
+import { StringifyOptions } from 'querystring';
+import { Uuid, RoleValidation } from '../shared/custom-validation';
 
 export class GameDTO {
   @IsString()
@@ -75,3 +79,19 @@ export class GameGroupDTO {
   @Length(3, 31)
   name: string;
 }
+
+export class JoinFactionDTO {
+  @IsUUID('4')
+  factionId: string;
+  @Length(3, 31)
+  factionPassword: string;
+  @IsUUID('4')
+  game: GameEntity;
+}
+
+export class PromotePlayerDTO {
+  @IsUUID('4')
+  player: string;
+  @Validate(RoleValidation)
+  role: string;
+}
diff --git a/src/game/game.service.ts b/src/game/game.service.ts
index dc1d929..5710752 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, JoinFactionDTO } from './game.dto';
 import { PersonEntity } from '../user/user.entity';
 import { GameGroupEntity } from './group.entity';
 import { FactionEntity } from './faction.entity';
@@ -249,19 +249,19 @@ export class GameService {
     throw new HttpException('player does not exist', HttpStatus.BAD_REQUEST);
   }
 
-  async joinFaction(person, faction) {
-    const name = faction.factionName;
+  async joinFaction(person, faction: JoinFactionDTO) {
     // get faction
     const factionInDb = await this.factionRepository.findOne({
-      where: { name },
+      factionId: faction.factionId,
     });
+
     if (!factionInDb) {
       throw new HttpException('No factions exist!', HttpStatus.BAD_REQUEST);
     }
     //check if password is correct
     if (factionInDb.passwordCheck(faction.factionPassword)) {
       const gameperson = await this.game_PersonRepository.create({
-        faction: faction.factionName,
+        faction: factionInDb,
         game: faction.game,
         role: 'soldier',
         person: person,
diff --git a/src/shared/custom-validation.ts b/src/shared/custom-validation.ts
new file mode 100644
index 0000000..a920e71
--- /dev/null
+++ b/src/shared/custom-validation.ts
@@ -0,0 +1,32 @@
+import {
+  ValidatorConstraint,
+  ValidatorConstraintInterface,
+  ValidationArguments,
+  Validator,
+} from 'class-validator';
+
+// check if input is null or valid uuid
+@ValidatorConstraint({ name: 'uuid', async: true })
+export class Uuid implements ValidatorConstraintInterface {
+  validate(uuid: string, args: ValidationArguments) {
+    const validator = new Validator();
+    return validator.isUUID(uuid, '4') || uuid == null; // for async validations you must return a Promise<boolean> here
+  }
+
+  defaultMessage(args: ValidationArguments) {
+    return 'Not valid uuid';
+  }
+}
+
+// checks if role is valid
+@ValidatorConstraint({ name: 'roleValidation', async: true })
+export class RoleValidation implements ValidatorConstraintInterface {
+  validate(role: string, args: ValidationArguments) {
+    const validRoles = ['admin', 'soldier', 'factionleader'];
+    return validRoles.includes(role);
+  }
+
+  defaultMessage(args: ValidationArguments) {
+    return 'Not valid uuid';
+  }
+}
-- 
GitLab