import { Inject, Injectable } from '@nestjs/common'; import { ISSUE_REPOSITORY, type IIssueRepository } from '../../../domain/repositories/issue.repository.interface.js'; import { IssueNotFoundException } from '../../../domain/exceptions/issue-not-found.exception.js'; import { IssueEditForbiddenException } from '../../../domain/exceptions/issue-edit-forbidden.exception.js'; import { UpdateIssueCommand } from './update-issue.command.js'; import { IssueWithUsersDto } from '../../dto/issue-with-users.dto.js'; import { IssueEventsService } from '../../services/issue-events.service.js'; import { IssueUserExpanderService } from '../../services/issue-user-expander.service.js'; import { IssueAssignmentNotifierService } from '../../services/issue-assignment-notifier.service.js'; import { IssueParticipantsService } from '../../services/issue-participants.service.js'; import { IssueUpdatedEvent } from '../../../domain/events/issue-updated.event.js'; @Injectable() export class UpdateIssueUseCase { constructor( @Inject(ISSUE_REPOSITORY) private readonly issueRepository: IIssueRepository, private readonly issueEventsService: IssueEventsService, private readonly issueUserExpander: IssueUserExpanderService, private readonly issueAssignmentNotifier: IssueAssignmentNotifierService, private readonly issueParticipants: IssueParticipantsService, ) {} async execute(command: UpdateIssueCommand): Promise { const issue = await this.issueRepository.findById(command.id, command.userId); if (!issue) { throw new IssueNotFoundException(command.id); } if (!issue.canBeEditedBy(command.userId)) { throw new IssueEditForbiddenException(command.id); } const observersBefore = [...issue.observers]; if (command.title !== undefined) { issue.updateTitle(command.title); } if (command.content !== undefined) { issue.updateContent(command.content); } if (command.status !== undefined) { issue.changeStatus(command.status); } if (command.priority !== undefined) { issue.changePriority(command.priority); } if (command.type !== undefined) { issue.changeType(command.type); } if (command.assignee !== undefined) { if (command.assignee === null || command.assignee === '') { issue.unassign(); } else { issue.assignTo(command.assignee); } } if (command.dueDate !== undefined) { issue.updateDueDate(command.dueDate); } // После assignee: новый исполнитель отбрасывается из наблюдателей if (command.observers !== undefined) { issue.setObservers(command.observers); } await this.issueParticipants.ensureObserversExist(issue.observers.filter((id) => !observersBefore.includes(id))); await this.issueRepository.update(issue, command.userId); const dto = await this.issueUserExpander.expand(issue); await this.issueParticipants.addToProject(issue); const domainEvents = issue.pullDomainEvents(); this.issueAssignmentNotifier.notify(issue, domainEvents); if (domainEvents.some((event) => event instanceof IssueUpdatedEvent)) { this.issueEventsService.emitIssueUpdated(dto); } return dto; } }