From b88c0d9b96bed4eb1bf515c67cfc51127ba24847 Mon Sep 17 00:00:00 2001
From: "saito.k"
Date: Fri, 19 Apr 2024 04:47:32 +0000
Subject: [PATCH 1/9] =?UTF-8?q?Merged=20PR=20877:=20=E3=83=87=E3=82=A3?=
=?UTF-8?q?=E3=83=BC=E3=83=A9=E3=83=BC=E5=8F=96=E5=BE=97API=E3=81=AE?=
=?UTF-8?q?=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 概要
[Task4104: ディーラー取得APIの修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4104)
- メールの文面を各言語版に置き換えました。
- 環境変数に設定されたアカウントIDのDealerはResponseに含めないように修正
## レビューポイント
- 環境変数からインスタンス変数に代入するときの処理に問題はあるか
- 環境変数のフォーマットはこれで良いか
- もっとよいやり方があれば指摘いただきたいです
- テストケースに不足はないか
## UIの変更
- なし
## クエリの変更
- なし
## 動作確認状況
- ローカルで確認
- 行った修正がデグレを発生させていないことを確認できるか
- ほかのテストに影響が出ていない
---
dictation_server/.env.local.example | 3 +-
dictation_server/.env.test | 3 +-
.../src/common/validators/env.validator.ts | 4 ++
.../accounts/accounts.service.spec.ts | 29 ++++++++++++
.../src/features/accounts/accounts.service.ts | 46 +++++++++++++++++--
5 files changed, 80 insertions(+), 5 deletions(-)
diff --git a/dictation_server/.env.local.example b/dictation_server/.env.local.example
index 8c03436..5aaecca 100644
--- a/dictation_server/.env.local.example
+++ b/dictation_server/.env.local.example
@@ -33,4 +33,5 @@ EMAIL_CONFIRM_LIFETIME=86400
REDIS_HOST=redis-cache
REDIS_PORT=6379
REDIS_PASSWORD=omdsredispass
-ADB2C_CACHE_TTL=86400
\ No newline at end of file
+ADB2C_CACHE_TTL=86400
+DEALER_ACCOUNT_ID_HIDDEN_LIST=1,2,3,4
\ No newline at end of file
diff --git a/dictation_server/.env.test b/dictation_server/.env.test
index a2748df..ca88821 100644
--- a/dictation_server/.env.test
+++ b/dictation_server/.env.test
@@ -34,4 +34,5 @@ REDIS_HOST=redis-cache
REDIS_PORT=6379
REDIS_PASSWORD=omdsredispass
ADB2C_CACHE_TTL=86400
-TEMPLATE_ROOT=dist
\ No newline at end of file
+TEMPLATE_ROOT=dist
+DEALER_ACCOUNT_ID_HIDDEN_LIST=50,99
\ No newline at end of file
diff --git a/dictation_server/src/common/validators/env.validator.ts b/dictation_server/src/common/validators/env.validator.ts
index 8ce706f..8ce1547 100644
--- a/dictation_server/src/common/validators/env.validator.ts
+++ b/dictation_server/src/common/validators/env.validator.ts
@@ -32,6 +32,10 @@ export class EnvValidator {
@IsString()
DB_PASSWORD: string;
+ @IsOptional()
+ @IsString()
+ DEALER_ACCOUNT_ID_HIDDEN_LIST: string;
+
// .env.local
@IsOptional()
@IsString()
diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts
index 29c5899..d5e0575 100644
--- a/dictation_server/src/features/accounts/accounts.service.spec.ts
+++ b/dictation_server/src/features/accounts/accounts.service.spec.ts
@@ -2645,6 +2645,35 @@ describe('getDealers', () => {
],
});
});
+
+ it('非表示指定されたDealer以外のDealerを取得できる', async () => {
+ if (!source) fail();
+ const module = await makeTestingModule(source);
+ if (!module) fail();
+ // 100件のDealerを作成し、country,id,company_nameを取得する
+ const dealers: { country: string; id: number; name: string }[] = [];
+ for (let i = 0; i < 100; i++) {
+ const { id, company_name, country } = (
+ await makeTestAccount(source, {
+ parent_account_id: i,
+ tier: TIERS.TIER4,
+ country: 'JP',
+ company_name: `DEALER_${i}`,
+ })
+ ).account;
+ dealers.push({ id, name: company_name, country });
+ }
+ const service = module.get(AccountsService);
+ const context = makeContext(`uuidv4`, 'requestId');
+ const result = await service.getDealers(context);
+ // idが50と99のDealerを非表示にする
+
+ expect(result.dealers.length).toBe(98);
+ expect(result).toEqual({
+ dealers: dealers.filter((dealer) => dealer.id !== 50 && dealer.id !== 99),
+ });
+ });
+
it('0件でもDealerを取得できる', async () => {
if (!source) fail();
const module = await makeTestingModule(source);
diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts
index 8b6e271..688981b 100644
--- a/dictation_server/src/features/accounts/accounts.service.ts
+++ b/dictation_server/src/features/accounts/accounts.service.ts
@@ -72,9 +72,13 @@ import {
WorktypeIdNotFoundError,
} from '../../repositories/worktypes/errors/types';
import { getUserNameAndMailAddress } from '../../gateways/adb2c/utils/utils';
+import { ConfigService } from '@nestjs/config';
@Injectable()
export class AccountsService {
+ // プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
+ private readonly dealerAccountIdHiddenList: number[] = [];
+ private readonly logger = new Logger(AccountsService.name);
constructor(
private readonly accountRepository: AccountsRepositoryService,
private readonly licensesRepository: LicensesRepositoryService,
@@ -84,8 +88,27 @@ export class AccountsService {
private readonly adB2cService: AdB2cService,
private readonly sendgridService: SendGridService,
private readonly blobStorageService: BlobstorageService,
- ) {}
- private readonly logger = new Logger(AccountsService.name);
+ private readonly configService: ConfigService,
+ ) {
+ const dealerAccountIdList = this.configService.get(
+ 'DEALER_ACCOUNT_ID_HIDDEN_LIST',
+ );
+ // ディーラーアカウントIDリストを数値配列に変換する
+ // 変換できない場合はエラーをスローする
+ // 存在しない場合や空文字列の場合は空の配列を返す
+ if (dealerAccountIdList) {
+ this.dealerAccountIdHiddenList = dealerAccountIdList
+ .split(',')
+ .map((x) => {
+ const id = parseInt(x, 10);
+ if (isNaN(id)) {
+ throw new Error('DEALER_ACCOUNT_ID_HIDDEN_LIST is invalid');
+ }
+ return id;
+ });
+ }
+ }
+
/**
* 第五階層用のライセンス情報を取得する
* @param accountId
@@ -1174,9 +1197,26 @@ export class AccountsService {
const dealerAccounts = await this.accountRepository.findDealerAccounts(
context,
);
+ // プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
+ // this.dealerAccountIdHiddenListに含まれるアカウント(動作確認用のアカウント)を除外する。
+ // 除外したアカウントをlogに出力する
+ const filteredDealerAccounts = dealerAccounts.filter((dealerAccount) => {
+ const isHidden = this.dealerAccountIdHiddenList.includes(
+ dealerAccount.id,
+ );
+ if (isHidden) {
+ this.logger.log(
+ `[${context.getTrackingId()}] hidden dealer account: ${
+ dealerAccount.id
+ }`,
+ );
+ }
+ return !isHidden;
+ });
+ // レスポンス用の型に変換
const dealers: GetDealersResponse = {
- dealers: dealerAccounts.map((dealerAccount): Dealer => {
+ dealers: filteredDealerAccounts.map((dealerAccount): Dealer => {
return {
id: dealerAccount.id,
name: dealerAccount.company_name,
From 0b01da936dc97593637efb04d8dd85d79b0a72b8 Mon Sep 17 00:00:00 2001
From: "SAITO-PC-3\\saito.k"
Date: Fri, 19 Apr 2024 19:15:23 +0900
Subject: [PATCH 2/9] =?UTF-8?q?CacheModule=E4=BD=9C=E6=88=90=E6=99=82?=
=?UTF-8?q?=E3=81=ABTTL=E3=82=92=E8=A8=AD=E5=AE=9A?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
dictation_server/src/common/test/modules.ts | 2 +-
dictation_server/src/features/accounts/accounts.service.spec.ts | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/dictation_server/src/common/test/modules.ts b/dictation_server/src/common/test/modules.ts
index 7c51a50..8d50139 100644
--- a/dictation_server/src/common/test/modules.ts
+++ b/dictation_server/src/common/test/modules.ts
@@ -80,7 +80,7 @@ export const makeTestingModule = async (
WorktypesRepositoryModule,
TermsRepositoryModule,
RedisModule,
- CacheModule.register({ isGlobal: true }),
+ CacheModule.register({ isGlobal: true, ttl: 86400 }),
],
providers: [
AuthService,
diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts
index d5e0575..e042a85 100644
--- a/dictation_server/src/features/accounts/accounts.service.spec.ts
+++ b/dictation_server/src/features/accounts/accounts.service.spec.ts
@@ -6873,6 +6873,7 @@ describe('deleteAccountAndData', () => {
expect(userRecord).toBe(null);
});
});
+
describe('getAccountInfoMinimalAccess', () => {
let source: DataSource | null = null;
beforeAll(async () => {
From 7eecb001c69f8f2a5c836ae9816990bb8f434508 Mon Sep 17 00:00:00 2001
From: "SAITO-PC-3\\saito.k"
Date: Sun, 21 Apr 2024 22:41:44 +0900
Subject: [PATCH 3/9] =?UTF-8?q?4/22=E3=81=AE=E6=9C=AC=E7=95=AA=E7=92=B0?=
=?UTF-8?q?=E5=A2=83=E3=83=87=E3=83=97=E3=83=AD=E3=82=A4=E3=81=AE=E3=81=9F?=
=?UTF-8?q?=E3=82=81=E3=81=AB=E7=A2=BA=E8=AA=8D=E6=9C=AA=E5=AE=9F=E6=96=BD?=
=?UTF-8?q?=E3=81=AE=E4=BF=AE=E6=AD=A3=E3=82=92=E3=82=B3=E3=83=A1=E3=83=B3?=
=?UTF-8?q?=E3=83=88=E3=82=A2=E3=82=A6=E3=83=88?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../accounts/accounts.service.spec.ts | 54 +++++++++---------
.../src/features/accounts/accounts.service.ts | 57 ++++++++++---------
2 files changed, 57 insertions(+), 54 deletions(-)
diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts
index e042a85..c76e4fe 100644
--- a/dictation_server/src/features/accounts/accounts.service.spec.ts
+++ b/dictation_server/src/features/accounts/accounts.service.spec.ts
@@ -2645,34 +2645,34 @@ describe('getDealers', () => {
],
});
});
+ // TODO 本番環境デプロイのためにこのテストはスキップする
+ // it('非表示指定されたDealer以外のDealerを取得できる', async () => {
+ // if (!source) fail();
+ // const module = await makeTestingModule(source);
+ // if (!module) fail();
+ // // 100件のDealerを作成し、country,id,company_nameを取得する
+ // const dealers: { country: string; id: number; name: string }[] = [];
+ // for (let i = 0; i < 100; i++) {
+ // const { id, company_name, country } = (
+ // await makeTestAccount(source, {
+ // parent_account_id: i,
+ // tier: TIERS.TIER4,
+ // country: 'JP',
+ // company_name: `DEALER_${i}`,
+ // })
+ // ).account;
+ // dealers.push({ id, name: company_name, country });
+ // }
+ // const service = module.get(AccountsService);
+ // const context = makeContext(`uuidv4`, 'requestId');
+ // const result = await service.getDealers(context);
+ // // idが50と99のDealerを非表示にする
- it('非表示指定されたDealer以外のDealerを取得できる', async () => {
- if (!source) fail();
- const module = await makeTestingModule(source);
- if (!module) fail();
- // 100件のDealerを作成し、country,id,company_nameを取得する
- const dealers: { country: string; id: number; name: string }[] = [];
- for (let i = 0; i < 100; i++) {
- const { id, company_name, country } = (
- await makeTestAccount(source, {
- parent_account_id: i,
- tier: TIERS.TIER4,
- country: 'JP',
- company_name: `DEALER_${i}`,
- })
- ).account;
- dealers.push({ id, name: company_name, country });
- }
- const service = module.get(AccountsService);
- const context = makeContext(`uuidv4`, 'requestId');
- const result = await service.getDealers(context);
- // idが50と99のDealerを非表示にする
-
- expect(result.dealers.length).toBe(98);
- expect(result).toEqual({
- dealers: dealers.filter((dealer) => dealer.id !== 50 && dealer.id !== 99),
- });
- });
+ // expect(result.dealers.length).toBe(98);
+ // expect(result).toEqual({
+ // dealers: dealers.filter((dealer) => dealer.id !== 50 && dealer.id !== 99),
+ // });
+ // });
it('0件でもDealerを取得できる', async () => {
if (!source) fail();
diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts
index 688981b..aaefaf6 100644
--- a/dictation_server/src/features/accounts/accounts.service.ts
+++ b/dictation_server/src/features/accounts/accounts.service.ts
@@ -76,8 +76,9 @@ import { ConfigService } from '@nestjs/config';
@Injectable()
export class AccountsService {
- // プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
- private readonly dealerAccountIdHiddenList: number[] = [];
+ // TODO 本番環境デプロイのためにこの変数はコメントアウトする 2024年4月22日
+ //プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
+ // private readonly dealerAccountIdHiddenList: number[] = [];
private readonly logger = new Logger(AccountsService.name);
constructor(
private readonly accountRepository: AccountsRepositoryService,
@@ -93,20 +94,21 @@ export class AccountsService {
const dealerAccountIdList = this.configService.get(
'DEALER_ACCOUNT_ID_HIDDEN_LIST',
);
+ // TODO 本番環境デプロイのためにこの変数はコメントアウトする 2024年4月22日
// ディーラーアカウントIDリストを数値配列に変換する
// 変換できない場合はエラーをスローする
// 存在しない場合や空文字列の場合は空の配列を返す
- if (dealerAccountIdList) {
- this.dealerAccountIdHiddenList = dealerAccountIdList
- .split(',')
- .map((x) => {
- const id = parseInt(x, 10);
- if (isNaN(id)) {
- throw new Error('DEALER_ACCOUNT_ID_HIDDEN_LIST is invalid');
- }
- return id;
- });
- }
+ // if (dealerAccountIdList) {
+ // this.dealerAccountIdHiddenList = dealerAccountIdList
+ // .split(',')
+ // .map((x) => {
+ // const id = parseInt(x, 10);
+ // if (isNaN(id)) {
+ // throw new Error('DEALER_ACCOUNT_ID_HIDDEN_LIST is invalid');
+ // }
+ // return id;
+ // });
+ // }
}
/**
@@ -1197,26 +1199,27 @@ export class AccountsService {
const dealerAccounts = await this.accountRepository.findDealerAccounts(
context,
);
+ // TODO 本番環境デプロイのためにこの変数はコメントアウトする 2024年4月22日
// プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
// this.dealerAccountIdHiddenListに含まれるアカウント(動作確認用のアカウント)を除外する。
// 除外したアカウントをlogに出力する
- const filteredDealerAccounts = dealerAccounts.filter((dealerAccount) => {
- const isHidden = this.dealerAccountIdHiddenList.includes(
- dealerAccount.id,
- );
- if (isHidden) {
- this.logger.log(
- `[${context.getTrackingId()}] hidden dealer account: ${
- dealerAccount.id
- }`,
- );
- }
- return !isHidden;
- });
+ // const filteredDealerAccounts = dealerAccounts.filter((dealerAccount) => {
+ // const isHidden = this.dealerAccountIdHiddenList.includes(
+ // dealerAccount.id,
+ // );
+ // if (isHidden) {
+ // this.logger.log(
+ // `[${context.getTrackingId()}] hidden dealer account: ${
+ // dealerAccount.id
+ // }`,
+ // );
+ // }
+ // return !isHidden;
+ // });
// レスポンス用の型に変換
const dealers: GetDealersResponse = {
- dealers: filteredDealerAccounts.map((dealerAccount): Dealer => {
+ dealers: dealerAccounts.map((dealerAccount): Dealer => {
return {
id: dealerAccount.id,
name: dealerAccount.company_name,
From ba7196cac16098324ac2e2a60396f5e58d078270 Mon Sep 17 00:00:00 2001
From: "SAITO-PC-3\\saito.k"
Date: Mon, 22 Apr 2024 10:44:56 +0900
Subject: [PATCH 4/9] =?UTF-8?q?=E6=9C=AC=E7=95=AA=E3=83=87=E3=83=97?=
=?UTF-8?q?=E3=83=AD=E3=82=A4=E3=82=88=E3=81=86=E3=81=AB=E3=82=B3=E3=83=A1?=
=?UTF-8?q?=E3=83=B3=E3=83=88=E3=82=A2=E3=82=A6=E3=83=88=E3=81=97=E3=81=9F?=
=?UTF-8?q?=E5=AE=9F=E8=A3=85=E3=82=92=E3=82=82=E3=81=A8=E3=81=AB=E6=88=BB?=
=?UTF-8?q?=E3=81=99?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../accounts/accounts.service.spec.ts | 54 +++++++++---------
.../src/features/accounts/accounts.service.ts | 55 +++++++++----------
2 files changed, 53 insertions(+), 56 deletions(-)
diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts
index c76e4fe..6debabc 100644
--- a/dictation_server/src/features/accounts/accounts.service.spec.ts
+++ b/dictation_server/src/features/accounts/accounts.service.spec.ts
@@ -2645,34 +2645,34 @@ describe('getDealers', () => {
],
});
});
- // TODO 本番環境デプロイのためにこのテストはスキップする
- // it('非表示指定されたDealer以外のDealerを取得できる', async () => {
- // if (!source) fail();
- // const module = await makeTestingModule(source);
- // if (!module) fail();
- // // 100件のDealerを作成し、country,id,company_nameを取得する
- // const dealers: { country: string; id: number; name: string }[] = [];
- // for (let i = 0; i < 100; i++) {
- // const { id, company_name, country } = (
- // await makeTestAccount(source, {
- // parent_account_id: i,
- // tier: TIERS.TIER4,
- // country: 'JP',
- // company_name: `DEALER_${i}`,
- // })
- // ).account;
- // dealers.push({ id, name: company_name, country });
- // }
- // const service = module.get(AccountsService);
- // const context = makeContext(`uuidv4`, 'requestId');
- // const result = await service.getDealers(context);
- // // idが50と99のDealerを非表示にする
+
+ it('非表示指定されたDealer以外のDealerを取得できる', async () => {
+ if (!source) fail();
+ const module = await makeTestingModule(source);
+ if (!module) fail();
+ // 100件のDealerを作成し、country,id,company_nameを取得する
+ const dealers: { country: string; id: number; name: string }[] = [];
+ for (let i = 0; i < 100; i++) {
+ const { id, company_name, country } = (
+ await makeTestAccount(source, {
+ parent_account_id: i,
+ tier: TIERS.TIER4,
+ country: 'JP',
+ company_name: `DEALER_${i}`,
+ })
+ ).account;
+ dealers.push({ id, name: company_name, country });
+ }
+ const service = module.get(AccountsService);
+ const context = makeContext(`uuidv4`, 'requestId');
+ const result = await service.getDealers(context);
+ // idが50と99のDealerを非表示にする
- // expect(result.dealers.length).toBe(98);
- // expect(result).toEqual({
- // dealers: dealers.filter((dealer) => dealer.id !== 50 && dealer.id !== 99),
- // });
- // });
+ expect(result.dealers.length).toBe(98);
+ expect(result).toEqual({
+ dealers: dealers.filter((dealer) => dealer.id !== 50 && dealer.id !== 99),
+ });
+ });
it('0件でもDealerを取得できる', async () => {
if (!source) fail();
diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts
index aaefaf6..94e7e3c 100644
--- a/dictation_server/src/features/accounts/accounts.service.ts
+++ b/dictation_server/src/features/accounts/accounts.service.ts
@@ -76,9 +76,8 @@ import { ConfigService } from '@nestjs/config';
@Injectable()
export class AccountsService {
- // TODO 本番環境デプロイのためにこの変数はコメントアウトする 2024年4月22日
//プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
- // private readonly dealerAccountIdHiddenList: number[] = [];
+ private readonly dealerAccountIdHiddenList: number[] = [];
private readonly logger = new Logger(AccountsService.name);
constructor(
private readonly accountRepository: AccountsRepositoryService,
@@ -94,21 +93,20 @@ export class AccountsService {
const dealerAccountIdList = this.configService.get(
'DEALER_ACCOUNT_ID_HIDDEN_LIST',
);
- // TODO 本番環境デプロイのためにこの変数はコメントアウトする 2024年4月22日
// ディーラーアカウントIDリストを数値配列に変換する
// 変換できない場合はエラーをスローする
// 存在しない場合や空文字列の場合は空の配列を返す
- // if (dealerAccountIdList) {
- // this.dealerAccountIdHiddenList = dealerAccountIdList
- // .split(',')
- // .map((x) => {
- // const id = parseInt(x, 10);
- // if (isNaN(id)) {
- // throw new Error('DEALER_ACCOUNT_ID_HIDDEN_LIST is invalid');
- // }
- // return id;
- // });
- // }
+ if (dealerAccountIdList) {
+ this.dealerAccountIdHiddenList = dealerAccountIdList
+ .split(',')
+ .map((x) => {
+ const id = parseInt(x, 10);
+ if (isNaN(id)) {
+ throw new Error('DEALER_ACCOUNT_ID_HIDDEN_LIST is invalid');
+ }
+ return id;
+ });
+ }
}
/**
@@ -1199,27 +1197,26 @@ export class AccountsService {
const dealerAccounts = await this.accountRepository.findDealerAccounts(
context,
);
- // TODO 本番環境デプロイのためにこの変数はコメントアウトする 2024年4月22日
// プロダクト バックログ項目 4077: [保守]本番環境動作確認用のDealerアカウントを表示しないようにする の対応
// this.dealerAccountIdHiddenListに含まれるアカウント(動作確認用のアカウント)を除外する。
// 除外したアカウントをlogに出力する
- // const filteredDealerAccounts = dealerAccounts.filter((dealerAccount) => {
- // const isHidden = this.dealerAccountIdHiddenList.includes(
- // dealerAccount.id,
- // );
- // if (isHidden) {
- // this.logger.log(
- // `[${context.getTrackingId()}] hidden dealer account: ${
- // dealerAccount.id
- // }`,
- // );
- // }
- // return !isHidden;
- // });
+ const filteredDealerAccounts = dealerAccounts.filter((dealerAccount) => {
+ const isHidden = this.dealerAccountIdHiddenList.includes(
+ dealerAccount.id,
+ );
+ if (isHidden) {
+ this.logger.log(
+ `[${context.getTrackingId()}] hidden dealer account: ${
+ dealerAccount.id
+ }`,
+ );
+ }
+ return !isHidden;
+ });
// レスポンス用の型に変換
const dealers: GetDealersResponse = {
- dealers: dealerAccounts.map((dealerAccount): Dealer => {
+ dealers: filteredDealerAccounts.map((dealerAccount): Dealer => {
return {
id: dealerAccount.id,
name: dealerAccount.company_name,
From af0ba78ae9bda018f93c125ef39c1397f1175e7c Mon Sep 17 00:00:00 2001
From: "saito.k"
Date: Thu, 25 Apr 2024 08:56:03 +0000
Subject: [PATCH 5/9] =?UTF-8?q?Merged=20PR=20883:=20Functions=E4=BF=AE?=
=?UTF-8?q?=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 概要
[Task4132: Functions修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4132)
- 自動割り当てを行うライセンスの取得条件を変更
- 有効期限が近いライセンスまたは有効期限が設定されていないライセンス(新規ライセンス)を取得する
- 有効期限が近いものから割り当てを行うので、ソートはサーバー側で行うようにした
- メール送信処理を追加
## レビューポイント
- テンプレート取得からメール送信までの実装で漏れはないか
- テストケースは足りているか
## UIの変更
- Before/Afterのスクショなど
- スクショ置き場
## クエリの変更
- 2行目で割り当てるライセンスを取得しているが、その条件を修正した
- https://ndstokyo.sharepoint.com/:u:/r/sites/Piranha/Shared%20Documents/General/OMDS/%E3%82%AF%E3%82%A8%E3%83%AA/task4132/after.log?csf=1&web=1&e=jh49c3
## 動作確認状況
- ローカルで確認、develop環境で確認など
- 行った修正がデグレを発生させていないことを確認できるか
- 追加したメール送信処理を確認するように各テストを修正し、テストが通っている
- テストの観点を拡充したうえでテストが通っていることを確認
- ライセンス割り当て履歴の内容をより詳細に確認するようにした
## 補足
- 相談、参考資料などがあれば
---
dictation_function/src/constants/index.ts | 10 +
.../src/functions/licenseAlert.ts | 16 +-
.../src/functions/licenseAutoAllocation.ts | 363 ++++++++++-
.../licenseAutoAllocationManualRetry.ts | 25 +-
dictation_function/src/sendgrid/sendgrid.ts | 27 +-
.../src/templates/template_U_108.html | 81 +++
.../src/templates/template_U_108.txt | 47 ++
.../templates/template_U_108_no_parent.html | 70 ++
.../templates/template_U_108_no_parent.txt | 41 ++
.../src/test/common/adb2c.mock.ts | 88 +++
.../src/test/common/sendGrid.mock.ts | 24 +
dictation_function/src/test/common/utility.ts | 25 +-
.../src/test/licenseAlert.spec.ts | 115 +---
.../src/test/licenseAutoAllocation.spec.ts | 611 ++++++++++++++++--
dictation_function/tsconfig.json | 2 +-
15 files changed, 1369 insertions(+), 176 deletions(-)
create mode 100644 dictation_function/src/templates/template_U_108.html
create mode 100644 dictation_function/src/templates/template_U_108.txt
create mode 100644 dictation_function/src/templates/template_U_108_no_parent.html
create mode 100644 dictation_function/src/templates/template_U_108_no_parent.txt
create mode 100644 dictation_function/src/test/common/adb2c.mock.ts
create mode 100644 dictation_function/src/test/common/sendGrid.mock.ts
diff --git a/dictation_function/src/constants/index.ts b/dictation_function/src/constants/index.ts
index f1e0b64..3975fda 100644
--- a/dictation_function/src/constants/index.ts
+++ b/dictation_function/src/constants/index.ts
@@ -293,3 +293,13 @@ export const HTTP_STATUS_CODES = {
BAD_REQUEST: 400,
INTERNAL_SERVER_ERROR: 500,
};
+
+/**
+ * メールの置換文字列
+ * @const {string}
+ */
+export const CUSTOMER_NAME = "$CUSTOMER_NAME$";
+export const DEALER_NAME = "$DEALER_NAME$";
+export const TOP_URL = "$TOP_URL$";
+export const USER_NAME = "$USER_NAME$";
+export const USER_EMAIL = "$USER_EMAIL$";
\ No newline at end of file
diff --git a/dictation_function/src/functions/licenseAlert.ts b/dictation_function/src/functions/licenseAlert.ts
index 5e7fd6d..f6b5f10 100644
--- a/dictation_function/src/functions/licenseAlert.ts
+++ b/dictation_function/src/functions/licenseAlert.ts
@@ -404,7 +404,9 @@ async function sendAlertMail(
// メールを送信
try {
await sendgrid.sendMail(
- targetAccount.primaryAdminEmail,
+ context,
+ [targetAccount.primaryAdminEmail],
+ [],
mailFrom,
subject,
text,
@@ -464,7 +466,9 @@ async function sendAlertMail(
// メールを送信
try {
await sendgrid.sendMail(
- targetAccount.secondaryAdminEmail,
+ context,
+ [targetAccount.secondaryAdminEmail],
+ [],
mailFrom,
subject,
text,
@@ -523,7 +527,9 @@ async function sendAlertMail(
// メールを送信
try {
await sendgrid.sendMail(
- targetAccount.primaryAdminEmail,
+ context,
+ [targetAccount.primaryAdminEmail],
+ [],
mailFrom,
subject,
text,
@@ -581,7 +587,9 @@ async function sendAlertMail(
// メールを送信
try {
await sendgrid.sendMail(
- targetAccount.secondaryAdminEmail,
+ context,
+ [targetAccount.secondaryAdminEmail],
+ [],
mailFrom,
subject,
text,
diff --git a/dictation_function/src/functions/licenseAutoAllocation.ts b/dictation_function/src/functions/licenseAutoAllocation.ts
index b4b623f..0e08f36 100644
--- a/dictation_function/src/functions/licenseAutoAllocation.ts
+++ b/dictation_function/src/functions/licenseAutoAllocation.ts
@@ -1,14 +1,20 @@
import { app, InvocationContext, Timer } from "@azure/functions";
-import { Between, DataSource, In, MoreThan, Repository } from "typeorm";
+import { Between, DataSource, In, IsNull, MoreThan, Repository } from "typeorm";
import { User } from "../entity/user.entity";
import { Account } from "../entity/account.entity";
import { License, LicenseAllocationHistory } from "../entity/license.entity";
import * as dotenv from "dotenv";
import {
+ ADB2C_SIGN_IN_TYPE,
+ CUSTOMER_NAME,
+ DEALER_NAME,
LICENSE_ALLOCATED_STATUS,
LICENSE_TYPE,
SWITCH_FROM_TYPE,
TIERS,
+ TOP_URL,
+ USER_EMAIL,
+ USER_NAME,
USER_ROLES,
} from "../constants";
import {
@@ -16,10 +22,19 @@ import {
DateWithZeroTime,
NewAllocatedLicenseExpirationDate,
} from "../common/types/types";
+import { readFileSync } from "fs";
+import path from "path";
+import { SendGridService } from "../sendgrid/sendgrid";
+import { AdB2cService } from "../adb2c/adb2c";
+import { RedisClient } from "redis";
+import { createRedisClient } from "../redis/redis";
export async function licenseAutoAllocationProcessing(
context: InvocationContext,
datasource: DataSource,
+ redisClient: RedisClient,
+ sendGrid: SendGridService,
+ adb2c: AdB2cService,
dateToTrigger?: Date
): Promise {
try {
@@ -32,6 +47,7 @@ export async function licenseAutoAllocationProcessing(
currentDateZeroTime = new DateWithZeroTime(dateToTrigger);
currentDateEndTime = new DateWithDayEndTime(dateToTrigger);
}
+
// 自動更新対象の候補となるアカウントを取得
const accountRepository = datasource.getRepository(Account);
const targetAccounts = await accountRepository.find({
@@ -55,6 +71,9 @@ export async function licenseAutoAllocationProcessing(
await allocateLicense(
context,
datasource,
+ redisClient,
+ sendGrid,
+ adb2c,
autoAllocationList,
currentDateZeroTime,
currentDateEndTime
@@ -94,8 +113,25 @@ export async function licenseAutoAllocation(
context.error(e);
throw e;
}
+ let redisClient: RedisClient;
+ try {
+ // redis接続
+ redisClient = createRedisClient();
+ } catch (e) {
+ context.log("redis client create failed.");
+ context.error(e);
+ throw e;
+ }
+ const sendGrid = new SendGridService();
+ const adb2c = new AdB2cService();
- await licenseAutoAllocationProcessing(context, datasource);
+ await licenseAutoAllocationProcessing(
+ context,
+ datasource,
+ redisClient,
+ sendGrid,
+ adb2c
+ );
} catch (e) {
context.log("licenseAutoAllocation failed.");
context.error(e);
@@ -215,24 +251,45 @@ export async function getAutoAllocatableLicense(
try {
context.log("[IN]getAutoAllocatableLicense");
// 割り当て可能なライセンスを取得
- const license = await licenseRepository.findOne({
- where: {
- account_id: accountId,
- status: In([
- LICENSE_ALLOCATED_STATUS.REUSABLE,
- LICENSE_ALLOCATED_STATUS.UNALLOCATED,
- ]),
- expiry_date: MoreThan(currentDateEndTime) || null,
- },
- order: {
- expiry_date: "ASC",
- },
+ const license = await licenseRepository.find({
+ where: [
+ {
+ account_id: accountId,
+ status: In([
+ LICENSE_ALLOCATED_STATUS.REUSABLE,
+ LICENSE_ALLOCATED_STATUS.UNALLOCATED,
+ ]),
+ expiry_date: MoreThan(currentDateEndTime),
+ },
+ {
+ account_id: accountId,
+ status: In([
+ LICENSE_ALLOCATED_STATUS.REUSABLE,
+ LICENSE_ALLOCATED_STATUS.UNALLOCATED,
+ ]),
+ expiry_date: IsNull(),
+ },
+ ],
});
- if (!license) {
+ if (license.length === 0) {
// 割り当て可能なライセンスが存在しない場合でもエラーとはしたくないので、undifinedを返却する
return undefined;
}
- return license;
+ // ライセンスをソートする
+ // 有効期限が近いものから割り当てるため、expiry_dateがnullのものは最後にする
+ const sortedLicense = license.sort((a, b) => {
+ if (a.expiry_date && b.expiry_date) {
+ return a.expiry_date.getTime() - b.expiry_date.getTime();
+ } else if (a.expiry_date && !b.expiry_date) {
+ return -1;
+ } else if (!a.expiry_date && b.expiry_date) {
+ return 1;
+ } else {
+ return 0;
+ }
+ });
+ // 有効期限が近いライセンスを返却する
+ return sortedLicense[0];
} catch (e) {
context.error(e);
context.log("getAutoAllocatableLicense failed.");
@@ -253,17 +310,23 @@ export async function getAutoAllocatableLicense(
export async function allocateLicense(
context: InvocationContext,
datasource: DataSource,
+ redisClient: RedisClient,
+ sendGrid: SendGridService,
+ adb2c: AdB2cService,
autoAllocationList: autoAllocationList,
currentDateZeroTime: DateWithZeroTime,
currentDateEndTime: DateWithDayEndTime
): Promise {
+ context.log("[IN]allocateLicense");
try {
- context.log("[IN]allocateLicense");
-
- // 自動更新対象ユーザーにライセンスを割り当てる
+ // 割り当て可能なライセンスが存在するかどうかのフラグ
let hasAllocatebleLicense = true;
+ // ユーザーに割り当てられているライセンスが自動更新対象であるかどうかのフラグ
+ let hasAutoRenewLicense = true;
for (const userId of autoAllocationList.userIds) {
await datasource.transaction(async (entityManager) => {
+ // フラグの初期化
+ hasAutoRenewLicense = true;
const licenseRepository = entityManager.getRepository(License);
const licenseAllocationHistoryRepo = entityManager.getRepository(
LicenseAllocationHistory
@@ -292,6 +355,7 @@ export async function allocateLicense(
});
if (!allocatedLicense) {
context.log(`skip auto allocation. userID:${userId}`);
+ hasAutoRenewLicense = false;
return;
}
@@ -365,17 +429,276 @@ export async function allocateLicense(
if (!hasAllocatebleLicense) {
break;
}
+
+ // ユーザーに割り当てられているライセンスが自動更新対象であるかどうかのフラグがfalseの場合、次のユーザーへ
+ if (!hasAutoRenewLicense) {
+ continue;
+ }
+
+ try {
+ //メール送信に必要な情報をDBから取得
+ const userRepository = datasource.getRepository(User);
+ const accountRepository = datasource.getRepository(Account);
+
+ // ライセンスを割り当てたユーザーとアカウントの情報を取得
+ const user = await userRepository.findOne({
+ where: { id: userId },
+ });
+ if (!user) {
+ throw new Error(`Target user not found. ${userId}`);
+ }
+ const account = await accountRepository.findOne({
+ where: { id: autoAllocationList.accountId },
+ relations: {
+ primaryAdminUser: true,
+ secondaryAdminUser: true,
+ },
+ });
+ if (!account) {
+ throw new Error(
+ `Target account not found. ${autoAllocationList.accountId}`
+ );
+ }
+ // アカウントのプライマリー管理者が存在しない場合はエラー
+ if (!account.primaryAdminUser) {
+ throw new Error(
+ `Primary admin user not found. accountID: ${account.id}`
+ );
+ }
+ // 親アカウントが存在する場合は取得
+ let parentAccount: Account | null = null;
+ if (account.parent_account_id) {
+ parentAccount = await accountRepository.findOne({
+ where: { id: account.parent_account_id },
+ });
+ if (!parentAccount) {
+ throw new Error(
+ `Parent account not found. accountID: ${account.parent_account_id}`
+ );
+ }
+ }
+
+ // アカウントの管理者とライセンスを割り当てたユーザーのメールアドレス取得に必要な外部IDを抽出
+ const externalIds: string[] = [];
+ externalIds.push(user.external_id);
+ externalIds.push(account.primaryAdminUser.external_id);
+ // セカンダリ管理者が存在する場合はセカンダリ管理者の外部IDも抽出
+ if (account.secondaryAdminUser) {
+ externalIds.push(account.secondaryAdminUser.external_id);
+ }
+ const adb2cUsers = await getMailAddressAndDisplayNameList(
+ context,
+ redisClient,
+ adb2c,
+ externalIds
+ );
+ // ライセンス割り当てされたユーザーの名前を取得
+ const userName = adb2cUsers.find(
+ (adb2cUser) => adb2cUser.externalId === user.external_id
+ )?.displayName;
+ if (!userName) {
+ throw new Error(
+ `Target ADb2Cuser name not found. externalId=${user.external_id}`
+ );
+ }
+ // ライセンス割り当てされたユーザーのメールアドレスを取得
+ const userMail = adb2cUsers.find(
+ (adb2cUser) => adb2cUser.externalId === user.external_id
+ )?.mailAddress;
+ if (!userMail) {
+ throw new Error(
+ `Target ADb2Cuser mail not found. externalId=${user.external_id}`
+ );
+ }
+ // アカウントのプライマリー管理者のメールアドレスを取得
+ const adminMails: string[] = [];
+ const primaryAdminMail = adb2cUsers.find(
+ (adb2cUser) =>
+ adb2cUser.externalId === account.primaryAdminUser?.external_id
+ )?.mailAddress;
+ if (!primaryAdminMail) {
+ throw new Error(
+ `Primary admin user mail not found. externalId=${account.primaryAdminUser.external_id}`
+ );
+ }
+ adminMails.push(primaryAdminMail);
+
+ // アカウントのセカンダリ管理者のメールアドレスを取得
+ const secondaryAdminMail = adb2cUsers.find(
+ (adb2cUser) =>
+ adb2cUser.externalId === account.secondaryAdminUser?.external_id
+ )?.mailAddress;
+ if (secondaryAdminMail) {
+ adminMails.push(secondaryAdminMail);
+ }
+
+ // メール送信
+ await sendMailWithU108(
+ context,
+ userName,
+ userMail,
+ adminMails,
+ account.company_name,
+ parentAccount ? parentAccount.company_name : null,
+ sendGrid
+ );
+ } catch (e) {
+ context.error(`error=${e}`);
+ // メール送信に関する例外はログだけ出して握りつぶす
+ }
}
} catch (e) {
// エラーが発生しても次のアカウントへの処理は継続させるため、例外をthrowせずにreturnだけする
- context.error(e);
context.log("allocateLicense failed.");
+ context.error(e);
return;
} finally {
context.log("[OUT]allocateLicense");
}
}
+// adb2cから指定した外部IDのユーザー情報を取得する
+export async function getMailAddressAndDisplayNameList(
+ context: InvocationContext,
+ redisClient: RedisClient,
+ adb2c: AdB2cService,
+ externalIds: string[]
+): Promise<
+ {
+ externalId: string;
+ displayName: string;
+ mailAddress: string;
+ }[]
+> {
+ context.log("[IN]getUsers");
+ try {
+ const users = [] as {
+ externalId: string;
+ displayName: string;
+ mailAddress: string;
+ }[];
+ // 外部IDからADB2Cユーザー情報を取得
+ const adb2cUsers = await adb2c.getUsers(context, redisClient, externalIds);
+ for (const externalId of externalIds) {
+ const adb2cUser = adb2cUsers.find((user) => user.id === externalId);
+ if (!adb2cUser) {
+ throw new Error(`ADB2C user not found. externalId=${externalId}`);
+ }
+ const mailAddress = adb2cUser.identities?.find(
+ (identity) => identity.signInType === ADB2C_SIGN_IN_TYPE.EMAILADDRESS
+ )?.issuerAssignedId;
+ if (!mailAddress) {
+ throw new Error(`ADB2C user mail not found. externalId=${externalId}`);
+ }
+ users.push({
+ externalId: externalId,
+ displayName: adb2cUser.displayName,
+ mailAddress: mailAddress,
+ });
+ }
+ return users;
+ } catch (e) {
+ context.error(e);
+ context.log("getUsers failed.");
+ throw e;
+ } finally {
+ context.log("[OUT]getUsers");
+ }
+}
+
+/**
+ * U-108のテンプレートを使用したメールを送信する
+ * @param context
+ * @param userName ライセンス割り当てされたユーザーの名前
+ * @param userMail ライセンス割り当てされたユーザーのメールアドレス
+ * @param customerAdminMails ライセンス割り当てされたユーザーの所属するアカウントの管理者(primary/secondary)のメールアドレス
+ * @param customerAccountName ライセンス割り当てされたユーザーの所属するアカウントの名前
+ * @param dealerAccountName 問題発生時に問い合わせする先の上位のディーラー名(会社名)
+ * @returns mail with u108
+ */
+export async function sendMailWithU108(
+ context: InvocationContext,
+ userName: string,
+ userMail: string,
+ customerAdminMails: string[],
+ customerAccountName: string,
+ dealerAccountName: string | null,
+ sendGrid: SendGridService
+): Promise {
+ context.log("[IN] sendMailWithU108");
+ try {
+ const subject = "License Assigned Notification [U-108]";
+ const domain = process.env.APP_DOMAIN;
+ if (!domain) {
+ throw new Error("APP_DOMAIN is not defined.");
+ }
+ const mailFrom = process.env.MAIL_FROM;
+ if (!mailFrom) {
+ throw new Error("MAIL_FROM is not defined.");
+ }
+ const url = new URL(domain).href;
+
+ let html: string;
+ let text: string;
+
+ if (dealerAccountName === null) {
+ const templateU108NoParentHtml = readFileSync(
+ path.resolve(__dirname, `../templates/template_U_108_no_parent.html`),
+ "utf-8"
+ );
+ const templateU108NoParentText = readFileSync(
+ path.resolve(__dirname, `../templates/template_U_108_no_parent.txt`),
+ "utf-8"
+ );
+ html = templateU108NoParentHtml
+ .replaceAll(CUSTOMER_NAME, customerAccountName)
+ .replaceAll(USER_NAME, userName)
+ .replaceAll(USER_EMAIL, userMail)
+ .replaceAll(TOP_URL, url);
+ text = templateU108NoParentText
+ .replaceAll(CUSTOMER_NAME, customerAccountName)
+ .replaceAll(USER_NAME, userName)
+ .replaceAll(USER_EMAIL, userMail)
+ .replaceAll(TOP_URL, url);
+ } else {
+ const templateU108Html = readFileSync(
+ path.resolve(__dirname, `../templates/template_U_108.html`),
+ "utf-8"
+ );
+ const templateU108Text = readFileSync(
+ path.resolve(__dirname, `../templates/template_U_108.txt`),
+ "utf-8"
+ );
+ html = templateU108Html
+ .replaceAll(CUSTOMER_NAME, customerAccountName)
+ .replaceAll(DEALER_NAME, dealerAccountName)
+ .replaceAll(USER_NAME, userName)
+ .replaceAll(USER_EMAIL, userMail)
+ .replaceAll(TOP_URL, url);
+ text = templateU108Text
+ .replaceAll(CUSTOMER_NAME, customerAccountName)
+ .replaceAll(DEALER_NAME, dealerAccountName)
+ .replaceAll(USER_NAME, userName)
+ .replaceAll(USER_EMAIL, userMail)
+ .replaceAll(TOP_URL, url);
+ }
+ const ccAddress = customerAdminMails.includes(userMail) ? [] : [userMail];
+
+ // メールを送信する
+ await sendGrid.sendMail(
+ context,
+ customerAdminMails,
+ ccAddress,
+ mailFrom,
+ subject,
+ text,
+ html
+ );
+ } finally {
+ context.log(`[OUT] sendMailWithU108`);
+ }
+}
+
app.timer("licenseAutoAllocation", {
schedule: "0 0 16 * * *",
handler: licenseAutoAllocation,
diff --git a/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts b/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts
index 18fa0f2..5864510 100644
--- a/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts
+++ b/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts
@@ -12,6 +12,10 @@ import { User } from "../entity/user.entity";
import { Account } from "../entity/account.entity";
import { License, LicenseAllocationHistory } from "../entity/license.entity";
import { HTTP_METHODS, HTTP_STATUS_CODES } from "../constants";
+import { RedisClient } from "redis";
+import { createRedisClient } from "../redis/redis";
+import { AdB2cService } from "../adb2c/adb2c";
+import { SendGridService } from "../sendgrid/sendgrid";
export async function licenseAutoAllocationManualRetry(
req: HttpRequest,
@@ -57,8 +61,27 @@ export async function licenseAutoAllocationManualRetry(
context.error(e);
throw e;
}
+ let redisClient: RedisClient;
+ try {
+ // redis接続
+ redisClient = createRedisClient();
+ } catch (e) {
+ context.log("redis client create failed.");
+ context.error(e);
+ throw e;
+ }
+ const sendGrid = new SendGridService();
+ const adb2c = new AdB2cService();
+
- await licenseAutoAllocationProcessing(context, datasource, dateToTrigger);
+ await licenseAutoAllocationProcessing(
+ context,
+ datasource,
+ redisClient,
+ sendGrid,
+ adb2c,
+ dateToTrigger
+ );
context.log("Automatic license allocation has been triggered.");
return {
status: HTTP_STATUS_CODES.OK,
diff --git a/dictation_function/src/sendgrid/sendgrid.ts b/dictation_function/src/sendgrid/sendgrid.ts
index cb90de1..ef8e049 100644
--- a/dictation_function/src/sendgrid/sendgrid.ts
+++ b/dictation_function/src/sendgrid/sendgrid.ts
@@ -1,3 +1,4 @@
+import { InvocationContext } from "@azure/functions";
import sendgrid from "@sendgrid/mail";
import { error } from "console";
@@ -9,9 +10,11 @@ export class SendGridService {
sendgrid.setApiKey(process.env.SENDGRID_API_KEY);
}
- /**
+ /**
* メールを送信する
+ * @param context
* @param to
+ * @param cc
* @param from
* @param subject
* @param text
@@ -19,28 +22,40 @@ export class SendGridService {
* @returns mail
*/
async sendMail(
- to: string,
+ context: InvocationContext,
+ to: string[],
+ cc: string[],
from: string,
subject: string,
text: string,
- html: string
+ html: string,
): Promise {
+ context.log(`[IN] ${this.sendMail.name}`);
try {
const res = await sendgrid
.send({
from: {
email: from,
},
- to: {
- email: to,
- },
+ to: to.map((v) => ({ email: v })),
+ cc: cc.map((v) => ({ email: v })),
subject: subject,
text: text,
html: html,
})
.then((v) => v[0]);
+ context.log(
+ ` status code: ${
+ res.statusCode
+ } body: ${JSON.stringify(res.body)}`,
+ );
} catch (e) {
+ context.warn(`send mail faild.`);
+ context.warn(`${this.sendMail.name} error=${e}`);
throw e;
+ } finally {
+ context.log(`[OUT] ${this.sendMail.name}`);
}
}
}
+
diff --git a/dictation_function/src/templates/template_U_108.html b/dictation_function/src/templates/template_U_108.html
new file mode 100644
index 0000000..0ba001c
--- /dev/null
+++ b/dictation_function/src/templates/template_U_108.html
@@ -0,0 +1,81 @@
+
+
+ License Assigned Notification [U-108]
+
+
+
+
<English>
+
Dear $CUSTOMER_NAME$,
+
+ Please be informed that a license has been assigned to the following
+ user.
+ - User Name: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+
+ Please log in to ODMS Cloud to verify the license expiration date.
+ URL: $TOP_URL$
+
+
+ If you need support regarding ODMS Cloud, please contact $DEALER_NAME$.
+
+
+ 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$,
+
+ Bitte beachten Sie, dass dem folgenden Benutzer eine Lizenz zugewiesen
+ wurde.
+ - Nutzername: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+
+ Bitte melden Sie sich bei ODMS Cloud an, um das Ablaufdatum der Lizenz
+ zu überprüfen.
+ URL: $TOP_URL$
+
+
+ Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich
+ bitte an $DEALER_NAME$.
+
+
+ Wenn Sie diese E-Mail irrtümlich erhalten haben, löschen Sie diese
+ E-Mail bitte aus Ihrem System.
+ Dies ist eine automatisch generierte
+ E-Mail und diese Mailbox wird nicht überwacht. Bitte antworten Sie
+ nicht.
+
+
+
+
<Français>
+
Chère/Cher $CUSTOMER_NAME$,
+
+ Veuillez être informé qu'une licence a été attribuée à l'utilisateur
+ suivant.
+ - Nom d'utilisateur: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+
+ Veuillez vous connecter à ODMS Cloud pour vérifier la date d'expiration
+ de la licence.
+ URL: $TOP_URL$
+
+
+ Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez
+ contacter $DEALER_NAME$.
+
+
+ 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_function/src/templates/template_U_108.txt b/dictation_function/src/templates/template_U_108.txt
new file mode 100644
index 0000000..3615550
--- /dev/null
+++ b/dictation_function/src/templates/template_U_108.txt
@@ -0,0 +1,47 @@
+
+
+Dear $CUSTOMER_NAME$,
+
+Please be informed that a license has been assigned to the following user.
+ - User Name: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+Please log in to ODMS Cloud to verify the license expiration date.
+URL: $TOP_URL$
+
+If you need support regarding ODMS Cloud, please contact $DEALER_NAME$.
+
+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$,
+
+Bitte beachten Sie, dass dem folgenden Benutzer eine Lizenz zugewiesen wurde.
+ - Nutzername: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+Bitte melden Sie sich bei ODMS Cloud an, um das Ablaufdatum der Lizenz zu überprüfen.
+URL: $TOP_URL$
+
+Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $DEALER_NAME$.
+
+Wenn Sie diese E-Mail irrtümlich erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
+Dies ist eine automatisch generierte E-Mail und diese Mailbox wird nicht überwacht. Bitte antworten Sie nicht.
+
+
+
+Chère/Cher $CUSTOMER_NAME$,
+
+Veuillez être informé qu'une licence a été attribuée à l'utilisateur suivant.
+ - Nom d'utilisateur: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+Veuillez vous connecter à ODMS Cloud pour vérifier la date d'expiration de la licence.
+URL: $TOP_URL$
+
+Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $DEALER_NAME$.
+
+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
diff --git a/dictation_function/src/templates/template_U_108_no_parent.html b/dictation_function/src/templates/template_U_108_no_parent.html
new file mode 100644
index 0000000..6f93225
--- /dev/null
+++ b/dictation_function/src/templates/template_U_108_no_parent.html
@@ -0,0 +1,70 @@
+
+
+ License Assigned Notification [U-108]
+
+
+
+
<English>
+
Dear $CUSTOMER_NAME$,
+
+ Please be informed that a license has been assigned to the following
+ user.
+ - User Name: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+
+ Please log in to ODMS Cloud to verify the license expiration date.
+ 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$,
+
+ Bitte beachten Sie, dass dem folgenden Benutzer eine Lizenz zugewiesen
+ wurde.
+ - Nutzername: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+
+ Bitte melden Sie sich bei ODMS Cloud an, um das Ablaufdatum der Lizenz
+ zu überprüfen.
+ URL: $TOP_URL$
+
+
+ Wenn Sie diese E-Mail irrtümlich erhalten haben, löschen Sie diese
+ E-Mail bitte aus Ihrem System.
+ Dies ist eine automatisch generierte
+ E-Mail und diese Mailbox wird nicht überwacht. Bitte antworten Sie
+ nicht.
+
+
+
+
<Français>
+
Chère/Cher $CUSTOMER_NAME$,
+
+ Veuillez être informé qu'une licence a été attribuée à l'utilisateur
+ suivant.
+ - Nom d'utilisateur: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+
+ Veuillez vous connecter à ODMS Cloud pour vérifier la date d'expiration
+ de la licence.
+ 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_function/src/templates/template_U_108_no_parent.txt b/dictation_function/src/templates/template_U_108_no_parent.txt
new file mode 100644
index 0000000..8c07856
--- /dev/null
+++ b/dictation_function/src/templates/template_U_108_no_parent.txt
@@ -0,0 +1,41 @@
+
+
+Dear $CUSTOMER_NAME$,
+
+Please be informed that a license has been assigned to the following user.
+ - User Name: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+Please log in to ODMS Cloud to verify the license expiration date.
+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$,
+
+Bitte beachten Sie, dass dem folgenden Benutzer eine Lizenz zugewiesen wurde.
+ - Nutzername: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+Bitte melden Sie sich bei ODMS Cloud an, um das Ablaufdatum der Lizenz zu überprüfen.
+URL: $TOP_URL$
+
+Wenn Sie diese E-Mail irrtümlich erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
+Dies ist eine automatisch generierte E-Mail und diese Mailbox wird nicht überwacht. Bitte antworten Sie nicht.
+
+
+
+Chère/Cher $CUSTOMER_NAME$,
+
+Veuillez être informé qu'une licence a été attribuée à l'utilisateur suivant.
+ - Nom d'utilisateur: $USER_NAME$
+ - Email: $USER_EMAIL$
+
+Veuillez vous connecter à ODMS Cloud pour vérifier la date d'expiration de la licence.
+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
diff --git a/dictation_function/src/test/common/adb2c.mock.ts b/dictation_function/src/test/common/adb2c.mock.ts
new file mode 100644
index 0000000..aa0a59b
--- /dev/null
+++ b/dictation_function/src/test/common/adb2c.mock.ts
@@ -0,0 +1,88 @@
+import { InvocationContext } from "@azure/functions";
+import { AdB2cUser } from "../../adb2c/types/types";
+import { ADB2C_SIGN_IN_TYPE } from "../../constants";
+import { RedisClient } from "redis-mock";
+
+// テスト用adb2c
+export class AdB2cServiceMock {
+ /**
+ * Azure AD B2Cからユーザ情報を取得する
+ * @param externalIds 外部ユーザーID
+ * @returns ユーザ情報
+ */
+ async getUsers(
+ context: InvocationContext,
+ redisClient: RedisClient,
+ externalIds: string[]
+ ): Promise {
+ const AdB2cMockUsers: AdB2cUser[] = [
+ {
+ id: "external_id1",
+ displayName: "test1",
+ identities: [
+ {
+ signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
+ issuer: "issuer",
+ issuerAssignedId: "test1@mail.com",
+ },
+ ],
+ },
+ {
+ id: "external_id2",
+ displayName: "test2",
+ identities: [
+ {
+ signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
+ issuer: "issuer",
+ issuerAssignedId: "test2@mail.com",
+ },
+ ],
+ },
+ {
+ id: "external_id3",
+ displayName: "test3",
+ identities: [
+ {
+ signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
+ issuer: "issuer",
+ issuerAssignedId: "test3@mail.com",
+ },
+ ],
+ },
+ {
+ id: "external_id4",
+ displayName: "test4",
+ identities: [
+ {
+ signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
+ issuer: "issuer",
+ issuerAssignedId: "test4@mail.com",
+ },
+ ],
+ },
+ {
+ id: "external_id5",
+ displayName: "test5",
+ identities: [
+ {
+ signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
+ issuer: "issuer",
+ issuerAssignedId: "test5@mail.com",
+ },
+ ],
+ },
+ {
+ id: "external_id6",
+ displayName: "test6",
+ identities: [
+ {
+ signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
+ issuer: "issuer",
+ issuerAssignedId: "test6@mail.com",
+ },
+ ],
+ },
+ ];
+ return AdB2cMockUsers;
+ }
+}
diff --git a/dictation_function/src/test/common/sendGrid.mock.ts b/dictation_function/src/test/common/sendGrid.mock.ts
new file mode 100644
index 0000000..7abfc30
--- /dev/null
+++ b/dictation_function/src/test/common/sendGrid.mock.ts
@@ -0,0 +1,24 @@
+import { InvocationContext } from "@azure/functions";
+
+export class SendGridServiceMock {
+ /**
+ * メールを送信する
+ * @param to
+ * @param from
+ * @param subject
+ * @param text
+ * @param html
+ * @returns mail
+ */
+ async sendMail(
+ context: InvocationContext,
+ to: string[],
+ cc: string[],
+ from: string,
+ subject: string,
+ text: string,
+ html: string
+ ): Promise {
+ return;
+ }
+}
diff --git a/dictation_function/src/test/common/utility.ts b/dictation_function/src/test/common/utility.ts
index 3db9a67..7cec394 100644
--- a/dictation_function/src/test/common/utility.ts
+++ b/dictation_function/src/test/common/utility.ts
@@ -173,7 +173,7 @@ export const makeTestAccount = async (
};
};
-export const createLicense = async (
+export const createAndAllocateLicense = async (
datasource: DataSource,
licenseId: number,
expiry_date: Date | null,
@@ -201,6 +201,29 @@ export const createLicense = async (
updated_at: new Date(),
});
identifiers.pop() as License;
+ // 割り当てるユーザーがいない場合は履歴を作成しない
+ if (!allocated_user_id) {
+ return;
+ }
+ // switch_from_typeを作成
+ // typeが"CARD"の場合は"CARD","TRIAL"の場合は"TRIAL","NORMAL"の場合は"NONE"を設定
+
+ const switch_from_type =
+ type === "CARD" ? "CARD" : type === "TRIAL" ? "TRIAL" : "NONE";
+
+ // ライセンスの割り当て履歴を作成
+ await datasource.getRepository(LicenseAllocationHistory).insert({
+ license_id: licenseId,
+ account_id: accountId,
+ user_id: allocated_user_id ?? -1,
+ is_allocated: true,
+ switch_from_type: switch_from_type,
+ executed_at: new Date(),
+ created_by: "test_runner",
+ created_at: new Date(),
+ updated_by: "updater",
+ updated_at: new Date(),
+ });
};
export const selectLicenseByAllocatedUser = async (
diff --git a/dictation_function/src/test/licenseAlert.spec.ts b/dictation_function/src/test/licenseAlert.spec.ts
index 610fe7e..42cfc51 100644
--- a/dictation_function/src/test/licenseAlert.spec.ts
+++ b/dictation_function/src/test/licenseAlert.spec.ts
@@ -1,6 +1,6 @@
import { DataSource } from "typeorm";
import { licenseAlertProcessing } from "../functions/licenseAlert";
-import { makeTestAccount, createLicense } from "./common/utility";
+import { makeTestAccount, createAndAllocateLicense } from "./common/utility";
import * as dotenv from "dotenv";
import {
DateWithDayEndTime,
@@ -8,13 +8,13 @@ import {
ExpirationThresholdDate,
NewTrialLicenseExpirationDate,
} from "../common/types/types";
-import { AdB2cUser } from "../adb2c/types/types";
-import { ADB2C_SIGN_IN_TYPE } from "../constants";
import { SendGridService } from "../sendgrid/sendgrid";
import { AdB2cService } from "../adb2c/adb2c";
import { InvocationContext } from "@azure/functions";
-import { RedisClient, createClient } from "redis-mock";
+import { createClient } from "redis-mock";
import { promisify } from "util";
+import { SendGridServiceMock } from "./common/sendGrid.mock";
+import { AdB2cServiceMock } from "./common/adb2c.mock";
describe("licenseAlert", () => {
dotenv.config({ path: ".env" });
@@ -56,7 +56,7 @@ describe("licenseAlert", () => {
{ tier: 5 },
{ external_id: "external_id1", accepted_dpa_version: null }
);
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
expiringSoonDate,
@@ -103,7 +103,7 @@ describe("licenseAlert", () => {
accepted_dpa_version: null,
}
);
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
expiringSoonDate,
@@ -147,7 +147,7 @@ describe("licenseAlert", () => {
{ tier: 5 },
{ external_id: "external_id3", accepted_dpa_version: null }
);
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
expiringSoonDate,
@@ -159,7 +159,7 @@ describe("licenseAlert", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
2,
expiryDate,
@@ -206,7 +206,7 @@ describe("licenseAlert", () => {
accepted_dpa_version: null,
}
);
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
expiringSoonDate,
@@ -254,7 +254,7 @@ describe("licenseAlert", () => {
accepted_privacy_notice_version: null,
}
);
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
expiringSoonDate,
@@ -278,97 +278,6 @@ describe("licenseAlert", () => {
});
});
-// テスト用sendgrid
-export class SendGridServiceMock {
- /**
- * メールを送信する
- * @param to
- * @param from
- * @param subject
- * @param text
- * @param html
- * @returns mail
- */
- async sendMail(
- to: string,
- from: string,
- subject: string,
- text: string,
- html: string
- ): Promise {
- return;
- }
-}
-// テスト用adb2c
-export class AdB2cServiceMock {
- /**
- * Azure AD B2Cからユーザ情報を取得する
- * @param externalIds 外部ユーザーID
- * @returns ユーザ情報
- */
- async getUsers(
- context: InvocationContext,
- redisClient: RedisClient,
- externalIds: string[]
- ): Promise {
- const AdB2cMockUsers: AdB2cUser[] = [
- {
- id: "external_id1",
- displayName: "test1",
- identities: [
- {
- signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
- issuer: "issuer",
- issuerAssignedId: "test1@mail.com",
- },
- ],
- },
- {
- id: "external_id2",
- displayName: "test2",
- identities: [
- {
- signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
- issuer: "issuer",
- issuerAssignedId: "test2@mail.com",
- },
- ],
- },
- {
- id: "external_id3",
- displayName: "test3",
- identities: [
- {
- signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
- issuer: "issuer",
- issuerAssignedId: "test3@mail.com",
- },
- ],
- },
- {
- id: "external_id4",
- displayName: "test4",
- identities: [
- {
- signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
- issuer: "issuer",
- issuerAssignedId: "test4@mail.com",
- },
- ],
- },
- {
- id: "external_id5",
- displayName: "test5",
- identities: [
- {
- signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS,
- issuer: "issuer",
- issuerAssignedId: "test5@mail.com",
- },
- ],
- },
- ];
- return AdB2cMockUsers;
- }
-}
+
+
diff --git a/dictation_function/src/test/licenseAutoAllocation.spec.ts b/dictation_function/src/test/licenseAutoAllocation.spec.ts
index d0bf9ef..24919e4 100644
--- a/dictation_function/src/test/licenseAutoAllocation.spec.ts
+++ b/dictation_function/src/test/licenseAutoAllocation.spec.ts
@@ -8,18 +8,24 @@ import {
import { DateWithDayEndTime } from "../common/types/types";
import {
makeTestAccount,
- createLicense,
+ createAndAllocateLicense,
makeTestUser,
selectLicenseByAllocatedUser,
selectLicenseAllocationHistory,
} from "./common/utility";
import * as dotenv from "dotenv";
import { InvocationContext } from "@azure/functions";
+import { AdB2cService } from "../adb2c/adb2c";
+import { SendGridService } from "../sendgrid/sendgrid";
+import { SendGridServiceMock } from "./common/sendGrid.mock";
+import { AdB2cServiceMock } from "./common/adb2c.mock";
+import { createClient } from "redis-mock";
describe("licenseAutoAllocation", () => {
dotenv.config({ path: ".env" });
dotenv.config({ path: ".env.local", override: true });
let source: DataSource | null = null;
+ const redisClient = createClient();
beforeEach(async () => {
source = new DataSource({
type: "sqlite",
@@ -40,33 +46,39 @@ describe("licenseAutoAllocation", () => {
it("有効期限が本日のライセンスが自動更新されること", async () => {
if (!source) fail();
const context = new InvocationContext();
-
+ const sendgridMock = new SendGridServiceMock() as SendGridService;
+ const adb2cMock = new AdB2cServiceMock() as AdB2cService;
+ // 呼び出し回数でテスト成否を判定
+ const spySend = jest.spyOn(sendgridMock, "sendMail");
const currentDateEndTime = new DateWithDayEndTime();
// アカウント
const account1 = await makeTestAccount(
source,
{ tier: 5 },
- { role: `${USER_ROLES.NONE}` }
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id1" }
);
const account2 = await makeTestAccount(
source,
{ tier: 5 },
- { role: `${USER_ROLES.NONE}` }
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id6" }
);
// 更新対象のユーザー(3role分)
const user1 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.NONE}`,
+ external_id: "external_id2",
});
const user2 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.AUTHOR}`,
+ external_id: "external_id3",
});
const user3 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.TYPIST}`,
+ external_id: "external_id4",
});
// 更新対象ではないユーザー(まだ有効期限が残っている)
@@ -90,10 +102,11 @@ describe("licenseAutoAllocation", () => {
const user7 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.NONE}`,
+ external_id: "external_id5",
});
// 割り当て済みで有効期限が本日のライセンス
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
currentDateEndTime,
@@ -105,7 +118,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
2,
currentDateEndTime,
@@ -117,7 +130,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
3,
currentDateEndTime,
@@ -129,7 +142,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
20,
currentDateEndTime,
@@ -141,7 +154,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
5,
currentDateEndTime,
@@ -153,7 +166,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
6,
currentDateEndTime,
@@ -165,7 +178,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
7,
currentDateEndTime,
@@ -183,7 +196,7 @@ describe("licenseAutoAllocation", () => {
nextDate.setDate(nextDate.getDate() + 1);
nextDate.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
nextDate.setMilliseconds(0);
- await createLicense(
+ await createAndAllocateLicense(
source,
4,
nextDate,
@@ -204,7 +217,7 @@ describe("licenseAutoAllocation", () => {
date.setDate(date.getDate() + i);
date.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
date.setMilliseconds(0);
- await createLicense(
+ await createAndAllocateLicense(
source,
i + 100,
date,
@@ -222,7 +235,7 @@ describe("licenseAutoAllocation", () => {
date.setDate(date.getDate() + 30);
date.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
date.setMilliseconds(0);
- await createLicense(
+ await createAndAllocateLicense(
source,
200,
date,
@@ -235,7 +248,13 @@ describe("licenseAutoAllocation", () => {
null
);
- await licenseAutoAllocationProcessing(context, source);
+ await licenseAutoAllocationProcessing(
+ context,
+ source,
+ redisClient,
+ sendgridMock,
+ adb2cMock
+ );
const user1Allocated = await selectLicenseByAllocatedUser(source, user1.id);
const user2Allocated = await selectLicenseByAllocatedUser(source, user2.id);
const user3Allocated = await selectLicenseByAllocatedUser(source, user3.id);
@@ -277,11 +296,349 @@ describe("licenseAutoAllocation", () => {
expect(licenseAllocationHistory.licenseAllocationHistory?.account_id).toBe(
account1.account.id
);
+ expect(
+ licenseAllocationHistory.licenseAllocationHistory?.switch_from_type
+ ).toBe("CARD");
+ // メール送信が行われていることを確認
+ expect(spySend).toHaveBeenCalledTimes(4);
+ });
+
+ it("新規ライセンスがある場合でも、有効期限が本日のライセンスが自動更新されること", async () => {
+ if (!source) fail();
+ const context = new InvocationContext();
+ const sendgridMock = new SendGridServiceMock() as SendGridService;
+ const adb2cMock = new AdB2cServiceMock() as AdB2cService;
+ // 呼び出し回数でテスト成否を判定
+ const spySend = jest.spyOn(sendgridMock, "sendMail");
+
+ const currentDateEndTime = new DateWithDayEndTime();
+
+ // アカウント
+ const account1 = await makeTestAccount(
+ source,
+ { tier: 5 },
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id1" }
+ );
+ const account2 = await makeTestAccount(
+ source,
+ { tier: 5 },
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id6" }
+ );
+
+ // 更新対象のユーザー(3role分)
+ const testNoneUser1 = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.NONE}`,
+ external_id: "external_id2",
+ });
+ const testAuthorUser2 = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.AUTHOR}`,
+ external_id: "external_id3",
+ });
+ const testTypistUser3 = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.TYPIST}`,
+ external_id: "external_id4",
+ });
+
+ // 更新対象ではないユーザー(まだ有効期限が残っている)
+ const testNoneUser4ExpirationRemain = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.NONE}`,
+ });
+
+ // 更新対象ではないユーザー(auto_renewがfalse)
+ const testNoneUser5AutoRenewFalse = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.NONE}`,
+ auto_renew: false,
+ });
+ // 更新対象のユーザー(Author二人目)
+ const testAuthorUser6 = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.AUTHOR}`,
+ external_id: "external_id5",
+ });
+ // 更新対象のユーザー(ただしライセンスが足りない)
+ const testNoneUser7lackofLicenses = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.NONE}`,
+ });
+
+ // 割り当て済みで有効期限が本日のライセンス
+ await createAndAllocateLicense(
+ source,
+ 1,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testNoneUser1.id,
+ null,
+ null,
+ null
+ );
+ await createAndAllocateLicense(
+ source,
+ 2,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.NORMAL,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testAuthorUser2.id,
+ null,
+ null,
+ null
+ );
+ await createAndAllocateLicense(
+ source,
+ 3,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.TRIAL,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testTypistUser3.id,
+ null,
+ null,
+ null
+ );
+ await createAndAllocateLicense(
+ source,
+ 20,
+ currentDateEndTime,
+ account2.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ account2.admin.id,
+ null,
+ null,
+ null
+ );
+ await createAndAllocateLicense(
+ source,
+ 5,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testNoneUser5AutoRenewFalse.id,
+ null,
+ null,
+ null
+ );
+ await createAndAllocateLicense(
+ source,
+ 6,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testAuthorUser6.id,
+ null,
+ null,
+ null
+ );
+ await createAndAllocateLicense(
+ source,
+ 7,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testNoneUser7lackofLicenses.id,
+ null,
+ null,
+ null
+ );
+
+ // 割り当て済みの更新対象ではないライセンス
+ const nextDate = new Date();
+ nextDate.setDate(nextDate.getDate() + 1);
+ nextDate.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
+ nextDate.setMilliseconds(0);
+ await createAndAllocateLicense(
+ source,
+ 4,
+ nextDate,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ testNoneUser4ExpirationRemain.id,
+ null,
+ null,
+ null
+ );
+
+ // 有効期限が先のライセンスを作成
+ // idが100のものは有効期限が当日なので自動割り当て対象外
+ // idが101のものから割り当てられる
+ for (let i = 0; i < 4; i++) {
+ const date = new Date();
+ date.setDate(date.getDate() + i);
+ date.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
+ date.setMilliseconds(0);
+ await createAndAllocateLicense(
+ source,
+ i + 100,
+ date,
+ account1.account.id,
+ LICENSE_TYPE.TRIAL,
+ LICENSE_ALLOCATED_STATUS.UNALLOCATED,
+ null,
+ null,
+ null,
+ null
+ );
+ }
+ // account1用の有効期限が設定されていないライセンスを作成
+ await createAndAllocateLicense(
+ source,
+ 99,
+ null,
+ account1.account.id,
+ LICENSE_TYPE.NORMAL,
+ LICENSE_ALLOCATED_STATUS.REUSABLE,
+ null,
+ null,
+ null,
+ null
+ );
+ // account2用の有効期限が設定されていないライセンスを作成
+ await createAndAllocateLicense(
+ source,
+ 200,
+ null,
+ account2.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.REUSABLE,
+ null,
+ null,
+ null,
+ null
+ );
+
+ await licenseAutoAllocationProcessing(
+ context,
+ source,
+ redisClient,
+ sendgridMock,
+ adb2cMock
+ );
+ const testNoneUser1Allocated = await selectLicenseByAllocatedUser(
+ source,
+ testNoneUser1.id
+ );
+ const testAuthorUser2Allocated = await selectLicenseByAllocatedUser(
+ source,
+ testAuthorUser2.id
+ );
+ const testTypistUser3Allocated = await selectLicenseByAllocatedUser(
+ source,
+ testTypistUser3.id
+ );
+ const testNoneUser4ExpirationRemainAllocated =
+ await selectLicenseByAllocatedUser(
+ source,
+ testNoneUser4ExpirationRemain.id
+ );
+ const testNoneUser5AutoRenewFalseAllocated =
+ await selectLicenseByAllocatedUser(
+ source,
+ testNoneUser5AutoRenewFalse.id
+ );
+ const testAuthorUser6Allocated = await selectLicenseByAllocatedUser(
+ source,
+ testAuthorUser6.id
+ );
+ const testNoneUser7lackofLicensesAllocated =
+ await selectLicenseByAllocatedUser(
+ source,
+ testNoneUser7lackofLicenses.id
+ );
+ const admin2Allocated = await selectLicenseByAllocatedUser(
+ source,
+ account2.admin.id
+ );
+ const testNoneUser1LicenseAllocationHistory =
+ await selectLicenseAllocationHistory(source, testNoneUser1.id, 99);
+ const testAuthorUser2LicenseAllocationHistory =
+ await selectLicenseAllocationHistory(source, testAuthorUser2.id, 101);
+ const testTypistUser3LicenseAllocationHistory =
+ await selectLicenseAllocationHistory(source, testTypistUser3.id, 103);
+
+ // Author、Typist、Noneの優先順位で割り当てられていることを確認
+ // 複数Authorがいる場合、それぞれに割り当てられていることを確認
+ expect(testAuthorUser2Allocated.license?.id).toBe(101);
+ expect(testAuthorUser6Allocated.license?.id).toBe(102);
+ expect(testTypistUser3Allocated.license?.id).toBe(103);
+ expect(testNoneUser1Allocated.license?.id).toBe(99);
+ // 有効期限がまだあるので、ライセンスが更新されていないことを確認
+ expect(testNoneUser4ExpirationRemainAllocated.license?.id).toBe(4);
+ // auto_renewがfalseなので、ライセンスが更新されていないことを確認
+ expect(testNoneUser5AutoRenewFalseAllocated.license?.id).toBe(5);
+ // ライセンスが足りない場合、ライセンスが更新されていないことを確認
+ expect(testNoneUser7lackofLicensesAllocated.license?.id).toBe(7);
+ // 複数アカウント分の処理が正常に行われていることの確認
+ expect(admin2Allocated.license?.id).toBe(200);
+
+ // ライセンス割り当て履歴テーブルが更新されていることを確認
+ expect(
+ testNoneUser1LicenseAllocationHistory.licenseAllocationHistory?.user_id
+ ).toBe(testNoneUser1.id);
+ expect(
+ testNoneUser1LicenseAllocationHistory.licenseAllocationHistory
+ ?.is_allocated
+ ).toBe(true);
+ expect(
+ testNoneUser1LicenseAllocationHistory.licenseAllocationHistory?.account_id
+ ).toBe(account1.account.id);
+ expect(
+ testNoneUser1LicenseAllocationHistory.licenseAllocationHistory
+ ?.switch_from_type
+ ).toBe("CARD");
+ expect(
+ testAuthorUser2LicenseAllocationHistory.licenseAllocationHistory?.user_id
+ ).toBe(testAuthorUser2.id);
+ expect(
+ testAuthorUser2LicenseAllocationHistory.licenseAllocationHistory
+ ?.is_allocated
+ ).toBe(true);
+ expect(
+ testAuthorUser2LicenseAllocationHistory.licenseAllocationHistory
+ ?.account_id
+ ).toBe(account1.account.id);
+ expect(
+ testAuthorUser2LicenseAllocationHistory.licenseAllocationHistory
+ ?.switch_from_type
+ ).toBe("NONE");
+ expect(
+ testTypistUser3LicenseAllocationHistory.licenseAllocationHistory?.user_id
+ ).toBe(testTypistUser3.id);
+ expect(
+ testTypistUser3LicenseAllocationHistory.licenseAllocationHistory
+ ?.is_allocated
+ ).toBe(true);
+ expect(
+ testTypistUser3LicenseAllocationHistory.licenseAllocationHistory
+ ?.account_id
+ ).toBe(account1.account.id);
+ expect(
+ testTypistUser3LicenseAllocationHistory.licenseAllocationHistory
+ ?.switch_from_type
+ ).toBe("TRIAL");
+ // メール送信が行われていることを確認
+ expect(spySend).toHaveBeenCalledTimes(5);
});
it("有効期限が指定日のライセンスが自動更新されること(リトライ用)", async () => {
if (!source) fail();
const context = new InvocationContext();
+ const sendgridMock = new SendGridServiceMock() as SendGridService;
+ const adb2cMock = new AdB2cServiceMock() as AdB2cService;
+ // 呼び出し回数でテスト成否を判定
+ const spySend = jest.spyOn(sendgridMock, "sendMail");
+
// 2023/11/22の日付を作成
const date1122 = new Date(2023, 10, 22, 23, 59, 59);
const currentDateEndTime = new DateWithDayEndTime(date1122);
@@ -289,26 +646,29 @@ describe("licenseAutoAllocation", () => {
const account1 = await makeTestAccount(
source,
{ tier: 5 },
- { role: `${USER_ROLES.NONE}` }
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id1" }
);
const account2 = await makeTestAccount(
source,
{ tier: 5 },
- { role: `${USER_ROLES.NONE}` }
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id6" }
);
// 更新対象のユーザー(3role分)
const user1 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.NONE}`,
+ external_id: "external_id2",
});
const user2 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.AUTHOR}`,
+ external_id: "external_id3",
});
const user3 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.TYPIST}`,
+ external_id: "external_id4",
});
// 更新対象ではないユーザー(まだ有効期限が残っている)
@@ -325,7 +685,7 @@ describe("licenseAutoAllocation", () => {
});
// 割り当て済みで有効期限が11/22のライセンス
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
currentDateEndTime,
@@ -337,7 +697,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
2,
currentDateEndTime,
@@ -349,7 +709,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
3,
currentDateEndTime,
@@ -361,7 +721,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
20,
currentDateEndTime,
@@ -373,7 +733,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
5,
currentDateEndTime,
@@ -390,7 +750,7 @@ describe("licenseAutoAllocation", () => {
nextDate.setDate(date1122.getDate() + 1);
nextDate.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
nextDate.setMilliseconds(0);
- await createLicense(
+ await createAndAllocateLicense(
source,
4,
nextDate,
@@ -409,7 +769,7 @@ describe("licenseAutoAllocation", () => {
// 2023/11/22の日付を作成
const date = new Date(2023, 10, 22, 23, 59, 59);
date.setDate(date.getDate() + i);
- await createLicense(
+ await createAndAllocateLicense(
source,
i + 100,
date,
@@ -427,7 +787,7 @@ describe("licenseAutoAllocation", () => {
dateMarch31.setMonth(12);
dateMarch31.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
dateMarch31.setMilliseconds(0);
- await createLicense(
+ await createAndAllocateLicense(
source,
200,
dateMarch31,
@@ -439,7 +799,14 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await licenseAutoAllocationProcessing(context, source, date1122);
+ await licenseAutoAllocationProcessing(
+ context,
+ source,
+ redisClient,
+ sendgridMock,
+ adb2cMock,
+ date1122
+ );
const user1Allocated = await selectLicenseByAllocatedUser(source, user1.id);
const user2Allocated = await selectLicenseByAllocatedUser(source, user2.id);
const user3Allocated = await selectLicenseByAllocatedUser(source, user3.id);
@@ -475,36 +842,50 @@ describe("licenseAutoAllocation", () => {
expect(licenseAllocationHistory.licenseAllocationHistory?.account_id).toBe(
account1.account.id
);
+ // メール送信が行われていることを確認
+ expect(spySend).toHaveBeenCalledTimes(4);
});
- it("新たに割り当てられるライセンスが存在しないため、ライセンスが自動更新されない(エラーではない)", async () => {
+ it("新たに割り当てられるライセンスが存在しないアカウントは、ライセンスが自動更新されない(エラーではない)", async () => {
if (!source) fail();
const context = new InvocationContext();
+ const sendgridMock = new SendGridServiceMock() as SendGridService;
+ const adb2cMock = new AdB2cServiceMock() as AdB2cService;
+ // 呼び出し回数でテスト成否を判定
+ const spySend = jest.spyOn(sendgridMock, "sendMail");
const currentDateEndTime = new DateWithDayEndTime();
- // アカウント
+ // アカウントと管理者
const account1 = await makeTestAccount(
source,
{ tier: 5 },
- { role: `${USER_ROLES.NONE}` }
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id1" }
+ );
+ const account2 = await makeTestAccount(
+ source,
+ { tier: 5 },
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id5" }
);
- // 更新対象のユーザー(3role分)
+ // account1の更新対象のユーザー(3role分)
const user1 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.NONE}`,
+ external_id: "external_id2",
});
const user2 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.AUTHOR}`,
+ external_id: "external_id3",
});
const user3 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.TYPIST}`,
+ external_id: "external_id4",
});
// 割り当て済みで有効期限が本日のライセンス
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
currentDateEndTime,
@@ -516,7 +897,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
2,
currentDateEndTime,
@@ -528,7 +909,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
3,
currentDateEndTime,
@@ -540,20 +921,67 @@ describe("licenseAutoAllocation", () => {
null,
null
);
+ await createAndAllocateLicense(
+ source,
+ 4,
+ currentDateEndTime,
+ account2.account.id,
+ LICENSE_TYPE.TRIAL,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ account2.admin.id,
+ null,
+ null,
+ null
+ );
- await licenseAutoAllocationProcessing(context, source);
+ // account2の有効期限が先の未割当ライセンスを作成
+ const nextDate = new Date();
+ nextDate.setDate(nextDate.getDate() + 1);
+ nextDate.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
+ nextDate.setMilliseconds(0);
+ await createAndAllocateLicense(
+ source,
+ 100,
+ nextDate,
+ account2.account.id,
+ LICENSE_TYPE.NORMAL,
+ LICENSE_ALLOCATED_STATUS.UNALLOCATED,
+ null,
+ null,
+ null,
+ null
+ );
+
+ await licenseAutoAllocationProcessing(
+ context,
+ source,
+ redisClient,
+ sendgridMock,
+ adb2cMock
+ );
const user1Allocated = await selectLicenseByAllocatedUser(source, user1.id);
const user2Allocated = await selectLicenseByAllocatedUser(source, user2.id);
const user3Allocated = await selectLicenseByAllocatedUser(source, user3.id);
+ const account2AdminAllocated = await selectLicenseByAllocatedUser(
+ source,
+ account2.admin.id
+ );
// ライセンスが更新されていないことを確認
expect(user1Allocated.license?.id).toBe(1);
expect(user2Allocated.license?.id).toBe(2);
expect(user3Allocated.license?.id).toBe(3);
+ expect(account2AdminAllocated.license?.id).toBe(100);
+ // メール送信が行われていないことを確認
+ expect(spySend).toHaveBeenCalledTimes(1);
});
it("tier4のアカウントのため、ライセンスが自動更新されない", async () => {
if (!source) fail();
const context = new InvocationContext();
+ const sendgridMock = new SendGridServiceMock() as SendGridService;
+ const adb2cMock = new AdB2cServiceMock() as AdB2cService;
+ // 呼び出し回数でテスト成否を判定
+ const spySend = jest.spyOn(sendgridMock, "sendMail");
const currentDateEndTime = new DateWithDayEndTime();
@@ -561,25 +989,28 @@ describe("licenseAutoAllocation", () => {
const account1 = await makeTestAccount(
source,
{ tier: 4 },
- { role: `${USER_ROLES.NONE}` }
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id1" }
);
// 更新対象のユーザー(3role分)
const user1 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.NONE}`,
+ external_id: "external_id2",
});
const user2 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.AUTHOR}`,
+ external_id: "external_id3",
});
const user3 = await makeTestUser(source, {
account_id: account1.account.id,
role: `${USER_ROLES.TYPIST}`,
+ external_id: "external_id4",
});
// 割り当て済みで有効期限が本日のライセンス
- await createLicense(
+ await createAndAllocateLicense(
source,
1,
currentDateEndTime,
@@ -591,7 +1022,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
2,
currentDateEndTime,
@@ -603,7 +1034,7 @@ describe("licenseAutoAllocation", () => {
null,
null
);
- await createLicense(
+ await createAndAllocateLicense(
source,
3,
currentDateEndTime,
@@ -624,7 +1055,7 @@ describe("licenseAutoAllocation", () => {
date.setDate(date.getDate() + i);
date.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
date.setMilliseconds(0);
- await createLicense(
+ await createAndAllocateLicense(
source,
i + 100,
date,
@@ -638,7 +1069,13 @@ describe("licenseAutoAllocation", () => {
);
}
- await licenseAutoAllocationProcessing(context, source);
+ await licenseAutoAllocationProcessing(
+ context,
+ source,
+ redisClient,
+ sendgridMock,
+ adb2cMock
+ );
const user1Allocated = await selectLicenseByAllocatedUser(source, user1.id);
const user2Allocated = await selectLicenseByAllocatedUser(source, user2.id);
const user3Allocated = await selectLicenseByAllocatedUser(source, user3.id);
@@ -646,5 +1083,99 @@ describe("licenseAutoAllocation", () => {
expect(user1Allocated.license?.id).toBe(1);
expect(user2Allocated.license?.id).toBe(2);
expect(user3Allocated.license?.id).toBe(3);
+ // メール送信が行われていないことを確認
+ expect(spySend).toHaveBeenCalledTimes(0);
+ });
+
+ it("メール送信に失敗しても、有効期限が本日のライセンスが自動更新されること", async () => {
+ if (!source) fail();
+ const context = new InvocationContext();
+ const sendgridMock = new SendGridServiceMock() as SendGridService;
+ const adb2cMock = new AdB2cServiceMock() as AdB2cService;
+ // 呼び出し回数でテスト成否を判定
+ const spySend = jest.spyOn(sendgridMock, "sendMail");
+ const currentDateEndTime = new DateWithDayEndTime();
+
+ // アカウント
+ const account1 = await makeTestAccount(
+ source,
+ { tier: 5 },
+ { role: `${USER_ROLES.NONE}`, external_id: "external_id1" }
+ );
+
+ // 更新対象のユーザー(3role分)
+ const user1 = await makeTestUser(source, {
+ account_id: account1.account.id,
+ role: `${USER_ROLES.NONE}`,
+ external_id: "external_id7", // メール送信失敗用
+ });
+ // 割り当て済みで有効期限が本日のライセンス
+ await createAndAllocateLicense(
+ source,
+ 1,
+ currentDateEndTime,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.ALLOCATED,
+ user1.id,
+ null,
+ null,
+ null
+ );
+
+ // 有効期限が先の未割当ライセンスを作成
+ // idが100のものは有効期限が当日なので自動割り当て対象外
+ // idが101のものから割り当てられる
+ for (let i = 0; i < 5; i++) {
+ const date = new Date();
+ date.setDate(date.getDate() + i);
+ date.setHours(23, 59, 59); // 時分秒を"23:59:59"に固定
+ date.setMilliseconds(0);
+ await createAndAllocateLicense(
+ source,
+ i + 100,
+ date,
+ account1.account.id,
+ LICENSE_TYPE.CARD,
+ LICENSE_ALLOCATED_STATUS.UNALLOCATED,
+ null,
+ null,
+ null,
+ null
+ );
+ }
+
+ await licenseAutoAllocationProcessing(
+ context,
+ source,
+ redisClient,
+ sendgridMock,
+ adb2cMock
+ );
+ const user1Allocated = await selectLicenseByAllocatedUser(source, user1.id);
+
+ const licenseAllocationHistory = await selectLicenseAllocationHistory(
+ source,
+ user1.id,
+ 101
+ );
+ // 割り当てられていることを確認
+ expect(user1Allocated.license?.id).toBe(101);
+
+ // ライセンス割り当て履歴テーブルが更新されていることを確認
+ expect(licenseAllocationHistory.licenseAllocationHistory?.user_id).toBe(
+ user1.id
+ );
+ expect(
+ licenseAllocationHistory.licenseAllocationHistory?.is_allocated
+ ).toBe(true);
+ expect(licenseAllocationHistory.licenseAllocationHistory?.account_id).toBe(
+ account1.account.id
+ );
+ expect(
+ licenseAllocationHistory.licenseAllocationHistory?.switch_from_type
+ ).toBe("CARD");
+ // メール送信が行われていないことを確認
+ expect(spySend).toHaveBeenCalledTimes(0);
});
});
diff --git a/dictation_function/tsconfig.json b/dictation_function/tsconfig.json
index dd9c7a4..a541177 100644
--- a/dictation_function/tsconfig.json
+++ b/dictation_function/tsconfig.json
@@ -1,7 +1,7 @@
{
"compilerOptions": {
"module": "commonjs",
- "target": "es6",
+ "target": "ES2021",
"outDir": "dist",
"rootDir": ".",
"sourceMap": true,
From e76242bddd9f3f119c4e62392df68010a49f0d25 Mon Sep 17 00:00:00 2001
From: "SAITO-PC-3\\saito.k"
Date: Thu, 25 Apr 2024 18:19:48 +0900
Subject: [PATCH 6/9] =?UTF-8?q?Functions=E3=81=AE=E3=83=86=E3=82=B9?=
=?UTF-8?q?=E3=83=88=E3=81=A7=E4=BD=BF=E7=94=A8=E3=81=99=E3=82=8B=E7=92=B0?=
=?UTF-8?q?=E5=A2=83=E5=A4=89=E6=95=B0=E3=82=92=E4=BF=AE=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
azure-pipelines-staging.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/azure-pipelines-staging.yml b/azure-pipelines-staging.yml
index 65c19c4..918dcf9 100644
--- a/azure-pipelines-staging.yml
+++ b/azure-pipelines-staging.yml
@@ -208,7 +208,7 @@ jobs:
ADB2C_ORIGIN: xxxxxx
SENDGRID_API_KEY: $(sendgrid-api-key)
MAIL_FROM: xxxxxx
- APP_DOMAIN: xxxxxxxxx
+ APP_DOMAIN: http://localhost:8081/
REDIS_HOST: xxxxxxxxxxxx
REDIS_PORT: 0
REDIS_PASSWORD: xxxxxxxxxxxx
From 8122f6f4e1803be84afea91af5d70cef02ae138f Mon Sep 17 00:00:00 2001
From: "makabe.t"
Date: Tue, 7 May 2024 00:05:17 +0000
Subject: [PATCH 7/9] =?UTF-8?q?Merged=20PR=20884:=20Function=E3=81=ABX-Req?=
=?UTF-8?q?uested-With=E3=83=98=E3=83=83=E3=83=80=E3=82=92=E9=81=A9?=
=?UTF-8?q?=E7=94=A8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 概要
[Task4142: FunctionにX-Requested-Withヘッダを適用](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4142)
- Functionのユーザー一括登録の処理中でOMDS CloudのAPIを呼び出す処理があるので、X-Requested-Withヘッダを適用しました。
- 一括登録失敗時のメール文面の翻訳でエラーがない場合のメッセージが日本語のままになっていたので各言語に対応しました。
## レビューポイント
- ヘッダの適用は適切でしょうか?
- 翻訳の適用方法で、言語ごとに割り当てる内容を定数としていますが、文面の置き換え方法に問題はないでしょうか?
## UIの変更
- なし
## クエリの変更
- なし
## 動作確認状況
- ローカルで確認
- 行った修正がデグレを発生させていないことを確認できるか
- 具体的にどのような確認をしたか
- ローカルからAPIを叩い検証証
---
.../src/functions/importUsers.ts | 10 ++
.../src/features/users/users.service.ts | 4 +-
.../src/gateways/sendgrid/sendgrid.service.ts | 106 +++++++++++++-----
dictation_server/src/templates/constants.ts | 18 ++-
.../src/templates/template_U_122.html | 18 +--
.../src/templates/template_U_122.txt | 18 +--
.../templates/template_U_122_no_parent.html | 18 +--
.../templates/template_U_122_no_parent.txt | 18 +--
8 files changed, 141 insertions(+), 69 deletions(-)
diff --git a/dictation_function/src/functions/importUsers.ts b/dictation_function/src/functions/importUsers.ts
index 38716b9..0a34802 100644
--- a/dictation_function/src/functions/importUsers.ts
+++ b/dictation_function/src/functions/importUsers.ts
@@ -18,6 +18,16 @@ import { sign, getJwtKey } from "../common/jwt";
import { AccessToken, SystemAccessToken } from "../common/jwt/types";
import { isImportJson, isStageJson } from "../blobstorage/types/guards";
import https from "https";
+import globalAxios from "axios";
+
+// すべてのリクエストのヘッダーにX-Requested-Withを追加
+globalAxios.interceptors.request.use((config) => {
+ // headersがあれば追加、なければ新規作成
+ config.headers = config.headers || {};
+ // X-Requested-Withを追加
+ config.headers["X-Requested-With"] = "XMLHttpRequest";
+ return config;
+});
export async function importUsersProcessing(
context: InvocationContext,
diff --git a/dictation_server/src/features/users/users.service.ts b/dictation_server/src/features/users/users.service.ts
index 957dde1..6896e98 100644
--- a/dictation_server/src/features/users/users.service.ts
+++ b/dictation_server/src/features/users/users.service.ts
@@ -63,7 +63,6 @@ import {
import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
import { getUserNameAndMailAddress } from '../../gateways/adb2c/utils/utils';
import { AccountsRepositoryService } from '../../repositories/accounts/accounts.repository.service';
-import { Account } from '../../repositories/accounts/entity/account.entity';
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
@Injectable()
@@ -195,7 +194,6 @@ export class UsersService {
);
//DBよりアクセス者の所属するアカウントIDを取得する
let adminUser: EntityUser;
- let account: Account | null;
try {
adminUser = await this.usersRepository.findUserByExternalId(
context,
@@ -210,7 +208,7 @@ export class UsersService {
}
const accountId = adminUser.account_id;
- account = adminUser.account;
+ const account = adminUser.account;
//authorIdが重複していないかチェックする
if (authorId) {
diff --git a/dictation_server/src/gateways/sendgrid/sendgrid.service.ts b/dictation_server/src/gateways/sendgrid/sendgrid.service.ts
index b399326..7432e72 100644
--- a/dictation_server/src/gateways/sendgrid/sendgrid.service.ts
+++ b/dictation_server/src/gateways/sendgrid/sendgrid.service.ts
@@ -20,10 +20,19 @@ import {
TYPIST_NAME,
VERIFY_LINK,
TEMPORARY_PASSWORD,
- EMAIL_DUPLICATION,
- AUTHOR_ID_DUPLICATION,
- UNEXPECTED_ERROR,
+ EMAIL_DUPLICATION_EN,
+ AUTHOR_ID_DUPLICATION_EN,
+ UNEXPECTED_ERROR_EN,
+ EMAIL_DUPLICATION_DE,
+ AUTHOR_ID_DUPLICATION_DE,
+ UNEXPECTED_ERROR_DE,
+ EMAIL_DUPLICATION_FR,
+ AUTHOR_ID_DUPLICATION_FR,
+ UNEXPECTED_ERROR_FR,
REQUEST_TIME,
+ NO_ERROR_MESSAGE_EN,
+ NO_ERROR_MESSAGE_DE,
+ NO_ERROR_MESSAGE_FR,
} from '../../templates/constants';
import { URL } from 'node:url';
@@ -1387,18 +1396,37 @@ export class SendGridService {
`[IN] [${context.getTrackingId()}] ${this.sendMailWithU122.name}`,
);
try {
- const duplicateEmailsMsg =
- duplicateEmails.length === 0
- ? 'エラーはありません'
- : duplicateEmails.map((x) => `L${x}`).join(', ');
- const duplicateAuthorIdsMsg =
- duplicateAuthorIds.length === 0
- ? 'エラーはありません'
- : duplicateAuthorIds.map((x) => `L${x}`).join(', ');
- const otherErrorsMsg =
- otherErrors.length === 0
- ? 'エラーはありません'
- : otherErrors.map((x) => `L${x}`).join(', ');
+ let duplicateEmailsMsgEn = NO_ERROR_MESSAGE_EN;
+ let duplicateAuthorIdsMsgEn = NO_ERROR_MESSAGE_EN;
+ let otherErrorsMsgEn = NO_ERROR_MESSAGE_EN;
+ let duplicateEmailsMsgDe = NO_ERROR_MESSAGE_DE;
+ let duplicateAuthorIdsMsgDe = NO_ERROR_MESSAGE_DE;
+ let otherErrorsMsgDe = NO_ERROR_MESSAGE_DE;
+ let duplicateEmailsMsgFr = NO_ERROR_MESSAGE_FR;
+ let duplicateAuthorIdsMsgFr = NO_ERROR_MESSAGE_FR;
+ let otherErrorsMsgFr = NO_ERROR_MESSAGE_FR;
+
+ if (duplicateEmails.length !== 0) {
+ duplicateEmailsMsgEn = duplicateEmails.map((x) => `L${x}`).join(', ');
+ duplicateEmailsMsgDe = duplicateEmails.map((x) => `L${x}`).join(', ');
+ duplicateEmailsMsgFr = duplicateEmails.map((x) => `L${x}`).join(', ');
+ }
+ if (duplicateAuthorIds.length !== 0) {
+ duplicateAuthorIdsMsgEn = duplicateAuthorIds
+ .map((x) => `L${x}`)
+ .join(', ');
+ duplicateAuthorIdsMsgDe = duplicateAuthorIds
+ .map((x) => `L${x}`)
+ .join(', ');
+ duplicateAuthorIdsMsgFr = duplicateAuthorIds
+ .map((x) => `L${x}`)
+ .join(', ');
+ }
+ if (otherErrors.length !== 0) {
+ otherErrorsMsgEn = otherErrors.map((x) => `L${x}`).join(', ');
+ otherErrorsMsgDe = otherErrors.map((x) => `L${x}`).join(', ');
+ otherErrorsMsgFr = otherErrors.map((x) => `L${x}`).join(', ');
+ }
const subject = 'User Bulk Registration Failed Notification [U-122]';
@@ -1408,27 +1436,51 @@ export class SendGridService {
if (!dealerAccountName) {
html = this.templateU122NoParentHtml
.replaceAll(CUSTOMER_NAME, customerAccountName)
- .replaceAll(EMAIL_DUPLICATION, duplicateEmailsMsg)
- .replaceAll(AUTHOR_ID_DUPLICATION, duplicateAuthorIdsMsg)
- .replaceAll(UNEXPECTED_ERROR, otherErrorsMsg);
+ .replaceAll(EMAIL_DUPLICATION_EN, duplicateEmailsMsgEn)
+ .replaceAll(EMAIL_DUPLICATION_DE, duplicateEmailsMsgDe)
+ .replaceAll(EMAIL_DUPLICATION_FR, duplicateEmailsMsgFr)
+ .replaceAll(AUTHOR_ID_DUPLICATION_EN, duplicateAuthorIdsMsgEn)
+ .replaceAll(AUTHOR_ID_DUPLICATION_DE, duplicateAuthorIdsMsgDe)
+ .replaceAll(AUTHOR_ID_DUPLICATION_FR, duplicateAuthorIdsMsgFr)
+ .replaceAll(UNEXPECTED_ERROR_EN, otherErrorsMsgEn)
+ .replaceAll(UNEXPECTED_ERROR_DE, otherErrorsMsgDe)
+ .replaceAll(UNEXPECTED_ERROR_FR, otherErrorsMsgFr);
text = this.templateU122NoParentText
.replaceAll(CUSTOMER_NAME, customerAccountName)
- .replaceAll(EMAIL_DUPLICATION, duplicateEmailsMsg)
- .replaceAll(AUTHOR_ID_DUPLICATION, duplicateAuthorIdsMsg)
- .replaceAll(UNEXPECTED_ERROR, otherErrorsMsg);
+ .replaceAll(EMAIL_DUPLICATION_EN, duplicateEmailsMsgEn)
+ .replaceAll(EMAIL_DUPLICATION_DE, duplicateEmailsMsgDe)
+ .replaceAll(EMAIL_DUPLICATION_FR, duplicateEmailsMsgFr)
+ .replaceAll(AUTHOR_ID_DUPLICATION_EN, duplicateAuthorIdsMsgEn)
+ .replaceAll(AUTHOR_ID_DUPLICATION_DE, duplicateAuthorIdsMsgDe)
+ .replaceAll(AUTHOR_ID_DUPLICATION_FR, duplicateAuthorIdsMsgFr)
+ .replaceAll(UNEXPECTED_ERROR_EN, otherErrorsMsgEn)
+ .replaceAll(UNEXPECTED_ERROR_DE, otherErrorsMsgDe)
+ .replaceAll(UNEXPECTED_ERROR_FR, otherErrorsMsgFr);
} else {
html = this.templateU122Html
.replaceAll(CUSTOMER_NAME, customerAccountName)
.replaceAll(DEALER_NAME, dealerAccountName)
- .replaceAll(EMAIL_DUPLICATION, duplicateEmailsMsg)
- .replaceAll(AUTHOR_ID_DUPLICATION, duplicateAuthorIdsMsg)
- .replaceAll(UNEXPECTED_ERROR, otherErrorsMsg);
+ .replaceAll(EMAIL_DUPLICATION_EN, duplicateEmailsMsgEn)
+ .replaceAll(EMAIL_DUPLICATION_DE, duplicateEmailsMsgDe)
+ .replaceAll(EMAIL_DUPLICATION_FR, duplicateEmailsMsgFr)
+ .replaceAll(AUTHOR_ID_DUPLICATION_EN, duplicateAuthorIdsMsgEn)
+ .replaceAll(AUTHOR_ID_DUPLICATION_DE, duplicateAuthorIdsMsgDe)
+ .replaceAll(AUTHOR_ID_DUPLICATION_FR, duplicateAuthorIdsMsgFr)
+ .replaceAll(UNEXPECTED_ERROR_EN, otherErrorsMsgEn)
+ .replaceAll(UNEXPECTED_ERROR_DE, otherErrorsMsgDe)
+ .replaceAll(UNEXPECTED_ERROR_FR, otherErrorsMsgFr);
text = this.templateU122Text
.replaceAll(CUSTOMER_NAME, customerAccountName)
.replaceAll(DEALER_NAME, dealerAccountName)
- .replaceAll(EMAIL_DUPLICATION, duplicateEmailsMsg)
- .replaceAll(AUTHOR_ID_DUPLICATION, duplicateAuthorIdsMsg)
- .replaceAll(UNEXPECTED_ERROR, otherErrorsMsg);
+ .replaceAll(EMAIL_DUPLICATION_EN, duplicateEmailsMsgEn)
+ .replaceAll(EMAIL_DUPLICATION_DE, duplicateEmailsMsgDe)
+ .replaceAll(EMAIL_DUPLICATION_FR, duplicateEmailsMsgFr)
+ .replaceAll(AUTHOR_ID_DUPLICATION_EN, duplicateAuthorIdsMsgEn)
+ .replaceAll(AUTHOR_ID_DUPLICATION_DE, duplicateAuthorIdsMsgDe)
+ .replaceAll(AUTHOR_ID_DUPLICATION_FR, duplicateAuthorIdsMsgFr)
+ .replaceAll(UNEXPECTED_ERROR_EN, otherErrorsMsgEn)
+ .replaceAll(UNEXPECTED_ERROR_DE, otherErrorsMsgDe)
+ .replaceAll(UNEXPECTED_ERROR_FR, otherErrorsMsgFr);
}
// メールを送信する
diff --git a/dictation_server/src/templates/constants.ts b/dictation_server/src/templates/constants.ts
index d6650a6..47ebb6d 100644
--- a/dictation_server/src/templates/constants.ts
+++ b/dictation_server/src/templates/constants.ts
@@ -12,6 +12,18 @@ export const FILE_NAME = '$FILE_NAME$';
export const TYPIST_NAME = '$TYPIST_NAME$';
export const TEMPORARY_PASSWORD = '$TEMPORARY_PASSWORD$';
export const REQUEST_TIME = '$REQUEST_TIME$';
-export const EMAIL_DUPLICATION = `$EMAIL_DUPLICATION$`;
-export const AUTHOR_ID_DUPLICATION = `$AUTHOR_ID_DUPLICATION$`;
-export const UNEXPECTED_ERROR = `$UNEXPECTED_ERROR$`;
+// 言語ごとに変更
+export const EMAIL_DUPLICATION_EN = `$EMAIL_DUPLICATION_EN$`;
+export const AUTHOR_ID_DUPLICATION_EN = `$AUTHOR_ID_DUPLICATION_EN$`;
+export const UNEXPECTED_ERROR_EN = `$UNEXPECTED_ERROR_EN$`;
+export const EMAIL_DUPLICATION_DE = `$EMAIL_DUPLICATION_DE$`;
+export const AUTHOR_ID_DUPLICATION_DE = `$AUTHOR_ID_DUPLICATION_DE$`;
+export const UNEXPECTED_ERROR_DE = `$UNEXPECTED_ERROR_DE$`;
+export const EMAIL_DUPLICATION_FR = `$EMAIL_DUPLICATION_FR$`;
+export const AUTHOR_ID_DUPLICATION_FR = `$AUTHOR_ID_DUPLICATION_FR$`;
+export const UNEXPECTED_ERROR_FR = `$UNEXPECTED_ERROR_FR$`;
+
+// 言語ごとに当てはまる値
+export const NO_ERROR_MESSAGE_EN = 'No errors';
+export const NO_ERROR_MESSAGE_DE = 'Keine Fehler';
+export const NO_ERROR_MESSAGE_FR = 'Aucune erreur';
diff --git a/dictation_server/src/templates/template_U_122.html b/dictation_server/src/templates/template_U_122.html
index f33c4c3..b456eb5 100644
--- a/dictation_server/src/templates/template_U_122.html
+++ b/dictation_server/src/templates/template_U_122.html
@@ -18,11 +18,11 @@
1. The e-mail address in the line below has already been registered or is a duplicate of an e-mail address in
another
line.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_EN$
2. The Author ID in the line below is already registered or is a duplicate of an Author ID in another line.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_EN$
* E-mail address and Author ID that have already been registered cannot be registered again.
@@ -35,7 +35,7 @@
3. An unexpected error occurred during user registration on the following line. If it does not succeed after
trying
again, please contact your dealer.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_EN$
If you need support regarding the ODMS Cloud, please contact $DEALER_NAME$.
@@ -59,12 +59,12 @@
1. Die E-Mail-Adresse in der Zeile unten ist bereits registriert oder ist ein Duplikat einer E-Mail-Adresse in
einer
anderen Zeile.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_DE$
2. Die Author-ID in der Zeile darunter ist bereits registriert oder ein Duplikat einer AuthorID in einer anderen
Zeile.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_DE$
* E-Mail-Adresse und Autoren-ID, die bereits registriert wurden, können nicht erneut registriert werden.
@@ -78,7 +78,7 @@
3. Bei der Benutzerregistrierung ist in der folgenden Zeile ein unerwarteter Fehler aufgetreten. Sollte es auch
nach
einem erneuten Versuch nicht erfolgreich sein, wenden Sie sich bitte an Ihren Händler.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_DE$
Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $DEALER_NAME$.
@@ -101,13 +101,13 @@
1. L'adresse e-mail dans la ligne ci-dessous a déjà été enregistrée ou est un double d'une adresse e-mail dans une
autre ligne.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_FR$
2. L'Identifiant Auteur dans la ligne ci-dessous est déjà enregistré ou est un double d'un Identifiant Auteur dans
une
autre ligne.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_FR$
* L'adresse e-mail et l'Identifiant Auteur déjà enregistrés ne peuvent pas être enregistrés à nouveau.
@@ -121,7 +121,7 @@
3. Une erreur inattendue s'est produite lors de l'enregistrement de l'utilisateur sur la ligne suivante. Si cela
ne
fonctionne pas après une nouvelle tentative, veuillez contacter votre revendeur.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_FR$
Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $DEALER_NAME$.
diff --git a/dictation_server/src/templates/template_U_122.txt b/dictation_server/src/templates/template_U_122.txt
index 6729c16..59315df 100644
--- a/dictation_server/src/templates/template_U_122.txt
+++ b/dictation_server/src/templates/template_U_122.txt
@@ -5,16 +5,16 @@ Dear $CUSTOMER_NAME$,
Bulk user registration using the CSV file has failed. The cause and location of the error is shown in 1, 2, and 3 below. ( L = Line )
1. The e-mail address in the line below has already been registered or is a duplicate of an e-mail address in another line.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_EN$
2. The Author ID in the line below is already registered or is a duplicate of an Author ID in another line.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_EN$
* E-mail address and Author ID that have already been registered cannot be registered again.
* Rows without errors have been successfully registered. Therefore, if you use the same CSV file and register the user that has been successfully registered, a duplicate error will occur. Please create a CSV file containing only the lines where the error occurred, or manually register them one by one.
3. An unexpected error occurred during user registration on the following line. If it does not succeed after trying again, please contact your dealer.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_EN$
If you need support regarding the ODMS Cloud, please contact $DEALER_NAME$.
@@ -28,16 +28,16 @@ Sehr geehrte(r) $CUSTOMER_NAME$,
Die Massenregistrierung von Benutzern mithilfe der CSV-Datei ist fehlgeschlagen. Die Ursache und der Ort des Fehlers werden in 1, 2 und 3 unten angezeigt. (L = Linie)
1. Die E-Mail-Adresse in der Zeile unten ist bereits registriert oder ist ein Duplikat einer E-Mail-Adresse in einer anderen Zeile.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_DE$
2. Die Author-ID in der Zeile darunter ist bereits registriert oder ein Duplikat einer AuthorID in einer anderen Zeile.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_DE$
* E-Mail-Adresse und Autoren-ID, die bereits registriert wurden, können nicht erneut registriert werden.
* Zeilen ohne Fehler wurden erfolgreich registriert. Wenn Sie daher dieselbe CSV-Datei verwenden und den erfolgreich registrierten Benutzer registrieren, tritt ein doppelter Fehler auf. Bitte erstellen Sie eine CSV-Datei, die nur die Zeilen enthält, in denen der Fehler aufgetreten ist, oder registrieren Sie sie einzeln manuell.
3. Bei der Benutzerregistrierung ist in der folgenden Zeile ein unerwarteter Fehler aufgetreten. Sollte es auch nach einem erneuten Versuch nicht erfolgreich sein, wenden Sie sich bitte an Ihren Händler.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_DE$
Wenn Sie Unterstützung bezüglich ODMS Cloud benötigen, wenden Sie sich bitte an $DEALER_NAME$.
@@ -51,16 +51,16 @@ Chère/Cher $CUSTOMER_NAME$,
L'enregistrement groupé des utilisateurs à l'aide du fichier CSV a échoué. La cause et l'emplacement de l'erreur sont indiqués aux points 1, 2 et 3 ci-dessous. ( L = Ligne )
1. L'adresse e-mail dans la ligne ci-dessous a déjà été enregistrée ou est un double d'une adresse e-mail dans une autre ligne.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_FR$
2. L'Identifiant Auteur dans la ligne ci-dessous est déjà enregistré ou est un double d'un Identifiant Auteur dans une autre ligne.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_FR$
* L'adresse e-mail et l'Identifiant Auteur déjà enregistrés ne peuvent pas être enregistrés à nouveau.
* Les lignes sans erreurs ont été enregistrées avec succès. Par conséquent, si vous utilisez le même fichier CSV et enregistrez l'utilisateur qui a été enregistré avec succès, une erreur en double se produira. Veuillez créer un fichier CSV contenant uniquement les lignes où l'erreur s'est produite, ou enregistrez-les manuellement une par une.
3. Une erreur inattendue s'est produite lors de l'enregistrement de l'utilisateur sur la ligne suivante. Si cela ne fonctionne pas après une nouvelle tentative, veuillez contacter votre revendeur.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_FR$
Si vous avez besoin d'assistance concernant ODMS Cloud, veuillez contacter $DEALER_NAME$.
diff --git a/dictation_server/src/templates/template_U_122_no_parent.html b/dictation_server/src/templates/template_U_122_no_parent.html
index bd9a2af..1b3903a 100644
--- a/dictation_server/src/templates/template_U_122_no_parent.html
+++ b/dictation_server/src/templates/template_U_122_no_parent.html
@@ -18,11 +18,11 @@
1. The e-mail address in the line below has already been registered or is a duplicate of an e-mail address in
another
line.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_EN$
2. The Author ID in the line below is already registered or is a duplicate of an Author ID in another line.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_EN$
* E-mail address and Author ID that have already been registered cannot be registered again.
@@ -35,7 +35,7 @@
3. An unexpected error occurred during user registration on the following line. If it does not succeed after
trying
again, please contact your dealer.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_EN$
If you received this e-mail in error, please delete this e-mail from your system.
@@ -56,12 +56,12 @@
1. Die E-Mail-Adresse in der Zeile unten ist bereits registriert oder ist ein Duplikat einer E-Mail-Adresse in
einer
anderen Zeile.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_DE$
2. Die Author-ID in der Zeile darunter ist bereits registriert oder ein Duplikat einer AuthorID in einer anderen
Zeile.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_DE$
* E-Mail-Adresse und Autoren-ID, die bereits registriert wurden, können nicht erneut registriert werden.
@@ -75,7 +75,7 @@
3. Bei der Benutzerregistrierung ist in der folgenden Zeile ein unerwarteter Fehler aufgetreten. Sollte es auch
nach
einem erneuten Versuch nicht erfolgreich sein, wenden Sie sich bitte an Ihren Händler.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_DE$
Wenn Sie diese E-Mail irrtümlich erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
@@ -95,13 +95,13 @@
1. L'adresse e-mail dans la ligne ci-dessous a déjà été enregistrée ou est un double d'une adresse e-mail dans une
autre ligne.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_FR$
2. L'Identifiant Auteur dans la ligne ci-dessous est déjà enregistré ou est un double d'un Identifiant Auteur dans
une
autre ligne.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_FR$
* L'adresse e-mail et l'Identifiant Auteur déjà enregistrés ne peuvent pas être enregistrés à nouveau.
@@ -115,7 +115,7 @@
3. Une erreur inattendue s'est produite lors de l'enregistrement de l'utilisateur sur la ligne suivante. Si cela
ne
fonctionne pas après une nouvelle tentative, veuillez contacter votre revendeur.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_FR$
Si vous avez reçu cet e-mail par erreur, veuillez supprimer cet e-mail de votre système.
diff --git a/dictation_server/src/templates/template_U_122_no_parent.txt b/dictation_server/src/templates/template_U_122_no_parent.txt
index f91ba7f..f9b3461 100644
--- a/dictation_server/src/templates/template_U_122_no_parent.txt
+++ b/dictation_server/src/templates/template_U_122_no_parent.txt
@@ -5,16 +5,16 @@ Dear $CUSTOMER_NAME$,
Bulk user registration using the CSV file has failed. The cause and location of the error is shown in 1, 2, and 3 below. ( L = Line )
1. The e-mail address in the line below has already been registered or is a duplicate of an e-mail address in another line.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_EN$
2. The Author ID in the line below is already registered or is a duplicate of an Author ID in another line.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_EN$
* E-mail address and Author ID that have already been registered cannot be registered again.
* Rows without errors have been successfully registered. Therefore, if you use the same CSV file and register the user that has been successfully registered, a duplicate error will occur. Please create a CSV file containing only the lines where the error occurred, or manually register them one by one.
3. An unexpected error occurred during user registration on the following line. If it does not succeed after trying again, please contact your dealer.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_EN$
If you 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.
@@ -26,16 +26,16 @@ Sehr geehrte(r) $CUSTOMER_NAME$,
Die Massenregistrierung von Benutzern mithilfe der CSV-Datei ist fehlgeschlagen. Die Ursache und der Ort des Fehlers werden in 1, 2 und 3 unten angezeigt. (L = Linie)
1. Die E-Mail-Adresse in der Zeile unten ist bereits registriert oder ist ein Duplikat einer E-Mail-Adresse in einer anderen Zeile.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_DE$
2. Die Author-ID in der Zeile darunter ist bereits registriert oder ein Duplikat einer AuthorID in einer anderen Zeile.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_DE$
* E-Mail-Adresse und Autoren-ID, die bereits registriert wurden, können nicht erneut registriert werden.
* Zeilen ohne Fehler wurden erfolgreich registriert. Wenn Sie daher dieselbe CSV-Datei verwenden und den erfolgreich registrierten Benutzer registrieren, tritt ein doppelter Fehler auf. Bitte erstellen Sie eine CSV-Datei, die nur die Zeilen enthält, in denen der Fehler aufgetreten ist, oder registrieren Sie sie einzeln manuell.
3. Bei der Benutzerregistrierung ist in der folgenden Zeile ein unerwarteter Fehler aufgetreten. Sollte es auch nach einem erneuten Versuch nicht erfolgreich sein, wenden Sie sich bitte an Ihren Händler.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_DE$
Wenn Sie diese E-Mail irrtümlich erhalten haben, löschen Sie diese E-Mail bitte aus Ihrem System.
Dies ist eine automatisch generierte E-Mail und diese Mailbox wird nicht überwacht. Bitte antworten Sie nicht.
@@ -47,16 +47,16 @@ Chère/Cher $CUSTOMER_NAME$,
L'enregistrement groupé des utilisateurs à l'aide du fichier CSV a échoué. La cause et l'emplacement de l'erreur sont indiqués aux points 1, 2 et 3 ci-dessous. ( L = Ligne )
1. L'adresse e-mail dans la ligne ci-dessous a déjà été enregistrée ou est un double d'une adresse e-mail dans une autre ligne.
- $EMAIL_DUPLICATION$
+ $EMAIL_DUPLICATION_FR$
2. L'Identifiant Auteur dans la ligne ci-dessous est déjà enregistré ou est un double d'un Identifiant Auteur dans une autre ligne.
- $AUTHOR_ID_DUPLICATION$
+ $AUTHOR_ID_DUPLICATION_FR$
* L'adresse e-mail et l'Identifiant Auteur déjà enregistrés ne peuvent pas être enregistrés à nouveau.
* Les lignes sans erreurs ont été enregistrées avec succès. Par conséquent, si vous utilisez le même fichier CSV et enregistrez l'utilisateur qui a été enregistré avec succès, une erreur en double se produira. Veuillez créer un fichier CSV contenant uniquement les lignes où l'erreur s'est produite, ou enregistrez-les manuellement une par une.
3. Une erreur inattendue s'est produite lors de l'enregistrement de l'utilisateur sur la ligne suivante. Si cela ne fonctionne pas après une nouvelle tentative, veuillez contacter votre revendeur.
- $UNEXPECTED_ERROR$
+ $UNEXPECTED_ERROR_FR$
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
From c813ddc0ac00dc0d7d29795176b4c1914b242807 Mon Sep 17 00:00:00 2001
From: "saito.k"
Date: Tue, 7 May 2024 05:37:16 +0000
Subject: [PATCH 8/9] =?UTF-8?q?Merged=20PR=20888:=20=E5=AF=BE=E5=BF=9C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 概要
[Task4160: 対応](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4160)
- 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず)
- 何をどう変更したか、追加したライブラリなど
- このPull Requestでの対象/対象外
- 影響範囲(他の機能にも影響があるか)
## レビューポイント
- 特にレビューしてほしい箇所
- 軽微なものや自明なものは記載不要
- 修正範囲が大きい場合などに記載
- 全体的にや仕様を満たしているか等は本当に必要な時のみ記載
- 修正箇所がほかの機能に影響していないか
## UIの変更
- Before/Afterのスクショなど
- スクショ置き場
## クエリの変更
- Repositoryを変更し、クエリが変更された場合は変更内容を確認する
- Before/Afterのクエリ
- クエリ置き場
## 動作確認状況
- ローカルで確認、develop環境で確認など
- 行った修正がデグレを発生させていないことを確認できるか
- 具体的にどのような確認をしたか
- どのケースに対してどのような手段でデグレがないことを担保しているか
## 補足
- 相談、参考資料などがあれば
---
dictation_client/.env.staging | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dictation_client/.env.staging b/dictation_client/.env.staging
index b4beb04..6474e1b 100644
--- a/dictation_client/.env.staging
+++ b/dictation_client/.env.staging
@@ -1,5 +1,5 @@
VITE_STAGE=staging
-VITE_B2C_CLIENTID=5d8f0db9-4506-41d6-a5bb-5ec39f6eba8d
-VITE_B2C_AUTHORITY=https://adb2codmsstg.b2clogin.com/adb2codmsstg.onmicrosoft.com/b2c_1_signin_stg
-VITE_B2C_KNOWNAUTHORITIES=adb2codmsstg.b2clogin.com
+VITE_B2C_CLIENTID=6ddb8ca0-c39e-4eba-a3c1-d18ea289a315
+VITE_B2C_AUTHORITY=https://adb2codmsstaging.b2clogin.com/adb2codmsstaging.onmicrosoft.com/b2c_1_signin_staging
+VITE_B2C_KNOWNAUTHORITIES=adb2codmsstaging.b2clogin.com
VITE_DESK_TOP_APP_SCHEME=odms-desktopapp
\ No newline at end of file
From 279a9ab037e870b5417368aca15e8dacff4a68d0 Mon Sep 17 00:00:00 2001
From: "makabe.t"
Date: Tue, 7 May 2024 07:11:39 +0000
Subject: [PATCH 9/9] =?UTF-8?q?Merged=20PR=20889:=20function=E4=BF=AE?=
=?UTF-8?q?=E6=AD=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 概要
[Task4164: function修正](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/4164)
- 元PBI or タスクへのリンク(内容・目的などはそちらにあるはず)
- 何をどう変更したか、追加したライブラリなど
- このPull Requestでの対象/対象外
- 影響範囲(他の機能にも影響があるか)
## レビューポイント
- 特にレビューしてほしい箇所
- 軽微なものや自明なものは記載不要
- 修正範囲が大きい場合などに記載
- 全体的にや仕様を満たしているか等は本当に必要な時のみ記載
- 修正箇所がほかの機能に影響していないか
## UIの変更
- Before/Afterのスクショなど
- スクショ置き場
## クエリの変更
- Repositoryを変更し、クエリが変更された場合は変更内容を確認する
- Before/Afterのクエリ
- クエリ置き場
## 動作確認状況
- ローカルで確認、develop環境で確認など
- 行った修正がデグレを発生させていないことを確認できるか
- 具体的にどのような確認をしたか
- どのケースに対してどのような手段でデグレがないことを担保しているか
## 補足
- 相談、参考資料などがあれば
---
dictation_function/package.json | 3 ++-
.../src/functions/licenseAutoAllocation.ts | 18 +-----------------
.../licenseAutoAllocationManualRetry.ts | 18 +-----------------
3 files changed, 4 insertions(+), 35 deletions(-)
diff --git a/dictation_function/package.json b/dictation_function/package.json
index 0be5119..1f1524a 100644
--- a/dictation_function/package.json
+++ b/dictation_function/package.json
@@ -9,7 +9,8 @@
"clean": "rimraf dist",
"prestart": "npm run clean && npm run build",
"start": "func start",
- "test": "sql-migrate up -config=/app/dictation_server/db/dbconfig.yml -env=test && jest -w 1",
+ "test": "tsc --noEmit && sql-migrate up -config=/app/dictation_server/db/dbconfig.yml -env=test && jest -w 1",
+ "typecheck": "tsc --noEmit",
"codegen": "sh codegen.sh"
},
"dependencies": {
diff --git a/dictation_function/src/functions/licenseAutoAllocation.ts b/dictation_function/src/functions/licenseAutoAllocation.ts
index 80d4414..8b1b053 100644
--- a/dictation_function/src/functions/licenseAutoAllocation.ts
+++ b/dictation_function/src/functions/licenseAutoAllocation.ts
@@ -97,23 +97,7 @@ export async function licenseAutoAllocation(
context.log("[IN]licenseAutoAllocation");
dotenv.config({ path: ".env" });
dotenv.config({ path: ".env.local", override: true });
- let datasource: DataSource;
- try {
- datasource = new DataSource({
- type: "mysql",
- host: process.env.DB_HOST,
- port: Number(process.env.DB_PORT),
- username: process.env.DB_USERNAME,
- password: process.env.DB_PASSWORD,
- database: process.env.DB_NAME,
- entities: [User, Account, License, LicenseAllocationHistory],
- });
- await datasource.initialize();
- } catch (e) {
- context.log("database initialize failed.");
- context.error(e);
- throw e;
- }
+ const datasource = await initializeDataSource(context);
let redisClient: RedisClient;
try {
// redis接続
diff --git a/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts b/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts
index b9d74e8..c4b4514 100644
--- a/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts
+++ b/dictation_function/src/functions/licenseAutoAllocationManualRetry.ts
@@ -41,23 +41,7 @@ export async function licenseAutoAllocationManualRetry(
context.log("[IN]licenseAutoAllocationManualRetry");
dotenv.config({ path: ".env" });
dotenv.config({ path: ".env.local", override: true });
- let datasource: DataSource;
- try {
- datasource = new DataSource({
- type: "mysql",
- host: process.env.DB_HOST,
- port: Number(process.env.DB_PORT),
- username: process.env.DB_USERNAME,
- password: process.env.DB_PASSWORD,
- database: process.env.DB_NAME,
- entities: [User, Account, License, LicenseAllocationHistory],
- });
- await datasource.initialize();
- } catch (e) {
- context.log("database initialize failed.");
- context.error(e);
- throw e;
- }
+ const datasource = await initializeDataSource(context);
let redisClient: RedisClient;
try {
// redis接続