Merged PR 224: タスク中断API実装
## 概要 [Task2119: タスク中断API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2119) - タスク中断APIの処理を実装 - テスト実装 - チェックアウト処理のエラーチェックを修正 - エラーが発生したときに何が原因なのかログに出力するように修正 ## レビューポイント - チェックインと同様の処理部分を切り出さずにそのまま実装したが、スマートに切り出せる方法はありそうか。 - チェックインとサスペンドの取得処理だけ切り出してもあまりうれしくない(この2つ以外のところで使えなさそう) - キャンセルでは使えるかもだけど - チェックアウトやその他のメソッドのタスク取得とまとめようとすると、チェック内容や検索条件に差異がありきれいに切り出すことができなさそう。 - まとめようとすると、引数が膨大でチェック項目も複雑になる ## UIの変更 - Before/Afterのスクショなど - スクショ置き場 ## 動作確認状況 - ローカルで確認 ## 補足 - コンフリクトが発生しているが、現在のdevelopを取り込むとエラーになるので解消し次第、取り込んで競合解決します - チェックインAPIの実装も入っていますが、そこは別のPRでレビューを行っているので対象外となります
This commit is contained in:
parent
7be4da29bb
commit
e4ba5229df
@ -4,3 +4,11 @@ import { TASK_STATUS } from '../../../constants';
|
|||||||
* Token.roleに配置されうる文字列リテラル型
|
* Token.roleに配置されうる文字列リテラル型
|
||||||
*/
|
*/
|
||||||
export type TaskStatus = (typeof TASK_STATUS)[keyof typeof TASK_STATUS];
|
export type TaskStatus = (typeof TASK_STATUS)[keyof typeof TASK_STATUS];
|
||||||
|
|
||||||
|
export const isTaskStatus = (arg: string): arg is TaskStatus => {
|
||||||
|
const param = arg as TaskStatus;
|
||||||
|
if (Object.values(TASK_STATUS).includes(param)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|||||||
@ -320,13 +320,24 @@ export class TasksController {
|
|||||||
'指定した文字起こしタスクを一時中断します(ステータスをPendingにします)',
|
'指定した文字起こしタスクを一時中断します(ステータスをPendingにします)',
|
||||||
})
|
})
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
|
@UseGuards(AuthGuard)
|
||||||
|
@UseGuards(
|
||||||
|
RoleGuard.requireds({
|
||||||
|
roles: [USER_ROLES.TYPIST],
|
||||||
|
}),
|
||||||
|
)
|
||||||
async suspend(
|
async suspend(
|
||||||
@Headers() headers,
|
@Req() req: Request,
|
||||||
@Param() params: ChangeStatusRequest,
|
@Param() params: ChangeStatusRequest,
|
||||||
): Promise<ChangeStatusResponse> {
|
): Promise<ChangeStatusResponse> {
|
||||||
const { audioFileId } = params;
|
const { audioFileId } = params;
|
||||||
console.log(audioFileId);
|
// AuthGuardでチェック済みなのでここでのアクセストークンチェックはしない
|
||||||
|
const accessToken = retrieveAuthorizationToken(req);
|
||||||
|
const { userId } = jwt.decode(accessToken, {
|
||||||
|
json: true,
|
||||||
|
}) as AccessToken;
|
||||||
|
|
||||||
|
this.taskService.suspend(audioFileId, userId);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1598,3 +1598,150 @@ describe('checkin', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('suspend', () => {
|
||||||
|
let source: DataSource = null;
|
||||||
|
beforeEach(async () => {
|
||||||
|
source = new DataSource({
|
||||||
|
type: 'sqlite',
|
||||||
|
database: ':memory:',
|
||||||
|
logging: false,
|
||||||
|
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||||
|
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||||
|
});
|
||||||
|
return source.initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await source.destroy();
|
||||||
|
source = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('API実行者が文字起こし実行中のタスクである場合、タスクを中断できる', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const { accountId } = await createAccount(source);
|
||||||
|
const { userId: typistUserId } = await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'typist-user-external-id',
|
||||||
|
'typist',
|
||||||
|
);
|
||||||
|
const { userId: authorUserId } = await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'author-user-external-id',
|
||||||
|
'author',
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
);
|
||||||
|
const { taskId } = await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
'',
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'InProgress',
|
||||||
|
typistUserId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
|
||||||
|
await service.suspend(1, 'typist-user-external-id');
|
||||||
|
const { status } = await getTask(source, taskId);
|
||||||
|
|
||||||
|
expect(status).toEqual('Pending');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('タスクのステータスがInprogressでない時、タスクを中断できない', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const { accountId } = await createAccount(source);
|
||||||
|
const { userId: typistUserId } = await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'typist-user-external-id',
|
||||||
|
'typist',
|
||||||
|
);
|
||||||
|
const { userId: authorUserId } = await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'author-user-external-id',
|
||||||
|
'author',
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
);
|
||||||
|
const { taskId } = await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
'',
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'Uploaded',
|
||||||
|
typistUserId,
|
||||||
|
);
|
||||||
|
await createCheckoutPermissions(source, taskId, typistUserId);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
await expect(service.suspend(1, 'typist-user-external-id')).rejects.toEqual(
|
||||||
|
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('API実行者が文字起こし実行中のタスクでない場合、タスクを中断できない', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const { accountId } = await createAccount(source);
|
||||||
|
await createUser(source, accountId, 'typist-user-external-id', 'typist');
|
||||||
|
const { userId: anotherTypistUserId } = await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'another-typist-user-external-id',
|
||||||
|
'typist',
|
||||||
|
);
|
||||||
|
const { userId: authorUserId } = await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'author-user-external-id',
|
||||||
|
'author',
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
);
|
||||||
|
const { taskId } = await createTask(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
authorUserId,
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
'',
|
||||||
|
'01',
|
||||||
|
'00000001',
|
||||||
|
'InProgress',
|
||||||
|
// API実行者のタスクではないため、typist_user_idは設定しない
|
||||||
|
);
|
||||||
|
await createCheckoutPermissions(source, taskId, anotherTypistUserId);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
|
||||||
|
await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual(
|
||||||
|
new HttpException(makeErrorResponse('E010601'), HttpStatus.BAD_REQUEST),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('タスクがない時、タスクを中断できない', async () => {
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
const { accountId } = await createAccount(source);
|
||||||
|
await createUser(source, accountId, 'typist-user-external-id', 'typist');
|
||||||
|
|
||||||
|
await createUser(
|
||||||
|
source,
|
||||||
|
accountId,
|
||||||
|
'author-user-external-id',
|
||||||
|
'author',
|
||||||
|
'MY_AUTHOR_ID',
|
||||||
|
);
|
||||||
|
|
||||||
|
const service = module.get<TasksService>(TasksService);
|
||||||
|
|
||||||
|
await expect(service.checkin(1, 'typist-user-external-id')).rejects.toEqual(
|
||||||
|
new HttpException(makeErrorResponse('E010603'), HttpStatus.BAD_REQUEST),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
import { AdB2cUser } from '../../gateways/adb2c/types/types';
|
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 {
|
||||||
|
AccountNotMatchError,
|
||||||
CheckoutPermissionNotFoundError,
|
CheckoutPermissionNotFoundError,
|
||||||
StatusNotMatchError,
|
StatusNotMatchError,
|
||||||
TaskAuthorIdNotMatchError,
|
TaskAuthorIdNotMatchError,
|
||||||
@ -163,7 +164,11 @@ export class TasksService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (roles.includes(USER_ROLES.TYPIST)) {
|
if (roles.includes(USER_ROLES.TYPIST)) {
|
||||||
return await this.taskRepository.checkout(audioFileId, account_id, id);
|
return await this.taskRepository.checkout(audioFileId, account_id, id, [
|
||||||
|
TASK_STATUS.UPLOADED,
|
||||||
|
TASK_STATUS.PENDING,
|
||||||
|
TASK_STATUS.IN_PROGRESS,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidRoleError(`invalid roles: ${roles.join(',')}`);
|
throw new InvalidRoleError(`invalid roles: ${roles.join(',')}`);
|
||||||
@ -179,6 +184,8 @@ export class TasksService {
|
|||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
);
|
);
|
||||||
case TasksNotFoundError:
|
case TasksNotFoundError:
|
||||||
|
case AccountNotMatchError:
|
||||||
|
case StatusNotMatchError:
|
||||||
throw new HttpException(
|
throw new HttpException(
|
||||||
makeErrorResponse('E010601'),
|
makeErrorResponse('E010601'),
|
||||||
HttpStatus.BAD_REQUEST,
|
HttpStatus.BAD_REQUEST,
|
||||||
@ -243,6 +250,52 @@ export class TasksService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定した音声ファイルに紐づくタスクをsuspendする
|
||||||
|
* @param audioFileId
|
||||||
|
* @param externalId
|
||||||
|
* @returns suspend
|
||||||
|
*/
|
||||||
|
async suspend(audioFileId: number, externalId: string): Promise<void> {
|
||||||
|
try {
|
||||||
|
const { id } = await this.usersRepository.findUserByExternalId(
|
||||||
|
externalId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return await this.taskRepository.suspend(
|
||||||
|
audioFileId,
|
||||||
|
id,
|
||||||
|
TASK_STATUS.IN_PROGRESS,
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`error=${e}`);
|
||||||
|
if (e instanceof Error) {
|
||||||
|
switch (e.constructor) {
|
||||||
|
case TasksNotFoundError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E010603'),
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
case StatusNotMatchError:
|
||||||
|
case TypistUserNotMatchError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E010601'),
|
||||||
|
HttpStatus.BAD_REQUEST,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E009999'),
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E009999'),
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private async getB2cUsers(
|
private async getB2cUsers(
|
||||||
tasks: TaskEntity[],
|
tasks: TaskEntity[],
|
||||||
permissions: CheckoutPermission[],
|
permissions: CheckoutPermission[],
|
||||||
|
|||||||
@ -174,7 +174,10 @@ export class AccountsRepositoryService {
|
|||||||
id: number,
|
id: number,
|
||||||
currentDate: Date,
|
currentDate: Date,
|
||||||
expiringSoonDate: Date,
|
expiringSoonDate: Date,
|
||||||
): Promise<{ licenseSummary: LicenseSummaryInfo; isStorageAvailable: boolean }> {
|
): Promise<{
|
||||||
|
licenseSummary: LicenseSummaryInfo;
|
||||||
|
isStorageAvailable: boolean;
|
||||||
|
}> {
|
||||||
return await this.dataSource.transaction(async (entityManager) => {
|
return await this.dataSource.transaction(async (entityManager) => {
|
||||||
const license = entityManager.getRepository(License);
|
const license = entityManager.getRepository(License);
|
||||||
const licenseOrder = entityManager.getRepository(LicenseOrder);
|
const licenseOrder = entityManager.getRepository(LicenseOrder);
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import {
|
|||||||
TypistUserNotMatchError,
|
TypistUserNotMatchError,
|
||||||
} from './errors/types';
|
} from './errors/types';
|
||||||
import { Roles } from '../../common/types/role';
|
import { Roles } from '../../common/types/role';
|
||||||
import { TaskStatus } from '../../common/types/taskStatus';
|
import { TaskStatus, isTaskStatus } from '../../common/types/taskStatus';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TasksRepositoryService {
|
export class TasksRepositoryService {
|
||||||
@ -88,13 +88,13 @@ export class TasksRepositoryService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 音声ファイルIDに紐づいたTaskを取得する
|
* 音声ファイルIDに紐づいたTaskを取得する
|
||||||
* @param audioFileId
|
* @param audio_file_id
|
||||||
* @param account_id
|
* @param account_id
|
||||||
* @param author_id
|
* @param author_id
|
||||||
* @returns task from author id
|
* @returns task from author id
|
||||||
*/
|
*/
|
||||||
async getTaskFromAudioFileId(
|
async getTaskFromAudioFileId(
|
||||||
audioFileId: number,
|
audio_file_id: number,
|
||||||
account_id: number,
|
account_id: number,
|
||||||
author_id: string,
|
author_id: string,
|
||||||
): Promise<Task> {
|
): Promise<Task> {
|
||||||
@ -106,18 +106,23 @@ export class TasksRepositoryService {
|
|||||||
file: true,
|
file: true,
|
||||||
},
|
},
|
||||||
where: {
|
where: {
|
||||||
audio_file_id: audioFileId,
|
audio_file_id: audio_file_id,
|
||||||
account_id: account_id,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!task) {
|
if (!task) {
|
||||||
throw new TasksNotFoundError(
|
throw new TasksNotFoundError(
|
||||||
`task not found. audio_file_id:${audioFileId}`,
|
`task not found. audio_file_id:${audio_file_id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// アカウントチェック
|
||||||
|
if (task.account_id !== account_id) {
|
||||||
|
throw new AccountNotMatchError(
|
||||||
|
`task account_id not match. audio_file_id:${audio_file_id}, account_id(Task):${task.account_id}, account_id:${account_id}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (task.file?.author_id !== author_id) {
|
if (task.file?.author_id !== author_id) {
|
||||||
throw new TaskAuthorIdNotMatchError(
|
throw new TaskAuthorIdNotMatchError(
|
||||||
`task authorId not match. audio_file_id:${audioFileId}, author_id:${author_id}, author_id(Task):${task.file?.author_id}`,
|
`task authorId not match. audio_file_id:${audio_file_id}, author_id:${author_id}, author_id(Task):${task.file?.author_id}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,33 +131,44 @@ export class TasksRepositoryService {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 音声ファイルIDに紐づいたTaskをCheckoutする
|
* 音声ファイルIDに紐づいたTaskをCheckoutする
|
||||||
* @param audioFileId
|
* @param audio_file_id
|
||||||
* @param account_id
|
* @param account_id
|
||||||
* @param user_id
|
* @param user_id
|
||||||
|
* @param permittedSourceStatus
|
||||||
* @returns checkout
|
* @returns checkout
|
||||||
*/
|
*/
|
||||||
async checkout(
|
async checkout(
|
||||||
audioFileId: number,
|
audio_file_id: number,
|
||||||
account_id: number,
|
account_id: number,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
|
permittedSourceStatus: TaskStatus[],
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
await this.dataSource.transaction(async (entityManager) => {
|
await this.dataSource.transaction(async (entityManager) => {
|
||||||
const taskRepo = entityManager.getRepository(Task);
|
const taskRepo = entityManager.getRepository(Task);
|
||||||
// 指定した音声ファイルIDに紐づくTaskの中でStatusが[Uploaded,Inprogress,Pending]であるものを取得
|
// 指定した音声ファイルIDに紐づくTaskの中でStatusが[Uploaded,Inprogress,Pending]であるものを取得
|
||||||
const task = await taskRepo.findOne({
|
const task = await taskRepo.findOne({
|
||||||
where: {
|
where: {
|
||||||
audio_file_id: audioFileId,
|
audio_file_id: audio_file_id,
|
||||||
account_id: account_id,
|
|
||||||
status: In([
|
|
||||||
TASK_STATUS.UPLOADED,
|
|
||||||
TASK_STATUS.IN_PROGRESS,
|
|
||||||
TASK_STATUS.PENDING,
|
|
||||||
]),
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!task) {
|
if (!task) {
|
||||||
throw new TasksNotFoundError(
|
throw new TasksNotFoundError(
|
||||||
`task not found. audio_file_id:${audioFileId}`,
|
`task not found. audio_file_id:${audio_file_id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// アカウントチェック
|
||||||
|
if (task.account_id !== account_id) {
|
||||||
|
throw new AccountNotMatchError(
|
||||||
|
`task account_id not match. audio_file_id:${audio_file_id}, account_id(Task):${task.account_id}, account_id:${account_id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!isTaskStatus(task.status)) {
|
||||||
|
throw new Error('invalid task status');
|
||||||
|
}
|
||||||
|
// ステータスチェック
|
||||||
|
if (!permittedSourceStatus.includes(task.status)) {
|
||||||
|
throw new StatusNotMatchError(
|
||||||
|
`Unexpected task status. status:${task.status}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +216,7 @@ export class TasksRepositoryService {
|
|||||||
// 対象タスクの文字起こし開始日時を現在時刻に更新。割り当てユーザーを自身のユーザーIDに更新
|
// 対象タスクの文字起こし開始日時を現在時刻に更新。割り当てユーザーを自身のユーザーIDに更新
|
||||||
// タスクのステータスがUploaded以外の場合、文字起こし開始時刻は更新しない
|
// タスクのステータスがUploaded以外の場合、文字起こし開始時刻は更新しない
|
||||||
await taskRepo.update(
|
await taskRepo.update(
|
||||||
{ audio_file_id: audioFileId },
|
{ audio_file_id: audio_file_id },
|
||||||
{
|
{
|
||||||
started_at:
|
started_at:
|
||||||
task.status === TASK_STATUS.UPLOADED
|
task.status === TASK_STATUS.UPLOADED
|
||||||
@ -225,14 +241,14 @@ export class TasksRepositoryService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Params tasks repository service
|
* 音声ファイルIDで指定したタスクをcheckinする
|
||||||
* @param audioFileId チェックインするタスクの音声ファイルID
|
* @param audio_file_id チェックインするタスクの音声ファイルID
|
||||||
* @param user_id チェックインするユーザーのID
|
* @param user_id チェックインするユーザーのID
|
||||||
* @param permittedSourceStatus チェックイン可能なステータス
|
* @param permittedSourceStatus チェックイン可能なステータス
|
||||||
* @returns checkin
|
* @returns checkin
|
||||||
*/
|
*/
|
||||||
async checkin(
|
async checkin(
|
||||||
audioFileId: number,
|
audio_file_id: number,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
permittedSourceStatus: TaskStatus,
|
permittedSourceStatus: TaskStatus,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@ -240,12 +256,12 @@ export class TasksRepositoryService {
|
|||||||
const taskRepo = entityManager.getRepository(Task);
|
const taskRepo = entityManager.getRepository(Task);
|
||||||
const task = await taskRepo.findOne({
|
const task = await taskRepo.findOne({
|
||||||
where: {
|
where: {
|
||||||
audio_file_id: audioFileId,
|
audio_file_id: audio_file_id,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
if (!task) {
|
if (!task) {
|
||||||
throw new TasksNotFoundError(
|
throw new TasksNotFoundError(
|
||||||
`task not found. audio_file_id:${audioFileId}`,
|
`task not found. audio_file_id:${audio_file_id}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (task.status !== permittedSourceStatus) {
|
if (task.status !== permittedSourceStatus) {
|
||||||
@ -261,7 +277,7 @@ export class TasksRepositoryService {
|
|||||||
|
|
||||||
// 対象タスクの文字起こし終了日時を現在時刻に更新。ステータスをFinishedに更新
|
// 対象タスクの文字起こし終了日時を現在時刻に更新。ステータスをFinishedに更新
|
||||||
await taskRepo.update(
|
await taskRepo.update(
|
||||||
{ audio_file_id: audioFileId },
|
{ audio_file_id: audio_file_id },
|
||||||
{
|
{
|
||||||
finished_at: new Date().toISOString(),
|
finished_at: new Date().toISOString(),
|
||||||
status: TASK_STATUS.FINISHED,
|
status: TASK_STATUS.FINISHED,
|
||||||
@ -270,6 +286,51 @@ export class TasksRepositoryService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 音声ファイルIDで指定したタスクをsuspendする
|
||||||
|
* @param audio_file_id 文字起こし中断するタスクの音声ファイルID
|
||||||
|
* @param user_id 文字起こし中断するユーザーのID
|
||||||
|
* @param permittedSourceStatus 文字起こし中断可能なステータス
|
||||||
|
* @returns suspend
|
||||||
|
*/
|
||||||
|
async suspend(
|
||||||
|
audio_file_id: number,
|
||||||
|
user_id: number,
|
||||||
|
permittedSourceStatus: TaskStatus,
|
||||||
|
): Promise<void> {
|
||||||
|
await this.dataSource.transaction(async (entityManager) => {
|
||||||
|
const taskRepo = entityManager.getRepository(Task);
|
||||||
|
const task = await taskRepo.findOne({
|
||||||
|
where: {
|
||||||
|
audio_file_id: audio_file_id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!task) {
|
||||||
|
throw new TasksNotFoundError(
|
||||||
|
`task not found. audio_file_id:${audio_file_id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (task.status !== permittedSourceStatus) {
|
||||||
|
throw new StatusNotMatchError(
|
||||||
|
`Unexpected task status. status:${task.status}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (task.typist_user_id !== user_id) {
|
||||||
|
throw new TypistUserNotMatchError(
|
||||||
|
`TypistUser not match. typist_user_id:${task.typist_user_id}, user_id:${user_id}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 対象タスクの文字起こし終了日時を現在時刻に更新。ステータスをFinishedに更新
|
||||||
|
await taskRepo.update(
|
||||||
|
{ audio_file_id: audio_file_id },
|
||||||
|
{
|
||||||
|
status: TASK_STATUS.PENDING,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指定したアカウントIDに紐づくTask関連情報の一覧を取得します
|
* 指定したアカウントIDに紐づくTask関連情報の一覧を取得します
|
||||||
* @param account_id
|
* @param account_id
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user