Skip to content
Snippets Groups Projects
Commit db29c44d authored by Samuli Virtapohja's avatar Samuli Virtapohja
Browse files

Merge branch 'piirto2' of...

Merge branch 'piirto2' of gitlab.labranet.jamk.fi:wimma-lab-2019/overflow/ehasa-backend into piirto2
parents c4db19ba 33b6c745
No related branches found
No related tags found
3 merge requests!59Development to master,!31Development,!26Piirto2
......@@ -64,6 +64,11 @@ export class GameController {
return this.gameservice.joinGroup(person, id);
}
@Get('get-faction-members/:id')
async getFactionMembers(@Param('id') factionId) {
return this. gameservice.listFactionMembers(factionId)
}
// param game ID is passed to @Roles
@Put('promote/:id')
@UseGuards(new AuthGuard())
......
import {
IsNotEmpty,
IsString,
IsDate,
Length,
IsInt,
Min,
Max,
IsArray,
IsJSON,
IsDateString,
IsNumber,
IsUUID,
Validate,
Min,
Max,
} from 'class-validator';
import { Timestamp } from 'typeorm';
import { ObjectivePointEntity, GameEntity } from './game.entity';
import { StringifyOptions } from 'querystring';
import { Uuid, RoleValidation } from '../shared/custom-validation';
import { ObjectivePointEntity } from './game.entity';
import { CenterJSON } from '../shared/custom-validation';
export class GameDTO {
@IsString()
......@@ -27,11 +20,8 @@ export class GameDTO {
@Length(1, 255)
desc: string;
@IsNotEmpty()
//@IsJSON()
@Validate(CenterJSON)
center: JSON;
//@IsJSON()
// 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()
......@@ -40,12 +30,30 @@ export class GameDTO {
@IsDateString()
@IsNotEmpty()
enddate: string;
// custom validation for array length (arr>min, arr<max)
//@Validate(ArrayLength, [4, 8])
factions?: FactionDTO[];
objective_points?: FlagboxDTO[];
}
export class newGameDTO {
@IsString()
@IsNotEmpty()
@Length(3, 30)
name: string;
@IsString()
@IsNotEmpty()
@Length(1, 255)
desc: string;
@IsNotEmpty()
@Validate(CenterJSON)
center: JSON;
@IsDateString()
@IsNotEmpty()
startdate: string;
@IsDateString()
@IsNotEmpty()
enddate: string;
}
export class FactionDTO {
@IsString()
@IsNotEmpty()
......@@ -66,10 +74,22 @@ export class FlagboxDTO {
}
export class FlagboxEventDTO {
@IsString()
@IsNotEmpty()
@Length(7)
node_id: string;
owner: number;
action: number;
capture: number;
@IsNumber()
@Min(0)
@Max(3)
owner: number; // owner = 0, => first entry in faction db, owner = 1, => second entry etc
@IsNumber()
@Min(0)
@Max(3)
action: number; // 0=no capture ongoing, 1=captured, 2=capture ongoing
@IsNumber()
@Min(0)
@Max(3)
capture: number; // which faction is capturing, same logic as in owner with numbers
oP_HistoryTimestamp?: string;
objective_point?: ObjectivePointEntity;
}
......
......@@ -12,10 +12,8 @@ import {
import { PersonEntity } from '../user/user.entity';
import { GameGroupEntity } from './group.entity';
import { FactionEntity } from './faction.entity';
import {
MapDrawingEntity,
Game_Person_MapDrawingEntity,
} from './coordinate.entity';
import { MapDrawingEntity } from './coordinate.entity';
import { TaskEntity } from '../task/task.entity';
// table that stores all created games
@Entity('Game')
......@@ -40,6 +38,8 @@ export class GameEntity {
objective_points => objective_points.game,
)
objective_points: ObjectivePointEntity[];
@OneToMany(type => TaskEntity, tasks => tasks.taskGame)
tasks: TaskEntity[];
gameObject() {
const { id, name } = this;
......
......@@ -8,7 +8,12 @@ import {
ObjectivePointEntity,
ObjectivePoint_HistoryEntity,
} from './game.entity';
import { GameDTO, FlagboxEventDTO, JoinFactionDTO } from './game.dto';
import {
GameDTO,
FlagboxEventDTO,
JoinFactionDTO,
GameGroupDTO,
} from './game.dto';
import { PersonEntity } from '../user/user.entity';
import { GameGroupEntity } from './group.entity';
import { FactionEntity } from './faction.entity';
......@@ -39,22 +44,18 @@ export class GameService {
// create a new game
async createNewGame(personId: PersonEntity, gameData: GameDTO) {
// checks if a game with the same name exists already
const { name } = gameData;
if (await this.gameRepository.findOne({ where: { name } })) {
if (await this.gameRepository.findOne({ name: gameData.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: gameData.factions,
});
const game = await this.gameRepository.create(gameData);
await this.gameRepository.insert(game);
// add gamePerson with role admin to the game
const gamePerson = await this.game_PersonRepository.create({
faction: null,
game: game,
person: personId,
role: 'admin',
});
gamePerson['role'] = 'admin';
await this.game_PersonRepository.insert(gamePerson);
return {
message: 'New game added',
......@@ -64,16 +65,13 @@ export class GameService {
// edit already created game
async editGame(id: string, gameData: GameDTO) {
// checks if a game with the same name exists already
const { name } = gameData;
if (await this.gameRepository.findOne({ name: name, id: Not(id) })) {
if (
await this.gameRepository.findOne({ name: gameData.name, id: Not(id) })
) {
throw new HttpException('Game already exists', HttpStatus.BAD_REQUEST);
}
// update game entry in db
const updatedGame = await this.gameRepository.create({
...gameData,
factions: null,
objective_points: null,
});
const updatedGame = await this.gameRepository.create(gameData);
updatedGame['id'] = id;
const gameId = await this.gameRepository.save(updatedGame);
......@@ -131,7 +129,7 @@ export class GameService {
}
// checks the password, creates an entry in GamePerson table with associated role&faction
async createGroup(person, gameId, groupData) {
async createGroup(person, gameId, groupData: GameGroupDTO) {
// check if the person already is in a group in this game
const checkDuplicate = await this.game_PersonRepository.findOne({
person: person,
......@@ -243,6 +241,14 @@ export class GameService {
this.notificationGateway.server.emit('flagbox', 'event update');
}
async listFactionMembers(faction) {
return await this.game_PersonRepository.find({
where: { faction },
relations: ['person'],
order: { person: 'DESC' },
});
}
async promotePlayer(body) {
const gamepersonId = body.player;
// get playerdata
......
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
......@@ -30,3 +30,23 @@ export class RoleValidation implements ValidatorConstraintInterface {
return 'Not valid uuid';
}
}
// checks for valid JSON for center
@ValidatorConstraint({ name: 'centerJSON', async: true })
export class CenterJSON implements ValidatorConstraintInterface {
validate(center: JSON, args: ValidationArguments) {
const validator = new Validator();
return (
validator.isNumber(center['lat']) &&
validator.isNumber(center['lng']) &&
validator.min(center['lat'], -90) &&
validator.max(center['lat'], 90) &&
validator.min(center['lng'], -180) &&
validator.max(center['lng'], 180)
);
}
defaultMessage(args: ValidationArguments) {
return 'Error with center JSON';
}
}
......@@ -32,9 +32,9 @@ export class RolesGuard implements CanActivate {
return false;
}
const gameId = request.params.id;
const user = await this.getUserObject(request.headers.authorization);
request.user = await this.getUserObject(request.headers.authorization);
const role = await this.game_PersonRepository.findOne({
person: user['id'],
person: request.user['id'],
game: gameId,
});
// check that the role matches the criteria and that token is valid for this game
......
......@@ -7,35 +7,41 @@ import {
UseGuards,
Param,
} from '@nestjs/common';
import { TaskService } from './task.service';
import { CreateTaskDTO, EditTaskDTO } from './task.dto';
import { AuthGuard } from '../shared/auth.guard';
import { Roles } from '../shared/roles.decorator';
import { ValidationPipe } from '../shared/validation.pipe';
import { TaskDTO } from './task.dto';
import { User } from 'src/user/user.decorator';
@Controller('task')
export class TaskController {
constructor(private taskService: TaskService) {}
/* @Post('new')
@UseGuards(new AuthGuard())
// creates a new task if the user has admin role in the game
// :id is the id of the game
@Post('new-task/:id')
@Roles('admin')
@UsePipes(new ValidationPipe())
async newGame(@User('id') person, @Body() body: GameDTO) {
return this.gameservice.createNewGame(person, body);
async newTask(@Param('id') id: string, @Body() task: CreateTaskDTO) {
return this.taskService.newTask(task);
}
@Put(':id')
// edits a created task if the user has admin role in the game
// :id is the id of the game
@Post('edit-task/:id')
@Roles('admin')
@UsePipes(new ValidationPipe())
async editGame(@Param('id') id: string, @Body() body: GameDTO) {
return this.gameservice.editGame(id, body);
} */
async editTask(@Param('id') id: string, @Body() data: EditTaskDTO) {
return this.taskService.editTask(data);
}
// creates a new task if the user has admin role in the game
// lists all the tasks for the game if user has game_person entry
// :id is the id of the game
@Post('new-task/:id')
//@Roles('admin')
@UsePipes(new ValidationPipe())
async newTask(@Param('id') id: string, @Body() task: TaskDTO) {
return this.taskService.newTask(task);
@Get('get-tasks/:id')
@Roles('soldier', 'factionleader', 'admin')
async fetchTasks(@User('id') person, @Param('id') id: string) {
return this.taskService.fetchTasks(person, id);
}
}
import {
IsString,
Length,
IsNumber,
IsBoolean,
Min,
Max,
Validate,
IsUUID,
Equals,
} from 'class-validator';
import { FactionEntity } from 'src/game/faction.entity';
import { FactionEntity } from '../game/faction.entity';
import { GameEntity } from '../game/game.entity';
import { Uuid } from '../shared/custom-validation';
export class TaskDTO {
export class CreateTaskDTO {
@IsString()
@Length(3, 31)
taskName: string;
@IsString()
@Length(0, 255)
taskDescription: string;
@IsNumber()
@Min(1)
@Max(99)
taskScore: number;
@IsString()
@Length(3, 31)
taskWinner?: string;
@IsBoolean()
taskIsActive: boolean;
// faction unique id
@IsString()
@Validate(Uuid)
faction: FactionEntity;
@Equals(null)
taskWinner: FactionEntity;
// faction unique id
@IsUUID('4')
taskGame: GameEntity;
}
export class EditTaskDTO {
@IsUUID('4')
taskId: string;
@IsUUID('4')
taskWinner: FactionEntity;
@IsUUID('4')
taskGame: GameEntity;
}
import { PrimaryGeneratedColumn, Column, Entity, ManyToOne } from 'typeorm';
import {
PrimaryGeneratedColumn,
Column,
Entity,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { FactionEntity } from 'src/game/faction.entity';
import { GameEntity } from 'src/game/game.entity';
@Entity('Task')
export class TaskEntity {
@PrimaryGeneratedColumn('uuid') taskId: string;
@Column({ type: 'text' }) taskName: string;
@Column({ type: 'text' }) taskDescription: string;
@Column({ type: 'float' }) taskScore: number;
@Column({ type: 'text' }) taskWinner: string;
@Column({ type: 'bool' }) taskIsActive: boolean;
@ManyToOne(type => FactionEntity, faction => faction.factionId)
faction: FactionEntity;
@ManyToOne(type => FactionEntity, faction => faction.factionId)
taskWinner: FactionEntity;
@ManyToOne(type => GameEntity, game => game.id)
@JoinColumn({ name: 'taskGame' })
taskGame: GameEntity;
}
......@@ -4,9 +4,15 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { TaskService } from './task.service';
import { TaskController } from './task.controller';
import { TaskEntity } from './task.entity';
import { FactionEntity } from '../game/faction.entity';
import { Game_PersonEntity } from '../game/game.entity';
import { NotificationModule } from '../notifications/notifications.module';
@Module({
imports: [TypeOrmModule.forFeature([TaskEntity])],
imports: [
TypeOrmModule.forFeature([TaskEntity, FactionEntity, Game_PersonEntity]),
NotificationModule,
],
controllers: [TaskController],
providers: [TaskService],
})
......
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
import { Repository } from 'typeorm';
import { InjectRepository } from '@nestjs/typeorm';
import { TaskEntity } from './task.entity';
import { TaskDTO } from './task.dto';
import { CreateTaskDTO, EditTaskDTO } from './task.dto';
import { FactionEntity } from '../game/faction.entity';
import { Game_PersonEntity } from '../game/game.entity';
import { NotificationGateway } from '../notifications/notifications.gateway';
@Injectable()
export class TaskService {
constructor(
@InjectRepository(TaskEntity)
private taskRepository: Repository<TaskEntity>,
@InjectRepository(FactionEntity)
private factionRepository: Repository<FactionEntity>,
@InjectRepository(Game_PersonEntity)
private gamePersonRepository: Repository<Game_PersonEntity>,
private notificationGateway: NotificationGateway,
) {}
async newTask(task: TaskDTO) {
async newTask(task: CreateTaskDTO) {
// check if is not null, check that the faction exists in the game
if (
task.faction != null &&
!(await this.factionRepository.findOne({
factionId: task.faction.toString(),
game: task.taskGame,
}))
) {
throw new HttpException('Faction not found', HttpStatus.BAD_REQUEST);
}
const createdTask = await this.taskRepository.create(task);
await this.taskRepository.insert(createdTask);
// 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',
);
return {
message: 'Task added',
};
}
async editTask(data: EditTaskDTO) {
const task = await this.taskRepository.findOne(data.taskId);
console.log(task);
// checks if task is already closed
if (!task.taskIsActive) {
throw new HttpException('Task is not active', HttpStatus.BAD_REQUEST);
}
// checks if faction is valid
if (
!(await this.factionRepository.findOne({
factionId: data.taskWinner.toString(),
game: data.taskGame,
}))
) {
throw new HttpException('Faction not found', HttpStatus.BAD_REQUEST);
}
task.taskWinner = data.taskWinner;
task.taskIsActive = false;
await this.taskRepository.save(task);
return {
message: 'Task updated and closed',
};
}
async fetchTasks(user, taskGame) {
const gamePerson = await this.gamePersonRepository.findOne({
where: {
person: user,
game: taskGame,
},
relations: ['faction'],
});
if (gamePerson.role == 'admin') {
return await this.taskRepository.find({
where: { taskGame: taskGame },
relations: ['faction'],
});
} else {
return await this.taskRepository.find({
relations: ['faction'],
where: [
{
taskGame: taskGame,
faction: gamePerson.faction.factionId,
taskIsActive: true,
},
{
taskGame: taskGame,
faction: null,
taskIsActive: true,
},
],
});
}
}
}
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