Merged PR 186: API実装(カードライセンス発行API)
## 概要 [Task1992: API実装(カードライセンス発行API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1992) - タスク 1992: API実装(カードライセンス発行API) -カードライセンス発行APIを実装 ## レビューポイント - DB登録時の処理が適切かどうか ## UIの変更 なし ## 動作確認状況 ユニットテスト実施済み ローカルでの動作確認実施済み ## 補足 なし
This commit is contained in:
parent
3a7bf60f3e
commit
ceea4920f6
@ -113,6 +113,15 @@ export const LICENSE_STATUS_ISSUE_REQUESTING = 'Issue Requesting';
|
||||
*/
|
||||
export const LICENSE_STATUS_ISSUED = 'Issued';
|
||||
|
||||
/**
|
||||
* ライセンス種別
|
||||
* @const {string[]}
|
||||
*/
|
||||
export const LICENSE_TYPE = {
|
||||
TRIAL: 'TRIAL',
|
||||
NORMAL: 'NORMAL',
|
||||
CARD: 'CARD',
|
||||
} as const;
|
||||
/**
|
||||
* ライセンス状態
|
||||
* @const {string[]}
|
||||
@ -130,6 +139,12 @@ export const LICENSE_ALLOCATED_STATUS = {
|
||||
*/
|
||||
export const LICENSE_EXPIRATION_THRESHOLD_DAYS = 14;
|
||||
|
||||
/**
|
||||
* カードライセンスの桁数
|
||||
* @const {number}
|
||||
*/
|
||||
export const CARD_LICENSE_LENGTH = 20;
|
||||
|
||||
/**
|
||||
* 音声ファイルに紐づくオプションアイテムの数
|
||||
* @const {string}
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
Post,
|
||||
Req,
|
||||
UseGuards,
|
||||
HttpException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiResponse,
|
||||
@ -27,6 +28,7 @@ import { AuthGuard } from '../../common/guards/auth/authguards';
|
||||
import { RoleGuard } from '../../common/guards/role/roleguards';
|
||||
import { ADMIN_ROLES } from '../../constants';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
|
||||
@ApiTags('licenses')
|
||||
@Controller('licenses')
|
||||
@ -95,6 +97,7 @@ export class LicensesController {
|
||||
@ApiOperation({ operationId: 'issueCardLicenses' })
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(AuthGuard)
|
||||
@UseGuards(RoleGuard.requireds({ roles: [ADMIN_ROLES.ADMIN] }))
|
||||
@Post('/cards')
|
||||
async issueCardLicenses(
|
||||
@Req() req: Request,
|
||||
@ -103,13 +106,21 @@ export class LicensesController {
|
||||
console.log(req.header('Authorization'));
|
||||
console.log(body);
|
||||
|
||||
// レスポンス値のサンプル
|
||||
const cardLicenseKeys: string[] = [
|
||||
'3S5F9P7L4X1J6G2M8Q0Y',
|
||||
'9R7K2U1H5V3B6M0D8W4C',
|
||||
'2L0X5Y9P6U7Q1G4C3W8N',
|
||||
];
|
||||
const accessToken = retrieveAuthorizationToken(req);
|
||||
const payload = jwt.decode(accessToken, { json: true }) as AccessToken;
|
||||
|
||||
return { cardLicenseKeys };
|
||||
// 第一階層以外は401を返す(後々UseGuardsで弾く)
|
||||
if (payload.tier != 1) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000108'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const cardLicenseKeys = await this.licensesService.issueCardLicenseKeys(
|
||||
payload.userId,
|
||||
body.createCount,
|
||||
);
|
||||
|
||||
return cardLicenseKeys;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { CreateOrdersRequest } from './types/types';
|
||||
import {
|
||||
CreateOrdersRequest,
|
||||
IssueCardLicensesRequest,
|
||||
IssueCardLicensesResponse,
|
||||
} from './types/types';
|
||||
import {
|
||||
makeDefaultAccountsRepositoryMockValue,
|
||||
makeDefaultLicensesRepositoryMockValue,
|
||||
@ -9,6 +13,14 @@ import {
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { PoNumberAlreadyExistError } from '../../repositories/licenses/errors/types';
|
||||
import { LicensesService } from './licenses.service';
|
||||
import { makeTestingModule } from '../../common/test/modules';
|
||||
import { DataSource } from 'typeorm';
|
||||
import {
|
||||
createAccount,
|
||||
createUser,
|
||||
selectCardLicensesCount,
|
||||
} from './test/utility';
|
||||
|
||||
describe('LicensesService', () => {
|
||||
it('ライセンス注文が完了する', async () => {
|
||||
@ -109,4 +121,97 @@ describe('LicensesService', () => {
|
||||
),
|
||||
);
|
||||
});
|
||||
it('カードライセンス発行が完了する', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new IssueCardLicensesRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
body.createCount = 10;
|
||||
const issueCardLicensesResponse: IssueCardLicensesResponse = {
|
||||
cardLicenseKeys: [
|
||||
'WZCETXC0Z9PQZ9GKRGGY',
|
||||
'F0JD7EZEDBH4PQRQ83YF',
|
||||
'H0HXBP5K9RW7T7JSVDJV',
|
||||
'HKIWX54EESYL4X132223',
|
||||
'363E81JR460UBHXGFXFI',
|
||||
'70IKAPV9K6YMEVLTOXBY',
|
||||
'1RJY1TRRYYTGF1LL9WLU',
|
||||
'BXM0HKFO7IULTL0A1B36',
|
||||
'XYLEWNY2LR6Q657CZE41',
|
||||
'AEJWRFFSWRQYQQJ6WVLV',
|
||||
],
|
||||
};
|
||||
expect(
|
||||
await service.issueCardLicenseKeys(token.userId, body.createCount),
|
||||
).toEqual(issueCardLicensesResponse);
|
||||
});
|
||||
it('カードライセンス発行に失敗した場合、エラーになる', async () => {
|
||||
const lisencesRepositoryMockValue =
|
||||
makeDefaultLicensesRepositoryMockValue();
|
||||
lisencesRepositoryMockValue.createCardLicenses = new Error('DB failed');
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const accountsRepositoryMockValue =
|
||||
makeDefaultAccountsRepositoryMockValue();
|
||||
const service = await makeLicensesServiceMock(
|
||||
lisencesRepositoryMockValue,
|
||||
usersRepositoryMockValue,
|
||||
accountsRepositoryMockValue,
|
||||
);
|
||||
const body = new IssueCardLicensesRequest();
|
||||
const token: AccessToken = { userId: '0001', role: '', tier: 5 };
|
||||
body.createCount = 1000;
|
||||
await expect(
|
||||
service.issueCardLicenseKeys(token.userId, body.createCount),
|
||||
).rejects.toEqual(
|
||||
new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('DBテスト', () => {
|
||||
let source: DataSource = null;
|
||||
beforeEach(async () => {
|
||||
source = new DataSource({
|
||||
type: 'sqlite',
|
||||
database: ':memory:',
|
||||
logging: false,
|
||||
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||
});
|
||||
return source.initialize();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await source.destroy();
|
||||
source = null;
|
||||
});
|
||||
|
||||
it('カードライセンス発行が完了する(発行数が合っているか確認)', async () => {
|
||||
const module = await makeTestingModule(source);
|
||||
|
||||
const { accountId } = await createAccount(source);
|
||||
const { externalId } = await createUser(
|
||||
source,
|
||||
accountId,
|
||||
'userId',
|
||||
'admin',
|
||||
);
|
||||
|
||||
const service = module.get<LicensesService>(LicensesService);
|
||||
const issueCount = 1000;
|
||||
await service.issueCardLicenseKeys(externalId, issueCount);
|
||||
const dbSelectResult = await selectCardLicensesCount(source);
|
||||
expect(dbSelectResult.count).toEqual(issueCount);
|
||||
});
|
||||
});
|
||||
|
||||
@ -7,6 +7,7 @@ import { AccountNotFoundError } from '../../repositories/accounts/errors/types';
|
||||
import { PoNumberAlreadyExistError } from '../../repositories/licenses/errors/types';
|
||||
import { LicensesRepositoryService } from '../../repositories/licenses/licenses.repository.service';
|
||||
import { UserNotFoundError } from '../../repositories/users/errors/types';
|
||||
import { IssueCardLicensesResponse } from './types/types';
|
||||
|
||||
@Injectable()
|
||||
export class LicensesService {
|
||||
@ -38,6 +39,7 @@ export class LicensesService {
|
||||
myAccountId = (await this.usersRepository.findUserByExternalId(userId))
|
||||
.account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -58,6 +60,7 @@ export class LicensesService {
|
||||
await this.accountsRepository.findAccountById(myAccountId)
|
||||
).parent_account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case AccountNotFoundError:
|
||||
throw new HttpException(
|
||||
@ -94,4 +97,47 @@ export class LicensesService {
|
||||
}
|
||||
}
|
||||
}
|
||||
async issueCardLicenseKeys(
|
||||
externalId: string,
|
||||
createCount: number,
|
||||
): Promise<IssueCardLicensesResponse> {
|
||||
const issueCardLicensesResponse = new IssueCardLicensesResponse();
|
||||
let myAccountId: number;
|
||||
|
||||
// ユーザIDからアカウントIDを取得する
|
||||
try {
|
||||
myAccountId = (
|
||||
await this.usersRepository.findUserByExternalId(externalId)
|
||||
).account_id;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
switch (e.constructor) {
|
||||
case UserNotFoundError:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E010204'),
|
||||
HttpStatus.BAD_REQUEST,
|
||||
);
|
||||
default:
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const licenseKeys = await this.licensesRepository.createCardLicenses(
|
||||
myAccountId,
|
||||
createCount,
|
||||
);
|
||||
issueCardLicensesResponse.cardLicenseKeys = licenseKeys;
|
||||
return issueCardLicensesResponse;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
this.logger.error('get cardlicensekeys failed');
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,7 @@ import { AccountsRepositoryService } from '../../../repositories/accounts/accoun
|
||||
|
||||
export type LicensesRepositoryMockValue = {
|
||||
order: undefined | Error;
|
||||
createCardLicenses: string[] | Error;
|
||||
};
|
||||
|
||||
export type AccountsRepositoryMockValue = {
|
||||
@ -44,12 +45,18 @@ export const makeLicensesServiceMock = async (
|
||||
export const makeLicensesRepositoryMock = (
|
||||
value: LicensesRepositoryMockValue,
|
||||
) => {
|
||||
const { order } = value;
|
||||
const { order, createCardLicenses } = value;
|
||||
return {
|
||||
order:
|
||||
order instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(order)
|
||||
: jest.fn<Promise<void>, []>().mockResolvedValue(order),
|
||||
createCardLicenses:
|
||||
createCardLicenses instanceof Error
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(createCardLicenses)
|
||||
: jest
|
||||
.fn<Promise<string[]>, []>()
|
||||
.mockResolvedValue(createCardLicenses),
|
||||
};
|
||||
};
|
||||
|
||||
@ -81,6 +88,18 @@ export const makeDefaultLicensesRepositoryMockValue =
|
||||
(): LicensesRepositoryMockValue => {
|
||||
return {
|
||||
order: undefined,
|
||||
createCardLicenses: [
|
||||
'WZCETXC0Z9PQZ9GKRGGY',
|
||||
'F0JD7EZEDBH4PQRQ83YF',
|
||||
'H0HXBP5K9RW7T7JSVDJV',
|
||||
'HKIWX54EESYL4X132223',
|
||||
'363E81JR460UBHXGFXFI',
|
||||
'70IKAPV9K6YMEVLTOXBY',
|
||||
'1RJY1TRRYYTGF1LL9WLU',
|
||||
'BXM0HKFO7IULTL0A1B36',
|
||||
'XYLEWNY2LR6Q657CZE41',
|
||||
'AEJWRFFSWRQYQQJ6WVLV',
|
||||
],
|
||||
};
|
||||
};
|
||||
export const makeDefaultUsersRepositoryMockValue =
|
||||
|
||||
57
dictation_server/src/features/licenses/test/utility.ts
Normal file
57
dictation_server/src/features/licenses/test/utility.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import { DataSource } from 'typeorm';
|
||||
import { User } from '../../../repositories/users/entity/user.entity';
|
||||
import { Account } from '../../../repositories/accounts/entity/account.entity';
|
||||
import { CardLicense } from '../../../repositories/licenses/entity/license.entity';
|
||||
|
||||
export const createAccount = async (
|
||||
datasource: DataSource,
|
||||
): Promise<{ accountId: number }> => {
|
||||
const { identifiers } = await datasource.getRepository(Account).insert({
|
||||
tier: 1,
|
||||
country: 'JP',
|
||||
delegation_permission: false,
|
||||
locked: false,
|
||||
company_name: 'test inc.',
|
||||
verified: true,
|
||||
deleted_at: '',
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
const account = identifiers.pop() as Account;
|
||||
return { accountId: account.id };
|
||||
};
|
||||
|
||||
export const createUser = async (
|
||||
datasource: DataSource,
|
||||
accountId: number,
|
||||
external_id: string,
|
||||
role: string,
|
||||
author_id?: string | undefined,
|
||||
): Promise<{ userId: number; externalId: string }> => {
|
||||
const { identifiers } = await datasource.getRepository(User).insert({
|
||||
account_id: accountId,
|
||||
external_id: external_id,
|
||||
role: role,
|
||||
accepted_terms_version: '1.0',
|
||||
author_id: author_id,
|
||||
email_verified: true,
|
||||
auto_renew: true,
|
||||
license_alert: true,
|
||||
notification: true,
|
||||
created_by: 'test_runner',
|
||||
created_at: new Date(),
|
||||
updated_by: 'updater',
|
||||
updated_at: new Date(),
|
||||
});
|
||||
const user = identifiers.pop() as User;
|
||||
return { userId: user.id, externalId: external_id };
|
||||
};
|
||||
|
||||
export const selectCardLicensesCount = async (
|
||||
datasource: DataSource,
|
||||
): Promise<{ count: number }> => {
|
||||
const count = await datasource.getRepository(CardLicense).count();
|
||||
return { count: count };
|
||||
};
|
||||
@ -40,7 +40,7 @@ export class License {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
expiry_date: Date;
|
||||
|
||||
@Column()
|
||||
@ -52,16 +52,16 @@ export class License {
|
||||
@Column()
|
||||
status: string;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
allocated_user_id: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
order_id: number;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
deleted_at: Date;
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
delete_order_id: number;
|
||||
}
|
||||
@Entity({ name: 'licenses_history' })
|
||||
@ -84,3 +84,27 @@ export class LicenseHistory {
|
||||
@Column()
|
||||
exchange_type: string;
|
||||
}
|
||||
|
||||
@Entity({ name: 'card_license_issue' })
|
||||
export class CardLicenseIssue {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
issued_at: Date;
|
||||
}
|
||||
|
||||
@Entity({ name: 'card_licenses' })
|
||||
export class CardLicense {
|
||||
@PrimaryGeneratedColumn()
|
||||
license_id: number;
|
||||
|
||||
@Column()
|
||||
issue_id: number;
|
||||
|
||||
@Column()
|
||||
card_license_key: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
activated_at: Date;
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { LicenseOrder } from './entity/license.entity';
|
||||
import { CardLicense, CardLicenseIssue, License, LicenseOrder } from './entity/license.entity';
|
||||
import { LicensesRepositoryService } from './licenses.repository.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([LicenseOrder])],
|
||||
imports: [TypeOrmModule.forFeature([LicenseOrder,License,CardLicense,CardLicenseIssue])],
|
||||
providers: [LicensesRepositoryService],
|
||||
exports: [LicensesRepositoryService],
|
||||
})
|
||||
|
||||
@ -1,9 +1,17 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { LicenseOrder } from './entity/license.entity';
|
||||
import { DataSource, In } from 'typeorm';
|
||||
import {
|
||||
LicenseOrder,
|
||||
License,
|
||||
CardLicenseIssue,
|
||||
CardLicense,
|
||||
} from './entity/license.entity';
|
||||
import {
|
||||
CARD_LICENSE_LENGTH,
|
||||
LICENSE_ALLOCATED_STATUS,
|
||||
LICENSE_STATUS_ISSUE_REQUESTING,
|
||||
LICENSE_STATUS_ISSUED,
|
||||
LICENSE_TYPE,
|
||||
} from '../../constants';
|
||||
import { PoNumberAlreadyExistError } from './errors/types';
|
||||
|
||||
@ -57,4 +65,124 @@ export class LicensesRepositoryService {
|
||||
);
|
||||
return createdEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* カードライセンスを発行する
|
||||
* @param accountId
|
||||
* @param count
|
||||
* @returns string[] カードライセンスキーの配列
|
||||
*/
|
||||
async createCardLicenses(
|
||||
accountId: number,
|
||||
count: number,
|
||||
): Promise<string[]> {
|
||||
const licenseKeys: string[] = [];
|
||||
|
||||
await this.dataSource.transaction(async (entityManager) => {
|
||||
const licensesRepo = entityManager.getRepository(License);
|
||||
const cardLicenseRepo = entityManager.getRepository(CardLicense);
|
||||
const cardLicenseIssueRepo =
|
||||
entityManager.getRepository(CardLicenseIssue);
|
||||
|
||||
const licenses = [];
|
||||
// ライセンステーブルを作成する(BULK INSERT)
|
||||
for (let i = 0; i < count; i++) {
|
||||
const license = new License();
|
||||
license.account_id = accountId;
|
||||
license.status = LICENSE_ALLOCATED_STATUS.UNALLOCATED;
|
||||
license.type = LICENSE_TYPE.CARD;
|
||||
licenses.push(license);
|
||||
}
|
||||
const savedLicenses = await licensesRepo.save(licenses);
|
||||
|
||||
// カードライセンス発行テーブルを作成する
|
||||
const cardLicenseIssue = new CardLicenseIssue();
|
||||
cardLicenseIssue.issued_at = new Date();
|
||||
const newCardLicenseIssue = cardLicenseIssueRepo.create(cardLicenseIssue);
|
||||
const savedCardLicensesIssue = await cardLicenseIssueRepo.save(
|
||||
newCardLicenseIssue,
|
||||
);
|
||||
|
||||
let isDuplicateKeysExist = true;
|
||||
let generateCount = count;
|
||||
while (isDuplicateKeysExist) {
|
||||
const generateKeys = await this.generateLicenseKeys(
|
||||
generateCount,
|
||||
licenseKeys,
|
||||
);
|
||||
// licenseKeysが既にカードライセンステーブルに存在するかチェック
|
||||
const existingCardLicenses = await cardLicenseRepo.find({
|
||||
where: {
|
||||
card_license_key: In(generateKeys),
|
||||
},
|
||||
});
|
||||
if (existingCardLicenses.length > 0) {
|
||||
// 重複分を配列から削除
|
||||
existingCardLicenses.forEach((existKey) => {
|
||||
generateKeys.splice(
|
||||
generateKeys.indexOf(existKey.card_license_key),
|
||||
1,
|
||||
);
|
||||
});
|
||||
// 重複がなかったものを格納
|
||||
generateKeys.forEach((keys) => {
|
||||
licenseKeys.push(keys);
|
||||
});
|
||||
// 重複分の再生成を行う
|
||||
generateCount = existingCardLicenses.length;
|
||||
continue;
|
||||
}
|
||||
// 重複がない場合は本ループで作成したkeyをすべて格納
|
||||
generateKeys.forEach((keys) => {
|
||||
licenseKeys.push(keys);
|
||||
});
|
||||
// 重複がない場合はループを終了
|
||||
isDuplicateKeysExist = false;
|
||||
}
|
||||
|
||||
const cardLicenses = [];
|
||||
// カードライセンステーブルを作成する(BULK INSERT)
|
||||
for (let i = 0; i < count; i++) {
|
||||
const cardLicense = new CardLicense();
|
||||
cardLicense.license_id = savedLicenses[i].id; // Licenseテーブルの自動採番されたIDを挿入
|
||||
cardLicense.issue_id = savedCardLicensesIssue.id; // CardLicenseIssueテーブルの自動採番されたIDを挿入
|
||||
cardLicense.card_license_key = licenseKeys[i];
|
||||
cardLicenses.push(cardLicense);
|
||||
}
|
||||
await cardLicenseRepo.save(cardLicenses);
|
||||
});
|
||||
return licenseKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* ランダム(大文字英数字)の一意のライセンスキーを作成する。
|
||||
* @param count
|
||||
* @param existingLicenseKeys 既に作成されたライセンスキーの配列
|
||||
* @returns licenseKeys
|
||||
*/
|
||||
async generateLicenseKeys(
|
||||
count: number,
|
||||
existingLicenseKeys: string[],
|
||||
): Promise<string[]> {
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
|
||||
const licenseKeys: string[] = [];
|
||||
|
||||
while (licenseKeys.length < count) {
|
||||
let licenseKey = '';
|
||||
for (let i = 0; i < CARD_LICENSE_LENGTH; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * characters.length);
|
||||
licenseKey += characters[randomIndex];
|
||||
}
|
||||
|
||||
// 重複しない一意のライセンスキーを生成するまで繰り返す
|
||||
if (
|
||||
!licenseKeys.includes(licenseKey) &&
|
||||
!existingLicenseKeys.includes(licenseKey)
|
||||
) {
|
||||
licenseKeys.push(licenseKey);
|
||||
}
|
||||
}
|
||||
|
||||
return licenseKeys;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user