import { HttpException, HttpStatus } from '@nestjs/common'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; import { makeDefaultAdB2cMockValue, makeDefaultConfigValue, makeDefaultSendGridlValue, makeDefaultSortCriteriaRepositoryMockValue, makeDefaultUsersRepositoryMockValue, makeUsersServiceMock, } from './test/users.service.mock'; import { createLicense, createUserGroup, getLicenses, makeTestingModuleWithAdb2c, } from './test/utility'; import { DataSource } from 'typeorm'; import { UsersService } from './users.service'; import { ADB2C_SIGN_IN_TYPE, LICENSE_ALLOCATED_STATUS, LICENSE_EXPIRATION_THRESHOLD_DAYS, LICENSE_TYPE, MANUAL_RECOVERY_REQUIRED, TASK_STATUS, USER_AUDIO_FORMAT, USER_LICENSE_EXPIRY_STATUS, USER_ROLES, } from '../../constants'; import { makeTestingModule } from '../../common/test/modules'; import { Context, makeContext } from '../../common/log'; import { overrideAdB2cService, overrideBlobstorageService, overrideSendgridService, overrideUsersRepositoryService, } from '../../common/test/overrides'; import { NewTrialLicenseExpirationDate } from '../licenses/types/types'; import { License } from '../../repositories/licenses/entity/license.entity'; import { AdB2cService } from '../../gateways/adb2c/adb2c.service'; import { getUser, getUserArchive, getUserFromExternalId, getUsers, makeTestAccount, makeTestSimpleAccount, makeTestUser, } from '../../common/test/utility'; import { v4 as uuidv4 } from 'uuid'; import { createOptionItems, createWorktype } from '../accounts/test/utility'; import { createWorkflow, createWorkflowTypist, getWorkflows, } from '../workflows/test/utility'; import { truncateAllTable } from '../../common/test/init'; import { createTask } from '../files/test/utility'; import { createCheckoutPermissions } from '../tasks/test/utility'; import { MultipleImportErrors } from './types/types'; import { TestLogger } from '../../common/test/logger'; import { SendGridService } from '../../gateways/sendgrid/sendgrid.service'; describe('UsersService.confirmUser', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザの仮登録時に払い出されるトークンにより、未認証のユーザが認証済みになり、トライアルライセンスが100件作成される', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = (await makeTestAccount(source)).account; const { id: userId } = await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user2', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); const service = module.get(UsersService); let _subject: string = ''; let _url: string | undefined = ''; overrideSendgridService(service, { sendMail: async ( context: Context, to: string[], cc: string[], from: string, subject: string, text: string, html: string, ) => { const urlPattern = /https?:\/\/[^\s]+/g; const urls = text.match(urlPattern); const url = urls?.pop(); _subject = subject; _url = url; }, }); // account id:1, user id: 2のトークン const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; const context = makeContext(`uuidv4`, 'requestId'); await service.confirmUser(context, token); //result const resultUser = await getUser(source, userId); const resultLicenses = await getLicenses(source, accountId); // トライアルライセンスは有効期限は今日を起算日として30日後の日付が変わるまで const expiryDate = new NewTrialLicenseExpirationDate(); const resultLicensesCheckParam: Omit< License, 'deleted_at' | 'created_by' | 'created_at' | 'updated_at' | 'updated_by' > = { id: 0, expiry_date: resultLicenses[0].expiry_date, account_id: resultLicenses[0].account_id, type: resultLicenses[0].type, status: resultLicenses[0].status, allocated_user_id: resultLicenses[0].allocated_user_id, order_id: resultLicenses[0].order_id, delete_order_id: resultLicenses[0].delete_order_id, user: resultLicenses[0].user ?? null, }; expect(resultUser?.email_verified).toBe(true); expect(resultLicenses.length).toBe(100); expect(resultLicensesCheckParam).toEqual({ id: 0, expiry_date: expiryDate, account_id: accountId, type: LICENSE_TYPE.TRIAL, status: LICENSE_ALLOCATED_STATUS.UNALLOCATED, allocated_user_id: null, order_id: null, delete_order_id: null, user: null, }); expect(_subject).toBe('Account Registered Notification [U-101]'); expect(_url).toBe('http://localhost:8081/'); }); it('トークンの形式が不正な場合、形式不正エラーとなる。', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const token = 'invalid.id.token'; const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); await expect(service.confirmUser(context, token)).rejects.toEqual( new HttpException(makeErrorResponse('E000101'), HttpStatus.BAD_REQUEST), ); }); it('ユーザが既に認証済みだった場合、認証済みユーザエラーとなる。', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = (await makeTestAccount(source)).account; await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: true, //emailを認証済みにする }); await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user2', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; const context = makeContext(`uuidv4`, 'requestId'); await expect(service.confirmUser(context, token)).rejects.toEqual( new HttpException(makeErrorResponse('E010202'), HttpStatus.BAD_REQUEST), ); }); it('ユーザーが存在しない場合は、想定外のエラーとなる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); overrideSendgridService(service, {}); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; const context = makeContext(`uuidv4`, 'requestId'); await expect(service.confirmUser(context, token)).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); }); describe('UsersService.confirmUserAndInitPassword', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザーが発行されたパスワードでログインできるようにする', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); overrideAdB2cService(service, { changePassword: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); let _subject: string = ''; overrideSendgridService(service, { sendMail: async ( context: Context, to: string[], cc: string[], from: string, subject: string, text: string, html: string, ) => { _subject = subject; }, }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); expect(_subject).toBe('Temporary password [U-113]'); const user = await getUserFromExternalId(source, 'externalId_user1'); expect(user?.email_verified).toBe(true); }); it('トークンの形式が不正な場合、形式不正エラーとなる。(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const sendgridService = module.get(SendGridService); const adB2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); overrideAdB2cService(service, { changePassword: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, { sendMail: jest.fn(), }); const token = 'invalid.id.token'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E000101')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されていないことを確認 expect(user?.email_verified).toBe(false); // メールが送信されていないことを確認 expect(sendgridService.sendMail).toBeCalledTimes(0); // パスワードが変更されていないことを確認 expect(adB2cService.changePassword).toBeCalledTimes(0); }); it('ユーザが既に認証済みだった場合、認証済みユーザエラーとなる。(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const sendgridService = module.get(SendGridService); const adB2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: true, // emailを認証済みにする }); overrideAdB2cService(service, { changePassword: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, { sendMail: jest.fn(), }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010202')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されていることを確認 expect(user?.email_verified).toBe(true); // メールが送信されていないことを確認 expect(sendgridService.sendMail).toBeCalledTimes(0); // パスワードが変更されていないことを確認 expect(adB2cService.changePassword).toBeCalledTimes(0); }); it('ADB2Cユーザーのパスワード更新に失敗した場合、リカバリ処理を行い、メールを未認証のままにする。(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const sendgridService = module.get(SendGridService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); overrideAdB2cService(service, { changePassword: async () => { throw new Error('ADB2C Error'); }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, { sendMail: jest.fn(), }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されていないことを確認 expect(user?.email_verified).toBe(false); // メールが送信されていないことを確認 expect(sendgridService.sendMail).toBeCalledTimes(0); }); it('ADB2Cユーザーのパスワード更新に失敗した場合、リカバリ処理を行うが、リカバリ処理に失敗すると認証のままになる(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const sendgridService = module.get(SendGridService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); const loggerSpy = jest .spyOn(service['logger'], 'error') .mockImplementation(); overrideAdB2cService(service, { changePassword: async () => { throw new Error('ADB2C Error'); }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideUsersRepositoryService(service, { updateUserUnverified: async () => { throw new Error('DB Error'); }, }); overrideSendgridService(service, { sendMail: jest.fn(), }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されたままであることを確認 expect(user?.email_verified).toBe(true); // メールが送信されていないことを確認 expect(sendgridService.sendMail).toBeCalledTimes(0); // loggerSpyがスパイしているlogger.logメソッドが出力したログを確認(目視確認用) const logs = loggerSpy.mock.calls.map((call) => call[0]); // 手動復旧が必要なエラーログが出力されていること expect(logs.some((x) => x.startsWith(MANUAL_RECOVERY_REQUIRED))).toBe(true); }); it('DBネットワークエラーとなる場合、エラーとなる。(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const sendgridService = module.get(SendGridService); const adB2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); overrideAdB2cService(service, { changePassword: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, { sendMail: jest.fn(), }); // DBエラーを発生させる overrideUsersRepositoryService(service, { updateUserVerified: async () => { throw new Error('DB Error'); }, }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されていないことを確認 expect(user?.email_verified).toBe(false); // メールが送信されていないことを確認 expect(sendgridService.sendMail).toBeCalledTimes(0); // パスワードが変更されていないことを確認 expect(adB2cService.changePassword).toBeCalledTimes(0); }); it('メール送信に失敗した場合、リカバリ処理を行い、メールを未認証の状態にする。(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adb2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); overrideAdB2cService(service, { changePassword: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, { sendMail: async () => { throw new Error('SendGrid Error'); }, }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されていないことを確認 expect(user?.email_verified).toBe(false); // ADB2Cのパスワードが変更されていることを確認(パスワードは変更されても、ユーザーにメールが届いていないので問題ない) expect(adb2cService.changePassword).toBeCalledTimes(1); }); it('メール送信に失敗した場合、リカバリ処理を行うが、リカバリ処理に失敗するとADB2Cのパスワードが変更され、DB上も認証された状態になる(メール認証API)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adB2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; // ユーザー作成 await makeTestUser(source, { account_id: accountId, external_id: 'externalId_user1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, email_verified: false, }); const loggerSpy = jest .spyOn(service['logger'], 'error') .mockImplementation(); overrideAdB2cService(service, { changePassword: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideUsersRepositoryService(service, { updateUserUnverified: async () => { throw new Error('DB Error'); }, }); overrideSendgridService(service, { sendMail: async () => { throw new Error('SendGrid Error'); }, }); const token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw'; try { await service.confirmUserAndInitPassword( makeContext('trackingId', 'requestId'), token, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } const user = await getUserFromExternalId(source, 'externalId_user1'); // ユーザーが認証されたままであることを確認 expect(user?.email_verified).toBe(true); // ADB2Cのパスワードが変更されていることを確認 expect(adB2cService.changePassword).toBeCalledTimes(1); // loggerSpyがスパイしているlogger.logメソッドが出力したログを確認(目視確認用) const logs = loggerSpy.mock.calls.map((call) => call[0]); // 手動復旧が必要なエラーログが出力されていること expect(logs.some((x) => x.startsWith(MANUAL_RECOVERY_REQUIRED))).toBe(true); }); }); describe('UsersService.createUser', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:None)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); let _subject: string = ''; let _url: string | undefined = ''; overrideSendgridService(service, { sendMail: async ( context: Context, to: string[], cc: string[], from: string, subject: string, text: string, html: string, ) => { const urlPattern = /https?:\/\/[^\s]+/g; const urls = text.match(urlPattern); const url = urls?.pop(); _subject = subject; _url = url; }, }); expect( await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ), ).toEqual(undefined); // 追加されたユーザーが正しくDBに登録されていることを確認 const user = await getUserFromExternalId(source, externalId); expect(user).not.toBeNull(); expect(user?.account_id).toEqual(accountId); expect(user?.role).toEqual(role); expect(user?.author_id).toEqual(null); expect(user?.email_verified).toEqual(false); expect(user?.auto_renew).toEqual(autoRenew); expect(user?.notification).toEqual(notification); expect(user?.encryption).toEqual(false); expect(user?.encryption_password).toEqual(null); expect(user?.prompt).toEqual(false); // 他にユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(2); expect(_subject).toBe('User Registration Notification [U-114]'); expect( _url?.startsWith('http://localhost:8081/mail-confirm/user?verify='), ).toBeTruthy(); }); it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Author; 暗号化あり)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user2'; const role = USER_ROLES.AUTHOR; const email = 'test2@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const authorId = 'testID'; const encryption = true; const prompt = true; const encryptionPassword = 'testPassword'; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); expect( await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, authorId, encryption, encryptionPassword, prompt, ), ).toEqual(undefined); // 追加されたユーザーが正しくDBに登録されていることを確認 const user = await getUserFromExternalId(source, externalId); expect(user).not.toBeNull(); expect(user?.account_id).toEqual(accountId); expect(user?.role).toEqual(role); expect(user?.author_id).toEqual(authorId); expect(user?.email_verified).toEqual(false); expect(user?.auto_renew).toEqual(autoRenew); expect(user?.notification).toEqual(notification); expect(user?.encryption).toEqual(encryption); expect(user?.encryption_password).toEqual(encryptionPassword); expect(user?.prompt).toEqual(prompt); // 他にユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(2); }); it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Author; 暗号化無し)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user2'; const role = USER_ROLES.AUTHOR; const email = 'test2@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const authorId = 'testID'; const encryption = false; const prompt = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); expect( await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, authorId, encryption, undefined, prompt, ), ).toEqual(undefined); // 追加されたユーザーが正しくDBに登録されていることを確認 const user = await getUserFromExternalId(source, externalId); expect(user).not.toBeNull(); expect(user?.account_id).toEqual(accountId); expect(user?.role).toEqual(role); expect(user?.author_id).toEqual(authorId); expect(user?.email_verified).toEqual(false); expect(user?.auto_renew).toEqual(autoRenew); expect(user?.notification).toEqual(notification); expect(user?.encryption).toEqual(encryption); expect(user?.encryption_password).toBeNull(); expect(user?.prompt).toEqual(prompt); // 他にユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(2); }); it('管理者権限のあるアクセストークンを使用して、新規ユーザが追加される(role:Transcriptioninst)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user3'; const role = USER_ROLES.TYPIST; const email = 'test3@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); expect( await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ), ).toEqual(undefined); // 追加されたユーザーが正しくDBに登録されていることを確認 const user = await getUserFromExternalId(source, externalId); expect(user).not.toBeNull(); expect(user?.account_id).toEqual(accountId); expect(user?.role).toEqual(role); expect(user?.author_id).toBeNull(); expect(user?.email_verified).toEqual(false); expect(user?.auto_renew).toEqual(autoRenew); expect(user?.notification).toEqual(notification); expect(user?.encryption).toEqual(false); expect(user?.encryption_password).toBeNull(); expect(user?.prompt).toEqual(false); // 他にユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(2); }); it('DBネットワークエラーとなる場合、リカバリ処理を実施し、ADB2Cに作成したユーザーを削除する', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const b2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; await makeTestAccount(source, {}, { external_id: adminExternalId }); const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, deleteUser: jest.fn(), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); // DBエラーを発生させる overrideUsersRepositoryService(service, { createNormalUser: async () => { throw new Error('DB error'); }, }); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } // ADB2Cに作成したユーザーを削除するメソッドが呼ばれていることを確認 expect(b2cService.deleteUser).toBeCalledWith( externalId, makeContext('trackingId', 'requestId'), ); }); it('DBネットワークエラーとなる場合、リカバリ処理を実施されるが、そのリカバリ処理に失敗した場合、ADB2Cのユーザーは削除されない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const b2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, deleteUser: jest.fn().mockRejectedValue(new Error('ADB2C error')), getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); // DBエラーを発生させる overrideUsersRepositoryService(service, { createNormalUser: async () => { throw new Error('DB error'); }, }); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } // 新規ユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(1); //アカウントIDがテスト用の管理者ユーザーのものであることを確認 expect(users[0].account_id).toEqual(accountId); // ADB2Cに作成したユーザーを削除するメソッドが呼ばれていることを確認 expect(b2cService.deleteUser).toBeCalledWith( externalId, makeContext('trackingId', 'requestId'), ); }); it('Azure ADB2Cでネットワークエラーとなる場合、エラーとなる。', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; await makeTestAccount(source, {}, { external_id: adminExternalId }); const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); throw new Error('ADB2C error'); }, }); overrideSendgridService(service, {}); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } // ユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(1); }); it('Azure AD B2C内でメールアドレスが重複している場合、エラーとなる。', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; await makeTestAccount(source, {}, { external_id: adminExternalId }); const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); // Conflictエラーを返す return { reason: 'email', message: 'The email address is already in use by another account.', }; }, }); overrideSendgridService(service, {}); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010301')); } else { fail(); } } // ユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(1); }); it('AuthorIDが重複している場合、エラーとなる。(AuthorID重複チェックでエラー)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const adminExternalId = 'ADMIN0001'; await makeTestAccount(source, {}, { external_id: adminExternalId }); const name = 'test_user2'; const role = USER_ROLES.AUTHOR; const autoRenew = true; const licenseAlert = true; const notification = true; const authorId = 'testID'; const encryption = true; const prompt = true; const encryptionPassword = 'testPassword'; const email_1 = 'test_1@example.com'; const externalId_1 = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email_1).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId_1 }; }, getUser: async () => { return { id: adminExternalId, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); expect( await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email_1, autoRenew, notification, authorId, encryption, encryptionPassword, prompt, ), ).toEqual(undefined); { // 他にユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(2); } // Azure Ad B2CのMockをユーザー2用に切り替える const email_2 = 'test_1@example.com'; const externalId_2 = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email_2).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId_2 }; }, }); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email_2, autoRenew, notification, authorId, encryption, encryptionPassword, prompt, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010302')); } else { fail(); } } // 新規にユーザーが登録されていないことを確認 { const users = await getUsers(source); expect(users.length).toEqual(2); } }); it('AuthorIDが重複している場合、エラー(insert失敗)となり、リカバリ処理が実行され、ADB2Cに追加したユーザーが削除される', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const b2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user2'; const role = USER_ROLES.AUTHOR; const email = 'test2@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const authorId = 'testID'; const encryption = true; const prompt = true; const encryptionPassword = 'testPassword'; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, deleteUser: jest.fn(), }); overrideSendgridService(service, {}); // AuthorIDのUNIQUE制約エラーを発生させる overrideUsersRepositoryService(service, { createNormalUser: async () => { throw { code: 'ER_DUP_ENTRY' }; }, }); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, authorId, encryption, encryptionPassword, prompt, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010302')); } else { fail(); } } // 新規にユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(1); expect(users[0].account_id).toEqual(accountId); // ADB2Cに作成したユーザーを削除するメソッドが呼ばれていることを確認 expect(b2cService.deleteUser).toBeCalledWith( externalId, makeContext('trackingId', 'requestId'), ); }); it('メール送信に失敗した場合、リカバリ処理が実行され、ADB2C,DBのユーザーが削除される', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const b2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; const { account } = await makeTestAccount( source, {}, { external_id: adminExternalId }, ); const { id: accountId } = account; const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, deleteUser: jest.fn(), }); overrideSendgridService(service, {}); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } // 新規ユーザーが登録されていないことを確認 const users = await getUsers(source); expect(users.length).toEqual(1); //アカウントIDがテスト用の管理者ユーザーのものであることを確認 expect(users[0].account_id).toEqual(accountId); // ADB2Cに作成したユーザーを削除するメソッドが呼ばれていることを確認 expect(b2cService.deleteUser).toBeCalledWith( externalId, makeContext('trackingId', 'requestId'), ); }); it('メール送信に失敗した場合、リカバリ処理が実行されるが、そのリカバリ処理に失敗した場合、ADB2C,DBのユーザーが削除されない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const service = module.get(UsersService); const b2cService = module.get(AdB2cService); const adminExternalId = 'ADMIN0001'; await makeTestAccount(source, {}, { external_id: adminExternalId }); const name = 'test_user1'; const role = USER_ROLES.NONE; const email = 'test1@example.com'; const autoRenew = true; const licenseAlert = true; const notification = true; const externalId = '0001'; overrideAdB2cService(service, { createUser: async ( _context: Context, _email: string, _password: string, _username: string, ) => { // ユーザー作成時に指定したパラメータが正しく渡されていることを確認 expect(email).toEqual(_email); expect(name).toEqual(_username); return { sub: externalId }; }, deleteUser: jest.fn().mockRejectedValue(new Error()), }); overrideSendgridService(service, { sendMail: async () => { throw new Error(); }, }); overrideUsersRepositoryService(service, { deleteNormalUser: async () => { throw new Error(); }, }); try { await service.createUser( makeContext('trackingId', 'requestId'), adminExternalId, name, role, email, autoRenew, notification, ); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } // リカバリ処理が失敗したため、DBのユーザーが削除されないことを確認 const users = await getUsers(source); expect(users.length).toEqual(2); // ADB2Cに作成したユーザーを削除するメソッドが呼ばれていることを確認 expect(b2cService.deleteUser).toBeCalledWith( externalId, makeContext('trackingId', 'requestId'), ); }); }); describe('UsersService.getUsers', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザーの一覧を取得できる(ライセンス未割当)', async () => { const adb2cParam = makeDefaultAdB2cMockValue(); if (!source) fail(); const module = await makeTestingModuleWithAdb2c(source, adb2cParam); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: typistUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id2', role: 'typist', author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { external_id: externalId_author, id: authorUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: 'author', author_id: 'AUTHOR_ID', auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); await createUserGroup(source, accountId, 'group1', [typistUserId]); const { id: noneUserId } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id3', role: 'none', author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const service = module.get(UsersService); const expectedUsers = [ { id: authorUserId, name: 'test1', role: 'author', authorId: 'AUTHOR_ID', typistGroupName: [], email: 'test1@mail.com', emailVerified: true, autoRenew: true, notification: true, encryption: false, prompt: false, expiration: undefined, remaining: undefined, licenseStatus: USER_LICENSE_EXPIRY_STATUS.NO_LICENSE, }, { id: typistUserId, name: 'test2', role: 'typist', authorId: undefined, typistGroupName: ['group1'], email: 'test2@mail.com', emailVerified: true, autoRenew: true, notification: true, encryption: false, prompt: false, expiration: undefined, remaining: undefined, licenseStatus: USER_LICENSE_EXPIRY_STATUS.NO_LICENSE, }, { id: noneUserId, name: 'test3', role: 'none', authorId: undefined, typistGroupName: [], email: 'test3@mail.com', emailVerified: true, autoRenew: true, notification: true, encryption: false, prompt: false, expiration: undefined, remaining: undefined, licenseStatus: USER_LICENSE_EXPIRY_STATUS.NO_LICENSE, }, ]; const context = makeContext(`uuidv4`, 'requestId'); expect(await service.getUsers(context, externalId_author)).toEqual( expectedUsers, ); }); it('ユーザーの一覧を取得できること(ライセンス割当済み)', async () => { const adb2cParam = makeDefaultAdB2cMockValue(); if (!source) fail(); const module = await makeTestingModuleWithAdb2c(source, adb2cParam); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { id: user1, external_id: external_id1 } = await makeTestUser( source, { account_id: accountId, external_id: 'external_id1', role: 'author', author_id: 'AUTHOR_ID1', auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }, ); const { id: user2 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id2', role: 'author', author_id: 'AUTHOR_ID2', auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user3 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id3', role: 'author', author_id: 'AUTHOR_ID3', auto_renew: false, encryption: false, encryption_password: undefined, prompt: false, }); const date1 = new Date(); date1.setDate(date1.getDate() + LICENSE_EXPIRATION_THRESHOLD_DAYS + 1); const date2 = new Date(); date2.setDate(date2.getDate() + LICENSE_EXPIRATION_THRESHOLD_DAYS); const date3 = new Date(); date3.setDate(date3.getDate() + LICENSE_EXPIRATION_THRESHOLD_DAYS - 1); await createLicense(source, accountId, user1, date1); await createLicense(source, accountId, user2, date2); await createLicense(source, accountId, user3, date3); const service = module.get(UsersService); const expectedUsers = [ { id: user1, name: 'test1', role: 'author', authorId: 'AUTHOR_ID1', typistGroupName: [], email: 'test1@mail.com', emailVerified: true, autoRenew: true, notification: true, encryption: false, prompt: false, expiration: `${date1.getFullYear()}/${ date1.getMonth() + 1 }/${date1.getDate()}`, remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS + 1, licenseStatus: USER_LICENSE_EXPIRY_STATUS.NORMAL, }, { id: user2, name: 'test2', role: 'author', authorId: 'AUTHOR_ID2', typistGroupName: [], email: 'test2@mail.com', emailVerified: true, autoRenew: true, notification: true, encryption: false, prompt: false, expiration: `${date2.getFullYear()}/${ date2.getMonth() + 1 }/${date2.getDate()}`, remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS, licenseStatus: USER_LICENSE_EXPIRY_STATUS.RENEW, }, { id: user3, name: 'test3', role: 'author', authorId: 'AUTHOR_ID3', typistGroupName: [], email: 'test3@mail.com', emailVerified: true, autoRenew: false, notification: true, encryption: false, prompt: false, expiration: `${date3.getFullYear()}/${ date3.getMonth() + 1 }/${date3.getDate()}`, remaining: LICENSE_EXPIRATION_THRESHOLD_DAYS - 1, licenseStatus: USER_LICENSE_EXPIRY_STATUS.ALERT, }, ]; const context = makeContext(`uuidv4`, 'requestId'); expect(await service.getUsers(context, external_id1)).toEqual( expectedUsers, ); }); it('DBからのユーザーの取得に失敗した場合、エラーとなる', async () => { const adb2cParam = makeDefaultAdB2cMockValue(); if (!source) fail(); const module = await makeTestingModuleWithAdb2c(source, adb2cParam); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: 'author', author_id: 'AUTHOR_ID', auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const context = makeContext(`uuidv4`, 'requestId'); const service = module.get(UsersService); await expect( service.getUsers(context, 'externalId_failed'), ).rejects.toEqual( new HttpException(makeErrorResponse('E009999'), HttpStatus.NOT_FOUND), ); }); it('ADB2Cからのユーザーの取得に失敗した場合、エラーとなる', async () => { const adb2cParam = makeDefaultAdB2cMockValue(); adb2cParam.getUsers = new Error('ADB2C error'); if (!source) fail(); const module = await makeTestingModuleWithAdb2c(source, adb2cParam); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: externalId_author } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: 'author', author_id: 'AUTHOR_ID', auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const context = makeContext(`uuidv4`, 'requestId'); const service = module.get(UsersService); await expect(service.getUsers(context, externalId_author)).rejects.toEqual( new HttpException(makeErrorResponse('E009999'), HttpStatus.NOT_FOUND), ); }); }); describe('UsersService.updateSortCriteria', () => { it('ソート条件を変更できる', async () => { const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const licensesRepositoryMockValue = null; const adb2cParam = makeDefaultAdB2cMockValue(); const sendgridMockValue = makeDefaultSendGridlValue(); const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); const service = await makeUsersServiceMock( usersRepositoryMockValue, licensesRepositoryMockValue, adb2cParam, sendgridMockValue, configMockValue, sortCriteriaRepositoryMockValue, ); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateSortCriteria( context, 'AUTHOR_ID', 'ASC', 'external_id', ), ).toEqual(undefined); }); it('ユーザー情報が存在せず、ソート条件を変更できない', async () => { const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const licensesRepositoryMockValue = null; const adb2cParam = makeDefaultAdB2cMockValue(); const sendgridMockValue = makeDefaultSendGridlValue(); const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); usersRepositoryMockValue.findUserByExternalId = new Error('user not found'); const service = await makeUsersServiceMock( usersRepositoryMockValue, licensesRepositoryMockValue, adb2cParam, sendgridMockValue, configMockValue, sortCriteriaRepositoryMockValue, ); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.updateSortCriteria(context, 'AUTHOR_ID', 'ASC', 'external_id'), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('ソート条件が存在せず、ソート条件を変更できない', async () => { const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const licensesRepositoryMockValue = null; const adb2cParam = makeDefaultAdB2cMockValue(); const sendgridMockValue = makeDefaultSendGridlValue(); const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); sortCriteriaRepositoryMockValue.updateSortCriteria = new Error( 'sort criteria not found', ); const service = await makeUsersServiceMock( usersRepositoryMockValue, licensesRepositoryMockValue, adb2cParam, sendgridMockValue, configMockValue, sortCriteriaRepositoryMockValue, ); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.updateSortCriteria(context, 'AUTHOR_ID', 'ASC', 'external_id'), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); }); describe('UsersService.getSortCriteria', () => { it('ソート条件を取得できる', async () => { const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const licensesRepositoryMockValue = null; const adb2cParam = makeDefaultAdB2cMockValue(); const sendgridMockValue = makeDefaultSendGridlValue(); const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); const service = await makeUsersServiceMock( usersRepositoryMockValue, licensesRepositoryMockValue, adb2cParam, sendgridMockValue, configMockValue, sortCriteriaRepositoryMockValue, ); const context = makeContext(`uuidv4`, 'requestId'); expect(await service.getSortCriteria(context, 'external_id')).toEqual({ direction: 'ASC', paramName: 'JOB_NUMBER', }); }); it('ソート条件が存在せず、ソート条件を取得できない', async () => { const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const licensesRepositoryMockValue = null; const adb2cParam = makeDefaultAdB2cMockValue(); const sendgridMockValue = makeDefaultSendGridlValue(); const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); sortCriteriaRepositoryMockValue.getSortCriteria = new Error( 'sort criteria not found', ); const service = await makeUsersServiceMock( usersRepositoryMockValue, licensesRepositoryMockValue, adb2cParam, sendgridMockValue, configMockValue, sortCriteriaRepositoryMockValue, ); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.getSortCriteria(context, 'external_id'), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); it('DBから取得した値が不正だった場合、エラーとなる', async () => { const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); const licensesRepositoryMockValue = null; const adb2cParam = makeDefaultAdB2cMockValue(); const sendgridMockValue = makeDefaultSendGridlValue(); const configMockValue = makeDefaultConfigValue(); const sortCriteriaRepositoryMockValue = makeDefaultSortCriteriaRepositoryMockValue(); sortCriteriaRepositoryMockValue.getSortCriteria = { id: 1, direction: 'AAA', parameter: 'BBBBB', user_id: 1, }; const service = await makeUsersServiceMock( usersRepositoryMockValue, licensesRepositoryMockValue, adb2cParam, sendgridMockValue, configMockValue, sortCriteriaRepositoryMockValue, ); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.getSortCriteria(context, 'external_id'), ).rejects.toEqual( new HttpException( makeErrorResponse('E009999'), HttpStatus.INTERNAL_SERVER_ERROR, ), ); }); }); describe('UsersService.updateUser', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザー情報を更新できる(None)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.NONE, undefined, false, false, undefined, undefined, undefined, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.NONE); expect(createdUser?.author_id).toBeNull(); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(false); expect(createdUser?.encryption_password).toBeNull(); expect(createdUser?.prompt).toBe(false); }); it('ユーザー情報を更新できる(Typist)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.TYPIST, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.TYPIST, undefined, false, false, undefined, undefined, undefined, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.TYPIST); expect(createdUser?.author_id).toBeNull(); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(false); expect(createdUser?.encryption_password).toBeNull(); expect(createdUser?.prompt).toBe(false); }); it('ユーザー情報を更新できる(Author)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.AUTHOR, author_id: undefined, auto_renew: true, encryption: true, encryption_password: 'password', prompt: true, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.AUTHOR, 'AUTHOR_ID', false, false, true, 'new_password', true, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.AUTHOR); expect(createdUser?.author_id).toBe('AUTHOR_ID'); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(true); expect(createdUser?.encryption_password).toBe('new_password'); expect(createdUser?.prompt).toBe(true); }); it('ユーザーのRoleを更新できる(None⇒Typist)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.TYPIST, undefined, false, false, undefined, undefined, undefined, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.TYPIST); expect(createdUser?.author_id).toBeNull(); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(false); expect(createdUser?.encryption_password).toBeNull(); expect(createdUser?.prompt).toBe(false); }); it('ユーザーのRoleを更新できる(None⇒Author)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.AUTHOR, 'AUTHOR_ID', false, false, false, undefined, false, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.AUTHOR); expect(createdUser?.author_id).toBe('AUTHOR_ID'); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(false); expect(createdUser?.encryption_password).toBeNull(); expect(createdUser?.prompt).toBe(false); }); it('None以外からRoleを変更した場合、エラーとなる(Typist⇒None)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.TYPIST, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.updateUser( context, external_id, user1, USER_ROLES.NONE, undefined, false, false, undefined, undefined, undefined, ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010207'), HttpStatus.BAD_REQUEST), ); }); it('Authorがパスワードundefinedで渡されたとき、元のパスワードを維持する(Encryptionがtrue)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_ID', auto_renew: true, encryption: true, encryption_password: 'password', prompt: true, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.AUTHOR, 'AUTHOR_ID', false, false, true, undefined, true, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.AUTHOR); expect(createdUser?.author_id).toBe('AUTHOR_ID'); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(true); expect(createdUser?.encryption_password).toBe('password'); expect(createdUser?.prompt).toBe(true); }); it('Authorが暗号化なしで更新した場合、パスワードをNULLにする(Encryptionがfalse)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_ID', auto_renew: true, encryption: false, encryption_password: 'password', prompt: true, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); expect( await service.updateUser( context, external_id, user1, USER_ROLES.AUTHOR, 'AUTHOR_ID', false, false, false, 'password', true, ), ).toEqual(undefined); const createdUser = await getUser(source, user1); expect(createdUser?.id).toBe(user1); expect(createdUser?.role).toBe(USER_ROLES.AUTHOR); expect(createdUser?.author_id).toBe('AUTHOR_ID'); expect(createdUser?.auto_renew).toBe(false); expect(createdUser?.notification).toBe(false); expect(createdUser?.encryption).toBe(false); expect(createdUser?.encryption_password).toBeNull(); expect(createdUser?.prompt).toBe(true); }); it('AuthorのDBにパスワードが設定されていない場合、パスワードundefinedでわたすとエラーとなる(Encryptionがtrue)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_ID', auto_renew: true, encryption: true, encryption_password: undefined, prompt: true, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.updateUser( context, external_id, user1, USER_ROLES.AUTHOR, 'AUTHOR_ID', false, false, true, undefined, true, ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010208'), HttpStatus.BAD_REQUEST), ); }); it('AuthorIdが既存のユーザーと重複した場合、エラーとなる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { id: accountId } = await makeTestSimpleAccount(source); const { external_id: external_id } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id', role: USER_ROLES.NONE, author_id: undefined, auto_renew: true, encryption: false, encryption_password: undefined, prompt: false, }); const { id: user1 } = await makeTestUser(source, { account_id: accountId, external_id: 'external_id1', role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_ID1', auto_renew: true, encryption: true, encryption_password: 'password', prompt: true, }); await makeTestUser(source, { account_id: accountId, external_id: 'external_id2', role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_ID2', auto_renew: true, encryption: true, encryption_password: 'password', prompt: true, }); const service = module.get(UsersService); overrideSendgridService(service, {}); const context = makeContext(`uuidv4`, 'requestId'); await expect( service.updateUser( context, external_id, user1, USER_ROLES.AUTHOR, 'AUTHOR_ID2', false, false, true, undefined, true, ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010302'), HttpStatus.BAD_REQUEST), ); }); }); describe('UsersService.updateAcceptedVersion', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('同意済み利用規約バージョンを更新できる(第五)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { admin } = await makeTestAccount(source, { tier: 5, }); const context = makeContext(uuidv4(), 'requestId'); const service = module.get(UsersService); await service.updateAcceptedVersion( context, admin.external_id, 'v2.0', 'v2.0', ); const user = await getUser(source, admin.id); expect(user?.accepted_eula_version).toBe('v2.0'); }); it('同意済み利用規約バージョンを更新できる(第一~第四)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { admin } = await makeTestAccount(source, { tier: 4, }); const context = makeContext(uuidv4(), 'requestId'); const service = module.get(UsersService); await service.updateAcceptedVersion( context, admin.external_id, 'v2.0', 'v2.0', 'v3.0', ); const user = await getUser(source, admin.id); expect(user?.accepted_eula_version).toBe('v2.0'); expect(user?.accepted_dpa_version).toBe('v3.0'); }); it('パラメータが不在のときエラーとなる(第一~第四)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { admin } = await makeTestAccount(source, { tier: 4, }); const context = makeContext(uuidv4(), 'requestId'); const service = module.get(UsersService); await expect( service.updateAcceptedVersion( context, admin.external_id, 'v2.0', 'v2.0', undefined, ), ).rejects.toEqual( new HttpException(makeErrorResponse('E010001'), HttpStatus.BAD_REQUEST), ); }); }); describe('UsersService.getUserName', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザーが存在しない場合は、ユーザー未存在エラー', async () => { if (!source) fail(); try { const module = await makeTestingModule(source); if (!module) fail(); const context = makeContext(uuidv4(), 'requestId'); const service = module.get(UsersService); await service.getUserName(context, 'external_id'); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010204')); } else { fail(); } } }); }); describe('UsersService.getRelations', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザー関連情報を取得できる(Author)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_1', encryption: true, encryption_password: 'password', prompt: true, }); const { id: user2 } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_2', }); await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_3', email_verified: false, }); const worktype1 = await createWorktype( source, account.id, 'worktypeB', undefined, true, ); await createOptionItems(source, worktype1.id); const worktype2 = await createWorktype(source, account.id, 'worktypeC'); await createOptionItems(source, worktype2.id); const worktype3 = await createWorktype(source, account.id, 'worktypeA'); await createOptionItems(source, worktype3.id); await createWorkflow(source, account.id, user1, worktype1.id); await createWorkflow(source, account.id, user1, worktype2.id); await createWorkflow(source, account.id, user1, worktype3.id); await createWorkflow(source, account.id, user1); await createWorkflow(source, account.id, user2, worktype1.id); // 作成したデータを確認 { const workflows = await getWorkflows(source, account.id); workflows.sort((a, b) => a.id - b.id); expect(workflows.length).toBe(5); expect(workflows[0].worktype_id).toBe(worktype1.id); expect(workflows[0].author_id).toBe(user1); expect(workflows[1].worktype_id).toBe(worktype2.id); expect(workflows[1].author_id).toBe(user1); expect(workflows[2].worktype_id).toBe(worktype3.id); expect(workflows[2].author_id).toBe(user1); expect(workflows[3].worktype_id).toBe(null); expect(workflows[3].author_id).toBe(user1); expect(workflows[4].worktype_id).toBe(worktype1.id); expect(workflows[4].author_id).toBe(user2); } const context = makeContext(external_id, 'requestId'); const service = module.get(UsersService); const relations = await service.getRelations(context, external_id); // レスポンスを確認 { expect(relations.authorId).toBe('AUTHOR_1'); expect(relations.authorIdList.length).toBe(2); expect(relations.authorIdList[0]).toBe('AUTHOR_1'); expect(relations.authorIdList[1]).toBe('AUTHOR_2'); const workTypeList = relations.workTypeList; expect(relations.workTypeList.length).toBe(3); // Workflowの作成順ではなくcustom_worktype_idの昇順で取得するためWorkTypeListの先頭はworktype3 expect(workTypeList[0].workTypeId).toBe(worktype3.custom_worktype_id); expect(workTypeList[0].optionItemList.length).toBe(10); expect(workTypeList[0].optionItemList[0].label).toBe(''); expect(workTypeList[0].optionItemList[0].initialValueType).toBe(2); expect(workTypeList[0].optionItemList[0].defaultValue).toBe(''); expect(workTypeList[1].workTypeId).toBe(worktype1.custom_worktype_id); expect(workTypeList[1].optionItemList.length).toBe(10); expect(workTypeList[2].workTypeId).toBe(worktype2.custom_worktype_id); expect(workTypeList[2].optionItemList.length).toBe(10); expect(relations.isEncrypted).toBe(true); expect(relations.encryptionPassword).toBe('password'); expect(relations.activeWorktype).toBe(worktype1.custom_worktype_id); expect(relations.audioFormat).toBe(USER_AUDIO_FORMAT); expect(relations.prompt).toBe(true); } }); it('ユーザー関連情報を取得できる(Author以外)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account } = await makeTestAccount(source, { tier: 5, }); const { external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.TYPIST, encryption: false, prompt: false, }); const { id: user2 } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_2', }); const worktype1 = await createWorktype(source, account.id, 'worktype1'); await createOptionItems(source, worktype1.id); await createWorkflow(source, account.id, user2, worktype1.id); // 作成したデータを確認 { const workflows = await getWorkflows(source, account.id); expect(workflows.length).toBe(1); expect(workflows[0].worktype_id).toBe(worktype1.id); expect(workflows[0].author_id).toBe(user2); } const context = makeContext(external_id, 'requestId'); const service = module.get(UsersService); const relations = await service.getRelations(context, external_id); // レスポンスを確認 { expect(relations.authorId).toBe(undefined); expect(relations.authorIdList.length).toBe(1); expect(relations.authorIdList[0]).toBe('AUTHOR_2'); expect(relations.workTypeList.length).toBe(0); expect(relations.isEncrypted).toBe(false); expect(relations.encryptionPassword).toBe(undefined); expect(relations.activeWorktype).toBe(''); expect(relations.audioFormat).toBe(USER_AUDIO_FORMAT); expect(relations.prompt).toBe(false); } }); it('ユーザーが存在しない場合は、ユーザー未存在エラー', async () => { if (!source) fail(); try { const module = await makeTestingModule(source); if (!module) fail(); const context = makeContext(uuidv4(), 'requestId'); const service = module.get(UsersService); await service.getRelations(context, 'external_id'); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E010204')); } else { fail(); } } }); }); describe('UsersService.deleteUser', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザーを削除できる(Author)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR_1', }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); // ユーザーが削除されたことを確認 { const user = await getUser(source, user1); expect(user).toBeNull(); // ユーザアーカイブが作成されたことを確認 const userArchive = await getUserArchive(source); expect(userArchive[0].external_id).toBe(external_id); } }); it('ユーザーを削除できる(Typist)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.TYPIST, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); // ユーザーが削除されたことを確認 { const user = await getUser(source, user1); expect(user).toBeNull(); // ユーザアーカイブが作成されたことを確認 const userArchive = await getUserArchive(source); expect(userArchive[0].external_id).toBe(external_id); } },600000); it('存在しないユーザは削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); // 現在日付を作成 const now = new Date(); try { await service.deleteUser(context, 100, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014001')); } else { fail(); } } }); it('管理者ユーザは削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); // 現在日付を作成 const now = new Date(); try { await service.deleteUser(context, admin.id, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014002')); } else { fail(); } } }); it('WorkFlowに割り当てられているユーザ(Author)は削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); const worktype1 = await createWorktype( source, account.id, 'worktype1', undefined, true, ); await createOptionItems(source, worktype1.id); await createWorkflow(source, account.id, user1, worktype1.id); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014003')); } else { fail(); } } }); it('WorkFlowに割り当てられているユーザ(Typist)は削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); const worktype1 = await createWorktype( source, account.id, 'worktype1', undefined, true, ); await createOptionItems(source, worktype1.id); const workflow1 = await createWorkflow( source, account.id, user1, worktype1.id, ); await createWorkflowTypist(source, workflow1.id, user2); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user2, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014004')); } else { fail(); } } }); it('ユーザグループに所属しているユーザは削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // ユーザグループを作成 const userGroup = await createUserGroup(source, account.id, 'userGroup', [ user1, user2, ]); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user2, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014005')); } else { fail(); } } }); it('削除対象ユーザー(Author)のAuthorIDが設定されているタスクがある場合、削除できない(statusがInprogress)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // タスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.IN_PROGRESS, user2, 'AUTHOR', admin.id, // 作成者がadmin ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014006')); } else { fail(); } } }); it('削除対象ユーザー(Author)のAuthorIDが設定されているタスクがある場合、削除できない(statusがFinished)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // タスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.FINISHED, user2, 'AUTHOR', admin.id, // 作成者がadmin ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014006')); } else { fail(); } } }); it('削除対象ユーザー(Author)のAuthorIDが設定されているタスクがある場合、削除できない(statusがBackup)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // タスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.BACKUP, user2, 'AUTHOR', admin.id, // 作成者がadmin ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014006')); } else { fail(); } } }); it('削除対象ユーザー(Author)が有効なタスクをまだ持っている場合、削除できない(statusがInprogress)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // タスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.IN_PROGRESS, user2, 'AUTHOR', user1, ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014006')); } else { fail(); } } }); it('削除対象ユーザー(Author)が有効なタスクをまだ持っている場合、削除できない(statusがFinished)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // タスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.FINISHED, user2, 'AUTHOR', user1, ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014006')); } else { fail(); } } }); it('削除対象ユーザー(Author)が有効なタスクをまだ持っている場合、削除できない(statusがBackup)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // タスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.BACKUP, user2, 'AUTHOR', user1, ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user1, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014006')); } else { fail(); } } }); it('削除対象ユーザー(Typist)タスクのチェックアウト権限まだ持っている場合、削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // CheckoutPermissionを作成 await createCheckoutPermissions(source, 100, user2); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user2, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014009')); } else { fail(); } } }); it('削除対象ユーザー(Typist)が文字起こし担当のタスクがまだ持っている場合、削除できない(statusがFinished)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // user2が文字起こし担当のタスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.FINISHED, user2, 'AUTHOR', user1, ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user2, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014009')); } else { fail(); } } },600000); it('削除対象ユーザー(Typist)が文字起こし担当のタスクがまだ持っている場合、削除できない(statusがBackup)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // user2が文字起こし担当のタスクを作成 await createTask( source, account.id, 'task-url', 'filename', TASK_STATUS.BACKUP, user2, 'AUTHOR', user1, ); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user2, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014009')); } else { fail(); } } }); it('削除対象ユーザーが有効なライセンスをまだ持っている場合、削除できない', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account, admin } = await makeTestAccount(source, { tier: 5, }); const { id: user1, external_id } = await makeTestUser(source, { account_id: account.id, role: USER_ROLES.AUTHOR, author_id: 'AUTHOR', }); const { id: user2, external_id: external_id2 } = await makeTestUser( source, { account_id: account.id, role: USER_ROLES.TYPIST, }, ); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); // 明日まで有効なライセンスを作成して紐づける const tomorrow = new Date(); tomorrow.setDate(tomorrow.getDate() + 1); await createLicense(source, account.id, user2, tomorrow); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, { id: external_id, displayName: 'user1', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user1@example.com', }, ], }, { id: external_id2, displayName: 'user2', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'user2@example.com', }, ], }, ]; }, getUser: async () => { return { id: admin.external_id, displayName: 'admin', }; }, }); overrideSendgridService(service, {}); try { // 現在日付を作成 const now = new Date(); await service.deleteUser(context, user2, now); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.BAD_REQUEST); expect(e.getResponse()).toEqual(makeErrorResponse('E014007')); } else { fail(); } } }); }); describe('UsersService.multipleImports', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザー一括登録ができる', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account: dealer } = await makeTestAccount(source, { company_name: 'dealerCompany', tier: 4, }); const { account, admin } = await makeTestAccount(source, { tier: 5, company_name: 'company', parent_account_id: dealer.id, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, ]; }, }); overrideSendgridService(service, {}); overrideBlobstorageService(service, { uploadImportsBlob: async () => {}, }); // メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。 const spy = jest .spyOn(service['sendgridService'], 'sendMailWithU120') .mockImplementation(); const now = new Date(); const date = `${now.getFullYear()}.${now.getMonth() + 1}.${now.getDate()}`; const filename = 'fileName.csv'; const users = [ { name: 'name1', email: 'mail1@example.com', role: 1, authorId: 'HOGE1', autoRenew: 0, notification: 0, encryption: 0, encryptionPassword: 'string', prompt: 0, }, { name: 'name2', email: 'mail2@example.com', role: 2, autoRenew: 0, notification: 0, }, ]; await service.multipleImports(context, admin.external_id, filename, users); // メール送信メソッドが呼ばれているか確認 expect(spy).toHaveBeenCalledWith( context, ['admin@example.com'], account.company_name, dealer.company_name, date, filename, ); }); it('Blobアップロードに失敗した場合はエラーとなること', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account: dealer } = await makeTestAccount(source, { company_name: 'dealerCompany', tier: 4, }); const { account, admin } = await makeTestAccount(source, { tier: 5, company_name: 'company', parent_account_id: dealer.id, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, ]; }, }); overrideSendgridService(service, {}); overrideBlobstorageService(service, { uploadImportsBlob: async () => { throw new Error('error'); }, }); const now = new Date(); const date = `${now.getFullYear()}.${now.getMonth() + 1}.${now.getDate()}`; const filename = 'fileName.csv'; const users = [ { name: 'name1', email: 'mail1@example.com', role: 1, authorId: 'HOGE1', autoRenew: 0, notification: 0, encryption: 0, encryptionPassword: 'string', prompt: 0, }, { name: 'name2', email: 'mail2@example.com', role: 2, autoRenew: 0, notification: 0, }, ]; try { await service.multipleImports( context, admin.external_id, filename, users, ); fail(); } catch (e) { if (e instanceof HttpException) { expect(e.getStatus()).toEqual(HttpStatus.INTERNAL_SERVER_ERROR); expect(e.getResponse()).toEqual(makeErrorResponse('E009999')); } else { fail(); } } }); }); describe('UsersService.multipleImportsComplate', () => { let source: DataSource | null = null; beforeAll(async () => { if (source == null) { source = await (async () => { const s = new DataSource({ type: 'mysql', host: 'test_mysql_db', port: 3306, username: 'user', password: 'password', database: 'odms', entities: [__dirname + '/../../**/*.entity{.ts,.js}'], synchronize: false, // trueにすると自動的にmigrationが行われるため注意 logger: new TestLogger('none'), logging: true, }); return await s.initialize(); })(); } }); beforeEach(async () => { if (source) { await truncateAllTable(source); } }); afterAll(async () => { await source?.destroy(); source = null; }); it('ユーザー一括登録完了メールを送信できる(成功)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account: dealer } = await makeTestAccount(source, { company_name: 'dealerCompany', tier: 4, }); const { account, admin } = await makeTestAccount(source, { tier: 5, company_name: 'company', parent_account_id: dealer.id, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, ]; }, }); overrideSendgridService(service, {}); // メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。 const spy = jest .spyOn(service['sendgridService'], 'sendMailWithU121') .mockImplementation(); const requestTime = Math.floor(new Date(2024, 2, 3).getTime() / 1000); const filename = `U_20240303_000000_${admin.account_id}_${admin.id}.csv`; const errors: MultipleImportErrors[] = []; // ユーザー一括登録完了 await service.multipleImportsComplate( context, account.id, filename, requestTime, errors, ); // ADB2Cユーザー削除メソッドが呼ばれているか確認 expect(spy).toHaveBeenCalledWith( context, ['admin@example.com'], account.company_name, dealer.company_name, '2024.3.3', filename, ); }); it('ユーザー一括登録完了メールを送信できる(失敗)', async () => { if (!source) fail(); const module = await makeTestingModule(source); if (!module) fail(); const { account: dealer } = await makeTestAccount(source, { company_name: 'dealerCompany', tier: 4, }); const { account, admin } = await makeTestAccount(source, { tier: 5, company_name: 'company', parent_account_id: dealer.id, }); const service = module.get(UsersService); const context = makeContext(`uuidv4`, 'requestId'); overrideAdB2cService(service, { getUsers: async () => { return [ { id: admin.external_id, displayName: 'admin', identities: [ { signInType: ADB2C_SIGN_IN_TYPE.EMAILADDRESS, issuer: 'issuer', issuerAssignedId: 'admin@example.com', }, ], }, ]; }, }); overrideSendgridService(service, {}); // メール送信関数が呼ばれたかどうかで判定を行う。実際のメール送信は行わない。 const spy = jest .spyOn(service['sendgridService'], 'sendMailWithU122') .mockImplementation(); const requestTime = Math.floor(new Date(2024, 2, 3).getTime() / 1000); const filename = `U_20240303_000000_${admin.account_id}_${admin.id}`; const errors: MultipleImportErrors[] = [ { name: 'user1', line: 1, errorCode: 'E010301', }, { name: 'user2', line: 2, errorCode: 'E010302', }, { name: 'user2', line: 3, errorCode: 'E010302', }, { name: 'user3', line: 4, errorCode: 'E009999', }, ]; // ユーザー一括登録完了 await service.multipleImportsComplate( context, account.id, filename, requestTime, errors, ); // ADB2Cユーザー削除メソッドが呼ばれているか確認 expect(spy).toHaveBeenCalledWith( context, ['admin@example.com'], account.company_name, dealer.company_name, [1], [2, 3], [4], ); }); });