From 040825dcfd7c437e3508ad7d37726142121c149e Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 5 Dec 2024 12:29:29 +0200 Subject: [PATCH 1/5] feat: project subscriptions on members assigned --- .../organization-project.service.ts | 63 ++++++++++++++++++- .../src/subscription/subscription.module.ts | 6 +- 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/packages/core/src/organization-project/organization-project.service.ts b/packages/core/src/organization-project/organization-project.service.ts index d04993d0c15..46c97bcef23 100644 --- a/packages/core/src/organization-project/organization-project.service.ts +++ b/packages/core/src/organization-project/organization-project.service.ts @@ -1,3 +1,4 @@ +import { EventBus } from '@nestjs/cqrs'; import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { ILike, In, IsNull, SelectQueryBuilder } from 'typeorm'; import { @@ -13,7 +14,8 @@ import { IOrganizationProjectsFindInput, IOrganizationProjectUpdateInput, IPagination, - RolesEnum + RolesEnum, + SubscriptionTypeEnum } from '@gauzy/contracts'; import { getConfig } from '@gauzy/config'; import { CustomEmbeddedFieldConfig, isNotEmpty } from '@gauzy/common'; @@ -22,10 +24,12 @@ import { RequestContext } from '../core/context'; import { OrganizationProjectEmployee } from '../core/entities/internal'; import { FavoriteService } from '../core/decorators'; import { RoleService } from '../role/role.service'; +import { SubscriptionService } from '../subscription/subscription.service'; import { ActivityLogService } from '../activity-log/activity-log.service'; +import { EmployeeService } from '../employee/employee.service'; +import { CreateSubscriptionEvent } from '../subscription/events'; import { OrganizationProject } from './organization-project.entity'; import { prepareSQLQuery as p } from './../database/database.helper'; -import { EmployeeService } from '../employee/employee.service'; import { TypeOrmEmployeeRepository } from '../employee/repository'; import { MikroOrmOrganizationProjectEmployeeRepository, @@ -38,6 +42,7 @@ import { @Injectable() export class OrganizationProjectService extends TenantAwareCrudService { constructor( + private readonly _eventBus: EventBus, readonly typeOrmOrganizationProjectRepository: TypeOrmOrganizationProjectRepository, readonly mikroOrmOrganizationProjectRepository: MikroOrmOrganizationProjectRepository, readonly typeOrmOrganizationProjectEmployeeRepository: TypeOrmOrganizationProjectEmployeeRepository, @@ -45,6 +50,7 @@ export class OrganizationProjectService extends TenantAwareCrudService + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.OrganizationProject, + entityId: project.id, + userId, + type: + id === employeeId + ? SubscriptionTypeEnum.CREATED_ENTITY + : SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + // Generate the activity log this._activityLogService.logActivity( BaseEntityEnum.OrganizationProject, @@ -268,6 +295,20 @@ export class OrganizationProjectService extends TenantAwareCrudService member.id)); + + // Unsubscribe members who were unassigned from project + try { + await Promise.all( + removedMembers.map( + async (member) => + await this._subscriptionService.delete({ + entity: BaseEntityEnum.OrganizationProject, + entityId: organizationProjectId, + userId: member.employee.userId + }) + ) + ); + } catch (error) {} } // 2. Update roles for existing members where necessary @@ -300,6 +341,24 @@ export class OrganizationProjectService extends TenantAwareCrudService + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.OrganizationProject, + entityId: organizationProjectId, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + await this.typeOrmOrganizationProjectEmployeeRepository.save(newProjectMembers); } } diff --git a/packages/core/src/subscription/subscription.module.ts b/packages/core/src/subscription/subscription.module.ts index f8b6262ded5..222f2a9c887 100644 --- a/packages/core/src/subscription/subscription.module.ts +++ b/packages/core/src/subscription/subscription.module.ts @@ -1,5 +1,5 @@ import { CqrsModule } from '@nestjs/cqrs'; -import { Module } from '@nestjs/common'; +import { Global, Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { MikroOrmModule } from '@mikro-orm/nestjs'; import { RolePermissionModule } from '../role-permission/role-permission.module'; @@ -10,6 +10,7 @@ import { SubscriptionController } from './subscription.controller'; import { Subscription } from './subscription.entity'; import { TypeOrmSubscriptionRepository } from './repository/type-orm-subscription.repository'; +@Global() @Module({ imports: [ TypeOrmModule.forFeature([Subscription]), @@ -18,6 +19,7 @@ import { TypeOrmSubscriptionRepository } from './repository/type-orm-subscriptio CqrsModule ], providers: [SubscriptionService, TypeOrmSubscriptionRepository, ...CommandHandlers, ...EventHandlers], - controllers: [SubscriptionController] + controllers: [SubscriptionController], + exports: [TypeOrmModule, MikroOrmModule, SubscriptionService, TypeOrmSubscriptionRepository] }) export class SubscriptionModule {} From ce8549f7a121367f38128f9c100e446164a93e81 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 5 Dec 2024 12:44:07 +0200 Subject: [PATCH 2/5] feat: team subscriptions on members assigned --- .../organization-team-employee.module.ts | 2 + .../organization-team-employee.service.ts | 44 ++++++++++++++++++- .../organization-team.service.ts | 31 ++++++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/packages/core/src/organization-team-employee/organization-team-employee.module.ts b/packages/core/src/organization-team-employee/organization-team-employee.module.ts index cbc939f50db..bb6744374d6 100644 --- a/packages/core/src/organization-team-employee/organization-team-employee.module.ts +++ b/packages/core/src/organization-team-employee/organization-team-employee.module.ts @@ -1,3 +1,4 @@ +import { CqrsModule } from '@nestjs/cqrs'; import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { MikroOrmModule } from '@mikro-orm/nestjs'; @@ -13,6 +14,7 @@ import { TypeOrmOrganizationTeamEmployeeRepository } from './repository'; TypeOrmModule.forFeature([OrganizationTeamEmployee]), MikroOrmModule.forFeature([OrganizationTeamEmployee]), RolePermissionModule, + CqrsModule, TaskModule ], controllers: [OrganizationTeamEmployeeController], diff --git a/packages/core/src/organization-team-employee/organization-team-employee.service.ts b/packages/core/src/organization-team-employee/organization-team-employee.service.ts index 97d504a8d9e..bc768d5a322 100644 --- a/packages/core/src/organization-team-employee/organization-team-employee.service.ts +++ b/packages/core/src/organization-team-employee/organization-team-employee.service.ts @@ -1,27 +1,34 @@ +import { EventBus } from '@nestjs/cqrs'; import { ForbiddenException, Injectable } from '@nestjs/common'; import { DeleteResult, FindOptionsWhere, UpdateResult } from 'typeorm'; import { + BaseEntityEnum, ID, IEmployee, IOrganizationTeamEmployeeActiveTaskUpdateInput, IOrganizationTeamEmployeeFindInput, IOrganizationTeamEmployeeUpdateInput, PermissionsEnum, - RolesEnum + RolesEnum, + SubscriptionTypeEnum } from '@gauzy/contracts'; import { TenantAwareCrudService } from './../core/crud'; import { RequestContext } from './../core/context'; import { Role } from './../core/entities/internal'; import { OrganizationTeamEmployee } from './organization-team-employee.entity'; import { TaskService } from './../tasks/task.service'; +import { CreateSubscriptionEvent } from '../subscription/events'; +import { SubscriptionService } from '../subscription/subscription.service'; import { MikroOrmOrganizationTeamEmployeeRepository, TypeOrmOrganizationTeamEmployeeRepository } from './repository'; @Injectable() export class OrganizationTeamEmployeeService extends TenantAwareCrudService { constructor( + private readonly _eventBus: EventBus, readonly typeOrmOrganizationTeamEmployeeRepository: TypeOrmOrganizationTeamEmployeeRepository, readonly mikroOrmOrganizationTeamEmployeeRepository: MikroOrmOrganizationTeamEmployeeRepository, - private readonly taskService: TaskService + private readonly taskService: TaskService, + private readonly subscriptionService: SubscriptionService ) { super(typeOrmOrganizationTeamEmployeeRepository, mikroOrmOrganizationTeamEmployeeRepository); } @@ -64,6 +71,21 @@ export class OrganizationTeamEmployeeService extends TenantAwareCrudService 0) { await this.deleteMemberByIds(removedMembers.map((member) => member.id)); + + // Unsubscribe members who were unassigned from project + try { + await Promise.all( + removedMembers.map( + async (member) => + await this.subscriptionService.delete({ + entity: BaseEntityEnum.OrganizationTeam, + entityId: organizationTeamId, + userId: member.employee.userId, + type: SubscriptionTypeEnum.ASSIGNMENT + }) + ) + ); + } catch (error) {} } // 2. Update role for existing members @@ -97,6 +119,24 @@ export class OrganizationTeamEmployeeService extends TenantAwareCrudService + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.OrganizationTeam, + entityId: organizationTeamId, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + await this.typeOrmRepository.save(newTeamMembers); } } diff --git a/packages/core/src/organization-team/organization-team.service.ts b/packages/core/src/organization-team/organization-team.service.ts index b21083eae4b..d1d662aba3c 100644 --- a/packages/core/src/organization-team/organization-team.service.ts +++ b/packages/core/src/organization-team/organization-team.service.ts @@ -1,3 +1,4 @@ +import { EventBus } from '@nestjs/cqrs'; import { Injectable, BadRequestException, @@ -19,7 +20,8 @@ import { IOrganizationTeamStatisticInput, ITimerStatus, BaseEntityEnum, - ID + ID, + SubscriptionTypeEnum } from '@gauzy/contracts'; import { isNotEmpty, parseToBoolean } from '@gauzy/common'; import { FavoriteService } from '../core/decorators'; @@ -36,6 +38,7 @@ import { TypeOrmEmployeeRepository } from '../employee/repository'; import { EmployeeService } from './../employee/employee.service'; import { TimerService } from '../time-tracking/timer/timer.service'; import { StatisticService } from '../time-tracking/statistic'; +import { CreateSubscriptionEvent } from '../subscription/events'; import { GetOrganizationTeamStatisticQuery } from './queries'; import { MikroOrmOrganizationTeamRepository, TypeOrmOrganizationTeamRepository } from './repository'; import { OrganizationTeam } from './organization-team.entity'; @@ -45,6 +48,7 @@ import { MikroOrmOrganizationTeamEmployeeRepository } from '../organization-team @Injectable() export class OrganizationTeamService extends TenantAwareCrudService { constructor( + private readonly _eventBus: EventBus, readonly typeOrmOrganizationTeamRepository: TypeOrmOrganizationTeamRepository, readonly mikroOrmOrganizationTeamRepository: MikroOrmOrganizationTeamRepository, readonly mikroOrmOrganizationTeamEmployeeRepository: MikroOrmOrganizationTeamEmployeeRepository, @@ -244,7 +248,7 @@ export class OrganizationTeamService extends TenantAwareCrudService + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.OrganizationTeam, + entityId: organizationTeam.id, + userId, + type: + id === employeeId + ? SubscriptionTypeEnum.CREATED_ENTITY + : SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + + return organizationTeam; } catch (error) { throw new BadRequestException(`Failed to create a team: ${error}`); } From 13e7f9799a031acf1934c4acf348a4b00f98affd Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 5 Dec 2024 12:52:50 +0200 Subject: [PATCH 3/5] feat: sprint subscriptions on members assigned --- .../organization-project.service.ts | 3 +- .../organization-sprint.service.ts | 62 ++++++++++++++++++- .../organization-team-employee.service.ts | 4 +- .../organization-team.service.ts | 2 +- 4 files changed, 66 insertions(+), 5 deletions(-) diff --git a/packages/core/src/organization-project/organization-project.service.ts b/packages/core/src/organization-project/organization-project.service.ts index 46c97bcef23..778218230fb 100644 --- a/packages/core/src/organization-project/organization-project.service.ts +++ b/packages/core/src/organization-project/organization-project.service.ts @@ -304,7 +304,8 @@ export class OrganizationProjectService extends TenantAwareCrudService { constructor( + private readonly _eventBus: EventBus, readonly typeOrmOrganizationSprintRepository: TypeOrmOrganizationSprintRepository, readonly mikroOrmOrganizationSprintRepository: MikroOrmOrganizationSprintRepository, readonly typeOrmOrganizationSprintEmployeeRepository: TypeOrmOrganizationSprintEmployeeRepository, @@ -39,6 +44,7 @@ export class OrganizationSprintService extends TenantAwareCrudService + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.OrganizationSprint, + entityId: sprint.id, + userId, + type: + id === employeeId + ? SubscriptionTypeEnum.CREATED_ENTITY + : SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + // Generate the activity log this.activityLogService.logActivity( BaseEntityEnum.OrganizationSprint, @@ -263,6 +290,21 @@ export class OrganizationSprintService extends TenantAwareCrudService member.id)); + + // Unsubscribe members who were unassigned from sprint + try { + await Promise.all( + removedMembers.map( + async (member) => + await this.subscriptionService.delete({ + entity: BaseEntityEnum.OrganizationSprint, + entityId: organizationSprintId, + userId: member.employee.userId, + type: SubscriptionTypeEnum.ASSIGNMENT + }) + ) + ); + } catch (error) {} } // 2. Update roles for existing members where necessary. @@ -292,6 +334,24 @@ export class OrganizationSprintService extends TenantAwareCrudService + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.OrganizationSprint, + entityId: organizationSprintId, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + await this.typeOrmOrganizationSprintEmployeeRepository.save(newSprintMembers); } } diff --git a/packages/core/src/organization-team-employee/organization-team-employee.service.ts b/packages/core/src/organization-team-employee/organization-team-employee.service.ts index bc768d5a322..3d75295e404 100644 --- a/packages/core/src/organization-team-employee/organization-team-employee.service.ts +++ b/packages/core/src/organization-team-employee/organization-team-employee.service.ts @@ -72,7 +72,7 @@ export class OrganizationTeamEmployeeService extends TenantAwareCrudService 0) { await this.deleteMemberByIds(removedMembers.map((member) => member.id)); - // Unsubscribe members who were unassigned from project + // Unsubscribe members who were unassigned from team try { await Promise.all( removedMembers.map( @@ -119,7 +119,7 @@ export class OrganizationTeamEmployeeService extends TenantAwareCrudService diff --git a/packages/core/src/organization-team/organization-team.service.ts b/packages/core/src/organization-team/organization-team.service.ts index d1d662aba3c..7828207c79b 100644 --- a/packages/core/src/organization-team/organization-team.service.ts +++ b/packages/core/src/organization-team/organization-team.service.ts @@ -262,7 +262,7 @@ export class OrganizationTeamService extends TenantAwareCrudService From a12e07c115787f855cbb429428e1e20aceed1135 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 5 Dec 2024 15:39:49 +0200 Subject: [PATCH 4/5] feat: task subscriptions on members assigned --- .../handlers/automation-task.sync.handler.ts | 103 +++++++++++++++++- .../commands/handlers/task-create.handler.ts | 30 ++++- packages/core/src/tasks/task.service.ts | 60 +++++++++- 3 files changed, 182 insertions(+), 11 deletions(-) diff --git a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts index 8fd9aaacd45..cd10aade77c 100644 --- a/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts +++ b/packages/core/src/tasks/commands/handlers/automation-task.sync.handler.ts @@ -1,4 +1,4 @@ -import { ICommandHandler, CommandHandler } from '@nestjs/cqrs'; +import { ICommandHandler, CommandHandler, EventBus } from '@nestjs/cqrs'; import { InjectRepository } from '@nestjs/typeorm'; import * as chalk from 'chalk'; import { @@ -9,11 +9,15 @@ import { IIntegrationMap, ITask, ITaskCreateInput, - ITaskUpdateInput + ITaskUpdateInput, + SubscriptionTypeEnum } from '@gauzy/contracts'; import { RequestContext } from '../../../core/context'; import { IntegrationMap, TaskStatus } from '../../../core/entities/internal'; +import { CreateSubscriptionEvent } from '../../../subscription/events'; import { AutomationTaskSyncCommand } from './../automation-task.sync.command'; +import { EmployeeService } from '../../../employee/employee.service'; +import { SubscriptionService } from '../../../subscription/subscription.service'; import { TaskService } from './../../task.service'; import { ActivityLogService } from '../../../activity-log/activity-log.service'; import { Task } from './../../task.entity'; @@ -24,6 +28,8 @@ import { TypeOrmTaskRepository } from '../../repository/type-orm-task.repository @CommandHandler(AutomationTaskSyncCommand) export class AutomationTaskSyncHandler implements ICommandHandler { constructor( + private readonly _eventBus: EventBus, + @InjectRepository(Task) private readonly typeOrmTaskRepository: TypeOrmTaskRepository, @@ -34,8 +40,9 @@ export class AutomationTaskSyncHandler implements ICommandHandler 0) { + try { + const employeeIds = entity.members.map(({ id }) => id); + const employees = await this._employeeService.findActiveEmployeesByEmployeeIds( + employeeIds, + organizationId, + tenantId + ); + await Promise.all( + employees.map(({ userId }) => + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.Task, + entityId: createdTask.id, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + } + + // Activity Log Task Creation this.activityLogService.logActivity( BaseEntityEnum.Task, ActionTypeEnum.Created, @@ -175,6 +220,7 @@ export class AutomationTaskSyncHandler implements ICommandHandler { try { + const { members = [] } = entity; // Find task relations const relations = this.typeOrmTaskRepository.metadata.relations.map((relation) => relation.propertyName); @@ -183,15 +229,60 @@ export class AutomationTaskSyncHandler implements ICommandHandler id); + const existingMemberIds = taskMembers.map(({ id }) => id); + + const removedMembers = taskMembers.filter((member) => !memberIds.includes(member.id)); + const newMembers = members.filter((member) => !existingMemberIds.includes(member.id)); // Update the existing task with the new entity data this.typeOrmTaskRepository.merge(existingTask, entity); // Save the updated task const updatedTask = await this.typeOrmTaskRepository.save(existingTask); + const { organizationId, tenantId } = updatedTask; + + // Unsubscribe members who were unassigned from task + if (removedMembers.length > 0) { + try { + await Promise.all( + removedMembers.map( + async (member) => + await this._subscriptionService.delete({ + entity: BaseEntityEnum.Task, + entityId: updatedTask.id, + userId: member.userId, + type: SubscriptionTypeEnum.ASSIGNMENT + }) + ) + ); + } catch (error) {} + } + + // Subscribe new assignees to the task + if (newMembers.length) { + try { + await Promise.all( + newMembers.map(({ userId }) => + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.Task, + entityId: updatedTask.id, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + } // Activity Log Task Update - const { organizationId, tenantId } = updatedTask; this.activityLogService.logActivity( BaseEntityEnum.Task, ActionTypeEnum.Updated, diff --git a/packages/core/src/tasks/commands/handlers/task-create.handler.ts b/packages/core/src/tasks/commands/handlers/task-create.handler.ts index 24cae283979..0778de1fd32 100644 --- a/packages/core/src/tasks/commands/handlers/task-create.handler.ts +++ b/packages/core/src/tasks/commands/handlers/task-create.handler.ts @@ -10,6 +10,7 @@ import { CreateSubscriptionEvent } from '../../../subscription/events'; import { TaskCreateCommand } from './../task-create.command'; import { TaskService } from '../../task.service'; import { Task } from './../../task.entity'; +import { EmployeeService } from '../../../employee/employee.service'; import { MentionService } from '../../../mention/mention.service'; import { ActivityLogService } from '../../../activity-log/activity-log.service'; @@ -22,6 +23,7 @@ export class TaskCreateHandler implements ICommandHandler { private readonly _cqrsEventBus: CqrsEventBus, private readonly _taskService: TaskService, private readonly _organizationProjectService: OrganizationProjectService, + private readonly _employeeService: EmployeeService, private readonly mentionService: MentionService, private readonly activityLogService: ActivityLogService ) {} @@ -36,7 +38,7 @@ export class TaskCreateHandler implements ICommandHandler { try { // Destructure input and triggered event flag from the command const { input, triggeredEvent } = command; - const { organizationId, mentionUserIds = [], ...data } = input; + const { organizationId, mentionUserIds = [], members = [], ...data } = input; // Retrieve current tenant ID from request context or use input tenant ID const tenantId = RequestContext.currentTenantId() ?? data.tenantId; @@ -103,7 +105,31 @@ export class TaskCreateHandler implements ICommandHandler { }) ); - // TODO : Subscribe assignees + // Subscribe assignees to the task + if (members.length > 0) { + try { + const employeeIds = members.map(({ id }) => id); + const employees = await this._employeeService.findActiveEmployeesByEmployeeIds( + employeeIds, + organizationId, + tenantId + ); + await Promise.all( + employees.map(({ userId }) => + this._cqrsEventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.Task, + entityId: task.id, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) {} + } // Generate the activity log this.activityLogService.logActivity( diff --git a/packages/core/src/tasks/task.service.ts b/packages/core/src/tasks/task.service.ts index 086e6a487fe..3ef963bc538 100644 --- a/packages/core/src/tasks/task.service.ts +++ b/packages/core/src/tasks/task.service.ts @@ -1,3 +1,4 @@ +import { EventBus } from '@nestjs/cqrs'; import { Injectable, BadRequestException, HttpStatus, HttpException } from '@nestjs/common'; import { IsNull, @@ -23,7 +24,8 @@ import { ITaskUpdateInput, PermissionsEnum, ActionTypeEnum, - ITaskDateFilterInput + ITaskDateFilterInput, + SubscriptionTypeEnum } from '@gauzy/contracts'; import { isEmpty, isNotEmpty } from '@gauzy/common'; import { isPostgres, isSqlite } from '@gauzy/config'; @@ -31,8 +33,10 @@ import { PaginationParams, TenantAwareCrudService } from './../core/crud'; import { addBetween } from './../core/util'; import { RequestContext } from '../core/context'; import { TaskViewService } from './views/view.service'; +import { SubscriptionService } from '../subscription/subscription.service'; import { MentionService } from '../mention/mention.service'; import { ActivityLogService } from '../activity-log/activity-log.service'; +import { CreateSubscriptionEvent } from '../subscription/events'; import { Task } from './task.entity'; import { TypeOrmOrganizationSprintTaskHistoryRepository } from './../organization-sprint/repository/type-orm-organization-sprint-task-history.repository'; import { GetTaskByIdDTO } from './dto'; @@ -43,10 +47,12 @@ import { MikroOrmTaskRepository } from './repository/mikro-orm-task.repository'; @Injectable() export class TaskService extends TenantAwareCrudService { constructor( + private readonly _eventBus: EventBus, readonly typeOrmTaskRepository: TypeOrmTaskRepository, readonly mikroOrmTaskRepository: MikroOrmTaskRepository, readonly typeOrmOrganizationSprintTaskHistoryRepository: TypeOrmOrganizationSprintTaskHistoryRepository, private readonly taskViewService: TaskViewService, + private readonly _subscriptionService: SubscriptionService, private readonly mentionService: MentionService, private readonly activityLogService: ActivityLogService ) { @@ -71,6 +77,15 @@ export class TaskService extends TenantAwareCrudService { const task = await this.findOneByIdString(id, { relations }); + const taskMembers = task.members; + + // Separate members into removed and new members + const memberIdSet = new Set(data.members.map(({ id }) => id)); + const existingMemberIdSet = new Set(taskMembers.map(({ id }) => id)); + + const removedMembers = taskMembers.filter((member) => !memberIdSet.has(member.id)); + const newMembers = data.members.filter((member) => !existingMemberIdSet.has(member.id)); + if (data.projectId && data.projectId !== task.projectId) { const { organizationId, projectId } = task; @@ -117,10 +132,49 @@ export class TaskService extends TenantAwareCrudService { } } - // TODO : Subscribe assignees + const { organizationId } = updatedTask; + // Unsubscribe members who were unassigned from task + if (removedMembers.length > 0) { + try { + await Promise.all( + removedMembers.map( + async (member) => + await this._subscriptionService.delete({ + entity: BaseEntityEnum.Task, + entityId: updatedTask.id, + userId: member.userId, + type: SubscriptionTypeEnum.ASSIGNMENT + }) + ) + ); + } catch (error) { + console.error('Error publishing CreateSubscriptionEvent:', error); + } + } + + // Subscribe the new assignees to the task + if (newMembers.length) { + try { + await Promise.all( + newMembers.map(({ userId }) => + this._eventBus.publish( + new CreateSubscriptionEvent({ + entity: BaseEntityEnum.Task, + entityId: updatedTask.id, + userId, + type: SubscriptionTypeEnum.ASSIGNMENT, + organizationId, + tenantId + }) + ) + ) + ); + } catch (error) { + console.error('Error publishing CreateSubscriptionEvent:', error); + } + } // Generate the activity log - const { organizationId } = updatedTask; this.activityLogService.logActivity( BaseEntityEnum.Task, ActionTypeEnum.Updated, From ae3ea5e916af61adf6016b3624bfddb5125f7b01 Mon Sep 17 00:00:00 2001 From: GloireMutaliko21 Date: Thu, 5 Dec 2024 16:08:28 +0200 Subject: [PATCH 5/5] fix: coderrabitai suggestions --- .../organization-project.service.ts | 8 ++++++-- .../organization-team-employee.service.ts | 8 ++++++-- .../organization-team/organization-team.service.ts | 4 +++- .../handlers/automation-task.sync.handler.ts | 12 +++++++++--- .../tasks/commands/handlers/task-create.handler.ts | 4 +++- packages/core/src/tasks/task.service.ts | 2 +- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/packages/core/src/organization-project/organization-project.service.ts b/packages/core/src/organization-project/organization-project.service.ts index 778218230fb..3fffe79feb5 100644 --- a/packages/core/src/organization-project/organization-project.service.ts +++ b/packages/core/src/organization-project/organization-project.service.ts @@ -147,7 +147,9 @@ export class OrganizationProjectService extends TenantAwareCrudService( @@ -309,7 +311,9 @@ export class OrganizationProjectService extends TenantAwareCrudService { ) ) ); - } catch (error) {} + } catch (error) { + this.logger.error('Error while subscribing members to task', error); + } } // Generate the activity log diff --git a/packages/core/src/tasks/task.service.ts b/packages/core/src/tasks/task.service.ts index 3ef963bc538..062f7a480d8 100644 --- a/packages/core/src/tasks/task.service.ts +++ b/packages/core/src/tasks/task.service.ts @@ -148,7 +148,7 @@ export class TaskService extends TenantAwareCrudService { ) ); } catch (error) { - console.error('Error publishing CreateSubscriptionEvent:', error); + console.error('Error unsubscribing members from the task:', error); } }