From f671653fc1975cb1ba9b4422f9ba979594ef5333 Mon Sep 17 00:00:00 2001 From: alexeh Date: Mon, 1 Jul 2024 09:43:57 +0200 Subject: [PATCH] update task ownership at user deletion --- api/src/modules/tasks/tasks.service.ts | 18 ++++++++++++----- api/src/modules/users/users.controller.ts | 3 +++ api/src/modules/users/users.module.ts | 2 ++ api/test/e2e/users/users.spec.ts | 24 +++++++++++++++++++++++ 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/api/src/modules/tasks/tasks.service.ts b/api/src/modules/tasks/tasks.service.ts index d24f0440d..d4921fe1f 100644 --- a/api/src/modules/tasks/tasks.service.ts +++ b/api/src/modules/tasks/tasks.service.ts @@ -17,11 +17,8 @@ import { UpdateTaskDto, } from 'modules/tasks/dto/update-task.dto'; import { GetReportsDto } from 'modules/tasks/dto/get-reports.dto'; -import { - ErrorRecord, - TaskReportService, -} from 'modules/tasks/task-report.service'; -import { ImportTaskError } from './types/import-task-error.type'; +import { TaskReportService } from 'modules/tasks/task-report.service'; +import { ImportTaskError } from 'modules/tasks/types/import-task-error.type'; @Injectable() export class TasksService extends AppBaseService< @@ -153,4 +150,15 @@ export class TasksService extends AppBaseService< errors as ImportTaskError[], ); } + + async updateTaskOwner(oldUserId: string, newUserId: string): Promise { + const tasks: Task[] = await this.taskRepository.find({ + where: { userId: oldUserId }, + }); + if (!tasks.length) return; + await this.taskRepository.update( + { userId: oldUserId }, + { userId: newUserId }, + ); + } } diff --git a/api/src/modules/users/users.controller.ts b/api/src/modules/users/users.controller.ts index e8be0e1d7..619f376d6 100644 --- a/api/src/modules/users/users.controller.ts +++ b/api/src/modules/users/users.controller.ts @@ -49,6 +49,7 @@ import { Public } from 'decorators/public.decorator'; import { ResetPasswordDto } from 'modules/authentication/dto/reset-password.dto'; import { GetUser } from 'decorators/get-user.decorator'; import { ScenariosService } from 'modules/scenarios/scenarios.service'; +import { TasksService } from 'modules/tasks/tasks.service'; @ApiTags(userResource.className) @Controller(`/api/v1/users`) @@ -58,6 +59,7 @@ export class UsersController { constructor( public readonly service: UsersService, private readonly scenarioService: ScenariosService, + private readonly taskService: TasksService, private readonly accessControl: AccessControl, ) {} @@ -251,6 +253,7 @@ export class UsersController { userIdToDelete, requestingUserId, ); + await this.taskService.updateTaskOwner(userIdToDelete, requestingUserId); return this.service.deleteUser(userIdToDelete); } } diff --git a/api/src/modules/users/users.module.ts b/api/src/modules/users/users.module.ts index b0e32cae6..f2e40ed6c 100644 --- a/api/src/modules/users/users.module.ts +++ b/api/src/modules/users/users.module.ts @@ -9,6 +9,7 @@ import { Role } from 'modules/authorization/roles/role.entity'; import { UserRepository } from 'modules/users/user.repository'; import { AuthorizationModule } from 'modules/authorization/authorization.module'; import { ScenariosModule } from 'modules/scenarios/scenarios.module'; +import { TasksModule } from 'modules/tasks/tasks.module'; @Module({ imports: [ @@ -16,6 +17,7 @@ import { ScenariosModule } from 'modules/scenarios/scenarios.module'; forwardRef(() => AuthenticationModule), AuthorizationModule, ScenariosModule, + TasksModule, ], providers: [UsersService, UserCommand, UserRepository], controllers: [UsersController], diff --git a/api/test/e2e/users/users.spec.ts b/api/test/e2e/users/users.spec.ts index 9599363bf..477f9a4c9 100644 --- a/api/test/e2e/users/users.spec.ts +++ b/api/test/e2e/users/users.spec.ts @@ -17,6 +17,7 @@ import { createScenarioIntervention, createSourcingLocation, createSourcingRecord, + createTask, createUser, } from '../../entity-mocks'; import { Scenario } from '../../../src/modules/scenarios/scenario.entity'; @@ -28,6 +29,7 @@ import { import { SourcingRecord } from '../../../src/modules/sourcing-records/sourcing-record.entity'; import { PERMISSIONS } from 'modules/authorization/permissions/permissions.enum'; import { JSONAPIUserData } from '../../../src/modules/users/user.entity'; +import { Task } from '../../../src/modules/tasks/task.entity'; /** * Tests for the UsersModule. @@ -467,5 +469,27 @@ describe('UsersModule (e2e)', () => { expect(scenariosOfNewUser).toHaveLength(2); expect(scenariosOfDeletedUser).toHaveLength(0); }); + test('A admin user should be able to delete a user, and task should be assigned to the deleting user', async () => { + const userToDelete = await createUser({ email: 'usertodelete@mail.com' }); + const newAdminUser = await setupTestUser(testApplication, ROLES.ADMIN, { + email: 'newadmin2@test.com', + }); + for (const _ of [1, 2, 3, 4, 5]) { + await createTask({ userId: userToDelete.id }); + } + const response = await request(testApplication.getHttpServer()) + .delete(`/api/v1/users/${userToDelete.id}`) + .set('Authorization', `Bearer ${newAdminUser.jwtToken}`); + + expect(response.status).toEqual(200); + const tasks = await dataSource.getRepository(Task).find(); + const taskOfDeletedUser = await dataSource + .getRepository(Task) + .find({ where: { userId: userToDelete.id } }); + expect(taskOfDeletedUser).toHaveLength(0); + tasks.forEach((task: Task) => + expect(task.userId).toEqual(newAdminUser.user.id), + ); + }); }); });