From 611adbfb4d891267490584c1f0569eb9ba2a88e0 Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Thu, 18 Apr 2019 14:22:57 +0100 Subject: [PATCH] Add bot that automatically tweets some things Signed-off-by: Michael Tremer --- Makefile.am | 1 + src/backend/base.py | 6 ++++ src/backend/blog.py | 12 +++++++ src/backend/tweets.py | 78 ++++++++++++++++++++++++++++++++++++++++++ src/crontab/ipfire.org | 3 ++ 5 files changed, 100 insertions(+) create mode 100644 src/backend/tweets.py diff --git a/Makefile.am b/Makefile.am index 5150e96e..4f147c57 100644 --- a/Makefile.am +++ b/Makefile.am @@ -67,6 +67,7 @@ backend_PYTHON = \ src/backend/releases.py \ src/backend/settings.py \ src/backend/talk.py \ + src/backend/tweets.py \ src/backend/util.py \ src/backend/wiki.py \ src/backend/zeiterfassung.py diff --git a/src/backend/base.py b/src/backend/base.py index 86e34611..6c79d8bf 100644 --- a/src/backend/base.py +++ b/src/backend/base.py @@ -18,6 +18,7 @@ from . import nopaste from . import releases from . import settings from . import talk +from . import tweets from . import wiki from . import zeiterfassung from .decorators import * @@ -92,6 +93,7 @@ class Backend(object): "cleanup-messages" : self.messages.queue.cleanup, "scan-files" : self.releases.scan_files, "send-all-messages" : self.messages.queue.send_all, + "tweet" : self.tweets.tweet, "update-blog-feeds" : self.blog.update_feeds, } @@ -111,3 +113,7 @@ class Backend(object): @lazy_property def messages(self): return messages.Messages(self) + + @lazy_property + def tweets(self): + return tweets.Tweets(self) diff --git a/src/backend/blog.py b/src/backend/blog.py index de2b8b69..e79dd308 100644 --- a/src/backend/blog.py +++ b/src/backend/blog.py @@ -98,6 +98,18 @@ class Blog(misc.Object): ORDER BY ts_rank(search_index.document, to_tsquery('english', %s)) DESC \ LIMIT %s", query, query, limit) + def has_had_recent_activity(self, t=None): + if t is None: + t = datetime.timedelta(hours=24) + + res = self.db.get("SELECT COUNT(*) AS count FROM blog \ + WHERE published_at IS NOT NULL AND published_at >= NOW() - %s", t) + + if res and res.count > 0: + return True + + return False + def create_post(self, title, text, author, tags=[], lang="markdown"): """ Creates a new post and returns the resulting Post object diff --git a/src/backend/tweets.py b/src/backend/tweets.py new file mode 100644 index 00000000..514581af --- /dev/null +++ b/src/backend/tweets.py @@ -0,0 +1,78 @@ +#!/usr/bin/python3 + +import datetime +import logging +import tornado.gen +import twython + +from .misc import Object + +class Tweets(Object): + @tornado.gen.coroutine + def tweet(self): + """ + Sends a random promotional tweet + """ + # Do not tweet too often + if self.has_had_recent_activity(): + logging.debug("Won't tweet because we recently did it") + return + + # Do not tweet when there was a blog post + if self.backend.blog.has_had_recent_activity(): + logging.debug("Won't tweet because the blog has had activity") + return + + # Select a tweet + tweet = self._get_random_tweet() + if not tweet: + logging.warning("Could not find anything to tweet") + return + + # Tweet the tweet + with self.db.transaction(): + self._tweet(tweet) + + def has_had_recent_activity(self, t=None): + if t is None: + t = datetime.timedelta(days=3) + + res = self.db.get("SELECT COUNT(*) AS count FROM tweets \ + WHERE last_tweeted_at IS NOT NULL AND last_tweeted_at >= NOW() - %s", t) + + if res and res.count > 0: + return True + + return False + + def _get_random_tweet(self): + res = self.db.get( + "WITH candidate_tweets AS (SELECT id, \ + (CURRENT_TIMESTAMP - COALESCE(last_tweeted_at, '1970-01-01')) * RANDOM() AS age \ + FROM tweets \ + WHERE (last_tweeted_at IS NULL OR last_tweeted_at <= CURRENT_TIMESTAMP - INTERVAL '1 month') \ + ) \ + SELECT tweets.* FROM candidate_tweets \ + LEFT JOIN tweets ON candidate_tweets.id = tweets.id \ + ORDER BY age DESC LIMIT 1") + + return res + + def _tweet(self, tweet): + logging.info("Tweeting: %s" % tweet.message) + + # Update database status + self.db.execute("UPDATE tweets \ + SET last_tweeted_at = CURRENT_TIMESTAMP, total_tweets = total_tweets + 1 \ + WHERE id = %s", tweet.id) + + # Connect to twitter + twitter = twython.Twython( + self.settings.get("twitter_consumer_key"), + self.settings.get("twitter_consumer_secret"), + self.settings.get("twitter_%s_access_token" % tweet.account), + self.settings.get("twitter_%s_access_token_secret" % tweet.account), + ) + + # Update status + twitter.update_status(status=tweet.message) diff --git a/src/crontab/ipfire.org b/src/crontab/ipfire.org index f4d8a5b8..b5b74598 100644 --- a/src/crontab/ipfire.org +++ b/src/crontab/ipfire.org @@ -12,3 +12,6 @@ # Check mirrors once every 30 min */30 * * * * nobody ipfire.org check-mirrors + +# Tweet once a week +0 8 * * * nobody sleep ${RANDOM} && ipfire.org tweet -- 2.47.3