Wiederholen Sie die Übermittlung, um einen Beitrag ohne ausreichende Traktion neu zu erstellen

Versuchen Sie erneut, einen Beitrag ohne ausreichende Traktion zu übermitteln, um ihn erneut zu bearbeiten

1. Überblick

Posting to Reddit is a crap shoot. Ein Beitrag kann großartig sein und viel Aufmerksamkeit erregen, während ein anderer, vielleicht besserer Beitrag überhaupt keine Liebe bekommt. Wie wäre es, wenn Sie diese Pfosten frühzeitig im Auge behalten und - wenn sie nicht genügend Traktion erhalten -deleting them quickly and resubmitting them.

In diesem kurzen Artikel setzen wirthe Reddit case study fort, indem wir eine interessante Funktionalität implementieren -delete and resubmit a post if it’s not getting enough attention immediatly.

Das einfache Ziel besteht darin, dem Benutzer zu ermöglichen, zu konfigurieren, wie viele Stimmen bei Reddit ausreichen, um zu berücksichtigen, dass die Post innerhalb eines bestimmten Zeitintervalls genügend Zugkraft erhält, um sie zu belassen.

2. Weitere Reddit-Berechtigungen

Erstens müssen wirask for additional permissions von der Reddit-API entfernen - insbesondere müssen wir Beiträge bearbeiten.

Daher fügen wir unseren RedditResource den Bereich "edit" hinzu:

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

3. Die Entität und das Repository

Fügen wir nun die zusätzlichen Informationen in die EntitätPostein:

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

Die Felder:

  • redditID: Post-ID auf Reddit, die beim Überprüfen der Punktzahl und beim Löschen des Posts verwendet wird

  • noOfAttempts: Maximale Anzahl von Wiederholungsversuchen (Beitrag löschen und erneut senden)

  • timeInterval: Zeitintervall, um zu überprüfen, ob der Pfosten genügend Traktion erhält

  • minScoreRequired: Mindestpunktzahl erforderlich, um es als erfolgreich genug zu betrachten, um es zu verlassen

Als Nächstes fügen wir einige neue Operationen in diePostRepository-Schnittstelle ein, um Beiträge einfach abzurufen, wenn wir sie überprüfen müssen:

public interface PostRepository extends JpaRepository {

    List findBySubmissionDateBeforeAndIsSent(Date date, boolean sent);

    List findByUser(User user);

    List findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
}

4. Eine neue geplante Aufgabe

Definieren Sie nun eine neue Aufgabe - die Aufgabe zum erneuten Senden - im Scheduler:

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

Alle paar Minuten werden lediglich die noch im Spiel befindlichen Posts wiederholt. Wenn sie nicht genügend Traktion erhalten, werden sie gelöscht und erneut gesendet.

Und hier ist die Methode voncheckAndReSubmit():

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

Wir müssen auch dieredditID im Auge behalten, wenn wir sie zum ersten Mal an Reddit senden:

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

Die Logik ist auch hier recht einfach: Wir speichern einfach die ID und verringern den Anzahl der Versuche-Zähler.

5. Holen Sie sich Reddit Post Score

Nun - mal sehen, wie wir die aktuelle Punktzahl des Beitrags von Reddit erhalten können:

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

Beachten Sie, dass:

  • Wir benötigen den Bereich "read", um die Post-Informationen von Reddit abzurufen

  • Wir fügen der reddit-ID "t3_" hinzu, umfull name des Beitrags zu erhalten

6. Löschen Sie den Reddit-Beitrag

Weiter - Mal sehen, wie Reddit-Post mit seiner ID gelöscht wird:

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

Fügen Sie nun die neuen Informationen zum Controller hinzu:

@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. Die Benutzeroberfläche - Konfigurieren Sie die Regeln

Zum Schluss ändern wir unser sehr einfaches Zeitplanformular, um die neuen Einstellungen erneut einzureichen:










9. Fazit

Wir verbessern weiter, was diese einfache App kann - wir können jetzt auf Reddit posten und - wenn der Post nicht schnell genug Traktion bekommt - das System ihn löschen und erneut posten lassen, um ihm eine bessere Chance zu geben durchführen.