it0/packages/services/auth-service/src/interfaces/rest/controllers/settings.controller.ts

191 lines
5.0 KiB
TypeScript

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<string, any> = {
platformName: 'IT0',
defaultTimezone: 'UTC',
defaultLanguage: 'en',
autoApproveThreshold: 1,
};
private notificationSettings: Record<string, any> = {
emailEnabled: false,
smsEnabled: false,
pushEnabled: true,
defaultEscalationPolicy: 'immediate',
};
private themeSettings: Record<string, any> = {
mode: 'dark',
primaryColor: '#3b82f6',
};
constructor(
@InjectRepository(User)
private readonly userRepository: Repository<User>,
@InjectRepository(ApiKey)
private readonly apiKeyRepository: Repository<ApiKey>,
) {}
// --- 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 };
}
}