Implement automatic tweeting of news
authorMagnus Hagander <magnus@hagander.net>
Sat, 9 Dec 2017 15:44:54 +0000 (16:44 +0100)
committerMagnus Hagander <magnus@hagander.net>
Sat, 9 Dec 2017 15:46:38 +0000 (16:46 +0100)
Once a twitter account has been registered (using the twitter_register
management command), the twitter_post command wills start posting all
new news to twitter, once they are approved. It will only post news from
the past 7 days to avoid accidentally flooding with old news.

pgweb/news/forms.py
pgweb/news/management/__init__.py [new file with mode: 0644]
pgweb/news/management/commands/__init__.py [new file with mode: 0644]
pgweb/news/management/commands/twitter_post.py [new file with mode: 0644]
pgweb/news/management/commands/twitter_register.py [new file with mode: 0644]
pgweb/news/migrations/0002_news_tweet.py [new file with mode: 0644]
pgweb/news/models.py

index 281a46e0fccd81faee06972a8fd8a7751a5b27aa..6173cc2bbe218bb914782309ffb98b1b8857d43b 100644 (file)
@@ -17,4 +17,4 @@ class NewsArticleForm(forms.ModelForm):
 
        class Meta:
                model = NewsArticle
-               exclude = ('submitter', 'approved', )
+               exclude = ('submitter', 'approved', 'tweeted')
diff --git a/pgweb/news/management/__init__.py b/pgweb/news/management/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pgweb/news/management/commands/__init__.py b/pgweb/news/management/commands/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pgweb/news/management/commands/twitter_post.py b/pgweb/news/management/commands/twitter_post.py
new file mode 100644 (file)
index 0000000..32ffb38
--- /dev/null
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+#
+# Script to post previosly unposted news to twitter
+#
+#
+
+from django.core.management.base import BaseCommand, CommandError
+from django.db import connection, transaction
+from django.conf import settings
+
+from datetime import datetime, timedelta
+import time
+
+from pgweb.news.models import NewsArticle
+
+import requests_oauthlib
+
+class Command(BaseCommand):
+       help = 'Post to twitter'
+
+       def handle(self, *args, **options):
+               curs = connection.cursor()
+               curs.execute("SELECT pg_try_advisory_lock(62387372)")
+               if not curs.fetchall()[0][0]:
+                       raise CommandError("Failed to get advisory lock, existing twitter_post process stuck?")
+
+               articles = list(NewsArticle.objects.filter(tweeted=False, approved=True, date__gt=datetime.now()-timedelta(days=7)).order_by('date'))
+               if not len(articles):
+                       return
+
+               tw = requests_oauthlib.OAuth1Session(settings.TWITTER_CLIENT,
+                                                                                        settings.TWITTER_CLIENTSECRET,
+                                                                                        settings.TWITTER_TOKEN,
+                                                                                        settings.TWITTER_TOKENSECRET)
+
+               for a in articles:
+                       # We hardcode 30 chars for the URL shortener. And then 10 to cover the intro and spacing.
+                       statusstr = u"News: {0} - {1}/about/news/{2}/".format(a.title[:140-40], settings.SITE_ROOT, a.id)
+                       r = tw.post('https://api.twitter.com/1.1/statuses/update.json', data={
+                               'status': statusstr,
+                       })
+                       if r.status_code != 200:
+                               print("Failed to post to twitter: %s " % r)
+                       else:
+                               a.tweeted = True
+                               a.save()
+                       # Don't post more often than once / 30 seconds, to not trigger flooding.
+                       time.sleep(30)
diff --git a/pgweb/news/management/commands/twitter_register.py b/pgweb/news/management/commands/twitter_register.py
new file mode 100644 (file)
index 0000000..46c100d
--- /dev/null
@@ -0,0 +1,43 @@
+#!/usr/bin/env python
+#
+# Script to register twitter oauth privileges
+#
+#
+
+from django.core.management.base import BaseCommand, CommandError
+from django.conf import settings
+
+import requests_oauthlib
+
+class Command(BaseCommand):
+       help = 'Register with twitter oauth'
+
+       def handle(self, *args, **options):
+               if not hasattr(settings, 'TWITTER_CLIENT'):
+                       raise CommandError("TWITTER_CLIENT must be set in settings_local.py")
+               if not hasattr(settings, 'TWITTER_CLIENTSECRET'):
+                       raise CommandError("TWITTER_CLIENTSECRET must be set in settings_local.py")
+               if hasattr(settings, 'TWITTER_TOKEN'):
+                       raise CommandError("TWITTER_TOKEN is already set in settings_local.py")
+               if hasattr(settings, 'TWITTER_TOKENSECRET'):
+                       raise CommandError("TWITTER_TOKENSECRET is already set in settings_local.py")
+
+               # OK, now we're good to go :)
+               oauth = requests_oauthlib.OAuth1Session(settings.TWITTER_CLIENT, settings.TWITTER_CLIENTSECRET)
+               fetch_response = oauth.fetch_request_token('https://api.twitter.com/oauth/request_token')
+
+               authorization_url = oauth.authorization_url('https://api.twitter.com/oauth/authorize')
+               print 'Please go here and authorize: %s' % authorization_url
+
+               pin = raw_input('Paste the PIN here: ')
+
+               oauth = requests_oauthlib.OAuth1Session(settings.TWITTER_CLIENT,
+                                                                                               settings.TWITTER_CLIENTSECRET,
+                                                                                               resource_owner_key=fetch_response.get('oauth_token'),
+                                                                                               resource_owner_secret=fetch_response.get('oauth_token_secret'),
+                                                                                               verifier=pin)
+               oauth_tokens = oauth.fetch_access_token('https://api.twitter.com/oauth/access_token')
+
+               print("Authorized. Please configure:")
+               print("TWITTER_TOKEN='%s'" % oauth_tokens.get('oauth_token'))
+               print("TWITTER_TOKENSECRET='%s'" % oauth_tokens.get('oauth_token_secret'))
diff --git a/pgweb/news/migrations/0002_news_tweet.py b/pgweb/news/migrations/0002_news_tweet.py
new file mode 100644 (file)
index 0000000..c4e3737
--- /dev/null
@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('news', '0001_initial'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='newsarticle',
+            name='tweeted',
+            field=models.BooleanField(default=True),
+        ),
+    ]
index c382356c4547e17fa6ed70117686a852cb771edc..22deee7e0db2b525dba2a2ff23e6746bd8f9812d 100644 (file)
@@ -8,6 +8,7 @@ class NewsArticle(models.Model):
        date = models.DateField(null=False, blank=False, default=date.today)
        title = models.CharField(max_length=200, null=False, blank=False)
        content = models.TextField(null=False, blank=False)
+       tweeted = models.BooleanField(null=False, blank=False, default=False)
 
        send_notification = True
        markdown_fields = ('content',)