import { InjectQueue } from '@nestjs/bullmq'; import { Body, Controller, Delete, Get, Post, Put, Request, Res, UseGuards } from '@nestjs/common'; import { Response } from 'express'; import { Queue } from 'bullmq'; import { PinoLogger } from 'nestjs-pino'; import { BooksService } from 'src/books/books.service'; import { BookSearchResultDto } from 'src/providers/dto/book-search-result.dto'; import { SeriesService } from 'src/series/series.service'; import { QueryFailedError } from 'typeorm'; import { UpdateBookDto } from 'src/books/dto/update-book.dto'; import { UpdateBookOriginDto } from 'src/books/dto/update-book-origin.dto'; import { LibraryService } from './library.service'; import { CreateSeriesSubscriptionDto } from 'src/series/dto/create-series-subscription.dto'; import { JwtAccessGuard } from 'src/auth/guards/jwt-access.guard'; import { SeriesDto } from 'src/series/dto/series.dto'; import { CreateBookOriginDto } from 'src/books/dto/create-book-origin.dto'; import { DeleteBookStatusDto } from 'src/books/dto/delete-book-status.dto'; @UseGuards(JwtAccessGuard) @Controller('library') export class LibraryController { constructor( private readonly books: BooksService, private readonly series: SeriesService, private readonly library: LibraryService, @InjectQueue('library') private readonly jobs: Queue, private readonly logger: PinoLogger, ) { } @Get('series') async getSeries( @Request() req, @Res({ passthrough: true }) response: Response, ) { return { success: true, data: await this.series.getAllSeries(), }; } @Post('series') async createSeries( @Request() req, @Body() body: CreateSeriesSubscriptionDto, @Res({ passthrough: true }) response: Response, ) { try { await this.library.addSeries({ provider: body.provider, providerSeriesId: body.providerSeriesId, title: body.title, }); return { success: true, }; } catch (err) { if (err instanceof QueryFailedError) { if (err.driverError.code == '23505') { // Subscription already exist. response.statusCode = 409; return { success: false, error_message: 'Series subscription already exists.', }; } } response.statusCode = 500; return { success: false, error_message: 'Something went wrong.', }; } } @Get('series/subscriptions') async getSeriesSubscriptions( @Request() req, @Res({ passthrough: true }) response: Response, ) { return { success: true, data: await this.series.getSeriesSubscribedBy(req.user.userId), }; } @Post('series/subscribe') async subscribe( @Request() req, @Body() body: SeriesDto, @Res({ passthrough: true }) response: Response, ) { try { await this.library.addSubscription({ ...body, userId: req.user.userId, }); return { success: true, }; } catch (err) { if (err instanceof QueryFailedError) { if (err.driverError.code == '23505') { // Subscription already exists. response.statusCode = 409; return { success: false, error_message: 'Series subscription already exists.', }; } else if (err.driverError.code == '23503') { // Series does not exist. response.statusCode = 400; return { success: false, error_message: 'Series does not exist.', }; } } response.statusCode = 500; return { success: false, error_message: 'Something went wrong.', }; } } @Get('books') async getBooksFromUser( @Request() req, ) { return { success: true, data: await this.books.findBookStatusesTrackedBy(req.user.userId), }; } @Post('books') async createBook( @Request() req, @Body() body: BookSearchResultDto, @Res({ passthrough: true }) response: Response, ) { if (body.provider && body.providerSeriesId) { try { await this.series.updateSeries({ provider: body.provider, providerSeriesId: body.providerSeriesId, title: body.title, }); } catch (err) { if (err instanceof QueryFailedError) { // Ignore if the series already exist. if (err.driverError.code != '23505') { response.statusCode = 500; return { success: false, error_message: 'Something went wrong.', }; } } } } try { return { success: true, data: await this.books.createBook(body), }; } catch (err) { if (err instanceof QueryFailedError) { if (err.driverError.code == '23505') { // Book exists already. response.statusCode = 409; return { success: false, error_message: 'The book has already been added previously.', }; } else if (err.driverError.code == '23503') { // Data dependency is missing. response.statusCode = 500; return { success: false, error_message: 'Series has not been added.', }; } } this.logger.error({ class: LibraryController.name, method: this.createBook.name, user: req.user, msg: 'Failed to create book.', error: err, }); response.statusCode = 500; return { success: false, error_message: 'Something went wrong while adding the book.', }; } } @Put('books') async updateBook( @Body() body: UpdateBookDto, ) { const data = { ...body }; delete data['bookId']; const result = await this.books.updateBook(body.bookId, data); return { success: result?.affected == 1, }; } @Delete('books/origins') async deleteBookOrigin( @Body() body: CreateBookOriginDto, ) { const data = { ...body }; delete data['bookOriginId']; const result = await this.books.deleteBookOrigin(body); return { success: result?.affected == 1, }; } @Delete('books/status') async deleteBookStatus( @Body() body: DeleteBookStatusDto, ) { const data = { ...body }; delete data['bookOriginId']; const result = await this.books.deleteBookStatus(body); return { success: result?.affected == 1, }; } @Put('books/origins') async updateBookOrigin( @Body() body: UpdateBookOriginDto, ) { const data = { ...body }; delete data['bookOriginId']; const result = await this.books.updateBookOrigin(body.bookOriginId, data); return { success: result?.affected == 1, }; } }