Вынес генерацию уведомлений в NotifyBoxAnswerGenerator
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is passing

This commit is contained in:
Struchkov Mark 2023-01-15 16:46:32 +03:00
parent 0c0fef6276
commit 246e4235c1
Signed by: upagge
GPG Key ID: D3018BE7BA428CA6
72 changed files with 1354 additions and 726 deletions

View File

@ -97,4 +97,9 @@ steps:
commands:
- echo "$DOCKER_REGISTRY_TOKEN" | docker login docker.io --username $DOCKER_REGISTRY_USER --password-stdin
- docker buildx create --use
- docker buildx build --push --platform linux/amd64,linux/arm64/v8 -t "$DOCKER_IMAGE_NAME:latest" -t "$DOCKER_IMAGE_NAME:$DRONE_TAG" .
- docker buildx build --push --platform linux/amd64,linux/arm64/v8 -t "$DOCKER_IMAGE_NAME:latest" -t "$DOCKER_IMAGE_NAME:$DRONE_TAG" .
---
kind: signature
hmac: 1bb00c9edf1c37a2f36c92ea6c1cb9023630b05550b4dc3148c6f5b30cad4af6
...

View File

@ -1,20 +1,28 @@
package dev.struchkov.bot.gitlab.context.domain;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* @author upagge 17.01.2021
*/
@Getter
@RequiredArgsConstructor
public enum PipelineStatus {
CREATED,
WAITING_FOR_RESOURCE,
PREPARING,
PENDING,
RUNNING,
SUCCESS,
FAILED,
CANCELED,
SKIPPED,
MANUAL,
SCHEDULED
CREATED("\uD83C\uDD95"),
WAITING_FOR_RESOURCE("\uD83D\uDCA2"),
PREPARING("♿️"),
PENDING("⚠️"),
RUNNING("\uD83D\uDD04"),
SUCCESS(""),
FAILED(""),
CANCELED("\uD83D\uDEAB"),
SKIPPED("\uD83D\uDD18"),
MANUAL("\uD83D\uDD79"),
SCHEDULED("\uD83D\uDD52"),
NULL("\uD83C\uDD95");
private final String icon;
}

View File

@ -26,4 +26,7 @@ public class AppSetting {
@Column(name = "first_start")
private boolean firstStart;
@Column(name = "enable_notify")
private boolean enableNotify;
}

View File

@ -38,7 +38,7 @@ public class Discussion {
@Column(name = "resolved")
private Boolean resolved;
@ManyToOne
@ManyToOne(optional = false)
@JoinTable(
name = "discussion_merge_request",
joinColumns = @JoinColumn(name = "discussion_id"),

View File

@ -1,35 +1,37 @@
package dev.struchkov.bot.gitlab.context.domain.notify;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Strings;
import lombok.Builder;
import java.text.MessageFormat;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
import lombok.Getter;
/**
* @author upagge 15.01.2021
*/
public record NewProjectNotify(
String projectName,
String projectUrl,
String projectDescription,
String authorName
) implements Notify {
@Getter
public final class NewProjectNotify implements Notify {
public static final String TYPE = "NewProjectNotify";
private final String projectName;
private final String projectUrl;
private final String projectDescription;
private final String authorName;
@Builder
public NewProjectNotify {
public NewProjectNotify(
String projectName,
String projectUrl,
String projectDescription,
String authorName
) {
this.projectName = projectName;
this.projectUrl = projectUrl;
this.projectDescription = projectDescription;
this.authorName = authorName;
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *New project*{1}[{2}]({3}){1}{4}{5}: {6}",
Smile.FUN.getValue(), Smile.HR.getValue(), projectName, projectUrl,
(projectDescription != null && !"".equals(projectDescription)) ? escapeMarkdown(projectDescription) + Smile.HR : Strings.EMPTY,
Smile.AUTHOR.getValue(), authorName
);
public String getType() {
return TYPE;
}
}

View File

@ -2,6 +2,6 @@ package dev.struchkov.bot.gitlab.context.domain.notify;
public interface Notify {
String generateMessage();
String getType();
}

View File

@ -1,19 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify;
import lombok.Builder;
/**
* @author upagge 20.09.2020
*/
public record SimpleTextNotify(String message) implements Notify {
@Builder
public SimpleTextNotify {
}
@Override
public String generateMessage() {
return message;
}
}

View File

@ -1,52 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.comment;
import dev.struchkov.bot.gitlab.context.domain.Answer;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Strings;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
import java.util.List;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Strings.TWO_NEW_LINE;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Getter
public class AnswerCommentNotify implements Notify {
private final String youMessage;
private final String url;
private final List<Answer> answers;
@Builder
protected AnswerCommentNotify(
String youMessage,
String url,
List<Answer> answers
) {
this.youMessage = youMessage;
this.url = url;
this.answers = answers;
}
@Override
public String generateMessage() {
final String answerText = answers.stream()
.map(answer -> answer.getAuthorName() + ": " + answer.getMessage().substring(0, Math.min(answer.getMessage().length(), 500)))
.collect(Collectors.joining(TWO_NEW_LINE));
return MessageFormat.format(
"{0} *Новые ответы* на [комментарий]({1}){2}" +
"{3}{2}" +
"{4}",
Smile.COMMENT,
url,
Smile.HR,
escapeMarkdown(Strings.cutoff(youMessage, 180)),
escapeMarkdown(answerText)
);
}
}

View File

@ -1,41 +1,45 @@
package dev.struchkov.bot.gitlab.context.domain.notify.comment;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Getter
public final class NewCommentNotify implements Notify {
public static final String TYPE = "NewCommentNotify";
private final String url;
private final String discussionMessage;
private final String discussionAuthor;
private final String previousMessage;
private final String previousAuthor;
private final String authorName;
private final String message;
@Builder
public NewCommentNotify(
String url,
String discussionMessage,
String discussionAuthor,
String previousMessage,
String previousAuthor,
String authorName,
String message
) {
this.url = url;
this.discussionMessage = discussionMessage;
this.discussionAuthor = discussionAuthor;
this.previousMessage = previousMessage;
this.previousAuthor = previousAuthor;
this.authorName = authorName;
this.message = message;
}
@Builder
public record NewCommentNotify(
String url,
String discussionMessage,
String discussionAuthor,
String previousMessage,
String previousAuthor,
String authorName,
String message
) implements Notify {
@Override
public String generateMessage() {
final StringBuilder builder = new StringBuilder(Smile.COMMENT.getValue()).append(" [New answer in discussion](").append(url).append(")\n--- --- --- ---");
if (checkNotNull(discussionMessage)) {
builder.append("\n-- -- discussion first message -- --\n")
.append("*").append(discussionAuthor).append("*: ").append(escapeMarkdown(discussionMessage));
}
if (checkNotNull(previousMessage)) {
builder.append("\n-- -- -- previous message -- -- --\n")
.append("*").append(previousAuthor).append("*: ").append(escapeMarkdown(previousMessage));
}
builder.append("\n-- -- -- --- new answer --- -- -- --\n")
.append("*").append(authorName).append("*: ").append(escapeMarkdown(message));
return builder.toString();
public String getType() {
return TYPE;
}
}

View File

@ -1,14 +1,13 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
@Getter
public class ConflictPrNotify extends PrNotify {
public static final String TYPE = "ConflictPrNotify";
private final String sourceBranch;
@Builder
@ -23,11 +22,8 @@ public class ConflictPrNotify extends PrNotify {
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Attention! MergeRequest conflict | {4}*{1}[{2}]({3})",
Smile.DANGEROUS.getValue(), Smile.HR.getValue(), title, url, projectName, sourceBranch
);
public String getType() {
return TYPE;
}
}

View File

@ -1,36 +0,0 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
/**
* // TODO: 11.10.2020 Добавить описание.
*
* @author upagge 11.10.2020
*/
@Getter
//TODO [28.01.2022]: Решить доработать и оставить или удалить
public class ForgottenSmartPrNotify extends PrNotify {
@Builder
protected ForgottenSmartPrNotify(
String title,
String url,
String projectName,
String repositorySlug
) {
super(projectName, title, url);
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *MergeRequest Review Reminder | {4}*{3}[{1}]({2})",
Smile.SMART.getValue(), title, url, Smile.HR.getValue(), projectName
);
}
}

View File

@ -1,19 +1,15 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Strings;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
import java.util.Set;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Getter
public class NewPrNotify extends PrNotify {
public static final String TYPE = "NewPrNotify";
private final String description;
private final String author;
private final String targetBranch;
@ -40,29 +36,8 @@ public class NewPrNotify extends PrNotify {
}
@Override
public String generateMessage() {
String labelText = labels.stream()
.map(label -> "#" + label)
.collect(Collectors.joining(" "));
if (!labelText.isEmpty()) {
labelText = "\n\n" + labelText;
}
return MessageFormat.format(
"{0} *New merge request for review | {1}*{2}[{3}]({4}){5}{2}{9}: {10} {12} {11}\n{7}: {8}",
Smile.FUN.getValue(),
projectName,
Smile.HR.getValue(),
title,
url,
labelText,
(description != null && !"".equals(description)) ? escapeMarkdown(description) + Smile.HR : Strings.EMPTY,
Smile.AUTHOR.getValue(),
author,
Smile.TREE.getValue(),
sourceBranch,
targetBranch,
Smile.ARROW.getValue()
);
public String getType() {
return TYPE;
}
}

View File

@ -1,15 +1,14 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.domain.MergeRequestState;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
import java.text.MessageFormat;
@Getter
public class StatusPrNotify extends PrNotify {
public static final String TYPE = "StatusPrNotify";
private final MergeRequestState oldStatus;
private final MergeRequestState newStatus;
@ -27,11 +26,8 @@ public class StatusPrNotify extends PrNotify {
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *MergeRequest status changed | {7}*{1}[{2}]({3}){1}{4} {5} {6}",
Smile.PEN.getValue(), Smile.HR.getValue(), title, url, oldStatus.name(), Smile.ARROW.getValue(), newStatus.name(), projectName
);
public String getType() {
return TYPE;
}
}

View File

@ -1,12 +1,13 @@
package dev.struchkov.bot.gitlab.context.domain.notify.mergerequest;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import lombok.Getter;
@Getter
public class UpdatePrNotify extends PrNotify {
public static final String TYPE = "UpdatePrNotify";
private final String author;
private final Long allTasks;
private final Long allResolvedTasks;
@ -32,26 +33,10 @@ public class UpdatePrNotify extends PrNotify {
this.personResolvedTasks = personResolvedTasks;
}
@Override
public String generateMessage() {
final StringBuilder builder = new StringBuilder(Smile.UPDATE.getValue()).append(" *MergeRequest update | ").append(projectName).append("*")
.append(Smile.HR.getValue())
.append("[").append(title).append("](").append(url).append(")");
if (allTasks > 0) {
builder.append(Smile.HR.getValue())
.append("All tasks: ").append(allResolvedTasks).append("/").append(allTasks);
if (personTasks > 0) {
builder.append("\nYour tasks: ").append(personResolvedTasks).append("/").append(personTasks);
}
}
builder.append(Smile.HR.getValue())
.append(Smile.AUTHOR.getValue()).append(": ").append(author);
return builder.toString();
public String getType() {
return TYPE;
}
}

View File

@ -1,43 +1,47 @@
package dev.struchkov.bot.gitlab.context.domain.notify.pipeline;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import java.text.MessageFormat;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
import lombok.Getter;
/**
* @author upagge 17.01.2021
*/
//TODO [16.12.2022|uPagge]: Нужно реализовать заполнение projectName
public record PipelineNotify(
Long pipelineId,
String projectName,
String refName,
String oldStatus,
String newStatus,
String webUrl
) implements Notify {
@Getter
public final class PipelineNotify implements Notify {
public static final String TYPE = "PipelineNotify";
private final Long projectId;
private final Long pipelineId;
private final String refName;
private final PipelineStatus oldStatus;
private final PipelineStatus newStatus;
private final String webUrl;
@Builder
public PipelineNotify {
public PipelineNotify(
Long projectId,
Long pipelineId,
String refName,
PipelineStatus oldStatus,
PipelineStatus newStatus,
String webUrl
) {
this.projectId = projectId;
this.pipelineId = pipelineId;
this.refName = refName;
this.oldStatus = oldStatus;
this.newStatus = newStatus;
this.webUrl = webUrl;
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Pipeline {1,number,#}* | {2}{3}[{4}]({5}){3}{6} {7} {8}",
Smile.BUILD,
pipelineId,
escapeMarkdown(projectName),
Smile.HR,
refName,
webUrl,
oldStatus,
Smile.ARROW,
newStatus
);
public String getType() {
return TYPE;
}
}

View File

@ -1,16 +1,11 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.haiti.utils.Pair;
import lombok.Builder;
import lombok.Getter;
import lombok.Singular;
import java.util.List;
import java.util.stream.Collectors;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
/**
* @author upagge 10.09.2020
@ -18,6 +13,8 @@ import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Getter
public class DiscussionNewNotify extends TaskNotify {
public static final String TYPE = "DiscussionNewNotify";
private final String mrName;
private final List<Pair<String, String>> notes;
@ -35,25 +32,8 @@ public class DiscussionNewNotify extends TaskNotify {
}
@Override
public String generateMessage() {
final StringBuilder builder = new StringBuilder(Smile.TASK.getValue()).append(" [New discussion](").append(url).append(")")
.append(Smile.HR.getValue())
.append(escapeMarkdown(mrName))
.append(Smile.HR.getValue())
.append("*").append(authorName).append("*: ").append(escapeMarkdown(messageTask));
if (checkNotNull(notes)) {
builder.append("\n-- -- -- -- comments -- -- -- --\n")
.append(convertNotes(notes));
}
return builder.toString();
}
private String convertNotes(List<Pair<String, String>> notes) {
return notes.stream()
.map(note -> "*" + note.getKey() + "*: " + note.getValue())
.collect(Collectors.joining("\n"));
public String getType() {
return TYPE;
}
}

View File

@ -1,17 +1,16 @@
package dev.struchkov.bot.gitlab.context.domain.notify.task;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import lombok.Builder;
import java.text.MessageFormat;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
import lombok.Getter;
/**
* @author upagge 10.09.2020
*/
@Getter
public class TaskCloseNotify extends TaskNotify {
public static final String TYPE = "TaskCloseNotify";
private final Long personTasks;
private final Long personResolvedTasks;
@ -29,11 +28,8 @@ public class TaskCloseNotify extends TaskNotify {
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Closed [task]({1}){2}*{3}*: {4}",
Smile.TASK.getValue(), url, Smile.HR.getValue(), authorName, escapeMarkdown(messageTask), personTasks, personResolvedTasks
);
public String getType() {
return TYPE;
}
}

View File

@ -24,4 +24,6 @@ public interface DiscussionRepository {
List<Discussion> findAllById(Set<String> discussionIds);
Set<String> findAllIds();
}

View File

@ -26,4 +26,6 @@ public interface MergeRequestRepository {
void deleteByStates(Set<MergeRequestState> states);
Set<Long> findAllIds();
}

View File

@ -23,4 +23,6 @@ public interface PipelineRepository {
void deleteByCreatedBefore(LocalDateTime date);
Set<Long> findAllIds();
}

View File

@ -25,4 +25,6 @@ public interface ProjectRepository {
Set<Long> findAllIds();
Optional<String> findProjectNameById(Long projectId);
}

View File

@ -21,4 +21,8 @@ public interface AppSettingService {
*/
void disableFirstStart();
boolean isEnableAllNotify();
void turnOnAllNotify();
}

View File

@ -37,4 +37,6 @@ public interface DiscussionService {
List<Discussion> getAll();
Set<String> getAllIds();
}

View File

@ -36,4 +36,6 @@ public interface MergeRequestsService {
void cleanOld();
Set<Long> getAllIds();
}

View File

@ -12,8 +12,4 @@ public interface NotifyService {
<T extends Notify> void send(T notify);
void enableAllNotify();
void disableAllNotify();
}

View File

@ -29,4 +29,6 @@ public interface PipelineService {
void cleanOld();
Set<Long> getAllIds();
}

View File

@ -5,6 +5,7 @@ import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import lombok.NonNull;
import java.util.List;
import java.util.Optional;
import java.util.Set;
/**
@ -25,4 +26,7 @@ public interface ProjectService {
ExistContainer<Project, Long> existsById(Set<Long> projectIds);
Set<Long> getAllIds();
Optional<String> getProjectNameById(Long projectId);
}

View File

@ -0,0 +1,31 @@
package dev.struchkov.bot.gitlab.context.utils;
import static dev.struchkov.haiti.utils.Exceptions.utilityClass;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
public class Icons {
public static final String HR = "\n-- -- -- -- --\n";
public static final String FUN = "\uD83C\uDF89";
public static final String VIEW = "\uD83D\uDC40";
public static final String TREE = "\uD83C\uDF33";
public static final String AUTHOR = "\uD83D\uDC68\u200D\uD83D\uDCBB";
public static final String UPDATE = "\uD83D\uDD04";
public static final String COMMENT = "\uD83D\uDCAC";
public static final String TASK = "\uD83D\uDCBC";
public static final String ARROW = "";
public static final String DANGEROUS = "⚠️";
public static final String PEN = "✏️";
public static final String BUILD = "\uD83D\uDEE0";
public static final String LINK = "\uD83D\uDD17";
private Icons() {
utilityClass();
}
public static String link(String title, String url) {
return "[" + escapeMarkdown(title) + "](" + url + ")";
}
}

View File

@ -1,55 +0,0 @@
package dev.struchkov.bot.gitlab.context.utils;
import dev.struchkov.bot.gitlab.context.domain.entity.MergeRequest;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Генерирует сообщения для отправки.
*
* @author upagge [07.02.2020]
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class MessageUtils {
public static Optional<String> mergeRequestForReview(@NonNull List<MergeRequest> mergeRequestsReviews) {
if (!mergeRequestsReviews.isEmpty()) {
return Optional.of(
mergeRequestsReviews.stream()
.map(MessageUtils::generateStringItemMergeRequestReview)
.collect(Collectors.joining("\n"))
);
}
return Optional.empty();
}
public static Optional<String> mergeRequestForNeedWork(@NonNull List<MergeRequest> mergeRequestNeedWork) {
if (!mergeRequestNeedWork.isEmpty()) {
return Optional.of(
mergeRequestNeedWork.stream()
.map(MessageUtils::generateStringItemMergeRequestNeedWork)
.collect(Collectors.joining("\n"))
);
}
return Optional.empty();
}
private static String generateStringItemMergeRequestNeedWork(MergeRequest mergeRequest) {
return "-- " + link(mergeRequest.getTitle(), mergeRequest.getWebUrl());
}
private static String generateStringItemMergeRequestReview(MergeRequest mergeRequest) {
return Smile.statusPr(mergeRequest.getUpdatedDate()) + " " +
link(mergeRequest.getTitle(), mergeRequest.getWebUrl());
}
private static String link(String name, String url) {
return "[" + name + "](" + url + ")";
}
}

View File

@ -3,10 +3,6 @@ package dev.struchkov.bot.gitlab.context.utils;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Period;
@AllArgsConstructor
public enum Smile {
@ -47,15 +43,6 @@ public enum Smile {
@Getter
private final String value;
public static Smile statusPr(LocalDateTime updateDate) {
int periodDay = Period.between(updateDate.toLocalDate(), LocalDate.now()).getDays();
if (periodDay < 5) {
return Smile.valueOf("DAY_" + periodDay);
} else {
return Smile.DAY_5;
}
}
@Override
public String toString() {
return value;

View File

@ -5,8 +5,8 @@ import dev.struchkov.bot.gitlab.context.repository.AppSettingRepository;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.haiti.context.exception.NotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.function.Supplier;
@ -25,18 +25,30 @@ public class AppSettingServiceImpl implements AppSettingService {
public static final Supplier<NotFoundException> NOT_FOUND_SETTINGS = notFoundException("Ошибка, невозможно найти настройки приложения, проверьте базу данных.");
private final AppSettingRepository appSettingRepository;
private final MessageSource messageSource;
@Override
@Transactional(readOnly = true)
public boolean isFirstStart() {
return getAppSetting().isFirstStart();
}
@Override
@Transactional
public void disableFirstStart() {
final AppSetting appSetting = getAppSetting();
appSetting.setFirstStart(false);
appSettingRepository.save(appSetting);
}
@Override
@Transactional(readOnly = true)
public boolean isEnableAllNotify() {
return getAppSetting().isEnableNotify();
}
@Override
@Transactional
public void turnOnAllNotify() {
final AppSetting appSetting = getAppSetting();
appSetting.setEnableNotify(true);
}
private AppSetting getAppSetting() {

View File

@ -300,6 +300,11 @@ public class DiscussionServiceImpl implements DiscussionService {
return repository.findAll();
}
@Override
public Set<String> getAllIds() {
return repository.findAllIds();
}
/**
* Уведомляет пользователя, если его никнейм упоминается в комментарии.
*/

View File

@ -250,6 +250,12 @@ public class MergeRequestsServiceImpl implements MergeRequestsService {
log.debug("Конец очистки старых MR");
}
@Override
@Transactional(readOnly = true)
public Set<Long> getAllIds() {
return repository.findAllIds();
}
private void notifyAboutUpdate(MergeRequest oldMergeRequest, MergeRequest mergeRequest, Project project) {
final Long botUserGitlabId = personInformation.getId();

View File

@ -1,33 +1,31 @@
package dev.struchkov.bot.gitlab.core.service.impl;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.MessageSendService;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class NotifyServiceImpl implements NotifyService {
private boolean enableAllNotify = true;
private final MessageSendService messageSendService;
private final AppSettingService settingService;
public NotifyServiceImpl(
@Lazy MessageSendService messageSendService,
AppSettingService settingService
) {
this.messageSendService = messageSendService;
this.settingService = settingService;
}
@Override
public <T extends Notify> void send(T notify) {
if (enableAllNotify) {
if (settingService.isEnableAllNotify()) {
messageSendService.send(notify);
}
}
@Override
public void enableAllNotify() {
enableAllNotify = true;
}
@Override
public void disableAllNotify() {
enableAllNotify = false;
}
}

View File

@ -49,7 +49,7 @@ public class PipelineServiceImpl implements PipelineService {
@Transactional
public Pipeline create(@NonNull Pipeline pipeline) {
final Pipeline newPipeline = repository.save(pipeline);
notifyNewPipeline(pipeline, "n/a");
notifyNewPipeline(pipeline, PipelineStatus.NULL);
return newPipeline;
}
@ -61,11 +61,12 @@ public class PipelineServiceImpl implements PipelineService {
.collect(Collectors.toList());
}
private void notifyNewPipeline(Pipeline pipeline, String oldStatus) {
private void notifyNewPipeline(Pipeline pipeline, PipelineStatus oldStatus) {
if (isNeedNotifyNewPipeline(pipeline)) {
notifyService.send(
PipelineNotify.builder()
.newStatus(pipeline.getStatus().name())
.projectId(pipeline.getProjectId())
.newStatus(pipeline.getStatus())
.pipelineId(pipeline.getId())
.refName(pipeline.getRef())
.webUrl(pipeline.getWebUrl())
@ -83,7 +84,7 @@ public class PipelineServiceImpl implements PipelineService {
pipeline.setProjectId(oldPipeline.getProjectId());
if (!oldPipeline.getUpdated().equals(pipeline.getUpdated())) {
notifyNewPipeline(pipeline, oldPipeline.getStatus().name());
notifyNewPipeline(pipeline, oldPipeline.getStatus());
return repository.save(pipeline);
}
@ -131,4 +132,9 @@ public class PipelineServiceImpl implements PipelineService {
log.debug("Конец очистки старых пайплайнов");
}
@Override
public Set<Long> getAllIds() {
return repository.findAllIds();
}
}

View File

@ -14,6 +14,7 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -92,6 +93,11 @@ public class ProjectServiceImpl implements ProjectService {
return repository.findAllIds();
}
@Override
public Optional<String> getProjectNameById(@NonNull Long projectId) {
return repository.findProjectNameById(projectId);
}
private void notifyAboutNewProject(Project newProject, String authorName) {
notifyService.send(
NewProjectNotify.builder()

View File

@ -29,7 +29,7 @@ public class GetAllDiscussionForMergeRequestTask extends RecursiveTask<List<Disc
@Override
@SneakyThrows
protected List<DiscussionJson> compute() {
Thread.sleep(100);
Thread.sleep(200);
final List<DiscussionJson> jsons = getDiscussionJson();
if (checkNotEmpty(jsons) && jsons.size() == PAGE_COUNT) {
final var newTask = new GetAllDiscussionForMergeRequestTask(discussionsUrl, projectId, mergeRequestTwoId, personalGitlabToken, page + 1);

View File

@ -30,7 +30,7 @@ public class GetAllMergeRequestForProjectTask extends RecursiveTask<List<MergeRe
@Override
@SneakyThrows
protected List<MergeRequestJson> compute() {
Thread.sleep(100);
Thread.sleep(200);
final List<MergeRequestJson> mergeRequestJsons = getMergeRequestJsons();
if (checkNotEmpty(mergeRequestJsons) && mergeRequestJsons.size() == PAGE_COUNT) {
final GetAllMergeRequestForProjectTask newTask = new GetAllMergeRequestForProjectTask(projectId, pageNumber + 1, urlMrOpen, gitlabToken);

View File

@ -31,7 +31,7 @@ public class GetPipelineShortTask extends RecursiveTask<List<PipelineShortJson>>
@Override
@SneakyThrows
protected List<PipelineShortJson> compute() {
Thread.sleep(100);
Thread.sleep(200);
final List<PipelineShortJson> jsons = getPipelineJsons();
if (jsons.size() == PAGE_COUNT) {
final GetPipelineShortTask newTask = new GetPipelineShortTask(urlPipelines, projectId, pageNumber + 1, lastUpdate, gitlabToken);

View File

@ -25,7 +25,7 @@ public class GetPipelineTask extends RecursiveTask<Optional<PipelineJson>> {
@Override
@SneakyThrows
protected Optional<PipelineJson> compute() {
Thread.sleep(100);
Thread.sleep(200);
return HttpParse.request(MessageFormat.format(urlPipeline, projectId, pipelineId))
.header(ACCEPT)
.header(StringUtils.H_PRIVATE_TOKEN, gitlabToken)

View File

@ -25,7 +25,7 @@ public class GetSingleMergeRequestTask extends RecursiveTask<Optional<MergeReque
@Override
@SneakyThrows
protected Optional<MergeRequestJson> compute() {
Thread.sleep(100);
Thread.sleep(200);
final String mrUrl = MessageFormat.format(urlMr, projectId, mrTwoId);
return HttpParse.request(mrUrl)
.header(ACCEPT)

View File

@ -47,4 +47,9 @@ public class DiscussionRepositoryImpl implements DiscussionRepository {
return jpaRepository.findAllById(discussionIds);
}
@Override
public Set<String> findAllIds() {
return jpaRepository.findAllIds();
}
}

View File

@ -65,4 +65,9 @@ public class MergeRequestRepositoryImpl implements MergeRequestRepository {
jpaRepository.deleteAllByStateIn(states);
}
@Override
public Set<Long> findAllIds() {
return jpaRepository.findAllIds();
}
}

View File

@ -48,4 +48,9 @@ public class PipelineRepositoryImpl implements PipelineRepository {
jpaRepository.deleteAllByCreatedBefore(date);
}
@Override
public Set<Long> findAllIds() {
return jpaRepository.findAllIds();
}
}

View File

@ -51,4 +51,9 @@ public class ProjectRepositoryImpl implements ProjectRepository {
return jpaRepository.findAllIds();
}
@Override
public Optional<String> findProjectNameById(Long projectId) {
return jpaRepository.findProjectNameById(projectId);
}
}

View File

@ -2,8 +2,10 @@ package dev.struchkov.bot.gitlab.data.jpa;
import dev.struchkov.bot.gitlab.context.domain.entity.Discussion;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
import java.util.Set;
/**
* @author upagge 11.02.2021
@ -15,4 +17,7 @@ public interface DiscussionJpaRepository extends JpaRepository<Discussion, Strin
*/
List<Discussion> findAllByMergeRequestId(Long mergeRequestId);
@Query("SELECT d.id FROM Discussion d")
Set<String> findAllIds();
}

View File

@ -24,4 +24,7 @@ public interface MergeRequestJpaRepository extends JpaRepositoryImplementation<M
void deleteAllByStateIn(Set<MergeRequestState> states);
@Query("SELECT mr.id FROM MergeRequest mr")
Set<Long> findAllIds();
}

View File

@ -2,6 +2,7 @@ package dev.struchkov.bot.gitlab.data.jpa;
import dev.struchkov.bot.gitlab.context.domain.PipelineStatus;
import dev.struchkov.bot.gitlab.context.domain.entity.Pipeline;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation;
import java.time.LocalDateTime;
@ -17,4 +18,7 @@ public interface PipelineJpaRepository extends JpaRepositoryImplementation<Pipel
void deleteAllByCreatedBefore(LocalDateTime date);
@Query("SELECT p.id FROM Pipeline p")
Set<Long> findAllIds();
}

View File

@ -3,7 +3,9 @@ package dev.struchkov.bot.gitlab.data.jpa;
import dev.struchkov.bot.gitlab.context.domain.entity.Project;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Optional;
import java.util.Set;
/**
@ -14,4 +16,7 @@ public interface ProjectJpaRepository extends JpaRepository<Project, Long> {
@Query("SELECT p.id FROM Project p")
Set<Long> findAllIds();
@Query("SELECT p.name FROM Project p WHERE p.id = :projectId")
Optional<String> findProjectNameById(@Param("projectId") Long projectId);
}

View File

@ -10,13 +10,9 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import static dev.struchkov.haiti.context.exception.NotFoundException.notFoundException;
import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT;
@ -30,20 +26,15 @@ import static dev.struchkov.haiti.utils.network.HttpParse.ACCEPT;
@EnableScheduling
public class AppConfig {
/**
* Отвечает за работу шедулеров в паралельном режиме
*/
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(12);
return taskScheduler;
}
@Bean
public ExecutorService executorService() {
return Executors.newFixedThreadPool(3);
}
// /**
// * Отвечает за работу шедулеров в паралельном режиме
// */
// @Bean
// public TaskScheduler taskScheduler() {
// ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
// taskScheduler.setPoolSize(12);
// return taskScheduler;
// }
@Bean
public ConversionService conversionService(Converter... converters) {

View File

@ -1,5 +1,6 @@
package dev.struchkov.bot.gitlab.scheduler;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
import dev.struchkov.bot.gitlab.context.service.PipelineService;
import dev.struchkov.bot.gitlab.core.service.parser.DiscussionParser;
@ -18,6 +19,8 @@ import org.springframework.stereotype.Service;
@RequiredArgsConstructor
public class SchedulerService {
private final AppSettingService settingService;
private final PipelineParser pipelineParser;
private final MergeRequestParser mergeRequestParser;
private final DiscussionParser discussionParser;
@ -28,14 +31,18 @@ public class SchedulerService {
@Scheduled(cron = "0 */1 * * * *")
public void newMergeRequest() {
log.debug("Запуск процесса обновления данных");
mergeRequestParser.parsingOldMergeRequest();
mergeRequestParser.parsingNewMergeRequest();
pipelineParser.scanOldPipeline();
pipelineParser.scanNewPipeline();
discussionParser.scanOldDiscussions();
discussionParser.scanNewDiscussion();
mergeRequestsService.cleanOld();
pipelineService.cleanOld();
if (!settingService.isFirstStart()) {
mergeRequestParser.parsingOldMergeRequest();
mergeRequestParser.parsingNewMergeRequest();
pipelineParser.scanOldPipeline();
pipelineParser.scanNewPipeline();
discussionParser.scanOldDiscussions();
discussionParser.scanNewDiscussion();
mergeRequestsService.cleanOld();
pipelineService.cleanOld();
} else {
log.warn("Процесс обновления данных не был выполнен, так как пользователь не выполнил первичную настройку.");
}
log.debug("Конец процесса обновления данных");
}

View File

@ -8,7 +8,12 @@
<column name="id" type="int">
<constraints primaryKey="true"/>
</column>
<column name="first_start" type="boolean"/>
<column name="first_start" type="boolean" defaultValue="true">
<constraints nullable="false"/>
</column>
<column name="enable_notify" type="boolean" defaultValue="false">
<constraints nullable="false"/>
</column>
</createTable>
</changeSet>

38
pom.xml
View File

@ -258,6 +258,44 @@
</profile>
</profiles>
<repositories>
<repository>
<id>struchkov-nexus-release</id>
<url>https://nexus.struchkov.dev/repository/maven-releases/</url>
<releases>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>fail</checksumPolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>struchkov-nexus-snapshot</id>
<url>https://nexus.struchkov.dev/repository/maven-snapshots/</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
<updatePolicy>always</updatePolicy>
<checksumPolicy>warn</checksumPolicy>
</snapshots>
</repository>
</repositories>
<distributionManagement>
<repository>
<id>struchkov-nexus-release</id>
<url>https://nexus.struchkov.dev/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<id>struchkov-nexus-snapshot</id>
<url>https://nexus.struchkov.dev/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<developers>
<developer>
<id>uPagge</id>

View File

@ -1,17 +1,20 @@
package dev.struchkov.bot.gitlab.telegram.config;
import dev.struchkov.bot.gitlab.telegram.service.ReplaceUrlLocalhost;
import dev.struchkov.bot.gitlab.telegram.unit.CommandUnit;
import dev.struchkov.bot.gitlab.telegram.unit.MenuConfig;
import dev.struchkov.bot.gitlab.telegram.unit.UnitConfig;
import dev.struchkov.bot.gitlab.telegram.unit.flow.InitSettingFlow;
import dev.struchkov.godfather.main.domain.content.Mail;
import dev.struchkov.godfather.simple.context.service.EventHandler;
import dev.struchkov.godfather.simple.context.service.PersonSettingService;
import dev.struchkov.godfather.simple.context.service.UnitPointerService;
import dev.struchkov.godfather.simple.core.provider.StoryLineHandler;
import dev.struchkov.godfather.simple.core.service.PersonSettingServiceImpl;
import dev.struchkov.godfather.simple.core.service.StorylineContextMapImpl;
import dev.struchkov.godfather.simple.core.service.StorylineMailService;
import dev.struchkov.godfather.simple.core.service.StorylineService;
import dev.struchkov.godfather.simple.core.service.UnitPointerServiceImpl;
import dev.struchkov.godfather.simple.data.StorylineContext;
import dev.struchkov.godfather.simple.data.repository.impl.PersonSettingLocalRepository;
import dev.struchkov.godfather.simple.data.repository.impl.StorylineMapRepository;
import dev.struchkov.godfather.simple.data.repository.impl.UnitPointLocalRepository;
@ -25,6 +28,7 @@ import dev.struchkov.godfather.telegram.simple.core.MailAutoresponderTelegram;
import dev.struchkov.godfather.telegram.simple.core.TelegramConnectBot;
import dev.struchkov.godfather.telegram.simple.core.service.SenderMapRepository;
import dev.struchkov.godfather.telegram.simple.sender.TelegramSender;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
@ -32,6 +36,8 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author upagge [30.01.2020]
@ -40,6 +46,16 @@ import java.util.List;
@EnableScheduling
public class TelegramBotConfig {
@Bean("messageExecutorService")
public ExecutorService executorService() {
return Executors.newFixedThreadPool(3);
}
@Bean
public StorylineContext storylineContext() {
return new StorylineContextMapImpl();
}
@Bean
public UnitPointerService unitPointerService() {
return new UnitPointerServiceImpl(new UnitPointLocalRepository());
@ -55,9 +71,10 @@ public class TelegramBotConfig {
UnitPointerService unitPointerService,
MenuConfig menuConfig,
UnitConfig unitConfig
InitSettingFlow unitConfig,
CommandUnit commandUnit
) {
final List<Object> config = List.of(menuConfig, unitConfig);
final List<Object> config = List.of(menuConfig, unitConfig, commandUnit);
return new StorylineMailService(
unitPointerService,
@ -68,6 +85,7 @@ public class TelegramBotConfig {
@Bean
public MailAutoresponderTelegram messageAutoresponderTelegram(
@Qualifier("messageExecutorService") ExecutorService executorService,
TelegramSending sending,
PersonSettingService personSettingService,
@ -76,6 +94,7 @@ public class TelegramBotConfig {
final MailAutoresponderTelegram autoresponder = new MailAutoresponderTelegram(
sending, personSettingService, mailStorylineService
);
autoresponder.setExecutorService(executorService);
return autoresponder;
}

View File

@ -3,13 +3,16 @@ package dev.struchkov.bot.gitlab.telegram.service;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
import dev.struchkov.bot.gitlab.context.domain.notify.Notify;
import dev.struchkov.bot.gitlab.context.service.MessageSendService;
import dev.struchkov.bot.gitlab.telegram.service.notify.NotifyBoxAnswerGenerator;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
/**
* Отправляет сообщение в телеграмм.
@ -17,18 +20,36 @@ import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
* @author upagge 17.09.2020
*/
@Service
@RequiredArgsConstructor
public class MessageSendTelegramService implements MessageSendService {
private final Map<String, NotifyBoxAnswerGenerator> generatorMap;
private final TelegramSending sending;
private final PersonInformation personInformation;
public MessageSendTelegramService(
List<NotifyBoxAnswerGenerator> generators,
TelegramSending sending,
PersonInformation personInformation
) {
this.generatorMap = generators.stream().collect(Collectors.toMap(NotifyBoxAnswerGenerator::getNotifyType, n -> n));
this.sending = sending;
this.personInformation = personInformation;
}
@Override
public void send(@NonNull Notify notify) {
final BoxAnswer boxAnswer = boxAnswer(notify.generateMessage());
boxAnswer.setRecipientIfNull(personInformation.getTelegramId());
sending.send(boxAnswer);
getGenerator(notify.getType())
.map(generator -> {
final BoxAnswer answer = generator.generate(notify);
answer.setRecipientIfNull(personInformation.getTelegramId());
return answer;
})
.ifPresent(sending::send);
}
private Optional<NotifyBoxAnswerGenerator> getGenerator(String notifyType) {
return Optional.ofNullable(generatorMap.get(notifyType));
}
}

View File

@ -1,9 +1,10 @@
package dev.struchkov.bot.gitlab.telegram.service;
import dev.struchkov.bot.gitlab.context.domain.notify.SimpleTextNotify;
import dev.struchkov.bot.gitlab.context.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.core.config.properties.AppProperty;
import dev.struchkov.bot.gitlab.core.config.properties.PersonProperty;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@ -16,20 +17,25 @@ import javax.annotation.PostConstruct;
@RequiredArgsConstructor
public class StartNotify {
private final NotifyService notifyService;
private final TelegramSending sending;
private final AppProperty appProperty;
private final AppSettingService settingService;
private final PersonProperty personProperty;
@PostConstruct
public void sendStartNotification() {
if (!settingService.isFirstStart()) {
notifyService.send(
SimpleTextNotify.builder()
.message("Hello. I wish you a productive day :)" +
"\n-- -- -- -- --\n" +
"Version " + appProperty.getVersion() + " | Developer: [uPagge](https://mark.struchkov.dev)")
.build()
);
final BoxAnswer boxAnswer = BoxAnswer.builder()
.recipientPersonId(personProperty.getTelegramId())
.message(
new StringBuilder()
.append("Hello. I wish you a productive day :)")
.append("\n-- -- -- -- --\n")
.append("Version ").append(appProperty.getVersion()).append(" | Developer: [uPagge](https://mark.struchkov.dev)")
.toString()
).build();
sending.send(boxAnswer);
}
}

View File

@ -0,0 +1,31 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.ConflictPrNotify;
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.godfather.main.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component
public class ConflictPrNotifyGenerator implements NotifyBoxAnswerGenerator<ConflictPrNotify> {
@Override
public BoxAnswer generate(ConflictPrNotify notify) {
final StringBuilder builder = new StringBuilder(Icons.DANGEROUS).append(" *Attention! MergeRequest conflict | ").append(escapeMarkdown(notify.getProjectName())).append("*")
.append(Icons.HR)
.append(link(notify.getTitle(), notify.getUrl()));
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
@Override
public String getNotifyType() {
return ConflictPrNotify.TYPE;
}
}

View File

@ -0,0 +1,48 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.task.DiscussionNewNotify;
import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.haiti.utils.Pair;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component
public class DiscussionNewNotifyGenerator implements NotifyBoxAnswerGenerator<DiscussionNewNotify> {
@Override
public BoxAnswer generate(DiscussionNewNotify notify) {
final StringBuilder builder = new StringBuilder(Icons.TASK).append(" [New discussion](").append(notify.getUrl()).append(")")
.append(Icons.HR)
.append(escapeMarkdown(notify.getMrName()))
.append(Icons.HR)
.append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessageTask()));
final List<Pair<String, String>> notes = notify.getNotes();
if (checkNotNull(notes)) {
builder.append("\n-- -- -- -- comments -- -- -- --\n")
.append(convertNotes(notes));
}
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
private String convertNotes(List<Pair<String, String>> notes) {
return notes.stream()
.map(note -> "*" + note.getKey() + "*: " + note.getValue())
.collect(Collectors.joining("\n"));
}
@Override
public String getNotifyType() {
return DiscussionNewNotify.TYPE;
}
}

View File

@ -0,0 +1,41 @@
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.Smile;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import org.springframework.stereotype.Component;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.haiti.utils.Checker.checkNotNull;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component
public class NewCommentNotifyGenerator implements NotifyBoxAnswerGenerator<NewCommentNotify> {
@Override
public BoxAnswer generate(NewCommentNotify notify) {
final StringBuilder builder = new StringBuilder(Smile.COMMENT.getValue()).append(" [New answer in discussion](").append(notify.getUrl()).append(")\n--- --- --- ---");
if (checkNotNull(notify.getDiscussionMessage())) {
builder.append("\n-- -- discussion first message -- --\n")
.append("*").append(notify.getDiscussionAuthor()).append("*: ").append(escapeMarkdown(notify.getDiscussionMessage()));
}
if (checkNotNull(notify.getPreviousMessage())) {
builder.append("\n-- -- -- previous message -- -- --\n")
.append("*").append(notify.getPreviousAuthor()).append("*: ").append(escapeMarkdown(notify.getPreviousMessage()));
}
builder.append("\n-- -- -- --- new answer --- -- -- --\n")
.append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessage()));
final String messageNotify = builder.toString();
return boxAnswer(messageNotify);
}
@Override
public String getNotifyType() {
return NewCommentNotify.TYPE;
}
}

View File

@ -0,0 +1,45 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.NewPrNotify;
import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import org.springframework.stereotype.Component;
import java.util.stream.Collectors;
import static dev.struchkov.bot.gitlab.context.utils.Icons.link;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component
public class NewPrNotifyGenerator implements NotifyBoxAnswerGenerator<NewPrNotify> {
@Override
public BoxAnswer generate(NewPrNotify notify) {
final String labelText = notify.getLabels().stream()
.map(label -> "#" + label)
.collect(Collectors.joining(" "));
final StringBuilder builder = new StringBuilder(Icons.FUN).append(" *New merge request for review | ").append(escapeMarkdown(notify.getProjectName())).append("*")
.append(Icons.HR)
.append(link(notify.getType(), notify.getUrl()));
if (!labelText.isEmpty()) {
builder.append("\n\n").append(labelText);
}
builder.append(Icons.HR)
.append(Icons.TREE).append(": ").append(notify.getSourceBranch()).append(Icons.ARROW).append(notify.getTargetBranch()).append("\n")
.append(Icons.AUTHOR).append(": ").append(notify.getAuthor());
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
@Override
public String getNotifyType() {
return NewPrNotify.TYPE;
}
}

View File

@ -0,0 +1,45 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.NewProjectNotify;
import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.haiti.utils.Strings;
import org.springframework.stereotype.Component;
import java.util.Optional;
import static dev.struchkov.bot.gitlab.context.utils.Icons.link;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
@Component
public class NewProjectNotifyGenerator implements NotifyBoxAnswerGenerator<NewProjectNotify> {
@Override
public BoxAnswer generate(NewProjectNotify notify) {
final Optional<String> optDescription = Optional.ofNullable(notify.getProjectDescription())
.map(Strings::escapeMarkdown);
final StringBuilder builder = new StringBuilder(Icons.FUN).append("*New project*")
.append(Icons.HR)
.append(link(notify.getProjectName(), notify.getProjectUrl()))
.append(Icons.HR);
if (optDescription.isPresent() || !Strings.EMPTY.equals(optDescription.get())) {
final String description = optDescription.get();
builder.append(description)
.append(Icons.HR);
}
builder.append(Icons.AUTHOR).append(": ").append(notify.getAuthorName());
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
@Override
public String getNotifyType() {
return NewProjectNotify.TYPE;
}
}

View File

@ -0,0 +1,18 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import java.util.List;
import java.util.stream.Collectors;
public interface NotifyBoxAnswerGenerator<T> {
BoxAnswer generate(T notify);
default List<BoxAnswer> generate(List<T> notify) {
return notify.stream().map(this::generate).collect(Collectors.toList());
}
String getNotifyType();
}

View File

@ -0,0 +1,60 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.pipeline.PipelineNotify;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.godfather.main.domain.BoxAnswer;
import dev.struchkov.haiti.utils.Strings;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.Optional;
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;
@Service
@RequiredArgsConstructor
public class PipelineNotifyGenerator implements NotifyBoxAnswerGenerator<PipelineNotify> {
private final ProjectService projectService;
@Override
public BoxAnswer generate(PipelineNotify notify) {
final Optional<String> optProjectName = projectService.getProjectNameById(notify.getProjectId())
.map(Strings::escapeMarkdown);
final StringBuilder builder = new StringBuilder(Icons.BUILD).append(" *Pipeline ").append(notify.getPipelineId()).append("*");
if (optProjectName.isPresent()) {
final String projectName = optProjectName.get();
builder.append(" | ").append(projectName);
}
final String notifyMessage = builder
.append(Icons.HR)
.append(Icons.TREE).append(": ").append(notify.getRefName())
.append(Icons.HR)
.append(notify.getOldStatus().getIcon()).append(" ").append(notify.getOldStatus()).append(Icons.ARROW).append(notify.getNewStatus().getIcon()).append(" ").append(notify.getNewStatus())
.toString();
return boxAnswer(
notifyMessage,
inlineKeyBoard(
simpleLine(
simpleButton(Icons.VIEW, "DELETE_MESSAGE"),
urlButton(Icons.LINK, notify.getWebUrl())
)
)
);
}
@Override
public String getNotifyType() {
return PipelineNotify.TYPE;
}
}

View File

@ -0,0 +1,33 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.StatusPrNotify;
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.godfather.main.domain.BoxAnswer.boxAnswer;
@Component
public class StatusPrNotifyGenerator implements NotifyBoxAnswerGenerator<StatusPrNotify> {
@Override
public BoxAnswer generate(StatusPrNotify notify) {
final StringBuilder builder = new StringBuilder(Icons.PEN).append(" *MergeRequest status changed | ").append(notify.getProjectName()).append("*")
.append(Icons.HR)
.append(link(notify.getTitle(), notify.getUrl()))
.append(Icons.HR)
.append(notify.getOldStatus().name()).append(Icons.ARROW).append(notify.getNewStatus().name());
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
@Override
public String getNotifyType() {
return StatusPrNotify.TYPE;
}
}

View File

@ -0,0 +1,31 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.task.TaskCloseNotify;
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.godfather.main.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component
public class TaskCloseNotifyGenerate implements NotifyBoxAnswerGenerator<TaskCloseNotify> {
@Override
public BoxAnswer generate(TaskCloseNotify notify) {
final StringBuilder builder = new StringBuilder(Icons.TASK).append(" *Closed ").append(link("task", notify.getUrl()))
.append(Icons.HR)
.append("*").append(notify.getAuthorName()).append("*: ").append(escapeMarkdown(notify.getMessageTask()));
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
@Override
public String getNotifyType() {
return TaskCloseNotify.TYPE;
}
}

View File

@ -0,0 +1,44 @@
package dev.struchkov.bot.gitlab.telegram.service.notify;
import dev.struchkov.bot.gitlab.context.domain.notify.mergerequest.UpdatePrNotify;
import dev.struchkov.bot.gitlab.context.utils.Icons;
import dev.struchkov.bot.gitlab.context.utils.Smile;
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.godfather.main.domain.BoxAnswer.boxAnswer;
import static dev.struchkov.haiti.utils.Strings.escapeMarkdown;
@Component
public class UpdatePrNotifyGenerator implements NotifyBoxAnswerGenerator<UpdatePrNotify> {
@Override
public BoxAnswer generate(UpdatePrNotify notify) {
final StringBuilder builder = new StringBuilder(Icons.UPDATE).append(" *MergeRequest update | ").append(escapeMarkdown(notify.getProjectName())).append("*")
.append(Smile.HR.getValue())
.append(link(notify.getTitle(), notify.getUrl()));
if (notify.getAllTasks() > 0) {
builder.append(Smile.HR.getValue())
.append("All tasks: ").append(notify.getAllResolvedTasks()).append("/").append(notify.getAllTasks());
if (notify.getPersonTasks() > 0) {
builder.append("\nYour tasks: ").append(notify.getPersonResolvedTasks()).append("/").append(notify.getPersonTasks());
}
}
builder.append(Icons.HR)
.append(Icons.AUTHOR).append(": ").append(notify.getAuthor());
final String notifyMessage = builder.toString();
return boxAnswer(notifyMessage);
}
@Override
public String getNotifyType() {
return UpdatePrNotify.TYPE;
}
}

View File

@ -0,0 +1,110 @@
package dev.struchkov.bot.gitlab.telegram.unit;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
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.ButtonClickAttachment;
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.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.ANSWER_NOTE;
import static dev.struchkov.godfather.main.domain.BoxAnswer.boxAnswer;
@Component
@RequiredArgsConstructor
public class CommandUnit {
private static final Pattern NOTE_LINK = Pattern.compile("#note_\\d+$");
private final PersonInformation personInformation;
private final AppSettingService settingService;
private final NoteService noteService;
private final DiscussionService discussionService;
private final TelegramSending telegramSending;
@Unit(value = ANSWER_NOTE, main = 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();
}
}
}
return false;
}
)
.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();
}
}
}
return boxAnswer("Error");
}
)
.build();
}
@Unit(value = "DELETE_MESSAGE", main = true)
public AnswerText<Mail> deleteMessage() {
return AnswerText.<Mail>builder()
.triggerCheck(mail -> {
final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId());
if (isAccess) {
final boolean isFirstStart = settingService.isFirstStart();
if (!isFirstStart) {
final Optional<ButtonClickAttachment> optButtonClick = Attachments.findFirstButtonClick(mail.getAttachments());
if (optButtonClick.isPresent()) {
final ButtonClickAttachment buttonClick = optButtonClick.get();
final String rawData = buttonClick.getRawCallBackData();
return rawData.equals("DELETE_MESSAGE");
}
}
}
return false;
})
.answer(mail -> {
final ButtonClickAttachment clickButton = Attachments.findFirstButtonClick(mail.getAttachments()).orElseThrow();
telegramSending.deleteMessage(mail.getPersonId(), clickButton.getMessageId());
})
.build();
}
}

View File

@ -2,15 +2,22 @@ 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.service.AppSettingService;
import dev.struchkov.bot.gitlab.context.service.MergeRequestsService;
import dev.struchkov.bot.gitlab.context.service.NoteService;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.bot.gitlab.core.config.properties.GitlabProperty;
import dev.struchkov.bot.gitlab.core.service.parser.ProjectParser;
import dev.struchkov.bot.gitlab.telegram.utils.Keys;
import dev.struchkov.bot.gitlab.telegram.utils.UnitName;
import dev.struchkov.godfather.main.domain.BoxAnswer;
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.keyboard.InlineKeyBoard;
import dev.struchkov.godfather.telegram.simple.context.service.TelegramSending;
import dev.struchkov.haiti.utils.Checker;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@ -19,6 +26,7 @@ import java.text.MessageFormat;
import java.util.List;
import java.util.stream.Collectors;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.ACCESS_ERROR;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.ADD_NEW_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.GENERAL_MENU;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.GET_ASSIGNEE_MERGE_REQUEST;
@ -26,6 +34,7 @@ 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;
@ -40,13 +49,32 @@ 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 NoteService noteService;
private final MergeRequestsService mergeRequestsService;
private final AppSettingService settingService;
@Unit(GENERAL_MENU)
@Unit(value = ACCESS_ERROR, main = true)
public AnswerText<Mail> accessError() {
return AnswerText.<Mail>builder()
.triggerCheck(mail -> !personInformation.getTelegramId().equals(mail.getPersonId()))
.answer(message -> {
final String messageText = new StringBuilder("\uD83D\uDEA8 *Попытка несанкционированного доступа к боту*")
.append(Smile.HR.getValue())
.append("\uD83E\uDDB9\u200D♂: ").append(message.getPersonId()).append("\n")
.append("\uD83D\uDCAC: ").append(message.getText())
.toString();
return BoxAnswer.builder().recipientPersonId(personInformation.getTelegramId()).message(messageText).build();
})
.build();
}
@Unit(value = GENERAL_MENU, main = true)
public AnswerText<Mail> menu(
@Unit(SETTINGS) MainUnit<Mail> settings,
@Unit(TEXT_ADD_NEW_PROJECT) MainUnit<Mail> textAddNewProject,
@ -54,17 +82,34 @@ public class MenuConfig {
@Unit(GET_ASSIGNEE_MERGE_REQUEST) MainUnit<Mail> getAssigneeMergeRequest
) {
return AnswerText.<Mail>builder()
.answer(boxAnswer(
"This is the bot menu, select a new item",
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))
)
)
.priority(5)
.triggerCheck(mail -> {
final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId());
if (isAccess) {
final boolean firstStart = settingService.isFirstStart();
return !firstStart;
}
return false;
})
.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))
);
final String personId = mail.getPersonId();
final var initSettingFinish = context.removeKey(personId, Keys.INIT_SETTING_FINISH);
if (initSettingFinish.isPresent()) {
context.removeKey(personId, Keys.INIT_SETTING_PRIVATE_PROJECT_MESSAGE_ID).ifPresent(messageId -> sending.deleteMessage(personId, messageId));
context.removeKey(personId, Keys.INIT_SETTING_PUBLIC_PROJECT_MESSAGE_ID).ifPresent(messageId -> sending.deleteMessage(personId, messageId));
return replaceBoxAnswer(messageText, generalMenuKeyBoard);
}
return boxAnswer(messageText, generalMenuKeyBoard);
}
)
.next(settings)
.next(textAddNewProject)

View File

@ -1,265 +0,0 @@
package dev.struchkov.bot.gitlab.telegram.unit;
import dev.struchkov.bot.gitlab.context.domain.PersonInformation;
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.bot.gitlab.context.service.NotifyService;
import dev.struchkov.bot.gitlab.context.utils.Smile;
import dev.struchkov.bot.gitlab.core.service.parser.ProjectParser;
import dev.struchkov.godfather.main.core.unit.UnitActiveType;
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.AnswerCheck;
import dev.struchkov.godfather.simple.core.unit.AnswerText;
import dev.struchkov.godfather.simple.core.unit.MainUnit;
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 lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.text.MessageFormat;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.ACCESS_ERROR;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.ANSWER_NOTE;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.AUTHORIZATION;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_FIRST_START;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_MENU_OR_ANSWER;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_PARSER_PRIVATE_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_PARSE_OWNER_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.END_SETTING;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.GENERAL_MENU;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.PARSER_PRIVATE_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.PARSE_OWNER_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.TEXT_PARSER_PRIVATE_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.TEXT_PARSE_OWNER_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;
/**
* TODO: Добавить описание класса.
*
* @author upagge [30.01.2020]
*/
@Component
@RequiredArgsConstructor
public class UnitConfig {
private static final Pattern NOTE_LINK = Pattern.compile("#note_\\d+$");
private final PersonInformation personInformation;
private final AppSettingService settingService;
private final NoteService noteService;
private final DiscussionService discussionService;
private final NotifyService notifyService;
private final ProjectParser projectParser;
@Unit(value = AUTHORIZATION, main = true)
public AnswerCheck<Mail> auth(
@Unit(CHECK_FIRST_START) MainUnit<Mail> checkFirstStart,
@Unit(ACCESS_ERROR) MainUnit<Mail> accessError
) {
return AnswerCheck.<Mail>builder()
.check(mail -> personInformation.getTelegramId().equals(mail.getPersonId()))
.unitTrue(checkFirstStart)
.unitFalse(accessError)
.build();
}
@Unit(value = ACCESS_ERROR)
public AnswerText<Mail> accessError() {
return AnswerText.<Mail>builder()
.answer(message -> {
final String messageText = new StringBuilder("\uD83D\uDEA8 *Попытка несанкционированного доступа к боту*")
.append(Smile.HR.getValue())
.append("\uD83E\uDDB9\u200D♂: ").append(message.getPersonId()).append("\n")
.append("\uD83D\uDCAC: ").append(message.getText())
.toString();
return BoxAnswer.builder().recipientPersonId(personInformation.getTelegramId()).message(messageText).build();
})
.build();
}
@Unit(value = CHECK_FIRST_START)
public AnswerCheck<Mail> checkFirstStart(
@Unit(TEXT_PARSER_PRIVATE_PROJECT) MainUnit<Mail> textParserPrivateProject,
@Unit(CHECK_MENU_OR_ANSWER) MainUnit<Mail> checkMenuOrAnswer
) {
return AnswerCheck.<Mail>builder()
.check(message -> settingService.isFirstStart())
.unitFalse(checkMenuOrAnswer)
.unitTrue(textParserPrivateProject)
.build();
}
@Unit(value = CHECK_MENU_OR_ANSWER)
public AnswerCheck<Mail> checkMenuOrAnswer(
@Unit(GENERAL_MENU) MainUnit<Mail> menu,
@Unit(ANSWER_NOTE) MainUnit<Mail> answerNote
) {
return AnswerCheck.<Mail>builder()
.check(
mail -> {
final List<Mail> forwardMails = mail.getForwardMail();
if (forwardMails != null && forwardMails.size() == 1) {
final Mail forwardMail = forwardMails.get(0);
return Attachments.findFirstLink(forwardMail.getAttachments()).isPresent();
}
return false;
}
)
.unitTrue(answerNote)
.unitFalse(menu)
.build();
}
@Unit(ANSWER_NOTE)
public AnswerText<Mail> answerNote() {
return AnswerText.<Mail>builder()
.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();
}
}
}
return boxAnswer("Error");
}
)
.build();
}
@Unit(TEXT_PARSER_PRIVATE_PROJECT)
public AnswerText<Mail> textParserPrivateProject(
@Unit(CHECK_PARSER_PRIVATE_PROJECT) MainUnit<Mail> checkParserPrivateProject
) {
return AnswerText.<Mail>builder()
.answer(() -> boxAnswer(
"Start tracking private projects?",
inlineKeyBoard(
simpleLine(
simpleButton("Yes", "YES"),
simpleButton("No", "NO")
)
)
)
)
.activeType(UnitActiveType.AFTER)
.next(checkParserPrivateProject)
.build();
}
@Unit(CHECK_PARSER_PRIVATE_PROJECT)
public AnswerCheck<Mail> checkParserPrivateProject(
@Unit(PARSER_PRIVATE_PROJECT) AnswerText<Mail> parserPrivateProject,
@Unit(TEXT_PARSE_OWNER_PROJECT) MainUnit<Mail> textParseOwnerProject
) {
return AnswerCheck.<Mail>builder()
.check(mail -> "YES".equalsIgnoreCase(mail.getText()))
.intermediateAnswerIfTrue(replaceBoxAnswer("Scanning of private projects has begun. Wait..."))
.unitTrue(parserPrivateProject)
.unitFalse(textParseOwnerProject)
.build();
}
@Unit(PARSER_PRIVATE_PROJECT)
public AnswerText<Mail> parserPrivateProject(
@Unit(TEXT_PARSE_OWNER_PROJECT) MainUnit<Mail> textParseOwnerProject
) {
return AnswerText.<Mail>builder()
.answer(() -> {
notifyService.disableAllNotify();
projectParser.parseAllPrivateProject();
return replaceBoxAnswer("Projects have been successfully added to tracking");
})
.next(textParseOwnerProject)
.build();
}
@Unit(TEXT_PARSE_OWNER_PROJECT)
public AnswerText<Mail> textParseOwnerProject(
@Unit(CHECK_PARSE_OWNER_PROJECT) MainUnit<Mail> checkParseOwnerProject
) {
return AnswerText.<Mail>builder()
.answer(
boxAnswer(
"Start tracking public projects that you own?",
inlineKeyBoard(
simpleLine(
simpleButton("Yes", "YES"),
simpleButton("No", "NO")
)
)
)
)
.activeType(UnitActiveType.AFTER)
.next(checkParseOwnerProject)
.build();
}
@Unit(CHECK_PARSE_OWNER_PROJECT)
public AnswerCheck<Mail> checkParseOwnerProject(
@Unit(PARSE_OWNER_PROJECT) MainUnit<Mail> parseOwnerProject,
@Unit(END_SETTING) MainUnit<Mail> endSetting
) {
return AnswerCheck.<Mail>builder()
.check(message -> "YES".equalsIgnoreCase(message.getText()))
.intermediateAnswerIfTrue(replaceBoxAnswer("Scanning of public projects has begun. Wait..."))
.unitTrue(parseOwnerProject)
.unitFalse(endSetting)
.build();
}
@Unit(PARSE_OWNER_PROJECT)
public AnswerText<Mail> parseOwnerProject(
@Unit(END_SETTING) MainUnit<Mail> endSetting
) {
return AnswerText.<Mail>builder()
.answer(() -> {
projectParser.parseAllProjectOwner();
return replaceBoxAnswer("Projects have been successfully added to tracking");
})
.next(endSetting)
.build();
}
@Unit(END_SETTING)
public AnswerText<Mail> endSetting() {
return AnswerText.<Mail>builder()
.answer(
() -> {
settingService.disableFirstStart();
notifyService.enableAllNotify();
return replaceBoxAnswer("""
Configuration completed successfully
Developer: [uPagge](https://mark.struchkov.dev)
""");
}
)
.activeType(UnitActiveType.AFTER)
.build();
}
}

View File

@ -0,0 +1,345 @@
package dev.struchkov.bot.gitlab.telegram.unit.flow;
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.service.MergeRequestsService;
import dev.struchkov.bot.gitlab.context.service.PipelineService;
import dev.struchkov.bot.gitlab.context.service.ProjectService;
import dev.struchkov.bot.gitlab.core.service.parser.DiscussionParser;
import dev.struchkov.bot.gitlab.core.service.parser.MergeRequestParser;
import dev.struchkov.bot.gitlab.core.service.parser.PipelineParser;
import dev.struchkov.bot.gitlab.core.service.parser.ProjectParser;
import dev.struchkov.bot.gitlab.telegram.utils.Keys;
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;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_PARSER_PRIVATE_PROJECT_NO;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_PARSER_PRIVATE_PROJECT_YES;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_PARSE_OWNER_PROJECT_NO;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.CHECK_PARSE_OWNER_PROJECT_YES;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.END_SETTING;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.FIRST_START;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.TEXT_PARSER_PRIVATE_PROJECT;
import static dev.struchkov.bot.gitlab.telegram.utils.UnitName.TEXT_PARSE_OWNER_PROJECT;
import static dev.struchkov.godfather.main.core.unit.UnitActiveType.AFTER;
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 java.text.MessageFormat.format;
/**
* TODO: Добавить описание класса.
*
* @author upagge [30.01.2020]
*/
@Component
@RequiredArgsConstructor
public class InitSettingFlow {
private final TelegramSending sending;
private final StorylineContext context;
private final PersonInformation personInformation;
private final AppSettingService settingService;
private final ProjectParser projectParser;
private final MergeRequestParser mergeRequestParser;
private final PipelineParser pipelineParser;
private final DiscussionParser discussionParser;
private final ProjectService projectService;
private final MergeRequestsService mergeRequestsService;
private final PipelineService pipelineService;
private final DiscussionService discussionService;
@Unit(value = FIRST_START, main = true)
public AnswerText<Mail> firstStart(
@Unit(value = TEXT_PARSER_PRIVATE_PROJECT) MainUnit<Mail> textParserPrivateProject
) {
return AnswerText.<Mail>builder()
.triggerCheck(mail -> {
final boolean isAccess = personInformation.getTelegramId().equals(mail.getPersonId());
if (isAccess) {
return settingService.isFirstStart();
}
return false;
})
.answer(
boxAnswer(
"""
Hello!
This bot will help you keep your finger on the pulse of all your GitLab projects.
Press start to start initial setup 👇
""",
inlineKeyBoard(simpleButton("start", TEXT_PARSER_PRIVATE_PROJECT))
)
)
.next(textParserPrivateProject)
.build();
}
@Unit(value = TEXT_PARSER_PRIVATE_PROJECT)
public AnswerText<Mail> textParserPrivateProject(
@Unit(CHECK_PARSER_PRIVATE_PROJECT_YES) MainUnit<Mail> checkParserPrivateProject
) {
return AnswerText.<Mail>builder()
.answer(() -> replaceBoxAnswer(
"Start tracking private projects?",
inlineKeyBoard(
simpleLine(
simpleButton("Yes", "YES"),
simpleButton("No", "NO")
)
)
)
)
.next(checkParserPrivateProject)
.build();
}
@Unit(CHECK_PARSER_PRIVATE_PROJECT_YES)
public AnswerText<Mail> checkParserPrivateProjectYes(
@Unit(TEXT_PARSE_OWNER_PROJECT) MainUnit<Mail> textParseOwnerProject
) {
final String step1 = """
-- -- -- -- --
🔘 Scanning of private projects has begun.
Wait...
-- -- -- -- --
""";
final String step2 = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🔘 Scanning merge requests in found projects.
Wait...
-- -- -- -- --
""";
final String step3 = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🟢 Merge requests have been successfully added. Found: {1}
🔘 Scanning pipelines in found merge requests.
Wait...
-- -- -- -- --
""";
final String step4 = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🟢 Merge requests have been successfully added. Found: {1}
🟢 Pipelines have been successfully added. Found: {2}
🔘 Scanning threads in merge requests.
Wait...
-- -- -- -- --
""";
final String finalAnswer = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🟢 Merge requests have been successfully added. Found: {1}
🟢 Pipelines have been successfully added. Found: {2}
🟢 Threads have been successfully added. Found: {3}
-- -- -- -- --
""";
return AnswerText.<Mail>builder()
.triggerCheck(clickButtonRaw("YES"))
.answer(mail -> {
final String personId = mail.getPersonId();
final Integer messageId = Attachments.findFirstButtonClick(mail.getAttachments())
.map(ButtonClickAttachment::getMessageId)
.orElseThrow();
sending.replaceMessage(personId, messageId, boxAnswer(step1));
projectParser.parseAllPrivateProject();
final int projectCount = projectService.getAllIds().size();
sending.replaceMessage(personId, messageId, boxAnswer(format(step2, projectCount)));
mergeRequestParser.parsingNewMergeRequest();
final int mrCount = mergeRequestsService.getAllIds().size();
sending.replaceMessage(personId, messageId, boxAnswer(format(step3, projectCount, mrCount)));
pipelineParser.scanNewPipeline();
final int pipelineCount = pipelineService.getAllIds().size();
sending.replaceMessage(personId, messageId, boxAnswer(format(step4, projectCount, mrCount, pipelineCount)));
discussionParser.scanNewDiscussion();
final int discussionCount = discussionService.getAllIds().size();
context.save(mail.getPersonId(), Keys.INIT_SETTING_PRIVATE_PROJECT_MESSAGE_ID, messageId);
return replaceBoxAnswer(format(finalAnswer, pipelineCount, mrCount, pipelineCount, discussionCount));
})
.next(textParseOwnerProject)
.build();
}
@Unit(CHECK_PARSER_PRIVATE_PROJECT_NO)
public AnswerText<Mail> checkParserPrivateProjectNo(
@Unit(TEXT_PARSE_OWNER_PROJECT) MainUnit<Mail> textParseOwnerProject
) {
return AnswerText.<Mail>builder()
.triggerPhrase("NO")
.answer(mail -> {
final Integer messageId = Attachments.findFirstButtonClick(mail.getAttachments())
.map(ButtonClickAttachment::getMessageId)
.orElseThrow();
context.save(mail.getPersonId(), Keys.INIT_SETTING_PRIVATE_PROJECT_MESSAGE_ID, messageId);
replaceBoxAnswer("Okay, I won't scan private projects.");
})
.next(textParseOwnerProject)
.build();
}
@Unit(TEXT_PARSE_OWNER_PROJECT)
public AnswerText<Mail> textParseOwnerProject(
@Unit(CHECK_PARSE_OWNER_PROJECT_YES) MainUnit<Mail> checkParseOwnerProjectYes,
@Unit(CHECK_PARSE_OWNER_PROJECT_NO) MainUnit<Mail> checkParseOwnerProjectNo
) {
return AnswerText.<Mail>builder()
.answer(
boxAnswer(
"Start tracking public projects that you own?",
inlineKeyBoard(
simpleLine(
simpleButton("Yes", "YES"),
simpleButton("No", "NO")
)
)
)
)
.activeType(AFTER)
.next(checkParseOwnerProjectYes)
.next(checkParseOwnerProjectNo)
.build();
}
@Unit(CHECK_PARSE_OWNER_PROJECT_YES)
public AnswerText<Mail> checkParseOwnerProjectYes(
@Unit(END_SETTING) MainUnit<Mail> endSetting
) {
final String step1 = """
-- -- -- -- --
🔘 Scanning of public projects has begun.
Wait...
-- -- -- -- --
""";
final String step2 = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🔘 Scanning merge requests in found projects.
Wait...
-- -- -- -- --
""";
final String step3 = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🟢 Merge requests have been successfully added. Found: {1}
🔘 Scanning pipelines in found merge requests.
Wait...
-- -- -- -- --
""";
final String step4 = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🟢 Merge requests have been successfully added. Found: {1}
🟢 Pipelines have been successfully added. Found: {2}
🔘 Scanning threads in merge requests.
Wait...
-- -- -- -- --
""";
final String finalAnswer = """
-- -- -- -- --
🟢 Projects have been successfully added to tracking. Found: {0}
🟢 Merge requests have been successfully added. Found: {1}
🟢 Pipelines have been successfully added. Found: {2}
🟢 Threads have been successfully added. Found: {3}
-- -- -- -- --
""";
return AnswerText.<Mail>builder()
.triggerCheck(clickButtonRaw("YES"))
.answer(mail -> {
final String personId = mail.getPersonId();
final Integer messageId = Attachments.findFirstButtonClick(mail.getAttachments())
.map(ButtonClickAttachment::getMessageId)
.orElseThrow();
sending.replaceMessage(personId, messageId, boxAnswer(step1));
projectParser.parseAllProjectOwner();
final int projectCount = projectService.getAllIds().size();
sending.replaceMessage(personId, messageId, boxAnswer(format(step2, projectCount)));
mergeRequestParser.parsingNewMergeRequest();
final int mrCount = mergeRequestsService.getAllIds().size();
sending.replaceMessage(personId, messageId, boxAnswer(format(step3, projectCount, mrCount)));
pipelineParser.scanNewPipeline();
final int pipelineCount = pipelineService.getAllIds().size();
sending.replaceMessage(personId, messageId, boxAnswer(format(step4, projectCount, mrCount, pipelineCount)));
discussionParser.scanNewDiscussion();
final int discussionCount = discussionService.getAllIds().size();
context.save(mail.getPersonId(), Keys.INIT_SETTING_PUBLIC_PROJECT_MESSAGE_ID, messageId);
return replaceBoxAnswer(format(finalAnswer, pipelineCount, mrCount, pipelineCount, discussionCount));
})
.next(endSetting)
.build();
}
@Unit(CHECK_PARSE_OWNER_PROJECT_NO)
public AnswerText<Mail> checkParseOwnerProjectNo(
@Unit(END_SETTING) MainUnit<Mail> endSetting
) {
return AnswerText.<Mail>builder()
.triggerCheck(clickButtonRaw("NO"))
.answer(mail -> {
final Integer messageId = Attachments.findFirstButtonClick(mail.getAttachments())
.map(ButtonClickAttachment::getMessageId)
.orElseThrow();
context.save(mail.getPersonId(), Keys.INIT_SETTING_PUBLIC_PROJECT_MESSAGE_ID, messageId);
return replaceBoxAnswer("Okay, I won't scan public projects.");
})
.next(endSetting)
.build();
}
@Unit(END_SETTING)
public AnswerText<Mail> endSetting() {
return AnswerText.<Mail>builder()
.activeType(AFTER)
.answer(
mail -> {
context.save(mail.getPersonId(), Keys.INIT_SETTING_FINISH, Boolean.TRUE);
settingService.isEnableAllNotify();
settingService.disableFirstStart();
return boxAnswer("""
Configuration completed successfully
Developer: [uPagge](https://mark.struchkov.dev)
""",
inlineKeyBoard(simpleButton("open menu", "INIT_SETTING_OPEN_MENU"))
);
}
)
.build();
}
}

View File

@ -0,0 +1,13 @@
package dev.struchkov.bot.gitlab.telegram.utils;
import dev.struchkov.godfather.main.domain.ContextKey;
import lombok.experimental.UtilityClass;
@UtilityClass
public class Keys {
public static final ContextKey<Boolean> INIT_SETTING_FINISH = ContextKey.of("INIT_SETTING_FINISH", Boolean.class);
public static final ContextKey<Integer> INIT_SETTING_PRIVATE_PROJECT_MESSAGE_ID = ContextKey.of("INIT_SETTING_PRIVATE_PROJECT_MESSAGE_ID", Integer.class);
public static final ContextKey<Integer> INIT_SETTING_PUBLIC_PROJECT_MESSAGE_ID = ContextKey.of("INIT_SETTING_PUBLIC_PROJECT_MESSAGE_ID", Integer.class);
}

View File

@ -10,18 +10,17 @@ public final class UnitName {
public static final String SETTINGS = "settings";
public static final String GET_TASKS = "getTasks";
public static final String GET_ASSIGNEE_MERGE_REQUEST = "getAssigneeMergeRequest";
public static final String CHECK_FIRST_START = "checkFirstStart";
public static final String CHECK_MENU_OR_ANSWER = "checkMenuOrAnswer";
public static final String FIRST_START = "checkFirstStart";
public static final String ANSWER_NOTE = "answerNote";
public static final String TEXT_PARSER_PRIVATE_PROJECT = "textParserPrivateProject";
public static final String CHECK_PARSER_PRIVATE_PROJECT = "checkParserPrivateProject";
public static final String PARSER_PRIVATE_PROJECT = "parserPrivateProject";
public static final String CHECK_PARSER_PRIVATE_PROJECT_YES = "checkParserPrivateProject";
public static final String TEXT_PARSE_OWNER_PROJECT = "textParseOwnerProject";
public static final String CHECK_PARSE_OWNER_PROJECT = "checkParseOwnerProject";
public static final String PARSE_OWNER_PROJECT = "parseOwnerProject";
public static final String CHECK_PARSE_OWNER_PROJECT_YES = "checkParseOwnerProject";
public static final String END_SETTING = "endSetting";
public static final String AUTHORIZATION = "AUTHORIZATION";
public static final String ACCESS_ERROR = "ACCESS_ERROR";
public static final String CHECK_PARSER_PRIVATE_PROJECT_NO = "CHECK_PARSER_PRIVATE_PROJECT_NO";
public static final String CHECK_PARSE_OWNER_PROJECT_NO = "CHECK_PARSE_OWNER_PROJECT_NO";
public static final String REPLACE_GENERAL_MENU = "REPLACE_GENERAL_MENU";
private UnitName() {
utilityClass();