## 概要 [Task2294: 外部連携APIにログを入れ込む(強化)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2294) - 外部連携APIのログを強化しました。 - contextオブジェクトで操作者情報を渡すようにしています。 - ログポリシーに従って追加しています。 - [ログポリシー](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/OMDSDictation/_wiki/wikis/OMDSDictation_wiki/223/%E3%83%AD%E3%82%B0%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC) ## レビューポイント - 出力内容に過不足はないか - ログ追加対象に過不足はないか。 - contextで操作者情報を渡しているが想定通りか ## UIの変更 - なし ## 動作確認状況 - ローカルで確認
262 lines
7.2 KiB
TypeScript
262 lines
7.2 KiB
TypeScript
import {
|
||
Body,
|
||
Controller,
|
||
Get,
|
||
HttpStatus,
|
||
Post,
|
||
Query,
|
||
Req,
|
||
UseGuards,
|
||
} from '@nestjs/common';
|
||
import {
|
||
ApiBearerAuth,
|
||
ApiOperation,
|
||
ApiResponse,
|
||
ApiTags,
|
||
} from '@nestjs/swagger';
|
||
import jwt from 'jsonwebtoken';
|
||
import { AccessToken } from '../../common/token';
|
||
import { ErrorResponse } from '../../common/error/types/types';
|
||
import { FilesService } from './files.service';
|
||
import {
|
||
AudioDownloadLocationRequest,
|
||
AudioDownloadLocationResponse,
|
||
AudioUploadFinishedRequest,
|
||
AudioUploadFinishedResponse,
|
||
AudioUploadLocationRequest,
|
||
AudioUploadLocationResponse,
|
||
TemplateDownloadLocationRequest,
|
||
TemplateDownloadLocationResponse,
|
||
} from './types/types';
|
||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||
import { RoleGuard } from '../../common/guards/role/roleguards';
|
||
import { USER_ROLES } from '../../constants';
|
||
import { retrieveAuthorizationToken } from '../../common/http/helper';
|
||
import { Request } from 'express';
|
||
import { makeContext } from '../../common/log';
|
||
|
||
@ApiTags('files')
|
||
@Controller('files')
|
||
export class FilesController {
|
||
constructor(private readonly filesService: FilesService) {}
|
||
|
||
@ApiResponse({
|
||
status: HttpStatus.OK,
|
||
type: AudioUploadFinishedResponse,
|
||
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: 'uploadFinished',
|
||
description:
|
||
'アップロードが完了した音声ファイルの情報を登録し、文字起こしタスクを生成します',
|
||
})
|
||
@ApiBearerAuth()
|
||
@UseGuards(AuthGuard)
|
||
@UseGuards(RoleGuard.requireds({ roles: [USER_ROLES.AUTHOR] }))
|
||
@Post('audio/upload-finished')
|
||
async uploadFinished(
|
||
@Req() req: Request,
|
||
@Body() body: AudioUploadFinishedRequest,
|
||
): Promise<AudioUploadFinishedResponse> {
|
||
const token = retrieveAuthorizationToken(req);
|
||
const accessToken = jwt.decode(token, { json: true }) as AccessToken;
|
||
|
||
const context = makeContext(accessToken.userId);
|
||
|
||
const {
|
||
url,
|
||
authorId,
|
||
fileName,
|
||
duration,
|
||
createdDate,
|
||
finishedDate,
|
||
uploadedDate,
|
||
fileSize,
|
||
priority,
|
||
audioFormat,
|
||
comment,
|
||
workType,
|
||
optionItemList,
|
||
isEncrypted,
|
||
} = body;
|
||
|
||
const res = await this.filesService.uploadFinished(
|
||
context,
|
||
accessToken.userId,
|
||
url,
|
||
authorId,
|
||
fileName,
|
||
duration,
|
||
createdDate,
|
||
finishedDate,
|
||
uploadedDate,
|
||
fileSize,
|
||
priority,
|
||
audioFormat,
|
||
comment,
|
||
workType,
|
||
optionItemList,
|
||
isEncrypted,
|
||
);
|
||
|
||
return { jobNumber: res.jobNumber };
|
||
}
|
||
|
||
@Get('audio/upload-location')
|
||
@ApiResponse({
|
||
status: HttpStatus.OK,
|
||
type: AudioUploadLocationResponse,
|
||
description: '成功時のレスポンス',
|
||
})
|
||
@ApiResponse({
|
||
status: HttpStatus.UNAUTHORIZED,
|
||
description: '認証エラー',
|
||
type: ErrorResponse,
|
||
})
|
||
@ApiResponse({
|
||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||
description: '想定外のサーバーエラー',
|
||
type: ErrorResponse,
|
||
})
|
||
@ApiOperation({
|
||
operationId: 'uploadLocation',
|
||
description:
|
||
'ログイン中ユーザー用のBlob Storage上の音声ファイルのアップロード先アクセスURLを取得します',
|
||
})
|
||
@ApiBearerAuth()
|
||
@UseGuards(AuthGuard)
|
||
@UseGuards(RoleGuard.requireds({ roles: [USER_ROLES.AUTHOR] }))
|
||
async uploadLocation(
|
||
@Req() req: Request,
|
||
// クエリパラメータ AudioUploadLocationRequest は空であるため内部で使用しない。
|
||
// 使用しないことを宣言するために先頭にプレフィックス_(アンダースコア)をつけている
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||
@Query() _query: AudioUploadLocationRequest,
|
||
): Promise<AudioUploadLocationResponse> {
|
||
const token = retrieveAuthorizationToken(req);
|
||
const accessToken = jwt.decode(token, { json: true }) as AccessToken;
|
||
|
||
const context = makeContext(accessToken.userId);
|
||
|
||
const url = await this.filesService.publishUploadSas(context, accessToken);
|
||
return { url };
|
||
}
|
||
|
||
@Get('audio/download-location')
|
||
@ApiResponse({
|
||
status: HttpStatus.OK,
|
||
type: AudioDownloadLocationResponse,
|
||
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: 'downloadLocation',
|
||
description:
|
||
'指定した音声ファイルのBlob Storage上のダウンロード先アクセスURLを取得します',
|
||
})
|
||
@ApiBearerAuth()
|
||
@UseGuards(AuthGuard)
|
||
@UseGuards(
|
||
RoleGuard.requireds({ roles: [USER_ROLES.AUTHOR, USER_ROLES.TYPIST] }),
|
||
)
|
||
async downloadLocation(
|
||
@Req() req: Request,
|
||
@Query() body: AudioDownloadLocationRequest,
|
||
): Promise<AudioDownloadLocationResponse> {
|
||
const { audioFileId } = body;
|
||
|
||
const token = retrieveAuthorizationToken(req);
|
||
const accessToken = jwt.decode(token, { json: true }) as AccessToken;
|
||
|
||
const context = makeContext(accessToken.userId);
|
||
|
||
const url = await this.filesService.publishAudioFileDownloadSas(
|
||
context,
|
||
accessToken.userId,
|
||
audioFileId,
|
||
);
|
||
|
||
return { url };
|
||
}
|
||
|
||
@Get('template/download-location')
|
||
@ApiResponse({
|
||
status: HttpStatus.OK,
|
||
type: TemplateDownloadLocationResponse,
|
||
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: 'downloadTemplateLocation',
|
||
description:
|
||
'指定した音声ファイルに対応したテンプレートファイルのBlob Storage上のダウンロード先アクセスURLを取得します',
|
||
})
|
||
@ApiBearerAuth()
|
||
@UseGuards(AuthGuard)
|
||
@UseGuards(
|
||
RoleGuard.requireds({ roles: [USER_ROLES.AUTHOR, USER_ROLES.TYPIST] }),
|
||
)
|
||
async downloadTemplateLocation(
|
||
@Req() req: Request,
|
||
@Query() body: TemplateDownloadLocationRequest,
|
||
): Promise<TemplateDownloadLocationResponse> {
|
||
const { audioFileId } = body;
|
||
|
||
const token = retrieveAuthorizationToken(req);
|
||
const accessToken = jwt.decode(token, { json: true }) as AccessToken;
|
||
|
||
const context = makeContext(accessToken.userId);
|
||
|
||
const url = await this.filesService.publishTemplateFileDownloadSas(
|
||
context,
|
||
accessToken.userId,
|
||
audioFileId,
|
||
);
|
||
|
||
return { url };
|
||
}
|
||
}
|