updating dependencies, fixing server reloads

This commit is contained in:
Amruth Pillai
2023-06-07 18:39:14 +02:00
parent c571f201d3
commit d4b6c16bf9
25 changed files with 1674 additions and 1821 deletions

View File

@ -7,9 +7,8 @@ import { join } from 'path';
import { AuthModule } from './auth/auth.module';
import { ConfigModule } from './config/config.module';
import { DatabaseModule } from './database/database.module';
import { HttpExceptionFilter } from './filters/http-exception.filter';
import { AllExceptionsFilter } from './filters/all-exceptions.filter';
import { FontsModule } from './fonts/fonts.module';
import { HealthModule } from './health/health.module';
import { IntegrationsModule } from './integrations/integrations.module';
import { MailModule } from './mail/mail.module';
import { PrinterModule } from './printer/printer.module';
@ -33,7 +32,6 @@ import { UsersModule } from './users/users.module';
FontsModule,
IntegrationsModule,
PrinterModule,
HealthModule,
],
providers: [
{
@ -42,7 +40,7 @@ import { UsersModule } from './users/users.module';
},
{
provide: APP_FILTER,
useClass: HttpExceptionFilter,
useClass: AllExceptionsFilter,
},
],
})

View File

@ -1,4 +1,4 @@
import { Body, Controller, Delete, Get, HttpCode, Patch, Post, UseGuards } from '@nestjs/common';
import { BadRequestException, Body, Controller, Delete, Get, HttpCode, Patch, Post, UseGuards } from '@nestjs/common';
import { User } from '@/decorators/user.decorator';
import { User as UserEntity } from '@/users/entities/user.entity';
@ -23,10 +23,14 @@ export class AuthController {
@Post('google')
async loginWithGoogle(@Body('credential') credential: string) {
const user = await this.authService.authenticateWithGoogle(credential);
const accessToken = this.authService.getAccessToken(user.id);
try {
const user = await this.authService.authenticateWithGoogle(credential);
const accessToken = this.authService.getAccessToken(user.id);
return { user, accessToken };
return { user, accessToken };
} catch (error) {
throw new BadRequestException('User with this email might already exist.');
}
}
@Post('register')

View File

@ -0,0 +1,23 @@
import { ArgumentsHost, Catch, ExceptionFilter, HttpException, HttpStatus } from '@nestjs/common';
import { HttpAdapterHost } from '@nestjs/core';
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
constructor(private readonly httpAdapterHost: HttpAdapterHost) {}
catch(exception: unknown, host: ArgumentsHost) {
const { httpAdapter } = this.httpAdapterHost;
const ctx = host.switchToHttp();
const httpStatus = exception instanceof HttpException ? exception.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR;
const responseBody = {
statusCode: httpStatus,
timestamp: new Date().toISOString(),
path: httpAdapter.getRequestUrl(ctx.getRequest()),
};
httpAdapter.reply(ctx.getResponse(), responseBody, httpStatus);
}
}

View File

@ -1,22 +0,0 @@
import { ArgumentsHost, Catch, ExceptionFilter, HttpException } from '@nestjs/common';
import type { Request, Response } from 'express';
import { TypeORMError } from 'typeorm';
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse<Response>();
const request = ctx.getRequest<Request>();
const statusCode = exception.getStatus();
const message = (exception.getResponse() as TypeORMError).message || exception.message;
response.status(statusCode).json({
statusCode,
message,
timestamp: new Date().toISOString(),
path: request.url,
});
}
}

View File

@ -1,4 +1,5 @@
import { CacheInterceptor, Controller, Get, UseGuards, UseInterceptors } from '@nestjs/common';
import { CacheInterceptor } from '@nestjs/cache-manager';
import { Controller, Get, UseGuards, UseInterceptors } from '@nestjs/common';
import { JwtAuthGuard } from '@/auth/guards/jwt.guard';

View File

@ -1,13 +0,0 @@
import { Controller, Get } from '@nestjs/common';
import { HealthCheck, HealthCheckService, TypeOrmHealthIndicator } from '@nestjs/terminus';
@Controller('health')
export class HealthController {
constructor(private health: HealthCheckService, private db: TypeOrmHealthIndicator) {}
@Get()
@HealthCheck()
check() {
return this.health.check([() => this.db.pingCheck('database')]);
}
}

View File

@ -1,11 +0,0 @@
import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { TerminusModule } from '@nestjs/terminus';
import { HealthController } from './health.controller';
@Module({
imports: [HttpModule, TerminusModule],
controllers: [HealthController],
})
export class HealthModule {}

View File

@ -1,4 +1,4 @@
import { Controller, Get, Param, Query } from '@nestjs/common';
import { Controller, GatewayTimeoutException,Get, Param, Query } from '@nestjs/common';
import { PrinterService } from './printer.service';
@ -7,11 +7,15 @@ export class PrinterController {
constructor(private readonly printerService: PrinterService) {}
@Get('/:username/:slug')
printAsPdf(
async printAsPdf(
@Param('username') username: string,
@Param('slug') slug: string,
@Query('lastUpdated') lastUpdated: string
): Promise<string> {
return this.printerService.printAsPdf(username, slug, lastUpdated);
try {
return await this.printerService.printAsPdf(username, slug, lastUpdated);
} catch (error) {
throw new GatewayTimeoutException();
}
}
}

View File

@ -5,17 +5,57 @@ import { PageConfig } from '@reactive-resume/schema';
import { access, mkdir, readdir, unlink, writeFile } from 'fs/promises';
import { join } from 'path';
import { PDFDocument } from 'pdf-lib';
import { Browser, chromium } from 'playwright-chromium';
import { BrowserContext, chromium } from 'playwright-chromium';
const minimal_chromium_args = [
'--autoplay-policy=user-gesture-required',
'--disable-background-networking',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-breakpad',
'--disable-client-side-phishing-detection',
'--disable-component-update',
'--disable-default-apps',
'--disable-dev-shm-usage',
'--disable-domain-reliability',
'--disable-extensions',
'--disable-features=AudioServiceOutOfProcess',
'--disable-hang-monitor',
'--disable-ipc-flooding-protection',
'--disable-notifications',
'--disable-offer-store-unmasked-wallet-cards',
'--disable-popup-blocking',
'--disable-print-preview',
'--disable-prompt-on-repost',
'--disable-renderer-backgrounding',
'--disable-setuid-sandbox',
'--disable-speech-api',
'--disable-sync',
'--hide-scrollbars',
'--ignore-gpu-blacklist',
'--metrics-recording-only',
'--mute-audio',
'--no-default-browser-check',
'--no-first-run',
'--no-pings',
'--no-sandbox',
'--no-zygote',
'--password-store=basic',
'--use-gl=swiftshader',
'--use-mock-keychain',
];
@Injectable()
export class PrinterService implements OnModuleInit, OnModuleDestroy {
private browser: Browser;
private browser: BrowserContext;
constructor(private readonly schedulerRegistry: SchedulerRegistry, private readonly configService: ConfigService) {}
async onModuleInit() {
this.browser = await chromium.launch({
args: ['--disable-dev-shm-usage'],
this.browser = await chromium.launchPersistentContext('.playwright', {
headless: true,
forcedColors: 'active',
args: minimal_chromium_args,
});
}
@ -34,6 +74,7 @@ export class PrinterService implements OnModuleInit, OnModuleDestroy {
await access(join(directory, filename));
} catch {
const activeSchedulerTimeouts = this.schedulerRegistry.getTimeouts();
await readdir(directory).then(async (files) => {
await Promise.all(
files.map(async (file) => {
@ -53,9 +94,8 @@ export class PrinterService implements OnModuleInit, OnModuleDestroy {
const page = await this.browser.newPage();
await page.goto(`${url}/${username}/${slug}/printer?secretKey=${secretKey}`);
await page.waitForLoadState('networkidle');
await page.waitForSelector('html.wf-active');
await page.goto(`${url}/${username}/${slug}/printer?secretKey=${secretKey}`, { waitUntil: 'networkidle' });
await page.waitForSelector('html.wf-active', { state: 'visible' });
const pageFormat: PageConfig['format'] = await page.$$eval(
'[data-page]',