saito.k fe5e8b8e1c Merged PR 895: API修正(アカウント作成系)
## 概要
[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のクエリ
- 既存のクエリに修正はなし

## 動作確認状況
- ローカルで確認
- 行った修正がデグレを発生させていないことを確認できるか
  - 具体的にどのような確認をしたか
    - 既存テストが通ることを確認
    - パートナーアカウント作成のテストにメール送信内容のチェックを追加
    - ソート条件が作成・削除されていることを確認するテストを追加

## 補足
- 相談、参考資料などがあれば
2024-05-14 07:18:57 +00:00

526 lines
16 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, 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;
};