Merged PR 75: API実装(ユーザー一覧取得)
## 概要 [Task1592: API実装(ユーザー一覧取得)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1592) - ユーザ一覧取得のAPIを実装 - アクセストークンにより権限を確認する - src/common/jwt/jwt.ts verifyAuthority([Task1593: API実装(ユーザー登録)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1593)で作成)を呼び出すため追って再修正します。(レビュー対象外です) - src/features/users/users.controller.ts getUsersから src/features/users/users.service.ts getUsersへ - DBから同一アカウントのユーザ一覧を取得する - findSameAccountUsersを新規作成 - Azure AD B2Cからユーザーを取得してマージ - src/gateways/adb2c/adb2c.service.ts getUserを新規作成 - マージはfor文でまわしています(力技) - マージした結果を返却 - 影響範囲 - usersテーブルの変更が入るときにマージ部分の手直しが要ります。(TODOを添えています) ## レビューポイント - 新規に作成したfindSameAccountUsersの妥当性 - 新規に作成したgetUserの妥当性 →Azureからの返り値はsrc/common/token/types.tsに定義済。 (Azure AD B2Cから取得できた項目で再定義) ## UIの変更 - 特になし ## 動作確認状況 - ローカルでビルド、テストを実行した後に動作を確認済。 ## 補足 - ご不便をおかけしました。よろしくお願いします。
This commit is contained in:
parent
21695a6590
commit
3f7a9ed11a
@ -4,8 +4,16 @@ import type {
|
||||
IDToken,
|
||||
JwkSignKey,
|
||||
RefreshToken,
|
||||
Aadb2cUser,
|
||||
} from './types';
|
||||
import { isIDToken } from './typeguard';
|
||||
|
||||
export type { AccessToken, B2cMetadata, IDToken, JwkSignKey, RefreshToken };
|
||||
export type {
|
||||
AccessToken,
|
||||
B2cMetadata,
|
||||
IDToken,
|
||||
JwkSignKey,
|
||||
RefreshToken,
|
||||
Aadb2cUser,
|
||||
};
|
||||
export { isIDToken };
|
||||
|
||||
@ -28,3 +28,8 @@ export type JwkSignKey = {
|
||||
e: string;
|
||||
n: string;
|
||||
};
|
||||
|
||||
export type Aadb2cUser = {
|
||||
displayName: string;
|
||||
mail: string;
|
||||
};
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersService } from '../users.service';
|
||||
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
|
||||
import { CryptoService } from '../../../gateways/crypto/crypto.service';
|
||||
import { Aadb2cUser, B2cMetadata, JwkSignKey } from '../../../common/token';
|
||||
import {
|
||||
AdB2cService,
|
||||
ConflictError,
|
||||
} from '../../../gateways/adb2c/adb2c.service';
|
||||
import { CryptoService } from '../../../gateways/crypto/crypto.service';
|
||||
import { SendGridService } from '../../../gateways/sendgrid/sendgrid.service';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { User } from '../../../repositories/users/entity/user.entity';
|
||||
import { JwkSignKey, B2cMetadata } from '../../../common/token';
|
||||
import { UsersRepositoryService } from '../../../repositories/users/users.repository.service';
|
||||
import { UsersService } from '../users.service';
|
||||
|
||||
export type CryptoMockValue = {
|
||||
getPublicKey: string | Error;
|
||||
@ -19,6 +19,7 @@ export type UsersRepositoryMockValue = {
|
||||
updateUserVerified: undefined | Error;
|
||||
findUserById: User | Error;
|
||||
createNormalUser: User | Error;
|
||||
findSameAccountUsers: User[] | Error;
|
||||
};
|
||||
|
||||
export type AdB2cMockValue = {
|
||||
@ -26,6 +27,7 @@ export type AdB2cMockValue = {
|
||||
getSignKeySets: JwkSignKey[] | Error;
|
||||
changePassword: { sub: string } | Error;
|
||||
createUser: string | ConflictError | Error;
|
||||
getUser: Aadb2cUser | Error;
|
||||
};
|
||||
|
||||
export type SendGridMockValue = {
|
||||
@ -59,6 +61,10 @@ export const makeDefaultAdB2cMockValue = (): AdB2cMockValue => {
|
||||
sub: 'TEST9999',
|
||||
},
|
||||
createUser: '001',
|
||||
getUser: {
|
||||
displayName: 'Hanako Sato',
|
||||
mail: 'hanako@sample.com',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -81,7 +87,8 @@ export const makeSendGridServiceMock = (value: SendGridMockValue) => {
|
||||
};
|
||||
|
||||
export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
|
||||
const { getMetaData, getSignKeySets, changePassword, createUser } = value;
|
||||
const { getMetaData, getSignKeySets, changePassword, createUser, getUser } =
|
||||
value;
|
||||
|
||||
return {
|
||||
getMetaData:
|
||||
@ -106,6 +113,14 @@ export const makeAdB2cServiceMock = (value: AdB2cMockValue) => {
|
||||
: jest
|
||||
.fn<Promise<string | ConflictError>, []>()
|
||||
.mockResolvedValue(createUser),
|
||||
getUser:
|
||||
getUser instanceof Error
|
||||
? jest
|
||||
.fn<Promise<Aadb2cUser | undefined>, []>()
|
||||
.mockRejectedValue(getUser)
|
||||
: jest
|
||||
.fn<Promise<Aadb2cUser | undefined>, []>()
|
||||
.mockResolvedValue(getUser),
|
||||
};
|
||||
};
|
||||
|
||||
@ -166,7 +181,12 @@ class authorIdError extends Error {
|
||||
}
|
||||
|
||||
export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
|
||||
const { updateUserVerified, findUserById, createNormalUser } = value;
|
||||
const {
|
||||
updateUserVerified,
|
||||
findUserById,
|
||||
createNormalUser,
|
||||
findSameAccountUsers,
|
||||
} = value;
|
||||
|
||||
const aIdError = new authorIdError('ER_DUP_ENTRY');
|
||||
|
||||
@ -185,6 +205,14 @@ export const makeUsersRepositoryMock = (value: UsersRepositoryMockValue) => {
|
||||
? jest.fn<Promise<void>, []>().mockRejectedValue(aIdError)
|
||||
: jest.fn<Promise<void>, []>().mockRejectedValue(createNormalUser)
|
||||
: jest.fn<Promise<User>, []>().mockResolvedValue(createNormalUser),
|
||||
findSameAccountUsers:
|
||||
findSameAccountUsers instanceof Error
|
||||
? jest
|
||||
.fn<Promise<User[] | undefined>, []>()
|
||||
.mockRejectedValue(findSameAccountUsers)
|
||||
: jest
|
||||
.fn<Promise<User[] | undefined>, []>()
|
||||
.mockResolvedValue(findSameAccountUsers),
|
||||
};
|
||||
};
|
||||
|
||||
@ -206,6 +234,7 @@ export const makeSendGridMock = (value: SendGridMockValue) => {
|
||||
.mockResolvedValue(createMailContentFromEmailConfirmForNormalUser),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeConfigMock = (value: ConfigMockValue) => {
|
||||
const { get } = value;
|
||||
|
||||
@ -216,6 +245,7 @@ export const makeConfigMock = (value: ConfigMockValue) => {
|
||||
: jest.fn<Promise<string>, []>().mockResolvedValue(get),
|
||||
};
|
||||
};
|
||||
|
||||
export const makeDefaultCryptoMockValue = (): CryptoMockValue => {
|
||||
return {
|
||||
getPublicKey: [
|
||||
@ -243,6 +273,7 @@ export const makeDefaultSendGridlValue = (): SendGridMockValue => {
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const makeDefaultConfigValue = (): ConfigMockValue => {
|
||||
return {
|
||||
get: `test@example.co.jp`,
|
||||
@ -254,9 +285,45 @@ export const makeDefaultUsersRepositoryMockValue =
|
||||
(): UsersRepositoryMockValue => {
|
||||
const newUser = new User();
|
||||
newUser.id = 111;
|
||||
|
||||
const user1 = new User();
|
||||
user1.id = 2;
|
||||
user1.external_id = 'ede66c43-9b9d-4222-93ed-5f11c96e08e2';
|
||||
user1.account_id = 1234567890123456;
|
||||
user1.role = 'none';
|
||||
user1.author_id = '6cce347f-0cf1-a15e-19ab-d00988b643f9';
|
||||
user1.accepted_terms_version = '1.0';
|
||||
user1.email_verified = true;
|
||||
user1.auto_renew = false;
|
||||
user1.license_alert = false;
|
||||
user1.notification = false;
|
||||
user1.deleted_at = null;
|
||||
user1.created_by = 'test';
|
||||
user1.created_at = new Date();
|
||||
user1.updated_by = null;
|
||||
user1.updated_at = null;
|
||||
|
||||
const user2 = new User();
|
||||
user2.id = 3;
|
||||
user2.external_id = '698176dc-4028-4638-a452-f00bf62a7781';
|
||||
user2.account_id = 1234567890123456;
|
||||
user2.role = 'none';
|
||||
user2.author_id = '551c4077-5b55-a38c-2c55-cd1edd537aa8';
|
||||
user2.accepted_terms_version = '1.0';
|
||||
user2.email_verified = true;
|
||||
user2.auto_renew = false;
|
||||
user2.license_alert = false;
|
||||
user2.notification = false;
|
||||
user2.deleted_at = null;
|
||||
user2.created_by = 'test';
|
||||
user2.created_at = new Date();
|
||||
user2.updated_by = null;
|
||||
user2.updated_at = null;
|
||||
|
||||
return {
|
||||
updateUserVerified: undefined,
|
||||
findUserById: newUser,
|
||||
createNormalUser: newUser,
|
||||
findSameAccountUsers: [user1, user2],
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
|
||||
describe('UsersController', () => {
|
||||
let controller: UsersController;
|
||||
const mockUserService = {};
|
||||
const mockCryptoService = {};
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
providers: [UsersService, CryptoService],
|
||||
})
|
||||
.overrideProvider(UsersService)
|
||||
.useValue(mockUserService)
|
||||
.overrideProvider(CryptoService)
|
||||
.useValue(mockCryptoService)
|
||||
.compile();
|
||||
|
||||
controller = module.get<UsersController>(UsersController);
|
||||
|
||||
@ -2,10 +2,10 @@ import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Post,
|
||||
Req,
|
||||
HttpException,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
ApiBearerAuth,
|
||||
@ -13,7 +13,14 @@ import {
|
||||
ApiResponse,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { Request } from 'express';
|
||||
import { confirmPermission } from '../../common/auth/auth';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { ErrorResponse } from '../../common/error/types/types';
|
||||
import { retrieveAccessToken } from '../../common/http/helper';
|
||||
import { isVerifyError, verify } from '../../common/jwt/jwt';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import {
|
||||
ConfirmRequest,
|
||||
ConfirmResponse,
|
||||
@ -23,13 +30,6 @@ import {
|
||||
SignupResponse,
|
||||
} from './types/types';
|
||||
import { UsersService } from './users.service';
|
||||
import { Request } from 'express';
|
||||
import { verify, isVerifyError } from '../../common/jwt/jwt';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { retrieveAccessToken } from '../../common/http/helper';
|
||||
import { confirmPermission } from '../../common/auth/auth';
|
||||
|
||||
@ApiTags('users')
|
||||
@Controller('users')
|
||||
@ -106,7 +106,38 @@ export class UsersController {
|
||||
@Get()
|
||||
async getUsers(@Req() req: Request): Promise<GetUsersResponse> {
|
||||
console.log(req.header('Authorization'));
|
||||
return { users: [] };
|
||||
|
||||
// アクセストークンにより権限を確認する
|
||||
const pubKey = await this.cryptoService.getPublicKey();
|
||||
const accessToken = retrieveAccessToken(req);
|
||||
|
||||
// アクセストークンが存在しない場合のエラー
|
||||
if (accessToken == undefined) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000107'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
const payload = verify<AccessToken>(accessToken, pubKey);
|
||||
|
||||
// アクセストークン形式エラー
|
||||
if (isVerifyError(payload)) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000101'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
// アクセストークンの権限不足エラー
|
||||
if (!confirmPermission(payload.scope)) {
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E000108'),
|
||||
HttpStatus.UNAUTHORIZED,
|
||||
);
|
||||
}
|
||||
|
||||
const users = await this.usersService.getUsers(accessToken);
|
||||
return { users };
|
||||
}
|
||||
|
||||
@ApiResponse({
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { AdB2cModule } from '../../gateways/adb2c/adb2c.module';
|
||||
import { CryptoModule } from '../../gateways/crypto/crypto.module';
|
||||
import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module';
|
||||
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
|
||||
import { UsersController } from './users.controller';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersRepositoryModule } from '../../repositories/users/users.repository.module';
|
||||
import { AdB2cModule } from '../../gateways/adb2c/adb2c.module';
|
||||
import { SendGridModule } from '../../gateways/sendgrid/sendgrid.module';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
import { HttpException, HttpStatus } from '@nestjs/common';
|
||||
import { AccessToken } from 'src/common/token';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { User as EntityUser } from '../../repositories/users/entity/user.entity';
|
||||
import { EmailAlreadyVerifiedError } from '../../repositories/users/users.repository.service';
|
||||
import {
|
||||
makeDefaultAdB2cMockValue,
|
||||
makeDefaultConfigValue,
|
||||
makeDefaultCryptoMockValue,
|
||||
makeDefaultSendGridlValue,
|
||||
makeDefaultUsersRepositoryMockValue,
|
||||
makeUsersServiceMock,
|
||||
makeDefaultAdB2cMockValue,
|
||||
makeDefaultSendGridlValue,
|
||||
makeDefaultConfigValue,
|
||||
} from './test/users.service.mock';
|
||||
import { EmailAlreadyVerifiedError } from '../../repositories/users/users.repository.service';
|
||||
import { AccessToken } from 'src/common/token';
|
||||
import { User } from './types/types';
|
||||
|
||||
describe('UsersService', () => {
|
||||
it('ユーザの仮登録時に払い出されるトークンにより、未認証のユーザが認証済みになる', async () => {
|
||||
@ -497,3 +499,99 @@ it('AuthorIDが重複している場合、エラーとなる。', async () => {
|
||||
new HttpException(makeErrorResponse('E010302'), HttpStatus.BAD_REQUEST),
|
||||
);
|
||||
});
|
||||
|
||||
it('ユーザの一覧を取得する', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
);
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
|
||||
expect(await service.getUsers(token)).toEqual(expectedUsers);
|
||||
});
|
||||
|
||||
const expectedUsers = [
|
||||
{
|
||||
name: 'Hanako Sato',
|
||||
role: 'none',
|
||||
authorId: '6cce347f-0cf1-a15e-19ab-d00988b643f9',
|
||||
typistGroupName: '',
|
||||
email: 'hanako@sample.com',
|
||||
emailVerified: true,
|
||||
autoRenew: false,
|
||||
licenseAlert: false,
|
||||
notification: false,
|
||||
},
|
||||
{
|
||||
name: 'Hanako Sato',
|
||||
role: 'none',
|
||||
authorId: '551c4077-5b55-a38c-2c55-cd1edd537aa8',
|
||||
typistGroupName: '',
|
||||
email: 'hanako@sample.com',
|
||||
emailVerified: true,
|
||||
autoRenew: false,
|
||||
licenseAlert: false,
|
||||
notification: false,
|
||||
},
|
||||
];
|
||||
|
||||
it('ユーザの一覧を取得に失敗する', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
usersRepositoryMockValue.findSameAccountUsers = new Error(
|
||||
'Failure to acquire',
|
||||
);
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
);
|
||||
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
|
||||
await expect(service.getUsers(token)).rejects.toEqual(
|
||||
new HttpException(makeErrorResponse('E009999'), HttpStatus.NOT_FOUND),
|
||||
);
|
||||
});
|
||||
|
||||
it('ユーザの一覧を0件取得する', async () => {
|
||||
const cryptoMockValue = makeDefaultCryptoMockValue();
|
||||
const usersRepositoryMockValue = makeDefaultUsersRepositoryMockValue();
|
||||
const adb2cParam = makeDefaultAdB2cMockValue();
|
||||
const sendgridMockValue = makeDefaultSendGridlValue();
|
||||
const configMockValue = makeDefaultConfigValue();
|
||||
|
||||
// モックでDBからのユーザ取得を空にする
|
||||
const noDbUsers: EntityUser[] = [];
|
||||
usersRepositoryMockValue.findSameAccountUsers = noDbUsers;
|
||||
|
||||
const service = await makeUsersServiceMock(
|
||||
cryptoMockValue,
|
||||
usersRepositoryMockValue,
|
||||
adb2cParam,
|
||||
sendgridMockValue,
|
||||
configMockValue,
|
||||
);
|
||||
|
||||
const token =
|
||||
'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2NvdW50SWQiOjEsInVzZXJJZCI6MiwiZW1haWwiOiJ4eHhAeHh4Lnh4eCIsImlhdCI6MTAwMDAwMDAwMCwiZXhwIjo5MDAwMDAwMDAwfQ.26L6BdNg-3TbyKT62PswlJ6RPMkcTtHzlDXW2Uo9XbMPVSrl2ObcuS6EcXjFFN2DEfNTKbqX_zevIWMpHOAdLNgGhk528nLrBrNvPASqtTjvW9muxMXpjUdjRVkmVbOylBHWW3YpWL9JEbJQ7rAzWDfaIdPhMovdaxumnZt_UwnlnrdaVPLACW7tkH_laEcAU507iSiM4mqxxG8FuTs34t6PEdwRuzZAQPN2IOPYNSvGNdJYryPacSeSNZ_z1xeBYXLOLQfOBZzyTReYDOhXdikhrNUbxjgnZQlSXBCVMlZ9PH42bHfp-LJIeJzW0yqnF6oLklvJP-fo8eW0k5iDOw';
|
||||
|
||||
const emptyMergedUsers: User[] = [];
|
||||
expect(await service.getUsers(token)).toEqual(emptyMergedUsers);
|
||||
});
|
||||
|
||||
@ -1,21 +1,22 @@
|
||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||
import { isVerifyError, verify } from '../../common/jwt';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import {
|
||||
UsersRepositoryService,
|
||||
EmailAlreadyVerifiedError,
|
||||
} from '../../repositories/users/users.repository.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||
import { isVerifyError, verify } from '../../common/jwt';
|
||||
import { makePassword } from '../../common/password/password';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import {
|
||||
AdB2cService,
|
||||
ConflictError,
|
||||
isConflictError,
|
||||
} from '../../gateways/adb2c/adb2c.service';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { CryptoService } from '../../gateways/crypto/crypto.service';
|
||||
import { SendGridService } from '../../gateways/sendgrid/sendgrid.service';
|
||||
import { User } from '../../repositories/users/entity/user.entity';
|
||||
import { makePassword } from '../../common/password/password';
|
||||
import { AccessToken } from '../../common/token';
|
||||
import { User as EntityUser } from '../../repositories/users/entity/user.entity';
|
||||
import {
|
||||
EmailAlreadyVerifiedError,
|
||||
UsersRepositoryService,
|
||||
} from '../../repositories/users/users.repository.service';
|
||||
import { User } from './types/types';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
@ -100,7 +101,7 @@ export class UsersService {
|
||||
const userId = Number(accessToken.userId);
|
||||
|
||||
//DBよりアクセス者の所属するアカウントIDを取得する
|
||||
let adminUser: User;
|
||||
let adminUser: EntityUser;
|
||||
try {
|
||||
adminUser = await this.usersRepository.findUserById(userId);
|
||||
} catch (e) {
|
||||
@ -141,7 +142,7 @@ export class UsersService {
|
||||
}
|
||||
|
||||
//Azure AD B2Cに登録したユーザー情報のID(sub)と受け取った情報を使ってDBにユーザーを登録する
|
||||
let newUser: User;
|
||||
let newUser: EntityUser;
|
||||
// TODO 本来はNULLだが、テーブル定義に誤ってNOTNULLが付いているため、一時的に適当な値を設定
|
||||
const accepted_terms_version = 'xxx';
|
||||
try {
|
||||
@ -261,4 +262,59 @@ export class UsersService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Users
|
||||
* @param accessToken
|
||||
* @returns users
|
||||
*/
|
||||
async getUsers(accessToken: string): Promise<User[]> {
|
||||
this.logger.log(`[IN] ${this.getUsers.name}`);
|
||||
|
||||
try {
|
||||
// DBよりアクセス者の所属するアカウントを取得する
|
||||
const pubKey = await this.cryptoService.getPublicKey();
|
||||
const payload = verify<AccessToken>(accessToken, pubKey);
|
||||
if (isVerifyError(payload)) {
|
||||
throw new Error(`${payload.reason} | ${payload.message}`);
|
||||
}
|
||||
|
||||
// DBから同一アカウントのユーザ一覧を取得する
|
||||
const dbUsers = await this.usersRepository.findSameAccountUsers(
|
||||
Number(payload.userId),
|
||||
);
|
||||
|
||||
// 値をマージして定義されたレスポンス通りに返す
|
||||
const users: User[] = [];
|
||||
// TODO 膨大なループが発生することが見込まれ商用には耐えないので、本実装時に修正予定
|
||||
for (let i = 0; i < dbUsers.length; i++) {
|
||||
// Azure AD B2Cからユーザーを取得する
|
||||
const aadb2cUser = await this.adB2cService.getUser(
|
||||
dbUsers[i].external_id,
|
||||
);
|
||||
|
||||
const user = new User();
|
||||
user.name = aadb2cUser.displayName;
|
||||
user.role = dbUsers[i].role;
|
||||
user.authorId = dbUsers[i].author_id;
|
||||
// TODO DBから取得できるようになるため暫定
|
||||
user.typistGroupName = '';
|
||||
user.email = aadb2cUser.mail;
|
||||
user.emailVerified = dbUsers[i].email_verified;
|
||||
user.autoRenew = dbUsers[i].auto_renew;
|
||||
user.licenseAlert = dbUsers[i].license_alert;
|
||||
user.notification = dbUsers[i].notification;
|
||||
users.push(user);
|
||||
}
|
||||
return users;
|
||||
} catch (e) {
|
||||
this.logger.error(`error=${e}`);
|
||||
throw new HttpException(
|
||||
makeErrorResponse('E009999'),
|
||||
HttpStatus.NOT_FOUND,
|
||||
);
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getUsers.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { ClientSecretCredential } from '@azure/identity';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import axios from 'axios';
|
||||
import { JwkSignKey, B2cMetadata } from '../../common/token';
|
||||
import { Client } from '@microsoft/microsoft-graph-client';
|
||||
import { TokenCredentialAuthenticationProvider } from '@microsoft/microsoft-graph-client/authProviders/azureTokenCredentials';
|
||||
import { ClientSecretCredential } from '@azure/identity';
|
||||
import { Aadb2cUser, B2cMetadata, JwkSignKey } from '../../common/token';
|
||||
|
||||
export type ConflictError = {
|
||||
reason: 'email';
|
||||
@ -165,4 +165,22 @@ export class AdB2cService {
|
||||
this.logger.log(`[OUT] ${this.changePassword.name}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Azure AD B2Cからユーザ情報を取得する
|
||||
* @param externalId 外部ユーザーID
|
||||
* @returns ユーザ情報
|
||||
*/
|
||||
async getUser(externalId: string): Promise<Aadb2cUser> {
|
||||
this.logger.log(`[IN] ${this.getUser.name}`);
|
||||
|
||||
try {
|
||||
return await this.graphClient.api(`users/${externalId}`).get();
|
||||
} catch (e) {
|
||||
this.logger.error(e);
|
||||
throw e;
|
||||
} finally {
|
||||
this.logger.log(`[OUT] ${this.getUser.name}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,4 +146,21 @@ export class UsersRepositoryService {
|
||||
return await repo.update({ id: targetUser.id }, targetUser);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 同じアカウントIDを持つユーザーを探す
|
||||
* @param userId
|
||||
* @returns User[]
|
||||
*/
|
||||
async findSameAccountUsers(userId: number): Promise<User[]> {
|
||||
const dbUser = await this.dataSource
|
||||
.getRepository(User)
|
||||
.findOne({ where: [{ id: userId }] });
|
||||
|
||||
const dbUsers = await this.dataSource
|
||||
.getRepository(User)
|
||||
.find({ where: [{ account_id: dbUser.account_id }] });
|
||||
|
||||
return dbUsers;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user