user.controller.ts 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  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. } from '@nestjs/common';
  15. import { UserService } from './user.service';
  16. import { CombinedAuthGuard } from '../auth/combined-auth.guard';
  17. import { UpdateUserDto } from './dto/update-user.dto';
  18. import { I18nService } from '../i18n/i18n.service';
  19. @Controller('users')
  20. @UseGuards(CombinedAuthGuard)
  21. export class UserController {
  22. constructor(
  23. private readonly userService: UserService,
  24. private readonly i18nService: I18nService,
  25. ) { }
  26. // --- API Key Management ---
  27. @Get('api-key')
  28. async getApiKey(@Request() req) {
  29. const apiKey = await this.userService.getOrCreateApiKey(req.user.id);
  30. return { apiKey };
  31. }
  32. @Post('api-key/rotate')
  33. async rotateApiKey(@Request() req) {
  34. const apiKey = await this.userService.regenerateApiKey(req.user.id);
  35. return { apiKey };
  36. }
  37. // --- Profile ---
  38. @Get('me')
  39. async getMe(@Request() req) {
  40. const user = await this.userService.findOneById(req.user.id);
  41. if (!user) throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
  42. let isNotebookEnabled = true;
  43. if (user.tenantId) {
  44. const settings = await this.userService.getTenantSettings(user.tenantId);
  45. isNotebookEnabled = settings?.isNotebookEnabled ?? true;
  46. }
  47. return {
  48. id: user.id,
  49. username: user.username,
  50. role: user.role,
  51. tenantId: user.tenantId,
  52. isAdmin: user.isAdmin,
  53. isNotebookEnabled,
  54. };
  55. }
  56. @Get()
  57. async findAll(@Request() req) {
  58. const callerRole = req.user.role;
  59. if (callerRole !== 'SUPER_ADMIN' && callerRole !== 'TENANT_ADMIN') {
  60. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyViewList'));
  61. }
  62. if (callerRole === 'SUPER_ADMIN') {
  63. return this.userService.findAll();
  64. } else {
  65. return this.userService.findByTenantId(req.user.tenantId);
  66. }
  67. }
  68. @Put('password')
  69. async changePassword(
  70. @Request() req,
  71. @Body() body: { currentPassword: string; newPassword: string },
  72. ) {
  73. const { currentPassword, newPassword } = body;
  74. if (!currentPassword || !newPassword) {
  75. throw new BadRequestException(this.i18nService.getErrorMessage('passwordsRequired'));
  76. }
  77. if (newPassword.length < 6) {
  78. throw new BadRequestException(this.i18nService.getErrorMessage('newPasswordMinLength'));
  79. }
  80. return this.userService.changePassword(
  81. req.user.id,
  82. currentPassword,
  83. newPassword,
  84. );
  85. }
  86. @Post()
  87. async createUser(
  88. @Request() req,
  89. @Body() body: { username: string; password: string; role?: string },
  90. ) {
  91. const callerRole = req.user.role;
  92. if (callerRole !== 'SUPER_ADMIN' && callerRole !== 'TENANT_ADMIN') {
  93. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyCreateUser'));
  94. }
  95. const { username, password } = body;
  96. if (!username || !password) {
  97. throw new BadRequestException(this.i18nService.getErrorMessage('usernamePasswordRequired'));
  98. }
  99. if (password.length < 6) {
  100. throw new BadRequestException(this.i18nService.getErrorMessage('passwordMinLength'));
  101. }
  102. // Determine target role based on caller's role and requested role
  103. let targetRole = 'USER';
  104. let isAdmin = false;
  105. if (callerRole === 'SUPER_ADMIN') {
  106. // Super Admin can create TENANT_ADMIN or USER. Default to requested role, fallback to USER.
  107. targetRole = body.role === 'TENANT_ADMIN' ? 'TENANT_ADMIN' : 'USER';
  108. isAdmin = targetRole === 'TENANT_ADMIN';
  109. } else if (callerRole === 'TENANT_ADMIN') {
  110. // Tenant Admin can ONLY create regular users.
  111. targetRole = 'USER';
  112. isAdmin = false;
  113. }
  114. // Pass the calculated params to the service
  115. return this.userService.createUser(username, password, isAdmin, req.user.tenantId, targetRole as any);
  116. }
  117. @Put(':id')
  118. async updateUser(
  119. @Request() req,
  120. @Body() body: UpdateUserDto,
  121. @Param('id') id: string,
  122. ) {
  123. const callerRole = req.user.role;
  124. if (callerRole !== 'SUPER_ADMIN' && callerRole !== 'TENANT_ADMIN') {
  125. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyUpdateUser'));
  126. }
  127. // 更新するユーザー情報を取得
  128. const userToUpdate = await this.userService.findOneById(id);
  129. if (!userToUpdate) {
  130. throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
  131. }
  132. if (callerRole === 'TENANT_ADMIN' && userToUpdate.tenantId !== req.user.tenantId) {
  133. throw new ForbiddenException('Cannot modify users outside your tenant');
  134. }
  135. // Prevent modifying the builtin admin account
  136. if (userToUpdate.username === 'admin') {
  137. throw new ForbiddenException(this.i18nService.getErrorMessage('cannotModifyBuiltinAdmin'));
  138. }
  139. // Role modification logic
  140. if (body.role && userToUpdate.role !== body.role) {
  141. if (callerRole !== 'SUPER_ADMIN') {
  142. throw new ForbiddenException('Only Super Admins can change user roles.');
  143. }
  144. if (userToUpdate.role === 'SUPER_ADMIN') {
  145. throw new ForbiddenException('Cannot modify the role of another Super Admin.');
  146. }
  147. // Sync isAdmin based on the newly selected role
  148. if (body.role === 'TENANT_ADMIN' || body.role === 'SUPER_ADMIN') {
  149. body.isAdmin = true;
  150. } else {
  151. body.isAdmin = false;
  152. }
  153. }
  154. return this.userService.updateUser(id, body);
  155. }
  156. @Delete(':id')
  157. async deleteUser(
  158. @Request() req,
  159. @Param('id') id: string,
  160. ) {
  161. const callerRole = req.user.role;
  162. if (callerRole !== 'SUPER_ADMIN' && callerRole !== 'TENANT_ADMIN') {
  163. throw new ForbiddenException(this.i18nService.getErrorMessage('adminOnlyDeleteUser'));
  164. }
  165. // 管理者が自身を削除するのを防止
  166. if (req.user.id === id) {
  167. throw new BadRequestException(this.i18nService.getErrorMessage('cannotDeleteSelf'));
  168. }
  169. // 削除するユーザー情報を取得
  170. const userToDelete = await this.userService.findOneById(id);
  171. if (!userToDelete) {
  172. throw new NotFoundException(this.i18nService.getErrorMessage('userNotFound'));
  173. }
  174. if (callerRole === 'TENANT_ADMIN' && userToDelete.tenantId !== req.user.tenantId) {
  175. throw new ForbiddenException('Cannot delete users outside your tenant');
  176. }
  177. // ビルトインadminアカウントの削除を阻止
  178. if (userToDelete.username === 'admin') {
  179. throw new ForbiddenException(this.i18nService.getErrorMessage('cannotDeleteBuiltinAdmin'));
  180. }
  181. return this.userService.deleteUser(id);
  182. }
  183. }