Повторите попытку отправить в 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 и - если публикация быстро не набирает обороты - мы можем попросить систему удалить ее и повторно опубликовать, чтобы дать ей больше шансов исполнение.