mirror of
https://github.com/ershisan99/flashcards-api.git
synced 2025-12-17 12:33:22 +00:00
add decks documentation
This commit is contained in:
@@ -52,7 +52,7 @@ import {
|
||||
export class AuthController {
|
||||
constructor(private commandBus: CommandBus) {}
|
||||
|
||||
@ApiOperation({ description: 'Retrieve current user data.' })
|
||||
@ApiOperation({ description: 'Retrieve current user data.', summary: 'Current user data' })
|
||||
@ApiUnauthorizedResponse({ description: 'Not logged in' })
|
||||
@ApiBadRequestResponse({ description: 'User not found' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@@ -63,7 +63,10 @@ export class AuthController {
|
||||
return await this.commandBus.execute(new GetCurrentUserDataCommand(userId))
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Sign in using email and password. Must have an account to do so.' })
|
||||
@ApiOperation({
|
||||
description: 'Sign in using email and password. Must have an account to do so.',
|
||||
summary: 'Sign in using email and password. Must have an account to do so.',
|
||||
})
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid credentials' })
|
||||
@ApiBody({ type: LoginDto })
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@@ -90,7 +93,7 @@ export class AuthController {
|
||||
return { accessToken: req.user.data.accessToken }
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Create a new user account' })
|
||||
@ApiOperation({ description: 'Create a new user account', summary: 'Create a new user account' })
|
||||
@ApiBadRequestResponse({ description: 'Email already exists' })
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@Post('sign-up')
|
||||
@@ -98,7 +101,7 @@ export class AuthController {
|
||||
return await this.commandBus.execute(new CreateUserCommand(registrationData))
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Verify user email' })
|
||||
@ApiOperation({ description: 'Verify user email', summary: 'Verify user email' })
|
||||
@ApiBadRequestResponse({ description: 'Email has already been verified' })
|
||||
@ApiNotFoundResponse({ description: 'User not found' })
|
||||
@ApiNoContentResponse({ description: 'Email verified successfully' })
|
||||
@@ -108,7 +111,10 @@ export class AuthController {
|
||||
return await this.commandBus.execute(new VerifyEmailCommand(body.code))
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Send verification email again' })
|
||||
@ApiOperation({
|
||||
description: 'Send verification email again',
|
||||
summary: 'Send verification email again',
|
||||
})
|
||||
@ApiBadRequestResponse({ description: 'Email has already been verified' })
|
||||
@ApiNotFoundResponse({ description: 'User not found' })
|
||||
@ApiNoContentResponse({ description: 'Verification email sent successfully' })
|
||||
@@ -118,7 +124,7 @@ export class AuthController {
|
||||
return await this.commandBus.execute(new ResendVerificationEmailCommand(body.userId))
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Sign current user out' })
|
||||
@ApiOperation({ description: 'Sign current user out', summary: 'Sign current user out' })
|
||||
@ApiUnauthorizedResponse({ description: 'Not logged in' })
|
||||
@ApiNoContentResponse({ description: 'Logged out successfully' })
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
@@ -136,7 +142,10 @@ export class AuthController {
|
||||
return null
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Get new access token using refresh token' })
|
||||
@ApiOperation({
|
||||
description: 'Get new access token using refresh token',
|
||||
summary: 'Get new access token using refresh token',
|
||||
})
|
||||
@ApiUnauthorizedResponse({ description: 'Invalid or missing refreshToken' })
|
||||
@ApiNoContentResponse({ description: 'New tokens generated successfully' })
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
@@ -165,7 +174,10 @@ export class AuthController {
|
||||
return null
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Send password recovery email' })
|
||||
@ApiOperation({
|
||||
description: 'Send password recovery email',
|
||||
summary: 'Send password recovery email',
|
||||
})
|
||||
@ApiBadRequestResponse({ description: 'Email has already been verified' })
|
||||
@ApiNotFoundResponse({ description: 'User not found' })
|
||||
@ApiNoContentResponse({ description: 'Password recovery email sent successfully' })
|
||||
@@ -175,7 +187,7 @@ export class AuthController {
|
||||
return await this.commandBus.execute(new SendPasswordRecoveryEmailCommand(body.email))
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Reset password' })
|
||||
@ApiOperation({ description: 'Reset password', summary: 'Reset password' })
|
||||
@ApiBadRequestResponse({ description: 'Password is required' })
|
||||
@ApiNotFoundResponse({ description: 'Incorrect or expired password reset token' })
|
||||
@ApiNoContentResponse({ description: 'Password reset successfully' })
|
||||
|
||||
@@ -3,4 +3,5 @@ export * from './login.dto'
|
||||
export * from './recover-password.dto'
|
||||
export * from './registration.dto'
|
||||
export * from './resend-verification-email.dto'
|
||||
export * from './save-grade.dto'
|
||||
export * from './update-auth.dto'
|
||||
|
||||
4
src/modules/auth/dto/save-grade.dto.ts
Normal file
4
src/modules/auth/dto/save-grade.dto.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export class SaveGradeDto {
|
||||
cardId: string
|
||||
grade: number
|
||||
}
|
||||
@@ -1 +1,20 @@
|
||||
export class Card {}
|
||||
import { Pagination } from '../../../infrastructure/common/pagination/pagination.dto'
|
||||
|
||||
export class Card {
|
||||
id: string
|
||||
deckId: string
|
||||
userId: string
|
||||
question: string
|
||||
answer: string
|
||||
shots: number
|
||||
answerImg: string
|
||||
questionImg: string
|
||||
rating: number
|
||||
created: Date
|
||||
updated: Date
|
||||
}
|
||||
|
||||
export class PaginatedCards {
|
||||
items: Card[]
|
||||
pagination: Pagination
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createPrismaOrderBy } from '../../../infrastructure/common/helpers/get-
|
||||
import { Pagination } from '../../../infrastructure/common/pagination/pagination.service'
|
||||
import { PrismaService } from '../../../prisma.service'
|
||||
import { CreateCardDto, GetAllCardsInDeckDto, UpdateCardDto } from '../dto'
|
||||
import { PaginatedCards } from '../entities/cards.entity'
|
||||
|
||||
@Injectable()
|
||||
export class CardsRepository {
|
||||
@@ -59,7 +60,7 @@ export class CardsRepository {
|
||||
itemsPerPage,
|
||||
orderBy,
|
||||
}: GetAllCardsInDeckDto
|
||||
) {
|
||||
): Promise<PaginatedCards> {
|
||||
try {
|
||||
const where = {
|
||||
decks: {
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
Controller,
|
||||
Delete,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Param,
|
||||
Patch,
|
||||
Post,
|
||||
@@ -15,14 +17,25 @@ import {
|
||||
} from '@nestjs/common'
|
||||
import { CommandBus } from '@nestjs/cqrs'
|
||||
import { FileFieldsInterceptor } from '@nestjs/platform-express'
|
||||
import { ApiTags } from '@nestjs/swagger'
|
||||
import {
|
||||
ApiConsumes,
|
||||
ApiNoContentResponse,
|
||||
ApiNotFoundResponse,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
ApiTags,
|
||||
ApiUnauthorizedResponse,
|
||||
} from '@nestjs/swagger'
|
||||
|
||||
import { Pagination } from '../../infrastructure/common/pagination/pagination.service'
|
||||
import { SaveGradeDto } from '../auth/dto'
|
||||
import { JwtAuthGuard } from '../auth/guards'
|
||||
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 { Deck, PaginatedDecks } from './entities/deck.entity'
|
||||
import {
|
||||
CreateDeckCommand,
|
||||
DeleteDeckByIdCommand,
|
||||
@@ -40,6 +53,20 @@ import {
|
||||
export class DecksController {
|
||||
constructor(private readonly decksService: DecksService, private commandBus: CommandBus) {}
|
||||
|
||||
@HttpCode(HttpStatus.PARTIAL_CONTENT)
|
||||
@ApiOperation({ description: 'Retrieve paginated decks list.', summary: 'Paginated decks list' })
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
findAll(@Query() query: GetAllDecksDto, @Req() req): Promise<PaginatedDecks> {
|
||||
const finalQuery = Pagination.getPaginationData(query)
|
||||
|
||||
return this.commandBus.execute(new GetAllDecksCommand({ ...finalQuery, userId: req.user.id }))
|
||||
}
|
||||
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@ApiOperation({ description: 'Create a deck', summary: 'Create a deck' })
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseInterceptors(FileFieldsInterceptor([{ name: 'cover', maxCount: 1 }]))
|
||||
@Post()
|
||||
@@ -50,7 +77,7 @@ export class DecksController {
|
||||
cover: Express.Multer.File[]
|
||||
},
|
||||
@Body() createDeckDto: CreateDeckDto
|
||||
) {
|
||||
): Promise<Deck> {
|
||||
const userId = req.user.id
|
||||
|
||||
return this.commandBus.execute(
|
||||
@@ -58,42 +85,64 @@ export class DecksController {
|
||||
)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get()
|
||||
findAll(@Query() query: GetAllDecksDto, @Req() req) {
|
||||
const finalQuery = Pagination.getPaginationData(query)
|
||||
|
||||
return this.commandBus.execute(new GetAllDecksCommand({ ...finalQuery, userId: req.user.id }))
|
||||
}
|
||||
|
||||
@ApiOperation({ description: 'Retrieve a deck by id', summary: 'Retrieve a deck by id' })
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':id')
|
||||
findOne(@Param('id') id: string) {
|
||||
findOne(@Param('id') id: string): Promise<Deck> {
|
||||
return this.commandBus.execute(new GetDeckByIdCommand(id))
|
||||
}
|
||||
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@ApiOperation({ description: 'Update a deck', summary: 'Update a deck' })
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@ApiNotFoundResponse({ description: 'Deck not found' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseInterceptors(FileFieldsInterceptor([{ name: 'cover', maxCount: 1 }]))
|
||||
@Patch(':id')
|
||||
update(
|
||||
@Param('id') id: string,
|
||||
@UploadedFiles()
|
||||
files: {
|
||||
cover: Express.Multer.File[]
|
||||
},
|
||||
@Body() updateDeckDto: UpdateDeckDto,
|
||||
@Req() req
|
||||
): Promise<Deck> {
|
||||
return this.commandBus.execute(
|
||||
new UpdateDeckCommand(id, updateDeckDto, req.user.id, files?.cover?.[0])
|
||||
)
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@ApiOperation({ description: 'Delete a deck', summary: 'Delete a deck' })
|
||||
@ApiOkResponse({ description: 'Deck deleted', type: Deck })
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@ApiNotFoundResponse({ description: 'Deck not found' })
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string, @Req() req): Promise<Deck> {
|
||||
return this.commandBus.execute(new DeleteDeckByIdCommand(id, req.user.id))
|
||||
}
|
||||
@ApiOperation({
|
||||
description: 'Retrieve paginated cards in a deck',
|
||||
summary: 'Retrieve cards in a deck',
|
||||
})
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':id/cards')
|
||||
findCardsInDeck(@Param('id') id: string, @Req() req, @Query() query: GetAllCardsInDeckDto) {
|
||||
findCardsInDeck(
|
||||
@Param('id') id: string,
|
||||
@Req() req,
|
||||
@Query() query: GetAllCardsInDeckDto
|
||||
): Promise<PaginatedCards> {
|
||||
const finalQuery = Pagination.getPaginationData(query)
|
||||
|
||||
return this.commandBus.execute(new GetAllCardsInDeckCommand(req.user.id, id, finalQuery))
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get(':id/learn')
|
||||
findRandomCardInDeck(@Param('id') id: string, @Req() req) {
|
||||
return this.commandBus.execute(new GetRandomCardInDeckCommand(req.user.id, id))
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Post(':id/learn')
|
||||
saveGrade(@Param('id') id: string, @Req() req, @Body() body: any) {
|
||||
return this.commandBus.execute(
|
||||
new SaveGradeCommand(req.user.id, { cardId: body.cardId, grade: body.grade })
|
||||
)
|
||||
}
|
||||
|
||||
@ApiConsumes('multipart/form-data')
|
||||
@ApiOperation({ description: 'Create card in a deck', summary: 'Create a card' })
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@ApiNotFoundResponse({ description: 'Deck not found' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseInterceptors(
|
||||
FileFieldsInterceptor([
|
||||
@@ -108,32 +157,36 @@ export class DecksController {
|
||||
@UploadedFiles()
|
||||
files: { questionImg: Express.Multer.File[]; answerImg: Express.Multer.File[] },
|
||||
@Body() card: CreateCardDto
|
||||
) {
|
||||
): Promise<Card> {
|
||||
return this.commandBus.execute(
|
||||
new CreateCardCommand(req.user.id, id, card, files.answerImg?.[0], files.questionImg?.[0])
|
||||
)
|
||||
}
|
||||
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@UseInterceptors(FileFieldsInterceptor([{ name: 'cover', maxCount: 1 }]))
|
||||
@Patch(':id')
|
||||
update(
|
||||
@Param('id') id: string,
|
||||
@UploadedFiles()
|
||||
files: {
|
||||
cover: Express.Multer.File[]
|
||||
},
|
||||
@Body() updateDeckDto: UpdateDeckDto,
|
||||
@Req() req
|
||||
) {
|
||||
return this.commandBus.execute(
|
||||
new UpdateDeckCommand(id, updateDeckDto, req.user.id, files?.cover?.[0])
|
||||
)
|
||||
@ApiOperation({
|
||||
description: 'Retrieve a random card in a deck. The cards priority is based on the grade',
|
||||
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))
|
||||
}
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Delete(':id')
|
||||
remove(@Param('id') id: string, @Req() req) {
|
||||
return this.commandBus.execute(new DeleteDeckByIdCommand(id, req.user.id))
|
||||
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
|
||||
@ApiNotFoundResponse({ description: 'Card not found' })
|
||||
@HttpCode(HttpStatus.NO_CONTENT)
|
||||
@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(
|
||||
new SaveGradeCommand(req.user.id, { cardId: body.cardId, grade: body.grade })
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger'
|
||||
import { Transform } from 'class-transformer'
|
||||
import { IsBoolean, IsOptional, Length } from 'class-validator'
|
||||
|
||||
export class CreateDeckDto {
|
||||
@Length(3, 30)
|
||||
name: string
|
||||
|
||||
/**
|
||||
* Cover image (binary)
|
||||
*/
|
||||
@IsOptional()
|
||||
@Length(0, 0)
|
||||
@ApiProperty({ type: 'string', format: 'binary' })
|
||||
cover?: string
|
||||
|
||||
/**
|
||||
* Private decks are not visible to other users
|
||||
*/
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform((val: string) => [true, 'true', 1, '1'].indexOf(val) > -1)
|
||||
isPrivate?: boolean
|
||||
|
||||
@ApiHideProperty()
|
||||
userId: string
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ApiHideProperty } from '@nestjs/swagger'
|
||||
import { IsUUID } from 'class-validator'
|
||||
|
||||
import { PaginationDto } from '../../../infrastructure/common/pagination/pagination.dto'
|
||||
@@ -10,15 +11,23 @@ export class GetAllDecksDto extends PaginationDto {
|
||||
@IsOptionalOrEmptyString()
|
||||
maxCardsCount?: string
|
||||
|
||||
/** Search by deck name */
|
||||
@IsOptionalOrEmptyString()
|
||||
name?: string
|
||||
|
||||
/** Filter by deck authorId */
|
||||
@IsOptionalOrEmptyString()
|
||||
@IsUUID(4)
|
||||
authorId?: string
|
||||
|
||||
userId: string
|
||||
@ApiHideProperty()
|
||||
userId?: string
|
||||
|
||||
/** A string that represents the name of the field to order by and the order direction.
|
||||
* The format is: "field_name-order_direction".
|
||||
* Available directions: "asc" and "desc".
|
||||
* @example "name-desc"
|
||||
* */
|
||||
@IsOrderBy()
|
||||
orderBy?: string | null
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { PartialType } from '@nestjs/mapped-types'
|
||||
import { ApiProperty } from '@nestjs/swagger'
|
||||
import { IsBoolean } from 'class-validator'
|
||||
|
||||
import { IsOptionalOrEmptyString } from '../../../infrastructure/decorators'
|
||||
@@ -7,12 +8,13 @@ import { CreateDeckDto } from './create-deck.dto'
|
||||
|
||||
export class UpdateDeckDto extends PartialType(CreateDeckDto) {
|
||||
@IsOptionalOrEmptyString()
|
||||
name: string
|
||||
name?: string
|
||||
|
||||
@IsOptionalOrEmptyString()
|
||||
@IsBoolean()
|
||||
isPrivate: boolean
|
||||
isPrivate?: boolean
|
||||
|
||||
@IsOptionalOrEmptyString()
|
||||
cover: string
|
||||
@ApiProperty({ type: 'string', format: 'binary' })
|
||||
cover?: string
|
||||
}
|
||||
|
||||
@@ -1 +1,26 @@
|
||||
export class Deck {}
|
||||
import { Pagination } from '../../../infrastructure/common/pagination/pagination.dto'
|
||||
|
||||
export class Deck {
|
||||
id: string
|
||||
userId: string
|
||||
name: string
|
||||
isPrivate: boolean
|
||||
shots: number
|
||||
cover: string | null
|
||||
rating: number
|
||||
created: Date
|
||||
updated: Date
|
||||
cardsCount: number
|
||||
author: DeckAuthor
|
||||
}
|
||||
|
||||
export class DeckAuthor {
|
||||
id: string
|
||||
name: string
|
||||
}
|
||||
|
||||
export class PaginatedDecks {
|
||||
items: Deck[]
|
||||
pagination: Pagination
|
||||
maxCardsCount: number
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import { createPrismaOrderBy } from '../../../infrastructure/common/helpers/get-
|
||||
import { Pagination } from '../../../infrastructure/common/pagination/pagination.service'
|
||||
import { PrismaService } from '../../../prisma.service'
|
||||
import { GetAllDecksDto } from '../dto'
|
||||
import { Deck, PaginatedDecks } from '../entities/deck.entity'
|
||||
|
||||
@Injectable()
|
||||
export class DecksRepository {
|
||||
@@ -21,7 +22,7 @@ export class DecksRepository {
|
||||
userId: string
|
||||
cover?: string
|
||||
isPrivate?: boolean
|
||||
}) {
|
||||
}): Promise<Deck> {
|
||||
try {
|
||||
return await this.prisma.deck.create({
|
||||
data: {
|
||||
@@ -35,6 +36,14 @@ export class DecksRepository {
|
||||
cover,
|
||||
isPrivate,
|
||||
},
|
||||
include: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
this.logger.error(e?.message)
|
||||
@@ -51,9 +60,7 @@ export class DecksRepository {
|
||||
minCardsCount,
|
||||
maxCardsCount,
|
||||
orderBy,
|
||||
}: GetAllDecksDto) {
|
||||
console.log(minCardsCount)
|
||||
console.log(Number(minCardsCount))
|
||||
}: GetAllDecksDto): Promise<PaginatedDecks> {
|
||||
try {
|
||||
const where = {
|
||||
cardsCount: {
|
||||
@@ -163,13 +170,21 @@ export class DecksRepository {
|
||||
public async updateDeckById(
|
||||
id: string,
|
||||
data: { name?: string; cover?: string; isPrivate?: boolean }
|
||||
) {
|
||||
): Promise<Deck> {
|
||||
try {
|
||||
return await this.prisma.deck.update({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
data,
|
||||
include: {
|
||||
author: {
|
||||
select: {
|
||||
id: true,
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
} catch (e) {
|
||||
this.logger.error(e?.message)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { FileUploadService } from '../../../infrastructure/file-upload-service/file-upload.service'
|
||||
import { CreateCardDto } from '../../cards/dto'
|
||||
import { Card } from '../../cards/entities/cards.entity'
|
||||
import { CardsRepository } from '../../cards/infrastructure/cards.repository'
|
||||
|
||||
export class CreateCardCommand {
|
||||
@@ -21,7 +22,7 @@ export class CreateCardHandler implements ICommandHandler<CreateCardCommand> {
|
||||
private readonly fileUploadService: FileUploadService
|
||||
) {}
|
||||
|
||||
async execute(command: CreateCardCommand) {
|
||||
async execute(command: CreateCardCommand): Promise<Card> {
|
||||
let questionImg, answerImg
|
||||
|
||||
if (command.questionImg && command.answerImg) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { FileUploadService } from '../../../infrastructure/file-upload-service/file-upload.service'
|
||||
import { CreateDeckDto } from '../dto'
|
||||
import { Deck } from '../entities/deck.entity'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
|
||||
export class CreateDeckCommand {
|
||||
@@ -15,7 +16,7 @@ export class CreateDeckHandler implements ICommandHandler<CreateDeckCommand> {
|
||||
private readonly fileUploadService: FileUploadService
|
||||
) {}
|
||||
|
||||
async execute(command: CreateDeckCommand) {
|
||||
async execute(command: CreateDeckCommand): Promise<Deck> {
|
||||
let cover
|
||||
|
||||
if (command.cover) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { BadRequestException, NotFoundException } from '@nestjs/common'
|
||||
import { ForbiddenException, NotFoundException } from '@nestjs/common'
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
@@ -16,7 +16,7 @@ export class DeleteDeckByIdHandler implements ICommandHandler<DeleteDeckByIdComm
|
||||
|
||||
if (!deck) throw new NotFoundException(`Deck with id ${command.id} not found`)
|
||||
if (deck.userId !== command.userId) {
|
||||
throw new BadRequestException(`You can't delete a deck that you don't own`)
|
||||
throw new ForbiddenException(`You can't delete a deck that you don't own`)
|
||||
}
|
||||
|
||||
return await this.deckRepository.deleteDeckById(command.id)
|
||||
|
||||
@@ -2,6 +2,7 @@ import { ForbiddenException, NotFoundException } from '@nestjs/common'
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { GetAllCardsInDeckDto } from '../../cards/dto'
|
||||
import { PaginatedCards } from '../../cards/entities/cards.entity'
|
||||
import { CardsRepository } from '../../cards/infrastructure/cards.repository'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
|
||||
@@ -20,7 +21,7 @@ export class GetAllCardsInDeckHandler implements ICommandHandler<GetAllCardsInDe
|
||||
private readonly decksRepository: DecksRepository
|
||||
) {}
|
||||
|
||||
async execute(command: GetAllCardsInDeckCommand) {
|
||||
async execute(command: GetAllCardsInDeckCommand): Promise<PaginatedCards> {
|
||||
const deck = await this.decksRepository.findDeckById(command.deckId)
|
||||
|
||||
if (!deck) throw new NotFoundException(`Deck with id ${command.deckId} not found`)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { GetAllDecksDto } from '../dto'
|
||||
import { PaginatedDecks } from '../entities/deck.entity'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
|
||||
export class GetAllDecksCommand {
|
||||
@@ -11,7 +12,7 @@ export class GetAllDecksCommand {
|
||||
export class GetAllDecksHandler implements ICommandHandler<GetAllDecksCommand> {
|
||||
constructor(private readonly deckRepository: DecksRepository) {}
|
||||
|
||||
async execute(command: GetAllDecksCommand) {
|
||||
async execute(command: GetAllDecksCommand): Promise<PaginatedDecks> {
|
||||
return await this.deckRepository.findAllDecks(command.params)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
import { Prisma } from '@prisma/client'
|
||||
import { pick } from 'remeda'
|
||||
|
||||
import { Card } from '../../cards/entities/cards.entity'
|
||||
import { CardsRepository } from '../../cards/infrastructure/cards.repository'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
|
||||
@@ -19,7 +20,7 @@ export class GetRandomCardInDeckHandler implements ICommandHandler<GetRandomCard
|
||||
private readonly decksRepository: DecksRepository
|
||||
) {}
|
||||
|
||||
private async getSmartRandomCard(cards: Array<CardWithGrade>) {
|
||||
private async getSmartRandomCard(cards: Array<CardWithGrade>): Promise<Card> {
|
||||
const selectionPool: Array<CardWithGrade> = []
|
||||
|
||||
cards.forEach(card => {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class SaveGradeHandler implements ICommandHandler<SaveGradeCommand> {
|
||||
private readonly gradesRepository: GradesRepository
|
||||
) {}
|
||||
|
||||
async execute(command: SaveGradeCommand) {
|
||||
async execute(command: SaveGradeCommand): Promise<void> {
|
||||
const deck = await this.decksRepository.findDeckByCardId(command.args.cardId)
|
||||
|
||||
if (!deck)
|
||||
@@ -33,7 +33,7 @@ export class SaveGradeHandler implements ICommandHandler<SaveGradeCommand> {
|
||||
throw new ForbiddenException(`You can't save cards to a private deck that you don't own`)
|
||||
}
|
||||
|
||||
return await this.gradesRepository.createGrade({
|
||||
await this.gradesRepository.createGrade({
|
||||
userId: command.userId,
|
||||
grade: command.args.grade,
|
||||
cardId: command.args.cardId,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
|
||||
|
||||
import { FileUploadService } from '../../../infrastructure/file-upload-service/file-upload.service'
|
||||
import { UpdateDeckDto } from '../dto'
|
||||
import { Deck } from '../entities/deck.entity'
|
||||
import { DecksRepository } from '../infrastructure/decks.repository'
|
||||
|
||||
export class UpdateDeckCommand {
|
||||
@@ -21,7 +22,7 @@ export class UpdateDeckHandler implements ICommandHandler<UpdateDeckCommand> {
|
||||
private readonly fileUploadService: FileUploadService
|
||||
) {}
|
||||
|
||||
async execute(command: UpdateDeckCommand) {
|
||||
async execute(command: UpdateDeckCommand): Promise<Deck> {
|
||||
const deck = await this.deckRepository.findDeckById(command.deckId)
|
||||
|
||||
if (!deck) {
|
||||
|
||||
Reference in New Issue
Block a user