Merged PR 537: API実装(代行操作用トークン更新API)
## 概要 [Task2906: API実装(代行操作用トークン更新API)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/2906) - アクセストークン更新APIとテストを実装しました。 ## レビューポイント - リポジトリのアカウントチェックは適切か - テストケースは適切か ## UIの変更 - なし ## 動作確認状況 - ローカルで確認
This commit is contained in:
parent
f33af7a9cd
commit
01d92b2408
@ -32,7 +32,7 @@ import { AuthGuard } from '../../common/guards/auth/authguards';
|
|||||||
import { RoleGuard } from '../../common/guards/role/roleguards';
|
import { RoleGuard } from '../../common/guards/role/roleguards';
|
||||||
import { ADMIN_ROLES, TIERS } from '../../constants';
|
import { ADMIN_ROLES, TIERS } from '../../constants';
|
||||||
import jwt from 'jsonwebtoken';
|
import jwt from 'jsonwebtoken';
|
||||||
import { AccessToken } from '../../common/token';
|
import { AccessToken, RefreshToken } from '../../common/token';
|
||||||
|
|
||||||
@ApiTags('auth')
|
@ApiTags('auth')
|
||||||
@Controller('auth')
|
@Controller('auth')
|
||||||
@ -248,9 +248,23 @@ export class AuthController {
|
|||||||
HttpStatus.UNAUTHORIZED,
|
HttpStatus.UNAUTHORIZED,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
const decodedRefreshToken = jwt.decode(refreshToken, { json: true });
|
||||||
|
if (!decodedRefreshToken) {
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E000101'),
|
||||||
|
HttpStatus.UNAUTHORIZED,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const { userId, delegateUserId } = decodedRefreshToken as RefreshToken;
|
||||||
|
|
||||||
const context = makeContext(uuidv4());
|
const context = makeContext(userId);
|
||||||
|
const accessToken = await this.authService.updateDelegationAccessToken(
|
||||||
|
context,
|
||||||
|
delegateUserId,
|
||||||
|
userId,
|
||||||
|
refreshToken,
|
||||||
|
);
|
||||||
|
|
||||||
return { accessToken: '' };
|
return { accessToken };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,9 +9,13 @@ import {
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { makeContext } from '../../common/log';
|
import { makeContext } from '../../common/log';
|
||||||
import { makeTestingModule } from '../../common/test/modules';
|
import { makeTestingModule } from '../../common/test/modules';
|
||||||
import { makeTestAccount } from '../../common/test/utility';
|
import { getAccount, makeTestAccount } from '../../common/test/utility';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
import { createTermInfo } from './test/utility';
|
import {
|
||||||
|
createTermInfo,
|
||||||
|
deleteAccount,
|
||||||
|
updateAccountDelegationPermission,
|
||||||
|
} from './test/utility';
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
import { TIERS, USER_ROLES } from '../../constants';
|
import { TIERS, USER_ROLES } from '../../constants';
|
||||||
import { decode, isVerifyError } from '../../common/jwt';
|
import { decode, isVerifyError } from '../../common/jwt';
|
||||||
@ -512,6 +516,214 @@ describe('generateDelegationAccessToken', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('updateDelegationAccessToken', () => {
|
||||||
|
let source: DataSource | null = null;
|
||||||
|
beforeEach(async () => {
|
||||||
|
source = new DataSource({
|
||||||
|
type: 'sqlite',
|
||||||
|
database: ':memory:',
|
||||||
|
logging: false,
|
||||||
|
entities: [__dirname + '/../../**/*.entity{.ts,.js}'],
|
||||||
|
synchronize: true, // trueにすると自動的にmigrationが行われるため注意
|
||||||
|
});
|
||||||
|
return source.initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
if (!source) return;
|
||||||
|
await source.destroy();
|
||||||
|
source = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('代行操作用リフレッシュトークンから代行操作用アクセストークンを更新できること', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
if (!module) fail();
|
||||||
|
const service = module.get<AuthService>(AuthService);
|
||||||
|
const { admin: parentAdmin, account: parentAccount } =
|
||||||
|
await makeTestAccount(source, {
|
||||||
|
tier: 4,
|
||||||
|
});
|
||||||
|
const { admin: partnerAdmin, account: partnerAccount } =
|
||||||
|
await makeTestAccount(
|
||||||
|
source,
|
||||||
|
{
|
||||||
|
tier: 5,
|
||||||
|
parent_account_id: parentAccount.id,
|
||||||
|
delegation_permission: true,
|
||||||
|
},
|
||||||
|
{ role: USER_ROLES.NONE },
|
||||||
|
);
|
||||||
|
|
||||||
|
const context = makeContext(parentAdmin.external_id);
|
||||||
|
|
||||||
|
const delegationRefreshToken = await service.generateDelegationRefreshToken(
|
||||||
|
context,
|
||||||
|
parentAdmin.external_id,
|
||||||
|
partnerAccount.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 取得できた代行操作用リフレッシュトークンをデコード
|
||||||
|
const decodeRefreshToken = decode<RefreshToken>(delegationRefreshToken);
|
||||||
|
if (isVerifyError(decodeRefreshToken)) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(decodeRefreshToken.role).toBe('none admin');
|
||||||
|
expect(decodeRefreshToken.tier).toBe(TIERS.TIER5);
|
||||||
|
expect(decodeRefreshToken.userId).toBe(partnerAdmin.external_id);
|
||||||
|
expect(decodeRefreshToken.delegateUserId).toBe(parentAdmin.external_id);
|
||||||
|
|
||||||
|
const token = await service.updateDelegationAccessToken(
|
||||||
|
context,
|
||||||
|
decodeRefreshToken.delegateUserId,
|
||||||
|
decodeRefreshToken.userId,
|
||||||
|
delegationRefreshToken,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 取得できた代行操作用リフレッシュトークンをデコード
|
||||||
|
const decodeAccessToken = decode<RefreshToken>(token);
|
||||||
|
if (isVerifyError(decodeAccessToken)) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(decodeAccessToken.role).toBe('none admin');
|
||||||
|
expect(decodeAccessToken.tier).toBe(TIERS.TIER5);
|
||||||
|
expect(decodeAccessToken.userId).toBe(partnerAdmin.external_id);
|
||||||
|
expect(decodeAccessToken.delegateUserId).toBe(parentAdmin.external_id);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('代行操作対象アカウントの代行操作が許可されていない場合、エラーとなること', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
if (!module) fail();
|
||||||
|
const service = module.get<AuthService>(AuthService);
|
||||||
|
const { admin: parentAdmin, account: parentAccount } =
|
||||||
|
await makeTestAccount(source, {
|
||||||
|
tier: 4,
|
||||||
|
});
|
||||||
|
const { admin: partnerAdmin, account: partnerAccount } =
|
||||||
|
await makeTestAccount(
|
||||||
|
source,
|
||||||
|
{
|
||||||
|
tier: 5,
|
||||||
|
parent_account_id: parentAccount.id,
|
||||||
|
delegation_permission: true,
|
||||||
|
},
|
||||||
|
{ role: USER_ROLES.NONE },
|
||||||
|
);
|
||||||
|
|
||||||
|
const context = makeContext(parentAdmin.external_id);
|
||||||
|
|
||||||
|
const delegationRefreshToken = await service.generateDelegationRefreshToken(
|
||||||
|
context,
|
||||||
|
parentAdmin.external_id,
|
||||||
|
partnerAccount.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 取得できた代行操作用リフレッシュトークンをデコード
|
||||||
|
const decodeRefreshToken = decode<RefreshToken>(delegationRefreshToken);
|
||||||
|
if (isVerifyError(decodeRefreshToken)) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(decodeRefreshToken.role).toBe('none admin');
|
||||||
|
expect(decodeRefreshToken.tier).toBe(TIERS.TIER5);
|
||||||
|
expect(decodeRefreshToken.userId).toBe(partnerAdmin.external_id);
|
||||||
|
expect(decodeRefreshToken.delegateUserId).toBe(parentAdmin.external_id);
|
||||||
|
|
||||||
|
if (decodeRefreshToken.delegateUserId === undefined) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代行操作対象アカウントの代行操作を許可しないように変更
|
||||||
|
await updateAccountDelegationPermission(source, partnerAccount.id, false);
|
||||||
|
const account = await getAccount(source, partnerAccount.id);
|
||||||
|
|
||||||
|
expect(account?.delegation_permission ?? true).toBeFalsy();
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.updateDelegationAccessToken(
|
||||||
|
context,
|
||||||
|
decodeRefreshToken.delegateUserId,
|
||||||
|
decodeRefreshToken.userId,
|
||||||
|
delegationRefreshToken,
|
||||||
|
);
|
||||||
|
fail();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toEqual(HttpStatus.UNAUTHORIZED);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E010503'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it('代行操作対象アカウントが存在しない場合、エラーとなること', async () => {
|
||||||
|
if (!source) fail();
|
||||||
|
const module = await makeTestingModule(source);
|
||||||
|
if (!module) fail();
|
||||||
|
const service = module.get<AuthService>(AuthService);
|
||||||
|
const { admin: parentAdmin, account: parentAccount } =
|
||||||
|
await makeTestAccount(source, {
|
||||||
|
tier: 4,
|
||||||
|
});
|
||||||
|
const { admin: partnerAdmin, account: partnerAccount } =
|
||||||
|
await makeTestAccount(
|
||||||
|
source,
|
||||||
|
{
|
||||||
|
tier: 5,
|
||||||
|
parent_account_id: parentAccount.id,
|
||||||
|
delegation_permission: true,
|
||||||
|
},
|
||||||
|
{ role: USER_ROLES.NONE },
|
||||||
|
);
|
||||||
|
|
||||||
|
const context = makeContext(parentAdmin.external_id);
|
||||||
|
|
||||||
|
const delegationRefreshToken = await service.generateDelegationRefreshToken(
|
||||||
|
context,
|
||||||
|
parentAdmin.external_id,
|
||||||
|
partnerAccount.id,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 取得できた代行操作用リフレッシュトークンをデコード
|
||||||
|
const decodeRefreshToken = decode<RefreshToken>(delegationRefreshToken);
|
||||||
|
if (isVerifyError(decodeRefreshToken)) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(decodeRefreshToken.role).toBe('none admin');
|
||||||
|
expect(decodeRefreshToken.tier).toBe(TIERS.TIER5);
|
||||||
|
expect(decodeRefreshToken.userId).toBe(partnerAdmin.external_id);
|
||||||
|
expect(decodeRefreshToken.delegateUserId).toBe(parentAdmin.external_id);
|
||||||
|
|
||||||
|
if (decodeRefreshToken.delegateUserId === undefined) {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代行操作対象アカウントを削除
|
||||||
|
deleteAccount(source, partnerAccount.id);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.updateDelegationAccessToken(
|
||||||
|
context,
|
||||||
|
decodeRefreshToken.delegateUserId,
|
||||||
|
partnerAdmin.external_id,
|
||||||
|
delegationRefreshToken,
|
||||||
|
);
|
||||||
|
fail();
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
expect(e.getStatus()).toEqual(HttpStatus.UNAUTHORIZED);
|
||||||
|
expect(e.getResponse()).toEqual(makeErrorResponse('E010501'));
|
||||||
|
} else {
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
const idTokenPayload = {
|
const idTokenPayload = {
|
||||||
exp: 9000000000,
|
exp: 9000000000,
|
||||||
nbf: 1000000000,
|
nbf: 1000000000,
|
||||||
|
|||||||
@ -25,8 +25,15 @@ import {
|
|||||||
AccountNotFoundError,
|
AccountNotFoundError,
|
||||||
AdminUserNotFoundError,
|
AdminUserNotFoundError,
|
||||||
} from '../../repositories/accounts/errors/types';
|
} from '../../repositories/accounts/errors/types';
|
||||||
import { DelegationNotAllowedError } from '../../repositories/users/errors/types';
|
import {
|
||||||
import { RoleUnexpectedError, TierUnexpectedError } from './errors/types';
|
DelegationNotAllowedError,
|
||||||
|
UserNotFoundError,
|
||||||
|
} from '../../repositories/users/errors/types';
|
||||||
|
import {
|
||||||
|
InvalidTokenFormatError,
|
||||||
|
RoleUnexpectedError,
|
||||||
|
TierUnexpectedError,
|
||||||
|
} from './errors/types';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AuthService {
|
export class AuthService {
|
||||||
@ -328,6 +335,116 @@ export class AuthService {
|
|||||||
return accessToken;
|
return accessToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代行操作用アクセストークンを更新する
|
||||||
|
* @param context
|
||||||
|
* @param delegateUserExternalId
|
||||||
|
* @param originUserExternalId
|
||||||
|
* @param refreshToken
|
||||||
|
* @returns delegation access token
|
||||||
|
*/
|
||||||
|
async updateDelegationAccessToken(
|
||||||
|
context: Context,
|
||||||
|
delegateUserExternalId: string | undefined,
|
||||||
|
originUserExternalId: string,
|
||||||
|
refreshToken: string,
|
||||||
|
): Promise<string> {
|
||||||
|
this.logger.log(
|
||||||
|
`[IN] [${context.trackingId}] ${this.updateDelegationAccessToken.name} | params: { ` +
|
||||||
|
`delegateUserExternalId: ${delegateUserExternalId}, ` +
|
||||||
|
`originUserExternalId: ${originUserExternalId}, };`,
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
if (!delegateUserExternalId) {
|
||||||
|
throw new UserNotFoundError('delegateUserExternalId is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
const user = await this.usersRepository.findUserByExternalId(
|
||||||
|
delegateUserExternalId,
|
||||||
|
);
|
||||||
|
|
||||||
|
const privateKey = getPrivateKey(this.configService);
|
||||||
|
const pubkey = getPublicKey(this.configService);
|
||||||
|
|
||||||
|
// トークンの検証
|
||||||
|
const decodedToken = verify<RefreshToken>(refreshToken, pubkey);
|
||||||
|
if (isVerifyError(decodedToken)) {
|
||||||
|
throw new InvalidTokenFormatError(
|
||||||
|
`Invalid token format. ${decodedToken.reason} | ${decodedToken.message}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// トークンの生成には検証済みトークンの値を使用する
|
||||||
|
const { userId, delegateUserId, tier, role } = decodedToken;
|
||||||
|
|
||||||
|
if (delegateUserId === undefined) {
|
||||||
|
throw new AdminUserNotFoundError('delegateUserId is undefined');
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代行操作対象アカウントの管理者ユーザーが存在して、アカウントに対して代行操作権限があるか確認
|
||||||
|
const delegationPermission =
|
||||||
|
await this.usersRepository.isAllowDelegationPermission(
|
||||||
|
user.account_id,
|
||||||
|
userId,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!delegationPermission) {
|
||||||
|
throw new DelegationNotAllowedError(
|
||||||
|
`Delegation is not allowed. delegateUserId=${delegateUserId}, userId=${userId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const accessToken = sign<AccessToken>(
|
||||||
|
{
|
||||||
|
role: role,
|
||||||
|
tier: tier,
|
||||||
|
userId: userId,
|
||||||
|
delegateUserId: delegateUserId,
|
||||||
|
},
|
||||||
|
this.accessTokenlifetime,
|
||||||
|
privateKey,
|
||||||
|
);
|
||||||
|
|
||||||
|
return accessToken;
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`error=${e}`);
|
||||||
|
if (e instanceof HttpException) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
if (e instanceof Error) {
|
||||||
|
switch (e.constructor) {
|
||||||
|
case InvalidTokenFormatError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E000101'),
|
||||||
|
HttpStatus.UNAUTHORIZED,
|
||||||
|
);
|
||||||
|
case UserNotFoundError:
|
||||||
|
case AccountNotFoundError:
|
||||||
|
case AdminUserNotFoundError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E010501'),
|
||||||
|
HttpStatus.UNAUTHORIZED,
|
||||||
|
);
|
||||||
|
case DelegationNotAllowedError:
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E010503'),
|
||||||
|
HttpStatus.UNAUTHORIZED,
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new HttpException(
|
||||||
|
makeErrorResponse('E009999'),
|
||||||
|
HttpStatus.INTERNAL_SERVER_ERROR,
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
this.logger.log(
|
||||||
|
`[OUT] [${context.trackingId}] ${this.updateDelegationAccessToken.name}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets id token
|
* Gets id token
|
||||||
* @param token
|
* @param token
|
||||||
|
|||||||
@ -2,3 +2,5 @@
|
|||||||
export class RoleUnexpectedError extends Error {}
|
export class RoleUnexpectedError extends Error {}
|
||||||
// Tier範囲想定外エラー
|
// Tier範囲想定外エラー
|
||||||
export class TierUnexpectedError extends Error {}
|
export class TierUnexpectedError extends Error {}
|
||||||
|
// トークン形式不正エラー
|
||||||
|
export class InvalidTokenFormatError extends Error {}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import { DataSource } from 'typeorm';
|
import { DataSource } from 'typeorm';
|
||||||
import { Term } from '../../../repositories/terms/entity/term.entity';
|
import { Term } from '../../../repositories/terms/entity/term.entity';
|
||||||
|
import { Account } from '../../../repositories/accounts/entity/account.entity';
|
||||||
|
import { User } from '../../../repositories/users/entity/user.entity';
|
||||||
|
|
||||||
export const createTermInfo = async (
|
export const createTermInfo = async (
|
||||||
datasource: DataSource,
|
datasource: DataSource,
|
||||||
@ -16,3 +18,21 @@ export const createTermInfo = async (
|
|||||||
});
|
});
|
||||||
identifiers.pop() as Term;
|
identifiers.pop() as Term;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const updateAccountDelegationPermission = async (
|
||||||
|
dataSource: DataSource,
|
||||||
|
id: number,
|
||||||
|
delegationPermission: boolean,
|
||||||
|
): Promise<void> => {
|
||||||
|
await dataSource
|
||||||
|
.getRepository(Account)
|
||||||
|
.update({ id: id }, { delegation_permission: delegationPermission });
|
||||||
|
};
|
||||||
|
|
||||||
|
export const deleteAccount = async (
|
||||||
|
dataSource: DataSource,
|
||||||
|
id: number,
|
||||||
|
): Promise<void> => {
|
||||||
|
await dataSource.getRepository(User).delete({ account_id: id });
|
||||||
|
await dataSource.getRepository(Account).delete({ id: id });
|
||||||
|
};
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
|
||||||
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
|
||||||
import { AccessToken } from '../../common/token';
|
|
||||||
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
|
||||||
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
|
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
|
||||||
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
import { BlobstorageService } from '../../gateways/blobstorage/blobstorage.service';
|
||||||
|
|||||||
@ -601,4 +601,47 @@ export class UsersRepositoryService {
|
|||||||
return primaryUser;
|
return primaryUser;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代行操作対象のユーザーの所属するアカウントの代行操作が許可されているか
|
||||||
|
* @param delegateAccountId 代行操作者のアカウントID
|
||||||
|
* @param originAccountId 代行操作対象のアカウントID
|
||||||
|
* @returns delegate accounts
|
||||||
|
*/
|
||||||
|
async isAllowDelegationPermission(
|
||||||
|
delegateAccountId: number,
|
||||||
|
originUserExternalId: string,
|
||||||
|
): Promise<boolean> {
|
||||||
|
return await this.dataSource.transaction(async (entityManager) => {
|
||||||
|
const userRepo = entityManager.getRepository(User);
|
||||||
|
const primaryUser = await userRepo.findOne({
|
||||||
|
where: {
|
||||||
|
external_id: originUserExternalId,
|
||||||
|
account: {
|
||||||
|
parent_account_id: delegateAccountId,
|
||||||
|
tier: TIERS.TIER5,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
relations: {
|
||||||
|
account: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!primaryUser) {
|
||||||
|
throw new AdminUserNotFoundError(
|
||||||
|
`Admin user is not found. externalId: ${originUserExternalId}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const originAccount = primaryUser.account;
|
||||||
|
|
||||||
|
// 運用上、アカウントがいないことはあり得ないが、プログラム上発生しうるのでエラーとして処理
|
||||||
|
if (!originAccount) {
|
||||||
|
throw new Error(`Account is Not Found. id: ${primaryUser.account_id}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 代行操作の許可の有無を返却
|
||||||
|
return originAccount.delegation_permission;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user