Перейти к основному содержимому

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

· 5 мин. чтения

1. Обзор

Публикация на Reddit — это дерьмовая съемка. Один пост может преуспеть и привлечь много внимания, в то время как другой, может быть, лучший пост вообще не получит любви. Как насчет того, чтобы следить за этими сообщениями на раннем этапе и, если они не получают достаточного внимания, быстро удалять их и отправлять повторно ?

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

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

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

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

Итак, мы добавим область « редактирования » в наш ресурс Reddit :

@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<Post, Long> {

List<Post> findBySubmissionDateBeforeAndIsSent(Date date, boolean sent);

List<Post> findByUser(User user);

List<Post> findByRedditIDNotNullAndNoOfAttemptsGreaterThan(int attempts);
}

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

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

@Scheduled(fixedRate = 3 * 60 * 1000)
public void checkAndReSubmitPosts() {
List<Post> 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);
...
}

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

5. Получите оценку публикации Reddit

Теперь давайте посмотрим, как мы можем получить текущую оценку поста с 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;
}

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

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

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

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

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

7. РеддитКонтроллер

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

@RequestMapping(value = "/schedule", method = RequestMethod.POST)
public String schedule(Model model,
@RequestParam Map<String, String> 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. Пользовательский интерфейс — настройка правил

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

<label class="col-sm-3">Resubmit Settings</label>

<label>Number of Attempts</label>
<select name="attempt">
<option value="0" selected>None</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>

<label>Time interval</label>
<select name="interval">
<option value="0" selected >None</option>
<option value="45">45 minutes</option>
<option value="60">1 hour</option>
<option value="120">2 hours</option>
</select>

<label>Min score</label>
<input type="number"value="0" name="score" required/>

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

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