mirror of
https://github.com/ershisan99/flashcards-api.git
synced 2025-12-16 20:59:26 +00:00
add duplicating random card prevention
This commit is contained in:
@@ -44,7 +44,6 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
if (req.cookies && 'accessToken' in req.cookies && req.cookies.accessToken.length > 0) {
|
||||
return req.cookies.accessToken
|
||||
}
|
||||
console.log(req.headers)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -34,18 +34,19 @@ import { CreateCardDto, GetAllCardsInDeckDto } from '../cards/dto'
|
||||
import { Card, PaginatedCards } from '../cards/entities/cards.entity'
|
||||
|
||||
import { DecksService } from './decks.service'
|
||||
import { UpdateDeckDto, CreateDeckDto, GetAllDecksDto } from './dto'
|
||||
import { CreateDeckDto, GetAllDecksDto, UpdateDeckDto } from './dto'
|
||||
import { GetRandomCardDto } from './dto/get-random-card.dto'
|
||||
import { Deck, DeckWithAuthor, PaginatedDecks } from './entities/deck.entity'
|
||||
import {
|
||||
CreateCardCommand,
|
||||
CreateDeckCommand,
|
||||
DeleteDeckByIdCommand,
|
||||
GetAllCardsInDeckCommand,
|
||||
GetAllDecksCommand,
|
||||
GetDeckByIdCommand,
|
||||
UpdateDeckCommand,
|
||||
GetRandomCardInDeckCommand,
|
||||
SaveGradeCommand,
|
||||
CreateCardCommand,
|
||||
UpdateDeckCommand,
|
||||
} from './use-cases'
|
||||
|
||||
@ApiTags('Decks')
|
||||
@@ -172,23 +173,33 @@ export class DecksController {
|
||||
summary: 'Retrieve a random card',
|
||||
})
|
||||
@Get(':id/learn')
|
||||
findRandomCardInDeck(@Param('id') id: string, @Req() req): Promise<Card> {
|
||||
return this.commandBus.execute(new GetRandomCardInDeckCommand(req.user.id, id))
|
||||
findRandomCardInDeck(
|
||||
@Param('id') id: string,
|
||||
@Req() req,
|
||||
@Query() query: GetRandomCardDto
|
||||
): Promise<Card> {
|
||||
return this.commandBus.execute(
|
||||
new GetRandomCardInDeckCommand(req.user.id, id, query.previousCardId)
|
||||
)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@ApiNotFoundResponse({ description: 'Card not found' })
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ApiNoContentResponse({ description: 'Grade saved' })
|
||||
@Post(':id/learn')
|
||||
@ApiOperation({
|
||||
description: 'Save the grade of a card',
|
||||
summary: 'Save the grade of a card',
|
||||
})
|
||||
saveGrade(@Param('id') id: string, @Req() req, @Body() body: SaveGradeDto): Promise<void> {
|
||||
return this.commandBus.execute(
|
||||
async saveGrade(@Param('id') id: string, @Req() req, @Body() body: SaveGradeDto) {
|
||||
const saved = await this.commandBus.execute(
|
||||
new SaveGradeCommand(req.user.id, { cardId: body.cardId, grade: body.grade })
|
||||
)
|
||||
|
||||
return await this.commandBus.execute(
|
||||
new GetRandomCardInDeckCommand(req.user.id, saved.deckId, saved.id)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
6
src/modules/decks/dto/get-random-card.dto.ts
Normal file
6
src/modules/decks/dto/get-random-card.dto.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { IsOptionalOrEmptyString } from '../../../infrastructure/decorators'
|
||||
|
||||
export class GetRandomCardDto {
|
||||
@IsOptionalOrEmptyString()
|
||||
previousCardId?: string
|
||||
}
|
||||
@@ -8,7 +8,11 @@ import { CardsRepository } from '../../cards/infrastructure/cards.repository'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
|
||||
export class GetRandomCardInDeckCommand {
|
||||
constructor(public readonly userId: string, public readonly deckId: string) {}
|
||||
constructor(
|
||||
public readonly userId: string,
|
||||
public readonly deckId: string,
|
||||
public readonly previousCardId: string
|
||||
) {}
|
||||
}
|
||||
|
||||
type CardWithGrade = Prisma.cardGetPayload<{ include: { grades: true } }>
|
||||
@@ -41,6 +45,19 @@ export class GetRandomCardInDeckHandler implements ICommandHandler<GetRandomCard
|
||||
return selectionPool[Math.floor(Math.random() * selectionPool.length)]
|
||||
}
|
||||
|
||||
private async getNotDuplicateRandomCard(
|
||||
cards: Array<CardWithGrade>,
|
||||
previousCardId: string
|
||||
): Promise<Card> {
|
||||
const randomCard = await this.getSmartRandomCard(cards)
|
||||
|
||||
if (randomCard.id === previousCardId) {
|
||||
return this.getNotDuplicateRandomCard(cards, previousCardId)
|
||||
}
|
||||
|
||||
return randomCard
|
||||
}
|
||||
|
||||
async execute(command: GetRandomCardInDeckCommand) {
|
||||
const deck = await this.decksRepository.findDeckById(command.deckId)
|
||||
|
||||
@@ -54,7 +71,7 @@ export class GetRandomCardInDeckHandler implements ICommandHandler<GetRandomCard
|
||||
command.userId,
|
||||
command.deckId
|
||||
)
|
||||
const smartRandomCard = await this.getSmartRandomCard(cards)
|
||||
const smartRandomCard = await this.getNotDuplicateRandomCard(cards, command.previousCardId)
|
||||
|
||||
return pick(smartRandomCard, [
|
||||
'id',
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { ForbiddenException, NotFoundException } from '@nestjs/common'
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { CardsRepository } from '../../cards/infrastructure/cards.repository'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
import { GradesRepository } from '../infrastructure/grades.repository'
|
||||
|
||||
@@ -18,12 +17,11 @@ export class SaveGradeCommand {
|
||||
@CommandHandler(SaveGradeCommand)
|
||||
export class SaveGradeHandler implements ICommandHandler<SaveGradeCommand> {
|
||||
constructor(
|
||||
private readonly cardsRepository: CardsRepository,
|
||||
private readonly decksRepository: DecksRepository,
|
||||
private readonly gradesRepository: GradesRepository
|
||||
) {}
|
||||
|
||||
async execute(command: SaveGradeCommand): Promise<void> {
|
||||
async execute(command: SaveGradeCommand) {
|
||||
const deck = await this.decksRepository.findDeckByCardId(command.args.cardId)
|
||||
|
||||
if (!deck)
|
||||
@@ -33,7 +31,7 @@ export class SaveGradeHandler implements ICommandHandler<SaveGradeCommand> {
|
||||
throw new ForbiddenException(`You can't save cards to a private deck that you don't own`)
|
||||
}
|
||||
|
||||
await this.gradesRepository.createGrade({
|
||||
return await this.gradesRepository.createGrade({
|
||||
userId: command.userId,
|
||||
grade: command.args.grade,
|
||||
cardId: command.args.cardId,
|
||||
|
||||
Reference in New Issue
Block a user