Рубрики
Без рубрики

Сохраните историю сообщений Reddit

Значительное улучшение в тематическом исследовании приложения Reddit – мы не отслеживаем полную историю действий для сообщений.

Автор оригинала: baeldung.

1. Обзор

В этой части тематического исследования приложения Reddit мы начнем отслеживать историю попыток отправки сообщения и сделаем статусы более описательными и простыми для понимания.

2. Совершенствование структуры почты

Во-первых, давайте начнем с замены старого статуса строки в сущности Post гораздо более полным списком ответов на отправку, отслеживая гораздо больше информации:

public class Post {
    ...
    @OneToMany(fetch = FetchType.EAGER, mappedBy = "post")
    private List submissionsResponse;
}

Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку:

@Entity
public class SubmissionResponse implements IEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private int attemptNumber;

    private String content;

    private Date submissionDate;

    private Date scoreCheckDate;

    @JsonIgnore
    @ManyToOne
    @JoinColumn(name = "post_id", nullable = false)
    private Post post;

    public SubmissionResponse(int attemptNumber, String content, Post post) {
        super();
        this.attemptNumber = attemptNumber;
        this.content = content;
        this.submissionDate = new Date();
        this.post = post;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("Attempt No ").append(attemptNumber).append(" : ").append(content);
        return builder.toString();
    }
}

Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку:

  • Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку: Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку:
  • Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку: Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку:

Далее, давайте посмотрим, что мы на самом деле отслеживаем в этой новой сущности ответа на отправку:

public interface SubmissionResponseRepository extends JpaRepository {

    SubmissionResponse findOneByPostAndAttemptNumber(Post post, int attemptNumber);
}

3. Служба планирования

Теперь нам нужно начать изменять уровень обслуживания, чтобы отслеживать эту дополнительную информацию.

Сначала мы убедимся, что у нас есть хорошо отформатированные причины успеха или неудачи, по которым сообщение считалось успешным или неудачным:

private final static String SCORE_TEMPLATE = "score %d %s minimum score %d";
private final static String TOTAL_VOTES_TEMPLATE = "total votes %d %s minimum total votes %d";

protected String getFailReason(Post post, PostScores postScores) { 
    StringBuilder builder = new StringBuilder(); 
    builder.append("Failed because "); 
    builder.append(String.format(
      SCORE_TEMPLATE, postScores.getScore(), "<", post.getMinScoreRequired())); 
    
    if (post.getMinTotalVotes() > 0) { 
        builder.append(" and "); 
        builder.append(String.format(TOTAL_VOTES_TEMPLATE, 
          postScores.getTotalVotes(), "<", post.getMinTotalVotes()));
    } 
    if (post.isKeepIfHasComments()) { 
        builder.append(" and has no comments"); 
    } 
    return builder.toString(); 
}

protected String getSuccessReason(Post post, PostScores postScores) {
    StringBuilder builder = new StringBuilder(); 
    if (postScores.getScore() >= post.getMinScoreRequired()) { 
        builder.append("Succeed because "); 
        builder.append(String.format(SCORE_TEMPLATE, 
          postScores.getScore(), ">=", post.getMinScoreRequired())); 
        return builder.toString(); 
    } 
    if (
      (post.getMinTotalVotes() > 0) && 
      (postScores.getTotalVotes() >= post.getMinTotalVotes())
    ) { 
        builder.append("Succeed because "); 
        builder.append(String.format(TOTAL_VOTES_TEMPLATE, 
          postScores.getTotalVotes(), ">=", post.getMinTotalVotes()));
        return builder.toString(); 
    } 
    return "Succeed because has comments"; 
}

Теперь мы улучшим старую логику и будем отслеживать эту дополнительную историческую информацию :

private void submitPost(...) {
    ...
    if (errorNode == null) {
        post.setSubmissionsResponse(addAttemptResponse(post, "Submitted to Reddit"));
        ...
    } else {
        post.setSubmissionsResponse(addAttemptResponse(post, errorNode.toString()));
        ...
    }
}
private void checkAndReSubmit(Post post) {
    if (didIntervalPass(...)) {
        PostScores postScores = getPostScores(post);
        if (didPostGoalFail(post, postScores)) {
            ...
            resetPost(post, getFailReason(post, postScores));
        } else {
            ...
            updateLastAttemptResponse(
              post, "Post reached target score successfully " + 
                getSuccessReason(post, postScores));
        }
    }
}
private void checkAndDeleteInternal(Post post) {
    if (didIntervalPass(...)) {
        PostScores postScores = getPostScores(post);
        if (didPostGoalFail(post, postScores)) {
            updateLastAttemptResponse(post, 
              "Deleted from reddit, consumed all attempts without reaching score " + 
                getFailReason(post, postScores));
            ...
        } else {
            updateLastAttemptResponse(post, 
              "Post reached target score successfully " + 
                getSuccessReason(post, postScores));
            ...
        }
    }
}
private void resetPost(Post post, String failReason) {
    ...
    updateLastAttemptResponse(post, "Deleted from Reddit, to be resubmitted " + failReason);
    ...
}

Обратите внимание, что методы более низкого уровня на самом деле делают:

  • add Attempt Response() : создает новую запись Submission Response и добавляет ее в сообщение (вызывается при каждой попытке отправки)
  • обновить ответ на последнюю попытку() : обновить ответ на последнюю попытку (вызывается при проверке оценки поста)

4. Запланированный пост DTO

Затем мы изменим DTO, чтобы убедиться, что эта новая информация будет предоставлена клиенту:

public class ScheduledPostDto {
    ...

    private String status;

    private List detailedStatus;
}

И вот простые Ответы на отправку :

public class SubmissionResponseDto {

    private int attemptNumber;

    private String content;

    private String localSubmissionDate;

    private String localScoreCheckDate;
}

Мы также изменим метод преобразования в нашем Запланированном постконтроллере :

private ScheduledPostDto convertToDto(Post post) {
    ...
    List response = post.getSubmissionsResponse();
    if ((response != null) && (response.size() > 0)) {
        postDto.setStatus(response.get(response.size() - 1).toString().substring(0, 30));
        List responsedto = 
          post.getSubmissionsResponse().stream().
            map(res -> generateResponseDto(res)).collect(Collectors.toList());
        postDto.setDetailedStatus(responsedto);
    } else {
        postDto.setStatus("Not sent yet");
        postDto.setDetailedStatus(Collections.emptyList());
    }
    return postDto;
}

private SubmissionResponseDto generateResponseDto(SubmissionResponse responseEntity) {
    SubmissionResponseDto dto = modelMapper.map(responseEntity, SubmissionResponseDto.class);
    String timezone = userService.getCurrentUser().getPreference().getTimezone();
    dto.setLocalSubmissionDate(responseEntity.getSubmissionDate(), timezone);
    if (responseEntity.getScoreCheckDate() != null) {
        dto.setLocalScoreCheckDate(responseEntity.getScoreCheckDate(), timezone);
    }
    return dto;
}

5. Передний Конец

Затем мы изменим наш интерфейс запланированные сообщения.jsp для обработки нашего нового ответа:



6. Тесты

Наконец, мы проведем простой модульный тест на наших новых методах:

Во-первых, мы проверим реализацию get Success Reason() :

@Test
public void whenHasEnoughScore_thenSucceed() {
    Post post = new Post();
    post.setMinScoreRequired(5);
    PostScores postScores = new PostScores(6, 10, 1);

    assertTrue(getSuccessReason(post, postScores).contains("Succeed because score"));
}

@Test
public void whenHasEnoughTotalVotes_thenSucceed() {
    Post post = new Post();
    post.setMinScoreRequired(5);
    post.setMinTotalVotes(8);
    PostScores postScores = new PostScores(2, 10, 1);

    assertTrue(getSuccessReason(post, postScores).contains("Succeed because total votes"));
}

@Test
public void givenKeepPostIfHasComments_whenHasComments_thenSucceed() {
    Post post = new Post();
    post.setMinScoreRequired(5);
    post.setKeepIfHasComments(true);
    final PostScores postScores = new PostScores(2, 10, 1);

    assertTrue(getSuccessReason(post, postScores).contains("Succeed because has comments"));
}

Далее мы протестируем реализацию getFailReason() :

@Test
public void whenNotEnoughScore_thenFail() {
    Post post = new Post();
    post.setMinScoreRequired(5);
    PostScores postScores = new PostScores(2, 10, 1);

    assertTrue(getFailReason(post, postScores).contains("Failed because score"));
}

@Test
public void whenNotEnoughTotalVotes_thenFail() {
    Post post = new Post();
    post.setMinScoreRequired(5);
    post.setMinTotalVotes(15);
    PostScores postScores = new PostScores(2, 10, 1);

    String reason = getFailReason(post, postScores);
    assertTrue(reason.contains("Failed because score"));
    assertTrue(reason.contains("and total votes"));
}

@Test
public void givenKeepPostIfHasComments_whenNotHasComments_thenFail() {
    Post post = new Post();
    post.setMinScoreRequired(5);
    post.setKeepIfHasComments(true);
    final PostScores postScores = new PostScores(2, 10, 0);

    String reason = getFailReason(post, postScores);
    assertTrue(reason.contains("Failed because score"));
    assertTrue(reason.contains("and has no comments"));
}

7. Заключение

В этом выпуске мы представили некоторые очень полезные сведения о жизненном цикле сообщения Reddit. Теперь мы можем точно видеть, когда сообщение было отправлено и удалено каждый раз, а также точную причину каждой операции.