Merge branch 'develop' into feature/delayed_sending
This commit is contained in:
commit
8d8acb6496
135
README.md
135
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=
|
||||
```
|
||||
|
||||
После запуска необходимо отправить боту сообщение, чтобы пройти первичную настройку.
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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<Note> 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);
|
||||
}
|
||||
|
@ -45,4 +45,7 @@ public class MergeRequestForDiscussion {
|
||||
@Column(name = "web_url")
|
||||
private String webUrl;
|
||||
|
||||
@Column(name = "notification")
|
||||
private boolean notification;
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -0,0 +1,7 @@
|
||||
package dev.struchkov.bot.gitlab.context.domain.notify.level;
|
||||
|
||||
public enum DiscussionLevel {
|
||||
|
||||
WITHOUT_NOTIFY, NOTIFY_WITHOUT_CONTEXT, NOTIFY_WITH_CONTEXT
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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<Pair<String, String>> notes;
|
||||
|
||||
@Builder
|
||||
public DiscussionNewNotify(
|
||||
String threadId,
|
||||
String mrName,
|
||||
String authorName,
|
||||
String url,
|
||||
@ -27,6 +29,7 @@ public class DiscussionNewNotify extends TaskNotify {
|
||||
@Singular List<Pair<String, String>> notes
|
||||
) {
|
||||
super(authorName, url, discussionMessage);
|
||||
this.threadId = threadId;
|
||||
this.mrName = mrName;
|
||||
this.notes = notes;
|
||||
}
|
||||
|
@ -30,4 +30,6 @@ public interface DiscussionRepository {
|
||||
|
||||
void cleanOld();
|
||||
|
||||
void notification(boolean enable, String discussionId);
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,8 @@ public interface MergeRequestRepository {
|
||||
|
||||
Set<Long> findAllIds();
|
||||
|
||||
void disableNotify(Long mrId);
|
||||
void notification(boolean enable, Long mrId);
|
||||
|
||||
void notificationByProjectId(boolean enable, Set<Long> projectIds);
|
||||
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
}
|
||||
|
@ -43,4 +43,6 @@ public interface DiscussionService {
|
||||
|
||||
void cleanOld();
|
||||
|
||||
void notification(boolean enable, String discussionId);
|
||||
|
||||
}
|
||||
|
@ -38,6 +38,8 @@ public interface MergeRequestsService {
|
||||
|
||||
Set<Long> getAllIds();
|
||||
|
||||
void disableNotify(@NonNull Long mrId);
|
||||
void notification(boolean enable, @NonNull Long mrId);
|
||||
|
||||
void notificationByProjectId(boolean enable, @NonNull Set<Long> projectIds);
|
||||
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 = "⚙️";
|
||||
|
@ -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);
|
||||
|
@ -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<Note> 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<Discussion> updateAll(@NonNull List<Discussion> 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<Note> 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<Note> 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<String> 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<String> 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<Note> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<Long> 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();
|
||||
|
@ -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<Project> createAll(List<Project> newProjects) {
|
||||
return newProjects.stream()
|
||||
.map(this::create)
|
||||
.map(newProject -> create(newProject, true))
|
||||
.toList();
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,4 +62,9 @@ public class DiscussionRepositoryImpl implements DiscussionRepository {
|
||||
jpaRepository.removeAllByMergeRequestIsNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notification(boolean enable, String discussionId) {
|
||||
jpaRepository.notification(enable, discussionId);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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<Long> projectIds) {
|
||||
jpaRepository.notificationByProjectId(enable, projectIds);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,4 +28,8 @@ public interface DiscussionJpaRepository extends JpaRepository<Discussion, Strin
|
||||
@Query("DELETE FROM Discussion d WHERE d.id = :id")
|
||||
void deleteById(@Param("id") String id);
|
||||
|
||||
@Modifying
|
||||
@Query("UPDATE Discussion d SET d.notification = :enable WHERE d.id = :discussionId")
|
||||
void notification(@Param("enable") boolean enable, @Param("discussionId") String discussionId);
|
||||
|
||||
}
|
||||
|
@ -29,7 +29,11 @@ public interface MergeRequestJpaRepository extends JpaRepositoryImplementation<M
|
||||
Set<Long> 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<Long> projectIds);
|
||||
|
||||
}
|
||||
|
@ -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()) {
|
||||
|
@ -20,6 +20,9 @@
|
||||
<column name="project_private_scan" type="boolean" defaultValue="false">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="discussion_notify_level" type="varchar(64)" defaultValue="NOTIFY_WITH_CONTEXT">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
@ -160,6 +163,9 @@
|
||||
references="person(id)"/>
|
||||
</column>
|
||||
<column name="resolved" type="boolean"/>
|
||||
<column name="notification" type="boolean">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
|
||||
<createIndex tableName="discussion" indexName="i_discussion_responsible_id">
|
||||
|
@ -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<Object> config = List.of(menuConfig, unitConfig, commandUnit, deleteMessageUnit, disableNotifyMrUnit, enableProjectNotify);
|
||||
final List<Object> config = List.of(menuConfig, unitConfig, commandUnit, deleteMessageUnit, disableNotifyMrUnit,
|
||||
disableNotifyThreadUnit, enableProjectNotify);
|
||||
|
||||
return new StorylineMailService(
|
||||
unitPointerService,
|
||||
|
@ -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<Confl
|
||||
@Override
|
||||
public BoxAnswer generate(ConflictMrNotify notify) {
|
||||
|
||||
final StringBuilder builder = new StringBuilder(Icons.DANGEROUS).append(" *Attention! MergeRequest conflict | ").append(escapeMarkdown(notify.getProjectName())).append("*")
|
||||
final StringBuilder builder = new StringBuilder(Icons.DANGEROUS).append(" *Attention. MergeRequest conflict!*")
|
||||
.append(Icons.HR)
|
||||
.append(link(notify.getTitle(), notify.getUrl()));
|
||||
.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);
|
||||
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
|
||||
|
@ -0,0 +1,50 @@
|
||||
package dev.struchkov.bot.gitlab.telegram.service.notify;
|
||||
|
||||
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictResolveMrNotify;
|
||||
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.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
|
||||
public class ConflictResolvePrNotifyGenerator implements NotifyBoxAnswerGenerator<ConflictResolveMrNotify> {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
@ -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<Di
|
||||
|
||||
@Override
|
||||
public BoxAnswer generate(DiscussionNewNotify notify) {
|
||||
final StringBuilder builder = new StringBuilder(Icons.TASK).append(" [New discussion](").append(notify.getUrl()).append(")")
|
||||
final StringBuilder builder = new StringBuilder(Icons.TASK).append(" *New Thread in your MR*")
|
||||
.append(Icons.HR)
|
||||
.append(escapeMarkdown(notify.getMrName()))
|
||||
.append(Icons.link(escapeMarkdown(notify.getMrName()), notify.getUrl()))
|
||||
.append(Icons.HR)
|
||||
.append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessageTask()));
|
||||
|
||||
final List<Pair<String, String>> 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<Pair<String, String>> notes) {
|
||||
|
@ -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<NewCommentNotify> {
|
||||
|
||||
@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
|
||||
|
@ -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<Mail> accessError() {
|
||||
return AnswerText.<Mail>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.<Mail>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<Mail> addNewProject() {
|
||||
return AnswerText.<Mail>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<LinkAttachment> 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<Long> projectId = singleton(project.getId());
|
||||
projectService.notification(true, projectId);
|
||||
projectService.processing(true, projectId);
|
||||
mergeRequestsService.notificationByProjectId(true, projectId);
|
||||
}
|
||||
return boxAnswer("\uD83D\uDC4D Projects added successfully!");
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
@ -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<Mail> answerNote() {
|
||||
return AnswerText.<Mail>builder()
|
||||
.triggerCheck(
|
||||
mail -> {
|
||||
final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId());
|
||||
if (isAccess) {
|
||||
final boolean isFirstStart = settingService.isFirstStart();
|
||||
if (!isFirstStart) {
|
||||
final List<Mail> forwardMails = mail.getForwardMail();
|
||||
if (Checker.checkNotNull(forwardMails) && forwardMails.size() == 1) {
|
||||
final Mail forwardMail = forwardMails.get(0);
|
||||
return Attachments.findFirstLink(forwardMail.getAttachments()).isPresent();
|
||||
}
|
||||
final List<Mail> 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<Attachment> 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");
|
||||
}
|
||||
|
@ -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<Mail> disableNotifyMr() {
|
||||
return AnswerText.<Mail>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<ButtonClickAttachment> 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 {
|
||||
|
@ -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<Mail> disableNotifyThread() {
|
||||
return AnswerText.<Mail>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();
|
||||
}
|
||||
|
||||
}
|
@ -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<Long> 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!");
|
||||
}
|
||||
)
|
||||
|
@ -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.<Mail>builder()
|
||||
.triggerCheck(clickButtonRaw("NO"))
|
||||
.answer(replaceBoxAnswer("Okay, I won't scan public projects."))
|
||||
.answer(replaceBoxAnswer("\uD83D\uDC4C I won't scan public projects."))
|
||||
.<Integer>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));
|
||||
})
|
||||
.<Integer>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.<Mail>builder()
|
||||
.triggerPhrase("NO")
|
||||
.answer(replaceBoxAnswer("Okay, I won't scan private projects."))
|
||||
.answer(replaceBoxAnswer("\uD83D\uDC4C I won't scan private projects."))
|
||||
.<Integer>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 {
|
||||
|
@ -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";
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user