Source code for oauth_dropins.tumblr

"""Tumblr OAuth drop-in.

API docs:
http://www.tumblr.com/docs/en/api/v2
http://www.tumblr.com/oauth/apps
"""
import logging
import urllib.parse

from flask import request
from google.cloud import ndb
import tumblpy

from . import views, models
from .webutil import flask_util, util
from .webutil.util import json_dumps, json_loads

logger = logging.getLogger(__name__)

TUMBLR_APP_KEY = util.read('tumblr_app_key')
TUMBLR_APP_SECRET = util.read('tumblr_app_secret')


[docs] class TumblrAuth(models.BaseAuth): """An authenticated Tumblr user. Provides methods that return information about this user and make OAuth-signed requests to the Tumblr API. Stores OAuth credentials in the datastore. See models.BaseAuth for usage details. Tumblr-specific details: implements api() but not urlopen(). api() returns a tumblpy.Tumblpy. The datastore entity key name is the Tumblr username. """ # access token token_key = ndb.StringProperty(required=True) token_secret = ndb.StringProperty(required=True) user_json = ndb.TextProperty(required=True)
[docs] def site_name(self): return 'Tumblr'
[docs] def user_display_name(self): """Returns the username. """ return self.key_id()
[docs] def access_token(self): """Returns the OAuth access token as a (string key, string secret) tuple. """ return (self.token_key, self.token_secret)
def _api(self): """Returns a tumblpy.Tumblpy. """ return TumblrAuth._api_from_token(self.token_key, self.token_secret) @staticmethod def _api_from_token(key, secret): """Returns a tumblpy.Tumblpy. """ assert TUMBLR_APP_KEY and TUMBLR_APP_SECRET, \ "Please fill in the tumblr_app_key and tumblr_app_secret files in your app's root directory." return tumblpy.Tumblpy(app_key=TUMBLR_APP_KEY, app_secret=TUMBLR_APP_SECRET, oauth_token=key, oauth_token_secret=secret)
[docs] class Start(views.Start): """Starts Tumblr auth. Requests an auth code and expects a redirect back. """ NAME = 'tumblr' LABEL = 'Tumblr'
[docs] def redirect_url(self, state=None): assert TUMBLR_APP_KEY and TUMBLR_APP_SECRET, \ "Please fill in the tumblr_app_key and tumblr_app_secret files in your app's root directory." tp = tumblpy.Tumblpy(app_key=TUMBLR_APP_KEY, app_secret=TUMBLR_APP_SECRET) auth_props = tp.get_authentication_tokens( callback_url=urllib.parse.urljoin(request.host_url, self.to_path)) # store the request token for later use in the callback view models.OAuthRequestToken(id=auth_props['oauth_token'], token_secret=auth_props['oauth_token_secret'], state=state).put() return auth_props['auth_url']
[docs] @classmethod def button_html(cls, *args, **kwargs): return super(cls, cls).button_html( *args, input_style='background-color: #406784; padding: 10px', **kwargs)
[docs] class Callback(views.Callback): """OAuth callback. Fetches the user's blogs and stores the credentials. """
[docs] def dispatch_request(self): verifier = request.values.get('oauth_verifier') request_token_key = request.values.get('oauth_token') if not verifier or not request_token_key: # user declined return self.finish(None) # look up the request token request_token = models.OAuthRequestToken.get_by_id(request_token_key) if request_token is None: flask_util.error(f'Invalid oauth_token: {request_token_key}') # generate and store the final token tp = tumblpy.Tumblpy(app_key=TUMBLR_APP_KEY, app_secret=TUMBLR_APP_SECRET, oauth_token=request_token_key, oauth_token_secret=request_token.token_secret) auth_token = tp.get_authorized_tokens(verifier) auth_token_key = auth_token['oauth_token'] auth_token_secret = auth_token['oauth_token_secret'] # get the user's blogs # http://www.tumblr.com/docs/en/api/v2#user-methods tp = TumblrAuth._api_from_token(auth_token_key, auth_token_secret) logger.debug('Fetching user/info') try: resp = tp.post('user/info') except BaseException as e: util.interpret_http_exception(e) raise logger.debug(f'Got: {resp}') user = resp['user'] auth = TumblrAuth(id=user['name'], token_key=auth_token_key, token_secret=auth_token_secret, user_json=json_dumps(resp)) auth.put() return self.finish(auth, state=request_token.state)