diff --git a/dictation_server/src/features/tasks/tasks.service.spec.ts b/dictation_server/src/features/tasks/tasks.service.spec.ts index ee38b41..06adcbd 100644 --- a/dictation_server/src/features/tasks/tasks.service.spec.ts +++ b/dictation_server/src/features/tasks/tasks.service.spec.ts @@ -1086,6 +1086,7 @@ describe('checkout', () => { await source.destroy(); source = null; }); + it('ユーザーのRoleがTypistで、タスクのチェックアウト権限が個人指定である時、タスクをチェックアウトできる', async () => { const module = await makeTestingModule(source); const { accountId } = await createAccount(source); @@ -1326,6 +1327,108 @@ describe('checkout', () => { ); }); + it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクをチェックアウトできる(Uploaded)', async () => { + const module = await makeTestingModule(source); + const { accountId } = await createAccount(source); + const { userId: authorUserId } = await createUser( + source, + accountId, + 'author-user-external-id', + 'author', + 'MY_AUTHOR_ID', + ); + await createTask( + source, + accountId, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + 'Uploaded', + ); + + const service = module.get(TasksService); + expect( + await service.checkout(1, ['author'], 'author-user-external-id'), + ).toEqual(undefined); + }); + + it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクをチェックアウトできる(Finished)', async () => { + const module = await makeTestingModule(source); + const { accountId } = await createAccount(source); + const { userId: authorUserId } = await createUser( + source, + accountId, + 'author-user-external-id', + 'author', + 'MY_AUTHOR_ID', + ); + await createTask( + source, + accountId, + authorUserId, + 'MY_AUTHOR_ID', + '', + '01', + '00000001', + 'Uploaded', + ); + + const service = module.get(TasksService); + expect( + await service.checkout(1, ['author'], 'author-user-external-id'), + ).toEqual(undefined); + }); + + it('ユーザーのRoleがAuthorで、アップロードした音声ファイルに紐づいたタスクが存在しない場合、タスクをチェックアウトできない', async () => { + const module = await makeTestingModule(source); + const { accountId } = await createAccount(source); + await createUser( + source, + accountId, + 'author-user-external-id', + 'author', + 'MY_AUTHOR_ID', + ); + + const service = module.get(TasksService); + await expect( + service.checkout(1, ['author'], 'author-user-external-id'), + ).rejects.toEqual( + new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST), + ); + }); + + it('ユーザーのRoleがAuthorで、音声ファイルに紐づいたタスクでユーザーと一致するAuthorIDでない場合、タスクをチェックアウトできない', async () => { + const module = await makeTestingModule(source); + const { accountId } = await createAccount(source); + const { userId: authorUserId } = await createUser( + source, + accountId, + 'author-user-external-id', + 'author', + 'MY_AUTHOR_ID', + ); + await createTask( + source, + accountId, + authorUserId, + 'OTHOR_AUTHOR', + '', + '01', + '00000001', + 'Uploaded', + ); + + const service = module.get(TasksService); + await expect( + service.checkout(1, ['author'], 'author-user-external-id'), + ).rejects.toEqual( + new HttpException(makeErrorResponse('E010602'), HttpStatus.BAD_REQUEST), + ); + }); + it('ユーザーのRoleに[Typist,author]が設定されていない時、タスクをチェックアウトできない', async () => { const module = await makeTestingModule(source); const { accountId } = await createAccount(source); diff --git a/dictation_server/src/features/tasks/tasks.service.ts b/dictation_server/src/features/tasks/tasks.service.ts index d4b9d01..ee05cb6 100644 --- a/dictation_server/src/features/tasks/tasks.service.ts +++ b/dictation_server/src/features/tasks/tasks.service.ts @@ -19,6 +19,7 @@ import { AdB2cUser } from '../../gateways/adb2c/types/types'; import { CheckoutPermission } from '../../repositories/checkout_permissions/entity/checkout_permission.entity'; import { CheckoutPermissionNotFoundError, + TaskAuthorIdNotMatchError, TasksNotFoundError, TypistUserGroupNotFoundError, TypistUserNotFoundError, @@ -147,10 +148,16 @@ export class TasksService { externalId: string, ): Promise { try { - const { id, account_id } = + const { id, account_id, author_id } = await this.usersRepository.findUserByExternalId(externalId); - // TODO authorの処理は別タスクで対応 + if (roles.includes(USER_ROLES.AUTHOR)) { + await this.taskRepository.getTaskFromAudioFileId( + audioFileId, + account_id, + author_id, + ); + return; } if (roles.includes(USER_ROLES.TYPIST)) { @@ -163,6 +170,7 @@ export class TasksService { if (e instanceof Error) { switch (e.constructor) { case CheckoutPermissionNotFoundError: + case TaskAuthorIdNotMatchError: case InvalidRoleError: throw new HttpException( makeErrorResponse('E010602'), diff --git a/dictation_server/src/repositories/tasks/errors/types.ts b/dictation_server/src/repositories/tasks/errors/types.ts index 1799418..ea2ee17 100644 --- a/dictation_server/src/repositories/tasks/errors/types.ts +++ b/dictation_server/src/repositories/tasks/errors/types.ts @@ -4,5 +4,7 @@ export class TypistUserGroupNotFoundError extends Error {} export class TypistUserNotFoundError extends Error {} // タスク未発見エラー export class TasksNotFoundError extends Error {} +// タスクAuthorID不一致エラー +export class TaskAuthorIdNotMatchError extends Error {} // チェックアウト権限未発見エラー export class CheckoutPermissionNotFoundError extends Error {} diff --git a/dictation_server/src/repositories/tasks/tasks.repository.service.ts b/dictation_server/src/repositories/tasks/tasks.repository.service.ts index 9ecf93d..620ece7 100644 --- a/dictation_server/src/repositories/tasks/tasks.repository.service.ts +++ b/dictation_server/src/repositories/tasks/tasks.repository.service.ts @@ -22,6 +22,7 @@ import { UserGroup } from '../user_groups/entity/user_group.entity'; import { User } from '../users/entity/user.entity'; import { CheckoutPermissionNotFoundError, + TaskAuthorIdNotMatchError, TasksNotFoundError, TypistUserGroupNotFoundError, TypistUserNotFoundError, @@ -32,6 +33,45 @@ import { Roles } from '../../common/types/role'; export class TasksRepositoryService { constructor(private dataSource: DataSource) {} + /** + * 音声ファイルIDに紐づいたTaskを取得する + * @param audioFileId + * @param account_id + * @param author_id + * @returns task from author id + */ + async getTaskFromAudioFileId( + audioFileId: number, + account_id: number, + author_id: string, + ): Promise { + return await this.dataSource.transaction(async (entityManager) => { + const taskRepo = entityManager.getRepository(Task); + // 指定した音声ファイルIDに紐づくTaskの中でAuthorIDが一致するものを取得 + const task = await taskRepo.findOne({ + relations: { + file: true, + }, + where: { + audio_file_id: audioFileId, + account_id: account_id, + }, + }); + if (!task) { + throw new TasksNotFoundError( + `task not found. audio_file_id:${audioFileId}`, + ); + } + if (task.file?.author_id !== author_id) { + throw new TaskAuthorIdNotMatchError( + `task authorId not match. audio_file_id:${audioFileId}, author_id:${author_id}, author_id(Task):${task.file?.author_id}`, + ); + } + + return task; + }); + } + async checkout( audioFileId: number, account_id: number,