diff --git a/dictation_server/src/features/accounts/accounts.controller.ts b/dictation_server/src/features/accounts/accounts.controller.ts index a23e3af..abb8031 100644 --- a/dictation_server/src/features/accounts/accounts.controller.ts +++ b/dictation_server/src/features/accounts/accounts.controller.ts @@ -193,18 +193,13 @@ export class AccountsController { @Get('typists') async getTypists(@Req() req: Request): Promise { console.log(req.header('Authorization')); - return { - typists: [ - { - id: 1, - name: 'AAA', - }, - { - id: 2, - name: 'BBB', - }, - ], - }; + // アクセストークン取得 + const accessToken = retrieveAuthorizationToken(req); + const payload = jwt.decode(accessToken, { json: true }) as AccessToken; + + const typists = await this.accountService.getTypists(payload.userId); + + return { typists }; } @ApiResponse({ diff --git a/dictation_server/src/features/accounts/accounts.service.spec.ts b/dictation_server/src/features/accounts/accounts.service.spec.ts index f845411..d73dfb5 100644 --- a/dictation_server/src/features/accounts/accounts.service.spec.ts +++ b/dictation_server/src/features/accounts/accounts.service.spec.ts @@ -26,26 +26,90 @@ describe('AccountsService', () => { expectedAccountLisenceCounts, ); }); -}); -it('ライセンス情報が取得できない場合、エラーとなる', async () => { - const accountId = 1; - const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); - const adb2cParam = makeDefaultAdB2cMockValue(); - const accountsRepositoryMockValue = makeDefaultAccountsRepositoryMockValue(); - accountsRepositoryMockValue.getLicenseSummaryInfo = null; - const sendGridMockValue = makeDefaultSendGridlValue(); - const service = await makeAccountsServiceMock( - accountsRepositoryMockValue, - usersRepositoryMockValue, - adb2cParam, - sendGridMockValue, - ); - await expect(service.getLicenseSummary(accountId)).rejects.toEqual( - new HttpException( - makeErrorResponse('E009999'), - HttpStatus.INTERNAL_SERVER_ERROR, - ), - ); + + it('ライセンス情報が取得できない場合、エラーとなる', async () => { + const accountId = 1; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const adb2cParam = makeDefaultAdB2cMockValue(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + accountsRepositoryMockValue.getLicenseSummaryInfo = null; + const sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + await expect(service.getLicenseSummary(accountId)).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 sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + expect(await service.getTypists(externalId)).toEqual([ + { id: 1, name: 'Typist1' }, + { id: 2, name: 'Typist2' }, + { id: 3, name: 'Typist3' }, + ]); + }); + it('ユーザー取得に失敗した場合、エラーとなる', async () => { + const externalId = 'externalId'; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + usersRepositoryMockValue.findTypistUsers = new Error(); + const adb2cParam = makeDefaultAdB2cMockValue(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + const sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + await expect(service.getTypists(externalId)).rejects.toEqual( + new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ), + ); + }); + it('ADB2Cからのユーザーの取得に失敗した場合、エラーとなる', async () => { + const externalId = 'externalId'; + const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue(); + const adb2cParam = makeDefaultAdB2cMockValue(); + adb2cParam.getUsers = new Error(); + const accountsRepositoryMockValue = + makeDefaultAccountsRepositoryMockValue(); + const sendGridMockValue = makeDefaultSendGridlValue(); + const service = await makeAccountsServiceMock( + accountsRepositoryMockValue, + usersRepositoryMockValue, + adb2cParam, + sendGridMockValue, + ); + await expect(service.getTypists(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 9ee99d5..24a715e 100644 --- a/dictation_server/src/features/accounts/accounts.service.ts +++ b/dictation_server/src/features/accounts/accounts.service.ts @@ -15,7 +15,7 @@ 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 { GetLicenseSummaryResponse } from './types/types'; +import { GetLicenseSummaryResponse, Typist } from './types/types'; import { AccessToken } from '../../common/token'; @Injectable() @@ -227,4 +227,42 @@ export class AccountsService { this.logger.log(`[OUT] ${this.getMyAccountInfo.name}`); return userInfo.account_id; } + + /** + * Gets typists + * @param externalId + * @returns typists + */ + async getTypists(externalId: string): Promise { + this.logger.log(`[IN] ${this.getTypists.name}`); + + // Typist取得 + try { + const typistUsers = await this.usersRepository.findTypistUsers( + externalId, + ); + const externalIds = typistUsers.map((x) => x.external_id); + + // B2Cからユーザー名を取得する + const adb2cUsers = await this.adB2cService.getUsers(externalIds); + + const typists = typistUsers.map((x) => { + const user = adb2cUsers.find((adb2c) => adb2c.id === x.external_id); + return { + id: x.id, + name: user.displayName, + }; + }); + + return typists; + } catch (e) { + this.logger.error(e); + throw new HttpException( + makeErrorResponse('E009999'), + HttpStatus.INTERNAL_SERVER_ERROR, + ); + } finally { + this.logger.log(`[OUT] ${this.getTypists.name}`); + } + } } 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 36bc170..09d411c 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,15 @@ import { } from '../../../gateways/adb2c/adb2c.service'; import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service'; import { LicenseSummaryInfo } from '../types/types'; +import { AdB2cUser } from '../../../gateways/adb2c/types/types'; export type UsersRepositoryMockValue = { findUserById: User | Error; findUserByExternalId: User | Error; + findTypistUsers: User[] | Error; }; export type AdB2cMockValue = { createUser: string | ConflictError | Error; + getUsers: AdB2cUser[] | Error; }; export type SendGridMockValue = { createMailContentFromEmailConfirm: { @@ -83,17 +86,21 @@ export const makeAccountsRepositoryMock = ( }; }; export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => { - const { findUserById } = value; + const { findUserById, findTypistUsers } = value; return { findUserById: findUserById instanceof Error ? jest.fn, []>().mockRejectedValue(findUserById) : jest.fn, []>().mockResolvedValue(findUserById), + findTypistUsers: + findTypistUsers instanceof Error + ? jest.fn, []>().mockRejectedValue(findTypistUsers) + : jest.fn, []>().mockResolvedValue(findTypistUsers), }; }; export const makeAdB2cServiceMock = (value: AdB2cMockValue) => { - const { createUser } = value; + const { createUser, getUsers } = value; return { createUser: @@ -102,6 +109,10 @@ export const makeAdB2cServiceMock = (value: AdB2cMockValue) => { : jest .fn, []>() .mockResolvedValue(createUser), + getUsers: + getUsers instanceof Error + ? jest.fn, []>().mockRejectedValue(getUsers) + : jest.fn, []>().mockResolvedValue(getUsers), }; }; export const makeSendGridServiceMock = (value: SendGridMockValue) => { @@ -161,14 +172,51 @@ export const makeDefaultUsersRepositoryMockValue = user.updated_by = null; user.updated_at = null; + const typists: User[] = []; + typists.push( + { + ...user, + id: 1, + external_id: 'typist1', + role: 'typist', + }, + { + ...user, + id: 2, + external_id: 'typist2', + role: 'typist', + }, + { + ...user, + id: 3, + external_id: 'typist3', + role: 'typist', + }, + ); + return { findUserById: user, findUserByExternalId: user, + findTypistUsers: typists, }; }; export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => { return { createUser: '001', + getUsers: [ + { + id: 'typist1', + displayName: 'Typist1', + }, + { + id: 'typist2', + displayName: 'Typist2', + }, + { + id: 'typist3', + displayName: 'Typist3', + }, + ], }; }; export const makeDefaultSendGridlValue = (): SendGridMockValue => { diff --git a/dictation_server/src/repositories/users/users.repository.service.ts b/dictation_server/src/repositories/users/users.repository.service.ts index 1ede522..333ca65 100644 --- a/dictation_server/src/repositories/users/users.repository.service.ts +++ b/dictation_server/src/repositories/users/users.repository.service.ts @@ -1,11 +1,12 @@ import { Injectable } from '@nestjs/common'; -import { DataSource, UpdateResult } from 'typeorm'; +import { DataSource, IsNull, UpdateResult } from 'typeorm'; import { User } from './entity/user.entity'; import { SortCriteria } from '../sort_criteria/entity/sort_criteria.entity'; import { getDirection, getTaskListSortableAttribute, } from '../../common/types/sort/util'; +import { USER_ROLES } from '../../constants'; // UsersRepositoryServiceで発生するエラーを定義 export class EmailAlreadyVerifiedError extends Error {} @@ -222,4 +223,31 @@ export class UsersRepositoryService { return dbUsers; } + + /** + * アカウント内のタイピストユーザーを取得する + * @param sub + * @returns typist users + */ + async findTypistUsers(sub: string): Promise { + return await this.dataSource.transaction(async (entityManager) => { + const repo = entityManager.getRepository(User); + + const user = await repo.findOne({ + where: { + external_id: sub, + }, + }); + + const typists = await repo.find({ + where: { + account_id: user.account_id, + role: USER_ROLES.TYPIST, + deleted_at: IsNull(), + }, + }); + + return typists; + }); + } }