Merged PR 205: API実装(タスクチェックアウトAPI (Author))
## 概要 [Task2009: API実装(タスクチェックアウトAPI (Author))](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2009) - タスクチェックアウトAPIのAuthorユーザーの動作を実装しました。 - 対応するタスクがあるかを確認だけして特に変更はしていません。 - 対応タスクを追加しました。 ## レビューポイント - 実装内容は認識通りか - テスト内容に不足はないか ## UIの変更 なし ## 動作確認状況 - ローカルで確認
This commit is contained in:
parent
8c5f5b61c1
commit
dadbc550c6
@ -1086,6 +1086,7 @@ describe('checkout', () => {
|
|||||||
await source.destroy();
|
await source.destroy();
|
||||||
source = null;
|
source = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
it('ユーザーのRoleがTypistで、タスクのチェックアウト権限が個人指定である時、タスクをチェックアウトできる', async () => {
|
it('ユーザーのRoleがTypistで、タスクのチェックアウト権限が個人指定である時、タスクをチェックアウトできる', async () => {
|
||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
const { accountId } = await createAccount(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>(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>(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>(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>(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 () => {
|
it('ユーザーのRoleに[Typist,author]が設定されていない時、タスクをチェックアウトできない', async () => {
|
||||||
const module = await makeTestingModule(source);
|
const module = await makeTestingModule(source);
|
||||||
const { accountId } = await createAccount(source);
|
const { accountId } = await createAccount(source);
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { AdB2cUser } from '../../gateways/adb2c/types/types';
|
|||||||
import { CheckoutPermission } from '../../repositories/checkout_permissions/entity/checkout_permission.entity';
|
import { CheckoutPermission } from '../../repositories/checkout_permissions/entity/checkout_permission.entity';
|
||||||
import {
|
import {
|
||||||
CheckoutPermissionNotFoundError,
|
CheckoutPermissionNotFoundError,
|
||||||
|
TaskAuthorIdNotMatchError,
|
||||||
TasksNotFoundError,
|
TasksNotFoundError,
|
||||||
TypistUserGroupNotFoundError,
|
TypistUserGroupNotFoundError,
|
||||||
TypistUserNotFoundError,
|
TypistUserNotFoundError,
|
||||||
@ -147,10 +148,16 @@ export class TasksService {
|
|||||||
externalId: string,
|
externalId: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const { id, account_id } =
|
const { id, account_id, author_id } =
|
||||||
await this.usersRepository.findUserByExternalId(externalId);
|
await this.usersRepository.findUserByExternalId(externalId);
|
||||||
// TODO authorの処理は別タスクで対応
|
|
||||||
if (roles.includes(USER_ROLES.AUTHOR)) {
|
if (roles.includes(USER_ROLES.AUTHOR)) {
|
||||||
|
await this.taskRepository.getTaskFromAudioFileId(
|
||||||
|
audioFileId,
|
||||||
|
account_id,
|
||||||
|
author_id,
|
||||||
|
);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (roles.includes(USER_ROLES.TYPIST)) {
|
if (roles.includes(USER_ROLES.TYPIST)) {
|
||||||
@ -163,6 +170,7 @@ export class TasksService {
|
|||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
switch (e.constructor) {
|
switch (e.constructor) {
|
||||||
case CheckoutPermissionNotFoundError:
|
case CheckoutPermissionNotFoundError:
|
||||||
|
case TaskAuthorIdNotMatchError:
|
||||||
case InvalidRoleError:
|
case InvalidRoleError:
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E010602'),
|
makeErrorResponse('E010602'),
|
||||||
|
|||||||
@ -4,5 +4,7 @@ export class TypistUserGroupNotFoundError extends Error {}
|
|||||||
export class TypistUserNotFoundError extends Error {}
|
export class TypistUserNotFoundError extends Error {}
|
||||||
// タスク未発見エラー
|
// タスク未発見エラー
|
||||||
export class TasksNotFoundError extends Error {}
|
export class TasksNotFoundError extends Error {}
|
||||||
|
// タスクAuthorID不一致エラー
|
||||||
|
export class TaskAuthorIdNotMatchError extends Error {}
|
||||||
// チェックアウト権限未発見エラー
|
// チェックアウト権限未発見エラー
|
||||||
export class CheckoutPermissionNotFoundError extends Error {}
|
export class CheckoutPermissionNotFoundError extends Error {}
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import { UserGroup } from '../user_groups/entity/user_group.entity';
|
|||||||
import { User } from '../users/entity/user.entity';
|
import { User } from '../users/entity/user.entity';
|
||||||
import {
|
import {
|
||||||
CheckoutPermissionNotFoundError,
|
CheckoutPermissionNotFoundError,
|
||||||
|
TaskAuthorIdNotMatchError,
|
||||||
TasksNotFoundError,
|
TasksNotFoundError,
|
||||||
TypistUserGroupNotFoundError,
|
TypistUserGroupNotFoundError,
|
||||||
TypistUserNotFoundError,
|
TypistUserNotFoundError,
|
||||||
@ -32,6 +33,45 @@ import { Roles } from '../../common/types/role';
|
|||||||
export class TasksRepositoryService {
|
export class TasksRepositoryService {
|
||||||
constructor(private dataSource: DataSource) {}
|
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<Task> {
|
||||||
|
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(
|
async checkout(
|
||||||
audioFileId: number,
|
audioFileId: number,
|
||||||
account_id: number,
|
account_id: number,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user