Compare commits

...

2 Commits

22 changed files with 266 additions and 69 deletions

View File

@ -40,6 +40,9 @@ public class Discussion {
@Column(name = "resolved") @Column(name = "resolved")
private Boolean resolved; private Boolean resolved;
@Column(name = "notification")
private boolean notification;
@ManyToOne(optional = false, cascade = CascadeType.REMOVE) @ManyToOne(optional = false, cascade = CascadeType.REMOVE)
@JoinTable( @JoinTable(
name = "discussion_merge_request", name = "discussion_merge_request",

View File

@ -45,4 +45,7 @@ public class MergeRequestForDiscussion {
@Column(name = "web_url") @Column(name = "web_url")
private String webUrl; private String webUrl;
@Column(name = "notification")
private boolean notification;
} }

View File

@ -9,6 +9,7 @@ public final class NewCommentNotify implements Notify {
public static final String TYPE = "NewCommentNotify"; public static final String TYPE = "NewCommentNotify";
private final String threadId;
private final String mergeRequestName; private final String mergeRequestName;
private final String url; private final String url;
private final String discussionMessage; private final String discussionMessage;
@ -21,6 +22,7 @@ public final class NewCommentNotify implements Notify {
@Builder @Builder
public NewCommentNotify( public NewCommentNotify(
String threadId,
String mergeRequestName, String mergeRequestName,
String url, String url,
String discussionMessage, String discussionMessage,
@ -31,6 +33,7 @@ public final class NewCommentNotify implements Notify {
String message, String message,
int numberNotes int numberNotes
) { ) {
this.threadId = threadId;
this.mergeRequestName = mergeRequestName; this.mergeRequestName = mergeRequestName;
this.url = url; this.url = url;
this.discussionMessage = discussionMessage; this.discussionMessage = discussionMessage;

View File

@ -15,11 +15,13 @@ public class DiscussionNewNotify extends TaskNotify {
public static final String TYPE = "DiscussionNewNotify"; public static final String TYPE = "DiscussionNewNotify";
private final String threadId;
private final String mrName; private final String mrName;
private final List<Pair<String, String>> notes; private final List<Pair<String, String>> notes;
@Builder @Builder
public DiscussionNewNotify( public DiscussionNewNotify(
String threadId,
String mrName, String mrName,
String authorName, String authorName,
String url, String url,
@ -27,6 +29,7 @@ public class DiscussionNewNotify extends TaskNotify {
@Singular List<Pair<String, String>> notes @Singular List<Pair<String, String>> notes
) { ) {
super(authorName, url, discussionMessage); super(authorName, url, discussionMessage);
this.threadId = threadId;
this.mrName = mrName; this.mrName = mrName;
this.notes = notes; this.notes = notes;
} }

View File

@ -30,4 +30,6 @@ public interface DiscussionRepository {
void cleanOld(); void cleanOld();
void notification(boolean enable, String discussionId);
} }

View File

@ -1,5 +1,7 @@
package dev.struchkov.bot.gitlab.context.service; 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(); boolean isPrivateProjectScan();
DiscussionLevel getLevelDiscussionNotify();
} }

View File

@ -43,4 +43,6 @@ public interface DiscussionService {
void cleanOld(); void cleanOld();
void notification(boolean enable, String discussionId);
} }

View File

@ -13,7 +13,7 @@ import java.util.Set;
*/ */
public interface ProjectService { public interface ProjectService {
Project create(@NonNull Project project); Project create(@NonNull Project project, boolean sendNotify);
Project update(@NonNull Project project); Project update(@NonNull Project project);

View File

@ -1,6 +1,7 @@
package dev.struchkov.bot.gitlab.core.service.impl; package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.entity.AppSetting; 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.repository.AppSettingRepository;
import dev.struchkov.bot.gitlab.context.service.AppSettingService; import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.haiti.context.exception.NotFoundException; import dev.struchkov.haiti.context.exception.NotFoundException;
@ -79,6 +80,11 @@ public class AppSettingServiceImpl implements AppSettingService {
return getAppSetting().isProjectPrivateScan(); return getAppSetting().isProjectPrivateScan();
} }
@Override
public DiscussionLevel getLevelDiscussionNotify() {
return getAppSetting().getDiscussionNotifyLevel();
}
private AppSetting getAppSetting() { private AppSetting getAppSetting() {
return appSettingRepository.findById(KEY) return appSettingRepository.findById(KEY)
.orElseThrow(NOT_FOUND_SETTINGS); .orElseThrow(NOT_FOUND_SETTINGS);

View File

@ -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.Note;
import dev.struchkov.bot.gitlab.context.domain.entity.Person; 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.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.DiscussionNewNotify;
import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskCloseNotify; import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskCloseNotify;
import dev.struchkov.bot.gitlab.context.repository.DiscussionRepository; 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.DiscussionService;
import dev.struchkov.bot.gitlab.context.service.NotifyService; import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty; 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.regex.Pattern;
import java.util.stream.Collectors; 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.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.Checker.checkNotNull; import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static java.lang.Boolean.FALSE; import static java.lang.Boolean.FALSE;
@ -53,24 +57,33 @@ import static java.lang.Boolean.FALSE;
public class DiscussionServiceImpl implements DiscussionService { public class DiscussionServiceImpl implements DiscussionService {
protected static final Pattern PATTERN = Pattern.compile("@[\\w]+"); protected static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final OkHttpClient client = new OkHttpClient();
private final DiscussionRepository repository; 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 GitlabProperty gitlabProperty;
private final PersonProperty personProperty; private final PersonProperty personProperty;
private final NotifyService notifyService;
@Override @Override
@Transactional @Transactional
public Discussion create(@NonNull Discussion discussion) { public Discussion create(@NonNull Discussion discussion) {
final List<Note> notes = discussion.getNotes(); final List<Note> notes = discussion.getNotes();
if (isNeedNotifyNewNote(discussion)) { final DiscussionLevel levelDiscussionNotify = settingService.getLevelDiscussionNotify();
notifyNewDiscussion(discussion); if (!WITHOUT_NOTIFY.equals(levelDiscussionNotify)) {
discussion.setNotification(true);
if (isNeedNotifyNewNote(discussion)) {
notifyNewDiscussion(discussion);
} else {
notes.forEach(note -> notificationPersonal(discussion, note));
}
} else { } else {
notes.forEach(note -> notificationPersonal(discussion, note)); discussion.setNotification(false);
} }
final boolean resolved = discussion.getNotes().stream() final boolean resolved = discussion.getNotes().stream()
@ -89,6 +102,7 @@ public class DiscussionServiceImpl implements DiscussionService {
discussion.setResponsible(oldDiscussion.getResponsible()); discussion.setResponsible(oldDiscussion.getResponsible());
discussion.setMergeRequest(oldDiscussion.getMergeRequest()); discussion.setMergeRequest(oldDiscussion.getMergeRequest());
discussion.setNotification(oldDiscussion.isNotification());
final Person responsiblePerson = discussion.getResponsible(); final Person responsiblePerson = discussion.getResponsible();
if (checkNotNull(responsiblePerson)) { if (checkNotNull(responsiblePerson)) {
@ -104,7 +118,10 @@ public class DiscussionServiceImpl implements DiscussionService {
} }
} }
} }
notifyUpdateNote(oldDiscussion, discussion);
if (oldDiscussion.isNotification()) {
notifyUpdateNote(oldDiscussion, discussion);
}
final boolean resolved = discussion.getNotes().stream() final boolean resolved = discussion.getNotes().stream()
.allMatch(note -> note.isResolvable() && note.getResolved()); .allMatch(note -> note.isResolvable() && note.getResolved());
@ -123,6 +140,7 @@ public class DiscussionServiceImpl implements DiscussionService {
final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest(); final MergeRequestForDiscussion mergeRequest = discussion.getMergeRequest();
final DiscussionNewNotify.DiscussionNewNotifyBuilder notifyBuilder = DiscussionNewNotify.builder() final DiscussionNewNotify.DiscussionNewNotifyBuilder notifyBuilder = DiscussionNewNotify.builder()
.threadId(discussion.getId())
.mrName(mergeRequest.getTitle()) .mrName(mergeRequest.getTitle())
.authorName(firstNote.getAuthor().getName()) .authorName(firstNote.getAuthor().getName())
.discussionMessage(firstNote.getBody()) .discussionMessage(firstNote.getBody())
@ -291,29 +309,40 @@ public class DiscussionServiceImpl implements DiscussionService {
log.debug("Конец очистки старых дискуссий"); log.debug("Конец очистки старых дискуссий");
} }
@Override
@Transactional
public void notification(boolean enable, String discussionId) {
repository.notification(enable, discussionId);
}
private void notifyNewAnswer(Discussion discussion, Note note) { private void notifyNewAnswer(Discussion discussion, Note note) {
if (!personInformation.getId().equals(note.getAuthor().getId())) { final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
if (!WITHOUT_NOTIFY.equals(discussionLevel)
&& !personInformation.getId().equals(note.getAuthor().getId())) {
final Note firstNote = discussion.getFirstNote(); final Note firstNote = discussion.getFirstNote();
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder() final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder()
.threadId(discussion.getId())
.url(note.getWebUrl())
.mergeRequestName(discussion.getMergeRequest().getTitle()); .mergeRequestName(discussion.getMergeRequest().getTitle());
if (prevLastNote.isPresent()) { if (NOTIFY_WITH_CONTEXT.equals(discussionLevel)) {
final Note prevNote = prevLastNote.get(); final Optional<Note> prevLastNote = discussion.getPrevLastNote();
notifyBuilder.previousMessage(prevNote.getBody()); if (prevLastNote.isPresent()) {
notifyBuilder.previousAuthor(prevNote.getAuthor().getName()); 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( notifyService.send(notifyBuilder.build());
notifyBuilder
.url(note.getWebUrl())
.discussionMessage(firstNote.getBody())
.discussionAuthor(firstNote.getAuthor().getName())
.message(note.getBody())
.authorName(note.getAuthor().getName())
.build()
);
} }
} }
@ -321,32 +350,43 @@ public class DiscussionServiceImpl implements DiscussionService {
* Уведомляет пользователя, если его никнейм упоминается в комментарии. * Уведомляет пользователя, если его никнейм упоминается в комментарии.
*/ */
protected void notificationPersonal(Discussion discussion, Note note) { protected void notificationPersonal(Discussion discussion, Note note) {
final Matcher matcher = PATTERN.matcher(note.getBody()); final DiscussionLevel discussionLevel = settingService.getLevelDiscussionNotify();
final Set<String> recipientsLogins = new HashSet<>(); if (!WITHOUT_NOTIFY.equals(discussionLevel)) {
while (matcher.find()) { final Matcher matcher = PATTERN.matcher(note.getBody());
final String login = matcher.group(0).replace("@", ""); final Set<String> recipientsLogins = new HashSet<>();
recipientsLogins.add(login);
}
if (recipientsLogins.contains(personInformation.getUsername())) {
final Optional<Note> prevLastNote = discussion.getPrevLastNote();
final Note firstNote = discussion.getFirstNote();
final NewCommentNotify.NewCommentNotifyBuilder notifyBuilder = NewCommentNotify.builder() while (matcher.find()) {
.mergeRequestName(discussion.getMergeRequest().getTitle()) final String login = matcher.group(0).replace("@", "");
.url(note.getWebUrl()) recipientsLogins.add(login);
.discussionMessage(firstNote.getBody())
.discussionAuthor(firstNote.getAuthor().getName());
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());
} }
notifyService.send(notifyBuilder.build()); 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());
}
} }
} }

View File

@ -33,11 +33,13 @@ public class ProjectServiceImpl implements ProjectService {
@Override @Override
@Transactional @Transactional
public Project create(@NonNull Project project) { public Project create(@NonNull Project project, boolean sendNotify) {
final Project newProject = repository.save(project); final Project newProject = repository.save(project);
final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName(); if (sendNotify) {
notifyAboutNewProject(newProject, authorName); final String authorName = personService.getByIdOrThrown(newProject.getCreatorId()).getName();
notifyAboutNewProject(newProject, authorName);
}
return newProject; return newProject;
} }
@ -57,7 +59,7 @@ public class ProjectServiceImpl implements ProjectService {
@Transactional @Transactional
public List<Project> createAll(List<Project> newProjects) { public List<Project> createAll(List<Project> newProjects) {
return newProjects.stream() return newProjects.stream()
.map(this::create) .map(newProject -> create(newProject, true))
.toList(); .toList();
} }

View File

@ -96,7 +96,7 @@ public class ProjectParser {
if (!projectService.existsById(projectJson.getId())) { if (!projectService.existsById(projectJson.getId())) {
createNewPersons(List.of(projectJson)); createNewPersons(List.of(projectJson));
final Project newProject = conversionService.convert(projectJson, Project.class); final Project newProject = conversionService.convert(projectJson, Project.class);
return projectService.create(newProject); return projectService.create(newProject, false);
} else { } else {
return projectService.getByIdOrThrow(projectJson.getId()); return projectService.getByIdOrThrow(projectJson.getId());
} }

View File

@ -62,4 +62,9 @@ public class DiscussionRepositoryImpl implements DiscussionRepository {
jpaRepository.removeAllByMergeRequestIsNull(); jpaRepository.removeAllByMergeRequestIsNull();
} }
@Override
public void notification(boolean enable, String discussionId) {
jpaRepository.notification(enable, discussionId);
}
} }

View File

@ -28,4 +28,8 @@ public interface DiscussionJpaRepository extends JpaRepository<Discussion, Strin
@Query("DELETE FROM Discussion d WHERE d.id = :id") @Query("DELETE FROM Discussion d WHERE d.id = :id")
void deleteById(@Param("id") String 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);
} }

View File

@ -163,6 +163,9 @@
references="person(id)"/> references="person(id)"/>
</column> </column>
<column name="resolved" type="boolean"/> <column name="resolved" type="boolean"/>
<column name="notification" type="boolean">
<constraints nullable="false"/>
</column>
</createTable> </createTable>
<createIndex tableName="discussion" indexName="i_discussion_responsible_id"> <createIndex tableName="discussion" indexName="i_discussion_responsible_id">

View File

@ -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.AnswerNoteUnit;
import dev.struchkov.bot.gitlab.telegram.unit.command.DeleteMessageUnit; 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.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.command.EnableProjectNotify;
import dev.struchkov.bot.gitlab.telegram.unit.flow.InitSettingFlow; import dev.struchkov.bot.gitlab.telegram.unit.flow.InitSettingFlow;
import dev.struchkov.godfather.main.core.unit.TypeUnit; import dev.struchkov.godfather.main.core.unit.TypeUnit;
@ -80,9 +81,11 @@ public class TelegramBotConfig {
AnswerNoteUnit commandUnit, AnswerNoteUnit commandUnit,
DeleteMessageUnit deleteMessageUnit, DeleteMessageUnit deleteMessageUnit,
DisableNotifyMrUnit disableNotifyMrUnit, DisableNotifyMrUnit disableNotifyMrUnit,
DisableNotifyThreadUnit disableNotifyThreadUnit,
EnableProjectNotify enableProjectNotify 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( return new StorylineMailService(
unitPointerService, unitPointerService,

View File

@ -9,6 +9,9 @@ import org.springframework.stereotype.Component;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; 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.bot.gitlab.telegram.utils.UnitName.DELETE_MESSAGE;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer; 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.button.SimpleButton.simpleButton;
@ -39,7 +42,8 @@ public class DiscussionNewNotifyGenerator implements NotifyBoxAnswerGenerator<Di
notifyMessage, notifyMessage,
inlineKeyBoard( inlineKeyBoard(
simpleButton(Icons.VIEW, DELETE_MESSAGE), simpleButton(Icons.VIEW, DELETE_MESSAGE),
urlButton(Icons.LINK, notify.getUrl()) urlButton(Icons.LINK, notify.getUrl()),
simpleButton(Icons.DISABLE_NOTIFY, "[" + BUTTON_ARG_DISABLE_NOTIFY_THREAD_ID + ":" + notify.getThreadId() + ";" + BUTTON_ARG_CONFIRMATION + ":" + BUTTON_VALUE_FALSE + "]")
) )
); );
} }

View File

@ -3,38 +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.domain.notify.comment.NewCommentNotify;
import dev.struchkov.bot.gitlab.context.utils.Icons; import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.godfather.main.domain.BoxAnswer; import dev.struchkov.godfather.main.domain.BoxAnswer;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; 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.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.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown; import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component @Component
@RequiredArgsConstructor
public class NewCommentNotifyGenerator implements NotifyBoxAnswerGenerator<NewCommentNotify> { public class NewCommentNotifyGenerator implements NotifyBoxAnswerGenerator<NewCommentNotify> {
@Override @Override
public BoxAnswer generate(NewCommentNotify notify) { public BoxAnswer generate(NewCommentNotify notify) {
final StringBuilder builder = new StringBuilder(Icons.COMMENT).append(" *New answer in Thread*") final StringBuilder builder = new StringBuilder(Icons.COMMENT).append(" *New answer in Thread*")
.append(Icons.HR) .append(Icons.HR)
.append(escapeMarkdown(notify.getMergeRequestName())); .append(Icons.link(escapeMarkdown(notify.getMergeRequestName()), notify.getUrl()))
.append("\n");
if (checkNotNull(notify.getDiscussionMessage())) { if (checkNotNull(notify.getDiscussionMessage())) {
builder.append("\n-- -- thread first message -- --\n") builder.append("\n-- -- thread first message -- --\n")
.append("*").append(notify.getDiscussionAuthor()).append("*: ").append(escapeMarkdown(notify.getDiscussionMessage())); .append("*").append(notify.getDiscussionAuthor()).append("*: ").append(escapeMarkdown(notify.getDiscussionMessage()))
.append("\n");
} }
if (checkNotNull(notify.getPreviousMessage())) { if (checkNotNull(notify.getPreviousMessage())) {
builder.append("\n-- -- -- previous message -- -- --\n") 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");
} }
if (checkNotNull(notify.getMessage())) { if (checkNotNull(notify.getMessage())) {
builder.append("\n-- -- -- --- new answer --- -- -- --\n") builder.append("\n-- -- -- --- new answer --- -- -- --\n")
.append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessage())); .append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessage()))
.append("\n");
} }
final String messageNotify = builder.toString(); 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 @Override

View File

@ -14,7 +14,6 @@ import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.Optional;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -54,16 +53,13 @@ public class DisableNotifyMrUnit {
public AnswerText<Mail> disableNotifyMr() { public AnswerText<Mail> disableNotifyMr() {
return AnswerText.<Mail>builder() return AnswerText.<Mail>builder()
.triggerCheck(mail -> { .triggerCheck(mail -> {
final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId()); final boolean isDisableButtonClick = Attachments.findFirstButtonClick(mail.getAttachments())
if (isAccess) { .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(); final boolean isFirstStart = settingService.isFirstStart();
if (!isFirstStart) { return isAccess && !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 false; return false;
}) })

View File

@ -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();
}
}

View File

@ -9,6 +9,7 @@ public class Const {
public static final String BUTTON_VALUE_TRUE = "t"; 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_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_ENABLE_NOTIFY_PROJECT_ID = "ena_p_id";
public static final String BUTTON_ARG_CONFIRMATION = "conf"; public static final String BUTTON_ARG_CONFIRMATION = "conf";

View File

@ -30,6 +30,7 @@ public final class UnitName {
// команды // команды
public static final String DELETE_MESSAGE = "DELETE_MESSAGE"; public static final String DELETE_MESSAGE = "DELETE_MESSAGE";
public static final String DISABLE_NOTIFY_MR = "DISABLE_NOTIFY_MR"; 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"; public static final String ENABLE_NOTIFY_PROJECT = "ENABLE_NOTIFY_PROJECT";
private UnitName() { private UnitName() {