From 487aef5f71a7f01f60a83a0d854abf79010b9272 Mon Sep 17 00:00:00 2001 From: Mark Struchkov Date: Mon, 3 Feb 2020 12:22:53 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B2=D0=B0=D1=8F=20=D1=80?= =?UTF-8?q?=D0=B0=D0=B1=D0=BE=D1=87=D0=B0=D1=8F=20=D0=B2=D0=B5=D1=80=D1=81?= =?UTF-8?q?=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 34 ++++ pom.xml | 101 +++++++++++ .../bitbucketbot/BitbucketbotApplication.java | 13 ++ .../tsc/bitbucketbot/bitbucket/LinkJson.java | 17 ++ .../bitbucket/PullRequestJson.java | 24 +++ .../bitbucket/PullRequestState.java | 12 ++ .../tsc/bitbucketbot/bitbucket/SelfJson.java | 15 ++ .../com/tsc/bitbucketbot/bitbucket/Sheet.java | 21 +++ .../bitbucket/UserDecisionJson.java | 19 ++ .../tsc/bitbucketbot/bitbucket/UserJson.java | 16 ++ .../bitbucket/UserPullRequestStatus.java | 12 ++ .../bitbucket/sheet/PullRequestSheetJson.java | 12 ++ .../bitbucket/sheet/UserSheetJson.java | 13 ++ .../tsc/bitbucketbot/config/AppConfig.java | 99 ++++++++++ .../bitbucketbot/config/BitbucketConfig.java | 20 +++ .../config/unit/EntranceUser.java | 170 ++++++++++++++++++ .../bitbucketbot/config/unit/PanelUnit.java | 41 +++++ .../bitbucketbot/config/unit/UnitConfig.java | 51 ++++++ .../bitbucketbot/domain/AuthBitbucket.java | 17 ++ .../com/tsc/bitbucketbot/domain/AuthType.java | 12 ++ .../domain/BitbucketUserRole.java | 12 ++ .../domain/PullRequestStatus.java | 12 ++ .../bitbucketbot/domain/ReviewerStatus.java | 12 ++ .../com/tsc/bitbucketbot/domain/UserAuth.java | 13 ++ .../domain/entity/PullRequest.java | 61 +++++++ .../bitbucketbot/domain/entity/Reviewer.java | 53 ++++++ .../tsc/bitbucketbot/domain/entity/User.java | 48 +++++ .../repository/PullRequestsRepository.java | 16 ++ .../repository/UserRepository.java | 23 +++ .../scheduler/SchedulerNewMessage.java | 24 +++ .../scheduler/SchedulerNewUser.java | 57 ++++++ .../scheduler/SchedulerPullRequest.java | 129 +++++++++++++ .../service/PullRequestsService.java | 25 +++ .../tsc/bitbucketbot/service/UserService.java | 33 ++++ .../com/tsc/bitbucketbot/service/Utils.java | 59 ++++++ .../converter/PullRequestJsonConverter.java | 68 +++++++ .../service/converter/UserJsonConverter.java | 24 +++ .../service/impl/PullRequestsServiceImpl.java | 57 ++++++ .../service/impl/UserServiceImpl.java | 69 +++++++ src/main/resources/application.yaml | 32 ++++ src/main/resources/liquibase/change-log.xml | 8 + .../liquibase/change-set/create-table.xml | 56 ++++++ 42 files changed, 1610 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/com/tsc/bitbucketbot/BitbucketbotApplication.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/LinkJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestState.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/SelfJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/Sheet.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/UserDecisionJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/UserJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/UserPullRequestStatus.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/PullRequestSheetJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/UserSheetJson.java create mode 100644 src/main/java/com/tsc/bitbucketbot/config/AppConfig.java create mode 100644 src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java create mode 100644 src/main/java/com/tsc/bitbucketbot/config/unit/EntranceUser.java create mode 100644 src/main/java/com/tsc/bitbucketbot/config/unit/PanelUnit.java create mode 100644 src/main/java/com/tsc/bitbucketbot/config/unit/UnitConfig.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/AuthBitbucket.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/AuthType.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/BitbucketUserRole.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/PullRequestStatus.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/ReviewerStatus.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/UserAuth.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/entity/PullRequest.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/entity/Reviewer.java create mode 100644 src/main/java/com/tsc/bitbucketbot/domain/entity/User.java create mode 100644 src/main/java/com/tsc/bitbucketbot/repository/PullRequestsRepository.java create mode 100644 src/main/java/com/tsc/bitbucketbot/repository/UserRepository.java create mode 100644 src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewMessage.java create mode 100644 src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewUser.java create mode 100644 src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerPullRequest.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/PullRequestsService.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/UserService.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/Utils.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/converter/PullRequestJsonConverter.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/converter/UserJsonConverter.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/impl/PullRequestsServiceImpl.java create mode 100644 src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java create mode 100644 src/main/resources/application.yaml create mode 100644 src/main/resources/liquibase/change-log.xml create mode 100644 src/main/resources/liquibase/change-set/create-table.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8fd1727 --- /dev/null +++ b/.gitignore @@ -0,0 +1,34 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/** +!**/src/test/** + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ + +### VS Code ### +.vscode/ +/.mvn/wrapper/ +/mvnw +/mvnw.cmd diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d2107e7 --- /dev/null +++ b/pom.xml @@ -0,0 +1,101 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.4.RELEASE + + + com.tsc.bitbucketbot + bitbucketbot + 0.0.1-SNAPSHOT + bitbucketbot + Demo project for Spring Boot + + + 1.8 + + + + + + org.sadtech.telegram + telegram-bot + 0.0.1-DEVELOPER + + + + org.springframework.boot + spring-boot-starter + + + + com.google.code.gson + gson + 2.8.5 + + + + org.springframework.boot + spring-boot-devtools + runtime + true + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.liquibase + liquibase-core + 3.8.5 + + + + org.postgresql + postgresql + 42.2.9 + + + + org.springframework.boot + spring-boot-starter-web + + + ch.qos.logback + logback-classic + + + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + org.junit.vintage + junit-vintage-engine + + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/src/main/java/com/tsc/bitbucketbot/BitbucketbotApplication.java b/src/main/java/com/tsc/bitbucketbot/BitbucketbotApplication.java new file mode 100644 index 0000000..6a2a023 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/BitbucketbotApplication.java @@ -0,0 +1,13 @@ +package com.tsc.bitbucketbot; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BitbucketbotApplication { + + public static void main(String[] args) { + SpringApplication.run(BitbucketbotApplication.class, args); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/LinkJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/LinkJson.java new file mode 100644 index 0000000..b96177d --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/LinkJson.java @@ -0,0 +1,17 @@ +package com.tsc.bitbucketbot.bitbucket; + +import lombok.Data; + +import java.util.List; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Data +public class LinkJson { + + private List self; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestJson.java new file mode 100644 index 0000000..69dc253 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestJson.java @@ -0,0 +1,24 @@ +package com.tsc.bitbucketbot.bitbucket; + +import lombok.Data; + +import java.util.List; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Data +public class PullRequestJson { + + private Long id; + private Integer version; + private PullRequestState state; + private String title; + private String description; + private LinkJson links; + private UserDecisionJson author; + private List reviewers; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestState.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestState.java new file mode 100644 index 0000000..0ad1a99 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/PullRequestState.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.bitbucket; + +/** + * TODO: Добавить комментарий енума. + * + * @author upagge [01.02.2020] + */ +public enum PullRequestState { + + OPEN, MERGED, DECLINED + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/SelfJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/SelfJson.java new file mode 100644 index 0000000..2042bfe --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/SelfJson.java @@ -0,0 +1,15 @@ +package com.tsc.bitbucketbot.bitbucket; + +import lombok.Data; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Data +public class SelfJson { + + private String href; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/Sheet.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/Sheet.java new file mode 100644 index 0000000..95e7332 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/Sheet.java @@ -0,0 +1,21 @@ +package com.tsc.bitbucketbot.bitbucket; + +import lombok.Data; + +import java.util.List; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Data +public abstract class Sheet { + + private Integer size; + private Integer limit; + private Boolean isLastPage; + private List values; + private Integer nextPageStart; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/UserDecisionJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/UserDecisionJson.java new file mode 100644 index 0000000..8cda3c9 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/UserDecisionJson.java @@ -0,0 +1,19 @@ +package com.tsc.bitbucketbot.bitbucket; + +import com.tsc.bitbucketbot.domain.BitbucketUserRole; +import lombok.Data; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Data +public class UserDecisionJson { + + private UserJson user; + private BitbucketUserRole role; + private Boolean approved; + private UserPullRequestStatus status; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/UserJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/UserJson.java new file mode 100644 index 0000000..6324c18 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/UserJson.java @@ -0,0 +1,16 @@ +package com.tsc.bitbucketbot.bitbucket; + +import lombok.Data; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Data +public class UserJson { + + private String name; + private String displayName; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/UserPullRequestStatus.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/UserPullRequestStatus.java new file mode 100644 index 0000000..2abb179 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/UserPullRequestStatus.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.bitbucket; + +/** + * TODO: Добавить комментарий енума. + * + * @author upagge [31.01.2020] + */ +public enum UserPullRequestStatus { + + UNAPPROVED, APPROVED, NEEDS_WORK + +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/PullRequestSheetJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/PullRequestSheetJson.java new file mode 100644 index 0000000..32ba942 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/PullRequestSheetJson.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.bitbucket.sheet; + +import com.tsc.bitbucketbot.bitbucket.PullRequestJson; +import com.tsc.bitbucketbot.bitbucket.Sheet; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [02.02.2020] + */ +public class PullRequestSheetJson extends Sheet { +} diff --git a/src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/UserSheetJson.java b/src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/UserSheetJson.java new file mode 100644 index 0000000..dc3060c --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/bitbucket/sheet/UserSheetJson.java @@ -0,0 +1,13 @@ +package com.tsc.bitbucketbot.bitbucket.sheet; + +import com.tsc.bitbucketbot.bitbucket.Sheet; +import com.tsc.bitbucketbot.bitbucket.UserJson; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [02.02.2020] + */ +public class UserSheetJson extends Sheet { + +} diff --git a/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java b/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java new file mode 100644 index 0000000..04e7e0c --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/config/AppConfig.java @@ -0,0 +1,99 @@ +package com.tsc.bitbucketbot.config; + +import org.sadtech.autoresponder.repository.UnitPointerRepository; +import org.sadtech.autoresponder.repository.UnitPointerRepositoryMap; +import org.sadtech.social.bot.domain.unit.AnswerCheck; +import org.sadtech.social.bot.service.action.AnswerSaveAction; +import org.sadtech.social.core.domain.content.Mail; +import org.sadtech.social.core.repository.impl.local.MailRepositoryList; +import org.sadtech.social.core.service.MailService; +import org.sadtech.social.core.service.MessageService; +import org.sadtech.social.core.service.impl.MailServiceImpl; +import org.sadtech.social.core.service.sender.Sending; +import org.sadtech.telegram.bot.TelegramConfig; +import org.sadtech.telegram.bot.autoresponder.MessageAutoresponderTelegram; +import org.sadtech.telegram.bot.listen.EventDistributor; +import org.sadtech.telegram.bot.listen.EventDistributorImpl; +import org.sadtech.telegram.bot.listen.TelegramConnect; +import org.sadtech.telegram.bot.listen.TelegramSender; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.TaskScheduler; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; + +import java.util.Collections; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Configuration +@EnableScheduling +public class AppConfig { + + @Bean + public MailService messageService() { + return new MailServiceImpl(new MailRepositoryList()); + } + + @Bean + public UnitPointerRepository unitPointerRepository() { + return new UnitPointerRepositoryMap(); + } + + @Bean + public MessageAutoresponderTelegram messageAutoresponderTelegram( + AnswerCheck checkMenu, + Sending sending, + MessageService messageService, + UnitPointerRepository unitPointerRepository + ) { + final MessageAutoresponderTelegram messageAutoresponderTelegram = new MessageAutoresponderTelegram( + Collections.singleton(checkMenu), + sending, + messageService, + unitPointerRepository + ); + messageAutoresponderTelegram.initSaveAction(new AnswerSaveAction<>()); + return messageAutoresponderTelegram; + } + + @Bean + public TaskScheduler taskScheduler() { + ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); + taskScheduler.setPoolSize(5); + return taskScheduler; + } + + @Bean + public Sending sending( + TelegramConnect telegramConnect + ) { + return new TelegramSender(telegramConnect); + } + + @Bean + public TelegramConnect telegramConnect( + TelegramConfig telegramConfig + ) { + return new TelegramConnect(telegramConfig); + } + + @Bean + @ConfigurationProperties("bitbucketbot.telegram") + public TelegramConfig telegramConfig() { + return new TelegramConfig(); + } + + @Bean + public EventDistributor eventDistributor( + TelegramConnect telegramConnect, + MailService mailService + ) { + return new EventDistributorImpl(telegramConnect, mailService); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java b/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java new file mode 100644 index 0000000..e59edb9 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/config/BitbucketConfig.java @@ -0,0 +1,20 @@ +package com.tsc.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 url; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/config/unit/EntranceUser.java b/src/main/java/com/tsc/bitbucketbot/config/unit/EntranceUser.java new file mode 100644 index 0000000..f75eb9f --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/config/unit/EntranceUser.java @@ -0,0 +1,170 @@ +package com.tsc.bitbucketbot.config.unit; + +import com.tsc.bitbucketbot.domain.AuthType; +import com.tsc.bitbucketbot.domain.entity.User; +import com.tsc.bitbucketbot.service.UserService; +import lombok.NonNull; +import org.apache.http.HttpHeaders; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.HttpClientBuilder; +import org.sadtech.social.bot.domain.unit.AnswerProcessing; +import org.sadtech.social.bot.domain.unit.AnswerSave; +import org.sadtech.social.bot.domain.unit.AnswerText; +import org.sadtech.social.bot.service.save.LocalPreservable; +import org.sadtech.social.bot.service.save.Preservable; +import org.sadtech.social.core.domain.BoxAnswer; +import org.sadtech.social.core.domain.content.Message; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.io.IOException; +import java.util.Base64; +import java.util.Optional; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [02.02.2020] + */ +@Configuration +public class EntranceUser { + + @Bean + public Preservable authBitbucketPreservable() { + return new LocalPreservable<>(); + } + + @Bean + public AnswerText entranceText( + AnswerSave saveLogin + ) { + return AnswerText.builder() + .boxAnswer(BoxAnswer.of("Пришлите ваш логин в bitbucket")) + .nextUnit(saveLogin) + .phrase("Войти") + .build(); + } + + @Bean + public AnswerSave saveLogin( + AnswerText savePasswordText, + Preservable authBitbucketPreservable + ) { + return AnswerSave.builder() + .preservable(authBitbucketPreservable) + .key(AuthType.LOGIN.name()) + .preservableData(Message::getText) + .nextUnit(savePasswordText) + .build(); + } + + @Bean + public AnswerText savePasswordText( + AnswerSave savePassword + ) { + return AnswerText.builder() + .boxAnswer(BoxAnswer.of("Пришлите ваш пароль в bitbucket")) + .nextUnit(savePassword) + .build(); + } + + @Bean + public AnswerSave savePassword( + Preservable authBitbucketPreservable, + AnswerText saveTokenText + ) { + return AnswerSave.builder() + .preservable(authBitbucketPreservable) + .key(AuthType.PASSWORD.name()) + .preservableData(Message::getText) + .nextUnit(saveTokenText) + .build(); + } + + @Bean + public AnswerText saveTokenText( + AnswerSave saveToken + ) { + return AnswerText.builder() + .boxAnswer(BoxAnswer.of("Пришлите ваш токен в bitbucket.\nПолучить можно здесь: http://192.168.236.164:7990/plugins/servlet/access-tokens/manage")) + .nextUnit(saveToken) + .build(); + } + + @Bean + public AnswerSave saveToken( + Preservable authBitbucketPreservable, + AnswerSave saveTelegramId + ) { + return AnswerSave.builder() + .preservable(authBitbucketPreservable) + .key(AuthType.TOKEN.name()) + .preservableData(Message::getText) + .nextUnit(saveTelegramId) + .build(); + } + + @Bean + public AnswerSave saveTelegramId( + Preservable authBitbucketPreservable, + AnswerProcessing auth + ) { + return AnswerSave.builder() + .preservable(authBitbucketPreservable) + .key(AuthType.TELEGRAM_ID.name()) + .preservableData(Message::getText) + .hidden(true) + .nextUnit(auth) + .build(); + } + + @Bean + public AnswerProcessing auth( + Preservable authBitbucketPreservable, + UserService userService + ) { + return AnswerProcessing.builder() + .processingData(message -> { + final Optional optLogin = authBitbucketPreservable.getByKey(message.getPersonId(), AuthType.LOGIN.name()); + final Optional optPassword = authBitbucketPreservable.getByKey(message.getPersonId(), AuthType.PASSWORD.name()); + final Optional optToken = authBitbucketPreservable.getByKey(message.getPersonId(), AuthType.TOKEN.name()); + if (optLogin.isPresent() && optPassword.isPresent() && optToken.isPresent()) { + try { + HttpClient httpClient = HttpClientBuilder.create().build(); + String encoding = Base64.getEncoder().encodeToString((optLogin.get() + ":" + optPassword.get()).getBytes()); + HttpGet httpPost = new HttpGet("http://192.168.236.164:7990/"); + httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + encoding); + HttpResponse response = httpClient.execute(httpPost); + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + return registerNewUser(userService, optLogin.get(), message.getPersonId(), optToken.get()); + } + } catch (IOException e) { + BoxAnswer.of("Не удалось авторизоваться"); + } + } + return BoxAnswer.of("Не удалось авторизоваться"); + }) + .build(); + } + + private BoxAnswer registerNewUser(@NonNull UserService userService, @NonNull String login, @NonNull Long telegramId, @NonNull String token) { + final Optional optUser = userService.getByLogin(login); + if (optUser.isPresent()) { + final User user = optUser.get(); + if (user.getTelegramId() == null) { + user.setTelegramId(telegramId); + user.setToken(token); + userService.update(user); + return BoxAnswer.of("Регистрация прошла успешно"); + } else { + return BoxAnswer.of("Пользоватль с таким логином уже зарегистрирован"); + } + } else { + return BoxAnswer.of("Необходимо либо создать пр, либо быть ревьювером текущего ПР, чтобы пройти регистрацию"); + } + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/config/unit/PanelUnit.java b/src/main/java/com/tsc/bitbucketbot/config/unit/PanelUnit.java new file mode 100644 index 0000000..2421ac9 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/config/unit/PanelUnit.java @@ -0,0 +1,41 @@ +package com.tsc.bitbucketbot.config.unit; + +import org.sadtech.social.bot.domain.unit.AnswerCheck; +import org.sadtech.social.bot.domain.unit.AnswerText; +import org.sadtech.social.bot.domain.unit.MainUnit; +import org.sadtech.social.core.domain.BoxAnswer; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [02.02.2020] + */ +@Configuration +public class PanelUnit { + + @Bean + public AnswerText textEntranceAdmin( + MainUnit checkPasswordEntranceAdmin + ) { + return AnswerText.builder() + .boxAnswer(BoxAnswer.of("Введите пароль")) + .phrase("Панель управления") + .nextUnit(checkPasswordEntranceAdmin) + .build(); + } + + @Bean + public AnswerCheck checkPasswordEntranceAdmin( + @Value("${bitbucketbot.panel.password}") String password + ){ + return AnswerCheck.builder() + .check(message -> password.equals(message.getText())) + .unitFalse(AnswerText.of("Пароль неверный")) +// .unitTrue() + .build(); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/config/unit/UnitConfig.java b/src/main/java/com/tsc/bitbucketbot/config/unit/UnitConfig.java new file mode 100644 index 0000000..597d24b --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/config/unit/UnitConfig.java @@ -0,0 +1,51 @@ +package com.tsc.bitbucketbot.config.unit; + +import com.tsc.bitbucketbot.service.UserService; +import org.sadtech.social.bot.domain.unit.AnswerCheck; +import org.sadtech.social.bot.domain.unit.AnswerText; +import org.sadtech.social.bot.domain.unit.MainUnit; +import org.sadtech.social.core.domain.BoxAnswer; +import org.sadtech.social.core.utils.KeyBoards; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Configuration +public class UnitConfig { + + @Bean + public AnswerCheck checkMenu( + UserService userService, + @Value("${bitbucketbot.telegram.admin-chatid}") Long adminChatId, + AnswerText menu + ) { + return AnswerCheck.builder() + .check(message -> !userService.existsByTelegramId(message.getPersonId()) || message.getPersonId().equals(adminChatId)) + .unitTrue(menu) + .unitFalse(AnswerText.of("Вы уже получаете уведомления")) + .build(); + } + + @Bean + public AnswerText menu( + MainUnit entranceText, + MainUnit textEntranceAdmin + ) { + return AnswerText.builder() + .boxAnswer( + BoxAnswer.builder() + .message("Привет. Я помогаю сотрудникам ТСК отслеживать события в Bitbucket. Если хочешь войти, обращайся к @upagge") + .keyBoard(KeyBoards.verticalMenuString("Войти", "Панель управления")) + .build() + ) + .nextUnit(entranceText) + .nextUnit(textEntranceAdmin) + .build(); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/AuthBitbucket.java b/src/main/java/com/tsc/bitbucketbot/domain/AuthBitbucket.java new file mode 100644 index 0000000..b72d430 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/AuthBitbucket.java @@ -0,0 +1,17 @@ +package com.tsc.bitbucketbot.domain; + +import lombok.Data; +import org.junit.experimental.theories.DataPoints; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Data +public class AuthBitbucket { + + private String login; + private String token; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/AuthType.java b/src/main/java/com/tsc/bitbucketbot/domain/AuthType.java new file mode 100644 index 0000000..67048e1 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/AuthType.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.domain; + +/** + * TODO: Добавить комментарий енума. + * + * @author upagge [31.01.2020] + */ +public enum AuthType { + + TOKEN, LOGIN, TELEGRAM_ID, PASSWORD + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/BitbucketUserRole.java b/src/main/java/com/tsc/bitbucketbot/domain/BitbucketUserRole.java new file mode 100644 index 0000000..614ff62 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/BitbucketUserRole.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.domain; + +/** + * TODO: Добавить комментарий енума. + * + * @author upagge [31.01.2020] + */ +public enum BitbucketUserRole { + + AUTHOR, REVIEWER + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/PullRequestStatus.java b/src/main/java/com/tsc/bitbucketbot/domain/PullRequestStatus.java new file mode 100644 index 0000000..cd5fa14 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/PullRequestStatus.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.domain; + +/** + * TODO: Добавить комментарий енума. + * + * @author upagge [31.01.2020] + */ +public enum PullRequestStatus { + + OPEN, MERGED, DECLINED + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/ReviewerStatus.java b/src/main/java/com/tsc/bitbucketbot/domain/ReviewerStatus.java new file mode 100644 index 0000000..42c1416 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/ReviewerStatus.java @@ -0,0 +1,12 @@ +package com.tsc.bitbucketbot.domain; + +/** + * TODO: Добавить комментарий енума. + * + * @author upagge [01.02.2020] + */ +public enum ReviewerStatus { + + NEEDS_WORK, APPROVED, UNAPPROVED + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/UserAuth.java b/src/main/java/com/tsc/bitbucketbot/domain/UserAuth.java new file mode 100644 index 0000000..1759e8e --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/UserAuth.java @@ -0,0 +1,13 @@ +package com.tsc.bitbucketbot.domain; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [02.02.2020] + */ +public class UserAuth { + + private String login; + private String password; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/entity/PullRequest.java b/src/main/java/com/tsc/bitbucketbot/domain/entity/PullRequest.java new file mode 100644 index 0000000..cfdb455 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/entity/PullRequest.java @@ -0,0 +1,61 @@ +package com.tsc.bitbucketbot.domain.entity; + +import com.tsc.bitbucketbot.domain.PullRequestStatus; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.CascadeType; +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.ManyToOne; +import javax.persistence.OneToMany; +import java.util.List; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Getter +@Setter +@Entity +@Builder +@NoArgsConstructor +@AllArgsConstructor +@EqualsAndHashCode(of = "id") +@ToString +public class PullRequest { + + @Id + @Column(name = "id") + private Long id; + + @ManyToOne + @JoinColumn(name = "autor_login") + private User author; + + @OneToMany(mappedBy = "pullRequestId", cascade = CascadeType.ALL) + private List reviewers; + + @Column(name = "url") + private String url; + + @Column(name = "name") + private String name; + + @Enumerated(EnumType.STRING) + @Column(name = "status") + private PullRequestStatus status; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/entity/Reviewer.java b/src/main/java/com/tsc/bitbucketbot/domain/entity/Reviewer.java new file mode 100644 index 0000000..c30e997 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/entity/Reviewer.java @@ -0,0 +1,53 @@ +package com.tsc.bitbucketbot.domain.entity; + +import com.tsc.bitbucketbot.domain.ReviewerStatus; +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +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.Table; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [01.02.2020] + */ +@Entity +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@Table(name = "reviewer") +@EqualsAndHashCode(of = "id") +public class Reviewer { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + // @OneToMany(fetch = FetchType.LAZY) +// @JoinColumn(name = "pull_request_id") + @Column(name = "pull_request_id") + private Long pullRequestId; + + // @OneToMany(fetch = FetchType.LAZY) +// @JoinColumn(name = "user_login") + @Column(name = "user_login") + private String user; + + @Enumerated(EnumType.STRING) + @Column(name = "status") + private ReviewerStatus status; + + +} diff --git a/src/main/java/com/tsc/bitbucketbot/domain/entity/User.java b/src/main/java/com/tsc/bitbucketbot/domain/entity/User.java new file mode 100644 index 0000000..a7c736c --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/domain/entity/User.java @@ -0,0 +1,48 @@ +package com.tsc.bitbucketbot.domain.entity; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.io.Serializable; + +/** + * 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 = "name") + private String name; + + @Column(name = "token") + private String token; + + @Column(name = "telegram_id") + private Long telegramId; + +} diff --git a/src/main/java/com/tsc/bitbucketbot/repository/PullRequestsRepository.java b/src/main/java/com/tsc/bitbucketbot/repository/PullRequestsRepository.java new file mode 100644 index 0000000..2690022 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/repository/PullRequestsRepository.java @@ -0,0 +1,16 @@ +package com.tsc.bitbucketbot.repository; + +import com.tsc.bitbucketbot.domain.entity.PullRequest; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; +import java.util.Set; + +/** + * TODO: Добавить описание интерфейса. + * + * @author upagge [31.01.2020] + */ +public interface PullRequestsRepository extends JpaRepository { + +} diff --git a/src/main/java/com/tsc/bitbucketbot/repository/UserRepository.java b/src/main/java/com/tsc/bitbucketbot/repository/UserRepository.java new file mode 100644 index 0000000..fb5cdc6 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/repository/UserRepository.java @@ -0,0 +1,23 @@ +package com.tsc.bitbucketbot.repository; + +import com.tsc.bitbucketbot.domain.entity.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Repository +public interface UserRepository extends JpaRepository { + + boolean existsByTelegramId(Long chatId); + + @Query("SELECT u FROM User u WHERE u.telegramId IS NOT NULL AND u.token IS NOT NULL") + List findAllRegistered(); + +} diff --git a/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewMessage.java b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewMessage.java new file mode 100644 index 0000000..f4cb0aa --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewMessage.java @@ -0,0 +1,24 @@ +package com.tsc.bitbucketbot.scheduler; + +import lombok.RequiredArgsConstructor; +import org.sadtech.telegram.bot.autoresponder.MessageAutoresponderTelegram; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Service +@RequiredArgsConstructor +public class SchedulerNewMessage { + + private final MessageAutoresponderTelegram messageAutoresponderTelegram; + + @Scheduled(fixedRate = 3000) + public void scan() { + messageAutoresponderTelegram.checkNewMessage(); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewUser.java b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewUser.java new file mode 100644 index 0000000..2c76ead --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerNewUser.java @@ -0,0 +1,57 @@ +package com.tsc.bitbucketbot.scheduler; + +import com.tsc.bitbucketbot.bitbucket.Sheet; +import com.tsc.bitbucketbot.bitbucket.UserJson; +import com.tsc.bitbucketbot.bitbucket.sheet.UserSheetJson; +import com.tsc.bitbucketbot.config.BitbucketConfig; +import com.tsc.bitbucketbot.domain.entity.User; +import com.tsc.bitbucketbot.service.UserService; +import com.tsc.bitbucketbot.service.Utils; +import lombok.RequiredArgsConstructor; +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 { + + public 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/com/tsc/bitbucketbot/scheduler/SchedulerPullRequest.java b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerPullRequest.java new file mode 100644 index 0000000..75baf17 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/scheduler/SchedulerPullRequest.java @@ -0,0 +1,129 @@ +package com.tsc.bitbucketbot.scheduler; + +import com.tsc.bitbucketbot.bitbucket.PullRequestJson; +import com.tsc.bitbucketbot.bitbucket.UserDecisionJson; +import com.tsc.bitbucketbot.bitbucket.UserPullRequestStatus; +import com.tsc.bitbucketbot.bitbucket.sheet.PullRequestSheetJson; +import com.tsc.bitbucketbot.config.BitbucketConfig; +import com.tsc.bitbucketbot.domain.ReviewerStatus; +import com.tsc.bitbucketbot.domain.entity.PullRequest; +import com.tsc.bitbucketbot.domain.entity.Reviewer; +import com.tsc.bitbucketbot.domain.entity.User; +import com.tsc.bitbucketbot.service.PullRequestsService; +import com.tsc.bitbucketbot.service.UserService; +import com.tsc.bitbucketbot.service.Utils; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.sadtech.social.core.domain.BoxAnswer; +import org.sadtech.social.core.service.sender.Sending; +import org.springframework.core.convert.ConversionService; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Service +@RequiredArgsConstructor +public class SchedulerPullRequest { + + private static final String URL = "http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=50&state=OPEN"; + private final BitbucketConfig bitbucketConfig; + private final PullRequestsService pullRequestsService; + private final UserService userService; + private final ConversionService conversionService; + private final Sending sending; + + @Scheduled(fixedRate = 15000) + public void checkNewPullRequest() { + final List users = userService.getAllRegistered(); + for (User user : users) { + Optional sheetJson = Utils.urlToJson(URL, user.getToken(), PullRequestSheetJson.class); + while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { + final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get(); + final Set pullRequestBitbucketId = pullRequestBitbucketSheet.getValues().stream() + .map(PullRequestJson::getId) + .collect(Collectors.toSet()); + Set existsId = pullRequestsService.existsAllById(pullRequestBitbucketId); + final Set newPullRequestBitbucket = pullRequestBitbucketSheet.getValues().stream() + .filter(pullRequestJson -> !existsId.contains(pullRequestJson.getId())) + .collect(Collectors.toSet()); + pullRequestsService.addAll( + newPullRequestBitbucket.stream() + .map(pullRequestJson -> conversionService.convert(pullRequestJson, PullRequest.class)) + .collect(Collectors.toSet()) + ); + final List newPullRequests = new ArrayList<>(); + for (PullRequestJson pullRequestJson : newPullRequestBitbucket) { + final List reviewers = pullRequestJson.getReviewers().stream() + .map(reviewer -> testConvert(pullRequestJson, reviewer)) + .collect(Collectors.toList()); + pullRequestsService.addReviewer(pullRequestJson.getId(), reviewers).ifPresent(newPullRequests::add); + } + sendNotification(newPullRequests); + if (pullRequestBitbucketSheet.getNextPageStart() != null) { + sheetJson = Utils.urlToJson(URL + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); + } else { + break; + } + } + } + } + + private Reviewer testConvert(PullRequestJson pullRequestJson, UserDecisionJson reviewer) { + final Reviewer newReviewer = new Reviewer(); + newReviewer.setPullRequestId(pullRequestJson.getId()); + newReviewer.setUser(reviewer.getUser().getName()); + newReviewer.setStatus(convertStatusReviewer(reviewer.getStatus())); + return newReviewer; + } + + private ReviewerStatus convertStatusReviewer(UserPullRequestStatus status) { + switch (status) { + case APPROVED: + return ReviewerStatus.APPROVED; + case NEEDS_WORK: + return ReviewerStatus.UNAPPROVED; + case UNAPPROVED: + return ReviewerStatus.NEEDS_WORK; + } + return null; + } + + private void sendNotification(@NonNull List newPullRequests) { + if (!newPullRequests.isEmpty()) { + Map map = new HashMap<>(); + newPullRequests.forEach( + pullRequest -> pullRequest.getReviewers().forEach( + reviewer -> test(pullRequest, reviewer, map) + ) + ); + map.forEach((key, value) -> sending.send(key, BoxAnswer.of(value.toString()))); + } + } + + private void test(PullRequest pullRequest, Reviewer reviewer, Map map) { + userService.getByLogin(reviewer.getUser()).ifPresent( + user -> { + final Long telegramId = user.getTelegramId(); + if (telegramId != null) { + if (!map.containsKey(telegramId)) { + map.put(telegramId, new StringBuilder("У вас есть новые ПР:\n\n")); + } + map.get(telegramId).append(pullRequest.getName()).append("\nАвтор: ").append(pullRequest.getAuthor().getName()).append("\nСсылка: ").append(pullRequest.getUrl()).append("\n-- -- -- -- --\n\n"); + } + } + ); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/PullRequestsService.java b/src/main/java/com/tsc/bitbucketbot/service/PullRequestsService.java new file mode 100644 index 0000000..7b64ccc --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/PullRequestsService.java @@ -0,0 +1,25 @@ +package com.tsc.bitbucketbot.service; + +import com.tsc.bitbucketbot.domain.entity.PullRequest; +import com.tsc.bitbucketbot.domain.entity.Reviewer; +import lombok.NonNull; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +public interface PullRequestsService { + + Set existsById(@NonNull final Set idList); + + Set existsAllById(@NonNull Set pullRequestJsonId); + + List addAll(Set pullRequests); + + Optional addReviewer(@NonNull Long pullRequestJsonId, @NonNull List reviewers); +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/UserService.java b/src/main/java/com/tsc/bitbucketbot/service/UserService.java new file mode 100644 index 0000000..f5cf5eb --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/UserService.java @@ -0,0 +1,33 @@ +package com.tsc.bitbucketbot.service; + +import com.tsc.bitbucketbot.domain.entity.User; +import lombok.NonNull; + +import java.util.List; +import java.util.Optional; +import java.util.Set; + +/** + * TODO: Добавить описание интерфейса. + * + * @author upagge [30.01.2020] + */ +public interface UserService { + + boolean existsByTelegramId(@NonNull final Long chatId); + + User add(@NonNull final User user); + + List getAll(); + + Optional getByLogin(String login); + + Optional update(User user); + + Set existsByLogin(@NonNull Set logins); + + List addAll(@NonNull Set users); + + List getAllRegistered(); + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/Utils.java b/src/main/java/com/tsc/bitbucketbot/service/Utils.java new file mode 100644 index 0000000..ffcca57 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/Utils.java @@ -0,0 +1,59 @@ +package com.tsc.bitbucketbot.service; + +import com.google.gson.Gson; +import lombok.NonNull; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.Optional; +import java.util.zip.GZIPInputStream; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [30.01.2020] + */ +@Service +public class Utils { + + private static Gson gson = new Gson(); + + public static Optional urlToJson(@NonNull String urlValue, String token, Class classOfT) { + StringBuilder sb = null; + URL url; + URLConnection urlCon; + try { + url = new URL(urlValue); + urlCon = url.openConnection(); + if (token != null) { + urlCon.setRequestProperty("Authorization", "Bearer " + token); + } + BufferedReader in; + if (urlCon.getHeaderField("Content-Encoding") != null + && urlCon.getHeaderField("Content-Encoding").equals("gzip")) { + in = new BufferedReader(new InputStreamReader(new GZIPInputStream(urlCon.getInputStream()))); + } else { + + in = new BufferedReader(new InputStreamReader(urlCon.getInputStream())); + } + String inputLine; + sb = new StringBuilder(); + + while ((inputLine = in.readLine()) != null) { + sb.append(inputLine); + } + in.close(); + } catch (IOException e) { + + } + if (sb != null) { + return Optional.of(gson.fromJson(sb.toString(), classOfT)); + } + return Optional.empty(); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/converter/PullRequestJsonConverter.java b/src/main/java/com/tsc/bitbucketbot/service/converter/PullRequestJsonConverter.java new file mode 100644 index 0000000..6ba32c9 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/converter/PullRequestJsonConverter.java @@ -0,0 +1,68 @@ +package com.tsc.bitbucketbot.service.converter; + +import com.tsc.bitbucketbot.bitbucket.PullRequestJson; +import com.tsc.bitbucketbot.bitbucket.PullRequestState; +import com.tsc.bitbucketbot.bitbucket.UserJson; +import com.tsc.bitbucketbot.domain.PullRequestStatus; +import com.tsc.bitbucketbot.domain.entity.PullRequest; +import com.tsc.bitbucketbot.domain.entity.User; +import com.tsc.bitbucketbot.service.UserService; +import lombok.RequiredArgsConstructor; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Component; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [01.02.2020] + */ +@Component +@RequiredArgsConstructor +public class PullRequestJsonConverter implements Converter { + + private final UserJsonConverter userJsonConverter; + private final UserService userService; + + @Override + public PullRequest convert(PullRequestJson json) { + return PullRequest.builder() + .id(json.getId()) + .author(this.convertUser(json.getAuthor().getUser())) + .name(json.getTitle()) + .url(json.getLinks().getSelf().get(0).getHref()) + .status(convertPullRequestStatus(json.getState())) + .build(); + } + + private User convertUser(UserJson userJson) { + return userService.getByLogin(userJson.getName()).orElse(userJsonConverter.convert(userJson)); + } + + private PullRequestStatus convertPullRequestStatus(PullRequestState state) { + switch (state) { + case OPEN: + return PullRequestStatus.OPEN; + case MERGED: + return PullRequestStatus.MERGED; + case DECLINED: + return PullRequestStatus.DECLINED; + } + return null; + } + +// private List convertReviewers(PullRequest pullRequest, List jsonReviewers) { +// return jsonReviewers.stream() +// .map( +// jsonReviewer -> { +// final Reviewer reviewer = new Reviewer(); +// reviewer.setReviewerKey(new ReviewerKey(convertUser(jsonReviewer.getUser()).getLogin())); +// reviewer.setStatus(convertStatusReviewer(jsonReviewer.getStatus())); +// return reviewer; +// } +// ) +// .collect(Collectors.toList()); +// } + + + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/converter/UserJsonConverter.java b/src/main/java/com/tsc/bitbucketbot/service/converter/UserJsonConverter.java new file mode 100644 index 0000000..49aa408 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/converter/UserJsonConverter.java @@ -0,0 +1,24 @@ +package com.tsc.bitbucketbot.service.converter; + +import com.tsc.bitbucketbot.bitbucket.UserJson; +import com.tsc.bitbucketbot.domain.entity.User; +import org.springframework.core.convert.converter.Converter; +import org.springframework.stereotype.Service; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [02.02.2020] + */ +@Service +public class UserJsonConverter implements Converter { + + @Override + public User convert(UserJson source) { + return User.builder() + .name(source.getDisplayName()) + .login(source.getName()) + .build(); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/impl/PullRequestsServiceImpl.java b/src/main/java/com/tsc/bitbucketbot/service/impl/PullRequestsServiceImpl.java new file mode 100644 index 0000000..e3e37a3 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/impl/PullRequestsServiceImpl.java @@ -0,0 +1,57 @@ +package com.tsc.bitbucketbot.service.impl; + +import com.tsc.bitbucketbot.domain.entity.PullRequest; +import com.tsc.bitbucketbot.domain.entity.Reviewer; +import com.tsc.bitbucketbot.repository.PullRequestsRepository; +import com.tsc.bitbucketbot.service.PullRequestsService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import javax.transaction.Transactional; +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * TODO: Добавить описание класса. + * + * @author upagge [31.01.2020] + */ +@Service +@RequiredArgsConstructor +public class PullRequestsServiceImpl implements PullRequestsService { + + private final PullRequestsRepository pullRequestsRepository; + + @Override + public Set existsById(@NonNull Set idList) { + return idList.stream() + .filter(pullRequestsRepository::existsById) + .collect(Collectors.toSet()); + } + + @Override + public Set existsAllById(@NonNull Set pullRequestJsonId) { + return pullRequestJsonId.stream().filter(pullRequestsRepository::existsById).collect(Collectors.toSet()); + } + + @Override + public List addAll(Set pullRequests) { + return pullRequestsRepository.saveAll(pullRequests); + } + + @Override + @Transactional + public Optional addReviewer(@NonNull Long pullRequestId, @NonNull List reviewers) { + final Optional optPullRequest = pullRequestsRepository.findById(pullRequestId); + if (optPullRequest.isPresent()) { + final PullRequest pullRequest = optPullRequest.get(); + pullRequest.setReviewers(reviewers); + return Optional.of(pullRequestsRepository.save(pullRequest)); + } + return Optional.empty(); + } + +} diff --git a/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java b/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..26d48b7 --- /dev/null +++ b/src/main/java/com/tsc/bitbucketbot/service/impl/UserServiceImpl.java @@ -0,0 +1,69 @@ +package com.tsc.bitbucketbot.service.impl; + +import com.tsc.bitbucketbot.domain.entity.User; +import com.tsc.bitbucketbot.repository.UserRepository; +import com.tsc.bitbucketbot.service.UserService; +import lombok.NonNull; +import lombok.RequiredArgsConstructor; +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 [30.01.2020] + */ +@Service +@RequiredArgsConstructor +public class UserServiceImpl implements UserService { + + private final UserRepository userRepository; + + @Override + public boolean existsByTelegramId(@NonNull Long chatId) { + return userRepository.existsByTelegramId(chatId); + } + + @Override + public User add(@NonNull User user) { + return userRepository.save(user); + } + + @Override + public List getAll() { + return userRepository.findAll(); + } + + @Override + public Optional getByLogin(String login) { + return userRepository.findById(login); + } + + @Override + public Optional update(User user) { + if (userRepository.existsById(user.getLogin())) { + return Optional.of(userRepository.save(user)); + } + return Optional.empty(); + } + + @Override + public Set existsByLogin(@NonNull Set logins) { + return logins.stream().filter(userRepository::existsById).collect(Collectors.toSet()); + } + + @Override + public List addAll(@NonNull Set users) { + return userRepository.saveAll(users); + } + + @Override + public List getAllRegistered() { + return userRepository.findAllRegistered(); + } + +} diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml new file mode 100644 index 0000000..1310325 --- /dev/null +++ b/src/main/resources/application.yaml @@ -0,0 +1,32 @@ +spring: + datasource: + url: jdbc:postgresql://localhost:5432/bitbucket_bot + username: postgres + driver-class-name: org.postgresql.Driver + password: + liquibase: + change-log: classpath:liquibase/change-log.xml + jpa: + show-sql: false + hibernate: + ddl-auto: none + database-platform: org.hibernate.dialect.PostgreSQLDialect + properties: + hibernate: + jdbc: + lob: + non_contextual_creation: true +bitbucketbot: + panel: + password: mnbyNie832r + telegram: + bot-username: bitbucket_sadtech_bot + bot-token: 1096235968:AAHvIy_mlZJXiNc9aDQWtCuiksz9YGknoXE + admin-chatid: 3000811 + proxy-config: + host: 54.39.16.26 + port: 62509 + type: SOCKS5 + bitbucket: + token: Nzg5NjUyNDQwMzk2OlA+6naQz02+GxOG0Q9li/jnsn7E + url: http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=50 diff --git a/src/main/resources/liquibase/change-log.xml b/src/main/resources/liquibase/change-log.xml new file mode 100644 index 0000000..6f02b49 --- /dev/null +++ b/src/main/resources/liquibase/change-log.xml @@ -0,0 +1,8 @@ + + + + + \ 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 new file mode 100644 index 0000000..845bd95 --- /dev/null +++ b/src/main/resources/liquibase/change-set/create-table.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file