import { Controller, Get, Put, Post, Delete, Param, Body, Req, UseGuards, NotFoundException, } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { RolesGuard, Roles } from '@it0/common'; import { User } from '../../../domain/entities/user.entity'; import { ApiKey } from '../../../domain/entities/api-key.entity'; import * as bcrypt from 'bcryptjs'; import * as crypto from 'crypto'; @Controller('api/v1/admin/settings') @UseGuards(RolesGuard) @Roles('admin') export class SettingsController { // In-memory store for platform settings (would be a DB table in production) private generalSettings: Record = { platformName: 'IT0', defaultTimezone: 'UTC', defaultLanguage: 'en', autoApproveThreshold: 1, }; private notificationSettings: Record = { emailEnabled: false, smsEnabled: false, pushEnabled: true, defaultEscalationPolicy: 'immediate', }; private themeSettings: Record = { mode: 'dark', primaryColor: '#3b82f6', }; constructor( @InjectRepository(User) private readonly userRepository: Repository, @InjectRepository(ApiKey) private readonly apiKeyRepository: Repository, ) {} // --- General Settings --- @Get('general') async getGeneral() { return this.generalSettings; } @Put('general') async updateGeneral(@Body() body: any) { Object.assign(this.generalSettings, body); return this.generalSettings; } // --- Notification Settings --- @Get('notifications') async getNotifications() { return this.notificationSettings; } @Put('notifications') async updateNotifications(@Body() body: any) { Object.assign(this.notificationSettings, body); return this.notificationSettings; } // --- API Keys --- @Get('api-keys') async listApiKeys(@Req() req: any) { const userId = req.user?.sub || req.user?.id; const keys = await this.apiKeyRepository.find({ where: userId ? { userId } : {}, order: { createdAt: 'DESC' }, }); return keys.map((k) => ({ id: k.id, name: k.name, key: '****' + k.keyHash.slice(-8), createdAt: k.createdAt.toISOString(), lastUsedAt: k.lastUsedAt?.toISOString() ?? null, })); } @Post('api-keys') async createApiKey(@Req() req: any, @Body() body: { name: string }) { const userId = req.user?.sub || req.user?.id; const tenantId = req.user?.tenantId || 'default'; const rawKey = `it0_${crypto.randomBytes(32).toString('hex')}`; const keyHash = await bcrypt.hash(rawKey, 10); const apiKey = this.apiKeyRepository.create({ id: crypto.randomUUID(), tenantId, userId, keyHash, name: body.name, permissions: [], isActive: true, }); await this.apiKeyRepository.save(apiKey); return { key: rawKey }; } @Delete('api-keys/:id') async deleteApiKey(@Param('id') id: string) { const key = await this.apiKeyRepository.findOne({ where: { id } }); if (!key) throw new NotFoundException(`API key "${id}" not found`); await this.apiKeyRepository.remove(key); return { success: true }; } // --- Theme Settings --- @Get('theme') async getTheme() { return this.themeSettings; } @Put('theme') async updateTheme(@Body() body: any) { Object.assign(this.themeSettings, body); return this.themeSettings; } // --- Account Settings --- @Get('account') async getAccount(@Req() req: any) { const userId = req.user?.sub || req.user?.id; if (!userId) return { displayName: 'Admin', email: '' }; const user = await this.userRepository.findOne({ where: { id: userId } }); if (!user) return { displayName: 'Admin', email: '' }; return { displayName: user.name, email: user.email, }; } @Put('account') async updateAccount(@Req() req: any, @Body() body: { displayName: string }) { const userId = req.user?.sub || req.user?.id; if (!userId) throw new NotFoundException('User not found'); const user = await this.userRepository.findOne({ where: { id: userId } }); if (!user) throw new NotFoundException('User not found'); user.name = body.displayName; const saved = await this.userRepository.save(user); return { displayName: saved.name, email: saved.email }; } @Put('account/password') async changePassword( @Req() req: any, @Body() body: { currentPassword: string; newPassword: string }, ) { const userId = req.user?.sub || req.user?.id; if (!userId) throw new NotFoundException('User not found'); const user = await this.userRepository.findOne({ where: { id: userId } }); if (!user) throw new NotFoundException('User not found'); const valid = await bcrypt.compare(body.currentPassword, user.passwordHash); if (!valid) { return { success: false, message: 'Current password is incorrect' }; } user.passwordHash = await bcrypt.hash(body.newPassword, 12); await this.userRepository.save(user); return { success: true }; } }