diff --git a/dictation_server/src/features/files/files.controller.ts b/dictation_server/src/features/files/files.controller.ts index af41275..f8b4328 100644 --- a/dictation_server/src/features/files/files.controller.ts +++ b/dictation_server/src/features/files/files.controller.ts @@ -338,9 +338,7 @@ export class FilesController { }) @ApiBearerAuth() @UseGuards(AuthGuard) - @UseGuards( - RoleGuard.requireds({ roles: [USER_ROLES.AUTHOR, USER_ROLES.TYPIST] }), - ) + @UseGuards(RoleGuard.requireds({ roles: [USER_ROLES.TYPIST] })) async downloadTemplateLocation( @Req() req: Request, @Query() body: TemplateDownloadLocationRequest, diff --git a/dictation_server/src/features/files/files.service.spec.ts b/dictation_server/src/features/files/files.service.spec.ts index d32d081..89c9f68 100644 --- a/dictation_server/src/features/files/files.service.spec.ts +++ b/dictation_server/src/features/files/files.service.spec.ts @@ -34,7 +34,12 @@ import { TasksRepositoryService } from '../../repositories/tasks/tasks.repositor import { NotificationhubService } from '../../gateways/notificationhub/notificationhub.service'; import { getCheckoutPermissions, getTask } from '../tasks/test/utility'; import { DateWithZeroTime } from '../licenses/types/types'; -import { LICENSE_ALLOCATED_STATUS, LICENSE_TYPE } from '../../constants'; +import { + LICENSE_ALLOCATED_STATUS, + LICENSE_TYPE, + TASK_STATUS, + USER_ROLES, +} from '../../constants'; describe('publishUploadSas', () => { let source: DataSource | null = null; @@ -1505,15 +1510,11 @@ describe('テンプレートファイルダウンロードURL取得', () => { it('ダウンロードSASトークンが乗っているURLを取得できる', async () => { if (!source) fail(); const { id: accountId } = await makeTestSimpleAccount(source); - const { external_id: externalId, author_id: authorId } = await makeTestUser( - source, - { - account_id: accountId, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', - }, - ); + const { external_id: externalId, id: userId } = await makeTestUser(source, { + account_id: accountId, + external_id: 'typist-user-external-id', + role: USER_ROLES.TYPIST, + }); const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`; const { audioFileId } = await createTask( @@ -1521,9 +1522,9 @@ describe('テンプレートファイルダウンロードURL取得', () => { accountId, url, 'test.zip', - 'InProgress', - undefined, - authorId ?? '', + TASK_STATUS.IN_PROGRESS, + userId, + 'AUTHOR_ID', ); const blobParam = makeBlobstorageServiceMockValue(); @@ -1539,13 +1540,12 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - expect( - await service.publishTemplateFileDownloadSas( - makeContext('tracking', 'requestId'), - externalId, - audioFileId, - ), - ).toEqual(`${url}?sas-token`); + const resultUrl = await service.publishTemplateFileDownloadSas( + makeContext('tracking', 'requestId'), + externalId, + audioFileId, + ); + expect(resultUrl).toBe(`${url}?sas-token`); }); it('ダウンロードSASトークンが乗っているURLを取得できる(第五階層の場合ライセンスのチェックを行う)', async () => { if (!source) fail(); @@ -1557,15 +1557,10 @@ describe('テンプレートファイルダウンロードURL取得', () => { parent_account_id: tier4Accounts[0].account.id, tier: 5, }); - const { - external_id: externalId, - id: userId, - author_id: authorId, - } = await makeTestUser(source, { + const { external_id: externalId, id: userId } = await makeTestUser(source, { account_id: tier5Accounts.account.id, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', + external_id: 'typist-user-external-id', + role: USER_ROLES.TYPIST, }); // 本日の日付を作成 let yesterday = new Date(); @@ -1591,9 +1586,9 @@ describe('テンプレートファイルダウンロードURL取得', () => { tier5Accounts.account.id, url, 'test.zip', - 'InProgress', - undefined, - authorId ?? '', + TASK_STATUS.IN_PROGRESS, + userId, + 'AUTHOR_ID', ); const blobParam = makeBlobstorageServiceMockValue(); @@ -1609,22 +1604,20 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - expect( - await service.publishTemplateFileDownloadSas( - makeContext('trackingId', 'requestId'), - externalId, - audioFileId, - ), - ).toEqual(`${url}?sas-token`); + const resultUrl = await service.publishTemplateFileDownloadSas( + makeContext('trackingId', 'requestId'), + externalId, + audioFileId, + ); + expect(resultUrl).toBe(`${url}?sas-token`); }); - it('Typistの場合、タスクのステータスが[Inprogress,Pending]以外でエラー', async () => { + it('タスクのステータスが[Inprogress,Pending]以外でエラー', async () => { if (!source) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: externalId, id: userId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', - role: 'typist', - author_id: undefined, + role: USER_ROLES.TYPIST, }); const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`; @@ -1633,7 +1626,7 @@ describe('テンプレートファイルダウンロードURL取得', () => { accountId, url, 'test.zip', - 'Finished', + TASK_STATUS.FINISHED, userId, ); @@ -1650,31 +1643,35 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - await expect( - service.publishTemplateFileDownloadSas( + try { + await service.publishTemplateFileDownloadSas( makeContext('tracking', 'requestId'), externalId, audioFileId, - ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), - ); + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); + } else { + fail(); + } + } }); - it('Typistの場合、自身が担当するタスクでない場合エラー', async () => { + it('自身が担当するタスクでない場合エラー', async () => { if (!source) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: externalId } = await makeTestUser(source, { account_id: accountId, external_id: 'typist-user-external-id', - role: 'typist', - author_id: undefined, + role: USER_ROLES.TYPIST, }); const { id: otherId } = await makeTestUser(source, { account_id: accountId, external_id: 'other-typist-user-external-id', - role: 'typist', - author_id: undefined, + role: USER_ROLES.TYPIST, }); const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`; @@ -1683,7 +1680,7 @@ describe('テンプレートファイルダウンロードURL取得', () => { accountId, url, 'test.zip', - 'InProgress', + TASK_STATUS.IN_PROGRESS, otherId, ); @@ -1700,60 +1697,21 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - await expect( - service.publishTemplateFileDownloadSas( + try { + await service.publishTemplateFileDownloadSas( makeContext('tracking', 'requestId'), externalId, audioFileId, - ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), - ); - }); - - it('Authorの場合、自身が登録したタスクでない場合エラー', async () => { - if (!source) fail(); - const { id: accountId } = await makeTestSimpleAccount(source); - const { external_id: externalId } = await makeTestUser(source, { - account_id: accountId, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', - }); - const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`; - - const { audioFileId } = await createTask( - source, - accountId, - url, - 'test.zip', - 'InProgress', - undefined, - 'OTHOR_ID', - ); - - const blobParam = makeBlobstorageServiceMockValue(); - blobParam.publishDownloadSas = `${url}?sas-token`; - blobParam.fileExists = true; - - const notificationParam = makeDefaultNotificationhubServiceMockValue(); - const module = await makeTestingModuleWithBlobAndNotification( - source, - blobParam, - notificationParam, - ); - if (!module) fail(); - const service = module.get(FilesService); - - await expect( - service.publishTemplateFileDownloadSas( - makeContext('tracking', 'requestId'), - externalId, - audioFileId, - ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), - ); + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); + } else { + fail(); + } + } }); it('Taskが存在しない場合はエラーとなる', async () => { @@ -1761,9 +1719,8 @@ describe('テンプレートファイルダウンロードURL取得', () => { const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: externalId } = await makeTestUser(source, { account_id: accountId, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', + external_id: 'typist-user-external-id', + role: USER_ROLES.TYPIST, }); const blobParam = makeBlobstorageServiceMockValue(); @@ -1777,29 +1734,31 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - await expect( - service.publishTemplateFileDownloadSas( + try { + await service.publishTemplateFileDownloadSas( makeContext('tracking', 'requestId'), externalId, 1, - ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST), - ); + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010603')); + } else { + fail(); + } + } }); it('blobストレージにファイルが存在しない場合はエラーとなる', async () => { if (!source) fail(); const { id: accountId } = await makeTestSimpleAccount(source); - const { external_id: externalId, author_id: authorId } = await makeTestUser( - source, - { - account_id: accountId, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', - }, - ); + const { external_id: externalId, id: userId } = await makeTestUser(source, { + account_id: accountId, + external_id: 'typist-user-external-id', + role: USER_ROLES.TYPIST, + }); const url = `https://saodmsusdev.blob.core.windows.net/account-${accountId}/Templates`; const { audioFileId } = await createTask( @@ -1807,9 +1766,9 @@ describe('テンプレートファイルダウンロードURL取得', () => { accountId, url, 'test.zip', - 'InProgress', - undefined, - authorId ?? '', + TASK_STATUS.IN_PROGRESS, + userId, + 'AUTHOR_ID', ); const blobParam = makeBlobstorageServiceMockValue(); @@ -1825,15 +1784,21 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - await expect( - service.publishTemplateFileDownloadSas( + try { + await service.publishTemplateFileDownloadSas( makeContext('tracking', 'requestId'), externalId, audioFileId, - ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010701'), HttpStatus.BAD_REQUEST), - ); + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010701')); + } else { + fail(); + } + } }); it('ダウンロード時にユーザーにライセンスが未割当の場合エラーとなる(第五階層限定)', async () => { if (!source) fail(); @@ -1845,15 +1810,10 @@ describe('テンプレートファイルダウンロードURL取得', () => { parent_account_id: tier4Accounts[0].account.id, tier: 5, }); - const { - external_id: externalId, - id: userId, - author_id: authorId, - } = await makeTestUser(source, { + const { external_id: externalId, id: userId } = await makeTestUser(source, { account_id: tier5Accounts.account.id, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', + external_id: 'typist-user-external-id', + role: USER_ROLES.TYPIST, }); const url = `https://saodmsusdev.blob.core.windows.net/account-${tier5Accounts.account.id}/${userId}`; @@ -1862,9 +1822,9 @@ describe('テンプレートファイルダウンロードURL取得', () => { tier5Accounts.account.id, url, 'test.zip', - 'InProgress', + TASK_STATUS.IN_PROGRESS, undefined, - authorId ?? '', + 'AUTHOR_ID', ); const blobParam = makeBlobstorageServiceMockValue(); @@ -1880,15 +1840,21 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - await expect( - service.publishTemplateFileDownloadSas( + try { + await service.publishTemplateFileDownloadSas( makeContext('trackingId', 'requestId'), externalId, audioFileId, - ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010812'), HttpStatus.BAD_REQUEST), - ); + ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010812')); + } else { + fail(); + } + } }); it('ダウンロード時にユーザーに割り当てられたライセンスが有効期限切れの場合エラー(第五階層限定)', async () => { if (!source) fail(); @@ -1900,15 +1866,10 @@ describe('テンプレートファイルダウンロードURL取得', () => { parent_account_id: tier4Accounts[0].account.id, tier: 5, }); - const { - external_id: externalId, - id: userId, - author_id: authorId, - } = await makeTestUser(source, { + const { external_id: externalId, id: userId } = await makeTestUser(source, { account_id: tier5Accounts.account.id, - external_id: 'author-user-external-id', - role: 'author', - author_id: 'AUTHOR_ID', + external_id: 'typist-user-external-id', + role: USER_ROLES.TYPIST, }); // 昨日の日付を作成 let yesterday = new Date(); @@ -1934,9 +1895,9 @@ describe('テンプレートファイルダウンロードURL取得', () => { tier5Accounts.account.id, url, 'test.zip', - 'InProgress', + TASK_STATUS.IN_PROGRESS, undefined, - authorId ?? '', + 'AUTHOR_ID', ); const blobParam = makeBlobstorageServiceMockValue(); @@ -1952,15 +1913,21 @@ describe('テンプレートファイルダウンロードURL取得', () => { if (!module) fail(); const service = module.get(FilesService); - await expect( - service.publishTemplateFileDownloadSas( + try { + await service.publishTemplateFileDownloadSas( makeContext('trackingId', 'requestId'), externalId, audioFileId, ), - ).rejects.toEqual( - new HttpException(makeErrorResponse('E010805'), HttpStatus.BAD_REQUEST), - ); + fail(); + } catch (e) { + if (e instanceof HttpException) { + expect(e.getStatus()).toBe(HttpStatus.BAD_REQUEST); + expect(e.getResponse()).toEqual(makeErrorResponse('E010805')); + } else { + fail(); + } + } }); }); diff --git a/dictation_server/src/features/files/files.service.ts b/dictation_server/src/features/files/files.service.ts index 8e73b0a..6c1b558 100644 --- a/dictation_server/src/features/files/files.service.ts +++ b/dictation_server/src/features/files/files.service.ts @@ -474,7 +474,7 @@ export class FilesService { // ユーザーがTypistの場合、自身が担当したタスクでない場合はエラー if (isTypist && task.typist_user_id !== userId) { - throw new AuthorUserNotMatchError( + throw new TypistUserNotFoundError( `task typist is not match. audio_file_id:${audioFileId}, task.typist_user_id:${task.typist_user_id}, userId:${userId}`, ); } @@ -563,8 +563,6 @@ export class FilesService { let accountId: number; let userId: number; let country: string; - let isTypist: boolean; - let authorId: string | undefined; try { const user = await this.usersRepository.findUserByExternalId( context, @@ -590,8 +588,6 @@ export class FilesService { accountId = user.account_id; userId = user.id; country = user.account.country; - isTypist = user.role === USER_ROLES.TYPIST; - authorId = user.author_id ?? undefined; } catch (e) { this.logger.error(`[${context.getTrackingId()}] error=${e}`); this.logger.log( @@ -619,27 +615,13 @@ export class FilesService { } try { - const status = isTypist - ? [TASK_STATUS.IN_PROGRESS, TASK_STATUS.PENDING] - : Object.values(TASK_STATUS); - const task = await this.tasksRepository.getTaskAndAudioFile( context, audioFileId, accountId, - status, + [TASK_STATUS.IN_PROGRESS, TASK_STATUS.PENDING], ); - const { file } = task; - - // タスクに紐づく音声ファイルだけが消される場合がある。 - // その場合はダウンロード不可なので不在エラーとして扱う - if (!file) { - throw new AudioFileNotFoundError( - `Audio file is not exists in DB. audio_file_id:${audioFileId}`, - ); - } - - const template_file = task.template_file; + const { template_file } = task; // タスクに紐づくテンプレートファイルがない場合がある。 // その場合はダウンロード不可なので不在エラーとして扱う @@ -649,16 +631,9 @@ export class FilesService { ); } - // ユーザーがAuthorの場合、自身が追加したタスクでない場合はエラー - if (!isTypist && file.author_id !== authorId) { - throw new AuthorUserNotMatchError( - `task author is not match. audio_file_id:${audioFileId}, task.file.author_id:${file.author_id}, authorId:${authorId}`, - ); - } - - // ユーザーがTypistの場合、自身が担当したタスクでない場合はエラー - if (isTypist && task.typist_user_id !== userId) { - throw new AuthorUserNotMatchError( + // ユーザー自身が担当したタスクでない場合はエラー + if (task.typist_user_id !== userId) { + throw new TypistUserNotFoundError( `task typist is not match. audio_file_id:${audioFileId}, task.typist_user_id:${task.typist_user_id}, userId:${userId}`, ); } @@ -693,7 +668,6 @@ export class FilesService { case TasksNotFoundError: case AccountNotMatchError: case StatusNotMatchError: - case AuthorUserNotMatchError: case TypistUserNotFoundError: throw new HttpException( makeErrorResponse('E010603'),