## 概要 [Task3839: 登録ツールにログを仕込む](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3839) 登録ツールが途中で動かなくなってしまう原因調査のために各関数にログを仕込みました。 ## レビューポイント - 特になし ## 動作確認状況 - ローカルで確認 ## 補足 - 相談、参考資料などがあれば
311 lines
9.4 KiB
TypeScript
311 lines
9.4 KiB
TypeScript
import { HttpException, HttpStatus, Injectable, Logger } from "@nestjs/common";
|
|
import { makeErrorResponse } from "../../common/error/makeErrorResponse";
|
|
import { makePassword } from "../../common/password/password";
|
|
import {
|
|
AdB2cService,
|
|
ConflictError,
|
|
isConflictError,
|
|
} from "../../gateways/adb2c/adb2c.service";
|
|
import {
|
|
User as EntityUser,
|
|
newUser,
|
|
} from "../../repositories/users/entity/user.entity";
|
|
import { UsersRepositoryService } from "../../repositories/users/users.repository.service";
|
|
import { MANUAL_RECOVERY_REQUIRED, USER_ROLES } from "../../constants";
|
|
import { Context } from "../../common/log";
|
|
import { UserRoles } from "../../common/types/role";
|
|
|
|
@Injectable()
|
|
export class UsersService {
|
|
private readonly logger = new Logger(UsersService.name);
|
|
constructor(
|
|
private readonly usersRepository: UsersRepositoryService,
|
|
private readonly adB2cService: AdB2cService
|
|
) {}
|
|
|
|
/**
|
|
* Creates user
|
|
* @param context
|
|
* @param name
|
|
* @param role
|
|
* @param email
|
|
* @param autoRenew
|
|
* @param notification
|
|
* @param accountId
|
|
* @param userid
|
|
* @param [authorId]
|
|
* @param [encryption]
|
|
* @param [encryptionPassword]
|
|
* @param [prompt]
|
|
* @returns user
|
|
*/
|
|
async createUser(
|
|
context: Context,
|
|
name: string,
|
|
role: UserRoles,
|
|
email: string,
|
|
autoRenew: boolean,
|
|
notification: boolean,
|
|
accountId: number,
|
|
userid: number,
|
|
authorId?: string | undefined,
|
|
encryption?: boolean | undefined,
|
|
encryptionPassword?: string | undefined,
|
|
prompt?: boolean | undefined
|
|
): Promise<void> {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${this.createUser.name} | params: { ` +
|
|
`role: ${role}, ` +
|
|
`autoRenew: ${autoRenew}, ` +
|
|
`notification: ${notification}, ` +
|
|
`accountId: ${accountId}, ` +
|
|
`userid: ${userid}, ` +
|
|
`authorId: ${authorId}, ` +
|
|
`encryption: ${encryption}, ` +
|
|
`prompt: ${prompt} };`
|
|
);
|
|
|
|
//authorIdが重複していないかチェックする
|
|
if (authorId) {
|
|
let isAuthorIdDuplicated = false;
|
|
try {
|
|
isAuthorIdDuplicated = await this.usersRepository.existsAuthorId(
|
|
context,
|
|
accountId,
|
|
authorId
|
|
);
|
|
this.logger.log(
|
|
`[${context.getTrackingId()}] isAuthorIdDuplicated=${isAuthorIdDuplicated}`
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
}
|
|
if (isAuthorIdDuplicated) {
|
|
throw new HttpException(
|
|
makeErrorResponse("E010302"),
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
}
|
|
this.logger.log("ランダムパスワード生成開始");
|
|
// ランダムなパスワードを生成する
|
|
const ramdomPassword = makePassword();
|
|
this.logger.log("ランダムパスワード生成完了");
|
|
|
|
//Azure AD B2Cにユーザーを新規登録する
|
|
let externalUser: { sub: string } | ConflictError;
|
|
try {
|
|
this.logger.log(`name=${name}`);
|
|
// idpにユーザーを作成
|
|
externalUser = await this.adB2cService.createUser(
|
|
context,
|
|
email,
|
|
ramdomPassword,
|
|
name
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
this.logger.error(
|
|
`[${context.getTrackingId()}] create externalUser failed`
|
|
);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
}
|
|
|
|
// メールアドレス重複エラー
|
|
if (isConflictError(externalUser)) {
|
|
throw new HttpException(
|
|
makeErrorResponse("E010301"),
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
}
|
|
|
|
//Azure AD B2Cに登録したユーザー情報のID(sub)と受け取った情報を使ってDBにユーザーを登録する
|
|
let newUser: EntityUser;
|
|
|
|
try {
|
|
//roleに応じてユーザー情報を作成する
|
|
const newUserInfo = this.createNewUserInfo(
|
|
context,
|
|
userid,
|
|
role,
|
|
accountId,
|
|
externalUser.sub,
|
|
autoRenew,
|
|
notification,
|
|
authorId,
|
|
encryption,
|
|
encryptionPassword,
|
|
prompt
|
|
);
|
|
// ユーザ作成
|
|
newUser = await this.usersRepository.createNormalUser(
|
|
context,
|
|
newUserInfo
|
|
);
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
this.logger.error(`[${context.getTrackingId()}]create user failed`);
|
|
//リカバリー処理
|
|
//Azure AD B2Cに登録したユーザー情報を削除する
|
|
await this.deleteB2cUser(externalUser.sub, context);
|
|
|
|
switch (e.code) {
|
|
case "ER_DUP_ENTRY":
|
|
//AuthorID重複エラー
|
|
throw new HttpException(
|
|
makeErrorResponse("E010302"),
|
|
HttpStatus.BAD_REQUEST
|
|
);
|
|
default:
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
}
|
|
}
|
|
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.createUser.name}`
|
|
);
|
|
return;
|
|
}
|
|
|
|
// Azure AD B2Cに登録したユーザー情報を削除する
|
|
// TODO 「タスク 2452: リトライ処理を入れる箇所を検討し、実装する」の候補
|
|
private async deleteB2cUser(externalUserId: string, context: Context) {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
this.deleteB2cUser.name
|
|
} | params: { externalUserId: ${externalUserId} }`
|
|
);
|
|
try {
|
|
await this.adB2cService.deleteUser(externalUserId, context);
|
|
this.logger.log(
|
|
`[${context.getTrackingId()}] delete externalUser: ${externalUserId}`
|
|
);
|
|
} catch (error) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
|
this.logger.error(
|
|
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete externalUser: ${externalUserId}`
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.deleteB2cUser.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
// DBに登録したユーザー情報を削除する
|
|
private async deleteUser(userId: number, context: Context) {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
this.deleteUser.name
|
|
} | params: { userId: ${userId} }`
|
|
);
|
|
try {
|
|
await this.usersRepository.deleteNormalUser(context, userId);
|
|
this.logger.log(`[${context.getTrackingId()}] delete user: ${userId}`);
|
|
} catch (error) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${error}`);
|
|
this.logger.error(
|
|
`${MANUAL_RECOVERY_REQUIRED} [${context.getTrackingId()}] Failed to delete user: ${userId}`
|
|
);
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.deleteUser.name}`
|
|
);
|
|
}
|
|
}
|
|
|
|
// roleを受け取って、roleに応じたnewUserを作成して返却する
|
|
private createNewUserInfo(
|
|
context: Context,
|
|
id: number,
|
|
role: UserRoles,
|
|
accountId: number,
|
|
externalId: string,
|
|
autoRenew: boolean,
|
|
notification: boolean,
|
|
authorId?: string | undefined,
|
|
encryption?: boolean | undefined,
|
|
encryptionPassword?: string | undefined,
|
|
prompt?: boolean | undefined
|
|
): newUser {
|
|
this.logger.log(
|
|
`[IN] [${context.getTrackingId()}] ${
|
|
this.createNewUserInfo.name
|
|
} | params: { ` +
|
|
`id: ${id}, ` +
|
|
`role: ${role}, ` +
|
|
`accountId: ${accountId}, ` +
|
|
`authorId: ${authorId}, ` +
|
|
`externalId: ${externalId}, ` +
|
|
`autoRenew: ${autoRenew}, ` +
|
|
`notification: ${notification}, ` +
|
|
`authorId: ${authorId}, ` +
|
|
`encryption: ${encryption}, ` +
|
|
`prompt: ${prompt} };`
|
|
);
|
|
try {
|
|
switch (role) {
|
|
case USER_ROLES.NONE:
|
|
case USER_ROLES.TYPIST:
|
|
return {
|
|
id,
|
|
account_id: accountId,
|
|
external_id: externalId,
|
|
auto_renew: autoRenew,
|
|
notification,
|
|
role,
|
|
accepted_dpa_version: null,
|
|
accepted_eula_version: null,
|
|
accepted_privacy_notice_version: null,
|
|
encryption: false,
|
|
encryption_password: null,
|
|
prompt: false,
|
|
author_id: null,
|
|
};
|
|
case USER_ROLES.AUTHOR:
|
|
return {
|
|
id,
|
|
account_id: accountId,
|
|
external_id: externalId,
|
|
auto_renew: autoRenew,
|
|
notification,
|
|
role,
|
|
author_id: authorId ?? null,
|
|
encryption: encryption ?? false,
|
|
encryption_password: encryptionPassword ?? null,
|
|
prompt: prompt ?? false,
|
|
accepted_dpa_version: null,
|
|
accepted_eula_version: null,
|
|
accepted_privacy_notice_version: null,
|
|
};
|
|
default:
|
|
//不正なroleが指定された場合はログを出力してエラーを返す
|
|
this.logger.error(
|
|
`[${context.getTrackingId()}] [NOT IMPLEMENT] [RECOVER] role: ${role}`
|
|
);
|
|
throw new HttpException(
|
|
makeErrorResponse("E009999"),
|
|
HttpStatus.INTERNAL_SERVER_ERROR
|
|
);
|
|
}
|
|
} catch (e) {
|
|
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
|
|
return e;
|
|
} finally {
|
|
this.logger.log(
|
|
`[OUT] [${context.getTrackingId()}] ${this.createNewUserInfo.name}`
|
|
);
|
|
}
|
|
}
|
|
}
|