Вроде все работает

This commit is contained in:
upagge 2020-09-13 20:04:16 +03:00
parent 9289957723
commit 121b19f8bc
No known key found for this signature in database
GPG Key ID: 15CD012E46F6BA34
23 changed files with 430 additions and 105 deletions

View File

@ -42,6 +42,9 @@ public class Comment {
@Column(name = "author_login") @Column(name = "author_login")
private String author; private String author;
@Column(name = "responsible_login")
private String responsible;
@Column(name = "message") @Column(name = "message")
private String message; private String message;

View File

@ -5,17 +5,19 @@ import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import org.sadtech.bot.bitbucketbot.domain.TaskStatus; import org.sadtech.bot.bitbucketbot.domain.TaskStatus;
import javax.persistence.CollectionTable;
import javax.persistence.Column; import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.EnumType; import javax.persistence.EnumType;
import javax.persistence.Enumerated; import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinTable; import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table; import javax.persistence.Table;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.HashSet;
import java.util.List; import java.util.Set;
@Entity @Entity
@Getter @Getter
@ -66,8 +68,9 @@ public class Task {
@Column(name = "responsible_login") @Column(name = "responsible_login")
private String responsible; private String responsible;
@JoinTable @ElementCollection(fetch = FetchType.EAGER)
@OneToMany @CollectionTable(name = "task_comments", joinColumns = @JoinColumn(name = "task_id"))
private List<Comment> comments = new ArrayList<>(); @Column(name = "comment_id")
private Set<Long> answers = new HashSet<>();
} }

View File

@ -26,4 +26,8 @@ public class CommentJson {
@JsonDeserialize(using = LocalDateTimeFromEpochDeserializer.class) @JsonDeserialize(using = LocalDateTimeFromEpochDeserializer.class)
private LocalDateTime updatedDate; private LocalDateTime updatedDate;
private Long customPullRequestId;
private String customCommentApiUrl;
} }

View File

@ -22,4 +22,6 @@ public interface CommentRepository extends SimpleManagerRepository<Comment, Long
List<Comment> findAllById(@NonNull Set<Long> ids); List<Comment> findAllById(@NonNull Set<Long> ids);
Set<Long> existsById(Set<Long> ids);
} }

View File

@ -3,10 +3,14 @@ package org.sadtech.bot.bitbucketbot.repository;
import org.sadtech.basic.context.repository.SimpleManagerRepository; import org.sadtech.basic.context.repository.SimpleManagerRepository;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface TaskRepository extends SimpleManagerRepository<Task, Long> { public interface TaskRepository extends SimpleManagerRepository<Task, Long> {
Optional<Task> findFirstByOrderByIdDesc(); Optional<Task> findFirstByOrderByIdDesc();
List<Task> findByCreateDateBetween(LocalDateTime dateFrom, LocalDateTime dateTo);
} }

View File

@ -42,4 +42,9 @@ public class CommentRepositoryImpl extends AbstractSimpleManagerRepository<Comme
return repositoryJpa.findAllById(ids); return repositoryJpa.findAllById(ids);
} }
@Override
public Set<Long> existsById(Set<Long> ids) {
return repositoryJpa.existsAllById(ids);
}
} }

View File

@ -6,6 +6,8 @@ import org.sadtech.bot.bitbucketbot.repository.TaskRepository;
import org.sadtech.bot.bitbucketbot.repository.jpa.TaskRepositoryJpa; import org.sadtech.bot.bitbucketbot.repository.jpa.TaskRepositoryJpa;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional; import java.util.Optional;
@Repository @Repository
@ -23,4 +25,9 @@ public class TaskRepositoryImpl extends AbstractSimpleManagerRepository<Task, Lo
return taskRepositoryJpa.findFirstByOrderByIdDesc(); return taskRepositoryJpa.findFirstByOrderByIdDesc();
} }
@Override
public List<Task> findByCreateDateBetween(LocalDateTime dateFrom, LocalDateTime dateTo) {
return taskRepositoryJpa.findByCreateDateBetween(dateFrom, dateTo);
}
} }

View File

@ -3,10 +3,12 @@ package org.sadtech.bot.bitbucketbot.repository.jpa;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
public interface CommentRepositoryJpa extends JpaRepository<Comment, Long> { public interface CommentRepositoryJpa extends JpaRepository<Comment, Long> {
@ -14,4 +16,7 @@ public interface CommentRepositoryJpa extends JpaRepository<Comment, Long> {
List<Comment> findByCreateDateBetween(@NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo); List<Comment> findByCreateDateBetween(@NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo);
@Query("SELECT c.id FROM Comment c WHERE c.id IN :ids")
Set<Long> existsAllById(@NonNull Set<Long> ids);
} }

View File

@ -1,12 +1,17 @@
package org.sadtech.bot.bitbucketbot.repository.jpa; package org.sadtech.bot.bitbucketbot.repository.jpa;
import lombok.NonNull;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional; import java.util.Optional;
public interface TaskRepositoryJpa extends JpaRepository<Task, Long> { public interface TaskRepositoryJpa extends JpaRepository<Task, Long> {
Optional<Task> findFirstByOrderByIdDesc(); Optional<Task> findFirstByOrderByIdDesc();
List<Task> findByCreateDateBetween(@NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo);
} }

View File

@ -16,9 +16,14 @@ public class CommentAndTaskScheduler {
commentAndTaskParser.scanNewCommentAndTask(); commentAndTaskParser.scanNewCommentAndTask();
} }
// @Scheduled(cron = "0 */1 * * * *") @Scheduled(cron = "0 */1 * * * *")
public void scanOldComment() { public void scanOldComment() {
commentAndTaskParser.scanOldComment(); commentAndTaskParser.scanOldComment();
} }
@Scheduled(cron = "0 */1 * * * *")
public void scanOldTask() {
commentAndTaskParser.scanOldTask();
}
} }

View File

@ -3,6 +3,7 @@ package org.sadtech.bot.bitbucketbot.service;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.basic.context.service.SimpleManagerService; import org.sadtech.basic.context.service.SimpleManagerService;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@ -16,4 +17,8 @@ public interface CommentService extends SimpleManagerService<Comment, Long> {
List<Comment> getAllById(@NonNull Set<Long> ids); List<Comment> getAllById(@NonNull Set<Long> ids);
Comment convert(@NonNull Task task);
Set<Long> existsById(@NonNull Set<Long> ids);
} }

View File

@ -1,10 +1,19 @@
package org.sadtech.bot.bitbucketbot.service; package org.sadtech.bot.bitbucketbot.service;
import lombok.NonNull;
import org.sadtech.basic.context.service.SimpleManagerService; import org.sadtech.basic.context.service.SimpleManagerService;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import java.time.LocalDateTime;
import java.util.List;
public interface TaskService extends SimpleManagerService<Task, Long> { public interface TaskService extends SimpleManagerService<Task, Long> {
Long getLastTaskId(); Long getLastTaskId();
Task convert(@NonNull Comment comment);
List<Task> getAllBetweenDate(@NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo);
} }

View File

@ -3,28 +3,26 @@ package org.sadtech.bot.bitbucketbot.service.converter;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity; import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Component @Component
public class ResultScanToComment implements Converter<ResultScan, Comment> { public class CommentJsonToComment implements Converter<CommentJson, Comment> {
@Override @Override
public Comment convert(ResultScan resultScan) { public Comment convert(CommentJson source) {
final CommentJson commentJson = resultScan.getCommentJson();
final Comment comment = new Comment(); final Comment comment = new Comment();
comment.setId(commentJson.getId()); comment.setId(source.getId());
comment.setCreateDate(commentJson.getCreatedDate()); comment.setCreateDate(source.getCreatedDate());
comment.setAuthor(commentJson.getAuthor().getName()); comment.setAuthor(source.getAuthor().getName());
comment.setPullRequestId(resultScan.getPullRequestId()); comment.setPullRequestId(source.getCustomPullRequestId());
comment.setMessage(commentJson.getText()); comment.setMessage(source.getText());
comment.setUrlApi(resultScan.getCommentApiUrl()); comment.setUrlApi(source.getCustomCommentApiUrl());
comment.setBitbucketVersion(commentJson.getVersion()); comment.setBitbucketVersion(source.getVersion());
comment.setAnswers( comment.setAnswers(
commentJson.getComments().stream() source.getComments().stream()
.filter(json -> Severity.NORMAL.equals(json.getSeverity())) .filter(json -> Severity.NORMAL.equals(json.getSeverity()))
.map(CommentJson::getId) .map(CommentJson::getId)
.collect(Collectors.toSet()) .collect(Collectors.toSet())

View File

@ -5,25 +5,32 @@ import org.sadtech.bot.bitbucketbot.domain.TaskStatus;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentState; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentState;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan; import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity;
import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.stream.Collectors;
@Component @Component
public class ResultScanToTaskConvert implements Converter<ResultScan, Task> { public class CommentJsonToTaskConvert implements Converter<CommentJson, Task> {
@Override @Override
public Task convert(ResultScan resultScan) { public Task convert(CommentJson source) {
final CommentJson json = resultScan.getCommentJson();
final Task task = new Task(); final Task task = new Task();
task.setId(json.getId()); task.setId(source.getId());
task.setAuthor(json.getAuthor().getName()); task.setAuthor(source.getAuthor().getName());
task.setDescription(json.getText()); task.setDescription(source.getText());
task.setCreateDate(json.getCreatedDate()); task.setCreateDate(source.getCreatedDate());
task.setBitbucketVersion(json.getVersion()); task.setBitbucketVersion(source.getVersion());
task.setPullRequestId(resultScan.getPullRequestId()); task.setPullRequestId(source.getCustomPullRequestId());
task.setStatus(convertState(json.getState())); task.setStatus(convertState(source.getState()));
task.setUrlApi(resultScan.getCommentApiUrl()); task.setUrlApi(source.getCustomCommentApiUrl());
task.setAnswers(
source.getComments().stream()
.filter(json -> Severity.NORMAL.equals(json.getSeverity()))
.map(CommentJson::getId)
.collect(Collectors.toSet())
);
return task; return task;
} }

View File

@ -0,0 +1,34 @@
package org.sadtech.bot.bitbucketbot.service.converter;
import org.sadtech.bot.bitbucketbot.domain.TaskStatus;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* // TODO: 12.09.2020 Добавить описание.
*
* @author upagge 12.09.2020
*/
@Component
public class CommentToTaskConvert implements Converter<Comment, Task> {
@Override
public Task convert(Comment source) {
final Task task = new Task();
task.setId(source.getId());
task.setUrl(source.getUrl());
task.setUrlApi(source.getUrlApi());
task.setResponsible(source.getResponsible());
task.setStatus(TaskStatus.OPEN);
task.setPullRequestId(source.getPullRequestId());
task.setBitbucketVersion(source.getBitbucketVersion());
task.setCreateDate(source.getCreateDate());
task.setDescription(source.getMessage());
task.setAuthor(source.getAuthor());
task.setAnswers(source.getAnswers());
return task;
}
}

View File

@ -0,0 +1,32 @@
package org.sadtech.bot.bitbucketbot.service.converter;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
/**
* // TODO: 12.09.2020 Добавить описание.
*
* @author upagge 12.09.2020
*/
@Component
public class TaskToCommentConvert implements Converter<Task, Comment> {
@Override
public Comment convert(Task source) {
final Comment comment = new Comment();
comment.setId(source.getId());
comment.setUrl(source.getUrl());
comment.setUrlApi(source.getUrlApi());
comment.setPullRequestId(source.getPullRequestId());
comment.setBitbucketVersion(source.getBitbucketVersion());
comment.setCreateDate(source.getCreateDate());
comment.setMessage(source.getDescription());
comment.setResponsible(source.getResponsible());
comment.setAuthor(source.getAuthor());
comment.setAnswers(source.getAnswers());
return comment;
}
}

View File

@ -8,19 +8,20 @@ import java.util.Optional;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
@RequiredArgsConstructor @RequiredArgsConstructor
public class Seeker implements Callable<Optional<ResultScan>> { public class Seeker implements Callable<Optional<CommentJson>> {
private final DataScan dataScan; private final DataScan dataScan;
private final String token; private final String token;
@Override @Override
public Optional<ResultScan> call() { public Optional<CommentJson> call() {
return Utils.urlToJson(dataScan.getUrlComment(), token, CommentJson.class) return Utils.urlToJson(dataScan.getUrlComment(), token, CommentJson.class)
.map( .map(
commentJson -> new ResultScan( commentJson -> {
dataScan.getUrlComment(), commentJson.setCustomPullRequestId(dataScan.getPullRequestId());
dataScan.getPullRequestId(), commentJson.setCustomCommentApiUrl(dataScan.getUrlComment());
commentJson) return commentJson;
}
); );
} }

View File

@ -2,21 +2,29 @@ package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.basic.core.service.AbstractSimpleManagerService; import org.sadtech.basic.core.service.AbstractSimpleManagerService;
import org.sadtech.bot.bitbucketbot.domain.Answer;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange; import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.exception.NotFoundException; import org.sadtech.bot.bitbucketbot.exception.NotFoundException;
import org.sadtech.bot.bitbucketbot.repository.CommentRepository; import org.sadtech.bot.bitbucketbot.repository.CommentRepository;
import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.CommentService; import org.sadtech.bot.bitbucketbot.service.CommentService;
import org.sadtech.bot.bitbucketbot.service.PersonService; import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.TaskService;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Service @Service
public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Long> implements CommentService { public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Long> implements CommentService {
@ -26,12 +34,23 @@ public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Lo
private final CommentRepository commentRepository; private final CommentRepository commentRepository;
private final PersonService personService; private final PersonService personService;
private final ChangeService changeService; private final ChangeService changeService;
private final TaskService taskService;
public CommentServiceImpl(CommentRepository commentRepository, PersonService personService, ChangeService changeService) { private final ConversionService conversionService;
public CommentServiceImpl(
CommentRepository commentRepository,
PersonService personService,
ChangeService changeService,
@Lazy TaskService taskService,
ConversionService conversionService
) {
super(commentRepository); super(commentRepository);
this.personService = personService; this.personService = personService;
this.commentRepository = commentRepository; this.commentRepository = commentRepository;
this.changeService = changeService; this.changeService = changeService;
this.taskService = taskService;
this.conversionService = conversionService;
} }
@Override @Override
@ -78,10 +97,10 @@ public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Lo
if (oldComment.getBitbucketVersion().equals(comment.getBitbucketVersion())) { if (oldComment.getBitbucketVersion().equals(comment.getBitbucketVersion())) {
oldComment.setBitbucketVersion(comment.getBitbucketVersion()); oldComment.setBitbucketVersion(comment.getBitbucketVersion());
oldComment.setMessage(oldComment.getMessage()); oldComment.setMessage(oldComment.getMessage());
return commentRepository.save(oldComment);
} }
updateAnswer(oldComment, comment);
return oldComment; return commentRepository.save(oldComment);
} }
@Override @Override
@ -89,4 +108,45 @@ public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Lo
return commentRepository.findAllById(ids); return commentRepository.findAllById(ids);
} }
@Override
public Comment convert(@NonNull Task task) {
taskService.deleteById(task.getId());
final Comment comment = conversionService.convert(task, Comment.class);
final Comment newComment = commentRepository.save(comment);
notificationPersonal(newComment);
return newComment;
}
@Override
public Set<Long> existsById(@NonNull Set<Long> ids) {
return commentRepository.existsById(ids);
}
private void updateAnswer(Comment oldComment, Comment newComment) {
final Set<Long> oldAnswerIds = oldComment.getAnswers();
final Set<Long> newAnswerIds = newComment.getAnswers();
if (!newAnswerIds.isEmpty()) {
final Set<Long> existsNewAnswersIds = commentRepository.existsById(newAnswerIds);
final List<Comment> newAnswers = commentRepository.findAllById(existsNewAnswersIds).stream()
.filter(comment -> !oldAnswerIds.contains(comment.getId()))
.collect(Collectors.toList());
oldComment.getAnswers().clear();
oldComment.setAnswers(existsNewAnswersIds);
changeService.save(
AnswerCommentChange.builder()
.telegramIds(
personService.getAllTelegramIdByLogin(Collections.singleton(newComment.getAuthor()))
)
.url(oldComment.getUrl())
.youMessage(newComment.getMessage())
.answers(
newAnswers.stream()
.map(answerComment -> Answer.of(answerComment.getAuthor(), answerComment.getMessage()))
.collect(Collectors.toList())
)
.build()
);
}
}
} }

View File

@ -4,9 +4,9 @@ import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.service.executor.DataScan; import org.sadtech.bot.bitbucketbot.service.executor.DataScan;
import org.sadtech.bot.bitbucketbot.service.executor.Executor; import org.sadtech.bot.bitbucketbot.service.executor.Executor;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
import org.sadtech.bot.bitbucketbot.service.executor.Seeker; import org.sadtech.bot.bitbucketbot.service.executor.Seeker;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -21,10 +21,10 @@ import java.util.stream.Collectors;
@Slf4j @Slf4j
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
public class ExecutorScanner implements Executor<DataScan, ResultScan> { public class ExecutorScanner implements Executor<DataScan, CommentJson> {
private final ExecutorService executorService; private final ExecutorService executorService;
private List<Future<Optional<ResultScan>>> resultList = new ArrayList<>(); private List<Future<Optional<CommentJson>>> resultList = new ArrayList<>();
private final BitbucketProperty bitbucketProperty; private final BitbucketProperty bitbucketProperty;
@Override @Override
@ -39,11 +39,11 @@ public class ExecutorScanner implements Executor<DataScan, ResultScan> {
} }
@Override @Override
public List<ResultScan> getResult() { public List<CommentJson> getResult() {
while (!resultList.stream().allMatch(Future::isDone)) { while (!resultList.stream().allMatch(Future::isDone)) {
} }
final List<ResultScan> result = resultList.stream() final List<CommentJson> result = resultList.stream()
.filter(Future::isDone) .filter(Future::isDone)
.map(this::getResultScan) .map(this::getResultScan)
.filter(Optional::isPresent) .filter(Optional::isPresent)
@ -53,7 +53,7 @@ public class ExecutorScanner implements Executor<DataScan, ResultScan> {
return result; return result;
} }
private Optional<ResultScan> getResultScan(Future<Optional<ResultScan>> test) { private Optional<CommentJson> getResultScan(Future<Optional<CommentJson>> test) {
try { try {
return test.get(); return test.get();
} catch (InterruptedException | ExecutionException e) { } catch (InterruptedException | ExecutionException e) {

View File

@ -3,42 +3,173 @@ package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.basic.core.service.AbstractSimpleManagerService; import org.sadtech.basic.core.service.AbstractSimpleManagerService;
import org.sadtech.basic.core.util.Assert; import org.sadtech.basic.core.util.Assert;
import org.sadtech.bot.bitbucketbot.domain.Answer;
import org.sadtech.bot.bitbucketbot.domain.TaskStatus;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskCloseChange;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskNewChange; import org.sadtech.bot.bitbucketbot.domain.change.task.TaskNewChange;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.exception.NotFoundException; import org.sadtech.bot.bitbucketbot.exception.NotFoundException;
import org.sadtech.bot.bitbucketbot.repository.TaskRepository; import org.sadtech.bot.bitbucketbot.repository.TaskRepository;
import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.CommentService;
import org.sadtech.bot.bitbucketbot.service.PersonService; import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.TaskService; import org.sadtech.bot.bitbucketbot.service.TaskService;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Service @Service
public class TaskServiceImpl extends AbstractSimpleManagerService<Task, Long> implements TaskService { public class TaskServiceImpl extends AbstractSimpleManagerService<Task, Long> implements TaskService {
private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final TaskRepository taskRepository; private final TaskRepository taskRepository;
private final PullRequestsService pullRequestsService; private final PullRequestsService pullRequestsService;
private final ChangeService changeService; private final ChangeService changeService;
private final PersonService personService; private final PersonService personService;
private final CommentService commentService;
public TaskServiceImpl(TaskRepository taskRepository, PullRequestsService pullRequestsService, ChangeService changeService, PersonService personService) { private final ConversionService conversionService;
public TaskServiceImpl(
TaskRepository taskRepository,
PullRequestsService pullRequestsService,
ChangeService changeService,
PersonService personService,
CommentService commentService,
ConversionService conversionService
) {
super(taskRepository); super(taskRepository);
this.taskRepository = taskRepository; this.taskRepository = taskRepository;
this.pullRequestsService = pullRequestsService; this.pullRequestsService = pullRequestsService;
this.changeService = changeService; this.changeService = changeService;
this.personService = personService; this.personService = personService;
this.commentService = commentService;
this.conversionService = conversionService;
} }
@Override @Override
public Task create(@NonNull Task task) { public Task create(@NonNull Task task) {
Assert.isNotNull(task.getId(), "При создании объекта должен быть установлен идентификатор"); Assert.isNotNull(task.getId(), "При создании объекта должен быть установлен идентификатор");
task.getComments().clear(); task.getAnswers().clear();
final Task newTask = taskRepository.save(task); final Task newTask = taskRepository.save(task);
notifyNewTask(task);
notificationPersonal(task);
return newTask;
}
@Override
public Task update(@NonNull Task task) {
final Task oldTask = taskRepository.findById(task.getId())
.orElseThrow(() -> new NotFoundException("Задача не найдена"));
if (!task.getBitbucketVersion().equals(oldTask.getBitbucketVersion())) {
oldTask.setDescription(task.getDescription());
oldTask.setBitbucketVersion(task.getBitbucketVersion());
}
updateAnswer(oldTask, task);
updateStatus(oldTask, task);
oldTask.setStatus(task.getStatus());
return taskRepository.save(oldTask);
}
private void updateStatus(Task oldTask, Task task) {
final TaskStatus oldStatus = oldTask.getStatus();
final TaskStatus newStatus = task.getStatus();
if (!oldStatus.equals(newStatus)) {
switch (newStatus) {
case OPEN:
changeService.save(
TaskNewChange.builder()
.messageTask(task.getDescription())
.authorName(task.getAuthor())
.url(task.getUrl())
.telegramIds(
personService.getAllTelegramIdByLogin(Collections.singleton(task.getResponsible()))
)
.build()
);
break;
case RESOLVED:
changeService.save(
TaskCloseChange.builder()
.messageTask(task.getDescription())
.authorName(task.getAuthor())
.url(task.getUrl())
.telegramIds(
personService.getAllTelegramIdByLogin(Collections.singleton(task.getAuthor()))
)
.build()
);
break;
default:
throw new NotFoundException("Обработчика типа не существует");
}
oldTask.setStatus(newStatus);
}
}
private void updateAnswer(Task oldTask, Task task) {
final Set<Long> oldAnswerIds = oldTask.getAnswers();
final Set<Long> newAnswerIds = task.getAnswers();
if (!newAnswerIds.isEmpty()) {
final Set<Long> existsNewAnswersIds = commentService.existsById(newAnswerIds);
final List<Comment> newAnswers = commentService.getAllById(existsNewAnswersIds).stream()
.filter(comment -> !oldAnswerIds.contains(comment.getId()))
.collect(Collectors.toList());
oldTask.getAnswers().clear();
oldTask.setAnswers(existsNewAnswersIds);
changeService.save(
AnswerCommentChange.builder()
.telegramIds(
personService.getAllTelegramIdByLogin(Collections.singleton(oldTask.getAuthor()))
)
.url(task.getUrl())
.youMessage(oldTask.getDescription())
.answers(
newAnswers.stream()
.map(answerComment -> Answer.of(answerComment.getAuthor(), answerComment.getMessage()))
.collect(Collectors.toList())
)
.build()
);
}
}
@Override
public Long getLastTaskId() {
return taskRepository.findFirstByOrderByIdDesc().map(Task::getId).orElse(0L);
}
@Override
public Task convert(@NonNull Comment comment) {
commentService.deleteById(comment.getId());
final Task task = conversionService.convert(comment, Task.class);
final Task newTask = taskRepository.save(task);
notifyNewTask(newTask);
return newTask;
}
@Override
public List<Task> getAllBetweenDate(@NonNull LocalDateTime dateFrom, @NonNull LocalDateTime dateTo) {
return taskRepository.findByCreateDateBetween(dateFrom, dateTo);
}
private void notifyNewTask(Task task) {
final PullRequest pullRequest = pullRequestsService.getById(task.getPullRequestId()) final PullRequest pullRequest = pullRequestsService.getById(task.getPullRequestId())
.orElseThrow(() -> new NotFoundException("ПР не найден")); .orElseThrow(() -> new NotFoundException("ПР не найден"));
@ -54,20 +185,24 @@ public class TaskServiceImpl extends AbstractSimpleManagerService<Task, Long> im
) )
.build() .build()
); );
return newTask;
} }
@Override private void notificationPersonal(@NonNull Task task) {
public Task update(@NonNull Task task) { Matcher matcher = PATTERN.matcher(task.getDescription());
final Task oldTask = taskRepository.findById(task.getId()).orElseThrow(() -> new NotFoundException("Задача не найдена")); Set<String> recipientsLogins = new HashSet<>();
oldTask.setStatus(task.getStatus()); while (matcher.find()) {
return taskRepository.save(oldTask); final String login = matcher.group(0).replace("@", "");
} recipientsLogins.add(login);
}
@Override final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins);
public Long getLastTaskId() { changeService.save(
return taskRepository.findFirstByOrderByIdDesc().map(Task::getId).orElse(0L); CommentChange.builder()
.authorName(task.getAuthor())
.url(task.getUrl())
.telegramIds(recipientsIds)
.message(task.getDescription())
.build()
);
} }
} }

View File

@ -7,8 +7,6 @@ import org.sadtech.basic.core.page.PaginationImpl;
import org.sadtech.bot.bitbucketbot.config.InitProperty; import org.sadtech.bot.bitbucketbot.config.InitProperty;
import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty; import org.sadtech.bot.bitbucketbot.config.properties.BitbucketProperty;
import org.sadtech.bot.bitbucketbot.config.properties.CommentSchedulerProperty; import org.sadtech.bot.bitbucketbot.config.properties.CommentSchedulerProperty;
import org.sadtech.bot.bitbucketbot.domain.Answer;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.entity.Comment; import org.sadtech.bot.bitbucketbot.domain.entity.Comment;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequestMini; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequestMini;
@ -16,14 +14,11 @@ import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity; import org.sadtech.bot.bitbucketbot.dto.bitbucket.Severity;
import org.sadtech.bot.bitbucketbot.exception.NotFoundException; import org.sadtech.bot.bitbucketbot.exception.NotFoundException;
import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.CommentService; import org.sadtech.bot.bitbucketbot.service.CommentService;
import org.sadtech.bot.bitbucketbot.service.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService; import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.TaskService; import org.sadtech.bot.bitbucketbot.service.TaskService;
import org.sadtech.bot.bitbucketbot.service.Utils; import org.sadtech.bot.bitbucketbot.service.Utils;
import org.sadtech.bot.bitbucketbot.service.executor.DataScan; import org.sadtech.bot.bitbucketbot.service.executor.DataScan;
import org.sadtech.bot.bitbucketbot.service.executor.ResultScan;
import org.sadtech.bot.bitbucketbot.service.impl.ExecutorScanner; import org.sadtech.bot.bitbucketbot.service.impl.ExecutorScanner;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -31,10 +26,8 @@ import org.springframework.stereotype.Component;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -47,8 +40,6 @@ public class CommentAndTaskParser {
private final CommentService commentService; private final CommentService commentService;
private final PullRequestsService pullRequestsService; private final PullRequestsService pullRequestsService;
private final PersonService personService;
private final ChangeService changeService;
private final ExecutorScanner executorScanner; private final ExecutorScanner executorScanner;
private final TaskService taskService; private final TaskService taskService;
private final ConversionService conversionService; private final ConversionService conversionService;
@ -65,7 +56,7 @@ public class CommentAndTaskParser {
do { do {
final List<DataScan> dataScans = generatingLinksToPossibleComments(commentId); final List<DataScan> dataScans = generatingLinksToPossibleComments(commentId);
executorScanner.registration(dataScans); executorScanner.registration(dataScans);
final List<ResultScan> resultScans = executorScanner.getResult(); final List<CommentJson> resultScans = executorScanner.getResult();
if (!resultScans.isEmpty()) { if (!resultScans.isEmpty()) {
final long commentMax = commentService.createAll(getCommentsByResultScan(resultScans)).stream() final long commentMax = commentService.createAll(getCommentsByResultScan(resultScans)).stream()
.mapToLong(Comment::getId) .mapToLong(Comment::getId)
@ -114,23 +105,24 @@ public class CommentAndTaskParser {
return commentUrls; return commentUrls;
} }
private List<Comment> getCommentsByResultScan(List<ResultScan> resultScans) { private List<Comment> getCommentsByResultScan(List<CommentJson> commentJsons) {
return resultScans.stream() return commentJsons.stream()
.filter(resultScan -> Severity.NORMAL.equals(resultScan.getCommentJson().getSeverity())) .filter(json -> Severity.NORMAL.equals(json.getSeverity()))
.map(resultScan -> conversionService.convert(resultScan, Comment.class)) .map(resultScan -> conversionService.convert(resultScan, Comment.class))
.peek( .peek(
comment -> { comment -> {
final PullRequestMini pullRequestMini = pullRequestsService.getMiniInfo(comment.getPullRequestId()) final PullRequestMini pullRequestMini = pullRequestsService.getMiniInfo(comment.getPullRequestId())
.orElseThrow(() -> new NotFoundException("Автор ПР не найден")); .orElseThrow(() -> new NotFoundException("Автор ПР не найден"));
comment.setUrl(generateUrl(comment.getId(), pullRequestMini.getUrl())); comment.setUrl(generateUrl(comment.getId(), pullRequestMini.getUrl()));
comment.setResponsible(pullRequestMini.getAuthorLogin());
} }
) )
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private List<Task> getTaskByResultScan(List<ResultScan> resultScans) { private List<Task> getTaskByResultScan(List<CommentJson> commentJsons) {
return resultScans.stream() return commentJsons.stream()
.filter(commentJson -> Severity.BLOCKER.equals(commentJson.getCommentJson().getSeverity())) .filter(json -> Severity.BLOCKER.equals(json.getSeverity()))
.map(resultScan -> conversionService.convert(resultScan, Task.class)) .map(resultScan -> conversionService.convert(resultScan, Task.class))
.peek( .peek(
task -> { task -> {
@ -156,45 +148,50 @@ public class CommentAndTaskParser {
} }
public void scanOldComment() { public void scanOldComment() {
@NonNull final List<Comment> comments = commentService.getAllBetweenDate( final List<Comment> comments = commentService.getAllBetweenDate(
LocalDateTime.now().minusDays(10), LocalDateTime.now() LocalDateTime.now().minusDays(20), LocalDateTime.now()
); );
for (Comment oldComment : comments) { for (Comment oldComment : comments) {
final Optional<CommentJson> optCommentJson = Utils.urlToJson( final Optional<CommentJson> optCommentJson = Utils.urlToJson(
oldComment.getUrl(), oldComment.getUrlApi(),
bitbucketProperty.getToken(), bitbucketProperty.getToken(),
CommentJson.class CommentJson.class
); );
final Comment newComment = commentService.update(conversionService.convert(oldComment, Comment.class));
if (optCommentJson.isPresent()) { if (optCommentJson.isPresent()) {
final CommentJson commentJson = optCommentJson.get(); final CommentJson json = optCommentJson.get();
notifyNewCommentAnswers(oldComment, newComment); if (Severity.BLOCKER.equals(json.getSeverity())) {
taskService.convert(oldComment);
} else {
final Comment newComment = conversionService.convert(json, Comment.class);
commentService.update(newComment);
}
} else {
commentService.deleteById(oldComment.getId());
} }
} }
} }
private void notifyNewCommentAnswers(Comment oldComment, Comment newComment) { public void scanOldTask() {
final Set<Long> oldAnswerIds = oldComment.getAnswers(); final List<Task> tasks = taskService.getAllBetweenDate(
final Set<Long> newAnswerIds = newComment.getAnswers(); LocalDateTime.now().minusDays(20), LocalDateTime.now()
if (!newAnswerIds.isEmpty()) { );
final List<Comment> newAnswers = commentService.getAllById(newAnswerIds).stream() for (Task oldTask : tasks) {
.filter(comment -> !oldAnswerIds.contains(comment.getId())) final Optional<CommentJson> optCommentJson = Utils.urlToJson(
.collect(Collectors.toList()); oldTask.getUrlApi(),
changeService.save( bitbucketProperty.getToken(),
AnswerCommentChange.builder() CommentJson.class
.telegramIds(
personService.getAllTelegramIdByLogin(Collections.singleton(newComment.getAuthor()))
)
.url(newComment.getPullRequestId().toString())
.youMessage(newComment.getMessage())
.answers(
newAnswers.stream()
.map(answerComment -> Answer.of(answerComment.getAuthor(), answerComment.getMessage()))
.collect(Collectors.toList())
)
.build()
); );
if (optCommentJson.isPresent()) {
final CommentJson json = optCommentJson.get();
if (Severity.NORMAL.equals(json.getSeverity())) {
commentService.convert(oldTask);
} else {
final Task newTask = conversionService.convert(json, Task.class);
taskService.update(newTask);
}
} else {
taskService.deleteById(oldTask.getId());
}
} }
} }

View File

@ -23,7 +23,7 @@ bitbucketbot:
no-comment-count: 20 no-comment-count: 20
comment-count: 100 comment-count: 100
init: init:
start-comment-id: 7796 start-comment-id: 7807
use: false use: false
server-send: server-send:
url: http://188.225.35.149:8080/api/send url: http://188.225.35.149:8080/api/send

View File

@ -101,6 +101,10 @@
<constraints nullable="false" foreignKeyName="task_author_login_person_login" <constraints nullable="false" foreignKeyName="task_author_login_person_login"
references="person(login)" deleteCascade="true"/> references="person(login)" deleteCascade="true"/>
</column> </column>
<column name="responsible_login" type="varchar(64)">
<constraints nullable="false" foreignKeyName="comment_responsible_login_person_login"
references="person(login)" deleteCascade="true"/>
</column>
<column name="pull_request_id" type="integer"> <column name="pull_request_id" type="integer">
<constraints nullable="false" foreignKeyName="comment_pull_request_id_pull_request_id" <constraints nullable="false" foreignKeyName="comment_pull_request_id_pull_request_id"
references="pull_request(id)" deleteCascade="true"/> references="pull_request(id)" deleteCascade="true"/>