Merged PR 408: API修正(WorktypeID一覧API)

## 概要
[Task2621: API修正(WorktypeID一覧API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2621)

- Worktype一覧APIでActiveWorkTypeも取得するよう修正しました。
- API IFでプロパティがnullableになっているところをrequiredに修正しました。

## レビューポイント
- ActiveWorktypeの取得に問題はないか
- テストケースは適切か
- IFの修正は問題ないか

## UIの変更
- なし

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-09-14 09:20:04 +00:00
parent 25de994013
commit 81d17fb57e
9 changed files with 75 additions and 21 deletions

View File

@ -3094,7 +3094,7 @@
"type": "array",
"items": { "$ref": "#/components/schemas/Worktype" }
},
"acrive": {
"active": {
"type": "number",
"description": "Active WorktypeIDに設定されているWorkTypeの内部ID"
}
@ -3390,8 +3390,7 @@
},
"encryptionPassword": {
"type": "string",
"description": "ユーザーが暗号化を掛ける場合のパスワード",
"nullable": true
"description": "ユーザーが暗号化を掛ける場合のパスワード"
},
"activeWorktype": {
"type": "string",
@ -3411,7 +3410,6 @@
"authorIdList",
"workTypeList",
"isEncrypted",
"encryptionPassword",
"activeWorktype",
"audioFormat",
"prompt"

View File

@ -3372,17 +3372,21 @@ describe('getWorktypes', () => {
const service = module.get<AccountsService>(AccountsService);
const context = makeContext(admin.external_id);
await createWorktype(source, account.id, 'worktype1', 'description1');
await createWorktype(source, account.id, 'worktype1', 'description1', true);
await createWorktype(source, account.id, 'worktype2');
//作成したデータを確認
const worktypes = await getWorktypes(source, account.id);
const accounts = await getAccounts(source);
{
expect(worktypes.length).toBe(2);
expect(worktypes[0].custom_worktype_id).toBe('worktype1');
expect(worktypes[1].custom_worktype_id).toBe('worktype2');
expect(worktypes[0].description).toBe('description1');
expect(worktypes[1].description).toBeNull();
expect(accounts.length).toBe(1);
expect(accounts[0].active_worktype_id).toBe(worktypes[0].id);
}
const resWorktypes = await service.getWorktypes(context, admin.external_id);
@ -3394,6 +3398,8 @@ describe('getWorktypes', () => {
expect(resWorktypes.worktypes[1].worktypeId).toBe('worktype2');
expect(resWorktypes.worktypes[0].description).toBe('description1');
expect(resWorktypes.worktypes[1].description).toBe(undefined);
expect(resWorktypes.active).toBe(worktypes[0].id);
}
});

View File

@ -1169,8 +1169,9 @@ export class AccountsService {
const { account_id: accountId } =
await this.usersRepository.findUserByExternalId(externalId);
// ワークタイプ一覧を取得する
const worktypes = await this.worktypesRepository.getWorktypes(accountId);
// ワークタイプ一覧とActiveWorktypeIDを取得する
const { worktypes, active_worktype_id } =
await this.worktypesRepository.getWorktypes(accountId);
return {
worktypes: worktypes.map((x) => ({
@ -1178,9 +1179,24 @@ export class AccountsService {
worktypeId: x.custom_worktype_id,
description: x.description ?? undefined,
})),
active: active_worktype_id,
};
} catch (e) {
this.logger.error(e);
this.logger.error(`error=${e}`);
if (e instanceof Error) {
switch (e.constructor) {
case AccountNotFoundError:
throw new HttpException(
makeErrorResponse('E010501'),
HttpStatus.BAD_REQUEST,
);
default:
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,

View File

@ -9,6 +9,7 @@ import { UserGroupMember } from '../../../repositories/user_groups/entity/user_g
import { Worktype } from '../../../repositories/worktypes/entity/worktype.entity';
import { OptionItem } from '../../../repositories/worktypes/entity/option_item.entity';
import { OPTION_ITEM_VALUE_TYPE } from '../../../constants';
import { Account } from '../../../repositories/accounts/entity/account.entity';
/**
* ユーティリティ: すべてのソート条件を取得する
@ -127,6 +128,7 @@ export const createWorktype = async (
accountId: number,
worktypeId: string,
description?: string,
isActive?: boolean,
): Promise<Worktype> => {
const { identifiers } = await datasource.getRepository(Worktype).insert({
account_id: accountId,
@ -139,6 +141,16 @@ export const createWorktype = async (
updated_at: new Date(),
});
const worktype = identifiers.pop() as Worktype;
if (isActive) {
await datasource.getRepository(Account).update(
{ id: accountId },
{
active_worktype_id: worktype.id,
},
);
}
return worktype;
};

View File

@ -358,7 +358,7 @@ export class GetWorktypesResponse {
required: false,
description: 'Active WorktypeIDに設定されているWorkTypeの内部ID',
})
acrive?: number | undefined;
active?: number | undefined;
}
export class CreateWorktypesRequest {

View File

@ -330,7 +330,7 @@ const defaultTasksRepositoryMockValue: {
audio_file_id: 1,
status: 'Uploaded',
priority: '00',
created_at: new Date('2023-01-01T01:01:01.000'),
created_at: new Date('2023-01-01T01:01:01.000Z'),
option_items: [
{
id: 1,
@ -401,10 +401,10 @@ const defaultTasksRepositoryMockValue: {
file_name: 'test.zip',
author_id: 'AUTHOR',
work_type_id: 'WorkType',
started_at: new Date('2023-01-01T01:01:01.000'),
started_at: new Date('2023-01-01T01:01:01.000Z'),
duration: '123000',
finished_at: new Date('2023-01-01T01:01:01.000'),
uploaded_at: new Date('2023-01-01T01:01:01.000'),
finished_at: new Date('2023-01-01T01:01:01.000Z'),
uploaded_at: new Date('2023-01-01T01:01:01.000Z'),
file_size: 123000,
priority: '00',
audio_format: 'DS',

View File

@ -159,7 +159,7 @@ export class GetRelationsResponse {
isEncrypted: boolean;
@ApiProperty({
description: 'ユーザーが暗号化を掛ける場合のパスワード',
nullable: true,
required: false,
})
encryptionPassword?: string | undefined;
@ApiProperty({

View File

@ -40,6 +40,9 @@ export class Account {
@Column({ nullable: true })
secondary_admin_user_id?: number;
@Column({ nullable: true })
active_worktype_id?: number;
@Column({ nullable: true })
deleted_at?: Date;

View File

@ -13,22 +13,41 @@ import {
} from './errors/types';
import { OptionItem } from './entity/option_item.entity';
import { PostWorktypeOptionItem } from '../../features/accounts/types/types';
import { AccountNotFoundError } from '../accounts/errors/types';
import { Account } from '../accounts/entity/account.entity';
@Injectable()
export class WorktypesRepositoryService {
constructor(private dataSource: DataSource) {}
/**
*
* @param accountId
* @returns worktypes
* ActiveWorktypeIDを取得する
* @param externalId
* @returns worktypes and active worktype id
*/
async getWorktypes(accountId: number): Promise<Worktype[]> {
async getWorktypes(accountId: number): Promise<{
worktypes: Worktype[];
active_worktype_id?: number | undefined;
}> {
return await this.dataSource.transaction(async (entityManager) => {
const repo = entityManager.getRepository(Worktype);
const WorktypeRepo = entityManager.getRepository(Worktype);
const accountRepo = entityManager.getRepository(Account);
const worktypes = await repo.find({ where: { account_id: accountId } });
return worktypes;
const account = await accountRepo.findOne({ where: { id: accountId } });
// 運用上アカウントがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
if (!account) {
throw new AccountNotFoundError();
}
const worktypes = await WorktypeRepo.find({
where: { account_id: account.id },
});
return {
worktypes,
active_worktype_id: account.active_worktype_id ?? undefined,
};
});
}
/**