import { Body, Controller, Get, HttpException, HttpStatus, Post, Query, Req, UseGuards, } from '@nestjs/common'; import { ApiBearerAuth, ApiOperation, ApiResponse, ApiTags, } from '@nestjs/swagger'; import { Request } from 'express'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; import { ErrorResponse } from '../../common/error/types/types'; import { retrieveAuthorizationToken } from '../../common/http/helper'; import { AccessToken } from '../../common/token'; import { ConfirmRequest, ConfirmResponse, GetRelationsResponse, GetUsersResponse, SignupRequest, SignupResponse, PostSortCriteriaRequest, PostSortCriteriaResponse, GetSortCriteriaRequest, GetSortCriteriaResponse, PostUpdateUserRequest, PostUpdateUserResponse, AllocateLicenseResponse, AllocateLicenseRequest, DeallocateLicenseResponse, DeallocateLicenseRequest, } from './types/types'; import { UsersService } from './users.service'; import jwt from 'jsonwebtoken'; import { AuthGuard } from '../../common/guards/auth/authguards'; import { isSortDirection, isTaskListSortableAttribute, } from '../../common/types/sort'; import { ADMIN_ROLES, TIERS } from '../../constants'; import { RoleGuard } from '../../common/guards/role/roleguards'; import { makeContext } from '../../common/log'; import { UserRoles } from '../../common/types/role'; import { v4 as uuidv4 } from 'uuid'; @ApiTags('users') @Controller('users') export class UsersController { constructor(private readonly usersService: UsersService) {} @ApiResponse({ status: HttpStatus.OK, type: ConfirmResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: '不正なトークン', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'confirmUser' }) @Post('confirm') async confirmUser(@Body() body: ConfirmRequest): Promise { await this.usersService.confirmUser(body.token); return {}; } @ApiResponse({ status: HttpStatus.OK, type: ConfirmResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: '不正なトークン', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'confirmUserAndInitPassword' }) @Post('confirm/initpassword') async confirmUserAndInitPassword( @Body() body: ConfirmRequest, ): Promise { const context = makeContext(uuidv4()); await this.usersService.confirmUserAndInitPassword(context, body.token); return {}; } @ApiResponse({ status: HttpStatus.OK, type: GetUsersResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'getUsers' }) @ApiBearerAuth() @UseGuards(AuthGuard) @UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] })) @Get() async getUsers(@Req() req: Request): Promise { const accessToken = retrieveAuthorizationToken(req); const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken; const users = await this.usersService.getUsers(decodedToken.userId); return { users }; } @ApiResponse({ status: HttpStatus.OK, type: SignupResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: '登録済みメールによる再登録、AuthorIDの重複など', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'signup' }) @ApiBearerAuth() @Post('/signup') @UseGuards(AuthGuard) @UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] })) async signup( @Req() req: Request, @Body() body: SignupRequest, ): Promise { const { name, role, email, autoRenew, licenseAlert, notification, authorId, encryption, encryptionPassword, prompt, } = body; const accessToken = retrieveAuthorizationToken(req); const payload = jwt.decode(accessToken, { json: true }) as AccessToken; const context = makeContext(payload.userId); //ユーザ作成処理 await this.usersService.createUser( context, payload, name, role as UserRoles, email, autoRenew, licenseAlert, notification, authorId, encryption, encryptionPassword, prompt, ); return {}; } @ApiResponse({ status: HttpStatus.OK, type: GetRelationsResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'getRelations', description: 'ログインしているユーザーに関連する各種情報を取得します', }) @ApiBearerAuth() @UseGuards(AuthGuard) @Get('relations') async getRelations(@Req() req: Request): Promise { const token = retrieveAuthorizationToken(req); const { userId } = jwt.decode(token, { json: true }) as AccessToken; const context = makeContext(userId); return await this.usersService.getRelations(context, userId); } @ApiResponse({ status: HttpStatus.OK, type: PostSortCriteriaResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: '不正なパラメータ', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'updateSortCriteria', description: 'ログインしているユーザーのタスクソート条件を更新します', }) @ApiBearerAuth() @UseGuards(AuthGuard) @Post('sort-criteria') async updateSortCriteria( @Body() body: PostSortCriteriaRequest, @Req() req: Request, ): Promise { const { direction, paramName } = body; const accessToken = retrieveAuthorizationToken(req); const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken; //型チェック if ( !isTaskListSortableAttribute(paramName) || !isSortDirection(direction) ) { throw new HttpException( makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST, ); } await this.usersService.updateSortCriteria( paramName, direction, decodedToken, ); return {}; } @ApiResponse({ status: HttpStatus.OK, type: GetSortCriteriaResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'getSortCriteria', description: 'ログインしているユーザーのタスクソート条件を取得します', }) @ApiBearerAuth() @UseGuards(AuthGuard) @Get('sort-criteria') async getSortCriteria( @Query() query: GetSortCriteriaRequest, @Req() req: Request, ): Promise { const {} = query; const accessToken = retrieveAuthorizationToken(req); const decodedToken = jwt.decode(accessToken, { json: true }) as AccessToken; const { direction, paramName } = await this.usersService.getSortCriteria( decodedToken, ); return { direction, paramName }; } @ApiResponse({ status: HttpStatus.OK, type: PostUpdateUserResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: '不正なパラメータ', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'updateUser', description: 'ユーザーの情報を更新します', }) @ApiBearerAuth() @UseGuards(AuthGuard) @UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] })) @Post('update') async updateUser( @Body() body: PostUpdateUserRequest, @Req() req: Request, ): Promise { const { id, role, authorId, autoRenew, licenseAlart, notification, encryption, encryptionPassword, prompt, } = body; const accessToken = retrieveAuthorizationToken(req); const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken; const context = makeContext(userId); await this.usersService.updateUser( context, userId, id, role, authorId, autoRenew, licenseAlart, notification, encryption, encryptionPassword, prompt, ); return {}; } @ApiResponse({ status: HttpStatus.OK, type: AllocateLicenseResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: '割り当て失敗時', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'allocateLicense', description: 'ライセンスを割り当てます', }) @ApiBearerAuth() @UseGuards(AuthGuard) @UseGuards( RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], tiers: [TIERS.TIER5] }), ) @Post('/license/allocate') async allocateLicense( @Body() body: AllocateLicenseRequest, @Req() req: Request, ): Promise { const accessToken = retrieveAuthorizationToken(req); const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken; const context = makeContext(userId); await this.usersService.allocateLicense( context, body.userId, body.newLicenseId, ); return {}; } @ApiResponse({ status: HttpStatus.OK, type: DeallocateLicenseResponse, description: '成功時のレスポンス', }) @ApiResponse({ status: HttpStatus.BAD_REQUEST, description: 'すでにライセンスが割り当て解除されている時', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.UNAUTHORIZED, description: '認証エラー', type: ErrorResponse, }) @ApiResponse({ status: HttpStatus.INTERNAL_SERVER_ERROR, description: '想定外のサーバーエラー', type: ErrorResponse, }) @ApiOperation({ operationId: 'deallocateLicense', description: 'ライセンス割り当てを解除します', }) @ApiBearerAuth() @UseGuards(AuthGuard) @UseGuards( RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN], tiers: [TIERS.TIER5] }), ) @Post('/license/deallocate') async deallocateLicense( @Body() body: DeallocateLicenseRequest, @Req() req: Request, ): Promise { //API実装時に詳細をかいていく //const accessToken = retrieveAuthorizationToken(req); //const { userId } = jwt.decode(accessToken, { json: true }) as AccessToken; //const context = makeContext(userId); //await this.usersService.deallocateLicense(context, body.userId); return {}; } }