import { Controller, Get, Post, Put, Delete, Body, Param, Query, UseGuards, UseInterceptors, UploadedFile, BadRequestException, } from '@nestjs/common'; import { FileInterceptor } from '@nestjs/platform-express'; import { ApiTags, ApiBearerAuth, ApiOperation, ApiQuery, ApiConsumes } from '@nestjs/swagger'; import { PluginsService } from './plugins.service'; import { InstallPluginDto } from './dto/install-plugin.dto'; import { UpdatePluginConfigDto } from './dto/update-plugin-config.dto'; 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'; @ApiTags('plugins') @ApiBearerAuth() @Controller('plugins') @UseGuards(JwtAuthGuard, PermissionsGuard) export class PluginsController { constructor(private readonly pluginsService: PluginsService) {} @Get() @RequirePermission('plugin.view') @ApiOperation({ summary: 'Get all installed plugins for tenant' }) getPlugins(@CurrentTenant() licenseId: string) { return this.pluginsService.getPlugins(licenseId); } @Post('install') @RequirePermission('plugin.manage') @ApiOperation({ summary: 'Install new plugin' }) installPlugin(@CurrentTenant() licenseId: string, @Body() dto: InstallPluginDto) { return this.pluginsService.installPlugin(licenseId, dto); } @Delete(':id') @RequirePermission('plugin.manage') @ApiOperation({ summary: 'Uninstall plugin' }) async uninstallPlugin(@CurrentTenant() licenseId: string, @Param('id') pluginId: string) { await this.pluginsService.uninstallPlugin(licenseId, pluginId); return { deleted: true }; } @Post(':id/reload') @RequirePermission('plugin.manage') @ApiOperation({ summary: 'Reload plugin on game server' }) reloadPlugin(@CurrentTenant() licenseId: string, @Param('id') pluginId: string) { return this.pluginsService.reloadPlugin(licenseId, pluginId); } @Put(':id/config') @RequirePermission('plugin.manage') @ApiOperation({ summary: 'Update plugin configuration' }) updateConfig( @CurrentTenant() licenseId: string, @Param('id') pluginId: string, @Body() dto: UpdatePluginConfigDto, ) { return this.pluginsService.updateConfig(licenseId, pluginId, dto); } @Get('search') @RequirePermission('plugin.view') @ApiOperation({ summary: 'Search uMod plugin directory (legacy stub)' }) @ApiQuery({ name: 'q', required: true, example: 'kits' }) searchUmod(@Query('q') query: string) { return this.pluginsService.searchUmod(query); } @Get('browse') @RequirePermission('plugin.view') @ApiOperation({ summary: 'Browse uMod plugin directory (proxied)' }) @ApiQuery({ name: 'query', required: false, example: 'vanish' }) @ApiQuery({ name: 'page', required: false, example: 1 }) @ApiQuery({ name: 'sort', required: false, example: 'downloads' }) browseUmod( @Query('query') query: string, @Query('page') page: string, @Query('sort') sort: string, ) { return this.pluginsService.browseUmod(query, page ? parseInt(page, 10) : 1, sort); } @Post('upload') @RequirePermission('plugin.manage') @ApiOperation({ summary: 'Upload a custom .cs plugin file' }) @ApiConsumes('multipart/form-data') @UseInterceptors(FileInterceptor('file')) uploadPlugin( @CurrentTenant() licenseId: string, @UploadedFile() file: Express.Multer.File, ) { if (!file) { throw new BadRequestException('No file provided'); } return this.pluginsService.uploadPlugin(licenseId, file); } }