Merged PR 167: タイピストユーザー取得API実装

## 概要
[Task1931: タイピストユーザー取得API実装](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1931)

- アカウント内のタイピストユーザーを取得する処理を実装しました。

## レビューポイント
- ADB2Cからのユーザー取得、マージは適切か

## UIの変更
なし

## 動作確認状況
- ローカルで確認
This commit is contained in:
makabe.t 2023-06-20 06:16:19 +00:00
parent 8c75f7a1b1
commit ef17e4ff0b
5 changed files with 209 additions and 36 deletions

View File

@ -193,18 +193,13 @@ export class AccountsController {
@Get('typists')
async getTypists(@Req() req: Request): Promise<GetTypistsResponse> {
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({

View File

@ -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 = {

View File

@ -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<Typist[]> {
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}`);
}
}
}

View File

@ -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<Promise<void>, []>().mockRejectedValue(findUserById)
: jest.fn<Promise<User>, []>().mockResolvedValue(findUserById),
findTypistUsers:
findTypistUsers instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(findTypistUsers)
: jest.fn<Promise<User[]>, []>().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<Promise<string | ConflictError>, []>()
.mockResolvedValue(createUser),
getUsers:
getUsers instanceof Error
? jest.fn<Promise<void>, []>().mockRejectedValue(getUsers)
: jest.fn<Promise<AdB2cUser[]>, []>().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 => {

View File

@ -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<User[]> {
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;
});
}
}