import { Controller, Get, HttpCode, Param, Post, UploadedFile, UseInterceptors, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { AdminUploadsService } from './admin-uploads.service'; import { CurrentAdmin } from '../auth/guards'; import type { AuthenticatedAdmin } from '../auth/jwt.strategy'; import { Body } from '@nestjs/common'; /** * The subset of multer's file object this controller uses. Declared locally * rather than pulling in @types/multer for one interface — multer itself ships * with @nestjs/platform-express, but its types do not. */ interface UploadedMulterFile { originalname: string; mimetype: string; size: number; buffer: Buffer; } /** * Legacy endpoints: * POST file/create -> storeWithoutData * PUT file/update/{id} -> updateBody (metadata only; not ported — nothing * in henza_admin calls it) * * The multipart field name `file` matches what every legacy uploader posts * (MyUpload.vue, SingleUploadInput.vue, UploadInput.vue, PodcastUploadInput.vue). * * PERMISSIONS. Legacy gated this on nothing at all: `file/create` sat outside * any middleware, and henza_server's `auth:api` group is itself commented out * (routes/admin.php:12), so the endpoint accepted anonymous uploads. That is a * security bug, not a feature, so it is NOT reproduced — these routes require a * signed-in admin. No specific rid is demanded, since legacy's permission * vocabulary has no media/file entry to port and inventing one would let it * drift from the 144 real rids. */ @Controller('admin/files') export class AdminUploadsController { constructor(private readonly uploads: AdminUploadsService) {} @Post('create') @HttpCode(200) @UseInterceptors(FileInterceptor('file')) create( @UploadedFile() file: UploadedMulterFile | undefined, @Body('purpose') purpose: string | undefined, @CurrentAdmin() admin: AuthenticatedAdmin, ) { return this.uploads.store(file, purpose, admin.id ?? null); } @Get(':id') findOne(@Param('id') id: string) { return this.uploads.findOne(id); } }