## 概要 [Task4043: API修正(アカウント作成系)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4043) - アカウント作成時にJobNumberの初期値を設定するように修正 - パートナーアカウント作成時にJobNumberの初期値を設定するように修正 - リカバリ処理にJobNumberのレコード削除を追加 - テスト修正 ## レビューポイント - JobNumber作成処理の追加する箇所に問題はないか - テストケースに不足はないか ## クエリの変更 - Repositoryを変更し、クエリが変更された場合は変更内容を確認する - Before/Afterのクエリ - 既存のクエリに修正はなし ## 動作確認状況 - ローカルで確認 - 行った修正がデグレを発生させていないことを確認できるか - 具体的にどのような確認をしたか - 既存テストが通ることを確認 - パートナーアカウント作成のテストにメール送信内容のチェックを追加 - ソート条件が作成・削除されていることを確認するテストを追加 ## 補足 - 相談、参考資料などがあれば
526 lines
16 KiB
TypeScript
526 lines
16 KiB
TypeScript
import { v4 as uuidv4 } from 'uuid';
|
||
import { DataSource } from 'typeorm';
|
||
import { User, UserArchive } from '../../repositories/users/entity/user.entity';
|
||
import { Account } from '../../repositories/accounts/entity/account.entity';
|
||
import {
|
||
ADMIN_ROLES,
|
||
FILE_RETENTION_DAYS_DEFAULT,
|
||
USER_ROLES,
|
||
} from '../../constants';
|
||
import { License } from '../../repositories/licenses/entity/license.entity';
|
||
import { AccountArchive } from '../../repositories/accounts/entity/account_archive.entity';
|
||
import { Task } from '../../repositories/tasks/entity/task.entity';
|
||
import { JobNumber } from '../../repositories/job_number/entity/job_number.entity';
|
||
import { SortCriteria } from '../../repositories/sort_criteria/entity/sort_criteria.entity';
|
||
|
||
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 tier1 = state.tier1Accounts.slice().shift();
|
||
{
|
||
const { account, admin } = await makeTestAccount(datasource, {
|
||
tier: 2,
|
||
parent_account_id: tier1?.account.id,
|
||
company_name: 'OMDS_US',
|
||
});
|
||
state.tier2Accounts.push({
|
||
account: account,
|
||
users: [admin],
|
||
});
|
||
}
|
||
{
|
||
const { account, admin } = await makeTestAccount(datasource, {
|
||
tier: 2,
|
||
parent_account_id: tier1?.account.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,
|
||
auto_file_delete: d?.auto_file_delete ?? false,
|
||
file_retention_days:
|
||
d?.file_retention_days ?? FILE_RETENTION_DAYS_DEFAULT,
|
||
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_eula_version: d?.accepted_eula_version ?? '1.0',
|
||
accepted_privacy_notice_version:
|
||
d?.accepted_privacy_notice_version ?? '1.0',
|
||
accepted_dpa_version: d?.accepted_dpa_version ?? '1.0',
|
||
email_verified: d?.email_verified ?? true,
|
||
auto_renew: d?.auto_renew ?? 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: number | null = 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,
|
||
},
|
||
});
|
||
if (!account || !admin) {
|
||
throw new Error('Unexpected null');
|
||
}
|
||
// sort_criteriaテーブルにデータを追加
|
||
await createSortCriteria(datasource, userId, 'JOB_NUMBER', 'ASC');
|
||
|
||
// job_numberテーブルにデータを追加
|
||
await createJobNumber(datasource, accountId, '00000000');
|
||
|
||
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,
|
||
auto_file_delete: d?.auto_file_delete ?? false,
|
||
file_retention_days: d?.file_retention_days ?? FILE_RETENTION_DAYS_DEFAULT,
|
||
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,
|
||
},
|
||
});
|
||
if (!account) {
|
||
throw new Error('Unexpected null');
|
||
}
|
||
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_eula_version: d?.accepted_eula_version ?? '1.0',
|
||
accepted_dpa_version: d?.accepted_dpa_version ?? '1.0',
|
||
email_verified: d?.email_verified ?? true,
|
||
auto_renew: d?.auto_renew ?? 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;
|
||
|
||
const user = await datasource.getRepository(User).findOne({
|
||
where: {
|
||
id: result.id,
|
||
},
|
||
});
|
||
if (!user) {
|
||
throw new Error('Unexpected null');
|
||
}
|
||
// sort_criteriaテーブルにデータを追加
|
||
await createSortCriteria(datasource, user.id, 'FILE_LENGTH', 'ASC');
|
||
return user;
|
||
};
|
||
|
||
/**
|
||
* テスト ユーティリティ: 指定IDのアカウントを取得する
|
||
* @param dataSource データソース
|
||
* @param id アカウントID
|
||
* @returns 該当アカウント
|
||
*/
|
||
export const getAccount = async (
|
||
dataSource: DataSource,
|
||
id: number,
|
||
): Promise<Account | null> => {
|
||
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 | null> => {
|
||
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();
|
||
};
|
||
|
||
/**
|
||
* テスト ユーティリティ: ユーザー退避テーブルの内容を取得する
|
||
* @param dataSource データソース
|
||
* @returns ユーザー退避テーブルの内容
|
||
*/
|
||
export const getAccountArchive = async (
|
||
dataSource: DataSource,
|
||
): Promise<AccountArchive[]> => {
|
||
return await dataSource.getRepository(AccountArchive).find();
|
||
};
|
||
|
||
export const getUserArchive = async (
|
||
dataSource: DataSource,
|
||
): Promise<UserArchive[]> => {
|
||
return await dataSource.getRepository(UserArchive).find();
|
||
};
|
||
export const getLicenses = async (
|
||
datasource: DataSource,
|
||
account_id: number,
|
||
): Promise<License[]> => {
|
||
const licenses = await datasource.getRepository(License).find({
|
||
where: {
|
||
account_id: account_id,
|
||
},
|
||
});
|
||
return licenses;
|
||
};
|
||
|
||
export const getTasks = async (
|
||
datasource: DataSource,
|
||
account_id: number,
|
||
): Promise<Task[]> => {
|
||
const tasks = await datasource.getRepository(Task).find({
|
||
where: { account_id: account_id },
|
||
});
|
||
return tasks;
|
||
};
|
||
|
||
// job_numberテーブルにレコードを作成する
|
||
export const createJobNumber = async (
|
||
datasource: DataSource,
|
||
accountId: number,
|
||
jobNumber: string,
|
||
): Promise<void> => {
|
||
await datasource.getRepository(JobNumber).insert({
|
||
account_id: accountId,
|
||
job_number: jobNumber,
|
||
});
|
||
};
|
||
|
||
// job_numberテーブルのレコードを更新する
|
||
export const updateJobNumber = async (
|
||
datasource: DataSource,
|
||
accountId: number,
|
||
jobNumber: string,
|
||
): Promise<void> => {
|
||
await datasource.getRepository(JobNumber).update(
|
||
{ account_id: accountId },
|
||
{
|
||
job_number: jobNumber,
|
||
},
|
||
);
|
||
};
|
||
|
||
// job_numberを取得する
|
||
export const getJobNumber = async (
|
||
datasource: DataSource,
|
||
account_id: number,
|
||
): Promise<JobNumber | null> => {
|
||
const jobNumber = await datasource.getRepository(JobNumber).findOne({
|
||
where: {
|
||
account_id: account_id,
|
||
},
|
||
});
|
||
return jobNumber;
|
||
};
|
||
|
||
// sort_criteriaを作成する
|
||
export const createSortCriteria = async (
|
||
datasource: DataSource,
|
||
userId: number,
|
||
parameter: string,
|
||
direction: string,
|
||
): Promise<void> => {
|
||
await datasource.getRepository(SortCriteria).insert({
|
||
user_id: userId,
|
||
parameter: parameter,
|
||
direction: direction,
|
||
});
|
||
};
|
||
|
||
// 指定したユーザーのsort_criteriaを更新する
|
||
export const updateSortCriteria = async (
|
||
datasource: DataSource,
|
||
userId: number,
|
||
parameter: string,
|
||
direction: string,
|
||
): Promise<void> => {
|
||
await datasource.getRepository(SortCriteria).update(
|
||
{ user_id: userId },
|
||
{
|
||
parameter: parameter,
|
||
direction: direction,
|
||
},
|
||
);
|
||
};
|
||
|
||
// 指定したユーザーのsort_criteriaを取得する
|
||
export const getSortCriteria = async (
|
||
datasource: DataSource,
|
||
userId: number,
|
||
): Promise<SortCriteria | null> => {
|
||
const sortCriteria = await datasource.getRepository(SortCriteria).findOne({
|
||
where: {
|
||
user_id: userId,
|
||
},
|
||
});
|
||
return sortCriteria;
|
||
};
|