## 概要 [Task3580: 本番環境に対する移行データの投入後の修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3580) - デモライセンスの判定を日時から日付だけ見るように修正しました。 - 9999/12/31で始まるかを見ています。 - メールアドレス重複のチェックは大文字小文字を区別せずに実行するようにしています。 ## レビューポイント - 対応箇所は適切でしょうか? - 対応として先頭文字列を見ていますが適切でしょうか? ## UIの変更 - なし ## クエリの変更 - なし ## 動作確認状況 - 本番踏み台で変換できることを確認 - 行った修正がデグレを発生させていないことを確認できるか - ツールの変更だけなので問題なし
698 lines
26 KiB
TypeScript
698 lines
26 KiB
TypeScript
import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
|
|
import { Context } from "../../common/log";
|
|
import {
|
|
AccountsFileType,
|
|
UsersFile,
|
|
LicensesFile,
|
|
WorktypesFile,
|
|
csvInputFile,
|
|
AccountsFile,
|
|
} from "../../common/types/types";
|
|
import {
|
|
COUNTRY_LIST,
|
|
MIGRATION_TYPE,
|
|
TIERS,
|
|
WORKTYPE_MAX_COUNT,
|
|
RECORDING_MODE,
|
|
LICENSE_ALLOCATED_STATUS,
|
|
USER_ROLES,
|
|
SWITCH_FROM_TYPE,
|
|
} from "src/constants";
|
|
import {
|
|
registInputDataResponse,
|
|
removeDuplicateEmailResponse,
|
|
} from "./types/types";
|
|
import fs from "fs";
|
|
import { makeErrorResponse } from "src/common/error/makeErrorResponse";
|
|
|
|
@Injectable()
|
|
export class TransferService {
|
|
constructor() {}
|
|
private readonly logger = new Logger(TransferService.name);
|
|
|
|
/**
|
|
* Transfer Input Data
|
|
* @param OutputFilePath: string
|
|
* @param csvInputFile: csvInputFile[]
|
|
*/
|
|
async transferInputData(
|
|
context: Context,
|
|
csvInputFile: csvInputFile[],
|
|
accountIdMap: Map<string, number>
|
|
): Promise<registInputDataResponse> {
|
|
// パラメータ内容が長大なのでログには出さない
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.transferInputData.name}`
|
|
);
|
|
|
|
try {
|
|
let accountsFileTypeLines: AccountsFileType[] = [];
|
|
let usersFileLines: UsersFile[] = [];
|
|
let licensesFileLines: LicensesFile[] = [];
|
|
let worktypesFileLines: WorktypesFile[] = [];
|
|
let errorArray: string[] = [];
|
|
let userIdIndex = 0;
|
|
// authorIdとuserIdの対応関係を保持するMapを定義
|
|
const authorIdToUserIdMap: Map<string, number> = new Map();
|
|
|
|
// countryのリストを生成
|
|
const countryAccounts = csvInputFile.filter(
|
|
(item) => item.type === "Country"
|
|
);
|
|
|
|
// csvInputFileを一行読み込みする
|
|
csvInputFile.forEach((line) => {
|
|
// typeが"USER"以外の場合、アカウントデータの作成を行う
|
|
if (line.type !== MIGRATION_TYPE.USER) {
|
|
// line.countryの値を読み込みCOUNTRY_LISTのlabelからvalueに変換する
|
|
const country = COUNTRY_LIST.find(
|
|
(country) => country.label === line.country
|
|
)?.value;
|
|
// adminNameの変換(last_name + " "+ first_name)
|
|
// もしline.last_nameとline.first_nameが存在しない場合、line.admin_mailをnameにする
|
|
let adminName = line.email;
|
|
if (line.last_name && line.first_name) {
|
|
adminName = `${line.last_name} ${line.first_name}`;
|
|
// スペースが前後に入っている場合があるのでTrimする
|
|
adminName = adminName.trim();
|
|
}
|
|
// ランダムパスワードの生成(データ登録ツール側で行うのでやらない)
|
|
// common/password/password.tsのmakePasswordを使用
|
|
// const autoGeneratedPassword = makePassword();
|
|
|
|
// parentAccountIdの設定
|
|
// parent_idが存在する場合、accountIdMapを参照し、accountIdに変換する
|
|
let parentAccountId: number | null = null;
|
|
if (line.parent_id) {
|
|
parentAccountId = accountIdMap.get(line.parent_id);
|
|
}
|
|
// 万が一parent_idが入力されているのに存在しなかった場合は、エラー配列に追加する
|
|
if (parentAccountId === undefined) {
|
|
errorArray.push(
|
|
`parent_id is invalid. parent_id=${line.parent_id}`
|
|
);
|
|
}
|
|
|
|
// userIdIndexをインクリメントする
|
|
userIdIndex++;
|
|
|
|
// AccountsFile配列にPush
|
|
accountsFileTypeLines.push({
|
|
// accountIdはaccountIdMapから取得する
|
|
accountId: accountIdMap.get(line.account_id),
|
|
type: line.type,
|
|
companyName: line.company_name,
|
|
country: country,
|
|
dealerAccountId: parentAccountId,
|
|
adminName: adminName,
|
|
adminMail: line.email,
|
|
userId: userIdIndex,
|
|
role: null,
|
|
authorId: null,
|
|
});
|
|
} else {
|
|
// typeが"USER"の場合、かつcountryのアカウントIDに所属していない場合
|
|
if (
|
|
line.type == MIGRATION_TYPE.USER &&
|
|
!countryAccounts.some(
|
|
(countryAccount) => countryAccount.account_id === line.account_id
|
|
)
|
|
) {
|
|
// line.author_idが存在する場合のみユーザーデータを作成する
|
|
if (line.author_id) {
|
|
// userIdIndexをインクリメントする
|
|
userIdIndex++;
|
|
|
|
// nameの変換
|
|
// もしline.last_nameとline.first_nameが存在しない場合、line.emailをnameにする
|
|
// 存在する場合は、last_name + " " + first_name
|
|
let name = line.user_email;
|
|
if (line.last_name && line.first_name) {
|
|
name = `${line.last_name} ${line.first_name}`;
|
|
}
|
|
// UsersFileの作成
|
|
usersFileLines.push({
|
|
accountId: accountIdMap.get(line.account_id),
|
|
userId: userIdIndex,
|
|
name: name,
|
|
role: USER_ROLES.AUTHOR,
|
|
authorId: line.author_id,
|
|
email: line.user_email,
|
|
});
|
|
// authorIdとuserIdの対応関係をマッピング
|
|
authorIdToUserIdMap.set(line.author_id, userIdIndex);
|
|
}
|
|
|
|
// ライセンスのデータの作成を行う
|
|
// line.expired_dateが"9999/12/31"で始まるデータの場合はデモライセンスなので登録しない
|
|
if (!line.expired_date.startsWith("9999/12/31")) {
|
|
// authorIdが設定されてる場合、statusは"allocated"、allocated_user_idは対象のユーザID
|
|
// されていない場合、statusは"reusable"、allocated_user_idはnull
|
|
let status: string;
|
|
let allocated_user_id: number | null;
|
|
if (line.author_id) {
|
|
status = LICENSE_ALLOCATED_STATUS.ALLOCATED;
|
|
allocated_user_id =
|
|
authorIdToUserIdMap.get(line.author_id) ?? null; // authorIdに対応するuserIdを取得
|
|
} else {
|
|
status = LICENSE_ALLOCATED_STATUS.REUSABLE;
|
|
allocated_user_id = null;
|
|
}
|
|
// LicensesFileの作成
|
|
licensesFileLines.push({
|
|
expiry_date: line.expired_date,
|
|
account_id: accountIdMap.get(line.account_id),
|
|
type: SWITCH_FROM_TYPE.NONE,
|
|
status: status,
|
|
allocated_user_id: allocated_user_id,
|
|
});
|
|
}
|
|
// WorktypesFileの作成
|
|
// wt1~wt20まで読み込み、account単位で作成する
|
|
// 作成したWorktypesFileを配列にPush
|
|
for (let i = 1; i <= WORKTYPE_MAX_COUNT; i++) {
|
|
const wt = `wt${i}`;
|
|
if (line[wt]) {
|
|
// account_idで同一のcustom_worktype_idが存在しない場合は、作成する
|
|
if (
|
|
!worktypesFileLines.find(
|
|
(worktype) =>
|
|
worktype.account_id ===
|
|
accountIdMap.get(line.account_id) &&
|
|
worktype.custom_worktype_id === line[wt]
|
|
)
|
|
) {
|
|
worktypesFileLines.push({
|
|
account_id: accountIdMap.get(line.account_id),
|
|
custom_worktype_id: line[wt],
|
|
});
|
|
} else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
// エラー配列に値が存在する場合はエラーファイルを出力する
|
|
if (errorArray.length > 0) {
|
|
const errorFileJson = JSON.stringify(errorArray);
|
|
fs.writeFileSync(`error.json`, errorFileJson);
|
|
throw new HttpException(
|
|
`errorArray is invalid. errorArray=${errorArray}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
return {
|
|
accountsFileTypeLines,
|
|
usersFileLines,
|
|
licensesFileLines,
|
|
worktypesFileLines,
|
|
};
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.transferInputData.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 階層の付け替えを行う
|
|
* @param accountsFileType: AccountsFileType[]
|
|
* @returns AccountsFile[]
|
|
*/
|
|
async relocateHierarchy(
|
|
context: Context,
|
|
accountsFileType: AccountsFileType[]
|
|
): Promise<AccountsFile[]> {
|
|
// パラメータ内容が長大なのでログには出さない
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.relocateHierarchy.name}`
|
|
);
|
|
|
|
try {
|
|
const relocatedAccounts: AccountsFile[] = [];
|
|
const dealerRecords: Map<number, number> = new Map();
|
|
|
|
const countryAccounts = accountsFileType.filter(
|
|
(item) => item.type === MIGRATION_TYPE.COUNTRY
|
|
);
|
|
|
|
const notCountryAccounts = accountsFileType.filter(
|
|
(item) => item.type !== MIGRATION_TYPE.COUNTRY
|
|
);
|
|
|
|
notCountryAccounts.forEach((notCountryAccount) => {
|
|
let assignDealerAccountId = notCountryAccount.dealerAccountId;
|
|
// 親アカウントIDがcountryの場合、countryの親アカウントIDを設定する
|
|
for (const countryAccount of countryAccounts) {
|
|
if (countryAccount.accountId === notCountryAccount.dealerAccountId) {
|
|
assignDealerAccountId = countryAccount.dealerAccountId;
|
|
}
|
|
}
|
|
|
|
const assignType = this.getAccountType(notCountryAccount.type);
|
|
|
|
const newAccount: AccountsFile = {
|
|
accountId: notCountryAccount.accountId,
|
|
type: assignType,
|
|
companyName: notCountryAccount.companyName,
|
|
country: notCountryAccount.country,
|
|
dealerAccountId: assignDealerAccountId,
|
|
adminName: notCountryAccount.adminName,
|
|
adminMail: notCountryAccount.adminMail,
|
|
userId: notCountryAccount.userId,
|
|
role: notCountryAccount.role,
|
|
authorId: notCountryAccount.authorId,
|
|
};
|
|
relocatedAccounts.push(newAccount);
|
|
});
|
|
|
|
return relocatedAccounts;
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.relocateHierarchy.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
// メソッド: アカウントタイプを数値に変換するヘルパー関数
|
|
private getAccountType(type: string): number {
|
|
switch (type) {
|
|
case MIGRATION_TYPE.ADMINISTRATOR:
|
|
return TIERS.TIER1;
|
|
case MIGRATION_TYPE.BC:
|
|
return TIERS.TIER2;
|
|
case MIGRATION_TYPE.DISTRIBUTOR:
|
|
return TIERS.TIER3;
|
|
case MIGRATION_TYPE.DEALER:
|
|
return TIERS.TIER4;
|
|
case MIGRATION_TYPE.CUSTOMER:
|
|
return TIERS.TIER5;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
/**
|
|
* JSONファイルの出力
|
|
* @param outputFilePath: string
|
|
* @param accountsFile: AccountsFile[]
|
|
* @param usersFile: UsersFile[]
|
|
* @param licensesFile: LicensesFile[]
|
|
* @param worktypesFile: WorktypesFile[]
|
|
*/
|
|
async outputJsonFile(
|
|
context: Context,
|
|
outputFilePath: string,
|
|
accountsFile: AccountsFile[],
|
|
usersFile: UsersFile[],
|
|
licensesFile: LicensesFile[],
|
|
worktypesFile: WorktypesFile[]
|
|
): Promise<void> {
|
|
// パラメータ内容が長大なのでログには出さない
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.outputJsonFile.name}`
|
|
);
|
|
|
|
try {
|
|
// JSONファイルの出力を行う
|
|
// AccountsFile配列の出力
|
|
const accountsFileJson = JSON.stringify(accountsFile);
|
|
fs.writeFileSync(`${outputFilePath}accounts.json`, accountsFileJson);
|
|
// UsersFile
|
|
const usersFileJson = JSON.stringify(usersFile);
|
|
fs.writeFileSync(`${outputFilePath}users.json`, usersFileJson);
|
|
// LicensesFile
|
|
const licensesFileJson = JSON.stringify(licensesFile);
|
|
fs.writeFileSync(`${outputFilePath}licenses.json`, licensesFileJson);
|
|
// WorktypesFile
|
|
const worktypesFileJson = JSON.stringify(worktypesFile);
|
|
fs.writeFileSync(`${outputFilePath}worktypes.json`, worktypesFileJson);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.outputJsonFile.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* データのバリデーションチェック
|
|
* @param csvInputFile: csvInputFile[]
|
|
*/
|
|
async validateInputData(
|
|
context: Context,
|
|
csvInputFile: csvInputFile[]
|
|
): Promise<void> {
|
|
// パラメータ内容が長大なのでログには出さない
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.validateInputData.name}`
|
|
);
|
|
|
|
try {
|
|
// エラー配列を定義
|
|
let errorArray: string[] = [];
|
|
// アカウントに対するworktypeのMap配列を作成する
|
|
const accountWorktypeMap = new Map<string, string[]>();
|
|
// csvInputFileのバリデーションチェックを行う
|
|
csvInputFile.forEach((line, index) => {
|
|
// typeのバリデーションチェック
|
|
if (
|
|
line.type !== MIGRATION_TYPE.ADMINISTRATOR &&
|
|
line.type !== MIGRATION_TYPE.BC &&
|
|
line.type !== MIGRATION_TYPE.COUNTRY &&
|
|
line.type !== MIGRATION_TYPE.DISTRIBUTOR &&
|
|
line.type !== MIGRATION_TYPE.DEALER &&
|
|
line.type !== MIGRATION_TYPE.CUSTOMER &&
|
|
line.type !== MIGRATION_TYPE.USER
|
|
) {
|
|
throw new HttpException(
|
|
`type is invalid. index=${index} type=${line.type}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
// typeがUSER以外の場合で、countryがnullの場合エラー配列に格納する
|
|
if (line.type !== MIGRATION_TYPE.USER) {
|
|
if (!line.country) {
|
|
// countryがnullの場合エラー配列に格納する
|
|
errorArray.push(`country is null. index=${index}`);
|
|
}
|
|
}
|
|
// countryのバリデーションチェック
|
|
if (line.country) {
|
|
if (!COUNTRY_LIST.find((country) => country.label === line.country)) {
|
|
throw new HttpException(
|
|
`country is invalid. index=${index} country=${line.country}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
}
|
|
// mailのバリデーションチェック
|
|
// メールアドレスの形式が正しいかどうかのチェック
|
|
const mailRegExp =
|
|
/^[a-zA-Z0-9!#$%&'_`/=~+\-?^{|}.]+@[a-zA-Z0-9!#$%&'_`/=~+\-?^{|}.]*\.[a-zA-Z0-9!#$%&'_`/=~+\-?^{|}.]*[a-zA-Z]$/;
|
|
if (line.email) {
|
|
if (!mailRegExp.test(line.email)) {
|
|
throw new HttpException(
|
|
`email is invalid. index=${index} email=${line.email}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
}
|
|
if (line.user_email) {
|
|
if (!mailRegExp.test(line.user_email)) {
|
|
throw new HttpException(
|
|
`user_email is invalid. index=${index} user_email=${line.email}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
}
|
|
// recording_modeの値が存在する場合
|
|
if (line.recording_mode) {
|
|
// recording_modeのバリデーションチェック
|
|
if (
|
|
line.recording_mode !== RECORDING_MODE.DS2_QP &&
|
|
line.recording_mode !== RECORDING_MODE.DS2_SP &&
|
|
line.recording_mode !== RECORDING_MODE.DSS
|
|
) {
|
|
throw new HttpException(
|
|
`recording_mode is invalid. index=${index} recording_mode=${line.recording_mode}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
}
|
|
// worktypeの1アカウント20件上限チェック
|
|
for (let i = 1; i <= WORKTYPE_MAX_COUNT; i++) {
|
|
const wt = `wt${i}`;
|
|
if (line[wt]) {
|
|
if (accountWorktypeMap.has(line.account_id)) {
|
|
const worktypes = accountWorktypeMap.get(line.account_id);
|
|
// 重複している場合はPushしない
|
|
if (worktypes?.includes(line[wt])) {
|
|
continue;
|
|
} else {
|
|
worktypes?.push(line[wt]);
|
|
}
|
|
// 20件を超えたらエラー
|
|
if (worktypes?.length > WORKTYPE_MAX_COUNT) {
|
|
throw new HttpException(
|
|
`worktype is over. index=${index} account_id=${line.account_id}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
} else {
|
|
accountWorktypeMap.set(line.account_id, [line[wt]]);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
// エラー配列に値が存在する場合はエラーファイルを出力する
|
|
if (errorArray.length > 0) {
|
|
const errorFileJson = JSON.stringify(errorArray);
|
|
fs.writeFileSync(`error.json`, errorFileJson);
|
|
throw new HttpException(
|
|
`errorArray is invalid. errorArray=${errorArray}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.validateInputData.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* removeDuplicateEmail
|
|
* @param accountsFileLines: AccountsFile[]
|
|
* @param usersFileLines: UsersFile[]
|
|
* @param licensesFileLines: LicensesFile[]
|
|
* @returns registInputDataResponse
|
|
*/
|
|
async removeDuplicateEmail(
|
|
context: Context,
|
|
accountsFileLines: AccountsFile[],
|
|
usersFileLines: UsersFile[],
|
|
licensesFileLines: LicensesFile[]
|
|
): Promise<removeDuplicateEmailResponse> {
|
|
// パラメータ内容が長大なのでログには出さない
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.removeDuplicateEmail.name}`
|
|
);
|
|
|
|
try {
|
|
const newAccountsFileLines: AccountsFile[] = [];
|
|
const newUsersFileLines: UsersFile[] = [];
|
|
const newLicensesFileLines: LicensesFile[] = [...licensesFileLines]; // licensesFileLinesを新規配列にコピー
|
|
|
|
// accountsFileLinesの行ループ
|
|
accountsFileLines.forEach((account) => {
|
|
const duplicateAdminMail = newAccountsFileLines.find(
|
|
(a) => a.adminMail.toLowerCase() === account.adminMail.toLowerCase() // メールアドレスは大文字小文字を区別しない
|
|
);
|
|
|
|
if (duplicateAdminMail) {
|
|
// 重複がある場合はどちらが取込対象か判断できないのでファイルを出力し、エラーにする
|
|
const errorFileJson = JSON.stringify(account);
|
|
fs.writeFileSync(`duplicate_error.json`, errorFileJson);
|
|
throw new HttpException(
|
|
`adminMail is duplicate. adminMail=${account.adminMail}`,
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
} else {
|
|
// 重複がない場合
|
|
newAccountsFileLines.push(account);
|
|
}
|
|
});
|
|
|
|
// usersFileLinesの行ループ
|
|
usersFileLines.forEach((user) => {
|
|
const duplicateUserEmail = newUsersFileLines.find(
|
|
(u) => u.email.toLowerCase() === user.email.toLowerCase() // メールアドレスは大文字小文字を区別しない
|
|
);
|
|
|
|
if (duplicateUserEmail) {
|
|
// 重複がある場合
|
|
const index = newLicensesFileLines.findIndex(
|
|
(license) =>
|
|
license.account_id === user.accountId &&
|
|
license.allocated_user_id === duplicateUserEmail.userId
|
|
);
|
|
if (index !== -1) {
|
|
// ライセンスの割り当てを解除
|
|
newLicensesFileLines[index].status =
|
|
LICENSE_ALLOCATED_STATUS.REUSABLE;
|
|
newLicensesFileLines[index].allocated_user_id = null;
|
|
}
|
|
} else {
|
|
// 重複がない場合
|
|
newUsersFileLines.push(user);
|
|
}
|
|
// newAccountsFileLinesとの突合せ
|
|
const duplicateAdminUserEmail = newAccountsFileLines.find(
|
|
(a) => a.adminMail.toLowerCase() === user.email.toLowerCase() // メールアドレスは大文字小文字を区別しない
|
|
);
|
|
// 重複がある場合
|
|
if (duplicateAdminUserEmail) {
|
|
// 同一アカウント内での重複の場合
|
|
const isDuplicateInSameAccount =
|
|
duplicateAdminUserEmail.accountId === user.accountId;
|
|
|
|
if (isDuplicateInSameAccount) {
|
|
// アカウント管理者にauthorロールを付与する
|
|
duplicateAdminUserEmail.role = USER_ROLES.AUTHOR;
|
|
duplicateAdminUserEmail.authorId = user.authorId;
|
|
|
|
// アカウントにライセンスが割り当てられているか確認する
|
|
const isAllocatedLicense = newLicensesFileLines.some(
|
|
(license) =>
|
|
license.account_id === duplicateAdminUserEmail.accountId &&
|
|
license.allocated_user_id === duplicateAdminUserEmail.userId
|
|
);
|
|
// 割り当てられていなければアカウントに割り当てる
|
|
if (!isAllocatedLicense) {
|
|
const index = newLicensesFileLines.findIndex(
|
|
(license) =>
|
|
license.account_id === user.accountId &&
|
|
license.allocated_user_id === user.userId
|
|
);
|
|
if (index !== -1) {
|
|
newLicensesFileLines[index].allocated_user_id =
|
|
duplicateAdminUserEmail.userId;
|
|
}
|
|
}
|
|
}
|
|
// ユーザーから割り当て解除する
|
|
const index = newLicensesFileLines.findIndex(
|
|
(license) =>
|
|
license.account_id === user.accountId &&
|
|
license.allocated_user_id === user.userId
|
|
);
|
|
if (index !== -1) {
|
|
// ライセンスの割り当てを解除
|
|
newLicensesFileLines[index].status =
|
|
LICENSE_ALLOCATED_STATUS.REUSABLE;
|
|
newLicensesFileLines[index].allocated_user_id = null;
|
|
}
|
|
// ユーザーの削除
|
|
const userIndex = newUsersFileLines.findIndex(
|
|
(u) => u.userId === user.userId
|
|
);
|
|
if (userIndex !== -1) {
|
|
newUsersFileLines.splice(userIndex, 1);
|
|
}
|
|
}
|
|
});
|
|
|
|
return {
|
|
accountsFileLines: newAccountsFileLines,
|
|
usersFileLines: newUsersFileLines,
|
|
licensesFileLines: newLicensesFileLines,
|
|
};
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.removeDuplicateEmail.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* transferDuplicateAuthor
|
|
* @param accountsFileLines: AccountsFile[]
|
|
* @param usersFileLines: UsersFile[]
|
|
* @returns UsersFile[]
|
|
*/
|
|
async transferDuplicateAuthor(
|
|
context: Context,
|
|
accountsFileLines: AccountsFile[],
|
|
usersFileLines: UsersFile[]
|
|
): Promise<UsersFile[]> {
|
|
// パラメータ内容が長大なのでログには出さない
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.transferDuplicateAuthor.name}`
|
|
);
|
|
|
|
try {
|
|
const newUsersFileLines: UsersFile[] = [];
|
|
|
|
for (const accountsFileLine of accountsFileLines) {
|
|
let duplicateSequence: number = 2;
|
|
let authorIdList: String[] = [];
|
|
|
|
// メールアドレス重複時はアカウントにもAuthorIdが設定されるので重複チェック用のリストに追加しておく
|
|
if (accountsFileLine.authorId) {
|
|
authorIdList.push(accountsFileLine.authorId);
|
|
}
|
|
|
|
const targetaccountUsers = usersFileLines.filter(
|
|
(item) => item.accountId === accountsFileLine.accountId
|
|
);
|
|
|
|
for (const targetaccountUser of targetaccountUsers) {
|
|
let assignAuthorId = targetaccountUser.authorId;
|
|
if (authorIdList.includes(targetaccountUser.authorId)) {
|
|
// 同じauthorIdがいる場合、自分のauthorIdに連番を付与する
|
|
assignAuthorId = assignAuthorId + duplicateSequence;
|
|
duplicateSequence = duplicateSequence + 1;
|
|
}
|
|
authorIdList.push(targetaccountUser.authorId);
|
|
|
|
// 新しいAuthorIdのユーザに詰め替え
|
|
const newUser: UsersFile = {
|
|
accountId: targetaccountUser.accountId,
|
|
userId: targetaccountUser.userId,
|
|
name: targetaccountUser.name,
|
|
role: targetaccountUser.role,
|
|
authorId: assignAuthorId,
|
|
email: targetaccountUser.email,
|
|
};
|
|
newUsersFileLines.push(newUser);
|
|
}
|
|
}
|
|
|
|
return newUsersFileLines;
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${
|
|
this.transferDuplicateAuthor.name
|
|
}`
|
|
);
|
|
}
|
|
}
|
|
}
|