Réessayer de soumettre à Reddit une publication sans traction suffisante

Réessayer de soumettre pour reddit une publication sans traction suffisante

1. Vue d'ensemble

Posting to Reddit is a crap shoot. Un message peut faire très bien et attirer beaucoup d'attention, tandis qu'un autre, peut-être meilleur, ne recevra aucun amour. Que diriez-vous de garder un œil sur ces messages dès le début et - s'ils ne reçoivent pas assez de traction -deleting them quickly and resubmitting them.

Dans cet article rapide, nous poursuivonsthe Reddit case study en implémentant une fonctionnalité intéressante -delete and resubmit a post if it’s not getting enough attention immediatly.

L’objectif simple est de permettre à l’utilisateur de configurer le nombre de votes sur Reddit pour qu’il soit suffisant de considérer que la poste reçoit suffisamment d’attrait pour le laisser en suspens - dans un certain intervalle de temps.

2. Plus d'autorisations Reddit

Premièrement, nous aurons besoin deask for additional permissions de l'API Reddit - en particulier, nous devons modifier les messages.

Nous allons donc ajouter la portée «edit» à notre RedditResource:

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

3. L'entité et le référentiel

Maintenant, ajoutons les informations supplémentaires dans notre entitéPost:

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

Les champs:

  • redditID: ID de publication sur Reddit, à utiliser lors de la vérification du score et lors de la suppression de la publication

  • noOfAttempts: nombre maximum d'essais de nouvelle soumission (supprimer le message et le renvoyer)

  • timeInterval: Intervalle de temps pour vérifier si le poteau obtient suffisamment de traction

  • minScoreRequired: score minimum requis pour le considérer comme suffisamment réussi pour quitter

Ensuite - ajoutons de nouvelles opérations dans notre interfacePostRepository - afin de récupérer facilement les messages lorsque nous devons les vérifier:

public interface PostRepository extends JpaRepository {

    List findBySubmissionDateBeforeAndIsSent(Date date, boolean sent);

    List findByUser(User user);

    List findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
}

4. Une nouvelle tâche planifiée

Maintenant, définissons une nouvelle tâche - la tâche de re-soumission - dans le planificateur:

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

Toutes les quelques minutes, il s'agit simplement d'itérer les messages qui sont encore en jeu - et, s'ils ne reçoivent pas assez de traction, cela les supprime et les soumet à nouveau.

Et voici la méthodecheckAndReSubmit():

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);
}

Nous devrons également garder une trace desredditID lors de leur première soumission à 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);
        ...
}

La logique est également simple: il suffit de sauvegarder l’id et de diminuer le nombre de tentatives.

5. Obtenez le score de publication Reddit

Voyons maintenant comment nous pouvons obtenir le score actuel du message à partir de 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;
}

Notez que:

  • Nous avons besoin de la portée «read» lors de la récupération des informations de publication depuis Reddit

  • Nous ajoutons «t3_» à l'identifiant reddit pour obtenirfull name du message

6. Supprimer le post Reddit

Ensuite, voyons comment supprimer le post Reddit en utilisant son identifiant:

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. LesRedditController

Maintenant, ajoutons les nouvelles informations au contrôleur:

@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. L'interface utilisateur - Configurer les règles

Enfin, modifions notre formulaire de planification très simple pour ajouter de nouveau les nouveaux paramètres:










9. Conclusion

Nous continuons à améliorer ce que cette application simple peut faire - nous pouvons maintenant publier sur Reddit et - si la publication ne reçoit pas assez de traction rapidement - nous pouvons demander au système de la supprimer et de la re-publier pour lui donner une meilleure chance de performant.