Повторите попытку отправить в Reddit сообщение без достаточной тяги

Повторите попытку отправить в Reddit сообщение без достаточной тяги

1. обзор

Posting to Reddit is a crap shoot. Один пост может быть отличным и получить много внимания, а другой, может быть, лучший пост вообще не получит любви. Как насчет того, чтобы следить за этими сообщениями на раннем этапе и - если они не получают достаточной поддержки -deleting them quickly and resubmitting them.

В этой быстрой статье мы продолжаемthe Reddit case study, реализуя интересную функцию -delete and resubmit a post if it’s not getting enough attention immediatly.

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

2. Дополнительные разрешения Reddit

Во-первых, нам понадобитсяask for additional permissions из Reddit API - в частности, нам нужно отредактировать сообщения.

Итак, мы добавим область «edit» в наш RedditResource:

@Bean
public OAuth2ProtectedResourceDetails reddit() {
    AuthorizationCodeResourceDetails details =
      new AuthorizationCodeResourceDetails();
    details.setScope(Arrays.asList("identity", "read", "submit", "edit"));
    ...
}

3. Сущность и репозиторий

А теперь давайте добавим дополнительную информацию в нашу сущностьPost:

@Entity
public class Post {
    ...
    private String redditID;
    private int noOfAttempts;
    private int timeInterval;
    private int minScoreRequired;
}

Поля:

  • redditID: идентификатор сообщения на Reddit, который будет использоваться при проверке оценки и при удалении сообщения.

  • noOfAttempts: максимальное количество попыток повторной отправки (удалите сообщение и отправьте его повторно)

  • timeInterval: интервал времени, чтобы проверить, получает ли сообщение достаточную тягу

  • minScoreRequired: минимальный балл, необходимый, чтобы считать его достаточно успешным, чтобы оставить его.

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

public interface PostRepository extends JpaRepository {

    List findBySubmissionDateBeforeAndIsSent(Date date, boolean sent);

    List findByUser(User user);

    List findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
}

4. Новое запланированное задание

Теперь - давайте определим новую задачу - задачу повторной отправки - в планировщик:

@Scheduled(fixedRate = 3 * 60 * 1000)
public void checkAndReSubmitPosts() {
    List submitted =
      postReopsitory.findByRedditIDNotNullAndNoOfAttemptsGreaterThan(0);
    for (Post post : submitted) {
        checkAndReSubmit(post);
    }
}

Каждые несколько минут он просто перебирает сообщения, которые все еще находятся в разработке, и, если они не получают достаточного внимания, удаляет их и отправляет снова.

А вот методcheckAndReSubmit():

private void checkAndReSubmit(Post post) {
    try {
        checkAndReSubmitInternal(post);
    } catch (final Exception e) {
        logger.error("Error occurred while check post " + post.toString(), e);
    }
}
private void checkAndReSubmitInternal(Post post) {
    if (didIntervalPassed(post.getSubmissionDate(), post.getTimeInterval())) {
        int score = getPostScore(post.getRedditID());
        if (score < post.getMinScoreRequired()) {
            deletePost(post.getRedditID());
            resetPost(post);
        } else {
            post.setNoOfAttempts(0);
            postReopsitory.save(post);
        }
    }
}
private boolean didIntervalPassed(Date submissonDate, int postInterval) {
    long currentTime = new Date().getTime();
    long interval = currentTime - submissonDate.getTime();
    long intervalInMinutes = TimeUnit.MINUTES.convert(interval, TimeUnit.MILLISECONDS);
    return intervalInMinutes > postInterval;
}
private void resetPost(Post post) {
    long time = new Date().getTime();
    time += TimeUnit.MILLISECONDS.convert(post.getTimeInterval(), TimeUnit.MINUTES);
    post.setRedditID(null);
    post.setSubmissionDate(new Date(time));
    post.setSent(false);
    post.setSubmissionResponse("Not sent yet");
    postReopsitory.save(post);
}

Нам также нужно будет отслеживатьredditID при первой отправке на Reddit:

private void submitPostInternal(Post post) {
    ...
    JsonNode node = redditRestTemplate.postForObject(
      "https://oauth.reddit.com/api/submit", param, JsonNode.class);
    JsonNode errorNode = node.get("json").get("errors").get(0);
    if (errorNode == null) {
        post.setRedditID(node.get("json").get("data").get("id").asText());
        post.setNoOfAttempts(post.getNoOfAttempts() - 1);
        ...
}

Логика здесь также довольно проста - мы просто сохраняем идентификатор и уменьшаем количество попыток.

5. Получить рейтинг Reddit Post

Теперь - давайте посмотрим, как мы можем получить текущую оценку публикации на Reddit:

private int getPostScore(String redditId) {
    JsonNode node = redditRestTemplate.getForObject(
      "https://oauth.reddit.com/api/info?id=t3_" + redditId, JsonNode.class);
    int score = node.get("data").get("children").get(0).get("data").get("score").asInt();
    return score;
}

Обратите внимание, что:

  • Нам нужна область «read» при получении информации о записи из Reddit.

  • Мы добавляем «t3_» к идентификатору Reddit, чтобы получитьfull name сообщения.

6. Удалить сообщение Reddit

Далее - давайте посмотрим, как удалить сообщение Reddit, используя его идентификатор:

private void deletePost(String redditId) {
    MultiValueMap param = new LinkedMultiValueMap();
    param.add("id", "t3_" + redditId);
    redditRestTemplate.postForObject(
      "https://oauth.reddit.com/api/del.json", param, JsonNode.class);
}

7. RedditController

А теперь давайте добавим новую информацию в контроллер:

@RequestMapping(value = "/schedule", method = RequestMethod.POST)
public String schedule(Model model,
  @RequestParam Map formParams) throws ParseException {
    Post post = new Post();
    post.setTitle(formParams.get("title"));
    post.setSubreddit(formParams.get("sr"));
    post.setUrl(formParams.get("url"));
    post.setNoOfAttempts(Integer.parseInt(formParams.get("attempt")));
    post.setTimeInterval(Integer.parseInt(formParams.get("interval")));
    post.setMinScoreRequired(Integer.parseInt(formParams.get("score")));
    ....
}

8. Пользовательский интерфейс - настройка правил

Наконец, давайте изменим нашу очень простую форму расписания, чтобы добавить новые настройки повторно:










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

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