Новые уведомления на ответы комментарии
This commit is contained in:
parent
d50af456a1
commit
da8c0bb706
@ -13,7 +13,7 @@ public class AppConfig {
|
||||
@Bean
|
||||
public TaskScheduler taskScheduler() {
|
||||
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
|
||||
taskScheduler.setPoolSize(6);
|
||||
taskScheduler.setPoolSize(7);
|
||||
return taskScheduler;
|
||||
}
|
||||
|
||||
|
@ -4,11 +4,6 @@ import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* TODO: Добавить описание класса.
|
||||
*
|
||||
* @author upagge [03.02.2020]
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class Pagination {
|
||||
|
@ -0,0 +1,50 @@
|
||||
package com.tsc.bitbucketbot.domain.entity;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.ElementCollection;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.JoinColumn;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Set;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Builder
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = "id")
|
||||
@ToString
|
||||
public class Comment {
|
||||
|
||||
@Id
|
||||
@Column(name = "id")
|
||||
// @GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "url")
|
||||
private String url;
|
||||
|
||||
@Column(name = "telegram")
|
||||
private Long telegram;
|
||||
|
||||
@Column(name = "date")
|
||||
private LocalDate date;
|
||||
|
||||
@ElementCollection(fetch = FetchType.EAGER)
|
||||
@CollectionTable(name = "comment_tree", joinColumns = @JoinColumn(name = "parent_id"))
|
||||
@Column(name = "child_id")
|
||||
private Set<Long> answers;
|
||||
|
||||
}
|
@ -5,6 +5,7 @@ import com.tsc.bitbucketbot.utils.LocalDateFromEpochDeserializer;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CommentJson {
|
||||
@ -12,6 +13,7 @@ public class CommentJson {
|
||||
private Long id;
|
||||
private String text;
|
||||
private UserJson author;
|
||||
private List<CommentJson> comments;
|
||||
|
||||
@JsonDeserialize(using = LocalDateFromEpochDeserializer.class)
|
||||
private LocalDate createdDate;
|
||||
|
@ -0,0 +1,16 @@
|
||||
package com.tsc.bitbucketbot.repository.jpa;
|
||||
|
||||
import com.tsc.bitbucketbot.domain.entity.Comment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface CommentRepository extends JpaRepository<Comment, Long> {
|
||||
|
||||
Optional<Comment> findFirstByOrderByIdDesc();
|
||||
|
||||
List<Comment> findByDateBetween(LocalDate dateFrom, LocalDate dateTo);
|
||||
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
package com.tsc.bitbucketbot.repository.jpa;
|
||||
|
||||
import com.tsc.bitbucketbot.domain.entity.TechInfo;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
public interface TechInfoRepository extends JpaRepository<TechInfo, Long> {
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package com.tsc.bitbucketbot.scheduler;
|
||||
import com.tsc.bitbucketbot.config.BitbucketConfig;
|
||||
import com.tsc.bitbucketbot.domain.MessageSend;
|
||||
import com.tsc.bitbucketbot.domain.Pagination;
|
||||
import com.tsc.bitbucketbot.domain.entity.Comment;
|
||||
import com.tsc.bitbucketbot.domain.entity.PullRequest;
|
||||
import com.tsc.bitbucketbot.dto.bitbucket.CommentJson;
|
||||
import com.tsc.bitbucketbot.service.CommentService;
|
||||
@ -18,9 +19,13 @@ import org.springframework.data.domain.Page;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@ -28,7 +33,7 @@ import java.util.regex.Pattern;
|
||||
public class SchedulerComments {
|
||||
|
||||
private static final Integer COUNT = 100;
|
||||
private static final Integer NO_COMMENT = 30;
|
||||
private static final Integer NO_COMMENT = 100;
|
||||
private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
|
||||
|
||||
private final CommentService commentService;
|
||||
@ -39,69 +44,110 @@ public class SchedulerComments {
|
||||
private final BitbucketConfig bitbucketConfig;
|
||||
|
||||
@Scheduled(cron = "0 */5 8-18 * * MON-FRI")
|
||||
public void test() {
|
||||
public void newComments() {
|
||||
log.info("Начало сканирования комментариев");
|
||||
long newLastCommentId = commentService.getLastCommentId();
|
||||
long commentId = newLastCommentId + 1;
|
||||
long commentId = commentService.getLastCommentId() + 1;
|
||||
long count = 0;
|
||||
do {
|
||||
int page = 0;
|
||||
Page<PullRequest> pageRequestSheet = pullRequestsService.getAll(Pagination.of(page++, COUNT));
|
||||
while (pageRequestSheet.hasContent()) {
|
||||
boolean commentSearch = false;
|
||||
for (PullRequest pullRequest : pageRequestSheet.getContent()) {
|
||||
final Optional<CommentJson> commentJson = Utils.urlToJson(
|
||||
getPrUrl(commentId, pullRequest),
|
||||
bitbucketConfig.getToken(),
|
||||
CommentJson.class
|
||||
);
|
||||
if (commentJson.isPresent()) {
|
||||
commentSearch = true;
|
||||
final CommentJson comment = commentJson.get();
|
||||
notification(
|
||||
comment,
|
||||
pullRequest.getName(),
|
||||
bitbucketConfig.getUrlPullRequest()
|
||||
.replace("{projectKey}", pullRequest.getProjectKey())
|
||||
.replace("{repositorySlug}", pullRequest.getRepositorySlug())
|
||||
.replace("{pullRequestId}", pullRequest.getBitbucketId().toString())
|
||||
);
|
||||
newLastCommentId = commentId;
|
||||
Page<PullRequest> pullRequestPage = pullRequestsService.getAll(Pagination.of(page++, COUNT));
|
||||
while (pullRequestPage.hasContent()) {
|
||||
for (PullRequest pullRequest : pullRequestPage.getContent()) {
|
||||
final String commentUrl = getCommentUrl(commentId, pullRequest);
|
||||
final Optional<CommentJson> optCommentJson = Utils.urlToJson(commentUrl, bitbucketConfig.getToken(), CommentJson.class);
|
||||
if (optCommentJson.isPresent()) {
|
||||
final CommentJson commentJson = optCommentJson.get();
|
||||
notification(commentJson, pullRequest);
|
||||
saveComments(commentJson, commentUrl);
|
||||
count = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (commentSearch) {
|
||||
count = 0;
|
||||
break;
|
||||
} else {
|
||||
count++;
|
||||
}
|
||||
pageRequestSheet = pullRequestsService.getAll(Pagination.of(page++, COUNT));
|
||||
pullRequestPage = pullRequestsService.getAll(Pagination.of(page++, COUNT));
|
||||
}
|
||||
count++;
|
||||
commentId += 1;
|
||||
} while (count < NO_COMMENT);
|
||||
commentService.saveLastCommentId(newLastCommentId);
|
||||
log.info("Конец сканирования комментариев");
|
||||
}
|
||||
|
||||
private String getPrUrl(long lastCommentId, PullRequest pullRequest) {
|
||||
@Scheduled(cron = "0 */1 8-18 * * MON-FRI")
|
||||
public void oldComments() {
|
||||
@NonNull final List<Comment> comments = commentService.getAllBetweenDate(LocalDate.now().minusDays(10), LocalDate.now());
|
||||
for (Comment comment : comments) {
|
||||
final Optional<CommentJson> optCommentJson = Utils.urlToJson(
|
||||
comment.getUrl(),
|
||||
bitbucketConfig.getToken(),
|
||||
CommentJson.class
|
||||
);
|
||||
if (optCommentJson.isPresent()) {
|
||||
final CommentJson commentJson = optCommentJson.get();
|
||||
final Set<Long> oldAnswerIds = comment.getAnswers();
|
||||
final List<CommentJson> answerJsons = commentJson.getComments().stream()
|
||||
.filter(answerJson -> !oldAnswerIds.contains(answerJson.getId()))
|
||||
.collect(Collectors.toList());
|
||||
if (!answerJsons.isEmpty()) {
|
||||
userService.getTelegramIdByLogin(commentJson.getAuthor().getName()).ifPresent(
|
||||
telegramAuthorComment -> messageSendService.add(
|
||||
MessageSend.builder()
|
||||
.telegramId(telegramAuthorComment)
|
||||
.message(Message.answerComment(commentJson.getText(), answerJsons))
|
||||
.build()
|
||||
)
|
||||
);
|
||||
comment.getAnswers().addAll(answerJsons.stream().map(CommentJson::getId).collect(Collectors.toList()));
|
||||
commentService.save(comment);
|
||||
}
|
||||
} else {
|
||||
commentService.delete(comment.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private void saveComments(CommentJson comment, String commentUrl) {
|
||||
final Comment newComment = new Comment();
|
||||
newComment.setId(comment.getId());
|
||||
newComment.setDate(LocalDate.now());
|
||||
newComment.setUrl(commentUrl);
|
||||
userService.getTelegramIdByLogin(comment.getAuthor().getName()).ifPresent(newComment::setTelegram);
|
||||
commentService.save(newComment);
|
||||
}
|
||||
|
||||
private String getCommentUrl(long commentId, PullRequest pullRequest) {
|
||||
return bitbucketConfig.getUrlPullRequestComment()
|
||||
.replace("{projectKey}", pullRequest.getProjectKey())
|
||||
.replace("{repositorySlug}", pullRequest.getRepositorySlug())
|
||||
.replace("{pullRequestId}", pullRequest.getBitbucketId().toString())
|
||||
.replace("{commentId}", String.valueOf(lastCommentId));
|
||||
.replace("{commentId}", String.valueOf(commentId));
|
||||
}
|
||||
|
||||
private void notification(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) {
|
||||
final String message = comment.getText();
|
||||
Matcher matcher = PATTERN.matcher(message);
|
||||
private void notification(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) {
|
||||
// notificationAuthorPr(comment, pullRequest);
|
||||
notificationPersonal(comment, pullRequest);
|
||||
}
|
||||
|
||||
private void notificationAuthorPr(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) {
|
||||
final Long authorTelegram = pullRequest.getAuthor().getTelegramId();
|
||||
if (authorTelegram != null) {
|
||||
messageSendService.add(
|
||||
MessageSend.builder()
|
||||
.telegramId(authorTelegram)
|
||||
.message(Message.commentPr(comment, pullRequest.getName(), pullRequest.getUrl()))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void notificationPersonal(@NonNull CommentJson comment, @NonNull PullRequest pullRequest) {
|
||||
Matcher matcher = PATTERN.matcher(comment.getText());
|
||||
while (matcher.find()) {
|
||||
final String login = matcher.group(0).replace("@", "");
|
||||
userService.getTelegramIdByLogin(login).ifPresent(
|
||||
telegramId -> messageSendService.add(
|
||||
MessageSend.builder()
|
||||
.telegramId(telegramId)
|
||||
.message(Message.personalNotify(comment, namePr, urlPr))
|
||||
.message(Message.personalNotify(comment, pullRequest.getName(), pullRequest.getUrl()))
|
||||
.build()
|
||||
)
|
||||
);
|
||||
|
@ -1,11 +1,24 @@
|
||||
package com.tsc.bitbucketbot.service;
|
||||
|
||||
import com.tsc.bitbucketbot.domain.Pagination;
|
||||
import com.tsc.bitbucketbot.domain.entity.Comment;
|
||||
import lombok.NonNull;
|
||||
import org.springframework.data.domain.Page;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface CommentService {
|
||||
|
||||
Long getLastCommentId();
|
||||
|
||||
void saveLastCommentId(@NonNull Long commentId);
|
||||
Page<Comment> getAll(@NonNull Pagination pagination);
|
||||
|
||||
@NonNull
|
||||
List<Comment> getAllBetweenDate(LocalDate dateFrom, LocalDate dateTo);
|
||||
|
||||
void save(@NonNull Comment comment);
|
||||
|
||||
void delete(@NonNull Long id);
|
||||
|
||||
}
|
||||
|
@ -1,29 +1,47 @@
|
||||
package com.tsc.bitbucketbot.service.impl;
|
||||
|
||||
import com.tsc.bitbucketbot.domain.entity.TechInfo;
|
||||
import com.tsc.bitbucketbot.repository.jpa.TechInfoRepository;
|
||||
import com.tsc.bitbucketbot.domain.Pagination;
|
||||
import com.tsc.bitbucketbot.domain.entity.Comment;
|
||||
import com.tsc.bitbucketbot.repository.jpa.CommentRepository;
|
||||
import com.tsc.bitbucketbot.service.CommentService;
|
||||
import lombok.NonNull;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class CommentServiceImpl implements CommentService {
|
||||
|
||||
private final TechInfoRepository techInfoRepository;
|
||||
private final CommentRepository commentRepository;
|
||||
|
||||
@Override
|
||||
public Long getLastCommentId() {
|
||||
final Optional<TechInfo> optLastCommentId = techInfoRepository.findById(1L);
|
||||
return optLastCommentId.isPresent() ? optLastCommentId.get().getLastCommentId() : 0L;
|
||||
return commentRepository.findFirstByOrderByIdDesc().map(Comment::getId).orElse(0L);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveLastCommentId(@NonNull Long commentId) {
|
||||
techInfoRepository.saveAndFlush(new TechInfo(1L, commentId));
|
||||
public Page<Comment> getAll(@NonNull Pagination pagination) {
|
||||
return commentRepository.findAll(PageRequest.of(pagination.getPage(), pagination.getSize()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull List<Comment> getAllBetweenDate(LocalDate dateFrom, LocalDate dateTo) {
|
||||
return commentRepository.findByDateBetween(dateFrom, dateTo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save(@NonNull Comment comment) {
|
||||
commentRepository.save(comment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete(@NonNull Long id) {
|
||||
commentRepository.deleteById(id);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -131,6 +131,35 @@ public class Message {
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String goodWeekEnd() {
|
||||
return "Ну вот и все! Веселых выходных " + Smile.MIG + Smile.BR +
|
||||
"До понедельника" + Smile.BUY + Smile.TWO_BR;
|
||||
}
|
||||
|
||||
public static String commentPr(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) {
|
||||
return Smile.BELL + " *Новый комментарий к ПР*" + Smile.BR +
|
||||
link(namePr, urlPr) +
|
||||
Smile.HR +
|
||||
comment.getAuthor().getName() + ": " + comment.getText().replaceAll("@[\\w]+", "");
|
||||
}
|
||||
|
||||
public static String personalNotify(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) {
|
||||
return Smile.BELL + " *Новое упоминание* | " + comment.getAuthor().getName() + Smile.BR +
|
||||
link(namePr, urlPr) +
|
||||
Smile.HR +
|
||||
comment.getText().replaceAll("@[\\w]+", "");
|
||||
}
|
||||
|
||||
public static String answerComment(@NonNull String commentMessage, @NonNull List<CommentJson> answerJsons) {
|
||||
final StringBuilder message = new StringBuilder();
|
||||
message.append(Smile.BELL).append("Новые ответы на ваш комментарий").append(Smile.HR)
|
||||
.append(commentMessage, 0, Math.min(commentMessage.length(), 180)).append(Smile.HR);
|
||||
answerJsons.forEach(answerJson -> message.append(answerJson.getAuthor().getName()).append(": ")
|
||||
.append(answerJson.getText(), 0, Math.min(answerJson.getText().length(), 500)).append(Smile.TWO_BR));
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
private static String needWorkPr(@NonNull List<PullRequest> pullRequestsNeedWork) {
|
||||
final StringBuilder message = new StringBuilder();
|
||||
pullRequestsNeedWork.stream()
|
||||
@ -157,17 +186,4 @@ public class Message {
|
||||
return "[" + name + "](" + url + ")";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static String goodWeekEnd() {
|
||||
return "Ну вот и все! Веселых выходных " + Smile.MIG + Smile.BR +
|
||||
"До понедельника" + Smile.BUY + Smile.TWO_BR;
|
||||
}
|
||||
|
||||
public static String personalNotify(@NonNull CommentJson comment, @NonNull String namePr, @NonNull String urlPr) {
|
||||
return Smile.BELL + " *Новое упоминание* | " + comment.getAuthor().getName() + Smile.BR +
|
||||
link(namePr, urlPr) +
|
||||
Smile.HR +
|
||||
comment.getText().replaceAll("@[\\w]+", "");
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ spring:
|
||||
liquibase:
|
||||
change-log: classpath:liquibase/change-log.xml
|
||||
jpa:
|
||||
show-sql: true
|
||||
show-sql: false
|
||||
hibernate:
|
||||
ddl-auto: none
|
||||
database-platform: org.hibernate.dialect.PostgreSQLDialect
|
||||
|
@ -6,5 +6,6 @@
|
||||
<include file="liquibase/change-set/create-table.xml"/>
|
||||
<include file="liquibase/change-set/v1.2.0.xml"/>
|
||||
<include file="liquibase/change-set/v1.3.0.xml"/>
|
||||
<include file="liquibase/change-set/v1.4.0.xml"/>
|
||||
|
||||
</databaseChangeLog>
|
37
src/main/resources/liquibase/change-set/v1.4.0.xml
Normal file
37
src/main/resources/liquibase/change-set/v1.4.0.xml
Normal file
@ -0,0 +1,37 @@
|
||||
<databaseChangeLog
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||
|
||||
<changeSet id="create-table-comments" author="upagge">
|
||||
<createTable tableName="comment">
|
||||
<column name="id" type="int" autoIncrement="true">
|
||||
<constraints primaryKey="true"/>
|
||||
</column>
|
||||
<column name="url" type="varchar(300)"/>
|
||||
<column name="telegram" type="integer"/>
|
||||
<column name="date" type="datetime"/>
|
||||
</createTable>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="create-table-comment-tree" author="upagge">
|
||||
<createTable tableName="comment_tree">
|
||||
<column name="parent_id" type="int">
|
||||
<constraints foreignKeyName="fk_parent_id_from_comment_id" references="comment(id)" nullable="false"/>
|
||||
</column>
|
||||
<column name="child_id" type="int">
|
||||
<constraints foreignKeyName="fk_child_id_from_comment_id" references="comment(id)" nullable="false"/>
|
||||
</column>
|
||||
</createTable>
|
||||
<addPrimaryKey tableName="comment_tree" columnNames="parent_id, child_id"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="drop-table" author="upagge">
|
||||
<dropTable tableName="tech_info"/>
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="dropForeignKeyConstraint-comment" author="upagge">
|
||||
<dropForeignKeyConstraint baseTableName="comment_tree" constraintName="fk_child_id_from_comment_id"/>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
Loading…
Reference in New Issue
Block a user