From da8c0bb7060a0199aa298c129e1ddb2ebcae6a1c Mon Sep 17 00:00:00 2001 From: upagge Date: Sun, 29 Mar 2020 12:48:14 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9D=D0=BE=D0=B2=D1=8B=D0=B5=20=D1=83=D0=B2?= =?UTF-8?q?=D0=B5=D0=B4=D0=BE=D0=BC=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD?= =?UTF-8?q?=D0=B0=20=D0=BE=D1=82=D0=B2=D0=B5=D1=82=D1=8B=20=D0=BA=D0=BE?= =?UTF-8?q?=D0=BC=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tsc/bitbucketbot/config/AppConfig.java | 2 +- .../tsc/bitbucketbot/domain/Pagination.java | 5 - .../bitbucketbot/domain/entity/Comment.java | 50 +++++++ .../dto/bitbucket/CommentJson.java | 2 + .../repository/jpa/CommentRepository.java | 16 +++ .../repository/jpa/TechInfoRepository.java | 8 -- .../scheduler/SchedulerComments.java | 124 ++++++++++++------ .../bitbucketbot/service/CommentService.java | 15 ++- .../service/impl/CommentServiceImpl.java | 34 +++-- .../com/tsc/bitbucketbot/utils/Message.java | 42 ++++-- src/main/resources/application.yaml | 2 +- src/main/resources/liquibase/change-log.xml | 1 + .../resources/liquibase/change-set/v1.4.0.xml | 37 ++++++ 13 files changed, 262 insertions(+), 76 deletions(-) create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/entity/Comment.java create mode 100644 src/main/java/com/tsc/bitbucketbot/repository/jpa/CommentRepository.java delete mode 100644 src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java create mode 100644 src/main/resources/liquibase/change-set/v1.4.0.xml diff --git a/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java b/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java index 1dd0ae6..a65bccc 100644 --- a/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java +++ b/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java @@ -13,7 +13,7 @@ public class AppConfig { @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); - taskScheduler.setPoolSize(6); + taskScheduler.setPoolSize(7); return taskScheduler; } diff --git a/src/main/java/com/tsc/bitbucketbot/domain/Pagination.java b/src/main/java/com/tsc/bitbucketbot/domain/Pagination.java index c184060..61dfd60 100644 --- a/src/main/java/com/tsc/bitbucketbot/domain/Pagination.java +++ b/src/main/java/com/tsc/bitbucketbot/domain/Pagination.java @@ -4,11 +4,6 @@ import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Data; -/** - * TODO: Добавить описание класса. - * - * @author upagge [03.02.2020] - */ @Data @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Pagination { diff --git a/src/main/java/com/tsc/bitbucketbot/domain/entity/Comment.java b/src/main/java/com/tsc/bitbucketbot/domain/entity/Comment.java new file mode 100644 index 0000000..cf15c81 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/entity/Comment.java @@ -0,0 +1,50 @@ +package com.tsc.bitbucketbot.domain.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import java.time.LocalDate; +import java.util.Set; + +@Getter +@Setter +@Entity +@Builder +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(of = "id") +@ToString +public class Comment { + + @Id + @Column(name = "id") +// @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "url") + private String url; + + @Column(name = "telegram") + private Long telegram; + + @Column(name = "date") + private LocalDate date; + + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "comment_tree", joinColumns = @JoinColumn(name = "parent_id")) + @Column(name = "child_id") + private Set answers; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java b/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java index cd337da..5531c37 100644 --- a/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java +++ b/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java @@ -5,6 +5,7 @@ import com.tsc.bitbucketbot.utils.LocalDateFromEpochDeserializer; import lombok.Data; import java.time.LocalDate; +import java.util.List; @Data public class CommentJson { @@ -12,6 +13,7 @@ public class CommentJson { private Long id; private String text; private UserJson author; + private List comments; @JsonDeserialize(using = LocalDateFromEpochDeserializer.class) private LocalDate createdDate; diff --git a/src/main/java/com/tsc/bitbucketbot/repository/jpa/CommentRepository.java b/src/main/java/com/tsc/bitbucketbot/repository/jpa/CommentRepository.java new file mode 100644 index 0000000..c19b116 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/repository/jpa/CommentRepository.java @@ -0,0 +1,16 @@ +package com.tsc.bitbucketbot.repository.jpa; + +import com.tsc.bitbucketbot.domain.entity.Comment; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; + +public interface CommentRepository extends JpaRepository { + + Optional findFirstByOrderByIdDesc(); + + List findByDateBetween(LocalDate dateFrom, LocalDate dateTo); + +} diff --git a/src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java b/src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java deleted file mode 100644 index f1e0d0a..0000000 --- a/src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.tsc.bitbucketbot.repository.jpa; - -import com.tsc.bitbucketbot.domain.entity.TechInfo; -import org.springframework.data.jpa.repository.JpaRepository; - -public interface TechInfoRepository extends JpaRepository { - -} diff --git a/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java index 11926c6..3a1a64d 100644 --- a/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java +++ b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java @@ -3,6 +3,7 @@ package com.tsc.bitbucketbot.scheduler; import com.tsc.bitbucketbot.config.BitbucketConfig; import com.tsc.bitbucketbot.domain.MessageSend; import com.tsc.bitbucketbot.domain.Pagination; +import com.tsc.bitbucketbot.domain.entity.Comment; import com.tsc.bitbucketbot.domain.entity.PullRequest; import com.tsc.bitbucketbot.dto.bitbucket.CommentJson; import com.tsc.bitbucketbot.service.CommentService; @@ -18,9 +19,13 @@ import org.springframework.data.domain.Page; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; @Slf4j @Service @@ -28,7 +33,7 @@ import java.util.regex.Pattern; public class SchedulerComments { private static final Integer COUNT = 100; - private static final Integer NO_COMMENT = 30; + private static final Integer NO_COMMENT = 100; private static final Pattern PATTERN = Pattern.compile("@[\\w]+"); private final CommentService commentService; @@ -39,69 +44,110 @@ public class SchedulerComments { private final BitbucketConfig bitbucketConfig; @Scheduled(cron = "0 */5 8-18 * * MON-FRI") - public void test() { + public void newComments() { log.info("Начало сканирования комментариев"); - long newLastCommentId = commentService.getLastCommentId(); - long commentId = newLastCommentId + 1; + long commentId = commentService.getLastCommentId() + 1; long count = 0; do { int page = 0; - Page pageRequestSheet = pullRequestsService.getAll(Pagination.of(page++, COUNT)); - while (pageRequestSheet.hasContent()) { - boolean commentSearch = false; - for (PullRequest pullRequest : pageRequestSheet.getContent()) { - final Optional commentJson = Utils.urlToJson( - getPrUrl(commentId, pullRequest), - bitbucketConfig.getToken(), - CommentJson.class - ); - if (commentJson.isPresent()) { - commentSearch = true; - final CommentJson comment = commentJson.get(); - notification( - comment, - pullRequest.getName(), - bitbucketConfig.getUrlPullRequest() - .replace("{projectKey}", pullRequest.getProjectKey()) - .replace("{repositorySlug}", pullRequest.getRepositorySlug()) - .replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) - ); - newLastCommentId = commentId; + Page pullRequestPage = pullRequestsService.getAll(Pagination.of(page++, COUNT)); + while (pullRequestPage.hasContent()) { + for (PullRequest pullRequest : pullRequestPage.getContent()) { + final String commentUrl = getCommentUrl(commentId, pullRequest); + final Optional optCommentJson = Utils.urlToJson(commentUrl, bitbucketConfig.getToken(), CommentJson.class); + if (optCommentJson.isPresent()) { + final CommentJson commentJson = optCommentJson.get(); + notification(commentJson, pullRequest); + saveComments(commentJson, commentUrl); + count = 0; break; } } - if (commentSearch) { - count = 0; - break; - } else { - count++; - } - pageRequestSheet = pullRequestsService.getAll(Pagination.of(page++, COUNT)); + pullRequestPage = pullRequestsService.getAll(Pagination.of(page++, COUNT)); } + count++; commentId += 1; } while (count < NO_COMMENT); - commentService.saveLastCommentId(newLastCommentId); log.info("Конец сканирования комментариев"); } - private String getPrUrl(long lastCommentId, PullRequest pullRequest) { + @Scheduled(cron = "0 */1 8-18 * * MON-FRI") + public void oldComments() { + @NonNull final List comments = commentService.getAllBetweenDate(LocalDate.now().minusDays(10), LocalDate.now()); + for (Comment comment : comments) { + final Optional optCommentJson = Utils.urlToJson( + comment.getUrl(), + bitbucketConfig.getToken(), + CommentJson.class + ); + if (optCommentJson.isPresent()) { + final CommentJson commentJson = optCommentJson.get(); + final Set oldAnswerIds = comment.getAnswers(); + final List answerJsons = commentJson.getComments().stream() + .filter(answerJson -> !oldAnswerIds.contains(answerJson.getId())) + .collect(Collectors.toList()); + if (!answerJsons.isEmpty()) { + userService.getTelegramIdByLogin(commentJson.getAuthor().getName()).ifPresent( + telegramAuthorComment -> messageSendService.add( + MessageSend.builder() + .telegramId(telegramAuthorComment) + .message(Message.answerComment(commentJson.getText(), answerJsons)) + .build() + ) + ); + comment.getAnswers().addAll(answerJsons.stream().map(CommentJson::getId).collect(Collectors.toList())); + commentService.save(comment); + } + } else { + commentService.delete(comment.getId()); + } + } + } + + @NonNull + private void saveComments(CommentJson comment, String commentUrl) { + final Comment newComment = new Comment(); + newComment.setId(comment.getId()); + newComment.setDate(LocalDate.now()); + newComment.setUrl(commentUrl); + userService.getTelegramIdByLogin(comment.getAuthor().getName()).ifPresent(newComment::setTelegram); + commentService.save(newComment); + } + + private String getCommentUrl(long commentId, PullRequest pullRequest) { return bitbucketConfig.getUrlPullRequestComment() .replace("{projectKey}", pullRequest.getProjectKey()) .replace("{repositorySlug}", pullRequest.getRepositorySlug()) .replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) - .replace("{commentId}", String.valueOf(lastCommentId)); + .replace("{commentId}", String.valueOf(commentId)); } - private void notification(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) { - final String message = comment.getText(); - Matcher matcher = PATTERN.matcher(message); + private void notification(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) { +// notificationAuthorPr(comment, pullRequest); + notificationPersonal(comment, pullRequest); + } + + private void notificationAuthorPr(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) { + final Long authorTelegram = pullRequest.getAuthor().getTelegramId(); + if (authorTelegram != null) { + messageSendService.add( + MessageSend.builder() + .telegramId(authorTelegram) + .message(Message.commentPr(comment, pullRequest.getName(), pullRequest.getUrl())) + .build() + ); + } + } + + private void notificationPersonal(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) { + Matcher matcher = PATTERN.matcher(comment.getText()); while (matcher.find()) { final String login = matcher.group(0).replace("@", ""); userService.getTelegramIdByLogin(login).ifPresent( telegramId -> messageSendService.add( MessageSend.builder() .telegramId(telegramId) - .message(Message.personalNotify(comment, namePr, urlPr)) + .message(Message.personalNotify(comment, pullRequest.getName(), pullRequest.getUrl())) .build() ) ); diff --git a/src/main/java/com/tsc/bitbucketbot/service/CommentService.java b/src/main/java/com/tsc/bitbucketbot/service/CommentService.java index 453d748..2f309fa 100644 --- a/src/main/java/com/tsc/bitbucketbot/service/CommentService.java +++ b/src/main/java/com/tsc/bitbucketbot/service/CommentService.java @@ -1,11 +1,24 @@ package com.tsc.bitbucketbot.service; +import com.tsc.bitbucketbot.domain.Pagination; +import com.tsc.bitbucketbot.domain.entity.Comment; import lombok.NonNull; +import org.springframework.data.domain.Page; + +import java.time.LocalDate; +import java.util.List; public interface CommentService { Long getLastCommentId(); - void saveLastCommentId(@NonNull Long commentId); + Page getAll(@NonNull Pagination pagination); + + @NonNull + List getAllBetweenDate(LocalDate dateFrom, LocalDate dateTo); + + void save(@NonNull Comment comment); + + void delete(@NonNull Long id); } diff --git a/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java b/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java index bcbcbe8..313373e 100644 --- a/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java +++ b/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java @@ -1,29 +1,47 @@ package com.tsc.bitbucketbot.service.impl; -import com.tsc.bitbucketbot.domain.entity.TechInfo; -import com.tsc.bitbucketbot.repository.jpa.TechInfoRepository; +import com.tsc.bitbucketbot.domain.Pagination; +import com.tsc.bitbucketbot.domain.entity.Comment; +import com.tsc.bitbucketbot.repository.jpa.CommentRepository; import com.tsc.bitbucketbot.service.CommentService; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; -import java.util.Optional; +import java.time.LocalDate; +import java.util.List; @Service @RequiredArgsConstructor public class CommentServiceImpl implements CommentService { - private final TechInfoRepository techInfoRepository; + private final CommentRepository commentRepository; @Override public Long getLastCommentId() { - final Optional optLastCommentId = techInfoRepository.findById(1L); - return optLastCommentId.isPresent() ? optLastCommentId.get().getLastCommentId() : 0L; + return commentRepository.findFirstByOrderByIdDesc().map(Comment::getId).orElse(0L); } @Override - public void saveLastCommentId(@NonNull Long commentId) { - techInfoRepository.saveAndFlush(new TechInfo(1L, commentId)); + public Page getAll(@NonNull Pagination pagination) { + return commentRepository.findAll(PageRequest.of(pagination.getPage(), pagination.getSize())); + } + + @Override + public @NonNull List getAllBetweenDate(LocalDate dateFrom, LocalDate dateTo) { + return commentRepository.findByDateBetween(dateFrom, dateTo); + } + + @Override + public void save(@NonNull Comment comment) { + commentRepository.save(comment); + } + + @Override + public void delete(@NonNull Long id) { + commentRepository.deleteById(id); } } diff --git a/src/main/java/com/tsc/bitbucketbot/utils/Message.java b/src/main/java/com/tsc/bitbucketbot/utils/Message.java index 1176135..2b77989 100644 --- a/src/main/java/com/tsc/bitbucketbot/utils/Message.java +++ b/src/main/java/com/tsc/bitbucketbot/utils/Message.java @@ -131,6 +131,35 @@ public class Message { return message.toString(); } + @NonNull + public static String goodWeekEnd() { + return "Ну вот и все! Веселых выходных " + Smile.MIG + Smile.BR + + "До понедельника" + Smile.BUY + Smile.TWO_BR; + } + + public static String commentPr(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) { + return Smile.BELL + " *Новый комментарий к ПР*" + Smile.BR + + link(namePr, urlPr) + + Smile.HR + + comment.getAuthor().getName() + ": " + comment.getText().replaceAll("@[\\w]+", ""); + } + + public static String personalNotify(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) { + return Smile.BELL + " *Новое упоминание* | " + comment.getAuthor().getName() + Smile.BR + + link(namePr, urlPr) + + Smile.HR + + comment.getText().replaceAll("@[\\w]+", ""); + } + + public static String answerComment(@NonNull String commentMessage, @NonNull List answerJsons) { + final StringBuilder message = new StringBuilder(); + message.append(Smile.BELL).append("Новые ответы на ваш комментарий").append(Smile.HR) + .append(commentMessage, 0, Math.min(commentMessage.length(), 180)).append(Smile.HR); + answerJsons.forEach(answerJson -> message.append(answerJson.getAuthor().getName()).append(": ") + .append(answerJson.getText(), 0, Math.min(answerJson.getText().length(), 500)).append(Smile.TWO_BR)); + return message.toString(); + } + private static String needWorkPr(@NonNull List pullRequestsNeedWork) { final StringBuilder message = new StringBuilder(); pullRequestsNeedWork.stream() @@ -157,17 +186,4 @@ public class Message { return "[" + name + "](" + url + ")"; } - @NonNull - public static String goodWeekEnd() { - return "Ну вот и все! Веселых выходных " + Smile.MIG + Smile.BR + - "До понедельника" + Smile.BUY + Smile.TWO_BR; - } - - public static String personalNotify(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) { - return Smile.BELL + " *Новое упоминание* | " + comment.getAuthor().getName() + Smile.BR + - link(namePr, urlPr) + - Smile.HR + - comment.getText().replaceAll("@[\\w]+", ""); - } - } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index f7b7cf9..ee2a01d 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -7,7 +7,7 @@ spring: liquibase: change-log: classpath:liquibase/change-log.xml jpa: - show-sql: true + show-sql: false hibernate: ddl-auto: none database-platform: org.hibernate.dialect.PostgreSQLDialect diff --git a/src/main/resources/liquibase/change-log.xml b/src/main/resources/liquibase/change-log.xml index db0a65f..01ca1ce 100644 --- a/src/main/resources/liquibase/change-log.xml +++ b/src/main/resources/liquibase/change-log.xml @@ -6,5 +6,6 @@ + \ No newline at end of file diff --git a/src/main/resources/liquibase/change-set/v1.4.0.xml b/src/main/resources/liquibase/change-set/v1.4.0.xml new file mode 100644 index 0000000..52beb89 --- /dev/null +++ b/src/main/resources/liquibase/change-set/v1.4.0.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file