saito.k d75c003b09 Merged PR 145: typist名をAzure AD B2Cから取得し表示できるようにする
## 概要
[Task1950: typist名をAzure AD B2Cから取得し表示できるようにする](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1950)

- チェックアウト権限にあるTypistのユーザー名をB2Cから取得する
  - チェックアウト権限に含まれているuser.externalIdを列挙
  - ExternalIdでフィルターをかけてユーザー情報を取得
  - B2Cへのリクエスト上限超過時のエラーを制御するために専用エラーを定義
- import文が常に絶対パスで指定されていて、それでテストがこけるので相対パスでインポートするようにvscodeを設定

## レビューポイント
- convert.tsの修正は問題ないか

## UIの変更
- Before/Afterのスクショなど
- スクショ置き場

## 動作確認状況
- ローカルで確認

## 補足
- 取得方法についてはMSに問い合わせ中
2023-06-19 00:48:32 +00:00

161 lines
5.3 KiB
TypeScript

import { HttpException, HttpStatus, Injectable, Logger } from '@nestjs/common';
import { TasksRepositoryService } from '../../repositories/tasks/tasks.repository.service';
import { AccessToken } from '../../common/token';
import { Task } from './types/types';
import { Task as TaskEntity } from '../../repositories/tasks/entity/task.entity';
import { createTasks } from './types/convert';
import { UsersRepositoryService } from '../../repositories/users/users.repository.service';
import { makeErrorResponse } from '../../common/error/makeErrorResponse';
import {
SortDirection,
TaskListSortableAttribute,
} from '../../common/types/sort';
import { ADMIN_ROLES, USER_ROLES } from '../../constants';
import {
AdB2cService,
Adb2cTooManyRequestsError,
} from '../../gateways/adb2c/adb2c.service';
import { AdB2cUser } from '../../gateways/adb2c/types/types';
import { CheckoutPermission } from '../../repositories/checkout_permissions/entity/checkout_permission.entity';
@Injectable()
export class TasksService {
private readonly logger = new Logger(TasksService.name);
constructor(
private readonly taskRepository: TasksRepositoryService,
private readonly usersRepository: UsersRepositoryService,
private readonly adB2cService: AdB2cService,
) {}
// TODO: 引数にAccessTokenがあるのは不適切なのでController側で分解したい
async getTasks(
accessToken: AccessToken,
offset: number,
limit: number,
status: string[],
paramName?: TaskListSortableAttribute,
direction?: SortDirection,
): Promise<{ tasks: Task[]; total: number }> {
const { role, userId } = accessToken;
const roles = role.split(' '); // TODO: Roleを型で定義されているものに修正する
// パラメータが省略された場合のデフォルト値: 保存するソート条件の値の初期値と揃える
const defaultParamName: TaskListSortableAttribute = 'JOB_NUMBER';
const defaultDirection: SortDirection = 'ASC';
try {
const { account_id, author_id } =
await this.usersRepository.findUserByExternalId(userId);
if (roles.includes(ADMIN_ROLES.ADMIN)) {
const result = await this.taskRepository.getTasksFromAccountId(
account_id,
offset,
limit,
paramName ?? defaultParamName,
direction ?? defaultDirection,
status,
);
// B2Cからユーザー名を取得する
const b2cUsers = await this.getB2cUsers(
result.tasks,
result.permissions,
);
const tasks = createTasks(result.tasks, result.permissions, b2cUsers);
return { tasks: tasks, total: result.count };
}
if (roles.includes(USER_ROLES.AUTHOR)) {
const result =
await this.taskRepository.getTasksFromAuthorIdAndAccountId(
author_id,
account_id,
offset,
limit,
paramName ?? defaultParamName,
direction ?? defaultDirection,
status,
);
// B2Cからユーザー名を取得する
const b2cUsers = await this.getB2cUsers(
result.tasks,
result.permissions,
);
const tasks = createTasks(result.tasks, result.permissions, b2cUsers);
return { tasks: tasks, total: result.count };
}
if (roles.includes(USER_ROLES.TYPIST)) {
const result = await this.taskRepository.getTasksFromTypistRelations(
userId,
offset,
limit,
paramName ?? defaultParamName,
direction ?? defaultDirection,
status,
);
// B2Cからユーザー名を取得する
const b2cUsers = await this.getB2cUsers(
result.tasks,
result.permissions,
);
const tasks = createTasks(result.tasks, result.permissions, b2cUsers);
return { tasks: tasks, total: result.count };
}
throw new Error(`invalid roles: ${roles.join(',')}`);
} catch (e) {
this.logger.error(`error=${e}`);
if (e instanceof Error) {
if (e.constructor === Adb2cTooManyRequestsError) {
throw new HttpException(
makeErrorResponse('E000301'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
throw new HttpException(
makeErrorResponse('E009999'),
HttpStatus.INTERNAL_SERVER_ERROR,
);
}
}
private async getB2cUsers(
tasks: TaskEntity[],
permissions: CheckoutPermission[],
): Promise<AdB2cUser[]> {
// 割り当て候補の外部IDを列挙
const assigneesExternalIds = permissions.map((x) => {
if (x.user) {
return x.user.external_id;
}
});
// 割り当てられているタイピストの外部IDを列挙
const typistExternalIds = tasks.flatMap((x) => {
if (x.typist_user) {
return x.typist_user.external_id;
}
});
console.log(assigneesExternalIds.concat(undefined));
//重複をなくす
const distinctedExternalIds = [
...new Set(assigneesExternalIds.concat(typistExternalIds)),
];
// undefinedがあった場合、取り除く
const filteredExternalIds: string[] = distinctedExternalIds.filter(
(x): x is string => x !== undefined,
);
// B2Cからユーザー名を取得する
return await this.adB2cService.getUsers(filteredExternalIds);
}
}