diff --git a/README.md b/README.md index bd1651c..ba5b225 100644 --- a/README.md +++ b/README.md @@ -1,30 +1,57 @@ # Уведомления GitLab в Telegram -Это приложение позволит вам получать уведомления о событиях из GitLab. +Этот проект позволяет оперативно получать и настраивать персональные уведомления о событиях из GitLab. -> Статья-документация: https://struchkov.dev/blog/gitlab-telegram-bot/ -> -> Исходный код: https://github.com/uPagge/gitlab-notification +> Статья о проекте: https://struchkov.dev/blog/gitlab-telegram-bot/ +> Канал в Telegram, в который публикуется информация о разработке: https://t.me/gitlab_notification -## Возможности бота -1. Уведомление о новых MergeRequest -2. Уведомление о возникновении конфликта в MergeRequest -3. Уведомление о добавлении вас в новый проект -4. Уведомление о смене статуса вашего MergeRequest -5. Уведомление о комментариях, в которых вас упоминают в формате @nickname -6. Уведомит о новой задаче в вашем MR. -7. Уведомит о закрытии вашей задачи в чужом MR -8. Уведомление о Pipeline +> ⚠️На данный момент вся разработка ведется в моем Gitea: https://git.struchkov.dev/Telegram-Bots/gitlab-notification +> GitHub остается для удобства пользователей проекта, чтобы иметь возможность давать обратную связь по багам и +> предложениям. + +> ⚠️Идет активная подготовка к выпуску версии 2.0.0, в котором будут исправлены все существующие баги, а также добавлена +> поддержка уведомлений Issue. +> На данный момент лучше использовать тег develop, вместо latest. + +## Основные возможности + +1. Уведомление о новых Merge Request. +2. Уведомление о возникновении конфликта в MergeRequest. +3. Уведомление о появлении нового проекта. +4. Уведомление о смене статуса вашего MergeRequest. +5. Уведомление о комментариях, в которых вас упоминают в формате @nickname. +6. Уведомит о новом комментарии-треде в вашем MR. +7. Уведомит о закрытии вашего треда в чужом MR. +8. Уведомление о результате сборки. ## Как запустить -1. Для начала нужно создать бота, который будет посылать вам уведомления в телеграмм. Делается это в [специальном боте](https://t.me/botfather) -2. После создания вы получите токен, сохраните его. Пример: 34534050345:FlfrleflerferfRE-ergerFLREF9ERF-NGjM -3. Теперь необходимо получить персональный токен в вашем gitlab. Достаточно токена на чтение. Сохраните его -4. Создайте базу данных gitlab_bot. **Обязательно именно такое название** -4. Можно приступать к запуску +1. Для начала нужно создать бота, который будет посылать вам уведомления. Делается это + в [специальном боте](https://t.me/botfather) +2. После создания вы получите токен, сохраните его. Пример: `34534050345:FlfrleflerferfRE-ergerFLREF9ERF-NGjM` +3. Теперь необходимо получить персональный токен в вашем gitlab. Достаточно токена на чтение. +4. Можно приступать к запуску используя один из способов ниже. + +### Переменные среды + +* `TELEGRAM_BOT_TOKEN` -- токен, который вы получили при создание бота. +* `TELEGRAM_BOT_USERNAME` -- название, которое вы дали боту. Пример my_gitlab_bot. +* `GITLAB_PERSONAL_TOKEN` -- ваш персональный токен из GitLab. +* `TELEGRAM_PERSON_ID` -- ваш id в телеграм, можно узнать у [этого бота](https://t.me/myidbot) +* `GITLAB_URL` -- можно указать https://gitlab.com или url на ваш локальный/корпоративный GitLab строго в таком + формате http://localhost:7990. +* `DATASOURCE_URL` -- ссылка на базу данных Postgres, в следующем формате: jdbc:postgresql://localhost:5432/gitlab_bot +* `DATASOURCE_USERNAME` -- пользовать базы данных +* `DATASOURCE_PASSWORD` -- пароль пользователя базы данных + +### Запуск + +Есть несколько способов запуска. Для удобства я собрал проект в Docker образ, а также подготовил Docker Compose. + +#### Docker + +Подойдет, если вы не хотите поднимать отдельный контейнер с базой данных -### Пример запуска ``` sudo docker run --name gitlab-notify \ --env TELEGRAM_BOT_TOKEN=value \ @@ -38,15 +65,65 @@ sudo docker run --name gitlab-notify \ --network="host" upagge/gitlab-telegram-notify:latest ``` -#### Переменные +#### Docker Compose -* `TELEGRAM_BOT_TOKEN` -- токен, который вы получили при создание бота. -* `TELEGRAM_BOT_USERNAME` -- название, которое вы дали боту. Пример my_gitlab_bot -* `GITLAB_PERSONAL_TOKEN` -- токен, который вы получили в GitLab -* `TELEGRAM_PERSON_ID` -- ваш id в телеграм, можно узнать у [этого бота](https://t.me/myidbot) -* `GITLAB_URL` -- можно указать https://gitlab.com или url на ваш локальный GitLab строго в таком формате http://localhost:7990 -* `DATASOURCE_URL` -- ссылка на базу данных Postgres, в следующем формате: jdbc:postgresql://localhost:5432/gitlab_bot -* `DATASOURCE_USERNAME` -- пользовать бд -* `DATASOURCE_PASSWORD` -- пароль от бд +Самый простой способ запуска. -После этого необходимо отправить боту сообщение, чтобы пройти первичную настройку. +docker-compose.yml +```yaml +version: '3.8' + +services: + + gitlab-bot-database: + image: postgres:15.1-alpine + restart: always + hostname: gitlab-bot-database + container_name: gitlab-bot-database + networks: + gitlab-bot: + environment: + POSTGRES_DB: "gitlab_bot" + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: ${DATASOURCE_PASSWORD} + volumes: + - gitlab-bot-database:/var/lib/postgresql/data/ + + gitlab-bot: + image: upagge/gitlab-telegram-notify:latest + hostname: gitlab-bot + container_name: gitlab-bot + privileged: true + networks: + gitlab-bot: + depends_on: + - gitlab-bot-database + environment: + TELEGRAM_BOT_TOKEN: ${TELEGRAM_BOT_TOKEN} + TELEGRAM_BOT_USERNAME: ${TELEGRAM_BOT_USERNAME} + GITLAB_PERSONAL_TOKEN: ${GITLAB_PERSONAL_TOKEN} + TELEGRAM_PERSON_ID: ${TELEGRAM_PERSON_ID} + GITLAB_URL: ${GITLAB_URL} + DATASOURCE_URL: "jdbc:postgresql://gitlab-bot-database:5432/gitlab_bot" + DATASOURCE_USERNAME: ${DATASOURCE_USERNAME} + DATASOURCE_PASSWORD: ${DATASOURCE_PASSWORD} + +volumes: + gitlab-bot-database: + +networks: + gitlab-bot: +``` + +.env +``` +TELEGRAM_BOT_TOKEN= +TELEGRAM_BOT_USERNAME= +GITLAB_PERSONAL_TOKEN= +TELEGRAM_PERSON_ID= +GITLAB_URL= +DATASOURCE_USERNAME= +DATASOURCE_PASSWORD= +``` + +После запуска необходимо отправить боту сообщение, чтобы пройти первичную настройку. diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/AppSetting.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/AppSetting.java index ec68dfd..a2e0fab 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/AppSetting.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/AppSetting.java @@ -1,7 +1,10 @@ package dev.struchkov.bot.gitlab.context.domain.entity; +import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel; import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.Id; import jakarta.persistence.Table; import lombok.Getter; @@ -34,4 +37,8 @@ public class AppSetting { @Column(name = "project_private_scan") private boolean projectPrivateScan; + @Enumerated(EnumType.STRING) + @Column(name = "discussion_notify_level") + private DiscussionLevel discussionNotifyLevel; + } 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 ef20605..d2634bb 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 @@ -17,6 +17,8 @@ import lombok.Setter; import java.util.List; import java.util.Optional; +import static dev.struchkov.haiti.utils.Checker.checkNotEmpty; + /** * @author upagge 11.02.2021 */ @@ -38,6 +40,9 @@ public class Discussion { @Column(name = "resolved") private Boolean resolved; + @Column(name = "notification") + private boolean notification; + @ManyToOne(optional = false, cascade = CascadeType.REMOVE) @JoinTable( name = "discussion_merge_request", @@ -62,6 +67,20 @@ public class Discussion { this.notes = notes; } + public int getNoteSize() { + if (checkNotEmpty(notes)) { + return notes.size(); + } + return 0; + } + + public Optional getNoteByNumber(int number) { + if (checkNotEmpty(notes) && number < notes.size()) { + return Optional.of(notes.get(number)); + } + return Optional.empty(); + } + public Note getFirstNote() { return this.notes.get(0); } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequestForDiscussion.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequestForDiscussion.java index f1000ae..f9f8372 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequestForDiscussion.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/entity/MergeRequestForDiscussion.java @@ -45,4 +45,7 @@ public class MergeRequestForDiscussion { @Column(name = "web_url") private String webUrl; + @Column(name = "notification") + private boolean notification; + } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/comment/NewCommentNotify.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/comment/NewCommentNotify.java index a0ffd7f..0280129 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/comment/NewCommentNotify.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/comment/NewCommentNotify.java @@ -9,6 +9,8 @@ public final class NewCommentNotify implements Notify { public static final String TYPE = "NewCommentNotify"; + private final String threadId; + private final String mergeRequestName; private final String url; private final String discussionMessage; private final String discussionAuthor; @@ -16,17 +18,23 @@ public final class NewCommentNotify implements Notify { private final String previousAuthor; private final String authorName; private final String message; + private final int numberNotes; @Builder public NewCommentNotify( + String threadId, + String mergeRequestName, String url, String discussionMessage, String discussionAuthor, String previousMessage, String previousAuthor, String authorName, - String message + String message, + int numberNotes ) { + this.threadId = threadId; + this.mergeRequestName = mergeRequestName; this.url = url; this.discussionMessage = discussionMessage; this.discussionAuthor = discussionAuthor; @@ -34,9 +42,9 @@ public final class NewCommentNotify implements Notify { this.previousAuthor = previousAuthor; this.authorName = authorName; this.message = message; + this.numberNotes = numberNotes; } - @Override public String getType() { return TYPE; diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/level/DiscussionLevel.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/level/DiscussionLevel.java new file mode 100644 index 0000000..73ad8bd --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/level/DiscussionLevel.java @@ -0,0 +1,7 @@ +package dev.struchkov.bot.gitlab.context.domain.notify.level; + +public enum DiscussionLevel { + + WITHOUT_NOTIFY, NOTIFY_WITHOUT_CONTEXT, NOTIFY_WITH_CONTEXT + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/mergerequest/ConflictResolveMrNotify.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/mergerequest/ConflictResolveMrNotify.java new file mode 100644 index 0000000..548ae5c --- /dev/null +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/mergerequest/ConflictResolveMrNotify.java @@ -0,0 +1,30 @@ +package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest; + +import lombok.Builder; +import lombok.Getter; + +@Getter +public class ConflictResolveMrNotify extends MrNotify { + + public static final String TYPE = "ConflictResolveMrNotify"; + + private final String sourceBranch; + + @Builder + private ConflictResolveMrNotify( + Long mrId, + String name, + String url, + String projectKey, + String sourceBranch + ) { + super(mrId, projectKey, name, url); + this.sourceBranch = sourceBranch; + } + + @Override + public String getType() { + return TYPE; + } + +} diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/task/DiscussionNewNotify.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/task/DiscussionNewNotify.java index 9caef45..7e06255 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/task/DiscussionNewNotify.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/domain/notify/task/DiscussionNewNotify.java @@ -15,11 +15,13 @@ public class DiscussionNewNotify extends TaskNotify { public static final String TYPE = "DiscussionNewNotify"; + private final String threadId; private final String mrName; private final List> notes; @Builder public DiscussionNewNotify( + String threadId, String mrName, String authorName, String url, @@ -27,6 +29,7 @@ public class DiscussionNewNotify extends TaskNotify { @Singular List> notes ) { super(authorName, url, discussionMessage); + this.threadId = threadId; this.mrName = mrName; this.notes = notes; } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/DiscussionRepository.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/DiscussionRepository.java index 1ff65f6..812453b 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/DiscussionRepository.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/DiscussionRepository.java @@ -30,4 +30,6 @@ public interface DiscussionRepository { void cleanOld(); + void notification(boolean enable, String discussionId); + } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/MergeRequestRepository.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/MergeRequestRepository.java index d82fd7c..bf7d90f 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/MergeRequestRepository.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/repository/MergeRequestRepository.java @@ -28,6 +28,8 @@ public interface MergeRequestRepository { Set findAllIds(); - void disableNotify(Long mrId); + void notification(boolean enable, Long mrId); + + void notificationByProjectId(boolean enable, Set projectIds); } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/AppSettingService.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/AppSettingService.java index ed05533..587a736 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/AppSettingService.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/AppSettingService.java @@ -1,5 +1,7 @@ package dev.struchkov.bot.gitlab.context.service; +import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel; + /** * Сервис отвечает за пользовательские настройки приложения. * @@ -33,4 +35,6 @@ public interface AppSettingService { boolean isPrivateProjectScan(); + DiscussionLevel getLevelDiscussionNotify(); + } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java index 5e1eda4..4abf57f 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/DiscussionService.java @@ -43,4 +43,6 @@ public interface DiscussionService { void cleanOld(); + void notification(boolean enable, String discussionId); + } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/MergeRequestsService.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/MergeRequestsService.java index 2569a06..66de696 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/MergeRequestsService.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/MergeRequestsService.java @@ -38,6 +38,8 @@ public interface MergeRequestsService { Set getAllIds(); - void disableNotify(@NonNull Long mrId); + void notification(boolean enable, @NonNull Long mrId); + + void notificationByProjectId(boolean enable, @NonNull Set projectIds); } diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/ProjectService.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/ProjectService.java index 11e326f..2bbf5cb 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/ProjectService.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/service/ProjectService.java @@ -13,7 +13,7 @@ import java.util.Set; */ public interface ProjectService { - Project create(@NonNull Project project); + Project create(@NonNull Project project, boolean sendNotify); Project update(@NonNull Project project); diff --git a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/utils/Icons.java b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/utils/Icons.java index 1cd7116..b037072 100644 --- a/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/utils/Icons.java +++ b/bot-context/src/main/java/dev/struchkov/bot/gitlab/context/utils/Icons.java @@ -16,6 +16,7 @@ public class Icons { public static final String TASK = "\uD83D\uDCBC"; public static final String ARROW = " ➜ "; public static final String DANGEROUS = "⚠️"; + public static final String GREEN_CIRCLE = "\uD83D\uDFE2"; public static final String PEN = "✏️"; public static final String ASSIGNEE = "\uD83C\uDFA9"; public static final String BUILD = "⚙️"; diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/AppSettingServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/AppSettingServiceImpl.java index 483e84c..92f4ef7 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/AppSettingServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/AppSettingServiceImpl.java @@ -1,6 +1,7 @@ package dev.struchkov.bot.gitlab.core.service.impl; import dev.struchkov.bot.gitlab.context.domain.entity.AppSetting; +import dev.struchkov.bot.gitlab.context.domain.notify.level.DiscussionLevel; import dev.struchkov.bot.gitlab.context.repository.AppSettingRepository; import dev.struchkov.bot.gitlab.context.service.AppSettingService; import dev.struchkov.haiti.context.exception.NotFoundException; @@ -79,6 +80,11 @@ public class AppSettingServiceImpl implements AppSettingService { return getAppSetting().isProjectPrivateScan(); } + @Override + public DiscussionLevel getLevelDiscussionNotify() { + return getAppSetting().getDiscussionNotifyLevel(); + } + private AppSetting getAppSetting() { return appSettingRepository.findById(KEY) .orElseThrow(NOT_FOUND_SETTINGS); diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java index 834262b..009ba79 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/DiscussionServiceImpl.java @@ -7,9 +7,11 @@ 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.TaskCloseNotify; 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.bot.gitlab.core.config.properties.GitlabProperty; @@ -38,6 +40,8 @@ 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.context.exception.NotFoundException.notFoundException; import static dev.struchkov.haiti.utils.Checker.checkNotNull; import static java.lang.Boolean.FALSE; @@ -53,24 +57,70 @@ import static java.lang.Boolean.FALSE; public class DiscussionServiceImpl implements DiscussionService { protected static final Pattern PATTERN = Pattern.compile("@[\\w]+"); + private final OkHttpClient client = new OkHttpClient(); private final DiscussionRepository repository; - private final PersonInformation personInformation; - private final OkHttpClient client = new OkHttpClient(); + private final NotifyService notifyService; + private final AppSettingService settingService; + + private final PersonInformation personInformation; private final GitlabProperty gitlabProperty; private final PersonProperty personProperty; - private final NotifyService notifyService; @Override @Transactional public Discussion create(@NonNull Discussion discussion) { final List notes = discussion.getNotes(); - if (isNeedNotifyNewNote(discussion)) { - notifyNewDiscussion(discussion); + final DiscussionLevel levelDiscussionNotify = settingService.getLevelDiscussionNotify(); + if (!WITHOUT_NOTIFY.equals(levelDiscussionNotify)) { + discussion.setNotification(true); + + if (isNeedNotifyNewNote(discussion)) { + notifyNewDiscussion(discussion); + } else { + notes.forEach(note -> notificationPersonal(discussion, note)); + } } else { - notes.forEach(this::notificationPersonal); + discussion.setNotification(false); + } + + final boolean resolved = discussion.getNotes().stream() + .allMatch(note -> note.isResolvable() && note.getResolved()); + + discussion.setResolved(resolved); + + return repository.save(discussion); + } + + @Override + @Transactional + public Discussion update(@NonNull Discussion discussion) { + final Discussion oldDiscussion = repository.findById(discussion.getId()) + .orElseThrow(notFoundException("Дискуссия не найдена")); + + discussion.setResponsible(oldDiscussion.getResponsible()); + discussion.setMergeRequest(oldDiscussion.getMergeRequest()); + discussion.setNotification(oldDiscussion.isNotification()); + + final Person responsiblePerson = discussion.getResponsible(); + if (checkNotNull(responsiblePerson)) { + for (Note note : discussion.getNotes()) { + if (responsiblePerson.getId().equals(note.getAuthor().getId())) { + note.setAuthor(responsiblePerson); + } + final Person resolvedBy = note.getResolvedBy(); + if (checkNotNull(resolvedBy)) { + if (responsiblePerson.getId().equals(resolvedBy.getId())) { + note.setResolvedBy(responsiblePerson); + } + } + } + } + + if (oldDiscussion.isNotification()) { + notifyUpdateNote(oldDiscussion, discussion); } final boolean resolved = discussion.getNotes().stream() @@ -90,6 +140,7 @@ public class DiscussionServiceImpl implements DiscussionService { final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest(); final DiscussionNewNotify.DiscussionNewNotifyBuilder notifyBuilder = DiscussionNewNotify.builder() + .threadId(discussion.getId()) .mrName(mergeRequest.getTitle()) .authorName(firstNote.getAuthor().getName()) .discussionMessage(firstNote.getBody()) @@ -116,39 +167,6 @@ public class DiscussionServiceImpl implements DiscussionService { && FALSE.equals(firstNote.getResolved()); // Комментарий не отмечен как решенный } - @Override - @Transactional - public Discussion update(@NonNull Discussion discussion) { - final Discussion oldDiscussion = repository.findById(discussion.getId()) - .orElseThrow(notFoundException("Дискуссия не найдена")); - - discussion.setResponsible(oldDiscussion.getResponsible()); - discussion.setMergeRequest(oldDiscussion.getMergeRequest()); - - final Person responsiblePerson = discussion.getResponsible(); - if (checkNotNull(responsiblePerson)) { - for (Note note : discussion.getNotes()) { - if (responsiblePerson.getId().equals(note.getAuthor().getId())) { - note.setAuthor(responsiblePerson); - } - final Person resolvedBy = note.getResolvedBy(); - if (checkNotNull(resolvedBy)) { - if (responsiblePerson.getId().equals(resolvedBy.getId())) { - note.setResolvedBy(responsiblePerson); - } - } - } - } - notifyUpdateNote(oldDiscussion, discussion); - - final boolean resolved = discussion.getNotes().stream() - .allMatch(note -> note.isResolvable() && note.getResolved()); - - discussion.setResolved(resolved); - - return repository.save(discussion); - } - @Override public List updateAll(@NonNull List discussions) { return discussions.stream() @@ -178,39 +196,13 @@ public class DiscussionServiceImpl implements DiscussionService { if (userParticipatedInDiscussion) { notifyNewAnswer(discussion, newNote); } else { - notificationPersonal(newNote); + notificationPersonal(discussion, newNote); } } } } - private void notifyNewAnswer(Discussion discussion, Note note) { - if (!personInformation.getId().equals(note.getAuthor().getId())) { - final Note firstNote = discussion.getFirstNote(); - final Optional prevLastNote = discussion.getPrevLastNote(); - - - final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder(); - - if (prevLastNote.isPresent()) { - final Note prevNote = prevLastNote.get(); - notifyBuilder.previousMessage(prevNote.getBody()); - notifyBuilder.previousAuthor(prevNote.getAuthor().getName()); - } - - notifyService.send( - notifyBuilder - .url(note.getWebUrl()) - .discussionMessage(firstNote.getBody()) - .discussionAuthor(firstNote.getAuthor().getName()) - .message(note.getBody()) - .authorName(note.getAuthor().getName()) - .build() - ); - } - } - private void updateTask(Note note, Note oldNote) { if (isResolved(note, oldNote)) { final MergeRequestForDiscussion mergeRequest = oldNote.getDiscussion().getMergeRequest(); @@ -253,20 +245,18 @@ public class DiscussionServiceImpl implements DiscussionService { final String requestUrl = MessageFormat.format(gitlabProperty.getNewNoteUrl(), projectId, mergeRequest.getTwoId(), discussion.getId(), text); - RequestBody formBody = new FormBody.Builder().build(); + final RequestBody formBody = new FormBody.Builder().build(); - Request request = new Request.Builder() + final Request request = new Request.Builder() .post(formBody) .header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken()) .url(requestUrl) .build(); - try { client.newCall(request).execute(); } catch (IOException e) { log.error(e.getMessage(), e); } - } @Override @@ -319,24 +309,84 @@ public class DiscussionServiceImpl implements DiscussionService { log.debug("Конец очистки старых дискуссий"); } + @Override + @Transactional + public void notification(boolean enable, String discussionId) { + repository.notification(enable, discussionId); + } + + private void notifyNewAnswer(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()); + } + } + /** * Уведомляет пользователя, если его никнейм упоминается в комментарии. */ - protected void notificationPersonal(@NonNull Note note) { - 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())) { - notifyService.send( - NewCommentNotify.builder() - .authorName(note.getAuthor().getName()) - .message(note.getBody()) - .url(note.getWebUrl()) - .build() - ); + protected void notificationPersonal(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()); + } } } diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java index 8a94a5d..16d1add 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/MergeRequestsServiceImpl.java @@ -12,6 +12,7 @@ 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; @@ -179,7 +180,8 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { if (isChangedMr) { notifyAboutStatus(oldMergeRequest, mergeRequest, project); - notifyAboutConflict(oldMergeRequest, mergeRequest, project); + notifyAboutNewConflict(oldMergeRequest, mergeRequest, project); + notifyAboutResolveConflict(oldMergeRequest, mergeRequest, project); notifyAboutUpdate(oldMergeRequest, mergeRequest, project); } @@ -195,14 +197,15 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { } //TODO [05.12.2022|uPagge]: Добавить уведомление, если происходит удаление + private void notifyAssignee(AssigneeChanged assigneeChanged, MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { switch (assigneeChanged) { case BECOME -> sendNotifyNewAssignee(mergeRequest, project.getName(), Optional.ofNullable(oldMergeRequest.getAssignee()).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()); @@ -268,8 +271,14 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { @Override @Transactional - public void disableNotify(@NonNull Long mrId) { - repository.disableNotify(mrId); + public void notification(boolean enable, @NonNull Long mrId) { + repository.notification(enable, mrId); + } + + @Override + @Transactional + public void notificationByProjectId(boolean enable, @NonNull Set projectIds) { + repository.notificationByProjectId(enable, projectIds); } private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { @@ -317,7 +326,7 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { } } - protected void notifyAboutConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { + protected void notifyAboutNewConflict(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) { final Long gitlabUserId = personInformation.getId(); if ( !oldMergeRequest.isConflict() // У старого MR не было конфликта @@ -336,6 +345,25 @@ public class MergeRequestsServiceImpl implements MergeRequestsService { } } + private void notifyAboutResolveConflict(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( + ConflictResolveMrNotify.builder() + .mrId(oldMergeRequest.getId()) + .sourceBranch(oldMergeRequest.getSourceBranch()) + .name(mergeRequest.getTitle()) + .url(mergeRequest.getWebUrl()) + .projectKey(project.getName()) + .build() + ); + } + } + protected void notifyAboutStatus(MergeRequest oldMergeRequest, MergeRequest newMergeRequest, Project project) { final MergeRequestState oldStatus = oldMergeRequest.getState(); final MergeRequestState newStatus = newMergeRequest.getState(); diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/ProjectServiceImpl.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/ProjectServiceImpl.java index 1d21ebe..b8c0e2a 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/ProjectServiceImpl.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/impl/ProjectServiceImpl.java @@ -33,11 +33,13 @@ public class ProjectServiceImpl implements ProjectService { @Override @Transactional - public Project create(@NonNull Project project) { + public Project create(@NonNull Project project, boolean sendNotify) { final Project newProject = repository.save(project); - final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName(); - notifyAboutNewProject(newProject, authorName); + if (sendNotify) { + final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName(); + notifyAboutNewProject(newProject, authorName); + } return newProject; } @@ -57,7 +59,7 @@ public class ProjectServiceImpl implements ProjectService { @Transactional public List createAll(List newProjects) { return newProjects.stream() - .map(this::create) + .map(newProject -> create(newProject, true)) .toList(); } diff --git a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/ProjectParser.java b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/ProjectParser.java index b7b719c..d644ac5 100644 --- a/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/ProjectParser.java +++ b/bot-core/src/main/java/dev/struchkov/bot/gitlab/core/service/parser/ProjectParser.java @@ -3,6 +3,7 @@ package dev.struchkov.bot.gitlab.core.service.parser; import dev.struchkov.bot.gitlab.context.domain.ExistContainer; import dev.struchkov.bot.gitlab.context.domain.entity.Person; import dev.struchkov.bot.gitlab.context.domain.entity.Project; +import dev.struchkov.bot.gitlab.context.service.MergeRequestsService; import dev.struchkov.bot.gitlab.context.service.PersonService; import dev.struchkov.bot.gitlab.context.service.ProjectService; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; @@ -38,8 +39,8 @@ public class ProjectParser { public static final String OWNER = "&owned=true"; public static final String PRIVATE = "&visibility=private"; - public static final String PUBLIC_OWNER = "&visibility=public&owned=true"; + private final MergeRequestsService mergeRequestsService; private final ProjectService projectService; private final PersonService personService; @@ -86,17 +87,18 @@ public class ProjectParser { } } - public void parseByUrl(String projectUrl) { + public Project parseByUrl(String projectUrl) { final ProjectJson projectJson = HttpParse.request(projectUrl) .header(ACCEPT) .header(StringUtils.H_PRIVATE_TOKEN, personProperty.getToken()) .execute(ProjectJson.class) - .orElseThrow(convertException("Ошибка получения проекта")); + .orElseThrow(convertException("Ошибка получения репозитория.")); if (!projectService.existsById(projectJson.getId())) { createNewPersons(List.of(projectJson)); - final Project newProject = conversionService.convert(projectJson, Project.class); - projectService.create(newProject); + return projectService.create(newProject, false); + } else { + return projectService.getByIdOrThrow(projectJson.getId()); } } diff --git a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java index 658ea19..d7a5979 100644 --- a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java +++ b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/DiscussionRepositoryImpl.java @@ -62,4 +62,9 @@ public class DiscussionRepositoryImpl implements DiscussionRepository { jpaRepository.removeAllByMergeRequestIsNull(); } + @Override + public void notification(boolean enable, String discussionId) { + jpaRepository.notification(enable, discussionId); + } + } diff --git a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/MergeRequestRepositoryImpl.java b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/MergeRequestRepositoryImpl.java index b0ffc72..645cb30 100644 --- a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/MergeRequestRepositoryImpl.java +++ b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/impl/MergeRequestRepositoryImpl.java @@ -71,8 +71,13 @@ public class MergeRequestRepositoryImpl implements MergeRequestRepository { } @Override - public void disableNotify(Long mrId) { - jpaRepository.disableNotify(mrId); + public void notification(boolean enable, Long mrId) { + jpaRepository.disableNotify(enable, mrId); + } + + @Override + public void notificationByProjectId(boolean enable, Set projectIds) { + jpaRepository.notificationByProjectId(enable, projectIds); } } diff --git a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/jpa/DiscussionJpaRepository.java b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/jpa/DiscussionJpaRepository.java index 7393f61..f24dc01 100644 --- a/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/jpa/DiscussionJpaRepository.java +++ b/bot-data/src/main/java/dev/struchkov/bot/gitlab/data/jpa/DiscussionJpaRepository.java @@ -28,4 +28,8 @@ public interface DiscussionJpaRepository extends JpaRepository findAllIds(); @Modifying - @Query("UPDATE MergeRequest mr SET mr.notification = false WHERE mr.id = :mrId") - void disableNotify(@Param("mrId") Long mrId); + @Query("UPDATE MergeRequest mr SET mr.notification = :enable WHERE mr.id = :mrId") + void disableNotify(@Param("enable") boolean enable, @Param("mrId") Long mrId); + + @Modifying + @Query("UPDATE MergeRequest mr SET mr.notification = :enable WHERE mr.projectId in :projectIds") + void notificationByProjectId(@Param("enable") boolean enable, @Param("projectIds") Set projectIds); } diff --git a/gitlab-app/src/main/java/dev/struchkov/bot/gitlab/scheduler/SchedulerService.java b/gitlab-app/src/main/java/dev/struchkov/bot/gitlab/scheduler/SchedulerService.java index ae4648a..9116efe 100644 --- a/gitlab-app/src/main/java/dev/struchkov/bot/gitlab/scheduler/SchedulerService.java +++ b/gitlab-app/src/main/java/dev/struchkov/bot/gitlab/scheduler/SchedulerService.java @@ -32,7 +32,7 @@ public class SchedulerService { private final MergeRequestsService mergeRequestsService; private final DiscussionService discussionService; - @Scheduled(cron = "0 */2 * * * *") + @Scheduled(cron = "0 */1 * * * *") public void newMergeRequest() { log.info("Запуск процесса обновления данных c GitLab"); if (!settingService.isFirstStart()) { diff --git a/gitlab-app/src/main/resources/liquibase/v.2.0.0/2022-12-03-create-tables.xml b/gitlab-app/src/main/resources/liquibase/v.2.0.0/2022-12-03-create-tables.xml index 1d9369f..93723f7 100644 --- a/gitlab-app/src/main/resources/liquibase/v.2.0.0/2022-12-03-create-tables.xml +++ b/gitlab-app/src/main/resources/liquibase/v.2.0.0/2022-12-03-create-tables.xml @@ -20,6 +20,9 @@ + + + @@ -160,6 +163,9 @@ references="person(id)"/> + + + diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/config/TelegramBotConfig.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/config/TelegramBotConfig.java index 1b610f1..b4e2538 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/config/TelegramBotConfig.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/config/TelegramBotConfig.java @@ -5,6 +5,7 @@ import dev.struchkov.bot.gitlab.telegram.unit.MenuConfig; import dev.struchkov.bot.gitlab.telegram.unit.command.AnswerNoteUnit; import dev.struchkov.bot.gitlab.telegram.unit.command.DeleteMessageUnit; import dev.struchkov.bot.gitlab.telegram.unit.command.DisableNotifyMrUnit; +import dev.struchkov.bot.gitlab.telegram.unit.command.DisableNotifyThreadUnit; import dev.struchkov.bot.gitlab.telegram.unit.command.EnableProjectNotify; import dev.struchkov.bot.gitlab.telegram.unit.flow.InitSettingFlow; import dev.struchkov.godfather.main.core.unit.TypeUnit; @@ -80,9 +81,11 @@ public class TelegramBotConfig { AnswerNoteUnit commandUnit, DeleteMessageUnit deleteMessageUnit, DisableNotifyMrUnit disableNotifyMrUnit, + DisableNotifyThreadUnit disableNotifyThreadUnit, EnableProjectNotify enableProjectNotify ) { - final List config = List.of(menuConfig, unitConfig, commandUnit, deleteMessageUnit, disableNotifyMrUnit, enableProjectNotify); + final List config = List.of(menuConfig, unitConfig, commandUnit, deleteMessageUnit, disableNotifyMrUnit, + disableNotifyThreadUnit, enableProjectNotify); return new StorylineMailService( unitPointerService, diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/ConflictPrNotifyGenerator.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/ConflictPrNotifyGenerator.java index 43653e9..98043dc 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/ConflictPrNotifyGenerator.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/ConflictPrNotifyGenerator.java @@ -5,8 +5,15 @@ import dev.struchkov.bot.gitlab.context.utils.Icons; import dev.struchkov.godfather.main.domain.BoxAnswer; import org.springframework.stereotype.Component; -import static dev.struchkov.bot.gitlab.context.utils.Icons.link; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_CONFIRMATION; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_DISABLE_NOTIFY_MR_ID; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_VALUE_FALSE; +import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.DELETE_MESSAGE; import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer; +import static dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton.simpleButton; +import static dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoardLine.simpleLine; +import static dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard.inlineKeyBoard; +import static dev.struchkov.godfather.telegram.domain.keyboard.button.UrlButton.urlButton; import static dev.struchkov.haiti.utils.Strings.escapeMarkdown; @Component @@ -15,12 +22,24 @@ public class ConflictPrNotifyGenerator implements NotifyBoxAnswerGenerator { + + @Override + public BoxAnswer generate(ConflictResolveMrNotify notify) { + + final StringBuilder builder = new StringBuilder(Icons.GREEN_CIRCLE).append(" *Merge request conflict resolved!*") + .append(Icons.HR) + .append(escapeMarkdown(notify.getTitle())) + .append(Icons.HR) + .append(Icons.PROJECT).append(": ").append(escapeMarkdown(notify.getProjectName())).append("\n") + .append(Icons.TREE).append(": ").append(escapeMarkdown(notify.getSourceBranch())); + + final String notifyMessage = builder.toString(); + return boxAnswer( + notifyMessage, + inlineKeyBoard( + simpleLine( + simpleButton(Icons.VIEW, DELETE_MESSAGE), + urlButton(Icons.LINK, notify.getUrl()), + simpleButton(Icons.DISABLE_NOTIFY, "[" + BUTTON_ARG_DISABLE_NOTIFY_MR_ID + ":" + notify.getMrId() + ";" + BUTTON_ARG_CONFIRMATION + ":" + BUTTON_VALUE_FALSE + "]") + ) + ) + ); + } + + @Override + public String getNotifyType() { + return ConflictResolveMrNotify.TYPE; + } + +} diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/DiscussionNewNotifyGenerator.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/DiscussionNewNotifyGenerator.java index 2acf68f..c8d4cce 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/DiscussionNewNotifyGenerator.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/DiscussionNewNotifyGenerator.java @@ -9,8 +9,15 @@ import org.springframework.stereotype.Component; import java.util.List; import java.util.stream.Collectors; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_CONFIRMATION; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_VALUE_FALSE; +import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.DELETE_MESSAGE; import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer; -import static dev.struchkov.haiti.utils.Checker.checkNotNull; +import static dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton.simpleButton; +import static dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard.inlineKeyBoard; +import static dev.struchkov.godfather.telegram.domain.keyboard.button.UrlButton.urlButton; +import static dev.struchkov.haiti.utils.Checker.checkNotEmpty; import static dev.struchkov.haiti.utils.Strings.escapeMarkdown; @Component @@ -18,20 +25,27 @@ public class DiscussionNewNotifyGenerator implements NotifyBoxAnswerGenerator> notes = notify.getNotes(); - if (checkNotNull(notes)) { + if (checkNotEmpty(notes)) { builder.append("\n-- -- -- -- comments -- -- -- --\n") .append(convertNotes(notes)); } final String notifyMessage = builder.toString(); - return boxAnswer(notifyMessage); + return boxAnswer( + notifyMessage, + inlineKeyBoard( + simpleButton(Icons.VIEW, DELETE_MESSAGE), + urlButton(Icons.LINK, notify.getUrl()), + simpleButton(Icons.DISABLE_NOTIFY, "[" + BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID + ":" + notify.getThreadId() + ";" + BUTTON_ARG_CONFIRMATION + ":" + BUTTON_VALUE_FALSE + "]") + ) + ); } private String convertNotes(List> notes) { diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/NewCommentNotifyGenerator.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/NewCommentNotifyGenerator.java index 2181bb6..4959105 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/NewCommentNotifyGenerator.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/service/notify/NewCommentNotifyGenerator.java @@ -3,34 +3,58 @@ package dev.struchkov.bot.gitlab.telegram.service.notify; import dev.struchkov.bot.gitlab.context.domain.notify.comment.NewCommentNotify; import dev.struchkov.bot.gitlab.context.utils.Icons; import dev.struchkov.godfather.main.domain.BoxAnswer; +import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_CONFIRMATION; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_VALUE_FALSE; +import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.DELETE_MESSAGE; import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer; +import static dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton.simpleButton; +import static dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard.inlineKeyBoard; +import static dev.struchkov.godfather.telegram.domain.keyboard.button.UrlButton.urlButton; import static dev.struchkov.haiti.utils.Checker.checkNotNull; import static dev.struchkov.haiti.utils.Strings.escapeMarkdown; @Component +@RequiredArgsConstructor public class NewCommentNotifyGenerator implements NotifyBoxAnswerGenerator { @Override public BoxAnswer generate(NewCommentNotify notify) { - final StringBuilder builder = new StringBuilder(Icons.COMMENT).append(" [New answer in discussion](").append(notify.getUrl()).append(")"); + final StringBuilder builder = new StringBuilder(Icons.COMMENT).append(" *New answer in Thread*") + .append(Icons.HR) + .append(Icons.link(escapeMarkdown(notify.getMergeRequestName()), notify.getUrl())) + .append("\n"); if (checkNotNull(notify.getDiscussionMessage())) { - builder.append("\n-- -- discussion first message -- --\n") - .append("*").append(notify.getDiscussionAuthor()).append("*: ").append(escapeMarkdown(notify.getDiscussionMessage())); + builder.append("\n-- -- thread first message -- --\n") + .append("*").append(notify.getDiscussionAuthor()).append("*: ").append(escapeMarkdown(notify.getDiscussionMessage())) + .append("\n"); } if (checkNotNull(notify.getPreviousMessage())) { builder.append("\n-- -- -- previous message -- -- --\n") - .append("*").append(notify.getPreviousAuthor()).append("*: ").append(escapeMarkdown(notify.getPreviousMessage())); + .append("*").append(notify.getPreviousAuthor()).append("*: ").append(escapeMarkdown(notify.getPreviousMessage())) + .append("\n"); } - builder.append("\n-- -- -- --- new answer --- -- -- --\n") - .append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessage())); + if (checkNotNull(notify.getMessage())) { + builder.append("\n-- -- -- --- new answer --- -- -- --\n") + .append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessage())) + .append("\n"); + } final String messageNotify = builder.toString(); - return boxAnswer(messageNotify); + return boxAnswer( + messageNotify, + inlineKeyBoard( + simpleButton(Icons.VIEW, DELETE_MESSAGE), + urlButton(Icons.LINK, notify.getUrl()), + simpleButton(Icons.DISABLE_NOTIFY, "[" + BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID + ":" + notify.getThreadId() + ";" + BUTTON_ARG_CONFIRMATION + ":" + BUTTON_VALUE_FALSE + "]") + ) + ); } @Override diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/MenuConfig.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/MenuConfig.java index c7b2e00..a98d863 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/MenuConfig.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/MenuConfig.java @@ -2,9 +2,11 @@ package dev.struchkov.bot.gitlab.telegram.unit; import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest; +import dev.struchkov.bot.gitlab.context.domain.entity.Project; import dev.struchkov.bot.gitlab.context.service.AppSettingService; import dev.struchkov.bot.gitlab.context.service.MergeRequestsService; import dev.struchkov.bot.gitlab.context.service.NoteService; +import dev.struchkov.bot.gitlab.context.service.ProjectService; import dev.struchkov.bot.gitlab.context.utils.Icons; import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; import dev.struchkov.bot.gitlab.core.service.parser.ProjectParser; @@ -14,15 +16,16 @@ import dev.struchkov.godfather.main.domain.annotation.Unit; import dev.struchkov.godfather.main.domain.content.Mail; import dev.struchkov.godfather.simple.core.unit.AnswerText; import dev.struchkov.godfather.simple.core.unit.MainUnit; -import dev.struchkov.godfather.simple.data.StorylineContext; +import dev.struchkov.godfather.telegram.domain.attachment.LinkAttachment; import dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard; -import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending; +import dev.struchkov.godfather.telegram.main.core.util.Attachments; import dev.struchkov.haiti.utils.Checker; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.text.MessageFormat; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.ACCESS_ERROR; @@ -33,10 +36,13 @@ import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.GET_TASKS; import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.SETTINGS; import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.TEXT_ADD_NEW_PROJECT; import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer; +import static dev.struchkov.godfather.main.domain.BoxAnswer.replaceBoxAnswer; import static dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton.simpleButton; import static dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoardLine.simpleLine; import static dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard.inlineKeyBoard; import static dev.struchkov.godfather.telegram.simple.core.util.TriggerChecks.clickButtonRaw; +import static dev.struchkov.godfather.telegram.simple.core.util.TriggerChecks.isLinks; +import static java.util.Collections.singleton; /** * // TODO: 16.01.2021 Добавить описание. @@ -47,16 +53,17 @@ import static dev.struchkov.godfather.telegram.simple.core.util.TriggerChecks.cl @RequiredArgsConstructor public class MenuConfig { - private final StorylineContext context; - private final TelegramSending sending; - - private final ProjectParser projectParser; private final GitlabProperty gitlabProperty; private final PersonInformation personInformation; + + private final ProjectParser projectParser; + + private final ProjectService projectService; private final NoteService noteService; private final MergeRequestsService mergeRequestsService; private final AppSettingService settingService; + @Unit(value = ACCESS_ERROR, main = true) public AnswerText accessError() { return AnswerText.builder() @@ -92,12 +99,12 @@ public class MenuConfig { .answer(mail -> { final String messageText = "This is the bot menu, select a new item"; final InlineKeyBoard generalMenuKeyBoard = inlineKeyBoard( - simpleLine(simpleButton("Add project", TEXT_ADD_NEW_PROJECT)), - simpleLine( - simpleButton("My tasks", GET_TASKS), - simpleButton("Merge Request", GET_ASSIGNEE_MERGE_REQUEST) - ), - simpleLine(simpleButton("Settings", SETTINGS)) + simpleLine(simpleButton("Add project", TEXT_ADD_NEW_PROJECT)) +// simpleLine( +// simpleButton("My tasks", GET_TASKS), +// simpleButton("Merge Request", GET_ASSIGNEE_MERGE_REQUEST) +// ); +// simpleLine(simpleButton("Settings", SETTINGS)) ); return boxAnswer(messageText, generalMenuKeyBoard); } @@ -115,7 +122,7 @@ public class MenuConfig { ) { return AnswerText.builder() .triggerCheck(clickButtonRaw(TEXT_ADD_NEW_PROJECT)) - .answer(boxAnswer("Copy the url of the project and send it to me")) + .answer(replaceBoxAnswer("Send me links to repositories you want to track")) .next(addNewProject) .build(); } @@ -123,13 +130,20 @@ public class MenuConfig { @Unit(ADD_NEW_PROJECT) public AnswerText addNewProject() { return AnswerText.builder() + .triggerCheck(isLinks()) .answer(mail -> { - final String mailText = mail.getText(); - final String projectUrl = gitlabProperty.getProjectAddUrl() + mailText.replace(gitlabProperty.getBaseUrl(), "") - .substring(1) - .replace("/", "%2F"); - projectParser.parseByUrl(projectUrl); - return boxAnswer("Project added successfully"); + final List links = Attachments.findAllLinks(mail.getAttachments()); + for (LinkAttachment link : links) { + final String projectUrl = gitlabProperty.getProjectAddUrl() + link.getUrl().replace(gitlabProperty.getBaseUrl(), "") + .substring(1) + .replace("/", "%2F"); + final Project project = projectParser.parseByUrl(projectUrl); + final Set projectId = singleton(project.getId()); + projectService.notification(true, projectId); + projectService.processing(true, projectId); + mergeRequestsService.notificationByProjectId(true, projectId); + } + return boxAnswer("\uD83D\uDC4D Projects added successfully!"); }) .build(); } diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/AnswerNoteUnit.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/AnswerNoteUnit.java index 0dcc772..0848aad 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/AnswerNoteUnit.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/AnswerNoteUnit.java @@ -5,20 +5,19 @@ import dev.struchkov.bot.gitlab.context.domain.entity.Note; import dev.struchkov.bot.gitlab.context.service.AppSettingService; import dev.struchkov.bot.gitlab.context.service.DiscussionService; import dev.struchkov.bot.gitlab.context.service.NoteService; -import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.annotation.Unit; -import dev.struchkov.godfather.main.domain.content.Attachment; import dev.struchkov.godfather.main.domain.content.Mail; import dev.struchkov.godfather.simple.core.unit.AnswerText; import dev.struchkov.godfather.telegram.domain.attachment.LinkAttachment; -import dev.struchkov.godfather.telegram.domain.attachment.TelegramAttachmentType; import dev.struchkov.godfather.telegram.main.core.util.Attachments; +import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending; import dev.struchkov.haiti.utils.Checker; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; import java.text.MessageFormat; import java.util.List; +import java.util.concurrent.ScheduledExecutorService; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,21 +34,24 @@ public class AnswerNoteUnit { private final AppSettingService settingService; private final NoteService noteService; private final DiscussionService discussionService; + private final ScheduledExecutorService scheduledExecutorService; + private final TelegramSending telegramSending; - @Unit(value = ANSWER_NOTE, main = true) + //TODO [07.02.2023|uPagge]: Можно возвращать ссылку на ответ + @Unit(value = ANSWER_NOTE, global = true) public AnswerText answerNote() { return AnswerText.builder() .triggerCheck( mail -> { - final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId()); - if (isAccess) { - final boolean isFirstStart = settingService.isFirstStart(); - if (!isFirstStart) { - final List forwardMails = mail.getForwardMail(); - if (Checker.checkNotNull(forwardMails) && forwardMails.size() == 1) { - final Mail forwardMail = forwardMails.get(0); - return Attachments.findFirstLink(forwardMail.getAttachments()).isPresent(); - } + final List forwardMails = mail.getForwardMail(); + if (Checker.checkNotNull(forwardMails) && forwardMails.size() == 1) { + final Mail forwardMail = forwardMails.get(0); + final boolean isLink = Attachments.findFirstLink(forwardMail.getAttachments()) + .isPresent(); + if (isLink) { + final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId()); + final boolean firstStart = settingService.isFirstStart(); + return isAccess && !firstStart; } } return false; @@ -57,20 +59,19 @@ public class AnswerNoteUnit { ) .answer( mail -> { - final List attachments = mail.getForwardMail().get(0).getAttachments(); - for (Attachment attachment : attachments) { - if (TelegramAttachmentType.LINK.name().equals(attachment.getType())) { - final String url = ((LinkAttachment) attachment).getUrl(); - final Matcher matcher = NOTE_LINK.matcher(url); - if (matcher.find()) { - final String noteText = url.substring(matcher.start(), matcher.end()); - final Long noteId = Long.valueOf(noteText.replaceAll("#note_", "")); - final Note note = noteService.getByIdOrThrow(noteId); - final String discussionId = note.getDiscussion().getId(); - discussionService.answer(discussionId, MessageFormat.format("@{0}, {1}", note.getAuthor().getUserName(), mail.getText())); - return BoxAnswer.builder().build(); - } - } + final String noteUrl = Attachments.findFirstLink(mail.getForwardMail().get(0).getAttachments()) + .map(LinkAttachment::getUrl) + .orElseThrow(); + final Matcher matcher = NOTE_LINK.matcher(noteUrl); + if (matcher.find()) { + final String noteText = noteUrl.substring(matcher.start(), matcher.end()); + final Long noteId = Long.valueOf(noteText.replace("#note_", "")); + final Note note = noteService.getByIdOrThrow(noteId); + final String discussionId = note.getDiscussion().getId(); + discussionService.answer(discussionId, MessageFormat.format("@{0}, {1}", note.getAuthor().getUserName(), mail.getText())); + return boxAnswer( + "\uD83D\uDC4D Response sent successfully" + ); } return boxAnswer("Error"); } diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyMrUnit.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyMrUnit.java index 05ef5c2..90a5808 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyMrUnit.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyMrUnit.java @@ -14,7 +14,6 @@ import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import java.util.Optional; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -54,16 +53,13 @@ public class DisableNotifyMrUnit { public AnswerText disableNotifyMr() { return AnswerText.builder() .triggerCheck(mail -> { - final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId()); - if (isAccess) { + final boolean isDisableButtonClick = Attachments.findFirstButtonClick(mail.getAttachments()) + .flatMap(buttonClick -> buttonClick.getArgByType(BUTTON_ARG_DISABLE_NOTIFY_MR_ID)) + .isPresent(); + if (isDisableButtonClick) { + final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId()); final boolean isFirstStart = settingService.isFirstStart(); - if (!isFirstStart) { - final Optional optButtonClick = Attachments.findFirstButtonClick(mail.getAttachments()); - if (optButtonClick.isPresent()) { - final ButtonClickAttachment buttonClick = optButtonClick.get(); - return buttonClick.getArgByType(BUTTON_ARG_DISABLE_NOTIFY_MR_ID).isPresent(); - } - } + return isAccess && !isFirstStart; } return false; }) @@ -79,7 +75,7 @@ public class DisableNotifyMrUnit { .orElseThrow(); if (confirmation) { - mergeRequestsService.disableNotify(mrId); + mergeRequestsService.notification(false, mrId); scheduledExecutorService.schedule(() -> telegramSending.deleteMessage(mail.getPersonId(), clickButton.getMessageId()), 5, TimeUnit.SECONDS); return replaceBoxAnswer(SUCCESSFULLY_DISABLED); } else { diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyThreadUnit.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyThreadUnit.java new file mode 100644 index 0000000..024f4b4 --- /dev/null +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/DisableNotifyThreadUnit.java @@ -0,0 +1,92 @@ +package dev.struchkov.bot.gitlab.telegram.unit.command; + +import dev.struchkov.bot.gitlab.context.domain.PersonInformation; +import dev.struchkov.bot.gitlab.context.service.AppSettingService; +import dev.struchkov.bot.gitlab.context.service.DiscussionService; +import dev.struchkov.bot.gitlab.context.utils.Icons; +import dev.struchkov.godfather.main.domain.annotation.Unit; +import dev.struchkov.godfather.main.domain.content.Mail; +import dev.struchkov.godfather.simple.core.unit.AnswerText; +import dev.struchkov.godfather.telegram.domain.attachment.ButtonClickAttachment; +import dev.struchkov.godfather.telegram.domain.attachment.ButtonClickAttachment.Arg; +import dev.struchkov.godfather.telegram.main.core.util.Attachments; +import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_CONFIRMATION; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID; +import static dev.struchkov.bot.gitlab.telegram.utils.Const.BUTTON_VALUE_TRUE; +import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.DELETE_MESSAGE; +import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.DISABLE_NOTIFY_THREAD; +import static dev.struchkov.godfather.main.domain.BoxAnswer.replaceBoxAnswer; +import static dev.struchkov.godfather.main.domain.keyboard.button.SimpleButton.simpleButton; +import static dev.struchkov.godfather.main.domain.keyboard.simple.SimpleKeyBoardLine.simpleLine; +import static dev.struchkov.godfather.telegram.domain.keyboard.InlineKeyBoard.inlineKeyBoard; + +@Component +@RequiredArgsConstructor +public class DisableNotifyThreadUnit { + + public static final String WARNING_ABOUT_DISABLE_NOTIFY = Icons.DISABLE_NOTIFY + """ + *Disabling notifications* + + Are you sure you want to stop receiving notifications of new replies to this thread? + """; + public static final String SUCCESSFULLY_DISABLED = "Notifications successfully disabled for this thread"; + + private final DiscussionService discussionService; + private final PersonInformation personInformation; + private final AppSettingService settingService; + private final TelegramSending telegramSending; + + private final ScheduledExecutorService scheduledExecutorService; + + @Unit(value = DISABLE_NOTIFY_THREAD, global = true) + public AnswerText disableNotifyThread() { + return AnswerText.builder() + .triggerCheck(mail -> { + final boolean isDisableButtonClick = Attachments.findFirstButtonClick(mail.getAttachments()) + .flatMap(buttonClick -> buttonClick.getArgByType(BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID)) + .isPresent(); + if (isDisableButtonClick) { + final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId()); + final boolean isFirstStart = settingService.isFirstStart(); + return isAccess && !isFirstStart; + } + return false; + }) + .answer(mail -> { + final ButtonClickAttachment clickButton = Attachments.findFirstButtonClick(mail.getAttachments()).orElseThrow(); + final boolean confirmation = clickButton.getArgByType(BUTTON_ARG_CONFIRMATION) + .map(Arg::getValue) + .map(BUTTON_VALUE_TRUE::equals) + .orElseThrow(); + final String discussionId = clickButton.getArgByType(BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID) + .map(Arg::getValue) + .map(String::valueOf) + .orElseThrow(); + + if (confirmation) { + discussionService.notification(false, discussionId); + scheduledExecutorService.schedule(() -> telegramSending.deleteMessage(mail.getPersonId(), clickButton.getMessageId()), 5, TimeUnit.SECONDS); + return replaceBoxAnswer(SUCCESSFULLY_DISABLED); + } else { + return replaceBoxAnswer( + WARNING_ABOUT_DISABLE_NOTIFY, + inlineKeyBoard( + simpleLine( + simpleButton(Icons.YES, "[" + BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID + ":" + discussionId + ";" + BUTTON_ARG_CONFIRMATION + ":" + BUTTON_VALUE_TRUE + "]"), + simpleButton(Icons.NO, DELETE_MESSAGE) + ) + ) + ); + } + }) + .build(); + } + +} diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/EnableProjectNotify.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/EnableProjectNotify.java index 811c301..2db429b 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/EnableProjectNotify.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/command/EnableProjectNotify.java @@ -2,6 +2,7 @@ package dev.struchkov.bot.gitlab.telegram.unit.command; import dev.struchkov.bot.gitlab.context.domain.PersonInformation; import dev.struchkov.bot.gitlab.context.service.AppSettingService; +import dev.struchkov.bot.gitlab.context.service.MergeRequestsService; import dev.struchkov.bot.gitlab.context.service.ProjectService; import dev.struchkov.bot.gitlab.context.utils.Icons; import dev.struchkov.bot.gitlab.telegram.utils.UnitName; @@ -28,6 +29,7 @@ import static dev.struchkov.godfather.main.domain.BoxAnswer.replaceBoxAnswer; public class EnableProjectNotify { private final ProjectService projectService; + private final MergeRequestsService mergeRequestsService; private final AppSettingService settingService; private final PersonInformation personInformation; @@ -59,6 +61,7 @@ public class EnableProjectNotify { final Set setProjectId = Set.of(projectId); projectService.processing(true, setProjectId); projectService.notification(true, setProjectId); + mergeRequestsService.notificationByProjectId(true, setProjectId); return replaceBoxAnswer(mail.getId(), Icons.GOOD + " you will now receive notifications!"); } ) diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/flow/InitSettingFlow.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/flow/InitSettingFlow.java index 6906a76..5a4970c 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/flow/InitSettingFlow.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/unit/flow/InitSettingFlow.java @@ -14,7 +14,6 @@ import dev.struchkov.godfather.main.domain.annotation.Unit; import dev.struchkov.godfather.main.domain.content.Mail; import dev.struchkov.godfather.simple.core.unit.AnswerText; import dev.struchkov.godfather.simple.core.unit.MainUnit; -import dev.struchkov.godfather.simple.data.StorylineContext; import dev.struchkov.godfather.telegram.domain.attachment.ButtonClickAttachment; import dev.struchkov.godfather.telegram.main.core.util.Attachments; import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending; @@ -57,7 +56,6 @@ import static java.text.MessageFormat.format; public class InitSettingFlow { private final TelegramSending sending; - private final StorylineContext context; private final PersonInformation personInformation; @@ -138,7 +136,7 @@ public class InitSettingFlow { ) { return AnswerText.builder() .triggerCheck(clickButtonRaw("NO")) - .answer(replaceBoxAnswer("Okay, I won't scan public projects.")) + .answer(replaceBoxAnswer("\uD83D\uDC4C I won't scan public projects.")) .callBack( sentBox -> scheduledExecutorService.schedule(() -> sending.deleteMessage(sentBox.getPersonId(), sentBox.getMessageId()), 10, TimeUnit.SECONDS) ) @@ -217,7 +215,7 @@ public class InitSettingFlow { discussionParser.scanNewDiscussion(); final int discussionCount = discussionService.getAllIds().size() - oldCountThreads; - return replaceBoxAnswer(format(finalAnswer, pipelineCount, mrCount, pipelineCount, discussionCount)); + return replaceBoxAnswer(format(finalAnswer, projectCount, mrCount, pipelineCount, discussionCount)); }) .callBack( sentBox -> scheduledExecutorService.schedule(() -> sending.deleteMessage(sentBox.getPersonId(), sentBox.getMessageId()), 10, TimeUnit.SECONDS) @@ -260,6 +258,7 @@ public class InitSettingFlow { .answer(mail -> { final ButtonClickAttachment buttonClick = Attachments.findFirstButtonClick(mail.getAttachments()).orElseThrow(); if ("YES".equals(buttonClick.getRawCallBackData())) { + sending.replaceMessage(mail.getPersonId(), mail.getId(), boxAnswer("⌛I write down the available projects. This may take a long time.")); projectParser.parseAllProjectOwner(); settingService.ownerProjectScan(true); } else { @@ -378,7 +377,7 @@ public class InitSettingFlow { ) { return AnswerText.builder() .triggerPhrase("NO") - .answer(replaceBoxAnswer("Okay, I won't scan private projects.")) + .answer(replaceBoxAnswer("\uD83D\uDC4C I won't scan private projects.")) .callBack( sentBox -> scheduledExecutorService.schedule(() -> sending.deleteMessage(sentBox.getPersonId(), sentBox.getMessageId()), 10, TimeUnit.SECONDS) ) @@ -394,7 +393,11 @@ public class InitSettingFlow { .activeType(AFTER) .answer( boxAnswer( - "Do you want to enable automatic notification of new private projects available to you?", + """ + Do you want to enable automatic notification of new private projects available to you? + -- -- -- -- -- + I will be forced to scan all available private projects for this. I will not scan other entities in projects and send any notifications for these projects. + """, inlineKeyBoard( simpleLine( simpleButton("Yes", "YES"), @@ -416,6 +419,7 @@ public class InitSettingFlow { .answer(mail -> { final ButtonClickAttachment buttonClick = Attachments.findFirstButtonClick(mail.getAttachments()).orElseThrow(); if ("YES".equals(buttonClick.getRawCallBackData())) { + sending.replaceMessage(mail.getPersonId(), mail.getId(), boxAnswer("⌛I write down the available private projects. This may take a long time.")); projectParser.parseAllPrivateProject(); settingService.privateProjectScan(true); } else { diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/Const.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/Const.java index 5b0ae6c..0940f78 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/Const.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/Const.java @@ -9,6 +9,7 @@ public class Const { public static final String BUTTON_VALUE_TRUE = "t"; public static final String BUTTON_ARG_DISABLE_NOTIFY_MR_ID = "dis_mr_id"; + public static final String BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID = "dis_th_id"; public static final String BUTTON_ARG_ENABLE_NOTIFY_PROJECT_ID = "ena_p_id"; public static final String BUTTON_ARG_CONFIRMATION = "conf"; diff --git a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/UnitName.java b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/UnitName.java index db72850..ea6caaf 100644 --- a/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/UnitName.java +++ b/telegram-bot/src/main/java/dev/struchkov/bot/gitlab/telegram/utils/UnitName.java @@ -30,6 +30,7 @@ public final class UnitName { // команды public static final String DELETE_MESSAGE = "DELETE_MESSAGE"; public static final String DISABLE_NOTIFY_MR = "DISABLE_NOTIFY_MR"; + public static final String DISABLE_NOTIFY_THREAD = "DISABLE_NOTIFY_THREAD"; public static final String ENABLE_NOTIFY_PROJECT = "ENABLE_NOTIFY_PROJECT"; private UnitName() {