From 324aba97e401e28f0a6632f104ad543fe2eb47e3 Mon Sep 17 00:00:00 2001 From: mike wakerly Date: Sun, 25 Jun 2017 16:11:51 -0400 Subject: [PATCH] Update Untappd plugin. --- pykeg/contrib/untappd/client.py | 45 +++++++++++++++ pykeg/contrib/untappd/oauth_client.py | 57 ------------------- pykeg/contrib/untappd/plugin.py | 8 ++- .../untappd/untappd_user_settings.html | 6 +- pykeg/contrib/untappd/views.py | 50 +++++----------- pykeg/settings.py | 4 +- 6 files changed, 70 insertions(+), 100 deletions(-) create mode 100644 pykeg/contrib/untappd/client.py delete mode 100644 pykeg/contrib/untappd/oauth_client.py diff --git a/pykeg/contrib/untappd/client.py b/pykeg/contrib/untappd/client.py new file mode 100644 index 000000000..443ed9fd9 --- /dev/null +++ b/pykeg/contrib/untappd/client.py @@ -0,0 +1,45 @@ +# Copyright 2017 Bevbot LLC, All Rights Reserved +# +# This file is part of the Pykeg package of the Kegbot project. +# For more information on Pykeg or Kegbot, see http://kegbot.org/ +# +# Pykeg is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 2 of the License, or +# (at your option) any later version. +# +# Pykeg is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Pykeg. If not, see . + +import requests +from requests_oauthlib import OAuth2Session + + +class UntappdClient: + AUTHORIZATION_URL = 'https://untappd.com/oauth/authenticate/' + ACCESS_TOKEN_URL = 'https://untappd.com/oauth/authorize/' + + def __init__(self, client_id, client_secret): + self.client_id = client_id + self.client_secret = client_secret + + def get_authorization_url(self, redirect_uri): + oauth = OAuth2Session(self.client_id, redirect_uri=redirect_uri) + return oauth.authorization_url(self.AUTHORIZATION_URL) + + def handle_authorization_callback(self, response_url, redirect_uri): + oauth = OAuth2Session(self.client_id, redirect_uri=redirect_uri) + token = oauth.fetch_token(self.ACCESS_TOKEN_URL, + authorization_response=response_url, + client_secret=self.client_secret, + method='GET') + return token + + def get_user_info(self, access_token): + return requests.get('https://api.untappd.com/v4/user/info', + params={'access_token': access_token}).json()['response']['user'] diff --git a/pykeg/contrib/untappd/oauth_client.py b/pykeg/contrib/untappd/oauth_client.py deleted file mode 100644 index 4b9980d36..000000000 --- a/pykeg/contrib/untappd/oauth_client.py +++ /dev/null @@ -1,57 +0,0 @@ -from django.conf import settings -from socialregistration.clients.oauth import OAuth2 -from socialregistration.settings import SESSION_KEY -import json -import urllib - - -class Untappd(OAuth2): - client_id = getattr(settings, 'UNTAPPD_CLIENT_ID', '') - secret = getattr(settings, 'UNTAPPD_CLIENT_SECRET', '') - auth_url = 'https://untappd.com/oauth/authenticate' - access_token_url = 'https://untappd.com/oauth/authorize/' - - def __init__(self, *args, **kwargs): - self._user_info = None - self.callback_url = kwargs.pop('callback_url') - super(Untappd, self).__init__(*args, **kwargs) - - def get_callback_url(self, **kwargs): - return self.callback_url - - def get_redirect_url(self, state='', **kwargs): - params = { - 'response_type': 'code', - 'client_id': self.client_id, - 'redirect_url': self.get_callback_url(**kwargs), - 'state': state, - } - - return '%s?%s' % (self.auth_url, urllib.urlencode(params)) - - def parse_access_token(self, content): - """ - Untappd returns JSON instead of url encoded data. - """ - response = json.loads(content) - if not response or not response.get('response'): - raise ValueError('Malformed response: %s' % str(response)) - - return response.get('response', {}) - - def request_access_token(self, params): - params['redirect_url'] = params['redirect_uri'] - del params['redirect_uri'] - params['response_type'] = 'code' - url = '%s?%s' % (self.access_token_url, urllib.urlencode(params)) - return self.request(url, method="GET") - - def get_user_info(self): - if self._user_info is None: - resp, content = self.request('https://api.untappd.com/v4/user/info') - self._user_info = json.loads(content)['response']['user'] - return self._user_info - - @staticmethod - def get_session_key(): - return '%suntappd' % SESSION_KEY diff --git a/pykeg/contrib/untappd/plugin.py b/pykeg/contrib/untappd/plugin.py index a5891863b..3de966a14 100644 --- a/pykeg/contrib/untappd/plugin.py +++ b/pykeg/contrib/untappd/plugin.py @@ -24,6 +24,7 @@ from pykeg.plugin import plugin from pykeg.plugin import util as plugin_util +from . import client from . import forms from . import tasks from . import views @@ -50,8 +51,8 @@ def get_user_settings_view(self): def get_extra_user_views(self): return [ - ('redirect/$', 'pykeg.contrib.untappd.views.auth_redirect', 'redirect'), - ('callback/$', 'pykeg.contrib.untappd.views.auth_callback', 'callback'), + ('redirect/$', views.auth_redirect, 'redirect'), + ('callback/$', views.auth_callback, 'callback'), ] def handle_new_events(self, events): @@ -154,3 +155,6 @@ def get_user_token(self, user): def save_user_token(self, user, token): self.datastore.set('user_token:%s' % user.id, token) + + def get_client(self): + return client.UntappdClient(*self.get_credentials()) diff --git a/pykeg/contrib/untappd/templates/contrib/untappd/untappd_user_settings.html b/pykeg/contrib/untappd/templates/contrib/untappd/untappd_user_settings.html index 996d3f5c1..6f1307e89 100644 --- a/pykeg/contrib/untappd/templates/contrib/untappd/untappd_user_settings.html +++ b/pykeg/contrib/untappd/templates/contrib/untappd/untappd_user_settings.html @@ -11,7 +11,7 @@

Untappd Account

- Untappd is currently linked to {{ profile.first_name }} {{ profile.last_name }}. + Untappd is currently linked to {{ profile.user_name }}.

@@ -30,7 +30,7 @@

Untappd Account

Link Untappd Account

- Link an Untappd account to your Kegbot account. + Link an Untappd account to your Kegbot account.

{% csrf_token %} @@ -45,7 +45,7 @@

Link Untappd Account

Settings

- Control how Kegbot will use use your account. + Control how Kegbot will use use your account.

{% csrf_token %} diff --git a/pykeg/contrib/untappd/views.py b/pykeg/contrib/untappd/views.py index 7c7064bdd..df42e973f 100644 --- a/pykeg/contrib/untappd/views.py +++ b/pykeg/contrib/untappd/views.py @@ -19,13 +19,11 @@ from django.contrib import messages from django.core.urlresolvers import reverse from django.shortcuts import redirect -from socialregistration.clients.oauth import OAuthError from pykeg.web.decorators import staff_member_required from django.contrib.auth.decorators import login_required from django.shortcuts import render from . import forms -from . import oauth_client @staff_member_required @@ -79,43 +77,25 @@ def auth_redirect(request): return redirect('account-plugin-settings', plugin_name='untappd') plugin = request.plugins['untappd'] - url = request.build_absolute_uri(reverse('plugin-untappd-callback')) - client = get_client(*plugin.get_credentials(), callback_url=url) - - request.session['untappd_client'] = client - - try: - return redirect(client.get_redirect_url()) - except OAuthError as error: - messages.error(request, 'Error: %s' % str(error)) - return redirect('account-plugin-settings', plugin_name='untappd') + client = plugin.get_client() + callback_url = request.build_absolute_uri(reverse('plugin-untappd-callback')) + url, state = client.get_authorization_url(callback_url) + return redirect(url) @login_required def auth_callback(request): - try: - client = request.session['untappd_client'] - del request.session['untappd_client'] - token = client.complete(dict(request.GET.items())) - except KeyError: - messages.error(request, 'Session expired.') - except OAuthError as error: - messages.error(request, str(error)) - else: - plugin = request.plugins.get('untappd') - profile = client.get_user_info() - token = client.get_access_token() - plugin.save_user_profile(request.user, profile) - plugin.save_user_token(request.user, token) - - username = '%s %s' % (profile.get('first_name'), profile.get('last_name')) - messages.success(request, 'Successfully linked to Untappd user %s' % username) + plugin = request.plugins['untappd'] + client = plugin.get_client() - return redirect('account-plugin-settings', plugin_name='untappd') + callback_url = request.build_absolute_uri(reverse('plugin-untappd-callback')) + result = client.handle_authorization_callback(request.build_absolute_uri(), callback_url) + token = result['access_token'] + profile = client.get_user_info(token) + username = profile['user_name'] + plugin.save_user_profile(request.user, profile) + plugin.save_user_token(request.user, token) -def get_client(client_id, client_secret, callback_url): - client = oauth_client.Untappd(callback_url=callback_url) - client.client_id = client_id - client.secret = client_secret - return client + messages.success(request, 'Successfully linked to Untappd user %s' % username) + return redirect('account-plugin-settings', plugin_name='untappd') diff --git a/pykeg/settings.py b/pykeg/settings.py index ed6c6ad48..6ecdaf47b 100644 --- a/pykeg/settings.py +++ b/pykeg/settings.py @@ -146,7 +146,7 @@ KEGBOT_PLUGINS = [ 'pykeg.contrib.foursquare.plugin.FoursquarePlugin', 'pykeg.contrib.twitter.plugin.TwitterPlugin', - # 'pykeg.contrib.untappd.plugin.UntappdPlugin', + 'pykeg.contrib.untappd.plugin.UntappdPlugin', 'pykeg.contrib.webhook.plugin.WebhookPlugin', ] @@ -357,8 +357,6 @@ # Update email addresses. DEFAULT_FROM_EMAIL = EMAIL_FROM_ADDRESS -# socialregistration (after importing common settings) - if KEGBOT_ENABLE_ADMIN: INSTALLED_APPS += ('django.contrib.admin',)