Skip to content

Commit

Permalink
feat: task subscriptions on members assigned
Browse files Browse the repository at this point in the history
  • Loading branch information
GloireMutaliko21 committed Dec 5, 2024
1 parent 13e7f97 commit a12e07c
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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';
Expand All @@ -24,6 +28,8 @@ import { TypeOrmTaskRepository } from '../../repository/type-orm-task.repository
@CommandHandler(AutomationTaskSyncCommand)
export class AutomationTaskSyncHandler implements ICommandHandler<AutomationTaskSyncCommand> {
constructor(
private readonly _eventBus: EventBus,

@InjectRepository(Task)
private readonly typeOrmTaskRepository: TypeOrmTaskRepository,

Expand All @@ -34,8 +40,9 @@ export class AutomationTaskSyncHandler implements ICommandHandler<AutomationTask
private readonly typeOrmIntegrationMapRepository: TypeOrmIntegrationMapRepository,

private readonly _taskService: TaskService,

private readonly activityLogService: ActivityLogService
private readonly activityLogService: ActivityLogService,
private readonly _employeeService: EmployeeService,
private readonly _subscriptionService: SubscriptionService
) {}

/**
Expand Down Expand Up @@ -145,8 +152,46 @@ export class AutomationTaskSyncHandler implements ICommandHandler<AutomationTask
// Save the new task
const createdTask = await this.typeOrmTaskRepository.save(newTask);

// Activity Log Task Creation
// Subscribe creator to the task
const { organizationId, tenantId } = createdTask;
this._eventBus.publish(
new CreateSubscriptionEvent({
entity: BaseEntityEnum.Task,
entityId: createdTask.id,
userId: createdTask.creatorId,
type: SubscriptionTypeEnum.CREATED_ENTITY,
organizationId,
tenantId
})
);

// Subscribe assignees to the task
if (entity.members.length > 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<Task>(
BaseEntityEnum.Task,
ActionTypeEnum.Created,
Expand Down Expand Up @@ -175,6 +220,7 @@ export class AutomationTaskSyncHandler implements ICommandHandler<AutomationTask
*/
async updateTask(id: ID, entity: ITaskUpdateInput): Promise<ITask> {
try {
const { members = [] } = entity;
// Find task relations
const relations = this.typeOrmTaskRepository.metadata.relations.map((relation) => relation.propertyName);

Expand All @@ -183,15 +229,60 @@ export class AutomationTaskSyncHandler implements ICommandHandler<AutomationTask
if (!existingTask) {
return;
}
const taskMembers = existingTask.members;

// Separate members into removed and new members
const memberIds = members.map(({ id }) => 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<Task>(
BaseEntityEnum.Task,
ActionTypeEnum.Updated,
Expand Down
30 changes: 28 additions & 2 deletions packages/core/src/tasks/commands/handlers/task-create.handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand All @@ -22,6 +23,7 @@ export class TaskCreateHandler implements ICommandHandler<TaskCreateCommand> {
private readonly _cqrsEventBus: CqrsEventBus,
private readonly _taskService: TaskService,
private readonly _organizationProjectService: OrganizationProjectService,
private readonly _employeeService: EmployeeService,
private readonly mentionService: MentionService,
private readonly activityLogService: ActivityLogService
) {}
Expand All @@ -36,7 +38,7 @@ export class TaskCreateHandler implements ICommandHandler<TaskCreateCommand> {
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;
Expand Down Expand Up @@ -103,7 +105,31 @@ export class TaskCreateHandler implements ICommandHandler<TaskCreateCommand> {
})
);

// 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<Task>(
Expand Down
60 changes: 57 additions & 3 deletions packages/core/src/tasks/task.service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { EventBus } from '@nestjs/cqrs';
import { Injectable, BadRequestException, HttpStatus, HttpException } from '@nestjs/common';
import {
IsNull,
Expand All @@ -23,16 +24,19 @@ import {
ITaskUpdateInput,
PermissionsEnum,
ActionTypeEnum,
ITaskDateFilterInput
ITaskDateFilterInput,
SubscriptionTypeEnum
} from '@gauzy/contracts';
import { isEmpty, isNotEmpty } from '@gauzy/common';
import { isPostgres, isSqlite } from '@gauzy/config';
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';
Expand All @@ -43,10 +47,12 @@ import { MikroOrmTaskRepository } from './repository/mikro-orm-task.repository';
@Injectable()
export class TaskService extends TenantAwareCrudService<Task> {
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
) {
Expand All @@ -71,6 +77,15 @@ export class TaskService extends TenantAwareCrudService<Task> {

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;

Expand Down Expand Up @@ -117,10 +132,49 @@ export class TaskService extends TenantAwareCrudService<Task> {
}
}

// 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<Task>(
BaseEntityEnum.Task,
ActionTypeEnum.Updated,
Expand Down

0 comments on commit a12e07c

Please sign in to comment.