From a6f56d71ee5a014f529c3fc67855ec4fd78ec8a0 Mon Sep 17 00:00:00 2001 From: "makabe.t" Date: Wed, 20 Dec 2023 08:50:16 +0000 Subject: [PATCH] =?UTF-8?q?Merged=20PR=20645:=20=E3=82=A2=E3=82=AB?= =?UTF-8?q?=E3=82=A6=E3=83=B3=E3=83=88=E6=83=85=E5=A0=B1=E6=B6=88=E5=8E=BB?= =?UTF-8?q?=E5=AE=8C=E4=BA=86=E9=80=9A=E7=9F=A5=20[U-111]=C2=A0=E3=81=AE?= =?UTF-8?q?=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 概要 [Task3307: アカウント情報消去完了通知 [U-111] の実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/3307) - ## レビューポイント - アカウント削除時の削除通知メール送信機能を追加しました。 ## UIの変更 - メールに必要な情報を取得するために削除前に取得処理を入れていますが不自然な点はないでしょうか? ## 動作確認状況 - ローカルで確認 --- .../accounts/accounts.service.spec.ts | 14 ++-- .../src/features/accounts/accounts.service.ts | 57 ++++++++++++++++ .../src/gateways/sendgrid/sendgrid.service.ts | 59 ++++++++++++++++ dictation_server/src/templates/constants.ts | 1 + .../src/templates/template_U_111.html | 68 +++++++++++++++++++ .../src/templates/template_U_111.txt | 35 ++++++++++ 6 files changed, 224 insertions(+), 10 deletions(-) create mode 100644 dictation_server/src/templates/template_U_111.html create mode 100644 dictation_server/src/templates/template_U_111.txt diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index cfaacab..1a6b85b 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -6142,11 +6142,7 @@ describe('deleteAccountAndData', () => { const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(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); - 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); + 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); + 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); + overrideSendgridService(service, {}); const loggerSpy = jest.spyOn(service['logger'], 'log').mockImplementation(); // 第五階層のアカウント作成 diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index a123d98..e913c27 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -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}`, ); diff --git a/dictation_server/src/gateways/sendgrid/sendgrid.service.ts b/dictation_server/src/gateways/sendgrid/sendgrid.service.ts index 70dc088..4b4c642 100644 --- a/dictation_server/src/gateways/sendgrid/sendgrid.service.ts +++ b/dictation_server/src/gateways/sendgrid/sendgrid.service.ts @@ -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('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 { + 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 diff --git a/dictation_server/src/templates/constants.ts b/dictation_server/src/templates/constants.ts index 8ff9d75..e7c95b8 100644 --- a/dictation_server/src/templates/constants.ts +++ b/dictation_server/src/templates/constants.ts @@ -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$'; diff --git a/dictation_server/src/templates/template_U_111.html b/dictation_server/src/templates/template_U_111.html new file mode 100644 index 0000000..819ea9c --- /dev/null +++ b/dictation_server/src/templates/template_U_111.html @@ -0,0 +1,68 @@ + + + Account Deleted Notification [U-111] + + +
+

<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. +

+
+ + diff --git a/dictation_server/src/templates/template_U_111.txt b/dictation_server/src/templates/template_U_111.txt new file mode 100644 index 0000000..bd98837 --- /dev/null +++ b/dictation_server/src/templates/template_U_111.txt @@ -0,0 +1,35 @@ + + +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. + + + +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. + + + +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. \ No newline at end of file