user.controller.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. import {
  2. BadRequestException,
  3. Body,
  4. Controller,
  5. Delete,
  6. ForbiddenException,
  7. NotFoundException,
  8. Get,
  9. Param,
  10. Post,
  11. Put,
  12. Request,
  13. UseGuards,
  14. Query,
  15. } from '@nestjs/common';
  16. import { UserService } from './user.service';
  17. import { CombinedAuthGuard } from '../auth/combined-auth.guard';
  18. import { CreateUserDto } from './dto/create-user.dto';
  19. import { UpdateUserDto } from './dto/update-user.dto';
  20. import { I18nService } from '../i18n/i18n.service';
  21. import { UserRole } from './user-role.enum';
  22. import { UserSettingService } from './user-setting.service';
  23. @Controller('users')
  24. @UseGuards(CombinedAuthGuard)
  25. export class UserController {
  26. constructor(
  27. private readonly userService: UserService,
  28. private readonly i18nService: I18nService,
  29. private readonly userSettingService: UserSettingService,
  30. ) { }
  31. // --- API Key Management ---
  32. @Get('api-key')
  33. async getApiKey(@Request() req) {
  34. const apiKey = await this.userService.getOrCreateApiKey(req.user.id);
  35. return { apiKey };
  36. }
  37. @Post('api-key/rotate')
  38. async rotateApiKey(@Request() req) {
  39. const apiKey = await this.userService.regenerateApiKey(req.user.id);
  40. return { apiKey };
  41. }
  42. // --- Personal Settings ---
  43. @Get('settings')
  44. async getSettings(@Request() req) {
  45. return this.userSettingService.getByUser(req.user.id);
  46. }
  47. @Put('settings/language')
  48. async updateLanguage(@Request() req, @Body() body: { language: string }) {
  49. if (!body.language) throw new BadRequestException('language is required');
  50. return this.userSettingService.update(req.user.id, body.language);
  51. }
  52. // --- Profile ---
  53. @Get('profile')
  54. async getProfile(@Request() req: any) {
  55. return this.userService.findOneById(req.user.id);
  56. }
  57. @Get('tenants')
  58. async getMyTenants(@Request() req: any) {
  59. return this.userService.getUserTenants(req.user.id);
  60. }
  61. @Get('me')
  62. async getMe(@Request() req) {
  63. const user = await this.userService.findOneById(req.user.id);
  64. if (!user) throw new NotFoundException();
  65. let isNotebookEnabled = true;
  66. if (user.tenantId) {
  67. const settings = await this.userService.getTenantSettings(user.tenantId);
  68. isNotebookEnabled = settings?.isNotebookEnabled ?? true;
  69. }
  70. const tenantName = user.tenantMembers?.[0]?.tenant?.name || 'Default';
  71. return {
  72. id: user.id,
  73. username: user.username,
  74. displayName: user.displayName,
  75. role: user.isAdmin ? UserRole.SUPER_ADMIN : UserRole.USER,
  76. tenantId: user.tenantId,
  77. tenantName,
  78. isAdmin: user.isAdmin,
  79. isNotebookEnabled,
  80. };
  81. }
  82. @Get()
  83. async findAll(
  84. @Request() req,
  85. @Query('page') page?: string,
  86. @Query('limit') limit?: string,
  87. ) {
  88. const callerRole = req.user.role;
  89. if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
  90. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyViewList'));
  91. }
  92. const p = page ? parseInt(page) : undefined;
  93. const l = limit ? parseInt(limit) : undefined;
  94. if (callerRole === UserRole.SUPER_ADMIN) {
  95. return this.userService.findAll(p, l);
  96. } else {
  97. return this.userService.findByTenantId(req.user.tenantId, p, l);
  98. }
  99. }
  100. @Put('password')
  101. async changePassword(
  102. @Request() req,
  103. @Body() body: { currentPassword: string; newPassword: string },
  104. ) {
  105. const { currentPassword, newPassword } = body;
  106. if (!currentPassword || !newPassword) {
  107. throw new BadRequestException(this.i18nService.getErrorMessage('passwordsRequired'));
  108. }
  109. if (newPassword.length < 6) {
  110. throw new BadRequestException(this.i18nService.getErrorMessage('newPasswordMinLength'));
  111. }
  112. return this.userService.changePassword(
  113. req.user.id,
  114. currentPassword,
  115. newPassword,
  116. );
  117. }
  118. @Post()
  119. async createUser(
  120. @Request() req,
  121. @Body() body: CreateUserDto,
  122. ) {
  123. const callerRole = req.user.role;
  124. if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
  125. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyCreateUser'));
  126. }
  127. const { username, password } = body;
  128. if (!username || !password) {
  129. throw new BadRequestException(this.i18nService.getErrorMessage('usernamePasswordRequired'));
  130. }
  131. if (password.length < 6) {
  132. throw new BadRequestException(this.i18nService.getErrorMessage('passwordMinLength'));
  133. }
  134. // All new global users default to non-admin.
  135. // Elevation to Super Admin status is handled separately.
  136. let isAdmin = false;
  137. if (callerRole === UserRole.SUPER_ADMIN) {
  138. isAdmin = false;
  139. } else if (callerRole === UserRole.TENANT_ADMIN) {
  140. isAdmin = false;
  141. }
  142. // Pass the calculated params to the service
  143. return this.userService.createUser(username, password, isAdmin, req.user.tenantId, body.displayName);
  144. }
  145. @Put(':id')
  146. async updateUser(
  147. @Request() req,
  148. @Body() body: UpdateUserDto,
  149. @Param('id') id: string,
  150. ) {
  151. const callerRole = req.user.role;
  152. if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
  153. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyUpdateUser'));
  154. }
  155. // Get user info to update
  156. const userToUpdate = await this.userService.findOneById(id);
  157. if (!userToUpdate) {
  158. throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
  159. }
  160. if (callerRole === 'TENANT_ADMIN' && userToUpdate.tenantId !== req.user.tenantId) {
  161. throw new ForbiddenException('Cannot modify users outside your tenant');
  162. }
  163. // Prevent modifying the builtin admin account
  164. if (userToUpdate.username === 'admin') {
  165. throw new ForbiddenException(this.i18nService.getErrorMessage('cannotModifyBuiltinAdmin'));
  166. }
  167. // Role modification is now obsolete on global level.
  168. // If Admin wants to elevate, they set isAdmin property directly.
  169. if (body.isAdmin !== undefined && userToUpdate.isAdmin !== body.isAdmin) {
  170. if (callerRole !== UserRole.SUPER_ADMIN) {
  171. throw new ForbiddenException('Only Super Admins can change user admin status.');
  172. }
  173. }
  174. // Validate password length if provided
  175. if (body.password && body.password.length < 6) {
  176. throw new BadRequestException(this.i18nService.getErrorMessage('passwordMinLength'));
  177. }
  178. return this.userService.updateUser(id, body);
  179. }
  180. @Delete(':id')
  181. async deleteUser(
  182. @Request() req,
  183. @Param('id') id: string,
  184. ) {
  185. const callerRole = req.user.role;
  186. if (callerRole !== UserRole.SUPER_ADMIN && callerRole !== UserRole.TENANT_ADMIN) {
  187. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyDeleteUser'));
  188. }
  189. // Prevent admin from deleting themselves
  190. if (req.user.id === id) {
  191. throw new BadRequestException(this.i18nService.getErrorMessage('cannotDeleteSelf'));
  192. }
  193. // Get user info to delete
  194. const userToDelete = await this.userService.findOneById(id);
  195. if (!userToDelete) {
  196. throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
  197. }
  198. if (callerRole === 'TENANT_ADMIN' && userToDelete.tenantId !== req.user.tenantId) {
  199. throw new ForbiddenException('Cannot delete users outside your tenant');
  200. }
  201. // Block deletion of built-in admin account
  202. if (userToDelete.username === 'admin') {
  203. throw new ForbiddenException(this.i18nService.getErrorMessage('cannotDeleteBuiltinAdmin'));
  204. }
  205. return this.userService.deleteUser(id);
  206. }
  207. }