import { BadRequestException, Controller, ForbiddenException, HttpCode, HttpStatus, Logger, Post, Req, UseGuards, UseInterceptors, } from '@nestjs/common'; import SpaceAbilityFactory from '../../core/casl/abilities/space-ability.factory'; import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'; import { AuthUser } from '../../common/decorators/auth-user.decorator'; import { User, Workspace } from '@docmost/db/types/entity.types'; import { SpaceCaslAction, SpaceCaslSubject, } from '../../core/casl/interfaces/space-ability.type'; import { FileInterceptor } from '../../common/interceptors/file.interceptor'; import * as bytes from 'bytes'; import * as path from 'path'; import { MAX_FILE_SIZE } from '../../core/attachment/attachment.constants'; import { ImportService } from './import.service'; import { AuthWorkspace } from '../../common/decorators/auth-workspace.decorator'; @Controller() export class ImportController { private readonly logger = new Logger(ImportController.name); constructor( private readonly importService: ImportService, private readonly spaceAbility: SpaceAbilityFactory, ) {} @UseInterceptors(FileInterceptor) @UseGuards(JwtAuthGuard) @HttpCode(HttpStatus.OK) @Post('pages/import') async importPage( @Req() req: any, @AuthUser() user: User, @AuthWorkspace() workspace: Workspace, ) { const validFileExtensions = ['.md', '.html']; const maxFileSize = bytes(MAX_FILE_SIZE); let file = null; try { file = await req.file({ limits: { fileSize: maxFileSize, fields: 3, files: 1 }, }); } catch (err: any) { this.logger.error(err.message); if (err?.statusCode === 413) { throw new BadRequestException( `File too large. Exceeds the ${MAX_FILE_SIZE} limit`, ); } } if (!file) { throw new BadRequestException('Failed to upload file'); } if ( !validFileExtensions.includes(path.extname(file.filename).toLowerCase()) ) { throw new BadRequestException('Invalid import file type.'); } const spaceId = file.fields?.spaceId?.value; if (!spaceId) { throw new BadRequestException('spaceId or format not found'); } const ability = await this.spaceAbility.createForUser(user, spaceId); if (ability.cannot(SpaceCaslAction.Edit, SpaceCaslSubject.Page)) { throw new ForbiddenException(); } return this.importService.importPage(file, user.id, spaceId, workspace.id); } }