From 57c787bf01080c7c8798466cacdf107f6221adf6 Mon Sep 17 00:00:00 2001 From: Struchkov Mark Date: Mon, 26 Aug 2024 17:56:18 +0300 Subject: [PATCH] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=BE=D0=B4=D1=85=D0=BE=D0=B4=D0=B0=20?= =?UTF-8?q?=D0=BA=20=D1=83=D0=B2=D0=B5=D0=B4=D0=BE=D0=BC=D0=BB=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D1=8F=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../context/domain/entity/Discussion.java | 7 + .../context/domain/entity/MergeRequest.java | 20 +- .../gitlab/context/domain/entity/Person.java | 4 +- .../context/domain/entity/Pipeline.java | 7 + .../domain/event/NewDiscussionEvent.java | 19 ++ .../domain/event/NewMergeRequestEvent.java | 19 ++ .../domain/event/NewPipelineEvent.java | 19 ++ .../context/domain/event/NewProjectEvent.java | 19 ++ .../domain/event/UpdateDiscussionEvent.java | 20 ++ .../domain/event/UpdateMergeRequestEvent.java | 25 ++ .../domain/event/UpdatePipelineEvent.java | 20 ++ .../core/handler/DiscussionHandler.java | 265 +++++++++++++++++ .../core/handler/MergeRequestHandler.java | 273 ++++++++++++++++++ .../gitlab/core/handler/PipelineHandler.java | 59 ++++ .../gitlab/core/handler/ProjectHandler.java | 36 +++ .../core/service/DiscussionServiceImpl.java | 237 +-------------- .../service/MergeRequestsServiceImpl.java | 242 +--------------- .../core/service/PipelineServiceImpl.java | 45 +-- .../core/service/ProjectServiceImpl.java | 25 +- 19 files changed, 829 insertions(+), 532 deletions(-) create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewDiscussionEvent.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewMergeRequestEvent.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewPipelineEvent.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewProjectEvent.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateDiscussionEvent.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateMergeRequestEvent.java create mode 100644 bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdatePipelineEvent.java create mode 100644 bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/DiscussionHandler.java create mode 100644 bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/MergeRequestHandler.java create mode 100644 bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/PipelineHandler.java create mode 100644 bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/ProjectHandler.java diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java index dd07c32..5de163b 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Discussion.java @@ -10,8 +10,12 @@ import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.util.List; @@ -25,7 +29,10 @@ import static dev.struchkov.haiti.utils.Checker.checkNotEmpty; @Getter @Setter @Entity +@NoArgsConstructor +@Builder(toBuilder = true) @Table(name = "discussion") +@AllArgsConstructor(access = AccessLevel.PRIVATE) @EqualsAndHashCode(onlyExplicitlyIncluded = true) public class Discussion { diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java index d463002..318a7bf 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequest.java @@ -17,8 +17,12 @@ import jakarta.persistence.JoinTable; import jakarta.persistence.ManyToOne; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; @@ -35,9 +39,12 @@ import java.util.Set; @Getter @Setter @Entity -@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE}) +@NoArgsConstructor +@Builder(toBuilder = true) @Table(name = "merge_request") +@FieldNames(mode = {Mode.TABLE, Mode.SIMPLE}) @EqualsAndHashCode(onlyExplicitlyIncluded = true) +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class MergeRequest { @Id @@ -95,17 +102,6 @@ public class MergeRequest { ) private List reviewers = new ArrayList<>(); - @OneToMany( - fetch = FetchType.LAZY, - cascade = {CascadeType.PERSIST, CascadeType.MERGE} - ) - @JoinTable( - name = "merge_request_approvals", - joinColumns = @JoinColumn(name = "merge_request_id", referencedColumnName = "id"), - inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id") - ) - private List approvals = new ArrayList<>(); - @Column(name = "target_branch") private String targetBranch; diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Person.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Person.java index bdb363b..ee3ce53 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Person.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Person.java @@ -9,6 +9,7 @@ import jakarta.persistence.Table; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Setter; +import lombok.ToString; /** * @author upagge 14.01.2021 @@ -16,9 +17,10 @@ import lombok.Setter; @Entity @Getter @Setter -@EqualsAndHashCode(onlyExplicitlyIncluded = true) +@ToString @Table(name = "person") @FieldNames(mode = {Mode.TABLE, Mode.SIMPLE}) +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class Person { @Id diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Pipeline.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Pipeline.java index 2471935..614577d 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Pipeline.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/Pipeline.java @@ -11,8 +11,12 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import java.time.LocalDateTime; @@ -25,8 +29,11 @@ import java.time.LocalDateTime; @Getter @Setter @FieldNames +@NoArgsConstructor @Table(name = "pipeline") +@Builder(toBuilder = true) @EqualsAndHashCode(onlyExplicitlyIncluded = true) +@AllArgsConstructor(access = AccessLevel.PRIVATE) public class Pipeline { @Id diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewDiscussionEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewDiscussionEvent.java new file mode 100644 index 0000000..b017478 --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewDiscussionEvent.java @@ -0,0 +1,19 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "newDiscussion") +public class NewDiscussionEvent { + + private Discussion discussion; + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewMergeRequestEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewMergeRequestEvent.java new file mode 100644 index 0000000..f6daa32 --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewMergeRequestEvent.java @@ -0,0 +1,19 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "newMergeRequest") +public class NewMergeRequestEvent { + + private MergeRequest mergeRequest; + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewPipelineEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewPipelineEvent.java new file mode 100644 index 0000000..595fa6a --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewPipelineEvent.java @@ -0,0 +1,19 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "newPipeline") +public class NewPipelineEvent { + + private Pipeline pipeline; + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewProjectEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewProjectEvent.java new file mode 100644 index 0000000..85ca121 --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/NewProjectEvent.java @@ -0,0 +1,19 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.entity.Project; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "newProject") +public class NewProjectEvent { + + private Project project; + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateDiscussionEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateDiscussionEvent.java new file mode 100644 index 0000000..b9961ea --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateDiscussionEvent.java @@ -0,0 +1,20 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "updateDiscussion") +public class UpdateDiscussionEvent { + + private Discussion oldDiscussion; + private Discussion newDiscussion; + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateMergeRequestEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateMergeRequestEvent.java new file mode 100644 index 0000000..c18d485 --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdateMergeRequestEvent.java @@ -0,0 +1,25 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.AssigneeChanged; +import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged; +import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "updateMergeRequest") +public class UpdateMergeRequestEvent { + + private MergeRequest oldMergeRequest; + private MergeRequest newMergeRequest; + + private AssigneeChanged assigneeChanged; + private ReviewerChanged reviewerChanged; + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdatePipelineEvent.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdatePipelineEvent.java new file mode 100644 index 0000000..e39cc1f --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/event/UpdatePipelineEvent.java @@ -0,0 +1,20 @@ +package dev.struchkov.bot.gitlab.context.domain.event; + +import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(staticName = "updatePipeline") +public class UpdatePipelineEvent { + + private Pipeline oldPipeline; + private Pipeline newPipeline; + +} diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/DiscussionHandler.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/DiscussionHandler.java new file mode 100644 index 0000000..8b31335 --- /dev/null +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/DiscussionHandler.java @@ -0,0 +1,265 @@ +package dev.struchkov.bot.gitlab.core.handler; + +import dev.struchkov.bot.gitlab.context.domain.PersonInformation; +import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; +import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion; +import dev.struchkov.bot.gitlab.context.domain.entity.Note; +import dev.struchkov.bot.gitlab.context.domain.event.NewDiscussionEvent; +import dev.struchkov.bot.gitlab.context.domain.event.UpdateDiscussionEvent; +import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentNotify; +import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel; +import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewNotify; +import dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadCloseNotify; +import dev.struchkov.bot.gitlab.context.service.AppSettingService; +import dev.struchkov.bot.gitlab.context.service.DiscussionService; +import dev.struchkov.bot.gitlab.context.service.NotifyService; +import dev.struchkov.haiti.utils.container.Pair; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.NOTIFY_WITH_CONTEXT; +import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY; +import static dev.struchkov.haiti.utils.Checker.checkNotNull; +import static dev.struchkov.haiti.utils.Checker.checkNull; +import static java.lang.Boolean.FALSE; +import static java.lang.Boolean.TRUE; + +@Component +@RequiredArgsConstructor +public class DiscussionHandler { + + protected static final Pattern PATTERN = Pattern.compile("@[\\w]+"); + + private final PersonInformation personInformation; + private final AppSettingService settingService; + private final DiscussionService discussionService; + + private final NotifyService notifyService; + + @EventListener + public void newDiscussionEvent(NewDiscussionEvent event) { + final Discussion discussion = event.getDiscussion(); + final List notes = discussion.getNotes(); + + if (isNeedNotifyNewNote(discussion)) { + notifyNewThread(discussion); + } else { + notes.forEach(note -> notifyAboutPersonalAnswer(discussion, note)); + } + } + + @EventListener + public void updateDiscussionHandle(UpdateDiscussionEvent event) { + final Discussion oldDiscussion = event.getOldDiscussion(); + final Discussion newDiscussion = event.getNewDiscussion(); + + if (oldDiscussion.isNotification()) { + final Map oldNoteMap = oldDiscussion + .getNotes().stream() + .collect(Collectors.toMap(Note::getId, n -> n)); + + // Пользователь участвовал в обсуждении + final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream() + .anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId())); + + final Note threadFirstNote = newDiscussion.getFirstNote(); + if (TRUE.equals(newDiscussion.getResolved())) { + notifyAboutCloseThread(threadFirstNote, oldNoteMap.get(threadFirstNote.getId()), newDiscussion.getLastNote()); + } + + for (Note newNote : newDiscussion.getNotes()) { + final Long newNoteId = newNote.getId(); + if (!oldNoteMap.containsKey(newNoteId)) { + if (userParticipatedInDiscussion) { + notifyAboutNewAnswer(newDiscussion, newNote); + } else { + notifyAboutPersonalAnswer(newDiscussion, newNote); + } + } + } + } + } + + /** + *

Уведомляет пользователя, если появился новый комментарий

+ */ + private void notifyNewThread(Discussion discussion) { + final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify(); + if (!WITHOUT_NOTIFY.equals(discussionLevel)) { + final Note firstNote = discussion.getFirstNote(); + + final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest(); + final DiscussionNewNotify.DiscussionNewNotifyBuilder messageBuilder = DiscussionNewNotify.builder() + .url(firstNote.getWebUrl()) + .threadId(discussion.getId()) + .mergeRequestName(mergeRequest.getTitle()) + .authorName(firstNote.getAuthor().getName()); + + if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) { + final List notes = discussion.getNotes(); + + messageBuilder + .discussionMessage(firstNote.getBody()); + + if (notes.size() > 1) { + for (int i = 1; i < notes.size(); i++) { + final Note note = notes.get(i); + messageBuilder.note( + new Pair<>(note.getAuthor().getName(), note.getBody()) + ); + } + } + } + + notifyService.send(messageBuilder.build()); + } + } + + private boolean isNeedNotifyNewNote(Discussion discussion) { + final Note firstNote = discussion.getFirstNote(); + final Long gitlabUserId = personInformation.getId(); + return firstNote.isResolvable() // Тип комментария требует решения (Задачи) + && gitlabUserId.equals(discussion.getResponsible().getId()) // Ответственный за дискуссию пользователь + && !gitlabUserId.equals(firstNote.getAuthor().getId()) // Создатель комментария не пользователь системы + && FALSE.equals(firstNote.getResolved()); // Комментарий не отмечен как решенный + } + + /** + * Уведомляет пользователя, если его никнейм упоминается в комментарии. + */ + private void notifyAboutPersonalAnswer(Discussion discussion, Note note) { + final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify(); + if (!WITHOUT_NOTIFY.equals(discussionLevel)) { + final Matcher matcher = PATTERN.matcher(note.getBody()); + final Set recipientsLogins = new HashSet<>(); + + while (matcher.find()) { + final String login = matcher.group(0).replace("@", ""); + recipientsLogins.add(login); + } + + if (recipientsLogins.contains(personInformation.getUsername())) { + final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder() + .threadId(discussion.getId()) + .mergeRequestName(discussion.getMergeRequest().getTitle()) + .url(note.getWebUrl()); + + if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) { + final Optional prevLastNote = discussion.getPrevLastNote(); + final Note firstNote = discussion.getFirstNote(); + + if (!firstNote.equals(note)) { + notifyBuilder.message(note.getBody()) + .authorName(note.getAuthor().getName()); + } + if (prevLastNote.isPresent()) { + final Note prevNote = prevLastNote.get(); + notifyBuilder.previousMessage(prevNote.getBody()); + notifyBuilder.previousAuthor(prevNote.getAuthor().getName()); + } + + notifyBuilder + .discussionMessage(firstNote.getBody()) + .discussionAuthor(firstNote.getAuthor().getName()); + } + + notifyService.send(notifyBuilder.build()); + } + } + } + + private void notifyAboutNewAnswer(Discussion discussion, Note note) { + final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify(); + + if (!WITHOUT_NOTIFY.equals(discussionLevel) + && !personInformation.getId().equals(note.getAuthor().getId())) { + final Note firstNote = discussion.getFirstNote(); + + final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder() + .threadId(discussion.getId()) + .url(note.getWebUrl()) + .mergeRequestName(discussion.getMergeRequest().getTitle()); + + if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) { + final Optional prevLastNote = discussion.getPrevLastNote(); + + if (prevLastNote.isPresent()) { + final Note prevNote = prevLastNote.get(); + notifyBuilder.previousMessage(prevNote.getBody()); + notifyBuilder.previousAuthor(prevNote.getAuthor().getName()); + } + + notifyBuilder + .discussionMessage(firstNote.getBody()) + .discussionAuthor(firstNote.getAuthor().getName()) + .message(note.getBody()) + .authorName(note.getAuthor().getName()); + } + + notifyService.send(notifyBuilder.build()); + } + } + + private void notifyAboutCloseThread(Note newNote, Note oldNote, Optional lastNote) { + final DiscussionLevel level = settingService.getLevelDiscussionNotify(); + if (!WITHOUT_NOTIFY.equals(level)) { + + if (isResolved(newNote, oldNote)) { + final MergeRequestForDiscussion mergeRequest = oldNote.getDiscussion().getMergeRequest(); + + final List discussions = discussionService.getAllByMergeRequestId(mergeRequest.getId()) + .stream() + .filter(discussion -> Objects.nonNull(discussion.getResponsible())) + .toList(); + final long allYouTasks = discussions.stream() + .filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId())) + .count(); + final long resolvedYouTask = discussions.stream() + .filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved()) + .count(); + + final ThreadCloseNotify.ThreadCloseNotifyBuilder notifyBuilder = ThreadCloseNotify.builder() + .mergeRequestName(mergeRequest.getTitle()) + .url(oldNote.getWebUrl()) + .personTasks(allYouTasks) + .personResolvedTasks(resolvedYouTask); + + if (NOTIFY_WITH_CONTEXT.equals(level)) { + notifyBuilder + .authorName(oldNote.getAuthor().getName()) + .messageTask(oldNote.getBody()); + + + lastNote.ifPresent( + note -> { + notifyBuilder.authorLastNote(note.getAuthor().getName()); + notifyBuilder.messageLastNote(note.getBody()); + } + ); + } + + notifyService.send(notifyBuilder.build()); + } + + } + } + + private boolean isResolved(Note note, Note oldNote) { + return checkNull(oldNote.getResolvedBy()) // В старом комментарии не было отметки о решении + && checkNotNull(note.getResolvedBy()) // А в новом есть отметка + && personInformation.getId().equals(oldNote.getAuthor().getId()) // и решающий не является пользователем бота + && !note.getResolvedBy().getId().equals(oldNote.getAuthor().getId()); // и решающий не является автором треда + } + +} diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/MergeRequestHandler.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/MergeRequestHandler.java new file mode 100644 index 0000000..ded4587 --- /dev/null +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/MergeRequestHandler.java @@ -0,0 +1,273 @@ +package dev.struchkov.bot.gitlab.core.handler; + +import dev.struchkov.bot.gitlab.context.domain.AssigneeChanged; +import dev.struchkov.bot.gitlab.context.domain.MergeRequestState; +import dev.struchkov.bot.gitlab.context.domain.PersonInformation; +import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged; +import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; +import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; +import dev.struchkov.bot.gitlab.context.domain.entity.Person; +import dev.struchkov.bot.gitlab.context.domain.entity.Project; +import dev.struchkov.bot.gitlab.context.domain.event.NewMergeRequestEvent; +import dev.struchkov.bot.gitlab.context.domain.event.UpdateMergeRequestEvent; +import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictMrNotify; +import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrNotify; +import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForAssignee; +import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForReview; +import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusMrNotify; +import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdateMrNotify; +import dev.struchkov.bot.gitlab.context.service.DiscussionService; +import dev.struchkov.bot.gitlab.context.service.NotifyService; +import dev.struchkov.bot.gitlab.context.service.ProjectService; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +import static dev.struchkov.haiti.utils.Checker.checkNotNull; +import static java.lang.Boolean.TRUE; + +@Component +@RequiredArgsConstructor +public class MergeRequestHandler { + + private final NotifyService notifyService; + + private final PersonInformation personInformation; + private final ProjectService projectService; + private final DiscussionService discussionService; + + @EventListener + public void newMrHandle(NewMergeRequestEvent event) { + final MergeRequest mergeRequest = event.getMergeRequest(); + final String projectName = projectService.getByIdOrThrow(mergeRequest.getProjectId()).getName(); + + final boolean userReviewer = mergeRequest.isUserReviewer(); + final boolean userAssignee = mergeRequest.isUserAssignee(); + if (userReviewer || userAssignee) { + if (!mergeRequest.isConflict()) { + + if (userReviewer) sendNotifyNewMrReview(mergeRequest, projectName); + if (userAssignee) sendNotifyNewAssignee(mergeRequest, projectName, null); + } + } + } + + @EventListener + public void updateMrHandle(UpdateMergeRequestEvent event) { + final MergeRequest oldMergeRequest = event.getOldMergeRequest(); + final MergeRequest newMergeRequest = event.getNewMergeRequest(); + final AssigneeChanged assigneeChanged = event.getAssigneeChanged(); + final ReviewerChanged reviewerChanged = event.getReviewerChanged(); + + final boolean isChangedMr = !oldMergeRequest.getUpdatedDate().equals(newMergeRequest.getUpdatedDate()) || oldMergeRequest.isConflict() != newMergeRequest.isConflict(); + final boolean isChangedLinkedEntity = reviewerChanged.isChanged() || assigneeChanged.isChanged(); + final boolean isMilestone = !Objects.equals(oldMergeRequest.getMilestone(), newMergeRequest.getMilestone()); + + if (isChangedMr || isChangedLinkedEntity || isMilestone) { + + if (oldMergeRequest.isNotification()) { + final Project project = projectService.getByIdOrThrow(newMergeRequest.getProjectId()); + + if (isChangedMr) { + notifyAboutStatus(oldMergeRequest, newMergeRequest, project); + notifyAboutNewConflict(oldMergeRequest, newMergeRequest, project); + notifyAboutResolveConflict(oldMergeRequest, newMergeRequest, project); + notifyAboutUpdate(oldMergeRequest, newMergeRequest, project); + } + + if (isChangedLinkedEntity) { + notifyReviewer(reviewerChanged, newMergeRequest, project); + notifyAssignee(assigneeChanged, oldMergeRequest, newMergeRequest, project); + } + } + + } + } + + private void sendNotifyNewMrReview(MergeRequest mergeRequest, String projectName) { + final NewMrForReview.NewMrForReviewBuilder builder = NewMrForReview.builder() + .mrId(mergeRequest.getId()) + .projectName(projectName) + .labels(mergeRequest.getLabels()) + .author(mergeRequest.getAuthor().getName()) + .milestone(mergeRequest.getMilestone()) + .description(mergeRequest.getDescription()) + .title(mergeRequest.getTitle()) + .url(mergeRequest.getWebUrl()) + .targetBranch(mergeRequest.getTargetBranch()) + .sourceBranch(mergeRequest.getSourceBranch()); + + getAssignee(mergeRequest) + .map(Person::getName) + .ifPresent(builder::assignee); + + notifyService.send(builder.build()); + } + + private void sendNotifyNewAssignee(MergeRequest mergeRequest, String projectName, String oldAssigneeName) { + final NewMrForAssignee.NewMrForAssigneeBuilder builder = NewMrForAssignee.builder() + .mrId(mergeRequest.getId()) + .projectName(projectName) + .labels(mergeRequest.getLabels()) + .author(mergeRequest.getAuthor().getName()) + .description(mergeRequest.getDescription()) + .milestone(mergeRequest.getMilestone()) + .title(mergeRequest.getTitle()) + .url(mergeRequest.getWebUrl()) + .targetBranch(mergeRequest.getTargetBranch()) + .sourceBranch(mergeRequest.getSourceBranch()) + .milestone(mergeRequest.getMilestone()) + .reviewers(mergeRequest.getReviewers().stream().map(Person::getName).toList()); + + if (checkNotNull(oldAssigneeName)) { + builder.oldAssigneeName(oldAssigneeName); + + getAssignee(mergeRequest) + .map(Person::getName) + .ifPresent(builder::newAssigneeName); + } + + notifyService.send(builder.build()); + } + + private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + final Long botUserGitlabId = personInformation.getId(); + if ( + !botUserGitlabId.equals(mergeRequest.getAuthor().getId()) // Автор MR не пользователь приложения + && !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) // Изменилась дата последнего коммита + && !mergeRequest.isConflict() // MR не находится в состоянии конфликта + && !botUserGitlabId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан НЕ пользователем бота + ) { + long allTask = 0; + long resolvedTask = 0; + long allYouTasks = 0; + long resolvedYouTask = 0; + + final List discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId()); + for (Discussion discussion : discussions) { + if (checkNotNull(discussion.getResponsible())) { + final boolean isBotUserAuthorDiscussion = botUserGitlabId.equals(discussion.getFirstNote().getAuthor().getId()); + allTask += 1; + if (isBotUserAuthorDiscussion) { + allYouTasks += 1; + } + if (TRUE.equals(discussion.getResolved())) { + resolvedTask += 1; + if (isBotUserAuthorDiscussion) { + resolvedYouTask += 1; + } + } + } + } + + final UpdateMrNotify.UpdateMrNotifyBuilder notifyBuilder = UpdateMrNotify.builder() + .mrId(oldMergeRequest.getId()) + .author(oldMergeRequest.getAuthor().getName()) + .name(oldMergeRequest.getTitle()) + .projectName(project.getName()) + .url(oldMergeRequest.getWebUrl()) + .allTasks(allTask) + .milestone(mergeRequest.getMilestone()) + .allResolvedTasks(resolvedTask) + .personTasks(allYouTasks) + .personResolvedTasks(resolvedYouTask); + + if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) { + notifyBuilder.comment("The conflict has been resolved"); + } + + notifyService.send(notifyBuilder.build()); + } + } + + protected void notifyAboutNewConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + final Long gitlabUserId = personInformation.getId(); + if ( + !oldMergeRequest.isConflict() // У старого MR не было конфликта + && mergeRequest.isConflict() // А у нового есть + && gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота + ) { + notifyService.send( + ConflictMrNotify.builder() + .mrId(oldMergeRequest.getId()) + .sourceBranch(oldMergeRequest.getSourceBranch()) + .name(mergeRequest.getTitle()) + .url(mergeRequest.getWebUrl()) + .projectKey(project.getName()) + .milestone(mergeRequest.getMilestone()) + .build() + ); + } + } + + private void notifyAboutResolveConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + final Long gitlabUserId = personInformation.getId(); + if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) { + // проверяем даты коммитов, так как при пуше в target ветку MR у которого есть конфликт, конфликт на время пропадает. Судя по всему GitLab после пуша заново проверяет вероятность конфликта. Чаще всего конфликт никуда не девается. + if (oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit())) { + mergeRequest.setConflict(true); + } else { + if (gitlabUserId.equals(oldMergeRequest.getAuthor().getId())) { + notifyService.send( + ConflictResolveMrNotify.builder() + .mrId(oldMergeRequest.getId()) + .sourceBranch(oldMergeRequest.getSourceBranch()) + .name(mergeRequest.getTitle()) + .url(mergeRequest.getWebUrl()) + .projectKey(project.getName()) + .milestone(mergeRequest.getMilestone()) + .build() + ); + } + } + } + } + + protected void notifyAboutStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) { + final MergeRequestState oldStatus = oldMergeRequest.getState(); + final MergeRequestState newStatus = newMergeRequest.getState(); + final Long gitlabUserId = personInformation.getId(); + if ( + !oldStatus.equals(newStatus) // статус изменился + && gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота + ) { + notifyService.send( + StatusMrNotify.builder() + .mrId(oldMergeRequest.getId()) + .name(newMergeRequest.getTitle()) + .url(oldMergeRequest.getWebUrl()) + .projectName(project.getName()) + .newStatus(newStatus) + .oldStatus(oldStatus) + .milestone(newMergeRequest.getMilestone()) + .build() + ); + } + } + + private Optional getAssignee(MergeRequest mergeRequest) { + return Optional.ofNullable(mergeRequest.getAssignee()); + } + + //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление + + private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + switch (assigneeChanged) { + case BECOME -> + sendNotifyNewAssignee(mergeRequest, project.getName(), getAssignee(oldMergeRequest).map(Person::getName).orElse(null)); + } + } + //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера + + private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) { + switch (reviewerChanged) { + case BECOME -> sendNotifyNewMrReview(mergeRequest, project.getName()); + } + } + + +} diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/PipelineHandler.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/PipelineHandler.java new file mode 100644 index 0000000..0d6af53 --- /dev/null +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/PipelineHandler.java @@ -0,0 +1,59 @@ +package dev.struchkov.bot.gitlab.core.handler; + +import dev.struchkov.bot.gitlab.context.domain.PersonInformation; +import dev.struchkov.bot.gitlab.context.domain.PipelineStatus; +import dev.struchkov.bot.gitlab.context.domain.entity.Person; +import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline; +import dev.struchkov.bot.gitlab.context.domain.event.NewPipelineEvent; +import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelineNotify; +import dev.struchkov.bot.gitlab.context.service.NotifyService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.Set; + +import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CANCELED; +import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.FAILED; +import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SKIPPED; +import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS; +import static dev.struchkov.haiti.utils.Checker.checkNotNull; + +@Component +@RequiredArgsConstructor +public class PipelineHandler { + + // Статусы пайплайнов, о которых нужно уведомить + private static final Set notificationStatus = Set.of(FAILED, SUCCESS, CANCELED, SKIPPED); + + private final PersonInformation personInformation; + private final NotifyService notifyService; + + @EventListener + public void newPipelineHandle(NewPipelineEvent event) { + final Pipeline pipeline = event.getPipeline(); + if (isNeedNotifyNewPipeline(pipeline)) { + notifyService.send( + PipelineNotify.builder() + .projectId(pipeline.getProjectId()) + .newStatus(pipeline.getStatus()) + .pipelineId(pipeline.getId()) + .refName(pipeline.getRef()) + .webUrl(pipeline.getWebUrl()) + .oldStatus(PipelineStatus.NULL) + .build() + ); + } + } + + private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) { + final Person personPipelineCreator = pipeline.getPerson(); + return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления + && checkNotNull(personPipelineCreator) // Создатель пайплайна не null + && personInformation.getId().equals(personPipelineCreator.getId()) // Пользователь приложения является инициатором пайплайна + && LocalDateTime.now().minusDays(1).isBefore(pipeline.getCreated()); // Пайплан был создан не более 24 часов назад + } + +} diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/ProjectHandler.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/ProjectHandler.java new file mode 100644 index 0000000..4f8c858 --- /dev/null +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/handler/ProjectHandler.java @@ -0,0 +1,36 @@ +package dev.struchkov.bot.gitlab.core.handler; + +import dev.struchkov.bot.gitlab.context.domain.entity.Project; +import dev.struchkov.bot.gitlab.context.domain.event.NewProjectEvent; +import dev.struchkov.bot.gitlab.context.domain.notify.project.NewProjectNotify; +import dev.struchkov.bot.gitlab.context.service.NotifyService; +import dev.struchkov.bot.gitlab.context.service.PersonService; +import lombok.RequiredArgsConstructor; +import org.springframework.context.event.EventListener; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class ProjectHandler { + + private final NotifyService notifyService; + private final PersonService personService; + + @EventListener + public void handleNewProjectEvent(NewProjectEvent event) { + final Project newProject = event.getProject(); + final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName(); + notifyService.send( + NewProjectNotify.builder() + .projectId(newProject.getId()) + .projectDescription(newProject.getDescription()) + .projectName(newProject.getName()) + .projectUrl(newProject.getWebUrl()) + .sshUrlToRepo(newProject.getSshUrlToRepo()) + .httpUrlToRepo(newProject.getHttpUrlToRepo()) + .authorName(authorName) + .build() + ); + } + +} diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/DiscussionServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/DiscussionServiceImpl.java index b004d63..7a63b82 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/DiscussionServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/DiscussionServiceImpl.java @@ -1,44 +1,31 @@ package dev.struchkov.bot.gitlab.core.service; import dev.struchkov.bot.gitlab.context.domain.ExistContainer; -import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion; import dev.struchkov.bot.gitlab.context.domain.entity.Note; import dev.struchkov.bot.gitlab.context.domain.entity.Person; -import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentNotify; import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel; -import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewNotify; -import dev.struchkov.bot.gitlab.context.domain.notify.task.ThreadCloseNotify; import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository; import dev.struchkov.bot.gitlab.context.service.AppSettingService; import dev.struchkov.bot.gitlab.context.service.DiscussionService; -import dev.struchkov.bot.gitlab.context.service.NotifyService; -import dev.struchkov.haiti.utils.container.Pair; import dev.struchkov.sdk.gitlab.core.GitlabSdkManager; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.HashSet; import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import java.util.stream.Collectors; -import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.NOTIFY_WITH_CONTEXT; +import static dev.struchkov.bot.gitlab.context.domain.event.NewDiscussionEvent.newDiscussion; +import static dev.struchkov.bot.gitlab.context.domain.event.UpdateDiscussionEvent.updateDiscussion; import static dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel.WITHOUT_NOTIFY; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; import static dev.struchkov.haiti.utils.Checker.checkNotNull; -import static dev.struchkov.haiti.utils.Checker.checkNull; -import static java.lang.Boolean.FALSE; -import static java.lang.Boolean.TRUE; /** * Сервис для работы с дискуссиями. @@ -50,31 +37,21 @@ import static java.lang.Boolean.TRUE; @RequiredArgsConstructor public class DiscussionServiceImpl implements DiscussionService { - protected static final Pattern PATTERN = Pattern.compile("@[\\w]+"); - private final DiscussionRepository repository; - private final NotifyService notifyService; private final AppSettingService settingService; - - private final PersonInformation personInformation; - private final GitlabSdkManager gitlabSdkManager; + private final ApplicationEventPublisher eventPublisher; @Override @Transactional public Discussion create(@NonNull Discussion discussion) { - final List notes = discussion.getNotes(); final DiscussionLevel levelDiscussionNotify = settingService.getLevelDiscussionNotify(); if (!WITHOUT_NOTIFY.equals(levelDiscussionNotify)) { discussion.setNotification(true); - if (isNeedNotifyNewNote(discussion)) { - notifyNewThread(discussion); - } else { - notes.forEach(note -> notifyAboutPersonalAnswer(discussion, note)); - } + eventPublisher.publishEvent(newDiscussion(discussion)); } else { discussion.setNotification(false); } @@ -116,23 +93,11 @@ public class DiscussionServiceImpl implements DiscussionService { .allMatch(note -> note.isResolvable() && note.getResolved()); discussion.setResolved(resolved); - if (oldDiscussion.isNotification()) { - notifyUpdateNote(oldDiscussion, discussion); - } - + eventPublisher.publishEvent(updateDiscussion(oldDiscussion, discussion)); return repository.save(discussion); } - private boolean isNeedNotifyNewNote(Discussion discussion) { - final Note firstNote = discussion.getFirstNote(); - final Long gitlabUserId = personInformation.getId(); - return firstNote.isResolvable() // Тип комментария требует решения (Задачи) - && gitlabUserId.equals(discussion.getResponsible().getId()) // Ответственный за дискуссию пользователь - && !gitlabUserId.equals(firstNote.getAuthor().getId()) // Создатель комментария не пользователь системы - && FALSE.equals(firstNote.getResolved()); // Комментарий не отмечен как решенный - } - @Override public List updateAll(@NonNull List discussions) { return discussions.stream() @@ -140,85 +105,6 @@ public class DiscussionServiceImpl implements DiscussionService { .collect(Collectors.toList()); } - private void notifyUpdateNote(Discussion oldDiscussion, Discussion discussion) { - final Map oldNoteMap = oldDiscussion - .getNotes().stream() - .collect(Collectors.toMap(Note::getId, n -> n)); - - // Пользователь участвовал в обсуждении - final boolean userParticipatedInDiscussion = oldDiscussion.getNotes().stream() - .anyMatch(note -> personInformation.getId().equals(note.getAuthor().getId())); - - final Note threadFirstNote = discussion.getFirstNote(); - if (TRUE.equals(discussion.getResolved())) { - notifyAboutCloseThread(threadFirstNote, oldNoteMap.get(threadFirstNote.getId()), discussion.getLastNote()); - } - - for (Note newNote : discussion.getNotes()) { - final Long newNoteId = newNote.getId(); - if (!oldNoteMap.containsKey(newNoteId)) { - if (userParticipatedInDiscussion) { - notifyAboutNewAnswer(discussion, newNote); - } else { - notifyAboutPersonalAnswer(discussion, newNote); - } - } - } - - } - - private void notifyAboutCloseThread(Note newNote, Note oldNote, Optional lastNote) { - final DiscussionLevel level = settingService.getLevelDiscussionNotify(); - if (!WITHOUT_NOTIFY.equals(level)) { - - if (isResolved(newNote, oldNote)) { - final MergeRequestForDiscussion mergeRequest = oldNote.getDiscussion().getMergeRequest(); - - final List discussions = getAllByMergeRequestId(mergeRequest.getId()) - .stream() - .filter(discussion -> Objects.nonNull(discussion.getResponsible())) - .toList(); - final long allYouTasks = discussions.stream() - .filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId())) - .count(); - final long resolvedYouTask = discussions.stream() - .filter(discussion -> personInformation.getId().equals(discussion.getFirstNote().getAuthor().getId()) && discussion.getResolved()) - .count(); - - final ThreadCloseNotify.ThreadCloseNotifyBuilder notifyBuilder = ThreadCloseNotify.builder() - .mergeRequestName(mergeRequest.getTitle()) - .url(oldNote.getWebUrl()) - .personTasks(allYouTasks) - .personResolvedTasks(resolvedYouTask); - - if (NOTIFY_WITH_CONTEXT.equals(level)) { - notifyBuilder - .authorName(oldNote.getAuthor().getName()) - .messageTask(oldNote.getBody()); - - - lastNote.ifPresent( - note -> { - notifyBuilder.authorLastNote(note.getAuthor().getName()); - notifyBuilder.messageLastNote(note.getBody()); - } - ); - } - - notifyService.send(notifyBuilder.build()); - } - - } - } - - private boolean isResolved(Note note, Note oldNote) { - return checkNull(oldNote.getResolvedBy()) // В старом комментарии не было отметки о решении - && checkNotNull(note.getResolvedBy()) // А в новом есть отметка - && personInformation.getId().equals(oldNote.getAuthor().getId()) // и решающий не является пользователем бота - && !note.getResolvedBy().getId().equals(oldNote.getAuthor().getId()); // и решающий не является автором треда - } - - @Override public void answer(@NonNull String discussionId, @NonNull String text) { final Discussion discussion = repository.findById(discussionId) @@ -285,115 +171,4 @@ public class DiscussionServiceImpl implements DiscussionService { repository.notification(enable, discussionId); } - private void notifyAboutNewAnswer(Discussion discussion, Note note) { - final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify(); - - if (!WITHOUT_NOTIFY.equals(discussionLevel) - && !personInformation.getId().equals(note.getAuthor().getId())) { - final Note firstNote = discussion.getFirstNote(); - - final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder() - .threadId(discussion.getId()) - .url(note.getWebUrl()) - .mergeRequestName(discussion.getMergeRequest().getTitle()); - - if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) { - final Optional prevLastNote = discussion.getPrevLastNote(); - - if (prevLastNote.isPresent()) { - final Note prevNote = prevLastNote.get(); - notifyBuilder.previousMessage(prevNote.getBody()); - notifyBuilder.previousAuthor(prevNote.getAuthor().getName()); - } - - notifyBuilder - .discussionMessage(firstNote.getBody()) - .discussionAuthor(firstNote.getAuthor().getName()) - .message(note.getBody()) - .authorName(note.getAuthor().getName()); - } - - notifyService.send(notifyBuilder.build()); - } - } - - /** - * Уведомляет пользователя, если его никнейм упоминается в комментарии. - */ - private void notifyAboutPersonalAnswer(Discussion discussion, Note note) { - final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify(); - if (!WITHOUT_NOTIFY.equals(discussionLevel)) { - final Matcher matcher = PATTERN.matcher(note.getBody()); - final Set recipientsLogins = new HashSet<>(); - - while (matcher.find()) { - final String login = matcher.group(0).replace("@", ""); - recipientsLogins.add(login); - } - - if (recipientsLogins.contains(personInformation.getUsername())) { - final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder() - .threadId(discussion.getId()) - .mergeRequestName(discussion.getMergeRequest().getTitle()) - .url(note.getWebUrl()); - - if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) { - final Optional prevLastNote = discussion.getPrevLastNote(); - final Note firstNote = discussion.getFirstNote(); - - if (!firstNote.equals(note)) { - notifyBuilder.message(note.getBody()) - .authorName(note.getAuthor().getName()); - } - if (prevLastNote.isPresent()) { - final Note prevNote = prevLastNote.get(); - notifyBuilder.previousMessage(prevNote.getBody()); - notifyBuilder.previousAuthor(prevNote.getAuthor().getName()); - } - - notifyBuilder - .discussionMessage(firstNote.getBody()) - .discussionAuthor(firstNote.getAuthor().getName()); - } - - notifyService.send(notifyBuilder.build()); - } - } - } - - /** - *

Уведомляет пользователя, если появился новый комментарий

- */ - private void notifyNewThread(Discussion discussion) { - final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify(); - if (!WITHOUT_NOTIFY.equals(discussionLevel)) { - final Note firstNote = discussion.getFirstNote(); - - final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest(); - final DiscussionNewNotify.DiscussionNewNotifyBuilder messageBuilder = DiscussionNewNotify.builder() - .url(firstNote.getWebUrl()) - .threadId(discussion.getId()) - .mergeRequestName(mergeRequest.getTitle()) - .authorName(firstNote.getAuthor().getName()); - - if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) { - final List notes = discussion.getNotes(); - - messageBuilder - .discussionMessage(firstNote.getBody()); - - if (notes.size() > 1) { - for (int i = 1; i < notes.size(); i++) { - final Note note = notes.get(i); - messageBuilder.note( - new Pair<>(note.getAuthor().getName(), note.getBody()) - ); - } - } - } - - notifyService.send(messageBuilder.build()); - } - } - } diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/MergeRequestsServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/MergeRequestsServiceImpl.java index 7f9aa5d..e9304c8 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/MergeRequestsServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/MergeRequestsServiceImpl.java @@ -6,40 +6,29 @@ import dev.struchkov.bot.gitlab.context.domain.IdAndStatusPr; import dev.struchkov.bot.gitlab.context.domain.MergeRequestState; import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.ReviewerChanged; -import dev.struchkov.bot.gitlab.context.domain.entity.Discussion; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequestForDiscussion; import dev.struchkov.bot.gitlab.context.domain.entity.Person; -import dev.struchkov.bot.gitlab.context.domain.entity.Project; -import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictMrNotify; -import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrNotify; -import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForAssignee; -import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewMrForReview; -import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusMrNotify; -import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdateMrNotify; import dev.struchkov.bot.gitlab.context.repository.MergeRequestRepository; -import dev.struchkov.bot.gitlab.context.service.DiscussionService; import dev.struchkov.bot.gitlab.context.service.MergeRequestsService; -import dev.struchkov.bot.gitlab.context.service.NotifyService; -import dev.struchkov.bot.gitlab.context.service.ProjectService; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.List; -import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.CLOSED; import static dev.struchkov.bot.gitlab.context.domain.MergeRequestState.MERGED; +import static dev.struchkov.bot.gitlab.context.domain.event.NewMergeRequestEvent.newMergeRequest; +import static dev.struchkov.bot.gitlab.context.domain.event.UpdateMergeRequestEvent.updateMergeRequest; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; import static dev.struchkov.haiti.utils.Checker.checkNotEmpty; -import static dev.struchkov.haiti.utils.Checker.checkNotNull; -import static java.lang.Boolean.TRUE; @Slf4j @Service @@ -48,11 +37,9 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { public static final Set DELETE_STATES = Set.of(MERGED, CLOSED); - private final MergeRequestRepository repository; + private final ApplicationEventPublisher eventPublisher; - private final NotifyService notifyService; - private final ProjectService projectService; - private final DiscussionService discussionService; + private final MergeRequestRepository repository; private final PersonInformation personInformation; @@ -69,13 +56,7 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { final MergeRequest savedMergeRequest = repository.save(mergeRequest); - if (botUserReviewer || botUserAssignee) { - if (!mergeRequest.isConflict()) { - final String projectName = projectService.getByIdOrThrow(savedMergeRequest.getProjectId()).getName(); - if (botUserReviewer) sendNotifyNewMrReview(savedMergeRequest, projectName); - if (botUserAssignee) sendNotifyNewAssignee(mergeRequest, projectName, null); - } - } + eventPublisher.publishEvent(newMergeRequest(savedMergeRequest)); return savedMergeRequest; } @@ -117,62 +98,14 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { return false; } - private void sendNotifyNewMrReview(MergeRequest mergeRequest, String projectName) { - final NewMrForReview.NewMrForReviewBuilder builder = NewMrForReview.builder() - .mrId(mergeRequest.getId()) - .projectName(projectName) - .labels(mergeRequest.getLabels()) - .author(mergeRequest.getAuthor().getName()) - .milestone(mergeRequest.getMilestone()) - .description(mergeRequest.getDescription()) - .title(mergeRequest.getTitle()) - .url(mergeRequest.getWebUrl()) - .targetBranch(mergeRequest.getTargetBranch()) - .sourceBranch(mergeRequest.getSourceBranch()); - - getAssignee(mergeRequest) - .map(Person::getName) - .ifPresent(builder::assignee); - - notifyService.send(builder.build()); - } - - private Optional getAssignee(MergeRequest mergeRequest) { - return Optional.ofNullable(mergeRequest.getAssignee()); - } - - private void sendNotifyNewAssignee(MergeRequest mergeRequest, String projectName, String oldAssigneeName) { - final NewMrForAssignee.NewMrForAssigneeBuilder builder = NewMrForAssignee.builder() - .mrId(mergeRequest.getId()) - .projectName(projectName) - .labels(mergeRequest.getLabels()) - .author(mergeRequest.getAuthor().getName()) - .description(mergeRequest.getDescription()) - .milestone(mergeRequest.getMilestone()) - .title(mergeRequest.getTitle()) - .url(mergeRequest.getWebUrl()) - .targetBranch(mergeRequest.getTargetBranch()) - .sourceBranch(mergeRequest.getSourceBranch()) - .milestone(mergeRequest.getMilestone()) - .reviewers(mergeRequest.getReviewers().stream().map(Person::getName).toList()); - - if (checkNotNull(oldAssigneeName)) { - builder.oldAssigneeName(oldAssigneeName); - - getAssignee(mergeRequest) - .map(Person::getName) - .ifPresent(builder::newAssigneeName); - } - - notifyService.send(builder.build()); - } - @Override @Transactional public MergeRequest update(@NonNull MergeRequest mergeRequest) { final MergeRequest oldMergeRequest = repository.findById(mergeRequest.getId()) .orElseThrow(notFoundException("MergeRequest не найден")); + final MergeRequest cloneOldMergeRequest = oldMergeRequest.toBuilder().build(); + mergeRequest.setNotification(oldMergeRequest.isNotification()); final Long gitlabUserId = personInformation.getId(); @@ -182,49 +115,13 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { mergeRequest.setUserAssignee(assigneeChanged.getNewStatus(oldMergeRequest.isUserAssignee())); mergeRequest.setUserReviewer(reviewerChanged.getNewStatus(oldMergeRequest.isUserReviewer())); - final boolean isChangedMr = !oldMergeRequest.getUpdatedDate().equals(mergeRequest.getUpdatedDate()) || oldMergeRequest.isConflict() != mergeRequest.isConflict(); - final boolean isChangedLinkedEntity = reviewerChanged.isChanged() || assigneeChanged.isChanged(); - final boolean isMilestone = !Objects.equals(oldMergeRequest.getMilestone(), mergeRequest.getMilestone()); + eventPublisher.publishEvent( + updateMergeRequest(cloneOldMergeRequest, mergeRequest, assigneeChanged, reviewerChanged) + ); - if (isChangedMr || isChangedLinkedEntity || isMilestone) { - - if (oldMergeRequest.isNotification()) { - final Project project = projectService.getByIdOrThrow(mergeRequest.getProjectId()); - - if (isChangedMr) { - notifyAboutStatus(oldMergeRequest, mergeRequest, project); - notifyAboutNewConflict(oldMergeRequest, mergeRequest, project); - notifyAboutResolveConflict(oldMergeRequest, mergeRequest, project); - notifyAboutUpdate(oldMergeRequest, mergeRequest, project); - } - - if (isChangedLinkedEntity) { - notifyReviewer(reviewerChanged, mergeRequest, project); - notifyAssignee(assigneeChanged, oldMergeRequest, mergeRequest, project); - } - } - - return repository.save(mergeRequest); - } - - return oldMergeRequest; + return repository.save(mergeRequest); } - //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление - - private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { - switch (assigneeChanged) { - case BECOME -> - sendNotifyNewAssignee(mergeRequest, project.getName(), getAssignee(oldMergeRequest).map(Person::getName).orElse(null)); - } - } - //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление ревьювера - - private void notifyReviewer(ReviewerChanged reviewerChanged, MergeRequest mergeRequest, Project project) { - switch (reviewerChanged) { - case BECOME -> sendNotifyNewMrReview(mergeRequest, project.getName()); - } - } @Override @Transactional @@ -295,119 +192,8 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { repository.notificationByProjectId(enable, projectIds); } - private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { - final Long botUserGitlabId = personInformation.getId(); - if ( - !botUserGitlabId.equals(mergeRequest.getAuthor().getId()) // Автор MR не пользователь приложения - && !oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit()) // Изменилась дата последнего коммита - && !mergeRequest.isConflict() // MR не находится в состоянии конфликта - && !botUserGitlabId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан НЕ пользователем бота - ) { - long allTask = 0; - long resolvedTask = 0; - long allYouTasks = 0; - long resolvedYouTask = 0; - - final List discussions = discussionService.getAllByMergeRequestId(oldMergeRequest.getId()); - for (Discussion discussion : discussions) { - if (checkNotNull(discussion.getResponsible())) { - final boolean isBotUserAuthorDiscussion = botUserGitlabId.equals(discussion.getFirstNote().getAuthor().getId()); - allTask += 1; - if (isBotUserAuthorDiscussion) { - allYouTasks += 1; - } - if (TRUE.equals(discussion.getResolved())) { - resolvedTask += 1; - if (isBotUserAuthorDiscussion) { - resolvedYouTask += 1; - } - } - } - } - - final UpdateMrNotify.UpdateMrNotifyBuilder notifyBuilder = UpdateMrNotify.builder() - .mrId(oldMergeRequest.getId()) - .author(oldMergeRequest.getAuthor().getName()) - .name(oldMergeRequest.getTitle()) - .projectName(project.getName()) - .url(oldMergeRequest.getWebUrl()) - .allTasks(allTask) - .milestone(mergeRequest.getMilestone()) - .allResolvedTasks(resolvedTask) - .personTasks(allYouTasks) - .personResolvedTasks(resolvedYouTask); - - if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) { - notifyBuilder.comment("The conflict has been resolved"); - } - - notifyService.send(notifyBuilder.build()); - } - } - - protected void notifyAboutNewConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { - final Long gitlabUserId = personInformation.getId(); - if ( - !oldMergeRequest.isConflict() // У старого MR не было конфликта - && mergeRequest.isConflict() // А у нового есть - && gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // и MR создан пользователем бота - ) { - notifyService.send( - ConflictMrNotify.builder() - .mrId(oldMergeRequest.getId()) - .sourceBranch(oldMergeRequest.getSourceBranch()) - .name(mergeRequest.getTitle()) - .url(mergeRequest.getWebUrl()) - .projectKey(project.getName()) - .milestone(mergeRequest.getMilestone()) - .build() - ); - } - } - - private void notifyAboutResolveConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { - final Long gitlabUserId = personInformation.getId(); - if (oldMergeRequest.isConflict() && !mergeRequest.isConflict()) { - // проверяем даты коммитов, так как при пуше в target ветку MR у которого есть конфликт, конфликт на время пропадает. Судя по всему GitLab после пуша заново проверяет вероятность конфликта. Чаще всего конфликт никуда не девается. - if (oldMergeRequest.getDateLastCommit().equals(mergeRequest.getDateLastCommit())) { - mergeRequest.setConflict(true); - } else { - if (gitlabUserId.equals(oldMergeRequest.getAuthor().getId())) { - notifyService.send( - ConflictResolveMrNotify.builder() - .mrId(oldMergeRequest.getId()) - .sourceBranch(oldMergeRequest.getSourceBranch()) - .name(mergeRequest.getTitle()) - .url(mergeRequest.getWebUrl()) - .projectKey(project.getName()) - .milestone(mergeRequest.getMilestone()) - .build() - ); - } - } - } - } - - protected void notifyAboutStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) { - final MergeRequestState oldStatus = oldMergeRequest.getState(); - final MergeRequestState newStatus = newMergeRequest.getState(); - final Long gitlabUserId = personInformation.getId(); - if ( - !oldStatus.equals(newStatus) // статус изменился - && gitlabUserId.equals(oldMergeRequest.getAuthor().getId()) // создатель MR является пользователем бота - ) { - notifyService.send( - StatusMrNotify.builder() - .mrId(oldMergeRequest.getId()) - .name(newMergeRequest.getTitle()) - .url(oldMergeRequest.getWebUrl()) - .projectName(project.getName()) - .newStatus(newStatus) - .oldStatus(oldStatus) - .milestone(newMergeRequest.getMilestone()) - .build() - ); - } + private Optional getAssignee(MergeRequest mergeRequest) { + return Optional.ofNullable(mergeRequest.getAssignee()); } } diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/PipelineServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/PipelineServiceImpl.java index c6119fc..42089cc 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/PipelineServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/PipelineServiceImpl.java @@ -1,17 +1,14 @@ package dev.struchkov.bot.gitlab.core.service; import dev.struchkov.bot.gitlab.context.domain.ExistContainer; -import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.PipelineStatus; -import dev.struchkov.bot.gitlab.context.domain.entity.Person; import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline; -import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelineNotify; import dev.struchkov.bot.gitlab.context.repository.PipelineRepository; -import dev.struchkov.bot.gitlab.context.service.NotifyService; import dev.struchkov.bot.gitlab.context.service.PipelineService; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,12 +17,9 @@ import java.util.List; import java.util.Set; import java.util.stream.Collectors; -import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.CANCELED; -import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.FAILED; -import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SKIPPED; -import static dev.struchkov.bot.gitlab.context.domain.PipelineStatus.SUCCESS; +import static dev.struchkov.bot.gitlab.context.domain.event.NewPipelineEvent.newPipeline; +import static dev.struchkov.bot.gitlab.context.domain.event.UpdatePipelineEvent.updatePipeline; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; -import static dev.struchkov.haiti.utils.Checker.checkNotNull; /** * Реализация сервиса для работы с пайплайнами. @@ -37,19 +31,15 @@ import static dev.struchkov.haiti.utils.Checker.checkNotNull; @RequiredArgsConstructor public class PipelineServiceImpl implements PipelineService { - // Статусы пайплайнов, о которых нужно уведомить - private static final Set notificationStatus = Set.of(FAILED, SUCCESS, CANCELED, SKIPPED); + private final ApplicationEventPublisher eventPublisher; - private final NotifyService notifyService; private final PipelineRepository repository; - private final PersonInformation personInformation; - @Override @Transactional public Pipeline create(@NonNull Pipeline pipeline) { final Pipeline newPipeline = repository.save(pipeline); - notifyNewPipeline(pipeline, PipelineStatus.NULL); + eventPublisher.publishEvent(newPipeline(newPipeline)); return newPipeline; } @@ -61,21 +51,6 @@ public class PipelineServiceImpl implements PipelineService { .collect(Collectors.toList()); } - private void notifyNewPipeline(Pipeline pipeline, PipelineStatus oldStatus) { - if (isNeedNotifyNewPipeline(pipeline)) { - notifyService.send( - PipelineNotify.builder() - .projectId(pipeline.getProjectId()) - .newStatus(pipeline.getStatus()) - .pipelineId(pipeline.getId()) - .refName(pipeline.getRef()) - .webUrl(pipeline.getWebUrl()) - .oldStatus(oldStatus) - .build() - ); - } - } - @Override public Pipeline update(@NonNull Pipeline pipeline) { final Pipeline oldPipeline = repository.findById(pipeline.getId()) @@ -84,7 +59,7 @@ public class PipelineServiceImpl implements PipelineService { pipeline.setProjectId(oldPipeline.getProjectId()); if (!oldPipeline.getUpdated().equals(pipeline.getUpdated())) { - notifyNewPipeline(pipeline, oldPipeline.getStatus()); + eventPublisher.publishEvent(updatePipeline(oldPipeline.toBuilder().build(), pipeline)); return repository.save(pipeline); } @@ -98,14 +73,6 @@ public class PipelineServiceImpl implements PipelineService { .collect(Collectors.toList()); } - private boolean isNeedNotifyNewPipeline(@NonNull Pipeline pipeline) { - final Person personPipelineCreator = pipeline.getPerson(); - return notificationStatus.contains(pipeline.getStatus()) // Пайплайн имеет статус необходимый для уведомления - && checkNotNull(personPipelineCreator) // Создатель пайплайна не null - && personInformation.getId().equals(personPipelineCreator.getId()) // Пользователь приложения является инициатором пайплайна - && LocalDateTime.now().minusDays(1).isBefore(pipeline.getCreated()); // Пайплан был создан не более 24 часов назад - } - @Override public List getAllByStatuses(@NonNull Set statuses) { return repository.findAllByStatuses(statuses); diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/ProjectServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/ProjectServiceImpl.java index ece5899..806dc6a 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/ProjectServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/ProjectServiceImpl.java @@ -2,13 +2,11 @@ package dev.struchkov.bot.gitlab.core.service; import dev.struchkov.bot.gitlab.context.domain.ExistContainer; import dev.struchkov.bot.gitlab.context.domain.entity.Project; -import dev.struchkov.bot.gitlab.context.domain.notify.project.NewProjectNotify; import dev.struchkov.bot.gitlab.context.repository.ProjectRepository; -import dev.struchkov.bot.gitlab.context.service.NotifyService; -import dev.struchkov.bot.gitlab.context.service.PersonService; import dev.struchkov.bot.gitlab.context.service.ProjectService; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,6 +15,7 @@ import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import static dev.struchkov.bot.gitlab.context.domain.event.NewProjectEvent.newProject; import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException; /** @@ -28,8 +27,7 @@ public class ProjectServiceImpl implements ProjectService { private final ProjectRepository repository; - private final NotifyService notifyService; - private final PersonService personService; + private final ApplicationEventPublisher eventPublisher; @Override @Transactional @@ -37,8 +35,7 @@ public class ProjectServiceImpl implements ProjectService { final Project newProject = repository.save(project); if (sendNotify) { - final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName(); - notifyAboutNewProject(newProject, authorName); + eventPublisher.publishEvent(newProject(project)); } return newProject; @@ -111,18 +108,4 @@ public class ProjectServiceImpl implements ProjectService { repository.processing(enable, projectIds); } - private void notifyAboutNewProject(Project newProject, String authorName) { - notifyService.send( - NewProjectNotify.builder() - .projectId(newProject.getId()) - .projectDescription(newProject.getDescription()) - .projectName(newProject.getName()) - .projectUrl(newProject.getWebUrl()) - .sshUrlToRepo(newProject.getSshUrlToRepo()) - .httpUrlToRepo(newProject.getHttpUrlToRepo()) - .authorName(authorName) - .build() - ); - } - }