diff --git a/dictation_server/src/features/accounts/accounts.controller.ts b/dictation_server/src/features/accounts/accounts.controller.ts index abb8031..9a1ce1d 100644 --- a/dictation_server/src/features/accounts/accounts.controller.ts +++ b/dictation_server/src/features/accounts/accounts.controller.ts @@ -227,17 +227,14 @@ export class AccountsController { @Get('typist-groups') async getTypistGroups(@Req() req: Request): Promise { console.log(req.header('Authorization')); - return { - typistGroups: [ - { - id: 1, - name: 'GroupA', - }, - { - id: 2, - name: 'GroupB', - }, - ], - }; + // アクセストークン取得 + const accessToken = retrieveAuthorizationToken(req); + const payload = jwt.decode(accessToken, { json: true }) as AccessToken; + + const typistGroups = await this.accountService.getTypistGroups( + payload.userId, + ); + + return { typistGroups }; } } diff --git a/dictation_server/src/features/accounts/accounts.module.ts b/dictation_server/src/features/accounts/accounts.module.ts index 69508d6..046e462 100644 --- a/dictation_server/src/features/accounts/accounts.module.ts +++ b/dictation_server/src/features/accounts/accounts.module.ts @@ -5,11 +5,13 @@ import { AccountsRepositoryModule } from '../../repositories/accounts/accounts.r import { AccountsController } from './accounts.controller'; import { AccountsService } from './accounts.service'; import { AdB2cModule } from '../../gateways/adb2c/adb2c.module'; +import { UserGroupsRepositoryModule } from '../../repositories/user_groups/user_groups.repository.module'; @Module({ imports: [ AccountsRepositoryModule, UsersRepositoryModule, + UserGroupsRepositoryModule, SendGridModule, AdB2cModule, ], diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index d73dfb5..636e023 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -5,6 +5,7 @@ import { makeDefaultAccountsRepositoryMockValue, makeDefaultAdB2cMockValue, makeDefaultSendGridlValue, + makeDefaultUserGroupsRepositoryMockValue, makeDefaultUsersRepositoryMockValue, } from './test/accounts.service.mock'; @@ -12,6 +13,8 @@ describe('AccountsService', () => { it('アカウントに紐づくライセンス情報を取得する', async () => { const accountId = 1; const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); const adb2cParam = makeDefaultAdB2cMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); @@ -19,6 +22,7 @@ describe('AccountsService', () => { const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, + userGroupsRepositoryMockValue, adb2cParam, sendGridMockValue, ); @@ -30,6 +34,8 @@ describe('AccountsService', () => { it('ライセンス情報が取得できない場合、エラーとなる', async () => { const accountId = 1; const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); const adb2cParam = makeDefaultAdB2cMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); @@ -38,6 +44,7 @@ describe('AccountsService', () => { const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, + userGroupsRepositoryMockValue, adb2cParam, sendGridMockValue, ); @@ -52,6 +59,8 @@ describe('AccountsService', () => { it('アカウントに紐づくタイピストユーザーを取得できる', async () => { const externalId = 'externalId'; const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); const adb2cParam = makeDefaultAdB2cMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); @@ -59,6 +68,7 @@ describe('AccountsService', () => { const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, + userGroupsRepositoryMockValue, adb2cParam, sendGridMockValue, ); @@ -72,6 +82,8 @@ describe('AccountsService', () => { const externalId = 'externalId'; const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); usersRepositoryMockValue.findTypistUsers = new Error(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); const adb2cParam = makeDefaultAdB2cMockValue(); const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); @@ -79,6 +91,7 @@ describe('AccountsService', () => { const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, + userGroupsRepositoryMockValue, adb2cParam, sendGridMockValue, ); @@ -92,6 +105,8 @@ describe('AccountsService', () => { it('ADB2Cからのユーザーの取得に失敗した場合、エラーとなる', async () => { const externalId = 'externalId'; const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); const adb2cParam = makeDefaultAdB2cMockValue(); adb2cParam.getUsers = new Error(); const accountsRepositoryMockValue = @@ -100,6 +115,7 @@ describe('AccountsService', () => { const service = await makeAccountsServiceMock( accountsRepositoryMockValue, usersRepositoryMockValue, + userGroupsRepositoryMockValue, adb2cParam, sendGridMockValue, ); @@ -110,6 +126,79 @@ describe('AccountsService', () => { ), ); }); + + it('アカウントに紐づくユーザーグループを取得できる', async () => { + const externalId = 'externalId'; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const adb2cParam = makeDefaultAdB2cMockValue(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); + const sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + userGroupsRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + + expect(await service.getTypistGroups(externalId)).toEqual([ + { id: 1, name: 'GroupA' }, + { id: 2, name: 'GroupB' }, + ]); + }); + it('ユーザーの取得に失敗した場合、エラーとなること', async () => { + const externalId = 'externalId'; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + usersRepositoryMockValue.findUserByExternalId = new Error('DB failed'); + const adb2cParam = makeDefaultAdB2cMockValue(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); + const sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + userGroupsRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + + await expect(service.getTypistGroups(externalId)).rejects.toEqual( + new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ), + ); + }); + it('ユーザーグループの取得に失敗した場合、エラーとなること', async () => { + const externalId = 'externalId'; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const adb2cParam = makeDefaultAdB2cMockValue(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + const userGroupsRepositoryMockValue = + makeDefaultUserGroupsRepositoryMockValue(); + userGroupsRepositoryMockValue.getUserGroups = new Error('DB failed'); + const sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + userGroupsRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + + await expect(service.getTypistGroups(externalId)).rejects.toEqual( + new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ), + ); + }); }); const expectedAccountLisenceCounts = { diff --git a/dictation_server/src/features/accounts/accounts.service.ts b/dictation_server/src/features/accounts/accounts.service.ts index 24a715e..f5c1ab0 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -15,14 +15,17 @@ import { Account } from '../../repositories/accounts/entity/account.entity'; import { User } from '../../repositories/users/entity/user.entity'; import { LICENSE_EXPIRATION_THRESHOLD_DAYS, TIER_5 } from '../../constants'; import { makeErrorResponse } from '../../common/error/makeErrorResponse'; +import { TypistGroup } from './types/types'; import { GetLicenseSummaryResponse, Typist } from './types/types'; import { AccessToken } from '../../common/token'; +import { UserGroupsRepositoryService } from '../../repositories/user_groups/user_groups.repository.service'; @Injectable() export class AccountsService { constructor( private readonly accountRepository: AccountsRepositoryService, private readonly usersRepository: UsersRepositoryService, + private readonly userGroupsRepository: UserGroupsRepositoryService, private readonly adB2cService: AdB2cService, private readonly sendgridService: SendGridService, private readonly configService: ConfigService, @@ -228,6 +231,28 @@ export class AccountsService { return userInfo.account_id; } + async getTypistGroups(externalId: string): Promise { + this.logger.log(`[IN] ${this.getTypistGroups.name}`); + + // TypistGroup取得 + try { + const user = await this.usersRepository.findUserByExternalId(externalId); + const userGroups = await this.userGroupsRepository.getUserGroups( + user.account_id, + ); + + return userGroups.map((x) => ({ id: x.id, name: x.name })); + } catch (e) { + this.logger.error(e); + throw new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } finally { + this.logger.log(`[OUT] ${this.getTypistGroups.name}`); + } + } + /** * Gets typists * @param externalId diff --git a/dictation_server/src/features/accounts/test/accounts.service.mock.ts b/dictation_server/src/features/accounts/test/accounts.service.mock.ts index 09d411c..42d4565 100644 --- a/dictation_server/src/features/accounts/test/accounts.service.mock.ts +++ b/dictation_server/src/features/accounts/test/accounts.service.mock.ts @@ -10,12 +10,17 @@ import { } from '../../../gateways/adb2c/adb2c.service'; import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service'; import { LicenseSummaryInfo } from '../types/types'; +import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity'; +import { UserGroupsRepositoryService } from '../../../repositories/user_groups/user_groups.repository.service'; import { AdB2cUser } from '../../../gateways/adb2c/types/types'; export type UsersRepositoryMockValue = { findUserById: User | Error; findUserByExternalId: User | Error; findTypistUsers: User[] | Error; }; +export type UserGroupsRepositoryMockValue = { + getUserGroups: UserGroup[] | Error; +}; export type AdB2cMockValue = { createUser: string | ConflictError | Error; getUsers: AdB2cUser[] | Error; @@ -37,6 +42,7 @@ export type AccountsRepositoryMockValue = { export const makeAccountsServiceMock = async ( accountsRepositoryMockValue: AccountsRepositoryMockValue, usersRepositoryMockValue: UsersRepositoryMockValue, + userGroupsRepositoryMockValue: UserGroupsRepositoryMockValue, adB2cMockValue: AdB2cMockValue, sendGridMockValue: SendGridMockValue, ): Promise => { @@ -55,6 +61,8 @@ export const makeAccountsServiceMock = async ( return makeAccountsRepositoryMock(accountsRepositoryMockValue); case UsersRepositoryService: return makeUsersRepositoryMock(usersRepositoryMockValue); + case UserGroupsRepositoryService: + return makeUserGroupsRepositoryMock(userGroupsRepositoryMockValue); case AdB2cService: return makeAdB2cServiceMock(adB2cMockValue); case SendGridService: @@ -86,19 +94,35 @@ export const makeAccountsRepositoryMock = ( }; }; export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => { - const { findUserById, findTypistUsers } = value; + const { findUserById, findUserByExternalId, findTypistUsers } = value; return { findUserById: findUserById instanceof Error ? jest.fn, []>().mockRejectedValue(findUserById) : jest.fn, []>().mockResolvedValue(findUserById), + findUserByExternalId: + findUserByExternalId instanceof Error + ? jest.fn, []>().mockRejectedValue(findUserByExternalId) + : jest.fn, []>().mockResolvedValue(findUserByExternalId), findTypistUsers: findTypistUsers instanceof Error ? jest.fn, []>().mockRejectedValue(findTypistUsers) : jest.fn, []>().mockResolvedValue(findTypistUsers), }; }; +export const makeUserGroupsRepositoryMock = ( + value: UserGroupsRepositoryMockValue, +) => { + const { getUserGroups } = value; + + return { + getUserGroups: + getUserGroups instanceof Error + ? jest.fn, []>().mockRejectedValue(getUserGroups) + : jest.fn, []>().mockResolvedValue(getUserGroups), + }; +}; export const makeAdB2cServiceMock = (value: AdB2cMockValue) => { const { createUser, getUsers } = value; @@ -200,6 +224,45 @@ export const makeDefaultUsersRepositoryMockValue = findTypistUsers: typists, }; }; + +export const makeDefaultUserGroupsRepositoryMockValue = + (): UserGroupsRepositoryMockValue => { + const user = new User(); + user.id = 1; + user.external_id = 'ede66c43-9b9d-4222-93ed-5f11c96e08e2'; + user.account_id = 1234567890123456; + user.role = 'none admin'; + user.author_id = '6cce347f-0cf1-a15e-19ab-d00988b643f9'; + user.accepted_terms_version = '1.0'; + user.email_verified = true; + user.auto_renew = false; + user.license_alert = false; + user.notification = false; + user.deleted_at = null; + user.created_by = 'test'; + user.created_at = new Date(); + user.updated_by = null; + user.updated_at = null; + + return { + getUserGroups: [ + { + id: 1, + account_id: 1, + name: 'GroupA', + created_by: 'test', + updated_by: 'test', + }, + { + id: 2, + account_id: 1, + name: 'GroupB', + created_by: 'test', + updated_by: 'test', + }, + ], + }; + }; export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => { return { createUser: '001', diff --git a/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts b/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts index 5248f1c..491bfba 100644 --- a/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts +++ b/dictation_server/src/repositories/user_groups/user_groups.repository.service.ts @@ -1,7 +1,22 @@ import { Injectable } from '@nestjs/common'; -import { DataSource } from 'typeorm'; +import { DataSource, IsNull } from 'typeorm'; +import { UserGroup } from './entity/user_group.entity'; @Injectable() export class UserGroupsRepositoryService { constructor(private dataSource: DataSource) {} + + async getUserGroups(account_id: number): Promise { + const value = await this.dataSource.transaction(async (entityManager) => { + const userGroupRepo = entityManager.getRepository(UserGroup); + + const userGroups = await userGroupRepo.find({ + // 論理削除されていないレコードを取得 + where: { account_id: account_id, deleted_at: IsNull() }, + }); + + return userGroups; + }); + return value; + } }