Merged PR 645: アカウント情報消去完了通知 [U-111] の実装

## 概要
[Task3307: アカウント情報消去完了通知 [U-111] の実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3307)

-

## レビューポイント
- アカウント削除時の削除通知メール送信機能を追加しました。

## UIの変更
- メールに必要な情報を取得するために削除前に取得処理を入れていますが不自然な点はないでしょうか?

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-12-20 08:50:16 +00:00
parent 1bc6618a6d
commit a6f56d71ee
6 changed files with 224 additions and 10 deletions

View File

@ -6142,11 +6142,7 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideSendgridService(service, {
sendMailWithU107: async () => {
return;
},
});
overrideSendgridService(service, {});
// 第一~第四階層のアカウント作成
const {
tier1Accounts: tier1Accounts,
@ -6254,11 +6250,6 @@ describe('deleteAccountAndData', () => {
const licensesB = await getLicenses(source, tier5AccountsB.account.id);
const usersService = module.get<UsersService>(UsersService);
overrideSendgridService(usersService, {
sendMailWithU108: async () => {
return;
},
});
// アカウントAのライセンスを割り当てる
await usersService.allocateLicense(
context,
@ -6352,6 +6343,7 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideSendgridService(service, {});
const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation();
// 第五階層のアカウント作成
const tier4Accounts = await makeHierarchicalAccounts(source);
@ -6416,6 +6408,7 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideSendgridService(service, {});
const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation();
// 第五階層のアカウント作成
const tier4Accounts = await makeHierarchicalAccounts(source);
@ -6470,6 +6463,7 @@ describe('deleteAccountAndData', () => {
const module = await makeTestingModule(source);
if (!module) fail();
const service = module.get<AccountsService>(AccountsService);
overrideSendgridService(service, {});
const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation();
// 第五階層のアカウント作成

View File

@ -2134,6 +2134,11 @@ export class AccountsService {
);
let country: string;
let dbUsers: User[];
// メール送信に必要な情報
let companyName: string | null = null;
let primaryAdminName: string | null = null;
let primaryAdminEmail: string | null = null;
try {
// パラメータとトークンから取得したアカウントIDの突き合わせ
const { account_id: myAccountId } =
@ -2150,6 +2155,35 @@ export class AccountsService {
context,
accountId,
);
// メール送信に必要な情報を取得する
try {
companyName = targetAccount.company_name;
if (!targetAccount.primary_admin_user_id) {
throw new Error(
`primary_admin_user_id not found. accountId: ${accountId}`,
);
}
const primaryAdmin = await this.usersRepository.findUserById(
context,
targetAccount.primary_admin_user_id,
);
const adb2cAdmin = await this.adB2cService.getUser(
context,
primaryAdmin.external_id,
);
const { displayName, emailAddress } =
getUserNameAndMailAddress(adb2cAdmin);
primaryAdminName = displayName;
primaryAdminEmail = emailAddress ?? null;
} catch (e) {
// メール送信に関する例外はログだけ出して握りつぶす
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
}
// 削除対象アカウントを削除する
dbUsers = await this.accountRepository.deleteAccountAndInsertArchives(
context,
@ -2206,6 +2240,29 @@ export class AccountsService {
);
}
// メール送信処理
try {
if (companyName === null) {
throw new Error('companyName is null');
}
if (primaryAdminName === null) {
throw new Error('primaryAdminName is null');
}
if (primaryAdminEmail === null) {
throw new Error('primaryAdminEmail is null');
}
await this.sendgridService.sendMailWithU111(
context,
primaryAdminName,
primaryAdminEmail,
companyName,
);
} catch (e) {
this.logger.error(`[${context.getTrackingId()}] error=${e}`);
// メール送信に関する例外はログだけ出して握りつぶす
}
this.logger.log(
`[OUT] [${context.getTrackingId()}] ${this.deleteAccountAndData.name}`,
);

View File

@ -11,6 +11,7 @@ import {
DEALER_NAME,
LICENSE_QUANTITY,
PO_NUMBER,
PRIMARY_ADMIN_NAME,
TOP_URL,
USER_EMAIL,
USER_NAME,
@ -36,6 +37,8 @@ export class SendGridService {
private readonly templateU108Text: string;
private readonly templateU109Html: string;
private readonly templateU109Text: string;
private readonly templateU111Html: string;
private readonly templateU111Text: string;
constructor(private readonly configService: ConfigService) {
this.appDomain = this.configService.getOrThrow<string>('APP_DOMAIN');
@ -110,6 +113,14 @@ export class SendGridService {
path.resolve(__dirname, `../../templates/template_U_109.txt`),
'utf-8',
);
this.templateU111Html = readFileSync(
path.resolve(__dirname, `../../templates/template_U_111.html`),
'utf-8',
);
this.templateU111Text = readFileSync(
path.resolve(__dirname, `../../templates/template_U_111.txt`),
'utf-8',
);
}
}
@ -529,6 +540,54 @@ export class SendGridService {
}
}
/**
* U-111使
* @param context
* @param primaryAdminName (primary)
* @param primaryAdminMail (primary)
* @param customerAccountName
* @returns mail with u111
*/
async sendMailWithU111(
context: Context,
primaryAdminName: string,
primaryAdminMail: string,
customerAccountName: string,
): Promise<void> {
this.logger.log(
`[IN] [${context.getTrackingId()}] ${this.sendMailWithU111.name}`,
);
try {
const subject = 'Account Deleted Notification [U-111]';
// メールの本文を作成する
const html = this.templateU111Html
.replaceAll(CUSTOMER_NAME, customerAccountName)
.replaceAll(PRIMARY_ADMIN_NAME, primaryAdminName)
.replaceAll(TOP_URL, this.appDomain);
const text = this.templateU111Text
.replaceAll(CUSTOMER_NAME, customerAccountName)
.replaceAll(PRIMARY_ADMIN_NAME, primaryAdminName)
.replaceAll(TOP_URL, this.appDomain);
// メールを送信する
this.sendMail(
context,
[primaryAdminMail],
[],
this.mailFrom,
subject,
text,
html,
);
} finally {
this.logger.log(
`[OUT] [${context.getTrackingId()}] ${this.sendMailWithU111.name}`,
);
}
}
/**
*
* @param context

View File

@ -3,5 +3,6 @@ export const DEALER_NAME = '$DEALER_NAME$';
export const LICENSE_QUANTITY = '$LICENSE_QUANTITY$';
export const PO_NUMBER = '$PO_NUMBER$';
export const TOP_URL = '$TOP_URL$';
export const PRIMARY_ADMIN_NAME = '$PRIMARY_ADMIN_NAME$';
export const USER_NAME = '$USER_NAME$';
export const USER_EMAIL = '$USER_EMAIL$';

View File

@ -0,0 +1,68 @@
<html>
<head>
<title>Account Deleted Notification [U-111]</title>
</head>
<body>
<div>
<h3>&lt;English&gt;</h3>
<p>Dear $CUSTOMER_NAME$, -> $PRIMARY_ADMIN_NAME$</p>
<p>
Thank you for using ODMS Cloud. Your account, including all information
has been deleted from the ODMS Cloud.
</p>
<p>
If you wish to use ODMS Cloud again, you will need to register your
account information again and order annual licenses from an OM Digital
Solutions authorized dealer.<br />
URL: $TOP_URL$
</p>
<p>
If you have received this e-mail in error, please delete this e-mail
from your system.<br />
This is an automatically generated e-mail and this mailbox is not
monitored. Please do not reply.
</p>
</div>
<div>
<h3>&lt;Deutsch&gt;</h3>
<p>Sehr geehrte(r) $CUSTOMER_NAME$, -> $PRIMARY_ADMIN_NAME$</p>
<p>
Vielen Dank, dass Sie ODMS Cloud nutzen. Ihr Konto, einschließlich aller
Informationen, wurde aus der ODMS Cloud gelöscht.
</p>
<p>
Wenn Sie ODMS Cloud erneut nutzen möchten, müssen Sie Ihre
Kontoinformationen erneut registrieren und Jahreslizenzen bei einem
autorisierten OM Digital Solutions-Händler bestellen.<br />
URL: $TOP_URL$
</p>
<p>
Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie
diese E-Mail bitte aus Ihrem System.<br />
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird
nicht überwacht. Bitte nicht antworten.
</p>
<p></p>
</div>
<div>
<h3>&lt;Français&gt;</h3>
<p>Chère/Cher $CUSTOMER_NAME$, -> $PRIMARY_ADMIN_NAME$</p>
<p>
Merci d'utiliser ODMS Cloud. Votre compte, y compris toutes les
informations, a été supprimé du cloud ODMS.
</p>
<p>
Si vous souhaitez utiliser à nouveau ODMS Cloud, vous devrez à nouveau
enregistrer les informations de votre compte et commander des licences
annuelles auprès d'un concessionnaire agréé OM Digital Solutions.<br />
URL: $TOP_URL$
</p>
<p>
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail
de votre système.<br />
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres
n'est pas surveillée. Merci de ne pas répondre.
</p>
</div>
</body>
</html>

View File

@ -0,0 +1,35 @@
<English>
Dear $CUSTOMER_NAME$, -> $PRIMARY_ADMIN_NAME$
Thank you for using ODMS Cloud. Your account, including all information has been deleted from the ODMS Cloud.
If you wish to use ODMS Cloud again, you will need to register your account information again and order annual licenses from an OM Digital Solutions authorized dealer.
URL: $TOP_URL$
If you have received this e-mail in error, please delete this e-mail from your system.
This is an automatically generated e-mail and this mailbox is not monitored. Please do not reply.
<Deutsch>
Sehr geehrte(r) $CUSTOMER_NAME$, -> $PRIMARY_ADMIN_NAME$
Vielen Dank, dass Sie ODMS Cloud nutzen. Ihr Konto, einschließlich aller Informationen, wurde aus der ODMS Cloud gelöscht.
Wenn Sie ODMS Cloud erneut nutzen möchten, müssen Sie Ihre Kontoinformationen erneut registrieren und Jahreslizenzen bei einem autorisierten OM Digital Solutions-Händler bestellen.
URL: $TOP_URL$
Wenn Sie diese E-Mail fälschlicherweise erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
Dies ist eine automatisch generierte E-Mail und dieses Postfach wird nicht überwacht. Bitte nicht antworten.
<Français>
Chère/Cher $CUSTOMER_NAME$, -> $PRIMARY_ADMIN_NAME$
Merci d'utiliser ODMS Cloud. Votre compte, y compris toutes les informations, a été supprimé du cloud ODMS.
Si vous souhaitez utiliser à nouveau ODMS Cloud, vous devrez à nouveau enregistrer les informations de votre compte et commander des licences annuelles auprès d'un concessionnaire agréé OM Digital Solutions.
URL: $TOP_URL$
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.
Il s'agit d'un e-mail généré automatiquement et cette boîte aux lettres n'est pas surveillée. Merci de ne pas répondre.