Token refresh

This commit is contained in:
Oleg Lavrovsky 2017-10-13 15:40:24 +02:00
parent 97b4dac813
commit 4f2562cbc3
4 changed files with 118 additions and 54 deletions

View file

@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.6 on 2017-10-13 13:15
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('feedler', '0006_auto_20171012_1458'),
]
operations = [
migrations.RenameField(
model_name='feedlysettings',
old_name='feedly_stream',
new_name='streams',
),
migrations.RemoveField(
model_name='feedlysettings',
name='feedly_auth',
),
migrations.RemoveField(
model_name='feedlysettings',
name='feedly_pages',
),
migrations.AddField(
model_name='feedlysettings',
name='token',
field=models.CharField(blank=True, help_text='Access Token from developer.feedly.com', max_length=255),
),
]

View file

@ -1,7 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import requests, json, codecs
from django.contrib import admin from django.contrib import admin
from django.db import models from django.db import models
@ -10,66 +8,20 @@ from django.dispatch import receiver
from django.core.mail import send_mail from django.core.mail import send_mail
from wagtail.contrib.settings.models import BaseSetting, register_setting from wagtail.contrib.settings.models import BaseSetting, register_setting
from wagtail.wagtailadmin import messages
from .models import Entry, Stream from .models import Stream
import feedler.feedparser as feedparser
import logging from feedler.refresh import refresh_streams
logger = logging.getLogger('feedler')
# Feedly integration module
@register_setting @register_setting
class FeedlySettings(BaseSetting): class FeedlySettings(BaseSetting):
feedly_auth = models.TextField( streams = models.ManyToManyField(Stream,
help_text='Your developer authorization key', blank=True)
feedly_pages = models.IntegerField(
choices=(
(1, '2'),
(2, '5'),
(3, '10'),
(4, '50'),
), blank=True, null=True, editable=False,
help_text='How many pages to fetch?'
)
feedly_stream = models.ManyToManyField(Stream,
help_text='Which streams to update') help_text='Which streams to update')
token = models.CharField(max_length=255, blank=True,
help_text='Access Token from developer.feedly.com')
class Meta: class Meta:
verbose_name = 'Feedly' verbose_name = 'Feedly'
API_BASEURL = 'https://cloud.feedly.com/v3/streams/contents?streamId='
@receiver(pre_save, sender=FeedlySettings) @receiver(pre_save, sender=FeedlySettings)
def handle_save_settings(sender, instance, *args, **kwargs): def handle_save_settings(sender, instance, *args, **kwargs):
if instance.feedly_auth: if instance.token: refresh_streams(instance)
streams = instance.feedly_stream.all()
for stream in streams:
# Start a request to download the feed
logger.info("Processing stream %s" % stream.title)
url = API_BASEURL + stream.ident
headers = {
'Authorization': 'OAuth ' + instance.feedly_auth
}
contents = requests.get(url, headers=headers).json()
if 'errorMessage' in contents:
# Usually this is a token expired
if 'token expired' in contents['errorMessage']:
# TODO: request new token
pass
logger.error(contents['errorMessage'])
messages.error(sender, "Failed to fetch items: %s" % contents['errorMessage'])
return
for raw_entry in contents['items']:
eid = raw_entry['id']
# Create or update data
try:
entry = Entry.objects.get(entry_id=eid)
logger.info("Updating entry '%s'" % eid)
except Entry.DoesNotExist:
logger.info("Adding entry '%s'" % eid)
entry = Entry()
# Parse the Feedly object
entry = feedparser.parse(entry, raw_entry, stream)
# Persist resulting object
entry.save()

73
feedler/refresh.py Normal file
View file

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
import requests, json, codecs
import logging
logger = logging.getLogger('feedler')
from .models import Entry
from feedler import feedparser
API_BASEURL = 'https://cloud.feedly.com/v3/'
API_STREAMS = API_BASEURL + 'streams/contents?streamId='
API_TOKENS = API_BASEURL + 'auth/token'
def refresh_streams(settings):
# Iterate through all saved streams
logger.warn("Refreshing all streams")
for stream in settings.streams.all():
if not refresh_stream(stream, settings):
return False
return True
def get_headers(settings):
return {
'Authorization': 'OAuth ' + settings.token
}
def refresh_token(settings):
# Request a new token
url = API_TOKENS
logger.warn("Refreshing Feedly access token")
payload = {
'refresh_token': settings.token,
'client_id': 'feedlydev',
'client_secret': 'feedlydev',
'grant_type': 'refresh_token'
}
contents = requests.get(url, data=payload, headers=get_headers(settings)).json()
if not 'access_token' in contents or not contents['access_token']:
logger.error("Access token could not be refreshed.")
return False
settings.token = contents['access_token']
settings.save()
return True
def refresh_stream(stream, settings, retry=False):
# Start a request to download the feed for a particular stream
logger.warn("Processing stream %s" % stream.title)
url = API_STREAMS + stream.ident
contents = requests.get(url, headers=get_headers(settings)).json()
if 'errorMessage' in contents:
# Usually this is a token expired
if 'token expired' in contents['errorMessage'] or 'unauthorized' in contents['errorMessage']:
if not refresh_token(settings): return False
# Make another attempt
if retry or not refresh_stream(stream, settings, True):
return False
else:
logger.error(contents['errorMessage'])
return False
for raw_entry in contents['items']:
eid = raw_entry['id']
# Create or update data
try:
entry = Entry.objects.get(entry_id=eid)
logger.info("Updating entry '%s'" % eid)
except Entry.DoesNotExist:
logger.info("Adding entry '%s'" % eid)
entry = Entry()
# Parse the Feedly object
entry = feedparser.parse(entry, raw_entry, stream)
# Persist resulting object
entry.save()

View file

@ -156,6 +156,12 @@ LOGGING = {
} }
}, },
'loggers': { 'loggers': {
'feedler': {
'handlers': [],
'level': 'INFO',
'propagate': False,
'formatter': 'verbose',
},
'publichealth': { 'publichealth': {
'handlers': [], 'handlers': [],
'level': 'INFO', 'level': 'INFO',