import { Controller, Get, Post, Query, Body, Res, UseGuards, UseInterceptors, UploadedFile, HttpException, HttpStatus, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { ApiTags, ApiBearerAuth } from '@nestjs/swagger'; import { Response } from 'express'; import { CurrentTenant } from '../../common/decorators/current-tenant.decorator'; import { RequirePermission } from '../../common/decorators/require-permission.decorator'; import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'; import { PermissionsGuard } from '../../common/guards/permissions.guard'; import { FilesService } from './files.service'; @ApiTags('Files') @ApiBearerAuth() @Controller('files') @UseGuards(JwtAuthGuard, PermissionsGuard) export class FilesController { constructor(private readonly filesService: FilesService) {} // VueFinder GET operations: ?q=index (list), ?q=search, ?q=preview, ?q=download @Get() @RequirePermission('files.view') async handleGet( @CurrentTenant() licenseId: string, @Query('q') operation: string, @Query('path') path: string, @Query('filter') filter: string, @Res({ passthrough: true }) res: Response, ) { switch (operation) { case 'index': case undefined: case '': return this.filesService.list(licenseId, path || 'server://'); case 'search': return this.filesService.search(licenseId, path || 'server://', filter); case 'preview': return this.filesService.preview(licenseId, path); case 'download': { const result = await this.filesService.download(licenseId, path); res.setHeader('Content-Type', 'application/octet-stream'); res.setHeader( 'Content-Disposition', `attachment; filename="${result.filename}"`, ); res.send(result.content); return; } default: throw new HttpException( `Unknown operation: ${operation}`, HttpStatus.BAD_REQUEST, ); } } // VueFinder POST operations: ?q=delete, rename, move, copy, new-folder, new-file, save, upload @Post() @RequirePermission('files.manage') @UseInterceptors(FileInterceptor('upload')) async handlePost( @CurrentTenant() licenseId: string, @Query('q') operation: string, @Body() body: Record, @UploadedFile() file?: Express.Multer.File, ) { switch (operation) { case 'delete': return this.filesService.delete(licenseId, body.path, body.items); case 'rename': return this.filesService.rename( licenseId, body.path, body.item, body.name, ); case 'move': return this.filesService.move( licenseId, body.path, body.items, body.destination, ); case 'copy': return this.filesService.copy( licenseId, body.path, body.items, body.destination, ); case 'new-folder': case 'mkdir': return this.filesService.createFolder(licenseId, body.path, body.name); case 'new-file': case 'newfile': return this.filesService.createFile(licenseId, body.path, body.name); case 'save': return this.filesService.save(licenseId, body.path, body.content); case 'upload': if (!file) { throw new HttpException('No file provided', HttpStatus.BAD_REQUEST); } return this.filesService.upload(licenseId, body.path, file); default: throw new HttpException( `Unknown operation: ${operation}`, HttpStatus.BAD_REQUEST, ); } } }