Рефакторинг системы генерации сообщений

This commit is contained in:
upagge 2020-09-10 06:18:18 +03:00
parent f4993776a0
commit d2cd4b62f5
No known key found for this signature in database
GPG Key ID: 15CD012E46F6BA34
21 changed files with 289 additions and 280 deletions

View File

@ -24,4 +24,6 @@ public abstract class Change {
this.telegramIds = telegramIds; this.telegramIds = telegramIds;
} }
public abstract String generateMessage();
} }

View File

@ -6,9 +6,12 @@ import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.Answer; import org.sadtech.bot.bitbucketbot.domain.Answer;
import org.sadtech.bot.bitbucketbot.domain.change.Change; import org.sadtech.bot.bitbucketbot.domain.change.Change;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
@Getter @Getter
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ -31,4 +34,16 @@ public class AnswerCommentChange extends Change {
this.answers = answers; this.answers = answers;
} }
@Override
public String generateMessage() {
final String answerText = answers.stream()
.map(answer -> answer.getAuthorName() + ": " + answer.getMessage().substring(0, Math.min(answer.getMessage().length(), 500)))
.collect(Collectors.joining("\n\n"));
return MessageFormat.format(
"{0} *Новые ответы на ваш комментарий* | [ПР]({1}){2}" +
"{3}{4}" +
"{5}",
Smile.BELL, url, Smile.HR, youMessage.substring(0, Math.min(youMessage.length(), 180)), Smile.HR, answerText
);
}
} }

View File

@ -5,7 +5,9 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.change.Change; import org.sadtech.bot.bitbucketbot.domain.change.Change;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set; import java.util.Set;
@Getter @Getter
@ -29,6 +31,14 @@ public class CommentChange extends Change {
this.url = url; this.url = url;
} }
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Новое упоминание* | [ПР]({1}){2}" +
"{3}: {4}",
Smile.BELL, url, Smile.HR, authorName, message.replaceAll("@[\\w]+", "")
);
}
} }

View File

@ -3,7 +3,9 @@ package org.sadtech.bot.bitbucketbot.domain.change.pullrequest;
import lombok.Builder; import lombok.Builder;
import lombok.Getter; import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set; import java.util.Set;
@Getter @Getter
@ -18,4 +20,13 @@ public class ConflictPrChange extends PrChange {
super(ChangeType.CONFLICT_PR, telegramIds, name, url); super(ChangeType.CONFLICT_PR, telegramIds, name, url);
} }
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Внимание конфликт в ПР*" +
"{1}" +
"[{2}]({3})\n\n",
Smile.DANGEROUS, Smile.HR, title, url
);
}
} }

View File

@ -4,7 +4,9 @@ import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set; import java.util.Set;
@Getter @Getter
@ -26,4 +28,17 @@ public class NewPrChange extends PrChange {
this.author = author; this.author = author;
} }
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Новый Pull Request*\n" +
"[{1}]({2})" +
"{3}\n" +
"{4}" +
"{5}: {6}\n\n",
Smile.FUN, title, url, Smile.HR,
(description != null && !"".equals(description)) ? description + Smile.HR : "",
Smile.AUTHOR, author
);
}
} }

View File

@ -11,8 +11,8 @@ import java.util.Set;
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
public abstract class PrChange extends Change { public abstract class PrChange extends Change {
private final String title; protected final String title;
private final String url; protected final String url;
protected PrChange(ChangeType type, Set<Long> telegramIds, String title, String url) { protected PrChange(ChangeType type, Set<Long> telegramIds, String title, String url) {
super(type, telegramIds); super(type, telegramIds);

View File

@ -5,9 +5,16 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange; import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors;
import static org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange.Type.DELETED;
import static org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange.Type.NEW;
import static org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange.Type.OLD;
@Getter @Getter
@EqualsAndHashCode(callSuper = true) @EqualsAndHashCode(callSuper = true)
@ -25,4 +32,40 @@ public class ReviewersPrChange extends PrChange {
this.reviewerChanges = reviewerChanges; this.reviewerChanges = reviewerChanges;
} }
@Override
public String generateMessage() {
StringBuilder stringBuilder = new StringBuilder();
final Map<ReviewerChange.Type, List<ReviewerChange>> changes = reviewerChanges.stream()
.collect(Collectors.groupingBy(ReviewerChange::getType));
if (changes.containsKey(OLD)) {
stringBuilder.append(Smile.BR).append("Изменили свое решение:").append(Smile.BR);
changes.get(OLD).forEach(
change -> stringBuilder
.append(Smile.AUTHOR).append(change.getName()).append(": ")
.append(change.getOldStatus().getValue()).append(" -> ")
.append(change.getStatus().getValue())
.append(Smile.BR)
);
}
if (changes.containsKey(NEW)) {
stringBuilder.append(Smile.BR).append("Новые ревьюверы:").append(Smile.BR);
changes.get(NEW).forEach(
change -> stringBuilder
.append(change.getName()).append(" (").append(change.getStatus().getValue()).append(")")
.append(Smile.BR)
);
}
if (changes.containsKey(DELETED)) {
stringBuilder.append(Smile.BR).append("Не выдержали ревью:").append(Smile.BR)
.append(
changes.get(DELETED).stream()
.map(ReviewerChange::getName).collect(Collectors.joining(","))
);
}
final String createMessage = stringBuilder.toString();
return Smile.PEN + " *Изменения ревьюверов вашего ПР*" +
Smile.HR +
"[" + title + "](" + url + ")\n" +
createMessage;
}
} }

View File

@ -5,7 +5,9 @@ import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus; import org.sadtech.bot.bitbucketbot.domain.PullRequestStatus;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set; import java.util.Set;
@Getter @Getter
@ -27,4 +29,14 @@ public class StatusPrChange extends PrChange {
this.newStatus = newStatus; this.newStatus = newStatus;
} }
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Изменился статус вашего ПР*{1}" +
"[{2}]({3})\n" +
"{4} -> {5}\n\n",
Smile.PEN, Smile.HR, title, url, oldStatus.name(), newStatus.name()
);
}
} }

View File

@ -4,7 +4,9 @@ import lombok.Builder;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.Getter; import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType; import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set; import java.util.Set;
@Getter @Getter
@ -22,4 +24,15 @@ public class UpdatePrChange extends PrChange {
this.author = author; this.author = author;
} }
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Обновление Pull Request*\n" +
"[{1}]({2})" +
"{3}" +
"{4}: {5}\n\n",
Smile.UPDATE, title, url, Smile.HR, Smile.AUTHOR, author
);
}
} }

View File

@ -0,0 +1,36 @@
package org.sadtech.bot.bitbucketbot.domain.change.task;
import lombok.Builder;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set;
/**
* // TODO: 10.09.2020 Добавить описание.
*
* @author upagge 10.09.2020
*/
public class TaskCloseChange extends TaskChange {
@Builder
protected TaskCloseChange(
Set<Long> telegramIds,
String authorName,
String url,
String messageTask
) {
super(ChangeType.RESOLVED_TASK, telegramIds, authorName, url, messageTask);
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} Задача выполнена* | [ПР]({1}){2}" +
"{3}: {4}",
Smile.TASK, url, Smile.HR, authorName, messageTask
);
}
}

View File

@ -0,0 +1,38 @@
package org.sadtech.bot.bitbucketbot.domain.change.task;
import lombok.Builder;
import lombok.Getter;
import org.sadtech.bot.bitbucketbot.domain.change.ChangeType;
import org.sadtech.bot.bitbucketbot.utils.Smile;
import java.text.MessageFormat;
import java.util.Set;
/**
* // TODO: 10.09.2020 Добавить описание.
*
* @author upagge 10.09.2020
*/
@Getter
public class TaskNewChange extends TaskChange {
@Builder
protected TaskNewChange(
Set<Long> telegramIds,
String authorName,
String url,
String messageTask
) {
super(ChangeType.NEW_TASK, telegramIds, authorName, url, messageTask);
}
@Override
public String generateMessage() {
return MessageFormat.format(
"{0} *Назначена новая задача* | [ПР]({1}){2}" +
"{3}: {4}",
Smile.TASK, url, Smile.HR, authorName, messageTask
);
}
}

View File

@ -10,8 +10,6 @@ import javax.persistence.Column;
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.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.JoinTable; import javax.persistence.JoinTable;
import javax.persistence.OneToMany; import javax.persistence.OneToMany;
@ -32,7 +30,6 @@ public class Task {
@Id @Id
@Column(name = "id") @Column(name = "id")
@EqualsAndHashCode.Include @EqualsAndHashCode.Include
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id; private Long id;
/** /**

View File

@ -1,17 +1,11 @@
package org.sadtech.bot.bitbucketbot.repository; package org.sadtech.bot.bitbucketbot.repository;
import lombok.NonNull; 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.util.Optional; import java.util.Optional;
public interface TaskRepository { public interface TaskRepository extends SimpleManagerRepository<Task, Long> {
Task save(@NonNull Task task);
void deleteById(@NonNull Long id);
Optional<Task> findById(@NonNull Long id);
Optional<Task> findFirstByOrderByIdDesc(); Optional<Task> findFirstByOrderByIdDesc();

View File

@ -1,7 +1,6 @@
package org.sadtech.bot.bitbucketbot.repository.impl; package org.sadtech.bot.bitbucketbot.repository.impl;
import lombok.NonNull; import org.sadtech.basic.database.repository.manager.AbstractSimpleManagerRepository;
import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import org.sadtech.bot.bitbucketbot.repository.TaskRepository; import org.sadtech.bot.bitbucketbot.repository.TaskRepository;
import org.sadtech.bot.bitbucketbot.repository.jpa.TaskRepositoryJpa; import org.sadtech.bot.bitbucketbot.repository.jpa.TaskRepositoryJpa;
@ -10,29 +9,18 @@ import org.springframework.stereotype.Repository;
import java.util.Optional; import java.util.Optional;
@Repository @Repository
@RequiredArgsConstructor public class TaskRepositoryImpl extends AbstractSimpleManagerRepository<Task, Long> implements TaskRepository {
public class TaskRepositoryImpl implements TaskRepository {
private final TaskRepositoryJpa taskRepositoryJpa; private final TaskRepositoryJpa taskRepositoryJpa;
@Override public TaskRepositoryImpl(TaskRepositoryJpa taskRepositoryJpa) {
public Task save(@NonNull Task task) { super(taskRepositoryJpa);
return taskRepositoryJpa.save(task); this.taskRepositoryJpa = taskRepositoryJpa;
}
@Override
public void deleteById(@NonNull Long id) {
taskRepositoryJpa.deleteById(id);
}
@Override
public Optional<Task> findById(@NonNull Long id) {
return taskRepositoryJpa.findById(id);
} }
@Override @Override
public Optional<Task> findFirstByOrderByIdDesc() { public Optional<Task> findFirstByOrderByIdDesc() {
return Optional.empty(); return taskRepositoryJpa.findFirstByOrderByIdDesc();
} }
} }

View File

@ -3,6 +3,10 @@ package org.sadtech.bot.bitbucketbot.repository.jpa;
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.util.Optional;
public interface TaskRepositoryJpa extends JpaRepository<Task, Long> { public interface TaskRepositoryJpa extends JpaRepository<Task, Long> {
Optional<Task> findFirstByOrderByIdDesc();
} }

View File

@ -1,21 +1,10 @@
package org.sadtech.bot.bitbucketbot.scheduler; package org.sadtech.bot.bitbucketbot.scheduler;
import lombok.NonNull;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.sadtech.bot.bitbucketbot.domain.MessageSend; import org.sadtech.bot.bitbucketbot.domain.MessageSend;
import org.sadtech.bot.bitbucketbot.domain.change.Change; import org.sadtech.bot.bitbucketbot.domain.change.Change;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ConflictPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.StatusPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange;
import org.sadtech.bot.bitbucketbot.exception.NotFoundException;
import org.sadtech.bot.bitbucketbot.service.ChangeService; import org.sadtech.bot.bitbucketbot.service.ChangeService;
import org.sadtech.bot.bitbucketbot.service.MessageSendService; import org.sadtech.bot.bitbucketbot.service.MessageSendService;
import org.sadtech.bot.bitbucketbot.utils.Message;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -45,7 +34,7 @@ public class SchedulerChangeParsing {
.filter(change -> change.getTelegramIds() != null && !change.getTelegramIds().isEmpty()) .filter(change -> change.getTelegramIds() != null && !change.getTelegramIds().isEmpty())
.collect(Collectors.toList()); .collect(Collectors.toList());
for (Change change : newChange) { for (Change change : newChange) {
final String message = generateMessage(change); final String message = change.generateMessage();
change.getTelegramIds().forEach( change.getTelegramIds().forEach(
telegramId -> messageSendService.add( telegramId -> messageSendService.add(
MessageSend.builder() MessageSend.builder()
@ -57,50 +46,4 @@ public class SchedulerChangeParsing {
} }
} }
/**
* Создает сообщение, которое необходимо отправить в зависимости от типа изменения.
*
* @param change Объект изменения
* @return Текстовое сообщение
*/
private String generateMessage(@NonNull Change change) {
String message;
switch (change.getType()) {
case NEW_PR:
message = Message.generate(((NewPrChange) change));
break;
case REVIEWERS:
message = Message.generate(((ReviewersPrChange) change));
break;
case STATUS_PR:
message = Message.generate(((StatusPrChange) change));
break;
case UPDATE_PR:
message = Message.generate(((UpdatePrChange) change));
break;
case CONFLICT_PR:
message = Message.generate(((ConflictPrChange) change));
break;
case NEW_COMMENT:
message = Message.generate(((CommentChange) change));
break;
case NEW_ANSWERS_COMMENT:
message = Message.generate(((AnswerCommentChange) change));
break;
case NEW_TASK:
case OPEN_TASK:
message = Message.generateNewTask(((TaskChange) change));
break;
case DELETED_TASK:
message = Message.generateDeleteTask(((TaskChange) change));
break;
case RESOLVED_TASK:
message = Message.generateResolveTask(((TaskChange) change));
break;
default:
throw new NotFoundException("Нет обработчика для типа " + change.getType().name());
}
return message;
}
} }

View File

@ -1,20 +1,9 @@
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.bot.bitbucketbot.domain.entity.Task; import org.sadtech.bot.bitbucketbot.domain.entity.Task;
import java.util.Collection; public interface TaskService extends SimpleManagerService<Task, Long> {
import java.util.List;
public interface TaskService {
Task create(@NonNull Task task);
void deleteById(@NonNull Long id);
Task update(@NonNull Task task);
List<Task> createAll(@NonNull Collection<Task> tasks);
Long getLastTaskId(); Long getLastTaskId();

View File

@ -3,31 +3,37 @@ 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.config.InitProperty; import org.sadtech.bot.bitbucketbot.config.InitProperty;
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.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.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.PullRequestsService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.time.LocalDateTime; import java.time.LocalDateTime;
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.Pattern;
@Service @Service
public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Long> implements CommentService { public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Long> implements CommentService {
private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final CommentRepository commentRepository; private final CommentRepository commentRepository;
private final PersonService personService; private final PersonService personService;
private final PullRequestsService pullRequestsService; private final ChangeService changeService;
private final InitProperty initProperty; private final InitProperty initProperty;
public CommentServiceImpl(CommentRepository commentRepository, PersonService personService, PullRequestsService pullRequestsService, InitProperty initProperty) { public CommentServiceImpl(CommentRepository commentRepository, PersonService personService, ChangeService changeService, InitProperty initProperty) {
super(commentRepository); super(commentRepository);
this.personService = personService; this.personService = personService;
this.commentRepository = commentRepository; this.commentRepository = commentRepository;
this.pullRequestsService = pullRequestsService; this.changeService = changeService;
this.initProperty = initProperty; this.initProperty = initProperty;
} }
@ -47,7 +53,27 @@ public class CommentServiceImpl extends AbstractSimpleManagerService<Comment, Lo
@Override @Override
public Comment create(@NonNull Comment comment) { public Comment create(@NonNull Comment comment) {
return commentRepository.save(comment); final Comment newComment = commentRepository.save(comment);
notificationPersonal(comment);
return newComment;
}
private void notificationPersonal(@NonNull Comment comment) {
Matcher matcher = PATTERN.matcher(comment.getMessage());
Set<String> recipientsLogins = new HashSet<>();
while (matcher.find()) {
final String login = matcher.group(0).replace("@", "");
recipientsLogins.add(login);
}
final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins);
changeService.save(
CommentChange.builder()
.authorName(comment.getAuthor())
.url(comment.getUrl())
.telegramIds(recipientsIds)
.message(comment.getMessage())
.build()
);
} }
@Override @Override

View File

@ -1,35 +1,60 @@
package org.sadtech.bot.bitbucketbot.service.impl; package org.sadtech.bot.bitbucketbot.service.impl;
import lombok.NonNull; import lombok.NonNull;
import lombok.RequiredArgsConstructor; import org.sadtech.basic.core.service.AbstractSimpleManagerService;
import org.sadtech.basic.core.util.Assert;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskNewChange;
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.CreateException;
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.PersonService;
import org.sadtech.bot.bitbucketbot.service.PullRequestsService;
import org.sadtech.bot.bitbucketbot.service.TaskService; import org.sadtech.bot.bitbucketbot.service.TaskService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.Collection; import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor public class TaskServiceImpl extends AbstractSimpleManagerService<Task, Long> implements TaskService {
public class TaskServiceImpl implements TaskService {
private final TaskRepository taskRepository; private final TaskRepository taskRepository;
@Override private final PullRequestsService pullRequestsService;
public Task create(@NonNull Task task) { private final ChangeService changeService;
if (task.getId() == null) { private final PersonService personService;
return taskRepository.save(task);
} public TaskServiceImpl(TaskRepository taskRepository, PullRequestsService pullRequestsService, ChangeService changeService, PersonService personService) {
throw new CreateException("При создании объекта не должно быть идентификатора"); super(taskRepository);
this.taskRepository = taskRepository;
this.pullRequestsService = pullRequestsService;
this.changeService = changeService;
this.personService = personService;
} }
@Override @Override
public void deleteById(@NonNull Long id) { public Task create(@NonNull Task task) {
taskRepository.deleteById(id); Assert.isNotNull(task.getId(), "При создании объекта должен быть установлен идентификатор");
final Task newTask = taskRepository.save(task);
final PullRequest pullRequest = pullRequestsService.getById(task.getPullRequestId())
.orElseThrow(() -> new NotFoundException("ПР не найден"));
changeService.save(
TaskNewChange.builder()
.authorName(task.getAuthor())
.messageTask(task.getDescription())
.url(task.getUrl())
.telegramIds(
personService.getAllTelegramIdByLogin(
Collections.singleton(pullRequest.getAuthorLogin())
)
)
.build()
);
return newTask;
} }
@Override @Override
@ -39,11 +64,6 @@ public class TaskServiceImpl implements TaskService {
return taskRepository.save(oldTask); return taskRepository.save(oldTask);
} }
@Override
public List<Task> createAll(@NonNull Collection<Task> tasks) {
return tasks.stream().map(this::create).collect(Collectors.toList());
}
@Override @Override
public Long getLastTaskId() { public Long getLastTaskId() {
return taskRepository.findFirstByOrderByIdDesc().map(Task::getId).orElse(0L); return taskRepository.findFirstByOrderByIdDesc().map(Task::getId).orElse(0L);

View File

@ -9,7 +9,6 @@ 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.Answer;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange; import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
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.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;
@ -30,12 +29,9 @@ import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -46,8 +42,6 @@ import java.util.stream.Collectors;
@RequiredArgsConstructor @RequiredArgsConstructor
public class CommentAndTaskParser { public class CommentAndTaskParser {
private static final Pattern PATTERN = Pattern.compile("@[\\w]+");
private final CommentService commentService; private final CommentService commentService;
private final PullRequestsService pullRequestsService; private final PullRequestsService pullRequestsService;
private final PersonService personService; private final PersonService personService;
@ -68,8 +62,8 @@ public class CommentAndTaskParser {
executorScanner.registration(dataScans); executorScanner.registration(dataScans);
final List<ResultScan> resultScans = executorScanner.getResult(); final List<ResultScan> resultScans = executorScanner.getResult();
if (!resultScans.isEmpty()) { if (!resultScans.isEmpty()) {
processingComments(resultScans); commentService.createAll(getCommentsByResultScan(resultScans));
processingTasks(resultScans); taskService.createAll(getTaskByResultScan(resultScans));
count = 0; count = 0;
} }
} while (count++ < commentSchedulerProperty.getNoCommentCount()); } while (count++ < commentSchedulerProperty.getNoCommentCount());
@ -83,16 +77,6 @@ public class CommentAndTaskParser {
return commentStartId; return commentStartId;
} }
private void processingComments(List<ResultScan> resultScans) {
final List<Comment> newComments = commentService.createAll(getCommentsByResultScan(resultScans));
newComments.forEach(this::notificationPersonal);
}
private void processingTasks(List<ResultScan> resultScans) {
final List<Task> newTasks = taskService.createAll(getTaskByResultScan(resultScans));
newTasks.forEach(changeService::createTask);
}
private List<DataScan> generatingLinksToPossibleComments(@NonNull Long commentId) { private List<DataScan> generatingLinksToPossibleComments(@NonNull Long commentId) {
List<DataScan> commentUrls = new ArrayList<>(); List<DataScan> commentUrls = new ArrayList<>();
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
@ -141,24 +125,6 @@ public class CommentAndTaskParser {
.replace("{commentId}", String.valueOf(commentId)); .replace("{commentId}", String.valueOf(commentId));
} }
private void notificationPersonal(@NonNull Comment comment) {
Matcher matcher = PATTERN.matcher(comment.getMessage());
Set<String> recipientsLogins = new HashSet<>();
while (matcher.find()) {
final String login = matcher.group(0).replace("@", "");
recipientsLogins.add(login);
}
final Set<Long> recipientsIds = personService.getAllTelegramIdByLogin(recipientsLogins);
changeService.createCommentChange(
CommentChange.builder()
.authorName(comment.getAuthor())
.url(comment.getUrl())
.telegramIds(recipientsIds)
.message(comment.getMessage())
.build()
);
}
public void scanOldComment() { public void scanOldComment() {
@NonNull final List<Comment> comments = commentService.getAllBetweenDate( @NonNull final List<Comment> comments = commentService.getAllBetweenDate(
LocalDateTime.now().minusDays(10), LocalDateTime.now() LocalDateTime.now().minusDays(10), LocalDateTime.now()

View File

@ -1,112 +1,28 @@
package org.sadtech.bot.bitbucketbot.utils; package org.sadtech.bot.bitbucketbot.utils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.NonNull; import lombok.NonNull;
import org.sadtech.bot.bitbucketbot.domain.change.comment.AnswerCommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.comment.CommentChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ConflictPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.NewPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.ReviewersPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.StatusPrChange;
import org.sadtech.bot.bitbucketbot.domain.change.pullrequest.UpdatePrChange;
import org.sadtech.bot.bitbucketbot.domain.change.task.TaskChange;
import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest; import org.sadtech.bot.bitbucketbot.domain.entity.PullRequest;
import org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange;
import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson; import org.sadtech.bot.bitbucketbot.dto.bitbucket.CommentJson;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange.Type.DELETED;
import static org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange.Type.NEW;
import static org.sadtech.bot.bitbucketbot.domain.util.ReviewerChange.Type.OLD;
/** /**
* Генерирует сообщения для отправки. * Генерирует сообщения для отправки.
* *
* @author upagge [07.02.2020] * @author upagge [07.02.2020]
*/ */
public class Message { @NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class Message {
private static final UpdateDataComparator COMPARATOR = new UpdateDataComparator(); private static final UpdateDataComparator COMPARATOR = new UpdateDataComparator();
private static final Integer PR_COUNT = 4; private static final Integer PR_COUNT = 4;
private static final String DONATION_LINK = "https://www.tinkoff.ru/sl/1T9s4esiMf"; private static final String DONATION_LINK = "https://www.tinkoff.ru/sl/1T9s4esiMf";
private static final String HELP_LINK = "https://nuzhnapomosh.ru/about/"; private static final String HELP_LINK = "https://nuzhnapomosh.ru/about/";
private Message() {
throw new IllegalStateException("Утилитарный класс");
}
@NonNull
public static String generate(NewPrChange newPrChange) {
String message = Smile.FUN + " *Новый Pull Request*" + Smile.BR +
link(newPrChange.getTitle(), newPrChange.getUrl()) +
Smile.HR;
if (newPrChange.getDescription() != null && !"".equals(newPrChange.getDescription())) {
message += newPrChange.getDescription() + Smile.HR;
}
message += Smile.AUTHOR + ": " + newPrChange.getAuthor() + Smile.TWO_BR;
return message;
}
public static String generate(@NonNull StatusPrChange change) {
return Smile.PEN + " *Изменился статус вашего ПР*" + Smile.HR +
link(change.getTitle(), change.getUrl()) + Smile.BR +
change.getOldStatus().name() + " -> " + change.getNewStatus().name() +
Smile.TWO_BR;
}
@NonNull
public static String generate(@NonNull ReviewersPrChange reviewersChange) {
StringBuilder stringBuilder = new StringBuilder();
final Map<ReviewerChange.Type, List<ReviewerChange>> changes = reviewersChange.getReviewerChanges().stream()
.collect(Collectors.groupingBy(ReviewerChange::getType));
if (changes.containsKey(OLD)) {
stringBuilder.append(Smile.BR).append("Изменили свое решение:").append(Smile.BR);
changes.get(OLD).forEach(
change -> stringBuilder
.append(Smile.AUTHOR).append(change.getName()).append(": ")
.append(change.getOldStatus().getValue()).append(" -> ")
.append(change.getStatus().getValue())
.append(Smile.BR)
);
}
if (changes.containsKey(NEW)) {
stringBuilder.append(Smile.BR).append("Новые ревьюверы:").append(Smile.BR);
changes.get(NEW).forEach(
change -> stringBuilder
.append(change.getName()).append(" (").append(change.getStatus().getValue()).append(")")
.append(Smile.BR)
);
}
if (changes.containsKey(DELETED)) {
stringBuilder.append(Smile.BR).append("Не выдержали ревью:").append(Smile.BR)
.append(
changes.get(DELETED).stream()
.map(ReviewerChange::getName).collect(Collectors.joining(","))
);
}
final String createMessage = stringBuilder.toString();
return Smile.PEN + " *Изменения ревьюверов вашего ПР*" +
Smile.HR +
link(reviewersChange.getTitle(), reviewersChange.getUrl()) + Smile.BR +
createMessage;
}
public static String generate(@NonNull UpdatePrChange change) {
return Smile.UPDATE + " *Обновление Pull Request*" + Smile.BR +
link(change.getTitle(), change.getUrl()) +
Smile.HR +
Smile.AUTHOR + ": " + change.getAuthor() +
Smile.TWO_BR;
}
public static String generate(@NonNull ConflictPrChange change) {
return Smile.DANGEROUS + "*Внимание конфликт в ПР*" + Smile.HR +
link(change.getTitle(), change.getUrl()) + Smile.TWO_BR;
}
@NonNull @NonNull
public static String goodMorningStatistic(List<PullRequest> pullRequestsReviews, List<PullRequest> pullRequestsNeedWork) { public static String goodMorningStatistic(List<PullRequest> pullRequestsReviews, List<PullRequest> pullRequestsNeedWork) {
StringBuilder message = new StringBuilder().append(Smile.SUN).append(" Доброе утро ").append(Smile.SUN).append(Smile.HR); StringBuilder message = new StringBuilder().append(Smile.SUN).append(" Доброе утро ").append(Smile.SUN).append(Smile.HR);
@ -150,35 +66,6 @@ public class Message {
comment.getAuthor().getName() + ": " + comment.getText().replaceAll("@[\\w]+", ""); comment.getAuthor().getName() + ": " + comment.getText().replaceAll("@[\\w]+", "");
} }
public static String generate(@NonNull CommentChange commentChange) {
return Smile.BELL + " *Новое упоминание* | " + link("ПР", commentChange.getUrl()) + Smile.HR +
commentChange.getAuthorName() + ": " + commentChange.getMessage().replaceAll("@[\\w]+", "");
}
public static String generate(@NonNull AnswerCommentChange answerCommentChange) {
final StringBuilder message = new StringBuilder();
message.append(Smile.BELL).append("Новые ответы на ваш комментарий").append(" | ").append(link("ПР", answerCommentChange.getUrl())).append(Smile.HR)
.append(answerCommentChange.getYouMessage(), 0, Math.min(answerCommentChange.getYouMessage().length(), 180)).append(Smile.HR);
answerCommentChange.getAnswers().forEach(answer -> message.append(answer.getAuthorName()).append(": ")
.append(answer.getMessage(), 0, Math.min(answer.getMessage().length(), 500)).append(Smile.TWO_BR));
return message.toString();
}
public static String generateNewTask(@NonNull TaskChange newTaskChange) {
return Smile.TASK + "*Назначена новая задача* | " + link("ПР", newTaskChange.getUrl()) + Smile.HR +
newTaskChange.getAuthorName() + ": " + newTaskChange.getMessageTask();
}
public static String generateDeleteTask(@NonNull TaskChange deletedTaskChange) {
return Smile.TASK + "*Задача была удалена* | " + link("ПР", deletedTaskChange.getUrl()) + Smile.HR +
deletedTaskChange.getAuthorName() + ": " + deletedTaskChange.getMessageTask();
}
public static String generateResolveTask(@NonNull TaskChange deletedTaskChange) {
return Smile.TASK + "*Задача выполнена* | " + link("ПР", deletedTaskChange.getUrl()) + Smile.HR +
deletedTaskChange.getAuthorName() + ": " + deletedTaskChange.getMessageTask();
}
private static String needWorkPr(@NonNull List<PullRequest> pullRequestsNeedWork) { private static String needWorkPr(@NonNull List<PullRequest> pullRequestsNeedWork) {
final StringBuilder message = new StringBuilder(); final StringBuilder message = new StringBuilder();
pullRequestsNeedWork.stream() pullRequestsNeedWork.stream()