Merged PR 469: API-IF実装

## 概要
[Task2806: API-IF実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2806)

以下APIのIFを実装しました。
・アカウント情報取得(未認証時最小アクセス)API
・利用規約情報取得API
・同意済バージョン更新API
またトークン生成APIのIFにコメントを追加しました。

## レビューポイント
なし

## UIの変更
なし

## 動作確認状況
swaggerUIで動作確認

## 補足
なし
This commit is contained in:
oura.a 2023-10-06 05:17:43 +00:00
parent f70e266e85
commit 34cf80d636
13 changed files with 340 additions and 3 deletions

View File

@ -33,7 +33,7 @@
}
},
"401": {
"description": "認証エラー",
"description": "認証エラー/同意済み利用規約が最新でない場合",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
@ -1262,6 +1262,52 @@
"security": [{ "bearer": [] }]
}
},
"/accounts/minimal-access": {
"post": {
"operationId": "getAccountInfoMinimalAccess",
"summary": "",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetAccountInfoMinimalAccessRequest"
}
}
}
},
"responses": {
"200": {
"description": "成功時のレスポンス",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetAccountInfoMinimalAccessResponse"
}
}
}
},
"400": {
"description": "対象のユーザーIDが存在しない場合",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"500": {
"description": "想定外のサーバーエラー",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
}
},
"tags": ["accounts"]
}
},
"/users/confirm": {
"post": {
"operationId": "confirmUser",
@ -1728,6 +1774,53 @@
"security": [{ "bearer": [] }]
}
},
"/users/accepted-version": {
"post": {
"operationId": "updateAcceptedVersion",
"summary": "",
"description": "利用規約同意バージョンを更新",
"parameters": [],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAcceptedVersionRequest"
}
}
}
},
"responses": {
"200": {
"description": "成功時のレスポンス",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UpdateAcceptedVersionResponse"
}
}
}
},
"400": {
"description": "パラメータ不正/対象のユーザidが存在しない場合",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
},
"500": {
"description": "想定外のサーバーエラー",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
}
},
"tags": ["users"]
}
},
"/files/audio/upload-finished": {
"post": {
"operationId": "uploadFinished",
@ -3134,6 +3227,34 @@
"tags": ["notification"],
"security": [{ "bearer": [] }]
}
},
"/terms": {
"post": {
"operationId": "getTermsInfo",
"summary": "",
"parameters": [],
"responses": {
"200": {
"description": "成功時のレスポンス",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/GetTermsInfoResponse"
}
}
}
},
"500": {
"description": "想定外のサーバーエラー",
"content": {
"application/json": {
"schema": { "$ref": "#/components/schemas/ErrorResponse" }
}
}
}
},
"tags": ["terms"]
}
}
},
"info": {
@ -3705,6 +3826,18 @@
},
"required": ["accountId"]
},
"GetAccountInfoMinimalAccessRequest": {
"type": "object",
"properties": {
"idToken": { "type": "string", "description": "idトークン" }
},
"required": ["idToken"]
},
"GetAccountInfoMinimalAccessResponse": {
"type": "object",
"properties": { "tier": { "type": "number", "description": "階層" } },
"required": ["tier"]
},
"ConfirmRequest": {
"type": "object",
"properties": { "token": { "type": "string" } },
@ -3925,6 +4058,22 @@
"required": ["userId"]
},
"DeallocateLicenseResponse": { "type": "object", "properties": {} },
"UpdateAcceptedVersionRequest": {
"type": "object",
"properties": {
"idToken": { "type": "string", "description": "IDトークン" },
"acceptedEULAVersion": {
"type": "string",
"description": "更新バージョンEULA"
},
"acceptedDPAVersion": {
"type": "string",
"description": "更新バージョンDPA"
}
},
"required": ["idToken", "acceptedEULAVersion"]
},
"UpdateAcceptedVersionResponse": { "type": "object", "properties": {} },
"AudioOptionItem": {
"type": "object",
"properties": {
@ -4406,7 +4555,8 @@
},
"required": ["pns", "handler"]
},
"RegisterResponse": { "type": "object", "properties": {} }
"RegisterResponse": { "type": "object", "properties": {} },
"GetTermsInfoResponse": { "type": "object", "properties": {} }
}
}
}

View File

@ -49,6 +49,7 @@ import { WorkflowsController } from './features/workflows/workflows.controller';
import { WorkflowsService } from './features/workflows/workflows.service';
import { validate } from './common/validators/env.validator';
import { WorkflowsRepositoryModule } from './repositories/workflows/workflows.repository.module';
import { TermsModule } from './features/terms/terms.module';
@Module({
imports: [
@ -108,6 +109,7 @@ import { WorkflowsRepositoryModule } from './repositories/workflows/workflows.re
AuthGuardsModule,
SortCriteriaRepositoryModule,
WorktypesRepositoryModule,
TermsModule,
],
controllers: [
HealthController,

View File

@ -63,6 +63,8 @@ import {
DeleteAccountRequest,
DeleteAccountResponse,
GetAuthorsResponse,
GetAccountInfoMinimalAccessRequest,
GetAccountInfoMinimalAccessResponse,
} from './types/types';
import { USER_ROLES, ADMIN_ROLES, TIERS } from '../../constants';
import { AuthGuard } from '../../common/guards/auth/authguards';
@ -1091,4 +1093,32 @@ export class AccountsController {
await this.accountService.deleteAccountAndData(context, userId, accountId);
return;
}
@Post('/minimal-access')
@ApiResponse({
status: HttpStatus.OK,
type: GetAccountInfoMinimalAccessResponse,
description: '成功時のレスポンス',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: '対象のユーザーIDが存在しない場合',
type: ErrorResponse,
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: '想定外のサーバーエラー',
type: ErrorResponse,
})
@ApiOperation({ operationId: 'getAccountInfoMinimalAccess' })
async getAccountInfoMinimalAccess(
@Body() body: GetAccountInfoMinimalAccessRequest,
): Promise<GetAccountInfoMinimalAccessResponse> {
const context = makeContext(uuidv4());
// TODO 仮実装。API実装タスクで本実装する。
// const idToken = await this.authService.getVerifiedIdToken(body.idToken);
// await this.accountService.getAccountInfoMinimalAccess(context, idToken);
return;
}
}

View File

@ -577,3 +577,13 @@ export class DeleteAccountRequest {
}
export class DeleteAccountResponse {}
export class GetAccountInfoMinimalAccessRequest {
@ApiProperty({ description: 'idトークン' })
idToken: string;
}
export class GetAccountInfoMinimalAccessResponse {
@ApiProperty({ description: '階層' })
tier: number;
}

View File

@ -41,7 +41,7 @@ export class AuthController {
})
@ApiResponse({
status: HttpStatus.UNAUTHORIZED,
description: '認証エラー',
description: '認証エラー/同意済み利用規約が最新でない場合',
type: ErrorResponse,
})
@ApiResponse({

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TermsController } from './terms.controller';
describe('TermsController', () => {
let controller: TermsController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [TermsController],
}).compile();
controller = module.get<TermsController>(TermsController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});

View File

@ -0,0 +1,40 @@
import { Controller, HttpStatus, Post } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { TermsService } from '../terms/terms.service';
import { ErrorResponse } from '../../common/error/types/types';
import { makeContext } from '../../common/log';
import { v4 as uuidv4 } from 'uuid';
import { GetTermsInfoResponse, TermInfo } from './types/types';
@ApiTags('terms')
@Controller('terms')
export class TermsController {
constructor(
private readonly termsService: TermsService, //private readonly cryptoService: CryptoService,
) {}
@Post()
@ApiResponse({
status: HttpStatus.OK,
type: GetTermsInfoResponse,
description: '成功時のレスポンス',
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: '想定外のサーバーエラー',
type: ErrorResponse,
})
@ApiOperation({ operationId: 'getTermsInfo' })
async getTermsInfo(): Promise<GetTermsInfoResponse> {
const context = makeContext(uuidv4());
// TODO 仮実装。API実装タスクで本実装する。
// const termInfo = await this.termsService.getTermsInfo(context);
const termsInfo = [
{ documentType: 'EULA', version: '1.0' },
{ documentType: 'DPA', version: '1.1' },
] as TermInfo[];
return { termsInfo };
}
}

View File

@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TermsController } from './terms.controller';
import { TermsService } from './terms.service';
@Module({
controllers: [TermsController],
providers: [TermsService]
})
export class TermsModule {}

View File

@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { TermsService } from './terms.service';
describe('TermsService', () => {
let service: TermsService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [TermsService],
}).compile();
service = module.get<TermsService>(TermsService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});

View File

@ -0,0 +1,4 @@
import { Injectable } from '@nestjs/common';
@Injectable()
export class TermsService {}

View File

@ -0,0 +1,12 @@
import { ApiProperty } from '@nestjs/swagger';
export class GetTermsInfoResponse {
termsInfo: TermInfo[];
}
export class TermInfo {
@ApiProperty({ description: '利用規約種別' })
documentType: string;
@ApiProperty({ description: 'バージョン' })
version: string;
}

View File

@ -255,3 +255,14 @@ export class DeallocateLicenseRequest {
}
export class DeallocateLicenseResponse {}
export class UpdateAcceptedVersionRequest {
@ApiProperty({ description: 'IDトークン' })
idToken: string;
@ApiProperty({ description: '更新バージョンEULA' })
acceptedEULAVersion: string;
@ApiProperty({ description: '更新バージョンDPA', required: false })
acceptedDPAVersion?: string | undefined;
}
export class UpdateAcceptedVersionResponse {}

View File

@ -37,6 +37,8 @@ import {
AllocateLicenseRequest,
DeallocateLicenseResponse,
DeallocateLicenseRequest,
UpdateAcceptedVersionRequest,
UpdateAcceptedVersionResponse,
} from './types/types';
import { UsersService } from './users.service';
import jwt from 'jsonwebtoken';
@ -469,4 +471,35 @@ export class UsersController {
await this.usersService.deallocateLicense(context, body.userId);
return {};
}
@ApiResponse({
status: HttpStatus.OK,
type: UpdateAcceptedVersionResponse,
description: '成功時のレスポンス',
})
@ApiResponse({
status: HttpStatus.BAD_REQUEST,
description: 'パラメータ不正/対象のユーザidが存在しない場合',
type: ErrorResponse,
})
@ApiResponse({
status: HttpStatus.INTERNAL_SERVER_ERROR,
description: '想定外のサーバーエラー',
type: ErrorResponse,
})
@ApiOperation({
operationId: 'updateAcceptedVersion',
description: '利用規約同意バージョンを更新',
})
@Post('/accepted-version')
async updateAcceptedVersion(
@Body() body: UpdateAcceptedVersionRequest,
): Promise<UpdateAcceptedVersionResponse> {
const context = makeContext(uuidv4());
// TODO 仮実装。API実装タスクで本実装する。
// const idToken = await this.authService.getVerifiedIdToken(body.idToken);
// await this.usersService.updateAcceptedVersion(context, idToken);
return {};
}
}