diff --git a/package-lock.json b/package-lock.json index 01f1711..b03798a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,7 +41,7 @@ }, "devDependencies": { "@nestjs/schematics": "^10.0.3", - "@nestjs/testing": "^10.2.8", + "@nestjs/testing": "^10.4.7", "@types/cron": "^2.0.1", "@types/express": "^4.17.21", "@types/jest": "^29.5.8", @@ -1905,12 +1905,13 @@ } }, "node_modules/@nestjs/testing": { - "version": "10.2.8", - "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.2.8.tgz", - "integrity": "sha512-9Kj5IQhM67/nj/MT6Wi2OmWr5YQnCMptwKVFrX1TDaikpY12196v7frk0jVjdT7wms7rV07GZle9I2z0aSjqtQ==", + "version": "10.4.7", + "resolved": "https://registry.npmjs.org/@nestjs/testing/-/testing-10.4.7.tgz", + "integrity": "sha512-aS3sQ0v4g8cyHDzW3xJv1+8MiFAkxUNXmnau588IFFI/nBIo/kevLNHNPr85keYekkJ/lwNDW72h8UGg8BYd9w==", "dev": true, + "license": "MIT", "dependencies": { - "tslib": "2.6.2" + "tslib": "2.7.0" }, "funding": { "type": "opencollective", @@ -1931,6 +1932,13 @@ } } }, + "node_modules/@nestjs/testing/node_modules/tslib": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", + "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==", + "dev": true, + "license": "0BSD" + }, "node_modules/@nestjs/websockets": { "version": "10.2.8", "resolved": "https://registry.npmjs.org/@nestjs/websockets/-/websockets-10.2.8.tgz", diff --git a/package.json b/package.json index 21a7ae2..2644a62 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ }, "devDependencies": { "@nestjs/schematics": "^10.0.3", - "@nestjs/testing": "^10.2.8", + "@nestjs/testing": "^10.4.7", "@types/cron": "^2.0.1", "@types/express": "^4.17.21", "@types/jest": "^29.5.8", diff --git a/src/game/comand-handlers/give-out-a-prize-command.handler.ts b/src/game/comand-handlers/give-out-a-prize-command.handler.ts index 2ebd100..77ddcb8 100644 --- a/src/game/comand-handlers/give-out-a-prize-command.handler.ts +++ b/src/game/comand-handlers/give-out-a-prize-command.handler.ts @@ -3,6 +3,7 @@ import { GiveOutAPrizeCommand } from '../commands/give-out-a-prize.command'; import { GameService } from '../game.service'; import { Logger } from '@nestjs/common'; import { GameQueueTypes } from '../../schemas/game-queue.schema'; +import {GuestsService} from "../../guests/guests.service"; @CommandHandler(GiveOutAPrizeCommand) export class GameGiveOutAPrizeCommandHandler @@ -10,11 +11,12 @@ export class GameGiveOutAPrizeCommandHandler private readonly logger = new Logger(GameGiveOutAPrizeCommandHandler.name); - constructor(private gameService: GameService) { + constructor(private gameService: GameService, private guestService: GuestsService) { } async execute(command: GiveOutAPrizeCommand): Promise { this.logger.verbose(`Player winning a prize ${command.telegramId}`); + await this.guestService.incrementPrizeCount(command.telegramId); return this.gameService.addTaskToGameQueue( command.telegramId, GameQueueTypes.giveOutAPrize, diff --git a/src/guests/guests.service.ts b/src/guests/guests.service.ts index c39980c..650f83a 100644 --- a/src/guests/guests.service.ts +++ b/src/guests/guests.service.ts @@ -24,8 +24,6 @@ import {MqtMessageModel} from "../messaging/models/mqt-message.model"; import {ConfigService} from "@nestjs/config"; import {StringHelper} from "../helpers/stringhelper"; import {DebuffsConsts} from "../game/entities/debuffs.consts"; -import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.command"; -import {GameQueueTypes} from "../schemas/game-queue.schema"; import {VoiceService} from "../voice/voice.service"; import {screpaDictManyInvalidAnswersDict} from "../voice/dicts/screpa-dict-many-invalid-answers.dict"; import {GuestPropertiesConsts} from "../schemas/properties.consts"; @@ -66,6 +64,10 @@ export class GuestsService { return this.guestModel.find().exec(); } + getModel() { + return this.guestModel; + } + async filter(properties: object) { return this.guestModel.find(properties).exec(); } @@ -340,4 +342,16 @@ export class GuestsService { guest.invalidAnswersInRow = 0; await guest.save(); } + + async incrementPrizeCount(telegramId: number) { + const guest = await this.findById(telegramId); + guest.rewardsReceived += 1; + await guest.save(); + } + + async updatePenaltiesCount(user: number) { + const guest = await this.findById(user); + guest.penaltiesReceived += 1; + await guest.save(); + } } diff --git a/src/mocks/gift-service.mock.ts b/src/mocks/gift-service.mock.ts new file mode 100644 index 0000000..1e5b4af --- /dev/null +++ b/src/mocks/gift-service.mock.ts @@ -0,0 +1,3 @@ +export const GiftServiceMock = { + getRemainingPrizeCount: () => jest.fn(), +} \ No newline at end of file diff --git a/src/mocks/quiz-service.mock.ts b/src/mocks/quiz-service.mock.ts new file mode 100644 index 0000000..4cef2c0 --- /dev/null +++ b/src/mocks/quiz-service.mock.ts @@ -0,0 +1,3 @@ +export const QuizServiceMock = { + getRemainQuestionCount: () =>jest.fn(), +} \ No newline at end of file diff --git a/src/mocks/shared-service.mock.ts b/src/mocks/shared-service.mock.ts new file mode 100644 index 0000000..e1696ae --- /dev/null +++ b/src/mocks/shared-service.mock.ts @@ -0,0 +1,3 @@ +export const SharedServiceMock = { + sendSocketNotificationToAllClients: jest.fn(), +} \ No newline at end of file diff --git a/src/mocks/state-service.mock.ts b/src/mocks/state-service.mock.ts new file mode 100644 index 0000000..797245e --- /dev/null +++ b/src/mocks/state-service.mock.ts @@ -0,0 +1,3 @@ +export const StateServiceMock = { + setState: jest.fn(), +} \ No newline at end of file diff --git a/src/quiz/quiz.controller.ts b/src/quiz/quiz.controller.ts index a0d850c..652de1f 100644 --- a/src/quiz/quiz.controller.ts +++ b/src/quiz/quiz.controller.ts @@ -1,7 +1,7 @@ -import { Body, Controller, Get, Post } from "@nestjs/common"; -import { QuestionDto, QuestionDtoExcel } from './dto/question.dto'; -import { QuizService } from "./quiz.service"; -import { ExtraQuestionDto } from './dto/extra-question.dto'; +import {Body, Controller, Get, Post} from "@nestjs/common"; +import {QuestionDto, QuestionDtoExcel} from './dto/question.dto'; +import {QuizService} from "./quiz.service"; +import {ExtraQuestionDto} from './dto/extra-question.dto'; @Controller('quiz') export class QuizController { @@ -50,4 +50,10 @@ export class QuizController { async dealPrize() { return this.quizService.dealPrize(); } + + @Get('endgame-extrapoints') + async endgameExtrapoints() + { + return await this.quizService.addEndgamePoints(); + } } diff --git a/src/quiz/quiz.service.ts b/src/quiz/quiz.service.ts index 821c573..42fb91a 100644 --- a/src/quiz/quiz.service.ts +++ b/src/quiz/quiz.service.ts @@ -10,12 +10,11 @@ import {ValidAnswerReceivedEvent} from '../game/events/valid-answer.recieved'; import {QuestionStorage, QuestionStorageDocument,} from '../schemas/question-storage.schema'; import {WrongAnswerReceivedEvent} from '../game/events/wrong-answer-received.event'; import {ProceedGameQueueCommand} from '../game/commands/proceed-game-queue.command'; -import {getRandomInt} from 'src/helpers/rand-number'; +import {getRandomInt} from '../helpers/rand-number'; import {Messages} from "../messaging/tg.text"; import {CreateNewQueueItemCommand} from "../game/commands/create-new-queue-item.command"; import {GameQueueTypes} from "../schemas/game-queue.schema"; import {IncreasePlayerWinningRateCommand} from "../game/commands/increase-player-winning-rate.command"; -import {SocketEvents} from "../shared/events.consts"; import {IncreasePlayerScoreCommand} from "../guests/command/increase-player-score.command"; @Injectable({ scope: Scope.TRANSIENT }) @@ -156,10 +155,36 @@ export class QuizService { return; } targetUser = lastInvalidAnswer.user; + await this.guestService.updatePenaltiesCount(lastInvalidAnswer.user); await this.commandBus.execute(new CreateNewQueueItemCommand(lastInvalidAnswer.user, GameQueueTypes.penalty)); } await this.commandBus.execute(new CreateNewQueueItemCommand(targetUser, GameQueueTypes.showresults)); + } + public async addEndgamePoints() { + const maxInvalidAnswersPromise = this.guestService.getModel().find({}).sort({ ['invalidAnswers']: 'desc'}).exec(); + const maxRewardsPromise = this.guestService.getModel().find({}).sort({['rewardsReceived']: "desc"}).exec(); + const maxPenaltiesPromise = this.guestService.getModel().find({}).sort({['penaltiesReceived']: 'desc'}).exec(); + + //const { maxRewards, maxInvalidAnswers } = Promise.all([maxRewardsPromise, maxInvalidAnswersPromise]); + const [maxRewards, maxInvalidAnswers, maxPenaltiesReceived] = await Promise.all([maxRewardsPromise, maxInvalidAnswersPromise, maxPenaltiesPromise]); + return { + maxInvalidAnswers: { + id: maxInvalidAnswers[0].id, + count: maxInvalidAnswers[0].invalidAnswers, + name: maxInvalidAnswers[0].name, + }, + maxRewards: { + id: maxRewards[0].id, + count: maxRewards[0].rewardsReceived, + name: maxRewards[0].name, + }, + maxPenalties: { + id: maxPenaltiesReceived[0].id, + count: maxPenaltiesReceived[0].penaltiesReceived, + name: maxPenaltiesReceived[0].name, + } + } } private async getNextQuestion() { diff --git a/src/scheduler/scheduler.service.spec.ts b/src/scheduler/scheduler.service.spec.ts index 1327eb5..e089e01 100644 --- a/src/scheduler/scheduler.service.spec.ts +++ b/src/scheduler/scheduler.service.spec.ts @@ -1,18 +1,55 @@ import { Test, TestingModule } from '@nestjs/testing'; import { SchedulerService } from './scheduler.service'; +import {GiftsService} from "../gifts/gifts.service"; +import {GiftServiceMock} from "../mocks/gift-service.mock"; +import {StateService} from "../state/state.service"; +import {StateServiceMock} from "../mocks/state-service.mock"; +import {QuizService} from "../quiz/quiz.service"; +import {QuizServiceMock} from "../mocks/quiz-service.mock"; +import {SharedService} from "../shared/shared.service"; +import {SharedServiceMock} from "../mocks/shared-service.mock"; + describe('SchedulerService', () => { let service: SchedulerService; - + let giftService: GiftsService; + let sharedService: SharedService; + let stateService: StateService; beforeEach(async () => { + jest.clearAllMocks(); const module: TestingModule = await Test.createTestingModule({ - providers: [SchedulerService], + providers: [SchedulerService, + { provide: GiftsService, useValue: GiftServiceMock }, + { provide: StateService, useValue: StateServiceMock }, + { provide: QuizService, useValue: QuizServiceMock }, + { provide: SharedService, useValue: SharedServiceMock }, + ], }).compile(); service = module.get(SchedulerService); + giftService = module.get(GiftsService); + sharedService = module.get(SharedService); + stateService = module.get(StateService); }); it('should be defined', () => { expect(service).toBeDefined(); }); + + it('should finish game if prizes count is 0', async () => { + const getRemainingPrizeCountFn = jest.spyOn(giftService, 'getRemainingPrizeCount').mockImplementation(() => Promise.resolve(0)); + const notificationFn = jest.spyOn(sharedService,'sendSocketNotificationToAllClients').mockImplementation(); + const setStateFn = jest.spyOn(stateService,'setState').mockImplementation((name,newstate) => Promise.resolve({ state: name, value: newstate})); + await service.gameStatus(); + expect(getRemainingPrizeCountFn).toHaveBeenCalled(); + expect(notificationFn).toHaveBeenCalled(); + expect(notificationFn).toHaveBeenCalledWith('state_changed', expect.objectContaining({ state: 'main', value: 'finish'})); + }); + + it('should not finish game if prizes count above 0', async () => { + const getRemainingPrizeCountFn = jest.spyOn(giftService, 'getRemainingPrizeCount').mockImplementation(() => Promise.resolve(5)); + const notificationFn = jest.spyOn(sharedService,'sendSocketNotificationToAllClients').mockImplementation() + await service.gameStatus(); + expect(notificationFn).not.toHaveBeenCalled(); + }); }); diff --git a/src/scheduler/scheduler.service.ts b/src/scheduler/scheduler.service.ts index 1b2974a..6898424 100644 --- a/src/scheduler/scheduler.service.ts +++ b/src/scheduler/scheduler.service.ts @@ -1,14 +1,10 @@ import { Injectable, Logger } from '@nestjs/common'; import { Cron } from '@nestjs/schedule'; import { StateService } from '../state/state.service'; -import {CommandBus, QueryBus} from '@nestjs/cqrs'; -import { GiftsService } from 'src/gifts/gifts.service'; -import { QuizService } from 'src/quiz/quiz.service'; -import { SharedService } from 'src/shared/shared.service'; -import {GetGuestPropertyQuery} from "../guests/command/get-guest-property.handler"; -import {GuestPropertiesConsts} from "../schemas/properties.consts"; -import {GetGuestQuery} from "../guests/queries/getguest.query"; -import {StringHelper} from "../helpers/stringhelper"; +import { QuizService } from '../quiz/quiz.service'; +import { GiftsService } from '../gifts/gifts.service'; +import { SharedService } from '../shared/shared.service'; + @Injectable() export class SchedulerService { private readonly logger = new Logger(SchedulerService.name); @@ -17,8 +13,6 @@ export class SchedulerService { constructor( private stateService: StateService, - private cmdBus: CommandBus, - private queryBus: QueryBus, private giftsService: GiftsService, private quizService: QuizService, private sharedService: SharedService, @@ -38,6 +32,7 @@ export class SchedulerService { const giftsLeft = await this.giftsService.getRemainingPrizeCount(); if (giftsLeft === 0) { const state = await this.stateService.setState('main', 'finish'); + console.log(this.state); this.sharedService.sendSocketNotificationToAllClients( 'state_changed', state, diff --git a/src/schemas/guest.schema.ts b/src/schemas/guest.schema.ts index 9ad02c2..e5ba7b2 100644 --- a/src/schemas/guest.schema.ts +++ b/src/schemas/guest.schema.ts @@ -25,8 +25,6 @@ export class Guest { @Prop({ default: 10 }) prizeChance: number; @Prop({ default: 0 }) - prizesCount: number; - @Prop({ default: 0 }) validAnswers: number; @Prop({ default: 0 }) invalidAnswers: number; @@ -34,6 +32,8 @@ export class Guest { invalidAnswersInRow: number; @Prop({ default:0 }) rewardsReceived: number; + @Prop({ default: 0}) + penaltiesReceived: number; @Prop({ type: Map }) properties: Record; } diff --git a/src/state/state.service.ts b/src/state/state.service.ts index 47dc65b..feaaaac 100644 --- a/src/state/state.service.ts +++ b/src/state/state.service.ts @@ -37,6 +37,9 @@ export class StateService { const stateEntity = await this.getState(name); stateEntity.value = newValue; await stateEntity.save(); - return stateEntity; + return { + state: stateEntity.state, + value: stateEntity.value, + } } }