## 概要 [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を指定してアカウントを作成するテストユーティリティを作成する必要があるが、あまり汎用的には思えず作成する手間が惜しかったため)
371 lines
11 KiB
TypeScript
371 lines
11 KiB
TypeScript
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();
|
||
};
|