Skip to content
Snippets Groups Projects
Commit 334573db authored by L4168's avatar L4168
Browse files

added input validation & comments

parent 78cae80f
No related branches found
No related tags found
2 merge requests!59Development to master,!10Gamecreation
import { Module } from '@nestjs/common';
import { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';
import { TypeOrmModule } from "@nestjs/typeorm";
import { AppService } from './app.service';
import { Connection } from "typeorm";
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 { Controller, Post, UseGuards, Body, Get, Param } from '@nestjs/common';
import { Controller, Post, UseGuards, Body, Get, Param, UsePipes } from '@nestjs/common';
import { GameService } from './game.service';
import { AuthGuard } from '../shared/auth.guard';
import { User } from 'src/user/user.decorator';
import { GameDTO, FactionDTO } from './game.dto';
import { User } from '../user/user.decorator';
import { GameDTO } from './game.dto';
import { ValidationPipe } from '../shared/validation.pipe';
import { async } from 'rxjs/internal/scheduler/async';
@Controller('game')
export class GameController {
......@@ -10,8 +13,16 @@ export class GameController {
@Post('new')
@UseGuards(new AuthGuard())
async newGame(@User('id') person, @Body() body) {
return this.gameservice.createNewGame(person, body, body.factions);
@UsePipes(new ValidationPipe())
async newGame(@User('id') person, @Body() body: GameDTO ) {
return this.gameservice.createNewGame(person, body);
}
@UseGuards(new AuthGuard())
@UsePipes(new ValidationPipe())
@Post(':id')
async joinGame(@User('id') person, @Param('id') id: string, @Body() password: string) {
return this.gameservice.joinGame(person, id, password);
}
@Get('listgames')
......
......@@ -4,9 +4,14 @@ import {
IsJSON,
IsNotEmpty,
Length,
IsArray,
Validate,
} from 'class-validator';
import { ArrayLength } from 'src/shared/array-validation';
export class GameDTO {
// uses class-validator built in validations
// see https://github.com/typestack/class-validator
@IsString()
@IsNotEmpty()
@Length(2, 31)
......@@ -15,7 +20,8 @@ export class GameDTO {
@IsNotEmpty()
@Length(1, 255)
desc: string;
@IsJSON()
//@IsJSON()
// doesn't accept with IsJSON, WIP to get validation for map
map: JSON;
@IsDateString()
@IsNotEmpty()
......@@ -23,6 +29,15 @@ export class GameDTO {
@IsDateString()
@IsNotEmpty()
enddate: string;
@IsArray()
@IsNotEmpty()
@Length(5, 15, {
each: true,
})
// custom validation for array length (arr>min, arr<max)
@Validate(ArrayLength, [4, 8])
passwords: [];
factions: FactionDTO[];
}
export class FactionDTO {
......
......@@ -6,7 +6,7 @@ import {
OneToMany,
Timestamp,
} from 'typeorm';
import { PersonEntity } from 'src/user/user.entity';
// table that stores all created games
@Entity('Game')
......@@ -17,8 +17,12 @@ export class GameEntity {
@Column('json') map: JSON;
@Column('timestamp') startdate: Timestamp;
@Column('timestamp') enddate: Timestamp;
@Column("text", {array: true}) passwords: [];
@OneToMany(type => FactionEntity, faction => faction.game)
factions: FactionEntity[];
@OneToMany(type => Game_PersonEntity, game_persons => game_persons.game)
game_persons: Game_PersonEntity[];
gameObject() {
const { id, name } = this;
......@@ -33,4 +37,25 @@ export class FactionEntity {
@Column('text') name: string;
@ManyToOne(type => GameEntity, game => game.factions)
game: GameEntity;
}
\ No newline at end of file
@OneToMany(type => Game_PersonEntity, game_persons => game_persons.faction)
game_persons: Game_PersonEntity[];
}
// table that stores players associated with particular game
@Entity('Game_Person')
export class Game_PersonEntity {
@PrimaryGeneratedColumn('uuid') gameId: string;
@ManyToOne(type => FactionEntity, faction => faction.game_persons)
faction: FactionEntity;
@ManyToOne(type => GameEntity, game => game.game_persons)
game: GameEntity;
@ManyToOne(type => PersonEntity, person => person.game_persons)
person: PersonEntity;
/*
@ManyToOne(type => PersonRoleEntity, person_role => person_role.game_persons)
person_role: PersonRoleEntity;
@ManyToMany(type => CoordinateEntity, game_person_coordinates => game_person_coordinates.game_persons)
game_person_coordinates: CoordinateEntity[]; */
}
import { Injectable, Logger } from '@nestjs/common';
import { Injectable, Logger, HttpException, HttpStatus } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Repository, In } from 'typeorm';
import { GameEntity, FactionEntity } from './game.entity';
import { FactionDTO, GameDTO } from './game.dto';
import { GameDTO } from './game.dto';
import { PersonEntity } from 'src/user/user.entity';
@Injectable()
export class GameService {
......@@ -11,43 +13,59 @@ export class GameService {
private gameRepository: Repository<GameEntity>,
@InjectRepository(FactionEntity)
private factionRepository: Repository<FactionEntity>,
) { }
@InjectRepository(PersonEntity)
private personRepository: Repository<PersonEntity>,
) {}
// create a new game
async createNewGame(
personId: string,
gameData: GameDTO,
factions: FactionDTO[],
) {
async createNewGame(personId: string, gameData: GameDTO) {
// checks if a game with the same name exists already
const { name } = gameData;
if (await this.gameRepository.findOne({ where: { name } })) {
throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST);
}
// else add the game to the database
const game = await this.gameRepository.create({
...gameData,
factions: factions,
factions: gameData.factions,
});
await this.gameRepository.insert(game);
// get the id of the game created to pass it to factions table
const gameid = await this.gameRepository.findOne({ where: { name: gameData.name } })
const gameid = await this.gameRepository.findOne({
where: { name: gameData.name },
});
factions.map(async faction => {
gameData.factions.map(async faction => {
let name = await this.factionRepository.create({
...faction,
game: gameid
game: gameid,
});
await this.factionRepository.insert(name);
});
return 'success';
}
// checks the password, creates an entry in GamePerson table with associated role&faction
async joinGame(person, gameId, password) {
const user = await this.personRepository.findOne({ where: { id: person.id } });
const game = await this.gameRepository.findOne({ where: { id: gameId } });
return 'WIP';
}
// returns name and id of each game
async listGames() {
const games = await this.gameRepository.find({ relations: ['factions'] });
return games.map(game => {
return { game };
return game.gameObject();
});
}
// returns information about a game identified by id
async returnGameInfo(id: string) {
const game = await this.gameRepository.findOne({ where: { id: id }, relations: ['factions'] });
const game = await this.gameRepository.findOne({
where: { id: id },
relations: ['factions'],
});
return game;
}
}
\ No newline at end of file
}
import {ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments} from "class-validator";
import { Logger } from "@nestjs/common";
// validates array length
@ValidatorConstraint({ name: "arrayLength", async: true })
export class ArrayLength implements ValidatorConstraintInterface {
validate(array: string[], args: ValidationArguments) {
Logger.log(array.length)
return array.length > args.constraints[0] && array.length < args.constraints[1]; // for async validations you must return a Promise<boolean> here
}
defaultMessage(args: ValidationArguments) { // here you can provide default error message if validation failed
return "Please input all passwords";
}
}
\ No newline at end of file
import { createParamDecorator } from "@nestjs/common";
// used to pass user information to controllers
export const User = createParamDecorator((data, req) => {
return data ? req.user[data] : req.user;
})
\ No newline at end of file
......@@ -2,6 +2,7 @@ import { Entity, Column, PrimaryGeneratedColumn, BeforeInsert, OneToMany } from
import * as bcrypt from 'bcryptjs';
import * as jwt from 'jsonwebtoken';
import { MapMarkerEntity } from 'src/mapmarkers/mapmarker.entity';
import { Game_PersonEntity } from 'src/game/game.entity';
@Entity('Person')
export class PersonEntity {
......@@ -10,12 +11,17 @@ export class PersonEntity {
@Column('text') password: string;
@OneToMany(type => MapMarkerEntity, marker => marker.player)
markers: MapMarkerEntity[];
@OneToMany(type => Game_PersonEntity, game_persons => game_persons.person)
game_persons: Game_PersonEntity[];
// hashes the password before inserting it to database
@BeforeInsert()
async hashPassword() {
this.password = await bcrypt.hash(this.password, 10);
}
// returns username and associated token
tokenObject() {
const {name, token} = this;
return {name, token};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment