diff --git a/pom.xml b/pom.xml index c1b7d8e..5b4d712 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,30 @@ + + org.sadtech.basic.filter + criteria-filter + 0.1.0-SNAPSHOT + + + + org.sadtech.basic + project-database + 0.1.0-SNAPSHOT + + + + org.hibernate.orm + hibernate-jpamodelgen + 6.0.0.Alpha5 + + + + org.springframework.boot + spring-boot-configuration-processor + 2.3.1.RELEASE + + com.google.guava guava diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/config/AppConfig.java b/src/main/java/org/sadtech/bot/bitbucketbot/config/AppConfig.java index e03c70b..657a5de 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/config/AppConfig.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/config/AppConfig.java @@ -9,10 +9,18 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +/** + * Общий файл настройки всего приложения. + * + * @author upagge + */ @Configuration @EnableScheduling public class AppConfig { + /** + * Отвечает за работу шедулеров в паралельном режиме + */ @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/config/BitbucketConfig.java b/src/main/java/org/sadtech/bot/bitbucketbot/config/BitbucketConfig.java deleted file mode 100644 index 5e73202..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/config/BitbucketConfig.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.sadtech.bot.bitbucketbot.config; - -import lombok.Data; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -/** - * TODO: Добавить описание класса. - * - * @author upagge [31.01.2020] - */ -@Data -@Component -@ConfigurationProperties("bitbucketbot.bitbucket") -public class BitbucketConfig { - - private String token; - private String urlPullRequestOpen; - private String urlPullRequestClose; - private String urlPullRequestComment; - private String urlPullRequest; - -} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/config/properties/BitbucketProperty.java b/src/main/java/org/sadtech/bot/bitbucketbot/config/properties/BitbucketProperty.java new file mode 100644 index 0000000..fd3f9a6 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/config/properties/BitbucketProperty.java @@ -0,0 +1,49 @@ +package org.sadtech.bot.bitbucketbot.config.properties; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Данные необходимые для взаимодействия с API Bitbucket. + * + * @author upagge [31.01.2020] + */ +@Getter +@Setter +@Component +@ConfigurationProperties("bitbucketbot.bitbucket") +public class BitbucketProperty { + + /** + * Токен администратора + */ + private String token; + + /** + * Адрес, по которому можно получить открытые ПР + */ + private String urlPullRequestOpen; + + /** + * Адрес, по которому можно получить закрытые ПР + */ + private String urlPullRequestClose; + + /** + * Адрес, по которому можно получить комментарии к ПР + */ + private String urlPullRequestComment; + + /** + * Адрес ПР + */ + private String urlPullRequest; + + /** + * Адрес на получение пользователей битбакет + */ + private String urlUsers; + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/config/properties/CommentSchedulerProperty.java b/src/main/java/org/sadtech/bot/bitbucketbot/config/properties/CommentSchedulerProperty.java new file mode 100644 index 0000000..d9af006 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/config/properties/CommentSchedulerProperty.java @@ -0,0 +1,30 @@ +package org.sadtech.bot.bitbucketbot.config.properties; + +import lombok.Getter; +import lombok.Setter; +import org.sadtech.bot.bitbucketbot.scheduler.SchedulerComments; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * Данные для конфигурации {@link SchedulerComments} + * + * @author upagge + */ +@Getter +@Setter +@Component +@ConfigurationProperties("bitbucketbot.scheduler.comment.settings") +public class CommentSchedulerProperty { + + /** + * Количество пустых комментариев подряд, после которого поиск останавливается + */ + private Integer noCommentCount; + + /** + * Количество комментариев в пачке сканирования + */ + private Integer commentCount; + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/controller/UserController.java b/src/main/java/org/sadtech/bot/bitbucketbot/controller/UserController.java index cc3e920..5e31e7c 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/controller/UserController.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/controller/UserController.java @@ -1,9 +1,9 @@ package org.sadtech.bot.bitbucketbot.controller; import lombok.RequiredArgsConstructor; -import org.sadtech.bot.bitbucketbot.domain.entity.User; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.sadtech.bot.bitbucketbot.dto.UserDto; -import org.sadtech.bot.bitbucketbot.service.UserService; +import org.sadtech.bot.bitbucketbot.service.PersonService; import org.springframework.core.convert.ConversionService; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.PostMapping; @@ -12,16 +12,21 @@ import org.springframework.web.bind.annotation.RestController; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +/** + * Контроллер отвечат за регистрацию пользователей. + * + * @author upagge + */ @RestController @RequiredArgsConstructor public class UserController { - private final UserService userService; + private final PersonService personService; private final ConversionService conversionService; @PostMapping(value = "/api/user/reg", consumes = APPLICATION_JSON_VALUE) public HttpStatus register(@RequestBody UserDto userDto) { - userService.reg(conversionService.convert(userDto, User.class)); + personService.reg(conversionService.convert(userDto, Person.class)); return HttpStatus.OK; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/PullRequestStatus.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/PullRequestStatus.java index 7f194eb..c7f83bd 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/PullRequestStatus.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/PullRequestStatus.java @@ -5,6 +5,8 @@ package org.sadtech.bot.bitbucketbot.domain; */ public enum PullRequestStatus { - OPEN, MERGED, DECLINED, DELETE + OPEN, + MERGED, + DECLINED } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/TaskStatus.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/TaskStatus.java new file mode 100644 index 0000000..e107385 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/TaskStatus.java @@ -0,0 +1,8 @@ +package org.sadtech.bot.bitbucketbot.domain; + +public enum TaskStatus { + + OPEN, + RESOLVED + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/Change.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/Change.java index de1f5b0..5838cb3 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/Change.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/Change.java @@ -8,13 +8,15 @@ import java.time.LocalDateTime; import java.util.Set; @Getter -@EqualsAndHashCode(of = "id") +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public abstract class Change { protected final ChangeType type; protected final LocalDateTime localDateTime = LocalDateTime.now(); protected final Set telegramIds; + @Setter + @EqualsAndHashCode.Include protected Long id; protected Change(ChangeType type, Set telegramIds) { diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ChangeType.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ChangeType.java index 3a9684c..498e76d 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ChangeType.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ChangeType.java @@ -8,6 +8,10 @@ public enum ChangeType { NEW_PR, CONFLICT_PR, NEW_COMMENT, - NEW_ANSWERS_COMMENT + NEW_ANSWERS_COMMENT, + NEW_TASK, + DELETED_TASK, + RESOLVED_TASK, + OPEN_TASK; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/AnswerCommentChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/comment/AnswerCommentChange.java similarity index 80% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/AnswerCommentChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/comment/AnswerCommentChange.java index ae35e22..95a8a08 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/AnswerCommentChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/comment/AnswerCommentChange.java @@ -1,9 +1,11 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.comment; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import org.sadtech.bot.bitbucketbot.domain.Answer; +import org.sadtech.bot.bitbucketbot.domain.change.Change; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.List; import java.util.Set; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/CommentChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/comment/CommentChange.java similarity index 77% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/CommentChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/comment/CommentChange.java index dfe3bc7..49dc160 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/CommentChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/comment/CommentChange.java @@ -1,8 +1,10 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.comment; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.Change; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.Set; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ConflictPrChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/ConflictPrChange.java similarity index 72% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ConflictPrChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/ConflictPrChange.java index 0012f45..28bd291 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ConflictPrChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/ConflictPrChange.java @@ -1,7 +1,8 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.pullrequest; import lombok.Builder; import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.Set; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/NewPrChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/NewPrChange.java similarity index 70% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/NewPrChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/NewPrChange.java index db30496..a10e2df 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/NewPrChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/NewPrChange.java @@ -1,8 +1,9 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.pullrequest; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.Set; @@ -16,11 +17,11 @@ public class NewPrChange extends PrChange { @Builder private NewPrChange( Set telegramIds, - String name, + String title, String url, String description, String author) { - super(ChangeType.NEW_PR, telegramIds, name, url); + super(ChangeType.NEW_PR, telegramIds, title, url); this.description = description; this.author = author; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/PrChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/PrChange.java similarity index 55% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/PrChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/PrChange.java index 8bb678a..a5a0f8f 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/PrChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/PrChange.java @@ -1,7 +1,9 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.pullrequest; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.Change; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.Set; @@ -9,12 +11,12 @@ import java.util.Set; @EqualsAndHashCode(callSuper = true) public abstract class PrChange extends Change { - private final String name; + private final String title; private final String url; - protected PrChange(ChangeType type, Set telegramIds, String name, String url) { + protected PrChange(ChangeType type, Set telegramIds, String title, String url) { super(type, telegramIds); - this.name = name; + this.title = title; this.url = url; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ReviewersPrChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/ReviewersPrChange.java similarity index 62% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ReviewersPrChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/ReviewersPrChange.java index 004a93a..7660731 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/ReviewersPrChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/ReviewersPrChange.java @@ -1,12 +1,13 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.pullrequest; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange; +import java.util.Collections; import java.util.List; -import java.util.Set; @Getter @EqualsAndHashCode(callSuper = true) @@ -16,11 +17,11 @@ public class ReviewersPrChange extends PrChange { @Builder private ReviewersPrChange( - Set telegramIds, - String name, + Long telegramId, + String title, String url, List reviewerChanges) { - super(ChangeType.REVIEWERS, telegramIds, name, url); + super(ChangeType.REVIEWERS, Collections.singleton(telegramId), title, url); this.reviewerChanges = reviewerChanges; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/StatusPrChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/StatusPrChange.java similarity index 84% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/StatusPrChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/StatusPrChange.java index 59ebca2..7254bed 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/StatusPrChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/StatusPrChange.java @@ -1,9 +1,10 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.pullrequest; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.Set; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/UpdatePrChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/UpdatePrChange.java similarity index 78% rename from src/main/java/org/sadtech/bot/bitbucketbot/domain/change/UpdatePrChange.java rename to src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/UpdatePrChange.java index e85d3eb..8e52fb9 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/UpdatePrChange.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/pullrequest/UpdatePrChange.java @@ -1,8 +1,9 @@ -package org.sadtech.bot.bitbucketbot.domain.change; +package org.sadtech.bot.bitbucketbot.domain.change.pullrequest; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import java.util.Set; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/task/TaskChange.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/task/TaskChange.java new file mode 100644 index 0000000..79556dc --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/change/task/TaskChange.java @@ -0,0 +1,32 @@ +package org.sadtech.bot.bitbucketbot.domain.change.task; + +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import org.sadtech.bot.bitbucketbot.domain.change.Change; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; + +import java.util.Set; + +@Getter +@EqualsAndHashCode(callSuper = true) +public class TaskChange extends Change { + + protected final String authorName; + protected final String url; + protected final String messageTask; + + @Builder + protected TaskChange( + ChangeType type, + Set telegramIds, + String authorName, + String url, + String messageTask + ) { + super(type, telegramIds); + this.authorName = authorName; + this.url = url; + this.messageTask = messageTask; + } +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Comment.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Comment.java index 0dfda0c..679235a 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Comment.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Comment.java @@ -1,48 +1,58 @@ package org.sadtech.bot.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.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; +import javax.persistence.Table; import java.time.LocalDateTime; import java.util.Set; @Getter @Setter @Entity -@Builder -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode(of = "id") -@ToString +@Table(name = "pull_request_comment") +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class Comment { + /** + * Идентификатор + */ @Id @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + @EqualsAndHashCode.Include private Long id; @Column(name = "url") private String url; - @Column(name = "pr_url") - private String prUrl; + @Column(name = "pull_request_id") + private Long pullRequestId; - @Column(name = "telegram") - private Long telegram; + @Column(name = "author_login") + private String author; - @Column(name = "date") - private LocalDateTime date; + @Column(name = "message") + private String message; + + @Column(name = "createDate") + private LocalDateTime createDate; + + /** + * Версия объекта в битбакет + */ + @Column(name = "bitbucket_version") + private Integer bitbucketVersion; @ElementCollection(fetch = FetchType.EAGER) @CollectionTable(name = "comment_tree", joinColumns = @JoinColumn(name = "parent_id")) diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Person.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Person.java new file mode 100644 index 0000000..e86dfac --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Person.java @@ -0,0 +1,59 @@ +package org.sadtech.bot.bitbucketbot.domain.entity; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * Пользователь битбакета. + * + * @author upagge [30.01.2020] + */ +@Getter +@Setter +@Entity +@Table(name = "person") +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class Person { + + /** + * Логин + */ + @Id + @Column(name = "id") + @GeneratedValue(strategy = GenerationType.IDENTITY) + @EqualsAndHashCode.Include + private Long id; + + /** + * Логин + */ + @Column(name = "login") + private String login; + + /** + * Персональный токен из битбакета + */ + @Column(name = "bitbucket_token") + private String token; + + /** + * Идентификатор телеграма + */ + @Column(name = "telegram_id") + private Long telegramId; + + /** + * ФИО + */ + @Column(name = "full_name") + private String fullName; + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/PullRequest.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/PullRequest.java index eed5f3f..74679a8 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/PullRequest.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/PullRequest.java @@ -1,12 +1,8 @@ package org.sadtech.bot.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 org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import javax.persistence.CascadeType; @@ -19,74 +15,122 @@ import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; import javax.persistence.OneToMany; +import javax.persistence.Table; import java.time.LocalDateTime; import java.util.List; /** - * TODO: Добавить описание класса. + * Сущность ПуллРеквест. * * @author upagge [31.01.2020] */ @Getter @Setter @Entity -@Builder -@AllArgsConstructor -@NoArgsConstructor -@EqualsAndHashCode(of = "id") -@ToString +@Table(name = "pull_request") +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class PullRequest { + /** + * Идентификатор + */ @Id @Column(name = "id") @GeneratedValue(strategy = GenerationType.IDENTITY) + @EqualsAndHashCode.Include private Long id; + /** + * Идентификатор на стороне битбакета + */ @Column(name = "bitbucket_pr_id") private Long bitbucketId; + /** + * Идентификатор репозитория на стороне битбакета + */ @Column(name = "repository_id") private Long repositoryId; + /** + * Идентификатор проекта на стороне битбакета + */ @Column(name = "project_key") private String projectKey; + /** + * Символьный идентификатор на стороне битбакета + */ @Column(name = "repository_slug") private String repositorySlug; + /** + * Версия объекта для блокировок + */ @Column(name = "version") private Integer version; + /** + * Описание пулреквеста + */ @Column(name = "description") private String description; - @ManyToOne - @JoinColumn(name = "author_login") - private User author; - - @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) - @JoinColumn(name = "pull_request_id") - private List reviewers; - + /** + * Адрес ПР + */ @Column(name = "url") private String url; - @Column(name = "name") - private String name; + /** + * Название ПР + */ + @Column(name = "title") + private String title; + /** + * Статус ПР + */ @Enumerated(EnumType.STRING) @Column(name = "status") private PullRequestStatus status; + /** + * Дата создания + */ @Column(name = "create_date") private LocalDateTime createDate; + /** + * Дата обновления + */ @Column(name = "update_date") private LocalDateTime updateDate; + /** + * Флаг показывающий наличие конфликта в ПР + */ @Column(name = "conflict") private boolean conflict; + /** + * Версия объекта в битбакет + */ + @Column(name = "bitbucket_version") + private Integer bitbucketVersion; + + /** + * Автор ПР + */ + @Column(name = "author_login") + private String authorLogin; + + /** + * Ревьюверы + */ + @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) + @JoinColumn(name = "pull_request_id") + private List reviewers; + } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Reviewer.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Reviewer.java index 4697071..4579a3a 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Reviewer.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Reviewer.java @@ -1,9 +1,7 @@ package org.sadtech.bot.bitbucketbot.domain.entity; -import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; -import lombok.NoArgsConstructor; import lombok.Setter; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; @@ -17,27 +15,35 @@ import javax.persistence.Id; import javax.persistence.Table; /** - * TODO: Добавить описание класса. + * Ревьювер пулреквеста. * * @author upagge [01.02.2020] */ @Entity @Getter @Setter -@NoArgsConstructor -@AllArgsConstructor -@Table(name = "reviewer") -@EqualsAndHashCode(of = "id") +@Table(name = "pull_request_reviewer") +@EqualsAndHashCode(onlyExplicitlyIncluded = true) public class Reviewer { + /** + * Идентификатор + */ @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "id") + @EqualsAndHashCode.Include + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; + /** + * Пользователь + */ @Column(name = "user_login") - private String user; + private String userLogin; + /** + * Статус + */ @Enumerated(EnumType.STRING) @Column(name = "status") private ReviewerStatus status; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Task.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Task.java new file mode 100644 index 0000000..972e51c --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/Task.java @@ -0,0 +1,69 @@ +package org.sadtech.bot.bitbucketbot.domain.entity; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import org.sadtech.bot.bitbucketbot.domain.TaskStatus; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import java.time.LocalDateTime; + +@Entity +@Getter +@Setter +@Table(name = "pull_request_task") +@EqualsAndHashCode(onlyExplicitlyIncluded = true) +public class Task { + + /** + * Идентификатор + */ + @Id + @Column(name = "id") + @EqualsAndHashCode.Include + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * Описание задачи + */ + @Column(name = "description") + private String description; + + @Enumerated(EnumType.STRING) + @Column(name = "status") + private TaskStatus status; + + @Column(name = "create_date") + private LocalDateTime createDate; + + @OneToMany + @Column(name = "pull_request_id") + private Long pullRequestId; + + @Column(name = "url") + private String url; + + @Column(name = "url_api") + private String urlApi; + + /** + * Версия объекта в битбакет + */ + @Column(name = "bitbucket_version") + private Integer bitbucketVersion; + + @OneToMany + @JoinColumn(name = "author_login") + private Person author; + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/TechInfo.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/TechInfo.java deleted file mode 100644 index 18527a9..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/TechInfo.java +++ /dev/null @@ -1,35 +0,0 @@ -package org.sadtech.bot.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/org/sadtech/bot/bitbucketbot/domain/entity/User.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/User.java deleted file mode 100644 index 523827b..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/domain/entity/User.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.sadtech.bot.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.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; - -/** - * TODO: Добавить описание класса. - * - * @author upagge [30.01.2020] - */ -@Builder -@Getter -@Setter -@Entity -@Table(name = "`user`") -@NoArgsConstructor -@AllArgsConstructor -@EqualsAndHashCode(of = "login") -@ToString -public class User { - - @Id - @Column(name = "login") - private String login; - - @Column(name = "token") - private String token; - - @Column(name = "telegram_id") - private Long telegramId; - - @Column(name = "full_name") - private String fullName; - -} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/domain/filter/PullRequestFilter.java b/src/main/java/org/sadtech/bot/bitbucketbot/domain/filter/PullRequestFilter.java new file mode 100644 index 0000000..081e1e4 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/domain/filter/PullRequestFilter.java @@ -0,0 +1,20 @@ +package org.sadtech.bot.bitbucketbot.domain.filter; + +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class PullRequestFilter { + + private Long bitbucketId; + private Long bitbucketRepositoryId; + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentJson.java b/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentJson.java index ad92f0c..195af07 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentJson.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentJson.java @@ -11,10 +11,15 @@ import java.util.List; public class CommentJson { private Long id; + private Integer version; private String text; private UserJson author; private List comments; + private Severity severity; + + private CommentState state; + @JsonDeserialize(using = LocalDateTimeFromEpochDeserializer.class) private LocalDateTime createdDate; diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentState.java b/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentState.java new file mode 100644 index 0000000..7c69842 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/CommentState.java @@ -0,0 +1,8 @@ +package org.sadtech.bot.bitbucketbot.dto.bitbucket; + +public enum CommentState { + + RESOLVED, + OPEN + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/Severity.java b/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/Severity.java new file mode 100644 index 0000000..77a97af --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/dto/bitbucket/Severity.java @@ -0,0 +1,8 @@ +package org.sadtech.bot.bitbucketbot.dto.bitbucket; + +public enum Severity { + + NORMAL, + BLOCKER + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/exception/BitbucketBotException.java b/src/main/java/org/sadtech/bot/bitbucketbot/exception/BitbucketBotException.java index 485d0b5..cf16000 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/exception/BitbucketBotException.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/exception/BitbucketBotException.java @@ -1,9 +1,13 @@ package org.sadtech.bot.bitbucketbot.exception; -class BitbucketBotException extends RuntimeException { +abstract class BitbucketBotException extends RuntimeException { - public BitbucketBotException(String message) { + protected BitbucketBotException(String message) { super(message); } + protected BitbucketBotException(String message, Throwable throwable) { + super(message, throwable); + } + } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/exception/CreateException.java b/src/main/java/org/sadtech/bot/bitbucketbot/exception/CreateException.java new file mode 100644 index 0000000..80479d9 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/exception/CreateException.java @@ -0,0 +1,9 @@ +package org.sadtech.bot.bitbucketbot.exception; + +public class CreateException extends BitbucketBotException { + + public CreateException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/exception/UpdateException.java b/src/main/java/org/sadtech/bot/bitbucketbot/exception/UpdateException.java new file mode 100644 index 0000000..802e45c --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/exception/UpdateException.java @@ -0,0 +1,9 @@ +package org.sadtech.bot.bitbucketbot.exception; + +public class UpdateException extends BitbucketBotException { + + public UpdateException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/PullRequestsRepository.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/PullRequestsRepository.java new file mode 100644 index 0000000..bf25529 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/PullRequestsRepository.java @@ -0,0 +1,20 @@ +package org.sadtech.bot.bitbucketbot.repository; + +import org.sadtech.basic.context.repository.BusinessLogicRepository; +import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; +import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; +import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; + +import java.util.List; +import java.util.Set; + +public interface PullRequestsRepository extends BusinessLogicRepository { + + List findAllByReviewerAndStatuses(String login, ReviewerStatus reviewerStatus, Set statuses); + + List findAllByAuthorAndReviewerStatus(String login, ReviewerStatus status); + + Set findAllIdByStatusIn(Set statuses); + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/TaskRepository.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/TaskRepository.java new file mode 100644 index 0000000..782fb48 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/TaskRepository.java @@ -0,0 +1,18 @@ +package org.sadtech.bot.bitbucketbot.repository; + +import lombok.NonNull; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; + +import java.util.Optional; + +public interface TaskRepository { + + Task save(@NonNull Task task); + + void deleteById(@NonNull Long id); + + Optional findById(@NonNull Long id); + + Optional findFirstByOrderByIdDesc(); + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/impl/PullRequestsRepositoryImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/impl/PullRequestsRepositoryImpl.java new file mode 100644 index 0000000..50ac50a --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/impl/PullRequestsRepositoryImpl.java @@ -0,0 +1,40 @@ +package org.sadtech.bot.bitbucketbot.repository.impl; + +import org.sadtech.basic.database.repository.AbstractBusinessLogicJpaRepository; +import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; +import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; +import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; +import org.sadtech.bot.bitbucketbot.repository.PullRequestsRepository; +import org.sadtech.bot.bitbucketbot.repository.jpa.PullRequestsRepositoryJpa; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Set; + +@Repository +public class PullRequestsRepositoryImpl extends AbstractBusinessLogicJpaRepository implements PullRequestsRepository { + + private final PullRequestsRepositoryJpa pullRequestsRepositoryJpa; + + protected PullRequestsRepositoryImpl(PullRequestsRepositoryJpa pullRequestsRepositoryJpa) { + super(pullRequestsRepositoryJpa); + this.pullRequestsRepositoryJpa = pullRequestsRepositoryJpa; + } + + @Override + public List findAllByReviewerAndStatuses(String login, ReviewerStatus reviewerStatus, Set statuses) { + return pullRequestsRepositoryJpa.findAllByReviewerAndStatuses(login, reviewerStatus, statuses); + } + + @Override + public List findAllByAuthorAndReviewerStatus(String login, ReviewerStatus status) { + return pullRequestsRepositoryJpa.findAllByAuthorAndReviewerStatus(login, status); + } + + @Override + public Set findAllIdByStatusIn(Set statuses) { + return pullRequestsRepositoryJpa.findAllIdByStatusIn(statuses); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/impl/TaskRepositoryImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/impl/TaskRepositoryImpl.java new file mode 100644 index 0000000..9bf5cb7 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/impl/TaskRepositoryImpl.java @@ -0,0 +1,33 @@ +package org.sadtech.bot.bitbucketbot.repository.impl; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; +import org.sadtech.bot.bitbucketbot.repository.TaskRepository; +import org.sadtech.bot.bitbucketbot.repository.jpa.TaskRepositoryJpa; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + +@Repository +@RequiredArgsConstructor +public class TaskRepositoryImpl implements TaskRepository { + + private final TaskRepositoryJpa taskRepositoryJpa; + + @Override + public Task save(@NonNull Task task) { + return taskRepositoryJpa.save(task); + } + + @Override + public void deleteById(@NonNull Long id) { + taskRepositoryJpa.deleteById(id); + } + + @Override + public Optional findById(@NonNull Long id) { + return taskRepositoryJpa.findById(id); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/UserRepository.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PersonRepository.java similarity index 57% rename from src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/UserRepository.java rename to src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PersonRepository.java index 9848d97..608b4ba 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/UserRepository.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PersonRepository.java @@ -1,6 +1,6 @@ package org.sadtech.bot.bitbucketbot.repository.jpa; -import org.sadtech.bot.bitbucketbot.domain.entity.User; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.stereotype.Repository; @@ -15,20 +15,22 @@ import java.util.Set; * @author upagge [30.01.2020] */ @Repository -public interface UserRepository extends JpaRepository { +public interface PersonRepository extends JpaRepository { boolean existsByTelegramId(Long chatId); boolean existsByLogin(String login); - List findAllByTelegramIdNotNullAndTokenNotNull(); + List findAllByTelegramIdNotNullAndTokenNotNull(); - @Query("SELECT u.telegramId FROM User u WHERE u.login=:login") + @Query("SELECT u.telegramId FROM Person u WHERE u.login=:login") Long findTelegramIdByLogin(String login); - @Query("SELECT u.telegramId FROM User u WHERE u.login IN :logins AND u.telegramId IS NOT NULL") + @Query("SELECT u.telegramId FROM Person u WHERE u.login IN :logins AND u.telegramId IS NOT NULL") Set findAllTelegramIdByLogin(Set logins); - Optional findByLogin(String login); + Optional findByLogin(String login); + + Person getByLogin(String login); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PullRequestsRepository.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PullRequestsRepositoryJpa.java similarity index 86% rename from src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PullRequestsRepository.java rename to src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PullRequestsRepositoryJpa.java index 8ceb7e5..6cd08cb 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PullRequestsRepository.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/PullRequestsRepositoryJpa.java @@ -4,8 +4,8 @@ import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; -import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; +import org.springframework.data.jpa.repository.support.JpaRepositoryImplementation; import org.springframework.data.repository.query.Param; import java.time.LocalDateTime; @@ -17,7 +17,7 @@ import java.util.Set; /** * @author upagge [31.01.2020] */ -public interface PullRequestsRepository extends JpaRepository { +public interface PullRequestsRepositoryJpa extends JpaRepositoryImplementation { Set findAllByIdIn(Set ids); @@ -34,7 +34,7 @@ public interface PullRequestsRepository extends JpaRepository @Query("SELECT p FROM PullRequest p LEFT JOIN p.reviewers r WHERE p.author.login=:author AND r.status=:reviewerStatus") List findAllByAuthorAndReviewerStatus(@Param("author") String author, @Param("reviewerStatus") ReviewerStatus reviewerStatus); - @Query("SELECT new org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr(p.id, p.status) FROM PullRequest p WHERE p.status IN :statuses") + // @Query("SELECT new org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr(p.id, p.status) FROM PullRequest p WHERE p.status IN :statuses") Set findAllIdByStatusIn(@Param("statuses") Set statuses); @Query("SELECT p.id from PullRequest p") diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/TaskRepositoryJpa.java b/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/TaskRepositoryJpa.java new file mode 100644 index 0000000..5c1a76e --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/repository/jpa/TaskRepositoryJpa.java @@ -0,0 +1,8 @@ +package org.sadtech.bot.bitbucketbot.repository.jpa; + +import org.sadtech.bot.bitbucketbot.domain.entity.Task; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface TaskRepositoryJpa extends JpaRepository { + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerChangeParsing.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerChangeParsing.java index f1d12f5..08f46df 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerChangeParsing.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerChangeParsing.java @@ -3,14 +3,15 @@ package org.sadtech.bot.bitbucketbot.scheduler; import lombok.NonNull; import lombok.RequiredArgsConstructor; import org.sadtech.bot.bitbucketbot.domain.MessageSend; -import org.sadtech.bot.bitbucketbot.domain.change.AnswerCommentChange; import org.sadtech.bot.bitbucketbot.domain.change.Change; -import org.sadtech.bot.bitbucketbot.domain.change.CommentChange; -import org.sadtech.bot.bitbucketbot.domain.change.ConflictPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.NewPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.ReviewersPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.StatusPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.UpdatePrChange; +import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ConflictPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.StatusPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange; +import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange; import org.sadtech.bot.bitbucketbot.exception.NotFoundException; import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.MessageSendService; @@ -21,6 +22,12 @@ import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; +/** + * Парсер изменений. Отслеживает изменения, которые были добавлены и добавляет событие на отправку уведомления + * пользователю. + * + * @author upagge + */ @Service @RequiredArgsConstructor public class SchedulerChangeParsing { @@ -28,6 +35,10 @@ public class SchedulerChangeParsing { private final MessageSendService messageSendService; private final ChangeService changeService; + /** + * Проверяет наличие новых изменений. Если изменения найдены, то создает новое сообщение и отправляет + * его в сервис отправки сообщений {@link MessageSendService} + */ @Scheduled(cron = "*/15 * * * * *") public void parsing() { final List newChange = changeService.getNew().stream() @@ -46,6 +57,12 @@ public class SchedulerChangeParsing { } } + /** + * Создает сообщение, которое необходимо отправить в зависимости от типа изменения. + * + * @param change Объект изменения + * @return Текстовое сообщение + */ private String generateMessage(@NonNull Change change) { String message; switch (change.getType()) { @@ -70,6 +87,16 @@ public class SchedulerChangeParsing { case NEW_ANSWERS_COMMENT: message = Message.generate(((AnswerCommentChange) change)); break; + case NEW_TASK: + case OPEN_TASK: + message = Message.generateNewTask(((TaskChange) change)); + break; + case DELETED_TASK: + message = Message.generateDeleteTask(((TaskChange) change)); + break; + case RESOLVED_TASK: + message = Message.generateResolveTask(((TaskChange) change)); + break; default: throw new NotFoundException("Нет обработчика для типа " + change.getType().name()); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerComments.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerComments.java index e609239..807d39b 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerComments.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerComments.java @@ -3,22 +3,32 @@ package org.sadtech.bot.bitbucketbot.scheduler; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.sadtech.bot.bitbucketbot.config.BitbucketConfig; +import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; +import org.sadtech.bot.bitbucketbot.config.properties.CommentSchedulerProperty; import org.sadtech.bot.bitbucketbot.domain.Answer; import org.sadtech.bot.bitbucketbot.domain.Pagination; -import org.sadtech.bot.bitbucketbot.domain.change.AnswerCommentChange; -import org.sadtech.bot.bitbucketbot.domain.change.CommentChange; +import org.sadtech.bot.bitbucketbot.domain.TaskStatus; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; +import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange; import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity; +import org.sadtech.bot.bitbucketbot.exception.NotFoundException; import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.CommentService; +import org.sadtech.bot.bitbucketbot.service.PersonService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService; -import org.sadtech.bot.bitbucketbot.service.UserService; +import org.sadtech.bot.bitbucketbot.service.TaskService; import org.sadtech.bot.bitbucketbot.service.Utils; import org.sadtech.bot.bitbucketbot.service.executor.DataScan; import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; import org.sadtech.bot.bitbucketbot.service.impl.ExecutorScanner; +import org.sadtech.bot.bitbucketbot.utils.Converter; +import org.springframework.core.convert.ConversionService; import org.springframework.data.domain.Page; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -34,125 +44,219 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +/** + * Шедулер отвечает за работу с комментариями. Поиск новых комментариев, проверка старых. Так как таски в + * битбакете реализуются через комментарии, то этот шедулер так же работает с тасками. + * + * @author upagge + */ @Slf4j @Service @RequiredArgsConstructor public class SchedulerComments { - private static final Integer COUNT = 100; - private static final Integer NO_COMMENT = 20; private static final Pattern PATTERN = Pattern.compile("@[\\w]+"); private final CommentService commentService; private final PullRequestsService pullRequestsService; - private final UserService userService; + private final PersonService personService; private final ChangeService changeService; private final ExecutorScanner executorScanner; + private final TaskService taskService; + private final ConversionService conversionService; - private final BitbucketConfig bitbucketConfig; + private final BitbucketProperty bitbucketProperty; + private final CommentSchedulerProperty commentSchedulerProperty; - @Scheduled(cron = "0 */3 * * * MON-FRI") + /** + * Сканирует появление новых комментариев + */ + @Scheduled(cron = "0 */3 * * * *") public void newComments() { long commentId = commentService.getLastCommentId() + 1; int count = 0; do { - List commentUrls = new ArrayList<>(); - for (int i = 0; i < 5; i++) { - int page = 0; - Page pullRequestPage = pullRequestsService.getAll(Pagination.of(page, COUNT)); - while (pullRequestPage.hasContent()) { - long finalCommentId = commentId; - commentUrls.addAll(pullRequestPage.getContent().stream() - .map(pullRequest -> new DataScan(getCommentUrl(finalCommentId, pullRequest), pullRequest.getUrl())) - .collect(Collectors.toList())); - pullRequestPage = pullRequestsService.getAll(Pagination.of(++page, COUNT)); - } - commentId++; - } - executorScanner.registration(commentUrls); - final List result = executorScanner.getResult(); - if (!result.isEmpty()) { - result.forEach(resultScan -> { - notificationPersonal(resultScan.getCommentJson(), resultScan.getUrlPr()); - saveComments(resultScan.getCommentJson(), resultScan.getUrlComment(), resultScan.getUrlPr()); - }); + final List dataScans = generatingLinksToPossibleComments(commentId); + executorScanner.registration(dataScans); + final List resultScans = executorScanner.getResult(); + if (!resultScans.isEmpty()) { + final List comments = getCommentsByResultScan(resultScans); + final List newComments = commentService.createAll(comments); + checkNewTask(newComments); + notificationPersonal(newComments); count = 0; } - } while (count++ < NO_COMMENT); + } while (count++ < commentSchedulerProperty.getNoCommentCount()); } - @Scheduled(cron = "0 */1 * * * MON-FRI") + private List getCommentsByResultScan(List resultScans) { + return resultScans.stream() + .map(result -> conversionService.convert(result, Comment.class)) + .collect(Collectors.toList()); + } + + private List generatingLinksToPossibleComments(@NonNull Long commentId) { + List commentUrls = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + int page = 0; + Page pullRequestPage = pullRequestsService.getAll( + Pagination.of(page, commentSchedulerProperty.getCommentCount()) + ); + while (pullRequestPage.hasContent()) { + long finalCommentId = commentId; + commentUrls.addAll(pullRequestPage.getContent().stream() + .map( + pullRequest -> new DataScan( + getCommentUrl(finalCommentId, pullRequest), + pullRequest.getId() + ) + ) + .collect(Collectors.toList())); + pullRequestPage = pullRequestsService.getAll( + Pagination.of(++page, commentSchedulerProperty.getCommentCount()) + ); + } + commentId++; + } + return commentUrls; + } + + + private void checkNewTask(CommentJson commentJson, String urlPr, String authorLoginPr) { + if (Severity.BLOCKER.equals(commentJson.getSeverity())) { + final Task task = new Task(); + task.setStatus(Converter.taskStatus(commentJson.getState())); + task.setComment(commentService.getProxyById(commentJson.getId()).orElseThrow(() -> new NotFoundException("Неожиданная ошибка"))); + + taskService.create(task); + + if (TaskStatus.OPEN.equals(task.getStatus())) { + changeService.add( + TaskChange.builder() + .type(ChangeType.NEW_TASK) + .authorName(commentJson.getAuthor().getDisplayName()) + .messageTask(commentJson.getText()) + .telegramIds(personService.getAllTelegramIdByLogin(Collections.singleton(authorLoginPr))) + .url(urlPr) + .build() + ); + } + } + } + + + /** + * Проверяет состояние старых комментариев + */ + @Scheduled(cron = "0 */1 * * * *") public void oldComments() { - @NonNull final List comments = commentService.getAllBetweenDate(LocalDateTime.now().minusDays(10), LocalDateTime.now()); + @NonNull final List comments = commentService.getAllBetweenDate( + LocalDateTime.now().minusDays(10), LocalDateTime.now() + ); for (Comment comment : comments) { final Optional optCommentJson = Utils.urlToJson( comment.getUrl(), - bitbucketConfig.getToken(), + bitbucketProperty.getToken(), CommentJson.class ); if (optCommentJson.isPresent()) { final CommentJson commentJson = optCommentJson.get(); - final Set oldAnswerIds = comment.getAnswers(); - final List newAnswers = commentJson.getComments().stream() - .filter(answerJson -> !oldAnswerIds.contains(answerJson.getId())) - .collect(Collectors.toList()); - if (!newAnswers.isEmpty()) { + checkNewAnswers(comment, commentJson); + checkOldTask(comment, commentJson); + } + } + } + + private void checkOldTask(Comment comment, CommentJson commentJson) { + final Task task = comment.getTask(); + if (task == null) { + checkNewTask(commentJson, comment.getPrUrl(), commentJson.getAuthor().getName()); + } else { + if (Severity.NORMAL.equals(commentJson.getSeverity())) { + taskService.deleteById(comment.getId()); + + changeService.add( + TaskChange.builder() + .type(ChangeType.DELETED_TASK) + .telegramIds(personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName()))) + .authorName(commentJson.getAuthor().getDisplayName()) + .url(comment.getPrUrl()) + .messageTask(commentJson.getText()) + .build() + ); + } else { + final TaskStatus taskStatus = task.getStatus(); + final TaskStatus newTaskStatus = Converter.taskStatus(commentJson.getState()); + task.setStatus(newTaskStatus); + taskService.update(task); + if (!taskStatus.equals(newTaskStatus)) { changeService.add( - AnswerCommentChange.builder() - .telegramIds( - userService.getTelegramIdByLogin(commentJson.getAuthor().getName()) - .map(Collections::singleton) - .orElse(Collections.emptySet()) - ) + TaskChange.builder() + .type(TaskStatus.RESOLVED.equals(newTaskStatus) ? ChangeType.RESOLVED_TASK : ChangeType.OPEN_TASK) + .authorName(commentJson.getAuthor().getDisplayName()) .url(comment.getPrUrl()) - .youMessage(commentJson.getText()) - .answers( - newAnswers.stream() - .map(json -> Answer.of(json.getAuthor().getName(), json.getText())) - .collect(Collectors.toList()) + .messageTask(commentJson.getText()) + .telegramIds( + TaskStatus.RESOLVED.equals(newTaskStatus) + ? personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName())) + : personService.getAllTelegramIdByLogin(Collections.singleton(commentJson.getAuthor().getName())) ) .build() ); - comment.getAnswers().addAll(newAnswers.stream().map(CommentJson::getId).collect(Collectors.toList())); - commentService.save(comment); } } } } - @NonNull - private void saveComments(CommentJson comment, String commentUrl, String prUrl) { - final Comment newComment = new Comment(); - newComment.setId(comment.getId()); - newComment.setDate(LocalDateTime.now()); - newComment.setUrl(commentUrl); - newComment.setPrUrl(prUrl); - userService.getTelegramIdByLogin(comment.getAuthor().getName()).ifPresent(newComment::setTelegram); - commentService.save(newComment); + private void checkNewAnswers(Comment comment, CommentJson commentJson) { + final Set oldAnswerIds = comment.getAnswers(); + final List newAnswers = commentJson.getComments().stream() + .filter(answerJson -> !oldAnswerIds.contains(answerJson.getId())) + .collect(Collectors.toList()); + if (!newAnswers.isEmpty()) { + changeService.add( + AnswerCommentChange.builder() + .telegramIds( + personService.getTelegramIdByLogin(commentJson.getAuthor().getName()) + .map(Collections::singleton) + .orElse(Collections.emptySet()) + ) + .url(comment.getPrUrl()) + .youMessage(commentJson.getText()) + .answers( + newAnswers.stream() + .map(json -> Answer.of(json.getAuthor().getName(), json.getText())) + .collect(Collectors.toList()) + ) + .build() + ); + comment.getAnswers().addAll(newAnswers.stream().map(CommentJson::getId).collect(Collectors.toList())); + commentService.save(comment); + } } private String getCommentUrl(long commentId, PullRequest pullRequest) { - return bitbucketConfig.getUrlPullRequestComment() + return bitbucketProperty.getUrlPullRequestComment() .replace("{projectKey}", pullRequest.getProjectKey()) .replace("{repositorySlug}", pullRequest.getRepositorySlug()) .replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) .replace("{commentId}", String.valueOf(commentId)); } - private void notificationPersonal(@NonNull CommentJson comment, @NonNull String urlPr) { - Matcher matcher = PATTERN.matcher(comment.getText()); + private void notificationPersonal(@NonNull Comment comment) { + Matcher matcher = PATTERN.matcher(comment.getMessage()); Set recipientsLogins = new HashSet<>(); while (matcher.find()) { final String login = matcher.group(0).replace("@", ""); recipientsLogins.add(login); } - final Set recipientsIds = userService.getAllTelegramIdByLogin(recipientsLogins); + final Set recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins); changeService.add( CommentChange.builder() - .authorName(comment.getAuthor().getName()) - .url(urlPr) + .authorName(comment.getAuthor().getLogin()) + .url(comment.getPullRequest()) .telegramIds(recipientsIds) - .message(comment.getText()) + .message(comment.getMessage()) .build() ); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNewUser.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNewUser.java deleted file mode 100644 index fa19566..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNewUser.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.sadtech.bot.bitbucketbot.scheduler; - -import lombok.RequiredArgsConstructor; -import org.sadtech.bot.bitbucketbot.config.BitbucketConfig; -import org.sadtech.bot.bitbucketbot.domain.entity.User; -import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson; -import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.UserSheetJson; -import org.sadtech.bot.bitbucketbot.service.UserService; -import org.sadtech.bot.bitbucketbot.service.Utils; -import org.springframework.core.convert.ConversionService; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -/** - * TODO: Добавить описание класса. - * - * @author upagge [02.02.2020] - */ -@Service -@RequiredArgsConstructor -public class SchedulerNewUser { - - private static final String URL = "http://192.168.236.164:7990/rest/api/1.0/admin/users"; - private final UserService userService; - private final ConversionService conversionService; - private final BitbucketConfig bitbucketConfig; - - @Scheduled(fixedRate = 86400000) - private void scan() { - Optional sheetJson = Utils.urlToJson(URL, bitbucketConfig.getToken(), UserSheetJson.class); - while (sheetJson.isPresent() && sheetJson.get().getValues()!=null && !sheetJson.get().getValues().isEmpty()) { - final UserSheetJson sheetUsers = sheetJson.get(); - final List users = sheetUsers.getValues(); - final Set logins = users.stream().map(UserJson::getName).collect(Collectors.toSet()); - final Set existsLogins = userService.existsByLogin(logins); - final Set newUsers = users.stream() - .filter(userJson -> !existsLogins.contains(userJson.getName())) - .map(userJson -> conversionService.convert(userJson, User.class)) - .collect(Collectors.toSet()); - if (!newUsers.isEmpty()) { - userService.addAll(newUsers); - } - if (sheetUsers.getNextPageStart() != null) { - sheetJson = Utils.urlToJson(URL + sheetUsers.getNextPageStart(), bitbucketConfig.getToken(), UserSheetJson.class); - } else { - break; - } - } - } - -} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNotification.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNotification.java index 9f5d12a..fd1be02 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNotification.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerNotification.java @@ -4,12 +4,12 @@ import lombok.RequiredArgsConstructor; import org.sadtech.bot.bitbucketbot.domain.MessageSend; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; -import org.sadtech.bot.bitbucketbot.domain.entity.User; import org.sadtech.bot.bitbucketbot.service.MessageSendService; +import org.sadtech.bot.bitbucketbot.service.PersonService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService; import org.sadtech.bot.bitbucketbot.service.ReportService; -import org.sadtech.bot.bitbucketbot.service.UserService; import org.sadtech.bot.bitbucketbot.utils.Message; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @@ -24,7 +24,7 @@ public class SchedulerNotification { private static final Set statuses = Collections.singleton(PullRequestStatus.OPEN); - private final UserService userService; + private final PersonService personService; private final PullRequestsService pullRequestsService; private final MessageSendService messageSendService; private final ReportService reportService; @@ -32,8 +32,8 @@ public class SchedulerNotification { // Утреннее сообщение @Scheduled(cron = "0 15 8 * * MON-FRI") public void goodMorning() { - List allRegister = userService.getAllRegister(); - for (User user : allRegister) { + List allRegister = personService.getAllRegister(); + for (Person user : allRegister) { List pullRequestsReviews = pullRequestsService.getAllByReviewerAndStatuses( user.getLogin(), ReviewerStatus.NEEDS_WORK, @@ -51,8 +51,8 @@ public class SchedulerNotification { @Scheduled(cron = "0 0 18 * * FRI") public void goodWeekEnd() { - List allRegister = userService.getAllRegister(); - for (User user : allRegister) { + List allRegister = personService.getAllRegister(); + for (Person user : allRegister) { messageSendService.add( MessageSend.builder() .telegramId(user.getTelegramId()) diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPullRequest.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPullRequest.java deleted file mode 100644 index bad3021..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPullRequest.java +++ /dev/null @@ -1,320 +0,0 @@ -package org.sadtech.bot.bitbucketbot.scheduler; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.sadtech.bot.bitbucketbot.config.BitbucketConfig; -import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; -import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; -import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; -import org.sadtech.bot.bitbucketbot.domain.change.ConflictPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.NewPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.ReviewersPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.StatusPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.UpdatePrChange; -import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; -import org.sadtech.bot.bitbucketbot.domain.entity.Reviewer; -import org.sadtech.bot.bitbucketbot.domain.entity.User; -import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange; -import org.sadtech.bot.bitbucketbot.dto.bitbucket.PullRequestJson; -import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson; -import org.sadtech.bot.bitbucketbot.service.ChangeService; -import org.sadtech.bot.bitbucketbot.service.PullRequestsService; -import org.sadtech.bot.bitbucketbot.service.UserService; -import org.sadtech.bot.bitbucketbot.service.Utils; -import org.sadtech.bot.bitbucketbot.utils.NonNullUtils; -import org.sadtech.bot.bitbucketbot.utils.Pair; -import org.springframework.core.convert.ConversionService; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.DECLINED; -import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.DELETE; -import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.MERGED; -import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.OPEN; - -/** - * @author upagge [30.01.2020] - */ -@Slf4j -@Service -@RequiredArgsConstructor -public class SchedulerPullRequest { - - private static final Set STATUSES = Stream.of(MERGED, OPEN, DECLINED).collect(Collectors.toSet()); - - private final PullRequestsService pullRequestsService; - private final UserService userService; - private final ChangeService changeService; - private final ConversionService conversionService; - private final BitbucketConfig bitbucketConfig; - - @Scheduled(fixedRate = 30000) - public void checkPullRequest() { - final Set existsId = pullRequestsService.getAllId(STATUSES).stream() - .map(IdAndStatusPr::getId) - .collect(Collectors.toSet()); - final Set openId = checkOpenPullRequest(); - log.info("Открыты: " + Arrays.toString(openId.toArray())); - final Set closeId = checkClosePullRequest(); - log.info("Закрыты: " + Arrays.toString(closeId.toArray())); - final Set newNotExistsId = existsId.stream() - .filter(id -> !openId.contains(id) && !closeId.contains(id)) - .collect(Collectors.toSet()); - log.info("Не найдены: " + Arrays.toString(newNotExistsId.toArray())); - if (!newNotExistsId.isEmpty()) { - updateDeletePr(newNotExistsId); - } - } - - private void updateDeletePr(@NonNull Set ids) { - final Set deletePr = pullRequestsService.getAllById(ids); - deletePr.stream() - .filter(pullRequest -> pullRequest.getAuthor().getTelegramId() != null) - .forEach(pullRequest -> changeService.add( - StatusPrChange.builder() - .name(pullRequest.getName()) - .url(pullRequest.getUrl()) - .oldStatus(pullRequest.getStatus()) - .newStatus(DELETE) - .telegramIds(Collections.singleton(pullRequest.getAuthor().getTelegramId())) - .build() - )); - pullRequestsService.updateAll( - deletePr.stream() - .peek(pullRequest -> pullRequest.setStatus(PullRequestStatus.DELETE)) - .collect(Collectors.toList()) - ); - } - - private Set checkClosePullRequest() { - final List users = userService.getAllRegister(); - final Set ids = new HashSet<>(); - for (User user : users) { - Optional sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class); - while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { - final PullRequestSheetJson bitbucketSheet = sheetJson.get(); - final Map existsPr = getExistsPr(bitbucketSheet.getValues()); - final Set pullRequests = pullRequestsService.getAllById(existsPr.keySet()); - if (!existsPr.isEmpty() && !pullRequests.isEmpty()) { - processingUpdateClosePr(existsPr, pullRequests); - ids.addAll( - pullRequestsService.updateAll(existsPr.values()).stream() - .map(PullRequest::getId) - .collect(Collectors.toSet()) - ); - } - - if (bitbucketSheet.getNextPageStart() != null) { - sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose() + bitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); - } else { - break; - } - } - } - return ids; - } - - private Set checkOpenPullRequest() { - final List users = userService.getAllRegister(); - final Set ids = new HashSet<>(); - for (User user : users) { - Optional sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class); - while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { - final PullRequestSheetJson jsonSheet = sheetJson.get(); - final Map existsPr = getExistsPr(jsonSheet.getValues()); - final Set pullRequests = pullRequestsService.getAllById(existsPr.keySet()); - if (!existsPr.isEmpty() && !pullRequests.isEmpty()) { - processingUpdateOpenPr(existsPr, pullRequests); - ids.addAll( - pullRequestsService.updateAll(existsPr.values()).stream() - .map(PullRequest::getId) - .collect(Collectors.toSet()) - ); - } - - if (jsonSheet.getNextPageStart() != null) { - sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen() + jsonSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); - } else { - break; - } - } - } - return ids; - } - - private Map getExistsPr(List pullRequestJsons) { - return pullRequestJsons.stream() - .filter(Objects::nonNull) - .map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class)) - .peek(pullRequest -> pullRequestsService.getIdByBitbucketIdAndReposId(pullRequest.getBitbucketId(), pullRequest.getRepositoryId()).ifPresent(pullRequest::setId)) - .filter(pullRequest -> pullRequest.getId() != null) - .collect(Collectors.toMap(PullRequest::getId, pullRequest -> pullRequest)); - } - - @NonNull - private void processingUpdateOpenPr(Map newPullRequests, Set pullRequests) { - for (PullRequest pullRequest : pullRequests) { - PullRequest newPullRequest = newPullRequests.get(pullRequest.getId()); - changeStatusPR(pullRequest, newPullRequest); - changeReviewersPR(pullRequest, newPullRequest); - processingReviewer(pullRequest, newPullRequest); - conflictPr(pullRequest, newPullRequest); - } - } - - @NonNull - private void processingUpdateClosePr(Map newPullRequests, Set pullRequests) { - for (PullRequest pullRequest : pullRequests) { - PullRequest newPullRequest = newPullRequests.get(pullRequest.getId()); - changeStatusPR(pullRequest, newPullRequest); - } - } - - @NonNull - private void conflictPr(PullRequest pullRequest, PullRequest newPullRequest) { - if (newPullRequest.isConflict() && !pullRequest.isConflict()) { - changeService.add( - ConflictPrChange.builder() - .name(pullRequest.getName()) - .url(pullRequest.getUrl()) - .telegramIds(NonNullUtils.telegramIdByUser(pullRequest.getAuthor())) - .build() - ); - } - } - - private void processingReviewer(PullRequest pullRequest, PullRequest newPullRequest) { - if (isUpdatePr(pullRequest, newPullRequest)) { - final Set logins = newPullRequest.getReviewers().stream() - .map(Reviewer::getUser) - .collect(Collectors.toSet()); - final Set telegramIds = userService.getAllTelegramIdByLogin(logins); - changeService.add( - UpdatePrChange.builder() - .name(newPullRequest.getName()) - .url(newPullRequest.getUrl()) - .author(newPullRequest.getAuthor().getLogin()) - .telegramIds(telegramIds) - .build() - ); - } - } - - @NonNull - private boolean isUpdatePr(PullRequest pullRequest, PullRequest newPullRequest) { - LocalDateTime oldDate = pullRequest.getUpdateDate(); - LocalDateTime newDate = newPullRequest.getUpdateDate(); - return !oldDate.isEqual(newDate); - } - - @NonNull - private void changeReviewersPR(PullRequest pullRequest, PullRequest newPullRequest) { - final Map oldReviewers = pullRequest.getReviewers().stream() - .collect(Collectors.toMap(Reviewer::getUser, reviewer -> reviewer)); - final Map newReviewers = newPullRequest.getReviewers().stream() - .collect(Collectors.toMap(Reviewer::getUser, reviewer -> reviewer)); - List reviewerChanges = new ArrayList<>(); - for (Reviewer newReviewer : newReviewers.values()) { - if (oldReviewers.containsKey(newReviewer.getUser())) { - final Reviewer oldReviewer = oldReviewers.get(newReviewer.getUser()); - final ReviewerStatus oldStatus = oldReviewer.getStatus(); - final ReviewerStatus newStatus = newReviewer.getStatus(); - if (!oldStatus.equals(newStatus)) { - reviewerChanges.add(ReviewerChange.ofOld(oldReviewer.getUser(), oldStatus, newStatus)); - } - } else { - reviewerChanges.add(ReviewerChange.ofNew(newReviewer.getUser(), newReviewer.getStatus())); - } - } - final Set oldLogins = oldReviewers.keySet(); - oldLogins.removeAll(newReviewers.keySet()); - oldLogins.forEach(login -> reviewerChanges.add(ReviewerChange.ofDeleted(login))); - if (!reviewerChanges.isEmpty()) { - changeService.add( - ReviewersPrChange.builder() - .name(pullRequest.getName()) - .url(pullRequest.getUrl()) - .reviewerChanges(reviewerChanges) - .telegramIds(NonNullUtils.telegramIdByUser(pullRequest.getAuthor())) - .build() - ); - } - } - - - @NonNull - private void changeStatusPR(PullRequest pullRequest, PullRequest newPullRequest) { - final PullRequestStatus oldStatus = pullRequest.getStatus(); - final PullRequestStatus newStatus = newPullRequest.getStatus(); - if (!oldStatus.equals(newStatus)) { - changeService.add( - StatusPrChange.builder() - .name(newPullRequest.getName()) - .url(newPullRequest.getUrl()) - .oldStatus(oldStatus) - .newStatus(newStatus) - .telegramIds(NonNullUtils.telegramIdByUser(newPullRequest.getAuthor())) - .build() - ); - } - } - - @Scheduled(fixedRate = 30000) - public void checkNewPullRequest() { - final List users = userService.getAllRegister(); - for (User user : users) { - Optional sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class); - while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { - final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get(); - final List newPullRequest = pullRequestBitbucketSheet.getValues().stream() - .collect(Collectors.toMap(pullRequestJson -> new Pair<>(pullRequestJson.getId(), pullRequestJson.getFromRef().getRepository().getId()), pullRequestJson -> pullRequestJson)) - .entrySet() - .stream() - .filter(test -> !pullRequestsService.existsByBitbucketIdAndReposId(test.getKey().getKey(), test.getKey().getValue())) - .map(test -> conversionService.convert(test.getValue(), PullRequest.class)) - .collect(Collectors.toList()); - final List newPullRequests = pullRequestsService.addAll(newPullRequest); - sendNotificationNewPullRequest(newPullRequests); - if (pullRequestBitbucketSheet.getNextPageStart() != null) { - sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); - } else { - break; - } - } - } - } - - private void sendNotificationNewPullRequest(@NonNull List newPullRequests) { - if (!newPullRequests.isEmpty()) { - for (PullRequest newPullRequest : newPullRequests) { - final Set reviewerTelegramIds = userService.getAllTelegramIdByLogin(newPullRequest.getReviewers().stream() - .map(Reviewer::getUser) - .collect(Collectors.toSet())); - changeService.add( - NewPrChange.builder() - .name(newPullRequest.getName()) - .url(newPullRequest.getUrl()) - .description(newPullRequest.getDescription()) - .author(newPullRequest.getAuthor().getLogin()) - .telegramIds(reviewerTelegramIds) - .build() - ); - } - } - } - -} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPushMessageSend.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPushMessageSend.java index ec9868d..080c8bb 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPushMessageSend.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/SchedulerPushMessageSend.java @@ -60,7 +60,9 @@ public class SchedulerPushMessageSend { List pushMessage = messageSendService.getPushMessage(); if (!pushMessage.isEmpty()) { try { - sendMessage(objectMapper.writeValueAsString(pushMessage)); + final String json = objectMapper.writeValueAsString(pushMessage); +// sendMessage(json); + System.out.println(json); } catch (JsonProcessingException e) { log.error(e.getMessage()); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/CommentAndTaskScheduler.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/CommentAndTaskScheduler.java new file mode 100644 index 0000000..5276950 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/CommentAndTaskScheduler.java @@ -0,0 +1,24 @@ +package org.sadtech.bot.bitbucketbot.scheduler.parser; + +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.service.parser.CommentAndTaskParser; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CommentAndTaskScheduler { + + private final CommentAndTaskParser commentAndTaskParser; + + @Scheduled(cron = "") + public void scanNewCommentAndTask() { + commentAndTaskParser.scanNewCommentAndTask(); + } + + @Scheduled(cron = "") + public void scanOldComment() { + commentAndTaskParser.scanOldComment(); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/PersonScheduler.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/PersonScheduler.java new file mode 100644 index 0000000..07fe8a8 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/PersonScheduler.java @@ -0,0 +1,20 @@ +package org.sadtech.bot.bitbucketbot.scheduler.parser; + +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.service.parser.PersonParser; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class PersonScheduler { + + private final PersonParser personParser; + + @Scheduled(cron = "") + public void scanPersons() { + personParser.scanNewPerson(); + } + + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/PullRequestParserScheduler.java b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/PullRequestParserScheduler.java new file mode 100644 index 0000000..85dc8aa --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/scheduler/parser/PullRequestParserScheduler.java @@ -0,0 +1,26 @@ +package org.sadtech.bot.bitbucketbot.scheduler.parser; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.sadtech.bot.bitbucketbot.service.parser.PullRequestParser; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PullRequestParserScheduler { + + private final PullRequestParser pullRequestParser; + + @Scheduled(cron = "") + public void parsingOldPullRequest() { + pullRequestParser.parsingOldPullRequest(); + } + + @Scheduled(cron = "") + public void parsingNewPullRequest() { + pullRequestParser.parsingNewPullRequest(); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/ChangeService.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/ChangeService.java index 617f65a..e5389bf 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/ChangeService.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/ChangeService.java @@ -5,10 +5,24 @@ import org.sadtech.bot.bitbucketbot.domain.change.Change; import java.util.List; +/** + * Сервис по работе с изменениями в битбакете. + * + * @author upagge + * @see Change + */ public interface ChangeService { + /** + * Позволяет добавить новое изменение в хранилище + * + * @param change Объект, который содержит изменения + */ void add(@NonNull Change change); + /** + * Позволяет получить новые изменения. + */ List getNew(); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/CommentService.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/CommentService.java index a949d04..c700dd6 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/CommentService.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/CommentService.java @@ -7,6 +7,8 @@ import org.springframework.data.domain.Page; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; +import java.util.Set; public interface CommentService { @@ -17,8 +19,15 @@ public interface CommentService { @NonNull List getAllBetweenDate(LocalDateTime dateFrom, LocalDateTime dateTo); - void save(@NonNull Comment comment); + Comment create(@NonNull Comment comment); void delete(@NonNull Long id); + Optional getProxyById(@NonNull Long id); + + List createAll(List newComments); + + Comment update(Comment comment); + + List getAllById(@NonNull Set ids); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/PersonService.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/PersonService.java new file mode 100644 index 0000000..a394670 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/PersonService.java @@ -0,0 +1,33 @@ +package org.sadtech.bot.bitbucketbot.service; + +import lombok.NonNull; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +public interface PersonService { + + Optional getByLogin(String login); + + Set existsByLogin(@NonNull Set logins); + + boolean existsByLogin(@NonNull String login); + + Person reg(@NonNull Person user); + + List getAllRegister(); + + Optional getTelegramIdByLogin(@NonNull String login); + + Set getAllTelegramIdByLogin(Set logins); + + Optional getProxyByLogin(@NonNull String login); + + Person create(@NonNull Person person); + + List createAll(Collection newUsers); + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/PullRequestsService.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/PullRequestsService.java index cd74072..a7a8b4d 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/PullRequestsService.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/PullRequestsService.java @@ -1,46 +1,24 @@ package org.sadtech.bot.bitbucketbot.service; import lombok.NonNull; +import org.sadtech.basic.context.service.BusinessLogicService; +import org.sadtech.basic.context.service.simple.FilterService; import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; -import org.sadtech.bot.bitbucketbot.domain.Pagination; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; -import org.springframework.data.domain.Page; +import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter; -import java.time.LocalDateTime; -import java.util.Collection; import java.util.List; -import java.util.Optional; import java.util.Set; -public interface PullRequestsService { - - @NonNull - boolean existsByBitbucketIdAndReposId(Long bitbucketId, Long repositoryId); - - Set getAllById(@NonNull Set pullRequestJsonId); - - List addAll(@NonNull Collection pullRequests); - - List updateAll(@NonNull Collection pullRequests); - - @NonNull - Optional getIdByBitbucketIdAndReposId(Long bitbucketId, Long repositoryId); - - void deleteAll(@NonNull Set id); +public interface PullRequestsService extends BusinessLogicService, FilterService { @NonNull List getAllByReviewerAndStatuses(@NonNull String login, @NonNull ReviewerStatus reviewerStatus, @NonNull Set pullRequestStatuses); List getAllByAuthorAndReviewerStatus(@NonNull String login, @NonNull ReviewerStatus status); - Set getAllId(); - Set getAllId(Set statuses); - Page getAll(@NonNull Pagination pagination); - - List getAllByAuthor(@NonNull String login, @NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo); - } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/TaskService.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/TaskService.java new file mode 100644 index 0000000..d05efed --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/TaskService.java @@ -0,0 +1,21 @@ +package org.sadtech.bot.bitbucketbot.service; + +import lombok.NonNull; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; + +import java.util.Collection; +import java.util.List; + +public interface TaskService { + + Task create(@NonNull Task task); + + void deleteById(@NonNull Long id); + + Task update(@NonNull Task task); + + List createAll(@NonNull Collection tasks); + + Long getLastTaskId(); + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/UserService.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/UserService.java deleted file mode 100644 index 418f455..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/UserService.java +++ /dev/null @@ -1,26 +0,0 @@ -package org.sadtech.bot.bitbucketbot.service; - -import lombok.NonNull; -import org.sadtech.bot.bitbucketbot.domain.entity.User; - -import java.util.List; -import java.util.Optional; -import java.util.Set; - -public interface UserService { - - Optional getByLogin(String login); - - Set existsByLogin(@NonNull Set logins); - - User reg(@NonNull User user); - - List addAll(Set newUsers); - - List getAllRegister(); - - Optional getTelegramIdByLogin(@NonNull String login); - - Set getAllTelegramIdByLogin(Set logins); - -} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/Utils.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/Utils.java index 377b6f3..54187ac 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/Utils.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/Utils.java @@ -18,7 +18,7 @@ import java.util.concurrent.TimeUnit; @Slf4j public class Utils { - private static ObjectMapper objectMapper; + private static final ObjectMapper objectMapper; static { objectMapper = new ObjectMapper(); @@ -35,8 +35,7 @@ public class Utils { throw new IllegalStateException("Утилитарный класс"); } - @NonNull - public static Optional urlToJson(String urlValue, String token, Class classOfT) { + public static Optional urlToJson(@NonNull String urlValue, @NonNull String token, @NonNull Class classOfT) { Request request = new Request.Builder() .url(urlValue) .header("Authorization", "Bearer " + token) diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/PullRequestJsonConverter.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/PullRequestJsonConverter.java index 816c9a2..9ad6ad2 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/PullRequestJsonConverter.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/PullRequestJsonConverter.java @@ -5,15 +5,12 @@ import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; import org.sadtech.bot.bitbucketbot.domain.entity.Reviewer; -import org.sadtech.bot.bitbucketbot.domain.entity.User; import org.sadtech.bot.bitbucketbot.dto.bitbucket.Outcome; import org.sadtech.bot.bitbucketbot.dto.bitbucket.Properties; import org.sadtech.bot.bitbucketbot.dto.bitbucket.PullRequestJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.PullRequestState; import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserDecisionJson; -import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserPullRequestStatus; -import org.sadtech.bot.bitbucketbot.service.UserService; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @@ -24,27 +21,25 @@ import java.util.stream.Collectors; @RequiredArgsConstructor public class PullRequestJsonConverter implements Converter { - private final UserJsonConverter userJsonConverter; - private final UserService userService; - @Override public PullRequest convert(PullRequestJson json) { - return PullRequest.builder() - .bitbucketId(json.getId()) - .version(json.getVersion()) - .createDate(json.getCreatedDate()) - .updateDate(json.getUpdatedDate()) - .conflict(convertConflict(json.getProperties())) - .description(convertDescription(json.getDescription())) - .repositoryId(json.getFromRef().getRepository().getId()) - .author(this.convertUser(json.getAuthor().getUser())) - .name(json.getTitle()) - .url(json.getLinks().getSelf().get(0).getHref()) - .status(convertPullRequestStatus(json.getState())) - .projectKey(json.getFromRef().getRepository().getProject().getKey()) - .repositorySlug(json.getFromRef().getRepository().getSlug()) - .reviewers(convertReviewers(json.getReviewers())) - .build(); + + final PullRequest pullRequest = new PullRequest(); + pullRequest.setBitbucketId(json.getId()); + pullRequest.setCreateDate(json.getCreatedDate()); + pullRequest.setUpdateDate(json.getUpdatedDate()); + pullRequest.setConflict(convertConflict(json.getProperties())); + pullRequest.setDescription(convertDescription(json.getDescription())); + pullRequest.setAuthorLogin(json.getAuthor().getUser().getName()); + pullRequest.setTitle(json.getTitle()); + pullRequest.setUrl(json.getLinks().getSelf().get(0).getHref()); + pullRequest.setStatus(convertPullRequestStatus(json.getState())); + pullRequest.setProjectKey(json.getFromRef().getRepository().getProject().getKey()); + pullRequest.setRepositorySlug(json.getFromRef().getRepository().getSlug()); + pullRequest.setReviewers(convertReviewers(json.getReviewers())); + pullRequest.setBitbucketVersion(json.getVersion()); + + return pullRequest; } private boolean convertConflict(Properties properties) { @@ -61,10 +56,6 @@ public class PullRequestJsonConverter implements Converter { final Reviewer reviewer = new Reviewer(); - reviewer.setUser(jsonReviewer.getUser().getName()); + reviewer.setUserLogin(jsonReviewer.getUser().getName()); reviewer.setStatus(convertStatusReviewer(jsonReviewer.getStatus())); return reviewer; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/ResultScanToComment.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/ResultScanToComment.java new file mode 100644 index 0000000..d3700e9 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/ResultScanToComment.java @@ -0,0 +1,49 @@ +package org.sadtech.bot.bitbucketbot.service.converter; + +import org.sadtech.bot.bitbucketbot.domain.entity.Comment; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity; +import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +import java.util.stream.Collectors; + +@Component +public class ResultScanToComment implements Converter { + + @Override + public Comment convert(ResultScan resultScan) { + final CommentJson commentJson = resultScan.getCommentJson(); + final Comment comment = new Comment(); + comment.setCreateDate(commentJson.getCreatedDate()); + comment.setAuthor(commentJson.getAuthor().getName()); + comment.setPullRequestId(getPullRequest(resultScan.getPullRequestId())); + comment.setMessage(commentJson.getText()); + comment.setUrl(resultScan.getUrlComment()); + comment.setBitbucketVersion(commentJson.getVersion()); + comment.setAnswers( + commentJson.getComments().stream() + .filter(json -> Severity.NORMAL.equals(json.getSeverity())) + .map(CommentJson::getId) + .collect(Collectors.toSet()) + ); + return comment; + + } + + private PullRequest getPullRequest(Long pullRequestId) { + final PullRequest pullRequest = new PullRequest(); + pullRequest.setId(pullRequestId); + return pullRequest; + } + + private Person getAuthor(String name) { + final Person user = new Person(); + user.setLogin(name); + return user; + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/ResultScanToTaskConvert.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/ResultScanToTaskConvert.java new file mode 100644 index 0000000..c48975f --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/ResultScanToTaskConvert.java @@ -0,0 +1,32 @@ +package org.sadtech.bot.bitbucketbot.service.converter; + +import org.sadtech.bot.bitbucketbot.domain.entity.Person; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; +import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +@Component +public class ResultScanToTaskConvert implements Converter { + + @Override + public Task convert(ResultScan resultScan) { + final CommentJson json = resultScan.getCommentJson(); + final Task task = new Task(); + task.setId(json.getId()); + task.setAuthor(getAuthor(json)); + task.setDescription(json.getText()); + task.setCreateDate(json.getCreatedDate()); + task.setBitbucketVersion(json.getVersion()); + task.setPullRequestId(resultScan.getPullRequestId()); + return task; + } + + private Person getAuthor(CommentJson json) { + final Person person = new Person(); + person.setLogin(json.getAuthor().getName()); + return person; + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserDtoConverter.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserDtoConverter.java index 814c4bb..36fe79b 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserDtoConverter.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserDtoConverter.java @@ -1,16 +1,16 @@ package org.sadtech.bot.bitbucketbot.service.converter; -import org.sadtech.bot.bitbucketbot.domain.entity.User; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.sadtech.bot.bitbucketbot.dto.UserDto; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Component; @Component -public class UserDtoConverter implements Converter { +public class UserDtoConverter implements Converter { @Override - public User convert(UserDto source) { - return User.builder() + public Person convert(UserDto source) { + return Person.builder() .login(source.getLogin()) .token(source.getToken()) .telegramId(source.getTelegramId()) diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserJsonConverter.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserJsonConverter.java index 4c033a3..4685a39 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserJsonConverter.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/converter/UserJsonConverter.java @@ -1,19 +1,19 @@ package org.sadtech.bot.bitbucketbot.service.converter; -import org.sadtech.bot.bitbucketbot.domain.entity.User; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson; import org.springframework.core.convert.converter.Converter; import org.springframework.stereotype.Service; @Service -public class UserJsonConverter implements Converter { +public class UserJsonConverter implements Converter { @Override - public User convert(UserJson source) { - return User.builder() - .fullName(source.getDisplayName()) - .login(source.getName()) - .build(); + public Person convert(UserJson source) { + final Person person = new Person(); + person.setFullName(source.getDisplayName()); + person.setLogin(source.getName()); + return person; } } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/DataScan.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/DataScan.java index 084d693..91daf90 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/DataScan.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/DataScan.java @@ -6,6 +6,6 @@ import lombok.Data; public class DataScan { private final String urlComment; - private final String urlPr; + private final Long pullRequestId; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/ResultScan.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/ResultScan.java index f43b13d..4e1b26c 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/ResultScan.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/ResultScan.java @@ -1,13 +1,15 @@ package org.sadtech.bot.bitbucketbot.service.executor; -import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; -@Data +@Getter +@RequiredArgsConstructor public class ResultScan { private final String urlComment; - private final String urlPr; + private final Long pullRequestId; private final CommentJson commentJson; } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/Seeker.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/Seeker.java index c048902..a23be64 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/Seeker.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/executor/Seeker.java @@ -16,7 +16,12 @@ public class Seeker implements Callable> { @Override public Optional call() { return Utils.urlToJson(dataScan.getUrlComment(), token, CommentJson.class) - .map(commentJson -> new ResultScan(dataScan.getUrlComment(), dataScan.getUrlPr(), commentJson)); + .map( + commentJson -> new ResultScan( + dataScan.getUrlComment(), + dataScan.getPullRequestId(), + commentJson) + ); } } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/CommentServiceImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/CommentServiceImpl.java index 01c8e01..43104df 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/CommentServiceImpl.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/CommentServiceImpl.java @@ -5,20 +5,29 @@ import lombok.RequiredArgsConstructor; import org.sadtech.bot.bitbucketbot.config.InitConfig; import org.sadtech.bot.bitbucketbot.domain.Pagination; import org.sadtech.bot.bitbucketbot.domain.entity.Comment; +import org.sadtech.bot.bitbucketbot.exception.NotFoundException; import org.sadtech.bot.bitbucketbot.repository.jpa.CommentRepository; import org.sadtech.bot.bitbucketbot.service.CommentService; +import org.sadtech.bot.bitbucketbot.service.PersonService; +import org.sadtech.bot.bitbucketbot.service.PullRequestsService; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; +import javax.transaction.Transactional; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class CommentServiceImpl implements CommentService { + private final PersonService personService; private final CommentRepository commentRepository; + private final PullRequestsService pullRequestsService; private final InitConfig initConfig; @Override @@ -41,8 +50,14 @@ public class CommentServiceImpl implements CommentService { } @Override - public void save(@NonNull Comment comment) { - commentRepository.save(comment); + public Comment create(@NonNull Comment comment) { + comment.setAuthor(personService.getProxyByLogin( + comment.getAuthor().getLogin()).orElseThrow(() -> new NotFoundException("")) + ); + comment.setPullRequest( + pullRequestsService.getProxyById(comment.getPullRequest().getId()).orElseThrow(() -> new NotFoundException("")) + ); + return commentRepository.save(comment); } @Override @@ -50,4 +65,36 @@ public class CommentServiceImpl implements CommentService { commentRepository.deleteById(id); } + @Override + public Optional getProxyById(@NonNull Long id) { + return Optional.ofNullable(commentRepository.getOne(id)); + } + + @Override + @Transactional + public List createAll(List newComments) { + return newComments.stream() + .map(this::create) + .collect(Collectors.toList()); + } + + @Override + public Comment update(Comment comment) { + final Comment oldComment = commentRepository.findById(comment.getId()) + .orElseThrow(() -> new NotFoundException("Комментарий не найден")); + + if (oldComment.getBitbucketVersion().equals(comment.getBitbucketVersion())) { + oldComment.setBitbucketVersion(comment.getBitbucketVersion()); + oldComment.setMessage(oldComment.getMessage()); + return commentRepository.save(oldComment); + } + + return oldComment; + } + + @Override + public List getAllById(@NonNull Set ids) { + return commentRepository.findAllById(ids); + } + } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/ExecutorScanner.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/ExecutorScanner.java index bda17fc..6705f79 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/ExecutorScanner.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/ExecutorScanner.java @@ -3,7 +3,7 @@ package org.sadtech.bot.bitbucketbot.service.impl; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.sadtech.bot.bitbucketbot.config.BitbucketConfig; +import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; import org.sadtech.bot.bitbucketbot.service.executor.DataScan; import org.sadtech.bot.bitbucketbot.service.executor.Executor; import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; @@ -25,13 +25,13 @@ public class ExecutorScanner implements Executor { private final ExecutorService executorService; private List>> resultList = new ArrayList<>(); - private final BitbucketConfig bitbucketConfig; + private final BitbucketProperty bitbucketProperty; @Override public boolean registration(@NonNull List dataScans) { resultList.addAll( dataScans.stream() - .map(dataScan -> new Seeker(dataScan, bitbucketConfig.getToken())) + .map(dataScan -> new Seeker(dataScan, bitbucketProperty.getToken())) .map(executorService::submit) .collect(Collectors.toList()) ); diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PersonServiceImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PersonServiceImpl.java new file mode 100644 index 0000000..3d383c2 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PersonServiceImpl.java @@ -0,0 +1,96 @@ +package org.sadtech.bot.bitbucketbot.service.impl; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson; +import org.sadtech.bot.bitbucketbot.exception.CreateException; +import org.sadtech.bot.bitbucketbot.exception.RegException; +import org.sadtech.bot.bitbucketbot.repository.jpa.PersonRepository; +import org.sadtech.bot.bitbucketbot.service.PersonService; +import org.sadtech.bot.bitbucketbot.service.Utils; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class PersonServiceImpl implements PersonService { + + private final PersonRepository personRepository; + private final BitbucketProperty bitbucketProperty; + + @Override + public Optional getByLogin(String login) { + return personRepository.findById(login); + } + + @Override + public Set existsByLogin(@NonNull Set logins) { + return logins.stream().filter(personRepository::existsById).collect(Collectors.toSet()); + } + + @Override + public boolean existsByLogin(@NonNull String login) { + return personRepository.existsByLogin(login); + } + + @Override + public Person reg(@NonNull Person user) { + final Optional optUser = personRepository.findByLogin(user.getLogin()); + if (optUser.isPresent()) { + final Person oldUser = optUser.get(); + if (oldUser.getTelegramId() == null) { + Optional sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class); + if (sheetJson.isPresent()) { + oldUser.setTelegramId(user.getTelegramId()); + return personRepository.save(oldUser); + } else { + throw new RegException("Ваш токен не валиден"); + } + } else { + throw new RegException("Вы уже авторизованы в системе"); + } + } + throw new RegException("Пользователь не найден, подождите обновление базы пользователей!"); + } + + @Override + public List getAllRegister() { + return personRepository.findAllByTelegramIdNotNullAndTokenNotNull(); + } + + @Override + public Optional getTelegramIdByLogin(@NonNull String login) { + return Optional.ofNullable(personRepository.findTelegramIdByLogin(login)); + } + + @Override + public Set getAllTelegramIdByLogin(Set logins) { + return personRepository.findAllTelegramIdByLogin(logins); + } + + @Override + public Optional getProxyByLogin(@NonNull String login) { + return Optional.ofNullable(personRepository.getByLogin(login)); + } + + @Override + public Person create(@NonNull Person person) { + if (person.getId() == null) { + return personRepository.save(person); + } + throw new CreateException("При создании пользователя должен отсутствовать id"); + } + + @Override + public List createAll(Collection newPersons) { + return newPersons.stream().map(this::create).collect(Collectors.toList()); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PullRequestsServiceImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PullRequestsServiceImpl.java index e0abc8e..93b92c2 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PullRequestsServiceImpl.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/PullRequestsServiceImpl.java @@ -1,65 +1,78 @@ package org.sadtech.bot.bitbucketbot.service.impl; import lombok.NonNull; -import lombok.RequiredArgsConstructor; +import org.sadtech.basic.context.page.Pagination; +import org.sadtech.basic.context.page.Sheet; +import org.sadtech.basic.core.service.AbstractBusinessLogicService; +import org.sadtech.basic.filter.criteria.CriteriaQuery; import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; -import org.sadtech.bot.bitbucketbot.domain.Pagination; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; -import org.sadtech.bot.bitbucketbot.repository.jpa.PullRequestsRepository; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest_; +import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter; +import org.sadtech.bot.bitbucketbot.exception.CreateException; +import org.sadtech.bot.bitbucketbot.exception.UpdateException; +import org.sadtech.bot.bitbucketbot.repository.PullRequestsRepository; +import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; +import org.sadtech.bot.bitbucketbot.utils.ChangeGenerator; import org.springframework.stereotype.Service; -import javax.transaction.Transactional; -import java.time.LocalDateTime; -import java.util.Collection; import java.util.List; import java.util.Optional; import java.util.Set; -import java.util.stream.Collectors; @Service -@RequiredArgsConstructor -public class PullRequestsServiceImpl implements PullRequestsService { +public class PullRequestsServiceImpl extends AbstractBusinessLogicService implements PullRequestsService { + private final ChangeService changeService; private final PullRequestsRepository pullRequestsRepository; - @Override - public boolean existsByBitbucketIdAndReposId(@NonNull Long bitbucketId, @NonNull Long repositoryId) { - return pullRequestsRepository.existsByBitbucketIdAndRepositoryId(bitbucketId, repositoryId); + protected PullRequestsServiceImpl(PullRequestsRepository pullRequestsRepository, ChangeService changeService) { + super(pullRequestsRepository); + this.changeService = changeService; + this.pullRequestsRepository = pullRequestsRepository; } @Override - public Set getAllById(@NonNull Set pullRequestJsonId) { - return pullRequestsRepository.findAllByIdIn(pullRequestJsonId); + public PullRequest create(@NonNull PullRequest pullRequest) { + if (pullRequest.getId() == null) { + final PullRequest newPullRequest = pullRequestsRepository.save(pullRequest); + changeService.add(ChangeGenerator.create(newPullRequest)); + return newPullRequest; + } + throw new CreateException("При создании идентификатор должен быть пустым"); } @Override - @Transactional - public List addAll(@NonNull Collection pullRequests) { - return pullRequestsRepository.saveAll(pullRequests); + public PullRequest update(@NonNull PullRequest pullRequest) { + final PullRequest oldPullRequest = findAndFillId(pullRequest); + + if (!oldPullRequest.getBitbucketVersion().equals(pullRequest.getBitbucketVersion())) { + oldPullRequest.setBitbucketVersion(pullRequest.getVersion()); + oldPullRequest.setConflict(pullRequest.isConflict()); + oldPullRequest.setTitle(pullRequest.getTitle()); + oldPullRequest.setDescription(pullRequest.getDescription()); + oldPullRequest.setStatus(pullRequest.getStatus()); + oldPullRequest.setReviewers(pullRequest.getReviewers()); + + final PullRequest newPullRequest = pullRequestsRepository.save(oldPullRequest); + + changeService.add(ChangeGenerator.createUpdatePr(pullRequest, newPullRequest)); + changeService.add(ChangeGenerator.createReviewersPr(pullRequest, newPullRequest)); + + return newPullRequest; + } + return oldPullRequest; } - @Override - public List updateAll(@NonNull Collection pullRequests) { - final List updatePullRequests = pullRequests.stream() - .filter(pullRequest -> pullRequestsRepository.existsById(pullRequest.getId())) - .collect(Collectors.toList()); - return pullRequestsRepository.saveAll(updatePullRequests); - } - - @Override - public Optional getIdByBitbucketIdAndReposId(@NonNull Long bitbucketId, @NonNull Long repositoryId) { - return pullRequestsRepository.findIdByBitbucketIdAndRepositoryId(bitbucketId, repositoryId); - } - - @Override - @Transactional - public void deleteAll(@NonNull Set id) { - pullRequestsRepository.deleteAllByIdIn(id); + private PullRequest findAndFillId(@NonNull PullRequest pullRequest) { + return pullRequestsRepository.findByFilterQuery( + CriteriaQuery.create() + .matchPhrase(PullRequest_.BITBUCKET_ID, pullRequest.getBitbucketId()) + .matchPhrase(PullRequest_.REPOSITORY_ID, pullRequest.getRepositoryId()) + ).orElseThrow(() -> new UpdateException("ПР с таким id не существует")); } @NonNull @@ -73,25 +86,33 @@ public class PullRequestsServiceImpl implements PullRequestsService { return pullRequestsRepository.findAllByAuthorAndReviewerStatus(login, status); } - @Override - public Set getAllId() { - return pullRequestsRepository.findAllIds(); - } - @Override public Set getAllId(Set statuses) { return pullRequestsRepository.findAllIdByStatusIn(statuses); } @Override - public Page getAll(@NonNull Pagination pagination) { - return pullRequestsRepository.findAll(PageRequest.of(pagination.getPage(), pagination.getSize())); + public Sheet getAllByFilter(@NonNull PullRequestFilter filter, Pagination pagination) { + return null; } @Override - public List getAllByAuthor(@NonNull String login, @NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo) { - return pullRequestsRepository.findAllByAuthorAndDateBetween(login, dateFrom, dateTo); + public Sheet getALlByFilterQuery(@NonNull PullRequestFilter filter, Pagination pagination) { + return null; } + @Override + public Optional getByFilterQuery(@NonNull PullRequestFilter filterQuery) { + return Optional.empty(); + } + + @Override + public boolean existsByFilterQuery(@NonNull PullRequestFilter filter) { + return pullRequestsRepository.existsByFilterQuery( + CriteriaQuery.create() + .matchPhrase(PullRequest_.BITBUCKET_ID, filter.getBitbucketId()) + .matchPhrase(PullRequest_.REPOSITORY_ID, filter.getBitbucketRepositoryId()) + ); + } } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/TaskServiceImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/TaskServiceImpl.java new file mode 100644 index 0000000..a22e2a4 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/TaskServiceImpl.java @@ -0,0 +1,52 @@ +package org.sadtech.bot.bitbucketbot.service.impl; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; +import org.sadtech.bot.bitbucketbot.exception.CreateException; +import org.sadtech.bot.bitbucketbot.exception.NotFoundException; +import org.sadtech.bot.bitbucketbot.repository.TaskRepository; +import org.sadtech.bot.bitbucketbot.service.TaskService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class TaskServiceImpl implements TaskService { + + private final TaskRepository taskRepository; + + @Override + public Task create(@NonNull Task task) { + if (task.getId() == null) { + return taskRepository.save(task); + } + throw new CreateException("При создании объекта не должно быть идентификатора"); + } + + @Override + public void deleteById(@NonNull Long id) { + taskRepository.deleteById(id); + } + + @Override + public Task update(@NonNull Task task) { + final Task oldTask = taskRepository.findById(task.getId()).orElseThrow(() -> new NotFoundException("Задача не найдена")); + oldTask.setStatus(task.getStatus()); + return taskRepository.save(oldTask); + } + + @Override + public List createAll(@NonNull Collection tasks) { + return tasks.stream().map(this::create).collect(Collectors.toList()); + } + + @Override + public Long getLastTaskId() { + return taskRepository.findFirstByOrderByIdDesc().map(Task::getId).orElse(0L); + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/UserServiceImpl.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/UserServiceImpl.java deleted file mode 100644 index d5f1839..0000000 --- a/src/main/java/org/sadtech/bot/bitbucketbot/service/impl/UserServiceImpl.java +++ /dev/null @@ -1,76 +0,0 @@ -package org.sadtech.bot.bitbucketbot.service.impl; - -import lombok.NonNull; -import lombok.RequiredArgsConstructor; -import org.sadtech.bot.bitbucketbot.config.BitbucketConfig; -import org.sadtech.bot.bitbucketbot.domain.entity.User; -import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson; -import org.sadtech.bot.bitbucketbot.exception.RegException; -import org.sadtech.bot.bitbucketbot.repository.jpa.UserRepository; -import org.sadtech.bot.bitbucketbot.service.UserService; -import org.sadtech.bot.bitbucketbot.service.Utils; -import org.springframework.stereotype.Service; - -import java.util.List; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - -@Service -@RequiredArgsConstructor -public class UserServiceImpl implements UserService { - - private final UserRepository userRepository; - private final BitbucketConfig bitbucketConfig; - - @Override - public Optional getByLogin(String login) { - return userRepository.findById(login); - } - - @Override - public Set existsByLogin(@NonNull Set logins) { - return logins.stream().filter(userRepository::existsById).collect(Collectors.toSet()); - } - - @Override - public User reg(@NonNull User user) { - final Optional optUser = userRepository.findByLogin(user.getLogin()); - if (optUser.isPresent()) { - final User oldUser = optUser.get(); - if (oldUser.getTelegramId() == null) { - Optional sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class); - if (sheetJson.isPresent()) { - oldUser.setTelegramId(user.getTelegramId()); - return userRepository.save(oldUser); - } else { - throw new RegException("Ваш токен не валиден"); - } - } else { - throw new RegException("Вы уже авторизованы в системе"); - } - } - throw new RegException("Пользователь не найден, подождите обновление базы пользователей!"); - } - - @Override - public List addAll(Set newUsers) { - return userRepository.saveAll(newUsers); - } - - @Override - public List getAllRegister() { - return userRepository.findAllByTelegramIdNotNullAndTokenNotNull(); - } - - @Override - public Optional getTelegramIdByLogin(@NonNull String login) { - return Optional.ofNullable(userRepository.findTelegramIdByLogin(login)); - } - - @Override - public Set getAllTelegramIdByLogin(Set logins) { - return userRepository.findAllTelegramIdByLogin(logins); - } - -} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/CommentAndTaskParser.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/CommentAndTaskParser.java new file mode 100644 index 0000000..ba0644a --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/CommentAndTaskParser.java @@ -0,0 +1,213 @@ +package org.sadtech.bot.bitbucketbot.service.parser; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; +import org.sadtech.bot.bitbucketbot.config.properties.CommentSchedulerProperty; +import org.sadtech.bot.bitbucketbot.domain.Answer; +import org.sadtech.bot.bitbucketbot.domain.Pagination; +import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; +import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange; +import org.sadtech.bot.bitbucketbot.domain.entity.Comment; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; +import org.sadtech.bot.bitbucketbot.domain.entity.Task; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity; +import org.sadtech.bot.bitbucketbot.service.ChangeService; +import org.sadtech.bot.bitbucketbot.service.CommentService; +import org.sadtech.bot.bitbucketbot.service.PersonService; +import org.sadtech.bot.bitbucketbot.service.PullRequestsService; +import org.sadtech.bot.bitbucketbot.service.TaskService; +import org.sadtech.bot.bitbucketbot.service.Utils; +import org.sadtech.bot.bitbucketbot.service.executor.DataScan; +import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; +import org.sadtech.bot.bitbucketbot.service.impl.ExecutorScanner; +import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Page; +import org.springframework.stereotype.Component; + +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +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; + +/** + *

Поиск новых комментариев и задач.

+ *

К несчастью, у битбакета не очень удобный API, и у них таска это то же самое что и комментарий, только с флагом

+ */ +@Component +@RequiredArgsConstructor +public class CommentAndTaskParser { + + private static final Pattern PATTERN = Pattern.compile("@[\\w]+"); + + private final CommentService commentService; + private final PullRequestsService pullRequestsService; + private final PersonService personService; + private final ChangeService changeService; + private final ExecutorScanner executorScanner; + private final TaskService taskService; + private final ConversionService conversionService; + + private final BitbucketProperty bitbucketProperty; + private final CommentSchedulerProperty commentSchedulerProperty; + + public void scanNewCommentAndTask() { + long commentId = getLastIdCommentOrTask() + 1; + int count = 0; + do { + final List dataScans = generatingLinksToPossibleComments(commentId); + executorScanner.registration(dataScans); + final List resultScans = executorScanner.getResult(); + if (!resultScans.isEmpty()) { + processingComments(resultScans); + processingTasks(resultScans); + count = 0; + } + } while (count++ < commentSchedulerProperty.getNoCommentCount()); + } + + private long getLastIdCommentOrTask() { + return Long.max(commentService.getLastCommentId(), taskService.getLastTaskId()); + } + + private void processingComments(List resultScans) { + final List newComments = commentService.createAll(getCommentsByResultScan(resultScans)); + newComments.forEach(this::notificationPersonal); + } + + private void processingTasks(List resultScans) { + final List newTasks = taskService.createAll(getTaskByResultScan(resultScans)); + newTasks.forEach(this::notificationNewTask); + } + + private List generatingLinksToPossibleComments(@NonNull Long commentId) { + List commentUrls = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + int page = 0; + Page pullRequestPage = pullRequestsService.getAll( + Pagination.of(page, commentSchedulerProperty.getCommentCount()) + ); + while (pullRequestPage.hasContent()) { + long finalCommentId = commentId; + commentUrls.addAll(pullRequestPage.getContent().stream() + .map( + pullRequest -> new DataScan( + getCommentUrl(finalCommentId, pullRequest), + pullRequest.getId() + ) + ) + .collect(Collectors.toList())); + pullRequestPage = pullRequestsService.getAll( + Pagination.of(++page, commentSchedulerProperty.getCommentCount()) + ); + } + commentId++; + } + return commentUrls; + } + + private List getCommentsByResultScan(List resultScans) { + return resultScans.stream() + .filter(resultScan -> Severity.NORMAL.equals(resultScan.getCommentJson().getSeverity())) + .map(resultScan -> conversionService.convert(resultScan, Comment.class)) + .collect(Collectors.toList()); + } + + private List getTaskByResultScan(List resultScans) { + return resultScans.stream() + .filter(commentJson -> Severity.BLOCKER.equals(commentJson.getCommentJson().getSeverity())) + .map(resultScan -> conversionService.convert(resultScan, Task.class)) + .collect(Collectors.toList()); + } + + private String getCommentUrl(long commentId, PullRequest pullRequest) { + return bitbucketProperty.getUrlPullRequestComment() + .replace("{projectKey}", pullRequest.getProjectKey()) + .replace("{repositorySlug}", pullRequest.getRepositorySlug()) + .replace("{pullRequestId}", pullRequest.getBitbucketId().toString()) + .replace("{commentId}", String.valueOf(commentId)); + } + + private void notificationPersonal(@NonNull Comment comment) { + Matcher matcher = PATTERN.matcher(comment.getMessage()); + Set recipientsLogins = new HashSet<>(); + while (matcher.find()) { + final String login = matcher.group(0).replace("@", ""); + recipientsLogins.add(login); + } + final Set recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins); + changeService.add( + CommentChange.builder() + .authorName(comment.getAuthor().getLogin()) + .url(comment.getUrl()) + .telegramIds(recipientsIds) + .message(comment.getMessage()) + .build() + ); + } + + private void notificationNewTask(@NonNull Task task) { + changeService.add( + TaskChange.builder() + .authorName(task.getAuthor().getFullName()) + .messageTask(task.getDescription()) + .type(ChangeType.NEW_TASK) + .url(task.getUrl()) + .telegramIds(Collections.singleton(task.getPullRequest().getAuthor().getTelegramId())) + .build() + ); + } + + public void scanOldComment() { + @NonNull final List comments = commentService.getAllBetweenDate( + LocalDateTime.now().minusDays(10), LocalDateTime.now() + ); + for (Comment oldComment : comments) { + final Optional optCommentJson = Utils.urlToJson( + oldComment.getUrl(), + bitbucketProperty.getToken(), + CommentJson.class + ); + final Comment newComment = commentService.update(conversionService.convert(oldComment, Comment.class)); + + if (optCommentJson.isPresent()) { + final CommentJson commentJson = optCommentJson.get(); + notifyNewCommentAnswers(oldComment, newComment); + } + } + } + + private void notifyNewCommentAnswers(Comment oldComment, Comment newComment) { + final Set oldAnswerIds = oldComment.getAnswers(); + final Set newAnswerIds = newComment.getAnswers(); + if (!newAnswerIds.isEmpty()) { + final List newAnswers = commentService.getAllById(newAnswerIds).stream() + .filter(comment -> !oldAnswerIds.contains(comment.getId())) + .collect(Collectors.toList()); + changeService.add( + AnswerCommentChange.builder() + .telegramIds( + Collections.singleton(newComment.getAuthor().getTelegramId()) + ) + .url(newComment.getPullRequest().getUrl()) + .youMessage(newComment.getMessage()) + .answers( + newAnswers.stream() + .map(comment -> Answer.of(comment.getAuthor().getFullName(), comment.getMessage())) + .collect(Collectors.toList()) + ) + .build() + ); + } + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/PersonParser.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/PersonParser.java new file mode 100644 index 0000000..cfcc6ef --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/PersonParser.java @@ -0,0 +1,49 @@ +package org.sadtech.bot.bitbucketbot.service.parser; + +import lombok.RequiredArgsConstructor; +import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.UserJson; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.UserSheetJson; +import org.sadtech.bot.bitbucketbot.service.PersonService; +import org.sadtech.bot.bitbucketbot.service.Utils; +import org.springframework.core.convert.ConversionService; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@RequiredArgsConstructor +public class PersonParser { + + private final PersonService personService; + private final ConversionService conversionService; + + private final BitbucketProperty bitbucketProperty; + + public void scanNewPerson() { + Optional sheetJson = Utils.urlToJson(bitbucketProperty.getUrlUsers(), bitbucketProperty.getToken(), UserSheetJson.class); + while (sheetJson.isPresent() && sheetJson.get().hasContent()) { + final UserSheetJson sheetUsers = sheetJson.get(); + final List users = sheetUsers.getValues(); + final Set logins = users.stream().map(UserJson::getName).collect(Collectors.toSet()); + final Set existsLogins = personService.existsByLogin(logins); + final Set newUsers = users.stream() + .filter(userJson -> !existsLogins.contains(userJson.getName())) + .map(userJson -> conversionService.convert(userJson, Person.class)) + .collect(Collectors.toSet()); + if (!newUsers.isEmpty()) { + personService.createAll(newUsers); + } + if (sheetUsers.getNextPageStart() != null) { + sheetJson = Utils.urlToJson(bitbucketProperty.getUrlUsers() + sheetUsers.getNextPageStart(), bitbucketProperty.getToken(), UserSheetJson.class); + } else { + break; + } + } + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/PullRequestParser.java b/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/PullRequestParser.java new file mode 100644 index 0000000..aab7825 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/service/parser/PullRequestParser.java @@ -0,0 +1,128 @@ +package org.sadtech.bot.bitbucketbot.service.parser; + +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; +import org.sadtech.bot.bitbucketbot.domain.IdAndStatusPr; +import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; +import org.sadtech.bot.bitbucketbot.domain.filter.PullRequestFilter; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.PullRequestJson; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.sheet.PullRequestSheetJson; +import org.sadtech.bot.bitbucketbot.service.PersonService; +import org.sadtech.bot.bitbucketbot.service.PullRequestsService; +import org.sadtech.bot.bitbucketbot.service.Utils; +import org.sadtech.bot.bitbucketbot.utils.Pair; +import org.springframework.core.convert.ConversionService; +import org.springframework.stereotype.Service; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.DECLINED; +import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.MERGED; +import static org.sadtech.bot.bitbucketbot.domain.PullRequestStatus.OPEN; + +@Slf4j +@Service +@RequiredArgsConstructor +public class PullRequestParser { + + private static final Set STATUSES = Stream.of(MERGED, OPEN, DECLINED).collect(Collectors.toSet()); + + private final PullRequestsService pullRequestsService; + private final PersonService personService; + private final ConversionService conversionService; + private final BitbucketProperty bitbucketProperty; + + public void parsingOldPullRequest() { + final Set existsId = pullRequestsService.getAllId(STATUSES).stream() + .map(IdAndStatusPr::getId) + .collect(Collectors.toSet()); + final Set openId = parsingPullRequest(bitbucketProperty.getUrlPullRequestOpen()); + final Set closeId = parsingPullRequest(bitbucketProperty.getUrlPullRequestClose()); + final Set newNotExistsId = existsId.stream() + .filter(id -> !openId.contains(id) && !closeId.contains(id)) + .collect(Collectors.toSet()); + log.info("Открыты: " + Arrays.toString(openId.toArray())); + log.info("Закрыты: " + Arrays.toString(closeId.toArray())); + log.info("Не найдены: " + Arrays.toString(newNotExistsId.toArray())); + if (!newNotExistsId.isEmpty()) { + pullRequestsService.deleteAll(newNotExistsId); + } + } + + private Set parsingPullRequest(@NonNull String url) { + final List users = personService.getAllRegister(); + final Set ids = new HashSet<>(); + for (Person user : users) { + Optional sheetJson = Utils.urlToJson(url, user.getToken(), PullRequestSheetJson.class); + while (sheetJson.isPresent() && sheetJson.get().hasContent()) { + final PullRequestSheetJson jsonSheet = sheetJson.get(); + final List existsPr = getExistsPr(jsonSheet.getValues()); + + ids.addAll( + pullRequestsService.updateAll(existsPr).stream() + .map(PullRequest::getId) + .collect(Collectors.toSet()) + ); + + if (jsonSheet.getNextPageStart() != null) { + sheetJson = Utils.urlToJson(url + jsonSheet.getNextPageStart(), bitbucketProperty.getToken(), PullRequestSheetJson.class); + } else { + break; + } + } + } + return ids; + } + + private List getExistsPr(@NonNull List pullRequestJsons) { + return pullRequestJsons.stream() + .filter(json -> pullRequestsService.existsByFilterQuery(bitbucketIdAndPullRequestId(json))) + .map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class)) + .peek(pullRequest -> pullRequestsService.getIdByBitbucketIdAndReposId(pullRequest.getBitbucketId(), pullRequest.getRepositoryId()).ifPresent(pullRequest::setId)) + .collect(Collectors.toList()); + } + + private PullRequestFilter bitbucketIdAndPullRequestId(PullRequestJson json) { + return PullRequestFilter.builder() + .bitbucketId(json.getId()) + .bitbucketRepositoryId(json.getFromRef().getRepository().getId()) + .build(); + } + + + public void parsingNewPullRequest() { + final List users = personService.getAllRegister(); + for (Person user : users) { + Optional sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class); + while (sheetJson.isPresent() && sheetJson.get().hasContent()) { + final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get(); + final List newPullRequest = pullRequestBitbucketSheet.getValues().stream() + .collect(Collectors.toMap(pullRequestJson -> new Pair<>(pullRequestJson.getId(), pullRequestJson.getFromRef().getRepository().getId()), pullRequestJson -> pullRequestJson)) + .values() + .stream() + .filter(pullRequestJson -> !pullRequestsService.existsByFilterQuery(bitbucketIdAndPullRequestId(pullRequestJson))) + .map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class)) + .collect(Collectors.toList()); + + pullRequestsService.createAll(newPullRequest); + + if (pullRequestBitbucketSheet.getNextPageStart() != null) { + sheetJson = Utils.urlToJson(bitbucketProperty.getUrlPullRequestOpen() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketProperty.getToken(), PullRequestSheetJson.class); + } else { + break; + } + } + } + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/utils/ChangeGenerator.java b/src/main/java/org/sadtech/bot/bitbucketbot/utils/ChangeGenerator.java new file mode 100644 index 0000000..eee564a --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/utils/ChangeGenerator.java @@ -0,0 +1,84 @@ +package org.sadtech.bot.bitbucketbot.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import lombok.NonNull; +import org.sadtech.bot.bitbucketbot.domain.ReviewerStatus; +import org.sadtech.bot.bitbucketbot.domain.change.Change; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange; +import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; +import org.sadtech.bot.bitbucketbot.domain.entity.Reviewer; +import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class ChangeGenerator { + + public static NewPrChange create(@NonNull PullRequest newPullRequest) { + return NewPrChange.builder() + .author(newPullRequest.getAuthor().getFullName()) + .description(newPullRequest.getDescription()) + .title(newPullRequest.getTitle()) + .url(newPullRequest.getUrl()) + .telegramIds( + newPullRequest.getReviewers().stream() + .map(reviewer -> reviewer.getUser().getTelegramId()) + .collect(Collectors.toSet()) + ) + .build(); + } + + public static UpdatePrChange createUpdatePr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest) { + return UpdatePrChange.builder() + .author(oldPullRequest.getAuthor().getFullName()) + .name(newPullRequest.getAuthor().getFullName()) + .telegramIds( + newPullRequest.getReviewers().stream() + .map(reviewer -> reviewer.getUser().getTelegramId()) + .collect(Collectors.toSet()) + ) + .url(newPullRequest.getUrl()) + .build(); + } + + public static Change createReviewersPr(@NonNull PullRequest oldPullRequest, @NonNull PullRequest newPullRequest) { + final Map oldReviewers = oldPullRequest.getReviewers().stream() + .collect(Collectors.toMap(Reviewer::getId, reviewer -> reviewer)); + final Map newReviewers = newPullRequest.getReviewers().stream() + .collect(Collectors.toMap(Reviewer::getId, reviewer -> reviewer)); + final List reviewerChanges = new ArrayList<>(); + for (Reviewer newReviewer : newReviewers.values()) { + if (oldReviewers.containsKey(newReviewer.getId())) { + final Reviewer oldReviewer = oldReviewers.get(newReviewer.getId()); + final ReviewerStatus oldStatus = oldReviewer.getStatus(); + final ReviewerStatus newStatus = newReviewer.getStatus(); + if (!oldStatus.equals(newStatus)) { + reviewerChanges.add(ReviewerChange.ofOld(oldReviewer.getUser().getFullName(), oldStatus, newStatus)); + } + } else { + reviewerChanges.add(ReviewerChange.ofNew(newReviewer.getUser().getFullName(), newReviewer.getStatus())); + } + } + final Set oldIds = oldReviewers.keySet(); + oldIds.removeAll(newReviewers.keySet()); + reviewerChanges.addAll( + oldReviewers.entrySet().stream() + .filter(e -> oldIds.contains(e.getKey())) + .map(e -> ReviewerChange.ofDeleted(e.getValue().getUser().getFullName())) + .collect(Collectors.toList()) + ); + return ReviewersPrChange.builder() + .title(newPullRequest.getTitle()) + .url(newPullRequest.getUrl()) + .telegramId(newPullRequest.getAuthor().getTelegramId()) + .reviewerChanges(reviewerChanges) + .build(); + } +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/utils/Converter.java b/src/main/java/org/sadtech/bot/bitbucketbot/utils/Converter.java new file mode 100644 index 0000000..427b8f0 --- /dev/null +++ b/src/main/java/org/sadtech/bot/bitbucketbot/utils/Converter.java @@ -0,0 +1,23 @@ +package org.sadtech.bot.bitbucketbot.utils; + +import lombok.AccessLevel; +import lombok.NoArgsConstructor; +import org.sadtech.bot.bitbucketbot.domain.TaskStatus; +import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentState; +import org.sadtech.bot.bitbucketbot.exception.NotFoundException; + +@NoArgsConstructor(access = AccessLevel.PRIVATE) +public class Converter { + + public static TaskStatus taskStatus(CommentState commentState) { + switch (commentState) { + case OPEN: + return TaskStatus.OPEN; + case RESOLVED: + return TaskStatus.RESOLVED; + default: + throw new NotFoundException("Неизвестный статус задачи"); + } + } + +} diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/utils/Message.java b/src/main/java/org/sadtech/bot/bitbucketbot/utils/Message.java index 724b8e8..963d0fc 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/utils/Message.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/utils/Message.java @@ -1,13 +1,14 @@ package org.sadtech.bot.bitbucketbot.utils; import lombok.NonNull; -import org.sadtech.bot.bitbucketbot.domain.change.AnswerCommentChange; -import org.sadtech.bot.bitbucketbot.domain.change.CommentChange; -import org.sadtech.bot.bitbucketbot.domain.change.ConflictPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.NewPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.ReviewersPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.StatusPrChange; -import org.sadtech.bot.bitbucketbot.domain.change.UpdatePrChange; +import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ConflictPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.StatusPrChange; +import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange; +import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; @@ -40,7 +41,7 @@ public class Message { @NonNull public static String generate(NewPrChange newPrChange) { String message = Smile.FUN + " *Новый Pull Request*" + Smile.BR + - link(newPrChange.getName(), newPrChange.getUrl()) + + link(newPrChange.getTitle(), newPrChange.getUrl()) + Smile.HR; if (newPrChange.getDescription() != null && !"".equals(newPrChange.getDescription())) { message += newPrChange.getDescription() + Smile.HR; @@ -51,7 +52,7 @@ public class Message { public static String generate(@NonNull StatusPrChange change) { return Smile.PEN + " *Изменился статус вашего ПР*" + Smile.HR + - link(change.getName(), change.getUrl()) + Smile.BR + + link(change.getTitle(), change.getUrl()) + Smile.BR + change.getOldStatus().name() + " -> " + change.getNewStatus().name() + Smile.TWO_BR; } @@ -89,13 +90,13 @@ public class Message { final String createMessage = stringBuilder.toString(); return Smile.PEN + " *Изменения ревьюверов вашего ПР*" + Smile.HR + - link(reviewersChange.getName(), reviewersChange.getUrl()) + Smile.BR + + link(reviewersChange.getTitle(), reviewersChange.getUrl()) + Smile.BR + createMessage; } public static String generate(@NonNull UpdatePrChange change) { return Smile.UPDATE + " *Обновление Pull Request*" + Smile.BR + - link(change.getName(), change.getUrl()) + + link(change.getTitle(), change.getUrl()) + Smile.HR + Smile.AUTHOR + ": " + change.getAuthor() + Smile.TWO_BR; @@ -103,7 +104,7 @@ public class Message { public static String generate(@NonNull ConflictPrChange change) { return Smile.DANGEROUS + "*Внимание конфликт в ПР*" + Smile.HR + - link(change.getName(), change.getUrl()) + Smile.TWO_BR; + link(change.getTitle(), change.getUrl()) + Smile.TWO_BR; } @NonNull @@ -132,7 +133,6 @@ public class Message { .append(Smile.BR); } message - .append(Smile.BR) .append("Удачного дня ").append(Smile.FLOWER).append(Smile.TWO_BR); return message.toString(); } @@ -164,6 +164,21 @@ public class Message { return message.toString(); } + public static String generateNewTask(@NonNull TaskChange newTaskChange) { + return Smile.TASK + "*Назначена новая задача* | " + link("ПР", newTaskChange.getUrl()) + Smile.HR + + newTaskChange.getAuthorName() + ": " + newTaskChange.getMessageTask(); + } + + public static String generateDeleteTask(@NonNull TaskChange deletedTaskChange) { + return Smile.TASK + "*Задача была удалена* | " + link("ПР", deletedTaskChange.getUrl()) + Smile.HR + + deletedTaskChange.getAuthorName() + ": " + deletedTaskChange.getMessageTask(); + } + + public static String generateResolveTask(@NonNull TaskChange deletedTaskChange) { + return Smile.TASK + "*Задача выполнена* | " + link("ПР", deletedTaskChange.getUrl()) + Smile.HR + + deletedTaskChange.getAuthorName() + ": " + deletedTaskChange.getMessageTask(); + } + private static String needWorkPr(@NonNull List pullRequestsNeedWork) { final StringBuilder message = new StringBuilder(); pullRequestsNeedWork.stream() diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/utils/NonNullUtils.java b/src/main/java/org/sadtech/bot/bitbucketbot/utils/NonNullUtils.java index d6f495c..9e07310 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/utils/NonNullUtils.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/utils/NonNullUtils.java @@ -1,7 +1,7 @@ package org.sadtech.bot.bitbucketbot.utils; import lombok.NonNull; -import org.sadtech.bot.bitbucketbot.domain.entity.User; +import org.sadtech.bot.bitbucketbot.domain.entity.Person; import java.util.Collections; import java.util.Set; @@ -12,7 +12,7 @@ public class NonNullUtils { throw new IllegalStateException("Утилитный класс"); } - public static Set telegramIdByUser(@NonNull User user) { + public static Set telegramIdByUser(@NonNull Person user) { return user.getTelegramId() != null ? Collections.singleton(user.getTelegramId()) : Collections.emptySet(); } diff --git a/src/main/java/org/sadtech/bot/bitbucketbot/utils/Smile.java b/src/main/java/org/sadtech/bot/bitbucketbot/utils/Smile.java index 6c0046f..9200325 100644 --- a/src/main/java/org/sadtech/bot/bitbucketbot/utils/Smile.java +++ b/src/main/java/org/sadtech/bot/bitbucketbot/utils/Smile.java @@ -26,6 +26,7 @@ public enum Smile { DAY_3("\uD83C\uDF18"), DAY_4("\uD83C\uDF11"), DAY_5("\uD83C\uDF1A"), + TASK("\uD83E\uDD39\uD83C\uDFFB\u200D♂️"), MEGA_FUN("\uD83D\uDE02"), DANGEROUS("⚠️"), BELL("\uD83D\uDECE"), diff --git a/src/main/resources/application-dev.yaml b/src/main/resources/application-dev.yaml index 08103b0..ea8e9d5 100644 --- a/src/main/resources/application-dev.yaml +++ b/src/main/resources/application-dev.yaml @@ -17,8 +17,13 @@ spring: lob: non_contextual_creation: true bitbucketbot: + scheduler: + comment: + settings: + no-comment-count: 20 + comment-count: 100 init: - start-comment-id: + start-comment-id: 5947 server-send: url: http://188.225.35.149:8080/api/send bitbucket: @@ -27,3 +32,4 @@ bitbucketbot: url-pull-request-close: http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=150&closedSince=86400 url-pull-request-comment: http://192.168.236.164:7990/rest/api/1.0/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/comments/{commentId} url-pull-request: http://192.168.236.164:7990/projects/{projectKey}/repos/{repositorySlug}/pull-requests/{pullRequestId}/overview + url-users: http://192.168.236.164:7990/rest/api/1.0/admin/users \ No newline at end of file diff --git a/src/main/resources/application-prod.yaml b/src/main/resources/application-prod.yaml index a7d173b..1f5c841 100644 --- a/src/main/resources/application-prod.yaml +++ b/src/main/resources/application-prod.yaml @@ -27,3 +27,4 @@ bitbucketbot: 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 + url-users: http://localhost:7990/rest/api/1.0/admin/users \ No newline at end of file diff --git a/src/main/resources/liquibase/change-log.xml b/src/main/resources/liquibase/change-log.xml index 3425cc2..e5e157d 100644 --- a/src/main/resources/liquibase/change-log.xml +++ b/src/main/resources/liquibase/change-log.xml @@ -3,10 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd"> - - - - - + \ No newline at end of file diff --git a/src/main/resources/liquibase/change-set/create-table.xml b/src/main/resources/liquibase/change-set/create-table.xml deleted file mode 100644 index 755185f..0000000 --- a/src/main/resources/liquibase/change-set/create-table.xml +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/liquibase/change-set/v1.2.0.xml b/src/main/resources/liquibase/change-set/v1.2.0.xml deleted file mode 100644 index ce2c5f2..0000000 --- a/src/main/resources/liquibase/change-set/v1.2.0.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/liquibase/change-set/v1.3.0.xml b/src/main/resources/liquibase/change-set/v1.3.0.xml deleted file mode 100644 index 066e11e..0000000 --- a/src/main/resources/liquibase/change-set/v1.3.0.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ 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 deleted file mode 100644 index 2c92210..0000000 --- a/src/main/resources/liquibase/change-set/v1.4.0.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/liquibase/change-set/v2.0.0.xml b/src/main/resources/liquibase/change-set/v2.0.0.xml deleted file mode 100644 index 8129fe1..0000000 --- a/src/main/resources/liquibase/change-set/v2.0.0.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/resources/liquibase/v.2.0.0/create-table.xml b/src/main/resources/liquibase/v.2.0.0/create-table.xml new file mode 100644 index 0000000..3aff0c1 --- /dev/null +++ b/src/main/resources/liquibase/v.2.0.0/create-table.xml @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/liquibase/v.2.0.0/cumulative.xml b/src/main/resources/liquibase/v.2.0.0/cumulative.xml new file mode 100644 index 0000000..8f6afbf --- /dev/null +++ b/src/main/resources/liquibase/v.2.0.0/cumulative.xml @@ -0,0 +1,8 @@ + + + + + \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index 0335154..e106cf3 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -18,7 +18,7 @@ - + \ No newline at end of file