Merged PR 152: API実装(タスク一覧取得 | typist)
## 概要 [Task1865: API実装(タスク一覧取得 | typist)](https://paruru.nds-tyo.co.jp:8443/tfs/ReciproCollection/fa4924a4-d079-4fab-9fb5-a9a11eb205f0/_workitems/edit/1865) - Typist用のRepository呼び出しを追加 ## レビュー対象外 - テスト実装(別Taskで対応予定) ## レビューポイント - SQLの呼び出し回数が増え気味だが問題なさそうか - Task一覧の取得条件は間違っていなさそうであるか ## 動作確認状況 - ローカルで確認(ユーザーグループ等は各1件程度のデータで確認)
This commit is contained in:
parent
4065268820
commit
2cdcae4924
@ -87,7 +87,7 @@ export class TasksController {
|
||||
? body.direction
|
||||
: undefined;
|
||||
|
||||
const { tasks, total } = await this.taskService.getTasksFromAccountId(
|
||||
const { tasks, total } = await this.taskService.getTasks(
|
||||
decodedToken,
|
||||
offset,
|
||||
limit,
|
||||
|
||||
@ -22,7 +22,7 @@ describe('TasksService', () => {
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
expect(
|
||||
await service.tasksService.getTasksFromAccountId(
|
||||
await service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
@ -87,7 +87,7 @@ describe('TasksService', () => {
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
await expect(
|
||||
service.tasksService.getTasksFromAccountId(
|
||||
service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
@ -119,7 +119,7 @@ describe('TasksService', () => {
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
await expect(
|
||||
service.tasksService.getTasksFromAccountId(
|
||||
service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
@ -148,7 +148,7 @@ describe('TasksService', () => {
|
||||
status: 'Uploaded',
|
||||
priority: '00',
|
||||
created_at: new Date('2023-01-01T01:01:01.000'),
|
||||
option_items: undefined,
|
||||
option_items: undefined, // 存在しない場合でも空配列であるはずのものがundefined
|
||||
file: {
|
||||
id: 1,
|
||||
account_id: 1,
|
||||
@ -185,7 +185,7 @@ describe('TasksService', () => {
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
await expect(
|
||||
service.tasksService.getTasksFromAccountId(
|
||||
service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
@ -220,7 +220,7 @@ describe('TasksService', () => {
|
||||
const status = ['Uploaded,Backup'];
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
const result = await service.tasksService.getTasksFromAccountId(
|
||||
const result = await service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
@ -292,7 +292,7 @@ describe('TasksService', () => {
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
await expect(
|
||||
service.tasksService.getTasksFromAccountId(
|
||||
service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
@ -323,7 +323,7 @@ describe('TasksService', () => {
|
||||
const paramName = 'JOB_NUMBER';
|
||||
const direction = 'ASC';
|
||||
await expect(
|
||||
service.tasksService.getTasksFromAccountId(
|
||||
service.tasksService.getTasks(
|
||||
accessToken,
|
||||
offset,
|
||||
limit,
|
||||
|
||||
@ -20,7 +20,7 @@ export class TasksService {
|
||||
) {}
|
||||
|
||||
// TODO: 引数にAccessTokenがあるのは不適切なのでController側で分解したい
|
||||
async getTasksFromAccountId(
|
||||
async getTasks(
|
||||
accessToken: AccessToken,
|
||||
offset: number,
|
||||
limit: number,
|
||||
@ -40,6 +40,9 @@ export class TasksService {
|
||||
await this.usersRepository.findUserByExternalId(userId);
|
||||
|
||||
if (roles.includes(ADMIN_ROLES.ADMIN)) {
|
||||
const { account_id } = await this.usersRepository.findUserByExternalId(
|
||||
userId,
|
||||
);
|
||||
const result = await this.taskRepository.getTasksFromAccountId(
|
||||
account_id,
|
||||
offset,
|
||||
@ -69,7 +72,18 @@ export class TasksService {
|
||||
}
|
||||
|
||||
if (roles.includes(USER_ROLES.TYPIST)) {
|
||||
throw new Error(`NOT IMPLEMENTED`);
|
||||
const result = await this.taskRepository.getTasksFromTypistRelations(
|
||||
userId,
|
||||
offset,
|
||||
limit,
|
||||
paramName ?? defaultParamName,
|
||||
direction ?? defaultDirection,
|
||||
status,
|
||||
);
|
||||
|
||||
const tasks = createTasks(result.tasks, result.permissions);
|
||||
|
||||
return { tasks: tasks, total: result.count };
|
||||
}
|
||||
|
||||
throw new Error(`invalid roles: ${roles.join(',')}`);
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { Task } from '../../../repositories/tasks/entity/task.entity';
|
||||
import { UserGroup } from '../../../repositories/user_groups/entity/user_group.entity';
|
||||
import { User } from '../../../repositories/users/entity/user.entity';
|
||||
import {
|
||||
@ -6,6 +7,7 @@ import {
|
||||
PrimaryGeneratedColumn,
|
||||
JoinColumn,
|
||||
OneToOne,
|
||||
ManyToOne,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity({ name: 'checkout_permission' })
|
||||
@ -29,4 +31,8 @@ export class CheckoutPermission {
|
||||
@OneToOne(() => UserGroup, (group) => group.id)
|
||||
@JoinColumn({ name: 'user_group_id' })
|
||||
user_group?: UserGroup;
|
||||
|
||||
@ManyToOne(() => Task, (task) => task.id)
|
||||
@JoinColumn({ name: 'task_id' })
|
||||
task?: Task;
|
||||
}
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
SortDirection,
|
||||
TaskListSortableAttribute,
|
||||
} from '../../common/types/sort';
|
||||
import { UserGroupMember } from '../user_groups/entity/user_group_member.entity';
|
||||
|
||||
@Injectable()
|
||||
export class TasksRepositoryService {
|
||||
@ -155,6 +156,127 @@ export class TasksRepositoryService {
|
||||
return value;
|
||||
}
|
||||
|
||||
async getTasksFromTypistRelations(
|
||||
external_user_id: string,
|
||||
offset: number,
|
||||
limit: number,
|
||||
sort_criteria: TaskListSortableAttribute,
|
||||
direction: SortDirection,
|
||||
status: string[],
|
||||
): Promise<{
|
||||
tasks: Task[];
|
||||
permissions: CheckoutPermission[];
|
||||
count: number;
|
||||
}> {
|
||||
const order = makeOrder(sort_criteria, direction);
|
||||
|
||||
const value = await this.dataSource.transaction(async (entityManager) => {
|
||||
const groupMemberRepo = entityManager.getRepository(UserGroupMember);
|
||||
// ユーザーの所属するすべてのグループを列挙
|
||||
const groups = await groupMemberRepo.find({
|
||||
relations: {
|
||||
user: true,
|
||||
},
|
||||
where: {
|
||||
user: {
|
||||
external_id: external_user_id,
|
||||
},
|
||||
},
|
||||
});
|
||||
// ユーザーの所属するすべてのグループIDを列挙
|
||||
const groupIds = groups.map((member) => member.user_group_id);
|
||||
|
||||
const checkoutRepo = entityManager.getRepository(CheckoutPermission);
|
||||
// ユーザーに対するチェックアウト権限、またはユーザーの所属するユーザーグループのチェックアウト権限を取得
|
||||
const related = await checkoutRepo.find({
|
||||
relations: {
|
||||
task: true,
|
||||
},
|
||||
where: [
|
||||
{
|
||||
// ユーザーがチェックアウト可能である
|
||||
user: {
|
||||
external_id: external_user_id,
|
||||
},
|
||||
},
|
||||
{
|
||||
// ユーザーの所属するユーザーグループがチェックアウト可能である
|
||||
user_group_id: In(groupIds),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// ユーザー本人、またはユーザーが所属するユーザーグループがチェックアウト可能なタスクIDの一覧を作成
|
||||
const relatedTaskIds = related.map((permission) => permission.task_id);
|
||||
|
||||
const taskRepo = entityManager.getRepository(Task);
|
||||
|
||||
// [✔] 自分が割り当てられている
|
||||
// [✔] または 自分が割り当て可能になっている
|
||||
// [✔] または 自分が所属しているTypistGroupが割り当て可能になっている
|
||||
// という条件のTask一覧を取得する
|
||||
|
||||
// limit/offsetによらず条件に一致するすべてのレコード数を取得
|
||||
const count = await taskRepo.count({
|
||||
where: [
|
||||
{
|
||||
// Typistが割り当てられているTaskを取得
|
||||
typist_user: {
|
||||
external_id: external_user_id,
|
||||
},
|
||||
status: In(status),
|
||||
},
|
||||
{
|
||||
// TypistまたはTypistが所属するユーザーグループが割り当て可能になっているTaskを取得
|
||||
id: In(relatedTaskIds),
|
||||
status: In(status),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// 条件に該当するTask一覧を取得
|
||||
const tasks = await taskRepo.find({
|
||||
relations: {
|
||||
file: true,
|
||||
option_items: true,
|
||||
typist_user: true,
|
||||
},
|
||||
where: [
|
||||
{
|
||||
// Typistが割り当てられているTaskを取得
|
||||
typist_user: {
|
||||
external_id: external_user_id,
|
||||
},
|
||||
status: In(status),
|
||||
},
|
||||
{
|
||||
// TypistまたはTypistが所属するユーザーグループが割り当て可能になっているTaskを取得
|
||||
id: In(relatedTaskIds),
|
||||
status: In(status),
|
||||
},
|
||||
],
|
||||
order: order, // 引数によってOrderに使用するパラメータを変更
|
||||
take: limit,
|
||||
skip: offset,
|
||||
});
|
||||
|
||||
// TODO: Task内にCheckoutPermissionを含める方法が上手くいかなかった(複雑になりすぎた? 原因未調査)ため、
|
||||
// 確実に上手くいく方法としてQueryの分割を行ったが、本来はオブジェクトの構築はTypeORMに一任したい
|
||||
const taskIds = tasks.map((x) => x.id);
|
||||
const permissions = await checkoutRepo.find({
|
||||
relations: {
|
||||
user: true,
|
||||
user_group: true,
|
||||
},
|
||||
where: {
|
||||
task_id: In(taskIds),
|
||||
},
|
||||
});
|
||||
return { tasks, permissions, count };
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* 文字起こしタスクと音声ファイル、オプションアイテムを追加
|
||||
*/
|
||||
|
||||
@ -0,0 +1,39 @@
|
||||
import { User } from '../../../repositories/users/entity/user.entity';
|
||||
import {
|
||||
Entity,
|
||||
Column,
|
||||
PrimaryGeneratedColumn,
|
||||
OneToOne,
|
||||
JoinColumn,
|
||||
} from 'typeorm';
|
||||
|
||||
@Entity({ name: 'user_group_member' })
|
||||
export class UserGroupMember {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
user_group_id: number;
|
||||
|
||||
@Column()
|
||||
user_id: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
deleted_at?: Date;
|
||||
|
||||
@Column()
|
||||
created_by: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
created_at?: Date;
|
||||
|
||||
@Column()
|
||||
updated_by: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
updated_at?: Date;
|
||||
|
||||
@OneToOne(() => User, (user) => user.id)
|
||||
@JoinColumn({ name: 'user_id' })
|
||||
user?: User;
|
||||
}
|
||||
@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { UserGroupsRepositoryService } from './user_groups.repository.service';
|
||||
import { UserGroup } from './entity/user_group.entity';
|
||||
import { UserGroupMember } from './entity/user_group_member.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([UserGroup])],
|
||||
imports: [TypeOrmModule.forFeature([UserGroup, UserGroupMember])],
|
||||
providers: [UserGroupsRepositoryService],
|
||||
exports: [UserGroupsRepositoryService],
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user