346 lines
9.8 KiB
TypeScript
346 lines
9.8 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,
|
||
TemplateUploadFinishedReqponse,
|
||
TemplateUploadFinishedRequest,
|
||
TemplateUploadLocationResponse,
|
||
} from './types/types';
|
||
import { AuthGuard } from '../../common/guards/auth/authguards';
|
||
import { RoleGuard } from '../../common/guards/role/roleguards';
|
||
import { ADMIN_ROLES, 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 };
|
||
}
|
||
|
||
@Get('template/upload-location')
|
||
@ApiResponse({
|
||
status: HttpStatus.OK,
|
||
type: TemplateUploadLocationResponse,
|
||
description: '成功時のレスポンス',
|
||
})
|
||
@ApiResponse({
|
||
status: HttpStatus.UNAUTHORIZED,
|
||
description: '認証エラー',
|
||
type: ErrorResponse,
|
||
})
|
||
@ApiResponse({
|
||
status: HttpStatus.INTERNAL_SERVER_ERROR,
|
||
description: '想定外のサーバーエラー',
|
||
type: ErrorResponse,
|
||
})
|
||
@ApiOperation({
|
||
operationId: 'uploadTemplateLocation',
|
||
description:
|
||
'ログイン中ユーザー用のBlob Storage上のテンプレートファイルのアップロード先アクセスURLを取得します',
|
||
})
|
||
@ApiBearerAuth()
|
||
@UseGuards(AuthGuard)
|
||
@UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }))
|
||
async uploadTemplateLocation(
|
||
@Req() req: Request,
|
||
): Promise<TemplateUploadLocationResponse> {
|
||
const token = retrieveAuthorizationToken(req);
|
||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||
|
||
const context = makeContext(userId);
|
||
|
||
const url = await this.filesService.publishTemplateFileUploadSas(
|
||
context,
|
||
userId,
|
||
);
|
||
|
||
return { url };
|
||
}
|
||
|
||
@ApiResponse({
|
||
status: HttpStatus.OK,
|
||
type: TemplateUploadFinishedReqponse,
|
||
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: 'uploadTemplateFinished',
|
||
description: 'アップロードが完了したテンプレートファイルの情報を登録します',
|
||
})
|
||
@ApiBearerAuth()
|
||
@UseGuards(AuthGuard)
|
||
@UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }))
|
||
@Post('template/upload-finished')
|
||
async templateUploadFinished(
|
||
@Req() req: Request,
|
||
@Body() body: TemplateUploadFinishedRequest,
|
||
): Promise<TemplateUploadFinishedReqponse> {
|
||
const { name, url } = body;
|
||
const token = retrieveAuthorizationToken(req);
|
||
const { userId } = jwt.decode(token, { json: true }) as AccessToken;
|
||
|
||
const context = makeContext(userId);
|
||
await this.filesService.templateUploadFinished(context, userId, url, name);
|
||
return {};
|
||
}
|
||
}
|