diff --git a/package-lock.json b/package-lock.json index 05c4c11f6797b7d67226fa03b30c6327b6fe9c69..e2dcee88b6c5b768ab67bf02467bec5e3b9289c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3125,7 +3125,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -3527,7 +3528,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -3582,6 +3584,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -3625,12 +3628,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, diff --git a/src/game/coordinate.entity.ts b/src/game/coordinate.entity.ts index e0087ba1c338d1b9420a3edf1db843e6bbf94275..851bb65c1b23ad74c06b2eb479710f5d121b08fa 100644 --- a/src/game/coordinate.entity.ts +++ b/src/game/coordinate.entity.ts @@ -1,42 +1,34 @@ import { - Entity, - Column, - PrimaryGeneratedColumn, - OneToMany, - ManyToOne, - PrimaryColumn, - Timestamp, - } from 'typeorm'; - import { - Game_PersonEntity, - ObjectivePointEntity, - GameEntity, - } from './game.entity'; - import { FactionEntity } from './faction.entity'; -import { type } from 'os'; - - @Entity('MapDrawing') - export class MapDrawingEntity { - @PrimaryGeneratedColumn('uuid') mapDrawingId: string; - @Column({ type: 'bool' }) drawingIsActive: boolean; - @Column({ type: 'time' }) drawingValidTill: string; - - @Column({ type: 'json', nullable: true }) data: JSON; - - @ManyToOne(type => FactionEntity, faction => faction.factionId) - faction: FactionEntity; - @ManyToOne(type => GameEntity, gameEntity => gameEntity.id) - gameId: GameEntity; - } + Entity, + Column, + PrimaryGeneratedColumn, + ManyToOne, + Timestamp, +} from 'typeorm'; +import { GameEntity, Game_PersonEntity } from './game.entity'; +import { FactionEntity } from './faction.entity'; - @Entity('Game_Person_MapDrawing') - export class Game_Person_MapDrawingEntity { - @PrimaryGeneratedColumn('uuid') GPmapDrawingId: string; - @Column({ type: 'timestamp' }) GPCTimeStamp: Timestamp; +@Entity('MapDrawing') +export class MapDrawingEntity { + @PrimaryGeneratedColumn('uuid') mapDrawingId: string; + @Column({ type: 'bool' }) drawingIsActive: boolean; + @Column({ type: 'time' }) drawingValidTill: string; - @ManyToOne(type => Game_PersonEntity, game_person => game_person.gamepersonId) - game_person: Game_PersonEntity; - @ManyToOne(type => MapDrawingEntity, map_drawing => map_drawing.mapDrawingId) - map_drawing: MapDrawingEntity; - } - \ No newline at end of file + @Column({ type: 'json', nullable: true }) data: JSON; + + @ManyToOne(type => FactionEntity, faction => faction.factionId) + faction: FactionEntity; + @ManyToOne(type => GameEntity, gameEntity => gameEntity.id) + gameId: GameEntity; +} + +@Entity('Game_Person_MapDrawing') +export class Game_Person_MapDrawingEntity { + @PrimaryGeneratedColumn('uuid') GPmapDrawingId: string; + @Column({ type: 'timestamp' }) GPCTimeStamp: Timestamp; + + @ManyToOne(type => Game_PersonEntity, game_person => game_person.gamepersonId) + game_person: Game_PersonEntity; + @ManyToOne(type => MapDrawingEntity, map_drawing => map_drawing.mapDrawingId) + map_drawing: MapDrawingEntity; +} diff --git a/src/game/game.controller.ts b/src/game/game.controller.ts index fdcc79e2b116030a64401f28dc192feaaf6c04f1..edff9d8e21ae4bd667b1eecb7162cacede906678 100644 --- a/src/game/game.controller.ts +++ b/src/game/game.controller.ts @@ -12,7 +12,7 @@ import { import { GameService } from './game.service'; import { AuthGuard } from '../shared/auth.guard'; import { User } from '../user/user.decorator'; -import { GameDTO, GameGroupDTO } from './game.dto'; +import { GameDTO, GameGroupDTO, FlagboxEventDTO } from './game.dto'; import { ValidationPipe } from '../shared/validation.pipe'; import { Roles } from '../shared/roles.decorator'; @@ -82,4 +82,14 @@ export class GameController { async returnGameInfo(@Param('id') id: string) { return this.gameservice.returnGameInfo(id); } + + @Get('flag/:id') + async flagboxQuery(@Param('id') id: string) { + return this.gameservice.flagboxQuery(id); + } + + @Post('flag/:id') + async flagboxEvent(@Param('id') id: string, @Body() data: FlagboxEventDTO) { + return this.gameservice.flagboxEvent(id, data); + } } diff --git a/src/game/game.dto.ts b/src/game/game.dto.ts index ea5c2e9dcdc1156eceb7c73791db06448443d1a5..952956dd30a375bd1c6be4c417757d69288fbc3c 100644 --- a/src/game/game.dto.ts +++ b/src/game/game.dto.ts @@ -9,6 +9,7 @@ import { IsArray, IsJSON, IsDateString, + IsNumber, } from 'class-validator'; import { Timestamp } from 'typeorm'; import { ObjectivePointEntity } from './game.entity'; @@ -28,6 +29,7 @@ export class GameDTO { // doesn't accept with IsJSON, WIP to get validation for map and center // IsJSON checks with json.parse, expecting string map?: JSON; + nodesettings?: JSON; @IsDateString() @IsNotEmpty() startdate: string; @@ -37,6 +39,7 @@ export class GameDTO { // custom validation for array length (arr>min, arr<max) //@Validate(ArrayLength, [4, 8]) factions?: FactionDTO[]; + objective_points?: FlagboxDTO[]; } export class FactionDTO { @@ -49,6 +52,24 @@ export class FactionDTO { game: GameDTO; } +export class FlagboxDTO { + @IsString() + @IsNotEmpty() + @Length(7) + objectivePointDescription: string; + @IsNumber() + objectivePointMultiplier: number; +} + +export class FlagboxEventDTO { + node_id: string; + owner: number; + action: number; + capture: number; + oP_HistoryTimestamp?: string; + objective_point?: ObjectivePointEntity; +} + export class GameGroupDTO { @IsString() @Length(3, 31) diff --git a/src/game/game.entity.ts b/src/game/game.entity.ts index 1eefcd31b9cda66999bf5dc893694f998d6883e9..36813094bc3a87c0903cb94f81260a42be803116 100644 --- a/src/game/game.entity.ts +++ b/src/game/game.entity.ts @@ -25,6 +25,7 @@ export class GameEntity { @Column('text') desc: string; @Column('json') center: JSON; @Column({ type: 'json', nullable: true }) map: JSON; + @Column({ type: 'json', nullable: true }) nodesettings?: JSON; @Column('timestamp') startdate: Timestamp; @Column('timestamp') enddate: Timestamp; @@ -85,8 +86,11 @@ export class ObjectivePointEntity { export class ObjectivePoint_HistoryEntity { @PrimaryGeneratedColumn('uuid') oP_HistoryId: string; @Column({ type: 'timestamp' }) oP_HistoryTimestamp: Timestamp; - @Column({}) oP_HistoryStatus: number; - + @Column('float') action: number; + @ManyToOne(type => FactionEntity, factionEntity => factionEntity.factionId) + capture: FactionEntity; + @ManyToOne(type => FactionEntity, factionentity => factionentity.factionId) + owner: FactionEntity; @ManyToOne( type => ObjectivePointEntity, objective_point => objective_point.objectivePointId, diff --git a/src/game/game.module.ts b/src/game/game.module.ts index 7df189f348bf12543437ecdd85d892980115c7ae..c908e483b7b1a867d5d8dfb8e8fab54ea212ecfe 100644 --- a/src/game/game.module.ts +++ b/src/game/game.module.ts @@ -3,13 +3,30 @@ import { TypeOrmModule } from '@nestjs/typeorm'; import { GameController } from './game.controller'; import { GameService } from './game.service'; -import { GameEntity, Game_PersonEntity } from './game.entity'; +import { + GameEntity, + Game_PersonEntity, + ObjectivePointEntity, + ObjectivePoint_HistoryEntity, +} from './game.entity'; import { PersonEntity } from '../user/user.entity'; import { GameGroupEntity } from './group.entity'; import { FactionEntity } from './faction.entity'; +import { NotificationModule } from '../notifications/notifications.module'; @Module({ - imports: [TypeOrmModule.forFeature([GameEntity, FactionEntity, Game_PersonEntity, PersonEntity, GameGroupEntity])], + imports: [ + TypeOrmModule.forFeature([ + GameEntity, + FactionEntity, + Game_PersonEntity, + PersonEntity, + GameGroupEntity, + ObjectivePointEntity, + ObjectivePoint_HistoryEntity, + ]), + NotificationModule, + ], controllers: [GameController], providers: [GameService], }) diff --git a/src/game/game.service.ts b/src/game/game.service.ts index e4dd8c7d49acb9bae906cf5a7eb4727e2597f673..f8d3c728c8e6ad59dbfb02228840f973f2b2120e 100644 --- a/src/game/game.service.ts +++ b/src/game/game.service.ts @@ -2,11 +2,17 @@ import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, Not } from 'typeorm'; -import { GameEntity, Game_PersonEntity } from './game.entity'; -import { GameDTO } from './game.dto'; +import { + GameEntity, + Game_PersonEntity, + ObjectivePointEntity, + ObjectivePoint_HistoryEntity, +} from './game.entity'; +import { GameDTO, FlagboxEventDTO } from './game.dto'; import { PersonEntity } from '../user/user.entity'; import { GameGroupEntity } from './group.entity'; import { FactionEntity } from './faction.entity'; +import { NotificationGateway } from 'src/notifications/notifications.gateway'; @Injectable() export class GameService { @@ -21,6 +27,13 @@ export class GameService { private game_PersonRepository: Repository<Game_PersonEntity>, @InjectRepository(GameGroupEntity) private game_GroupRepository: Repository<GameGroupEntity>, + @InjectRepository(ObjectivePointEntity) + private objectivePointRepository: Repository<ObjectivePointEntity>, + @InjectRepository(ObjectivePoint_HistoryEntity) + private objectivePoint_HistoryRepository: Repository< + ObjectivePoint_HistoryEntity + >, + private notificationGateway: NotificationGateway, ) {} // create a new game @@ -34,7 +47,7 @@ export class GameService { // else add the game to the database const game = await this.gameRepository.create({ ...gameData, - factions: gameData.factions, + factionsId: gameData.factions, }); await this.gameRepository.insert(game); const gamePerson = await this.game_PersonRepository.create({ @@ -63,15 +76,15 @@ export class GameService { // update game entry in db const updatedGame = await this.gameRepository.create({ ...gameData, - factions: null, + factionsId: null, + objective_points: null, }); updatedGame['id'] = id; const gameId = await this.gameRepository.save(updatedGame); - // get all the factions that are associated with the game to deny duplicate entries + // get all the factions that are associated with the game to deny duplicate entries const factions = await this.factionRepository.find(gameId); const factionNames = factions.map(({ factionName }) => factionName); - console.log(factionNames); // add the factions to db if (gameData.factions) { gameData.factions.map(async faction => { @@ -85,6 +98,32 @@ export class GameService { }); } + // 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); + } + }); + } + + // TO DO: ADD FLAGBOX LOCATION TO MAPDRAWING ENTITY + return { message: 'Game updated', }; @@ -190,8 +229,35 @@ export class GameService { async returnGameInfo(id: string) { const game = await this.gameRepository.findOne({ where: { id: id }, - relations: ['factions'], + relations: ['factions', 'objective_points'], }); return game; } + + // returns flagbox settings + async flagboxQuery(gameId) { + const game = await this.gameRepository.findOne({ id: gameId }); + return game.nodesettings; + } + + // add events to history and send updates with socket + async flagboxEvent(gameId, data: FlagboxEventDTO) { + // get all the factions associated with the game + const factionRef = await this.factionRepository.find({ game: gameId }); + // get reference to the objective + const objectiveRef = await this.objectivePointRepository.findOne({ + where: { objectivePointDescription: data.node_id, game: gameId }, + }); + data.oP_HistoryTimestamp = new Date(Date.now()).toLocaleString(); + 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, + }); + await this.objectivePoint_HistoryRepository.insert(eventUpdate); + // send flagbox event to flagbox subscribers + this.notificationGateway.server.emit('flagbox', 'event update'); + } } diff --git a/src/mapmarkers/mapmarker.entity.ts b/src/mapmarkers/mapmarker.entity.ts index 237951a9f362fe774515f82d2fd63dfc1ed7415a..0b26cbaa9a869fd81c7669a557b233a32c67b0f4 100644 --- a/src/mapmarkers/mapmarker.entity.ts +++ b/src/mapmarkers/mapmarker.entity.ts @@ -1,20 +1,20 @@ import { - Entity, - Column, - PrimaryGeneratedColumn, - Timestamp, - ManyToOne, - } from 'typeorm'; - - import { PersonEntity } from '../user/user.entity'; + Entity, + Column, + PrimaryGeneratedColumn, + Timestamp, + ManyToOne, +} from 'typeorm'; + +import { PersonEntity } from '../user/user.entity'; import { GameEntity, Game_PersonEntity } from 'src/game/game.entity'; - - /* + +/* Entity: MapMarker - represents data that database contains on mapmarker */ - - /* @Entity('MapMarker') + +/* @Entity('MapMarker') export class MapMarkerEntity { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'text', nullable: true }) latitude: string; @@ -24,4 +24,4 @@ import { GameEntity, Game_PersonEntity } from 'src/game/game.entity'; @ManyToOne(type => Game_PersonEntity, player => player.markers) player: Game_PersonEntity; } - */ \ No newline at end of file + */ diff --git a/src/mapmarkers/mapmarker.service.ts b/src/mapmarkers/mapmarker.service.ts index 1a948694810e6ba42b961bde7bd73de02ba24fb6..f320d17b0892cec302281a1ee6f99b13fb788b78 100644 --- a/src/mapmarkers/mapmarker.service.ts +++ b/src/mapmarkers/mapmarker.service.ts @@ -1,11 +1,10 @@ -import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; -import { Repository, In } from 'typeorm'; +import { Injectable } from '@nestjs/common'; +import { Repository } from 'typeorm'; import { InjectRepository } from '@nestjs/typeorm'; import { MapMarkerEntity } from './mapmarker.entity'; import { MapMarkerDTO } from './mapmarker.dto'; import { PersonEntity } from '../user/user.entity'; -import { userInfo } from 'os'; @Injectable() export class MapMarkerService { @@ -29,12 +28,11 @@ export class MapMarkerService { //create© entity properties const location = await this.mapmarkerRepository.create({ ...data, - player: user, }); // insert created entity NOTE: insert method doesn't check for duplicates. await this.mapmarkerRepository.insert(location); // return data and player id&name - return { ...data, player: location.player.nameObject() }; + return { ...data }; } catch (error) { return error; } @@ -49,7 +47,7 @@ export class MapMarkerService { }); // return markers from database with said playerdata return markers.map(marker => { - return { ...marker, player: marker.player.nameObject() }; + return { ...marker }; }); } catch (error) { return error.message; diff --git a/src/notifications/notifications.module.ts b/src/notifications/notifications.module.ts index 5441d120b1e633b86c0c4d1db32416b2daf80937..97cf59c1f929cfc14b5335b0308e7615ac10dee8 100644 --- a/src/notifications/notifications.module.ts +++ b/src/notifications/notifications.module.ts @@ -6,5 +6,6 @@ import { TypeOrmModule } from '@nestjs/typeorm'; @Module({ imports: [TypeOrmModule.forFeature([NotificationEntity])], providers: [NotificationGateway], + exports: [NotificationGateway], }) export class NotificationModule {} diff --git a/src/shared/roles.controller.ts b/src/shared/roles.controller.ts index 76f56300b3abd944e86a9c5bdbfb651e322e8ab6..0d91e061c7fea732af225819e87f8529ff326eab 100644 --- a/src/shared/roles.controller.ts +++ b/src/shared/roles.controller.ts @@ -1,51 +1,51 @@ const AccessControl = require('accesscontrol'); const grants = { - admin: { - mapmarker: { - "create:any": [], - "delete:any": [], - "read:any": [], - "update:any": [] - }, - powerup: { - "create:any": [], - "delete:any": [], - "read:any": [], - "update:any": [] - }, - faction: { - "create:any": [], - "delete:any": [], - "read:any": [], - "update:any": [] - }, - players: { - "create:any": [], - "delete:any": [], - "read:any": [], - "update:any": [] - } + admin: { + mapmarker: { + 'create:any': [], + 'delete:any': [], + 'read:any': [], + 'update:any': [], }, - faction_leader: { - mapmarker: { - "create:own": [], - "delete:own": [], - "read:own": [] - }, - powerup: { - "read:own": [] - }, - faction: { - "read:own": [], - "update:own": [] - }, - players: { - "read:own": [], - "update:own": [] - } - } - //player & spectator + powerup: { + 'create:any': [], + 'delete:any': [], + 'read:any': [], + 'update:any': [], + }, + faction: { + 'create:any': [], + 'delete:any': [], + 'read:any': [], + 'update:any': [], + }, + players: { + 'create:any': [], + 'delete:any': [], + 'read:any': [], + 'update:any': [], + }, + }, + faction_leader: { + mapmarker: { + 'create:own': [], + 'delete:own': [], + 'read:own': [], + }, + powerup: { + 'read:own': [], + }, + faction: { + 'read:own': [], + 'update:own': [], + }, + players: { + 'read:own': [], + 'update:own': [], + }, + }, + //player & spectator }; const ac = new AccessControl(grants); @@ -85,4 +85,4 @@ router.get('/videos/:title', function (req, res, next) { // resource is forbidden for this user/role res.status(403).end(); } -});*/ \ No newline at end of file +});*/ diff --git a/src/user/user.entity.ts b/src/user/user.entity.ts index 99dbea97b97aaa448e723e0602369991c6b243e1..1e44121e0eed81e1a1b7a7f35e9a95e557c89e5e 100644 --- a/src/user/user.entity.ts +++ b/src/user/user.entity.ts @@ -7,14 +7,14 @@ import { } from 'typeorm'; import * as bcrypt from 'bcryptjs'; import * as jwt from 'jsonwebtoken'; -import {Game_PersonEntity} from '../game/game.entity' +import { Game_PersonEntity } from '../game/game.entity'; @Entity('Person') export class PersonEntity { @PrimaryGeneratedColumn('uuid') id: string; @Column({ type: 'text', unique: true }) name: string; @Column('text') password: string; - + @OneToMany(type => Game_PersonEntity, game_persons => game_persons.person) game_persons: Game_PersonEntity[];