| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- import {
- BadRequestException,
- Body,
- Controller,
- Delete,
- ForbiddenException,
- NotFoundException,
- Get,
- Param,
- Post,
- Put,
- Request,
- UseGuards,
- Query,
- } from '@nestjs/common';
- import { UserService } from './user.service';
- import { CombinedAuthGuard } from '../auth/combined-auth.guard';
- import { CreateUserDto } from './dto/create-user.dto';
- import { UpdateUserDto } from './dto/update-user.dto';
- import { I18nService } from '../i18n/i18n.service';
- import { UserRole } from './user-role.enum';
- import { UserSettingService } from './user-setting.service';
- @Controller('users')
- @UseGuards(CombinedAuthGuard)
- export class UserController {
- constructor(
- private readonly userService: UserService,
- private readonly i18nService: I18nService,
- private readonly userSettingService: UserSettingService,
- ) { }
- // --- API Key Management ---
- @Get('api-key')
- async getApiKey(@Request() req) {
- const apiKey = await this.userService.getOrCreateApiKey(req.user.id);
- return { apiKey };
- }
- @Post('api-key/rotate')
- async rotateApiKey(@Request() req) {
- const apiKey = await this.userService.regenerateApiKey(req.user.id);
- return { apiKey };
- }
- // --- Personal Settings ---
- @Get('settings')
- async getSettings(@Request() req) {
- return this.userSettingService.getByUser(req.user.id);
- }
- @Put('settings/language')
- async updateLanguage(@Request() req, @Body() body: { language: string }) {
- if (!body.language) throw new BadRequestException('language is required');
- return this.userSettingService.update(req.user.id, body.language);
- }
- // --- Profile ---
- @Get('profile')
- async getProfile(@Request() req: any) {
- return this.userService.findOneById(req.user.id);
- }
- @Get('tenants')
- async getMyTenants(@Request() req: any) {
- return this.userService.getUserTenants(req.user.id);
- }
- @Get('me')
- async getMe(@Request() req) {
- const user = await this.userService.findOneById(req.user.id);
- if (!user) throw new NotFoundException();
- let isNotebookEnabled = true;
- if (user.tenantId) {
- const settings = await this.userService.getTenantSettings(user.tenantId);
- isNotebookEnabled = settings?.isNotebookEnabled ?? true;
- }
- const tenantName = user.tenantMembers?.[0]?.tenant?.name || 'Default';
- return {
- id: user.id,
- username: user.username,
- displayName: user.displayName,
- role: user.isAdmin ? UserRole.SUPER_ADMIN : UserRole.USER,
- tenantId: user.tenantId,
- tenantName,
- isAdmin: user.isAdmin,
- isNotebookEnabled,
- };
- }
- @Get()
- async findAll(
- @Request() req,
- @Query('page') page?: string,
- @Query('limit') limit?: string,
- ) {
- const callerRole = req.user.role;
- if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
- throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyViewList'));
- }
- const p = page ? parseInt(page) : undefined;
- const l = limit ? parseInt(limit) : undefined;
- if (callerRole === UserRole.SUPER_ADMIN) {
- return this.userService.findAll(p, l);
- } else {
- return this.userService.findByTenantId(req.user.tenantId, p, l);
- }
- }
- @Put('password')
- async changePassword(
- @Request() req,
- @Body() body: { currentPassword: string; newPassword: string },
- ) {
- const { currentPassword, newPassword } = body;
- if (!currentPassword || !newPassword) {
- throw new BadRequestException(this.i18nService.getErrorMessage('passwordsRequired'));
- }
- if (newPassword.length < 6) {
- throw new BadRequestException(this.i18nService.getErrorMessage('newPasswordMinLength'));
- }
- return this.userService.changePassword(
- req.user.id,
- currentPassword,
- newPassword,
- );
- }
- @Post()
- async createUser(
- @Request() req,
- @Body() body: CreateUserDto,
- ) {
- const callerRole = req.user.role;
- if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
- throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyCreateUser'));
- }
- const { username, password } = body;
- if (!username || !password) {
- throw new BadRequestException(this.i18nService.getErrorMessage('usernamePasswordRequired'));
- }
- if (password.length < 6) {
- throw new BadRequestException(this.i18nService.getErrorMessage('passwordMinLength'));
- }
- // All new global users default to non-admin.
- // Elevation to Super Admin status is handled separately.
- let isAdmin = false;
- if (callerRole === UserRole.SUPER_ADMIN) {
- isAdmin = false;
- } else if (callerRole === UserRole.TENANT_ADMIN) {
- isAdmin = false;
- }
- // Pass the calculated params to the service
- return this.userService.createUser(username, password, isAdmin, req.user.tenantId, body.displayName);
- }
- @Put(':id')
- async updateUser(
- @Request() req,
- @Body() body: UpdateUserDto,
- @Param('id') id: string,
- ) {
- const callerRole = req.user.role;
- if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
- throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyUpdateUser'));
- }
- // Get user info to update
- const userToUpdate = await this.userService.findOneById(id);
- if (!userToUpdate) {
- throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
- }
- if (callerRole === 'TENANT_ADMIN' && userToUpdate.tenantId !== req.user.tenantId) {
- throw new ForbiddenException('Cannot modify users outside your tenant');
- }
- // Prevent modifying the builtin admin account
- if (userToUpdate.username === 'admin') {
- throw new ForbiddenException(this.i18nService.getErrorMessage('cannotModifyBuiltinAdmin'));
- }
- // Role modification is now obsolete on global level.
- // If Admin wants to elevate, they set isAdmin property directly.
- if (body.isAdmin !== undefined && userToUpdate.isAdmin !== body.isAdmin) {
- if (callerRole !== UserRole.SUPER_ADMIN) {
- throw new ForbiddenException('Only Super Admins can change user admin status.');
- }
- }
- // Validate password length if provided
- if (body.password && body.password.length < 6) {
- throw new BadRequestException(this.i18nService.getErrorMessage('passwordMinLength'));
- }
- return this.userService.updateUser(id, body);
- }
- @Delete(':id')
- async deleteUser(
- @Request() req,
- @Param('id') id: string,
- ) {
- const callerRole = req.user.role;
- if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
- throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyDeleteUser'));
- }
- // Prevent admin from deleting themselves
- if (req.user.id === id) {
- throw new BadRequestException(this.i18nService.getErrorMessage('cannotDeleteSelf'));
- }
- // Get user info to delete
- const userToDelete = await this.userService.findOneById(id);
- if (!userToDelete) {
- throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
- }
- if (callerRole === 'TENANT_ADMIN' && userToDelete.tenantId !== req.user.tenantId) {
- throw new ForbiddenException('Cannot delete users outside your tenant');
- }
- // Block deletion of built-in admin account
- if (userToDelete.username === 'admin') {
- throw new ForbiddenException(this.i18nService.getErrorMessage('cannotDeleteBuiltinAdmin'));
- }
- return this.userService.deleteUser(id);
- }
- }
|