oura.a 2812bc3d20 Merged PR 383: API実装(パートナー取得API)
## 概要
[Task2540: API実装(パートナー取得API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2540)

パートナー取得APIを実装しました。

## レビューポイント
・データ取得方法が適切かどうか。
以下の優先順位を意識して作成したが適切か?また、意識できていない実装になっていないか?
①QueryBuilderを使用せずに処理する
②RDB、adb2cへのアクセス回数を最小限にする

## UIの変更
なし
## 動作確認状況
ローカルで動作確認済み、UT実施済み

## 補足
プライマリ、セカンダリ管理者IDがない場合のテストはUTでは実装せず、ローカルでの動作確認で正常に動作することを確認しました。
(プライマリ、セカンダリ管理者IDを指定してアカウントを作成するテストユーティリティを作成する必要があるが、あまり汎用的には思えず作成する手間が惜しかったため)
2023-09-08 09:45:10 +00:00

371 lines
11 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { v4 as uuidv4 } from 'uuid';
import { DataSource } from 'typeorm';
import { User } from '../../repositories/users/entity/user.entity';
import { Account } from '../../repositories/accounts/entity/account.entity';
import { ADMIN_ROLES, USER_ROLES } from '../../constants';
type InitialTestDBState = {
tier1Accounts: { account: Account; users: User[] }[];
tier2Accounts: { account: Account; users: User[] }[];
tier3Accounts: { account: Account; users: User[] }[];
tier4Accounts: { account: Account; users: User[] }[];
tier5Accounts: { account: Account; users: User[] }[];
};
// 上書きされたら困る項目を除外したAccount型
type OverrideAccount = Omit<
Account,
'id' | 'primary_admin_user_id' | 'secondary_admin_user_id' | 'user'
>;
// 上書きされたら困る項目を除外したUser型
type OverrideUser = Omit<
User,
'id' | 'account' | 'license' | 'userGroupMembers'
>;
type AccountDefault = { [K in keyof OverrideAccount]?: OverrideAccount[K] };
type UserDefault = { [K in keyof OverrideUser]?: OverrideUser[K] };
/**
* テスト ユーティリティ: 1~4階層のアカウントとその管理者ユーザーを作成します
* @param dataSource データソース
* @returns 作成されたデータセット
*/
export const makeHierarchicalAccounts = async (
datasource: DataSource,
): Promise<InitialTestDBState> => {
const state: InitialTestDBState = {
tier1Accounts: [],
tier2Accounts: [],
tier3Accounts: [],
tier4Accounts: [],
tier5Accounts: [],
};
// 第1階層を作成
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 1,
company_name: 'OMDS',
});
state.tier1Accounts.push({
account: account,
users: [admin],
});
}
// 第2階層を作成
{
const { account: tier1 } = state.tier1Accounts.slice().shift();
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 2,
parent_account_id: tier1.id,
company_name: 'OMDS_US',
});
state.tier2Accounts.push({
account: account,
users: [admin],
});
}
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 2,
parent_account_id: tier1.id,
company_name: 'OMDS_EU',
});
state.tier2Accounts.push({
account: account,
users: [admin],
});
}
}
// 第3階層を作成
{
for (const v of state.tier2Accounts) {
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 3,
parent_account_id: v.account.id,
company_name: `Agency_${v.account.id}_01`,
});
state.tier3Accounts.push({
account: account,
users: [admin],
});
}
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 3,
parent_account_id: v.account.id,
company_name: `Agency_${v.account.id}_02`,
});
state.tier3Accounts.push({
account: account,
users: [admin],
});
}
}
// 第4階層を作成
for (const v of state.tier3Accounts) {
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 4,
parent_account_id: v.account.id,
company_name: `Distributor_${v.account.id}_01`,
});
state.tier4Accounts.push({
account: account,
users: [admin],
});
}
{
const { account, admin } = await makeTestAccount(datasource, {
tier: 4,
parent_account_id: v.account.id,
company_name: `Distributor_${v.account.id}_02`,
});
state.tier4Accounts.push({
account: account,
users: [admin],
});
}
}
}
return state;
};
/**
* テスト ユーティリティ: 指定したプロパティを上書きしたアカウントとその管理者ユーザーを作成する
* @param dataSource データソース
* @param defaultUserValue Account型と同等かつoptionalなプロパティを持つ上書き箇所指定用オブジェクト
* @param defaultAdminUserValue User型と同等かつoptionalなプロパティを持つ上書き箇所指定用オブジェクト(account_id等の所属関係が破壊される上書きは無視する)
* @returns 作成したアカウント
*/
export const makeTestAccount = async (
datasource: DataSource,
defaultAccountValue?: AccountDefault,
defaultAdminUserValue?: UserDefault,
isPrimaryAdminNotExist?: boolean,
isSecondaryAdminNotExist?: boolean,
): Promise<{ account: Account; admin: User }> => {
let accountId: number;
let userId: number;
{
const d = defaultAccountValue;
const { identifiers } = await datasource.getRepository(Account).insert({
tier: d?.tier ?? 1,
parent_account_id: d?.parent_account_id ?? undefined,
country: d?.country ?? 'US',
delegation_permission: d?.delegation_permission ?? false,
locked: d?.locked ?? false,
company_name: d?.company_name ?? 'test inc.',
verified: d?.verified ?? true,
deleted_at: d?.deleted_at ?? '',
created_by: d?.created_by ?? 'test_runner',
created_at: d?.created_at ?? new Date(),
updated_by: d?.updated_by ?? 'updater',
updated_at: d?.updated_at ?? new Date(),
});
const result = identifiers.pop() as Account;
accountId = result.id;
}
{
const d = defaultAdminUserValue;
const { identifiers } = await datasource.getRepository(User).insert({
external_id: d?.external_id ?? uuidv4(),
account_id: accountId,
role: d?.role ?? 'admin none',
author_id: d?.author_id ?? undefined,
accepted_terms_version: d?.accepted_terms_version ?? '1.0',
email_verified: d?.email_verified ?? true,
auto_renew: d?.auto_renew ?? true,
license_alert: d?.license_alert ?? true,
notification: d?.notification ?? true,
encryption: d?.encryption ?? true,
encryption_password: d?.encryption_password ?? 'password',
prompt: d?.prompt ?? true,
deleted_at: d?.deleted_at ?? '',
created_by: d?.created_by ?? 'test_runner',
created_at: d?.created_at ?? new Date(),
updated_by: d?.updated_by ?? 'updater',
updated_at: d?.updated_at ?? new Date(),
});
const result = identifiers.pop() as User;
userId = result.id;
}
// Accountの管理者を設定する
let secondaryAdminUserId = null;
if (isPrimaryAdminNotExist && !isSecondaryAdminNotExist) {
secondaryAdminUserId = userId;
}
await datasource.getRepository(Account).update(
{ id: accountId },
{
primary_admin_user_id: isPrimaryAdminNotExist ? null : userId,
secondary_admin_user_id: secondaryAdminUserId,
},
);
const account = await datasource.getRepository(Account).findOne({
where: {
id: accountId,
},
});
const admin = await datasource.getRepository(User).findOne({
where: {
id: userId,
},
});
return {
account: account,
admin: admin,
};
};
/**
* テスト ユーティリティ: 指定したプロパティを上書きした管理者ユーザーの存在しないアカウントを作成する
* @param dataSource データソース
* @param defaultUserValue Account型と同等かつoptionalなプロパティを持つ上書き箇所指定用オブジェクト
* @returns 作成したアカウント
*/
export const makeTestSimpleAccount = async (
datasource: DataSource,
defaultAccountValue?: AccountDefault,
): Promise<Account> => {
const d = defaultAccountValue;
const { identifiers } = await datasource.getRepository(Account).insert({
tier: d?.tier ?? 1,
parent_account_id: d?.parent_account_id ?? undefined,
country: d?.country ?? 'US',
delegation_permission: d?.delegation_permission ?? false,
locked: d?.locked ?? false,
company_name: d?.company_name ?? 'test inc.',
verified: d?.verified ?? true,
deleted_at: d?.deleted_at ?? '',
created_by: d?.created_by ?? 'test_runner',
created_at: d?.created_at ?? new Date(),
updated_by: d?.updated_by ?? 'updater',
updated_at: d?.updated_at ?? new Date(),
});
const result = identifiers.pop() as Account;
const account = await datasource.getRepository(Account).findOne({
where: {
id: result.id,
},
});
return account;
};
/**
* テスト ユーティリティ: 指定したプロパティを上書きしたユーザーを作成する
* @param dataSource データソース
* @param defaultUserValue User型と同等かつoptionalなプロパティを持つ上書き箇所指定用オブジェクト
* @returns 作成したユーザー
*/
export const makeTestUser = async (
datasource: DataSource,
defaultUserValue?: UserDefault,
): Promise<User> => {
const d = defaultUserValue;
const { identifiers } = await datasource.getRepository(User).insert({
account_id: d?.account_id ?? -1,
external_id: d?.external_id ?? uuidv4(),
role: d?.role ?? `${ADMIN_ROLES.STANDARD} ${USER_ROLES.NONE}`,
author_id: d?.author_id,
accepted_terms_version: d?.accepted_terms_version,
email_verified: d?.email_verified ?? true,
auto_renew: d?.auto_renew ?? true,
license_alert: d?.license_alert ?? true,
notification: d?.notification ?? true,
encryption: d?.encryption ?? true,
encryption_password: d?.encryption_password,
prompt: d?.prompt ?? true,
created_by: d?.created_by ?? 'test_runner',
created_at: d?.created_at ?? new Date(),
updated_by: d?.updated_by ?? 'updater',
updated_at: d?.updated_at ?? new Date(),
});
const result = identifiers.pop() as User;
return await datasource.getRepository(User).findOne({
where: {
id: result.id,
},
});
};
/**
* テスト ユーティリティ: 指定IDのアカウントを取得する
* @param dataSource データソース
* @param id アカウントID
* @returns 該当アカウント
*/
export const getAccount = async (dataSource: DataSource, id: number) => {
return await dataSource.getRepository(Account).findOne({
where: { id: id },
});
};
/**
* テスト ユーティリティ: すべてのアカウントを取得する
* @param dataSource データソース
* @returns 該当アカウント一覧
*/
export const getAccounts = async (
dataSource: DataSource,
): Promise<Account[]> => {
return await dataSource.getRepository(Account).find();
};
/**
* テスト ユーティリティ: 指定ExternalIdのユーザーを取得する
* @param dataSource データソース
* @param externalId 外部ID
* @returns 該当ユーザー
*/
export const getUserFromExternalId = async (
dataSource: DataSource,
externalId: string,
) => {
return await dataSource.getRepository(User).findOne({
where: { external_id: externalId },
});
};
/**
* テスト ユーティリティ: 指定Idのユーザーを取得する
* @param dataSource データソース
* @param externalId 外部ID
* @returns 該当ユーザー
*/
export const getUser = async (
datasource: DataSource,
id: number,
): Promise<User> => {
const user = await datasource.getRepository(User).findOne({
where: {
id: id,
},
});
return user;
};
/**
* テスト ユーティリティ: すべてのユーザーを取得する
* @param dataSource データソース
* @returns 該当ユーザー一覧
*/
export const getUsers = async (dataSource: DataSource): Promise<User[]> => {
return await dataSource.getRepository(User).find();
};