diff --git a/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java b/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java index 90ba88d..3f9202b 100644 --- a/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java +++ b/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java @@ -18,5 +18,6 @@ public class BitbucketConfig { private String urlPullRequestOpen; private String urlPullRequestClose; private String urlPullRequestComment; + private String urlPullRequest; } diff --git a/src/main/java/com/tsc/bitbucketbot/domain/entity/TechInfo.java b/src/main/java/com/tsc/bitbucketbot/domain/entity/TechInfo.java new file mode 100644 index 0000000..da19f1b --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/entity/TechInfo.java @@ -0,0 +1,35 @@ +package com.tsc.bitbucketbot.domain.entity; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +@Getter +@Setter +@Entity +@Table(name = "tech_info") +@EqualsAndHashCode(of = "surogatId") +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class TechInfo { + + @Id + @Column(name = "surogat_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long surogatId; + + @Column(name = "last_comment_id") + private Long lastCommentId; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java b/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java new file mode 100644 index 0000000..cd337da --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/dto/bitbucket/CommentJson.java @@ -0,0 +1,22 @@ +package com.tsc.bitbucketbot.dto.bitbucket; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.tsc.bitbucketbot.utils.LocalDateFromEpochDeserializer; +import lombok.Data; + +import java.time.LocalDate; + +@Data +public class CommentJson { + + private Long id; + private String text; + private UserJson author; + + @JsonDeserialize(using = LocalDateFromEpochDeserializer.class) + private LocalDate createdDate; + + @JsonDeserialize(using = LocalDateFromEpochDeserializer.class) + private LocalDate updatedDate; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java b/src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java new file mode 100644 index 0000000..f1e0d0a --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/repository/jpa/TechInfoRepository.java @@ -0,0 +1,8 @@ +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/repository/jpa/UserRepository.java b/src/main/java/com/tsc/bitbucketbot/repository/jpa/UserRepository.java index 80ec58a..cd4633a 100644 --- a/src/main/java/com/tsc/bitbucketbot/repository/jpa/UserRepository.java +++ b/src/main/java/com/tsc/bitbucketbot/repository/jpa/UserRepository.java @@ -2,6 +2,7 @@ package com.tsc.bitbucketbot.repository.jpa; import com.tsc.bitbucketbot.domain.entity.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; import java.util.List; @@ -20,4 +21,7 @@ public interface UserRepository extends JpaRepository { List findAllByTelegramIdNotNullAndTokenNotNull(); + @Query("SELECT u.telegramId FROM User u WHERE u.login=:login") + Long findTelegramIdByLogin(String login); + } diff --git a/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java new file mode 100644 index 0000000..561cf6f --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerComments.java @@ -0,0 +1,106 @@ +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.PullRequest; +import com.tsc.bitbucketbot.dto.bitbucket.CommentJson; +import com.tsc.bitbucketbot.service.CommentService; +import com.tsc.bitbucketbot.service.MessageSendService; +import com.tsc.bitbucketbot.service.PullRequestsService; +import com.tsc.bitbucketbot.service.UserService; +import com.tsc.bitbucketbot.service.Utils; +import com.tsc.bitbucketbot.utils.Message; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.util.Optional; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +@Service +@RequiredArgsConstructor +public class SchedulerComments { + + private static final Integer COUNT = 100; + private static final Integer NO_COMMENT = 100; + private static final Pattern PATTERN = Pattern.compile("@[\\w]+"); + + private final CommentService commentService; + private final PullRequestsService pullRequestsService; + private final MessageSendService messageSendService; + private final UserService userService; + + private final BitbucketConfig bitbucketConfig; + + @Scheduled(cron = "5 8-18 * * MON-FRI") + public void test() { + long newLastCommentId = commentService.getLastCommentId(); + long commentId = newLastCommentId + 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, + bitbucketConfig.getUrlPullRequest() + .replace("{projectKey}", pullRequest.getProjectKey()) + .replace("{repositorySlug}", pullRequest.getRepositorySlug()) + .replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) + ); + newLastCommentId = commentId; + break; + } + } + if (commentSearch) { + count = 0; + break; + } else { + count++; + } + pageRequestSheet = pullRequestsService.getAll(Pagination.of(page++, COUNT)); + } + commentId += 1; + } while (count < NO_COMMENT); + commentService.saveLastCommentId(newLastCommentId); + } + + private String getPrUrl(long lastCommentId, PullRequest pullRequest) { + return bitbucketConfig.getUrlPullRequestComment() + .replace("{projectKey}", pullRequest.getProjectKey()) + .replace("{repositorySlug}", pullRequest.getRepositorySlug()) + .replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) + .replace("{commentId}", String.valueOf(lastCommentId)); + } + + private void notification(@NonNull CommentJson comment, @NonNull String urlPr) { + final String message = comment.getText(); + Matcher matcher = PATTERN.matcher(message); + 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, urlPr)) + .build() + ) + ); + } + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/CommentService.java b/src/main/java/com/tsc/bitbucketbot/service/CommentService.java new file mode 100644 index 0000000..453d748 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/CommentService.java @@ -0,0 +1,11 @@ +package com.tsc.bitbucketbot.service; + +import lombok.NonNull; + +public interface CommentService { + + Long getLastCommentId(); + + void saveLastCommentId(@NonNull Long commentId); + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/UserService.java b/src/main/java/com/tsc/bitbucketbot/service/UserService.java index f3e2724..a7cd0ed 100644 --- a/src/main/java/com/tsc/bitbucketbot/service/UserService.java +++ b/src/main/java/com/tsc/bitbucketbot/service/UserService.java @@ -25,4 +25,7 @@ public interface UserService { List addAll(Set newUsers); List getAllRegister(); + + Optional getTelegramIdByLogin(@NonNull String login); + } diff --git a/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java b/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java new file mode 100644 index 0000000..bcbcbe8 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/impl/CommentServiceImpl.java @@ -0,0 +1,29 @@ +package com.tsc.bitbucketbot.service.impl; + +import com.tsc.bitbucketbot.domain.entity.TechInfo; +import com.tsc.bitbucketbot.repository.jpa.TechInfoRepository; +import com.tsc.bitbucketbot.service.CommentService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.util.Optional; + +@Service +@RequiredArgsConstructor +public class CommentServiceImpl implements CommentService { + + private final TechInfoRepository techInfoRepository; + + @Override + public Long getLastCommentId() { + final Optional optLastCommentId = techInfoRepository.findById(1L); + return optLastCommentId.isPresent() ? optLastCommentId.get().getLastCommentId() : 0L; + } + + @Override + public void saveLastCommentId(@NonNull Long commentId) { + techInfoRepository.saveAndFlush(new TechInfo(1L, commentId)); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java b/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java index 3f5cd74..2e6ef84 100644 --- a/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java +++ b/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java @@ -67,4 +67,9 @@ public class UserServiceImpl implements UserService { return userRepository.findAllByTelegramIdNotNullAndTokenNotNull(); } + @Override + public Optional getTelegramIdByLogin(@NonNull String login) { + return Optional.ofNullable(userRepository.findTelegramIdByLogin(login)); + } + } diff --git a/src/main/java/com/tsc/bitbucketbot/utils/Message.java b/src/main/java/com/tsc/bitbucketbot/utils/Message.java index 9b73a6c..acc7fda 100644 --- a/src/main/java/com/tsc/bitbucketbot/utils/Message.java +++ b/src/main/java/com/tsc/bitbucketbot/utils/Message.java @@ -3,6 +3,7 @@ package com.tsc.bitbucketbot.utils; import com.tsc.bitbucketbot.domain.PullRequestStatus; import com.tsc.bitbucketbot.domain.entity.PullRequest; import com.tsc.bitbucketbot.domain.util.ReviewerChange; +import com.tsc.bitbucketbot.dto.bitbucket.CommentJson; import lombok.NonNull; import java.time.LocalDate; @@ -159,4 +160,10 @@ public class Message { return "Ну вот и все! Веселых выходных " + Smile.MIG + Smile.BREAK + "До понедельника" + Smile.BUY + Smile.TWO_BREAK; } + + public static String personalNotify(@NonNull CommentJson comment, @NonNull String urlPr) { + return Smile.BELL + " Вам " + link("тут", urlPr) + " телеграмма пришла от " + comment.getAuthor().getName() + + Smile.HR + + comment.getText().replaceAll("@[\\w]+", ""); + } } diff --git a/src/main/java/com/tsc/bitbucketbot/utils/Smile.java b/src/main/java/com/tsc/bitbucketbot/utils/Smile.java index 3179e47..3481ba2 100644 --- a/src/main/java/com/tsc/bitbucketbot/utils/Smile.java +++ b/src/main/java/com/tsc/bitbucketbot/utils/Smile.java @@ -27,6 +27,7 @@ public enum Smile { DAY_5("\uD83C\uDF1A"), MEGA_FUN("\uD83D\uDE02"), DANGEROUS("⚠️"), + BELL("\uD83D\uDECE"), HR("\n -- -- -- -- --\n"); @Getter diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index 932c4cc..f7b7cf9 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -24,5 +24,6 @@ bitbucketbot: url-pull-request-open: http://localhost:7990/rest/api/1.0/dashboard/pull-requests?limit=150&state=OPEN url-pull-request-close: http://localhost:7990/rest/api/1.0/dashboard/pull-requests?limit=150&closedSince=86400 url-pull-request-comment: http://localhost:7990/rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/comments/{commentId} + url-pull-request: http://localhost:7990/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/overview server: port: 8018