release-1.0.0

This commit is contained in:
upagge 2020-02-29 01:04:29 +03:00
parent 2739efff32
commit 044305e176
33 changed files with 411 additions and 432 deletions

View File

@ -10,7 +10,7 @@
</parent> </parent>
<groupId>com.tsc.bitbucketbot</groupId> <groupId>com.tsc.bitbucketbot</groupId>
<artifactId>bitbucketbot</artifactId> <artifactId>bitbucketbot</artifactId>
<version>0.0.1-SNAPSHOT</version> <version>1.0.0-RELEASE</version>
<name>bitbucketbot</name> <name>bitbucketbot</name>
<description>Demo project for Spring Boot</description> <description>Demo project for Spring Boot</description>
@ -21,9 +21,8 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.sadtech.telegram</groupId> <groupId>com.squareup.okhttp3</groupId>
<artifactId>telegram-bot</artifactId> <artifactId>okhttp</artifactId>
<version>0.0.1-DEVELOPER</version>
</dependency> </dependency>
<dependency> <dependency>
@ -90,6 +89,7 @@
</dependencies> </dependencies>
<build> <build>
<finalName>bitbucketbot</finalName>
<plugins> <plugins>
<plugin> <plugin>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>

View File

@ -1,99 +1,20 @@
package com.tsc.bitbucketbot.config; 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.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import java.util.Collections;
/**
* TODO: Добавить описание класса.
*
* @author upagge [30.01.2020]
*/
@Configuration @Configuration
@EnableScheduling @EnableScheduling
public class AppConfig { 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<Mail> messageService,
UnitPointerRepository unitPointerRepository
) {
final MessageAutoresponderTelegram messageAutoresponderTelegram = new MessageAutoresponderTelegram(
Collections.singleton(checkMenu),
sending,
messageService,
unitPointerRepository
);
messageAutoresponderTelegram.initSaveAction(new AnswerSaveAction<>());
return messageAutoresponderTelegram;
}
@Bean @Bean
public TaskScheduler taskScheduler() { public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(6); taskScheduler.setPoolSize(5);
return taskScheduler; 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);
}
} }

View File

@ -0,0 +1,8 @@
package com.tsc.bitbucketbot.config;
import java.net.Authenticator;
public class AuthProxy extends Authenticator {
}

View File

@ -15,6 +15,7 @@ import org.springframework.stereotype.Component;
public class BitbucketConfig { public class BitbucketConfig {
private String token; private String token;
private String url; private String urlPullRequestOpen;
private String urlPullRequestClose;
} }

View File

@ -0,0 +1,16 @@
package com.tsc.bitbucketbot.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Getter
@Setter
@Configuration
@ConfigurationProperties(prefix = "bitbucketbot.server-send")
public class PushMessageConfig {
private String url;
}

View File

@ -1,172 +0,0 @@
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<String> authBitbucketPreservable() {
return new LocalPreservable<>();
}
@Bean
public AnswerText entranceText(
AnswerSave<String> saveLogin
) {
return AnswerText.builder()
.boxAnswer(BoxAnswer.of("Пришлите ваш логин в bitbucket. Пример: vpupkin"))
.nextUnit(saveLogin)
.phrase("Войти")
.build();
}
@Bean
public AnswerSave<String> saveLogin(
AnswerText savePasswordText,
Preservable<String> authBitbucketPreservable
) {
return AnswerSave.<String>builder()
.preservable(authBitbucketPreservable)
.key(AuthType.LOGIN.name())
.preservableData(Message::getText)
.nextUnit(savePasswordText)
.build();
}
@Bean
public AnswerText savePasswordText(
AnswerSave<String> savePassword
) {
return AnswerText.builder()
.boxAnswer(BoxAnswer.of("Пришлите ваш пароль в bitbucket. Пример: qwertt123"))
.nextUnit(savePassword)
.build();
}
@Bean
public AnswerSave<String> savePassword(
Preservable<String> authBitbucketPreservable,
AnswerText saveTokenText
) {
return AnswerSave.<String>builder()
.preservable(authBitbucketPreservable)
.key(AuthType.PASSWORD.name())
.preservableData(Message::getText)
.nextUnit(saveTokenText)
.build();
}
@Bean
public AnswerText saveTokenText(
AnswerSave<String> saveToken
) {
return AnswerText.builder()
.boxAnswer(BoxAnswer.of("Пришлите ваш токен в bitbucket.\олучить здесь: http://192.168.236.164:7990/plugins/servlet/access-tokens/manage"))
.nextUnit(saveToken)
.build();
}
@Bean
public AnswerSave<String> saveToken(
Preservable<String> authBitbucketPreservable,
AnswerSave<String> saveTelegramId
) {
return AnswerSave.<String>builder()
.preservable(authBitbucketPreservable)
.key(AuthType.TOKEN.name())
.preservableData(Message::getText)
.nextUnit(saveTelegramId)
.build();
}
@Bean
public AnswerSave<String> saveTelegramId(
Preservable<String> authBitbucketPreservable,
AnswerProcessing<Message> auth
) {
return AnswerSave.<String>builder()
.preservable(authBitbucketPreservable)
.key(AuthType.TELEGRAM_ID.name())
.preservableData(Message::getText)
.hidden(true)
.nextUnit(auth)
.build();
}
@Bean
public AnswerProcessing<Message> auth(
Preservable<String> authBitbucketPreservable,
UserService userService
) {
return AnswerProcessing.builder()
.processingData(message -> {
final Optional<String> optLogin = authBitbucketPreservable.getByKey(message.getPersonId(), AuthType.LOGIN.name());
final Optional<String> optPassword = authBitbucketPreservable.getByKey(message.getPersonId(), AuthType.PASSWORD.name());
final Optional<String> 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());
} else {
return BoxAnswer.of("Вероятно превышено количество попыток входа. Необходимо в браузере выйти из своего аккаунта и повторно войти");
}
} 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<User> 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("Необходимо либо создать пр, либо быть ревьювером текущего ПР, чтобы пройти регистрацию");
}
}
}

View File

@ -1,59 +0,0 @@
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.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,
AnswerText menu,
AnswerText generalMenu
) {
return AnswerCheck.builder()
.check(message -> !userService.existsByTelegramId(message.getPersonId()))
.unitTrue(menu)
.unitFalse(generalMenu)
.build();
}
@Bean
public AnswerText menu(
MainUnit entranceText
) {
return AnswerText.builder()
.boxAnswer(
BoxAnswer.builder()
.message("Привет. Я помогаю сотрудникам ТСК отслеживать события в Bitbucket.")
.keyBoard(KeyBoards.verticalMenuString("Войти"))
.build()
)
.nextUnit(entranceText)
.build();
}
@Bean
public AnswerText generalMenu() {
return AnswerText.builder()
.boxAnswer(
BoxAnswer.builder()
.message("Привет. Ты уже авторизован. Возможно тут появятся новые фичи... Но это не точно\о вопросам функциональности бота пиши сюда: @upagge")
.build()
)
.build();
}
}

View File

@ -0,0 +1,28 @@
package com.tsc.bitbucketbot.controller;
import com.tsc.bitbucketbot.domain.entity.User;
import com.tsc.bitbucketbot.dto.UserDto;
import com.tsc.bitbucketbot.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.core.convert.ConversionService;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
@RestController
@RequiredArgsConstructor
public class UserController {
private final UserService userService;
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));
return HttpStatus.OK;
}
}

View File

@ -1,17 +0,0 @@
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;
}

View File

@ -0,0 +1,27 @@
package com.tsc.bitbucketbot.domain;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.Setter;
@NoArgsConstructor
@Builder
@AllArgsConstructor
@Getter
@Setter
@EqualsAndHashCode(of = "id")
public class MessageSend {
private Long id;
@NonNull
private Long telegramId;
@NonNull
private String message;
}

View File

@ -10,11 +10,8 @@ import lombok.ToString;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.Table; import javax.persistence.Table;
import java.io.Serializable;
/** /**
* TODO: Добавить описание класса. * TODO: Добавить описание класса.
@ -36,9 +33,6 @@ public class User {
@Column(name = "login") @Column(name = "login")
private String login; private String login;
@Column(name = "name")
private String name;
@Column(name = "token") @Column(name = "token")
private String token; private String token;

View File

@ -0,0 +1,14 @@
package com.tsc.bitbucketbot.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UserDto {
private Long telegramId;
private String login;
private String token;
}

View File

@ -0,0 +1,9 @@
package com.tsc.bitbucketbot.exception;
class BitbucketBotException extends RuntimeException {
BitbucketBotException(String message) {
super(message);
}
}

View File

@ -0,0 +1,9 @@
package com.tsc.bitbucketbot.exception;
public class RegException extends BitbucketBotException {
public RegException(String message) {
super(message);
}
}

View File

@ -0,0 +1,17 @@
package com.tsc.bitbucketbot.repository;
import com.tsc.bitbucketbot.domain.MessageSend;
import lombok.NonNull;
import java.util.Collection;
import java.util.List;
public interface MessageSendRepository {
void add(@NonNull MessageSend messageSend);
List<MessageSend> getAll();
void deleteAll(@NonNull Collection<MessageSend> messageSends);
}

View File

@ -0,0 +1,34 @@
package com.tsc.bitbucketbot.repository.impl;
import com.tsc.bitbucketbot.domain.MessageSend;
import com.tsc.bitbucketbot.repository.MessageSendRepository;
import lombok.NonNull;
import org.springframework.stereotype.Repository;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@Repository
public class MessageSendRepositoryImpl implements MessageSendRepository {
private List<MessageSend> messageSends = new ArrayList<>();
private Long count = 1L;
@Override
public void add(@NonNull MessageSend messageSend) {
messageSend.setId(count++);
messageSends.add(messageSend);
}
@Override
public List<MessageSend> getAll() {
return new ArrayList<>(messageSends);
}
@Override
public void deleteAll(@NonNull Collection<MessageSend> messageSends) {
this.messageSends.removeAll(messageSends);
}
}

View File

@ -1,4 +1,4 @@
package com.tsc.bitbucketbot.repository; package com.tsc.bitbucketbot.repository.jpa;
import com.tsc.bitbucketbot.domain.entity.PullRequest; import com.tsc.bitbucketbot.domain.entity.PullRequest;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;

View File

@ -1,12 +1,9 @@
package com.tsc.bitbucketbot.repository; package com.tsc.bitbucketbot.repository.jpa;
import com.tsc.bitbucketbot.domain.entity.User; import com.tsc.bitbucketbot.domain.entity.User;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.util.List;
/** /**
* TODO: Добавить описание класса. * TODO: Добавить описание класса.
* *
@ -17,7 +14,6 @@ public interface UserRepository extends JpaRepository<User, String> {
boolean existsByTelegramId(Long chatId); boolean existsByTelegramId(Long chatId);
@Query("SELECT u FROM User u WHERE u.telegramId IS NOT NULL AND u.token IS NOT NULL") boolean existsByLogin(String login);
List<User> findAllRegistered();
} }

View File

@ -1,24 +0,0 @@
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();
}
}

View File

@ -3,22 +3,22 @@ package com.tsc.bitbucketbot.scheduler;
import com.tsc.bitbucketbot.bitbucket.PullRequestJson; import com.tsc.bitbucketbot.bitbucket.PullRequestJson;
import com.tsc.bitbucketbot.bitbucket.sheet.PullRequestSheetJson; import com.tsc.bitbucketbot.bitbucket.sheet.PullRequestSheetJson;
import com.tsc.bitbucketbot.config.BitbucketConfig; import com.tsc.bitbucketbot.config.BitbucketConfig;
import com.tsc.bitbucketbot.domain.MessageSend;
import com.tsc.bitbucketbot.domain.PullRequestStatus; import com.tsc.bitbucketbot.domain.PullRequestStatus;
import com.tsc.bitbucketbot.domain.ReviewerStatus; import com.tsc.bitbucketbot.domain.ReviewerStatus;
import com.tsc.bitbucketbot.domain.entity.PullRequest; import com.tsc.bitbucketbot.domain.entity.PullRequest;
import com.tsc.bitbucketbot.domain.entity.Reviewer; import com.tsc.bitbucketbot.domain.entity.Reviewer;
import com.tsc.bitbucketbot.domain.entity.User; import com.tsc.bitbucketbot.domain.entity.User;
import com.tsc.bitbucketbot.domain.util.ReviewerChange; import com.tsc.bitbucketbot.domain.util.ReviewerChange;
import com.tsc.bitbucketbot.service.MessageSendService;
import com.tsc.bitbucketbot.service.PullRequestsService; import com.tsc.bitbucketbot.service.PullRequestsService;
import com.tsc.bitbucketbot.service.UserService; import com.tsc.bitbucketbot.service.UserService;
import com.tsc.bitbucketbot.service.Utils; import com.tsc.bitbucketbot.service.Utils;
import com.tsc.bitbucketbot.service.converter.PullRequestJsonConverter; import com.tsc.bitbucketbot.service.converter.PullRequestJsonConverter;
import com.tsc.bitbucketbot.utils.Message; import com.tsc.bitbucketbot.utils.Message;
import javafx.util.Pair; import com.tsc.bitbucketbot.utils.Pair;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; 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.core.convert.ConversionService;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -41,19 +41,17 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class SchedulerPullRequest { public class SchedulerPullRequest {
private static final String URL_OPEN_PR = "http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=150&state=OPEN";
private static final String URL_CLOSE_PR = "http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=150&closedSince=86400";
private final BitbucketConfig bitbucketConfig;
private final PullRequestsService pullRequestsService; private final PullRequestsService pullRequestsService;
private final UserService userService; private final UserService userService;
private final MessageSendService messageSendService;
private final ConversionService conversionService; private final ConversionService conversionService;
private final Sending sending; private final BitbucketConfig bitbucketConfig;
@Scheduled(fixedRate = 15000) @Scheduled(fixedRate = 30000)
public void checkClosePullRequest() { public void checkClosePullRequest() {
final List<User> users = userService.getAllRegistered(); final List<User> users = userService.getAll();
for (User user : users) { for (User user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(URL_CLOSE_PR, user.getToken(), PullRequestSheetJson.class); Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) {
final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get(); final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get();
final List<PullRequestJson> bitbucketPullRequests = pullRequestBitbucketSheet.getValues().stream() final List<PullRequestJson> bitbucketPullRequests = pullRequestBitbucketSheet.getValues().stream()
@ -83,7 +81,7 @@ public class SchedulerPullRequest {
if (telegramId != null) { if (telegramId != null) {
final PullRequestStatus pullRequestStatus = PullRequestJsonConverter.convertPullRequestStatus(bitbucketPullRequest.getState()); final PullRequestStatus pullRequestStatus = PullRequestJsonConverter.convertPullRequestStatus(bitbucketPullRequest.getState());
@NonNull final String message = Message.statusPullRequest(bitbucketPullRequest.getTitle(), bitbucketPullRequest.getLinks().getSelf().get(0).getHref(), PullRequestStatus.OPEN, pullRequestStatus); @NonNull final String message = Message.statusPullRequest(bitbucketPullRequest.getTitle(), bitbucketPullRequest.getLinks().getSelf().get(0).getHref(), PullRequestStatus.OPEN, pullRequestStatus);
sending.send(telegramId, BoxAnswer.of(message)); messageSendService.add(MessageSend.builder().telegramId(telegramId).message(message).build());
} }
} }
} }
@ -91,7 +89,7 @@ public class SchedulerPullRequest {
pullRequestsService.deleteAll(pullRequestId); pullRequestsService.deleteAll(pullRequestId);
if (pullRequestBitbucketSheet.getNextPageStart() != null) { if (pullRequestBitbucketSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(URL_CLOSE_PR + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class);
} else { } else {
break; break;
} }
@ -99,11 +97,11 @@ public class SchedulerPullRequest {
} }
} }
@Scheduled(fixedRate = 15000) @Scheduled(fixedRate = 30000)
public void checkOldPullRequest() { public void checkOldPullRequest() {
final List<User> users = userService.getAllRegistered(); final List<User> users = userService.getAll();
for (User user : users) { for (User user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(URL_OPEN_PR, user.getToken(), PullRequestSheetJson.class); Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) {
final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get(); final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get();
final Map<Long, PullRequest> existsPullRequestBitbucket = pullRequestBitbucketSheet.getValues().stream() final Map<Long, PullRequest> existsPullRequestBitbucket = pullRequestBitbucketSheet.getValues().stream()
@ -123,7 +121,7 @@ public class SchedulerPullRequest {
} }
if (pullRequestBitbucketSheet.getNextPageStart() != null) { if (pullRequestBitbucketSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(URL_CLOSE_PR + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class);
} else { } else {
break; break;
} }
@ -144,7 +142,7 @@ public class SchedulerPullRequest {
final String message = stringBuilder.toString(); final String message = stringBuilder.toString();
if (!Message.EMPTY.equalsIgnoreCase(message)) { if (!Message.EMPTY.equalsIgnoreCase(message)) {
updatePullRequest.add(newPullRequest); updatePullRequest.add(newPullRequest);
sending.send(author.getTelegramId(), BoxAnswer.of(message)); messageSendService.add(MessageSend.builder().message(message).telegramId(author.getTelegramId()).build());
} }
} }
} }
@ -188,11 +186,11 @@ public class SchedulerPullRequest {
} }
@Scheduled(fixedRate = 15000) @Scheduled(fixedRate = 30000)
public void checkNewPullRequest() { public void checkNewPullRequest() {
final List<User> users = userService.getAllRegistered(); final List<User> users = userService.getAll();
for (User user : users) { for (User user : users) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(URL_OPEN_PR, user.getToken(), PullRequestSheetJson.class); Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen(), user.getToken(), PullRequestSheetJson.class);
while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) { while (sheetJson.isPresent() && sheetJson.get().getValues() != null && !sheetJson.get().getValues().isEmpty()) {
final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get(); final PullRequestSheetJson pullRequestBitbucketSheet = sheetJson.get();
final List<PullRequest> newPullRequest = pullRequestBitbucketSheet.getValues().stream() final List<PullRequest> newPullRequest = pullRequestBitbucketSheet.getValues().stream()
@ -205,7 +203,7 @@ public class SchedulerPullRequest {
final List<PullRequest> newPullRequests = pullRequestsService.addAll(newPullRequest); final List<PullRequest> newPullRequests = pullRequestsService.addAll(newPullRequest);
sendNotification(newPullRequests); sendNotification(newPullRequests);
if (pullRequestBitbucketSheet.getNextPageStart() != null) { if (pullRequestBitbucketSheet.getNextPageStart() != null) {
sheetJson = Utils.urlToJson(URL_OPEN_PR + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class); sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestOpen() + pullRequestBitbucketSheet.getNextPageStart(), bitbucketConfig.getToken(), PullRequestSheetJson.class);
} else { } else {
break; break;
} }
@ -221,7 +219,7 @@ public class SchedulerPullRequest {
reviewer -> test(pullRequest, reviewer, map) reviewer -> test(pullRequest, reviewer, map)
) )
); );
map.forEach((key, value) -> sending.send(key, BoxAnswer.of(value.toString()))); map.forEach((key, value) -> messageSendService.add(MessageSend.builder().telegramId(key).message(value.toString()).build()));
} }
} }
@ -235,7 +233,7 @@ public class SchedulerPullRequest {
} }
map.get(telegramId).append("\uD83C\uDF89 *Новый Pull Request*\n") map.get(telegramId).append("\uD83C\uDF89 *Новый Pull Request*\n")
.append("[").append(pullRequest.getName()).append("](").append(pullRequest.getUrl()).append(")\n") .append("[").append(pullRequest.getName()).append("](").append(pullRequest.getUrl()).append(")\n")
.append("\uD83D\uDC68\u200D\uD83D\uDCBB: ").append(pullRequest.getAuthor().getName()) .append("\uD83D\uDC68\u200D\uD83D\uDCBB: ").append(pullRequest.getAuthor().getLogin())
.append("\n-- -- -- -- --\n") .append("\n-- -- -- -- --\n")
.append("\uD83D\uDCCC: ").append("#").append(pullRequest.getAuthor().getLogin()).append(" #pullRequest") .append("\uD83D\uDCCC: ").append("#").append(pullRequest.getAuthor().getLogin()).append(" #pullRequest")
.append("\n\n"); .append("\n\n");

View File

@ -0,0 +1,82 @@
package com.tsc.bitbucketbot.scheduler;
import com.google.gson.Gson;
import com.tsc.bitbucketbot.config.PushMessageConfig;
import com.tsc.bitbucketbot.domain.MessageSend;
import com.tsc.bitbucketbot.service.MessageSendService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Service
@Slf4j
@RequiredArgsConstructor
public class SchedulerPushMessageSend {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private final MessageSendService messageSendService;
private final Gson gson = new Gson();
private final PushMessageConfig pushMessageConfig;
private OkHttpClient client;
@PostConstruct
public void init() {
int proxyPort = 8080;
String proxyHost = "proxy.tsc.ts";
final String username = "internet";
final String password = "123454321";
Authenticator proxyAuthenticator = (route, response) -> {
String credential = Credentials.basic(username, password);
return response.request().newBuilder()
.header("Proxy-Authorization", credential)
.build();
};
client = new OkHttpClient.Builder()
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)))
.proxyAuthenticator(proxyAuthenticator)
.build();
}
@Scheduled(fixedDelay = 15000)
public void sendNewMessage() {
List<MessageSend> pushMessage = messageSendService.getPushMessage();
if (!pushMessage.isEmpty()) {
sendMessage(gson.toJson(pushMessage));
}
}
private void sendMessage(String json) {
RequestBody body = RequestBody.create(JSON, json);
Request request = new Request.Builder()
.url(pushMessageConfig.getUrl())
.post(body)
.build();
try {
client.newCall(request).execute();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}

View File

@ -0,0 +1,14 @@
package com.tsc.bitbucketbot.service;
import com.tsc.bitbucketbot.domain.MessageSend;
import lombok.NonNull;
import java.util.List;
public interface MessageSendService {
void add(@NonNull MessageSend messageSend);
List<MessageSend> getPushMessage();
}

View File

@ -14,10 +14,6 @@ import java.util.Set;
*/ */
public interface UserService { public interface UserService {
boolean existsByTelegramId(@NonNull final Long chatId);
User add(@NonNull final User user);
List<User> getAll(); List<User> getAll();
Optional<User> getByLogin(String login); Optional<User> getByLogin(String login);
@ -26,8 +22,8 @@ public interface UserService {
Set<String> existsByLogin(@NonNull Set<String> logins); Set<String> existsByLogin(@NonNull Set<String> logins);
List<User> addAll(@NonNull Set<User> users); Optional<User> reg(@NonNull User user);
List<User> getAllRegistered(); List<User> addAll(Set<User> newUsers);
} }

View File

@ -72,7 +72,7 @@ public class PullRequestJsonConverter implements Converter<PullRequestJson, Pull
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
public static ReviewerStatus convertStatusReviewer(UserPullRequestStatus status) { private static ReviewerStatus convertStatusReviewer(UserPullRequestStatus status) {
switch (status) { switch (status) {
case APPROVED: case APPROVED:
return ReviewerStatus.APPROVED; return ReviewerStatus.APPROVED;
@ -84,5 +84,4 @@ public class PullRequestJsonConverter implements Converter<PullRequestJson, Pull
return null; return null;
} }
} }

View File

@ -0,0 +1,20 @@
package com.tsc.bitbucketbot.service.converter;
import com.tsc.bitbucketbot.domain.entity.User;
import com.tsc.bitbucketbot.dto.UserDto;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
@Component
public class UserDtoConverter implements Converter<UserDto, User> {
@Override
public User convert(UserDto source) {
return User.builder()
.login(source.getLogin())
.token(source.getToken())
.telegramId(source.getTelegramId())
.build();
}
}

View File

@ -16,7 +16,6 @@ public class UserJsonConverter implements Converter<UserJson, User> {
@Override @Override
public User convert(UserJson source) { public User convert(UserJson source) {
return User.builder() return User.builder()
.name(source.getDisplayName())
.login(source.getName()) .login(source.getName())
.build(); .build();
} }

View File

@ -0,0 +1,30 @@
package com.tsc.bitbucketbot.service.impl;
import com.tsc.bitbucketbot.domain.MessageSend;
import com.tsc.bitbucketbot.repository.MessageSendRepository;
import com.tsc.bitbucketbot.service.MessageSendService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
@RequiredArgsConstructor
public class MessageSendServiceImpl implements MessageSendService {
private final MessageSendRepository messageSendRepository;
@Override
public void add(@NonNull MessageSend messageSend) {
messageSendRepository.add(messageSend);
}
@Override
public List<MessageSend> getPushMessage() {
List<MessageSend> newMessages = messageSendRepository.getAll();
messageSendRepository.deleteAll(newMessages);
return newMessages;
}
}

View File

@ -1,7 +1,7 @@
package com.tsc.bitbucketbot.service.impl; package com.tsc.bitbucketbot.service.impl;
import com.tsc.bitbucketbot.domain.entity.PullRequest; import com.tsc.bitbucketbot.domain.entity.PullRequest;
import com.tsc.bitbucketbot.repository.PullRequestsRepository; import com.tsc.bitbucketbot.repository.jpa.PullRequestsRepository;
import com.tsc.bitbucketbot.service.PullRequestsService; import com.tsc.bitbucketbot.service.PullRequestsService;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View File

@ -1,8 +1,12 @@
package com.tsc.bitbucketbot.service.impl; package com.tsc.bitbucketbot.service.impl;
import com.tsc.bitbucketbot.bitbucket.sheet.PullRequestSheetJson;
import com.tsc.bitbucketbot.config.BitbucketConfig;
import com.tsc.bitbucketbot.domain.entity.User; import com.tsc.bitbucketbot.domain.entity.User;
import com.tsc.bitbucketbot.repository.UserRepository; import com.tsc.bitbucketbot.exception.RegException;
import com.tsc.bitbucketbot.repository.jpa.UserRepository;
import com.tsc.bitbucketbot.service.UserService; import com.tsc.bitbucketbot.service.UserService;
import com.tsc.bitbucketbot.service.Utils;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -22,16 +26,7 @@ import java.util.stream.Collectors;
public class UserServiceImpl implements UserService { public class UserServiceImpl implements UserService {
private final UserRepository userRepository; private final UserRepository userRepository;
private final BitbucketConfig bitbucketConfig;
@Override
public boolean existsByTelegramId(@NonNull Long chatId) {
return userRepository.existsByTelegramId(chatId);
}
@Override
public User add(@NonNull User user) {
return userRepository.save(user);
}
@Override @Override
public List<User> getAll() { public List<User> getAll() {
@ -57,13 +52,22 @@ public class UserServiceImpl implements UserService {
} }
@Override @Override
public List<User> addAll(@NonNull Set<User> users) { public Optional<User> reg(@NonNull User user) {
return userRepository.saveAll(users); if (userRepository.existsByLogin(user.getLogin()) && !userRepository.existsByTelegramId(user.getTelegramId())) {
Optional<PullRequestSheetJson> sheetJson = Utils.urlToJson(bitbucketConfig.getUrlPullRequestClose(), user.getToken(), PullRequestSheetJson.class);
if (sheetJson.isPresent()) {
return Optional.of(userRepository.save(user));
} else {
throw new RegException("Ваш токен не валиден");
}
} else {
throw new RegException("Пользователь с таким логином или телеграмом уже есть в системе");
}
} }
@Override @Override
public List<User> getAllRegistered() { public List<User> addAll(Set<User> newUsers) {
return userRepository.findAllRegistered(); return userRepository.saveAll(newUsers);
} }
} }

View File

@ -0,0 +1,19 @@
package com.tsc.bitbucketbot.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* Адаптированная реализация Pair из пакета javafx.util. Реализация необходима, так как в некоторых сборках JDK этот
* пакет может отсутствовать.
*
* @author mstruchkov 21.06.2019
*/
@Data
@AllArgsConstructor
public class Pair<K, V> {
private K key;
private V value;
}

View File

@ -17,16 +17,11 @@ spring:
lob: lob:
non_contextual_creation: true non_contextual_creation: true
bitbucketbot: bitbucketbot:
telegram: server-send:
bot-username: bitbucket_sadtech_bot url: http://193.164.149.25:8080/api/send
bot-token: 1096235968:AAHvIy_mlZJXiNc9aDQWtCuiksz9YGknoXE
admin-chatid: 3000811
proxy-config:
host: 212.237.23.75
port: 1080
type: SOCKS5
user: upagge
password: seAbotd9Bidu%ZqZB3g4
bitbucket: bitbucket:
token: Nzg5NjUyNDQwMzk2OlA+6naQz02+GxOG0Q9li/jnsn7E token: Nzg5NjUyNDQwMzk2OlA+6naQz02+GxOG0Q9li/jnsn7E
url: http://192.168.236.164:7990/rest/api/1.0/dashboard/pull-requests?limit=50 url-pull-request-open: http://localhost:7990/rest/api/1.0/dashboard/pull-requests?limit=150&state=OPEN
url-pull-request-close: http://localhost:7990/rest/api/1.0/dashboard/pull-requests?limit=150&closedSince=86400
server:
port: 8018

View File

@ -8,9 +8,6 @@
<column name="login" type="varchar(50)"> <column name="login" type="varchar(50)">
<constraints primaryKey="true"/> <constraints primaryKey="true"/>
</column> </column>
<column name="name" type="varchar(100)">
<constraints nullable="false"/>
</column>
<column name="token" type="varchar(200)"/> <column name="token" type="varchar(200)"/>
<column name="telegram_id" type="integer"> <column name="telegram_id" type="integer">
<constraints unique="true"/> <constraints unique="true"/>

View File

@ -0,0 +1,24 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{dd.MM.yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{20} - %msg%n</pattern>
</encoder>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>scanner-logs.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>bitbucket.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>10</maxHistory>
<totalSizeCap>50MB</totalSizeCap>
</rollingPolicy>
<encoder>
<pattern>%d{dd.MM.yyyy HH:mm:ss.SSS} [%thread] %-5level %logger{20} - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<!-- <appender-ref ref="STDOUT"/>-->
<appender-ref ref="FILE"/>
</root>
</configuration>