import { Controller, Get, Post, Param, Delete, UseGuards, UploadedFile, UseInterceptors, Body, ForbiddenException, NotFoundException, Req, Res, ParseIntPipe } from '@nestjs/common'; import { FilesService } from './files.service'; import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard'; import { FileInterceptor } from '@nestjs/platform-express'; import { diskStorage } from 'multer'; import { extname } from 'path'; import type { Response } from 'express'; import { PrismaService } from '../prisma/prisma.service'; import * as fs from 'fs'; @Controller('files') @UseGuards(JwtAuthGuard) export class FilesController { constructor( private readonly filesService: FilesService, private readonly prisma: PrismaService ) {} @Post('upload') @UseInterceptors(FileInterceptor('file', { storage: diskStorage({ destination: './uploads', filename: (req, file, callback) => { const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1E9); const ext = extname(file.originalname); callback(null, `${uniqueSuffix}${ext}`); }, }), })) async uploadFile(@UploadedFile() file: Express.Multer.File, @Body('timetableEntryId') timetableEntryId: string, @Req() req: any) { const user = req.user; const entryId = timetableEntryId ? parseInt(timetableEntryId) : undefined; if (!file) { throw new NotFoundException('No file uploaded'); } try { if (entryId) { // Lesson Upload const lesson = await this.prisma.timetableEntry.findUnique({ where: { id: entryId } }); if (!lesson) throw new NotFoundException('Lesson not found'); if (user.role !== 'Lehrer') { // Student uploading to lesson if (!lesson.allowStudentUploads) { throw new ForbiddenException('Uploads not allowed for this lesson'); } } } else { // General Upload if (user.role !== 'Lehrer') { throw new ForbiddenException('Only teachers can upload general files'); } } return await this.filesService.saveFile(file, user.id, entryId); } catch (error) { // Cleanup file if error if (file.path && fs.existsSync(file.path)) { fs.unlinkSync(file.path); } throw error; } } @Get() async findAllGeneral() { return this.filesService.findAllGeneral(); } @Get('lesson/:id') async findByLesson(@Param('id', ParseIntPipe) id: number, @Req() req: any) { return this.filesService.findByLesson(id, req.user.id, req.user.role); } @Get('download/:id') async downloadFile(@Param('id', ParseIntPipe) id: number, @Res() res: Response) { const fileEntity = await this.filesService.getFileEntity(id); res.download(fileEntity.path, fileEntity.filename); } @Delete(':id') async deleteFile(@Param('id', ParseIntPipe) id: number, @Req() req: any) { return this.filesService.deleteFile(id, req.user.id, req.user.role); } }