Add FlaskSessionCacheHandler (#833)

Updated examples/app.py
Updated CHANGELOG.md and appropriate docs.
This commit is contained in:
Bryan Malyn 2022-06-25 14:00:08 -05:00 committed by GitHub
parent 7337bf9352
commit 7fc08809f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 40 additions and 26 deletions

View File

@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Added `market` parameter to `album` and `albums` to address ([#753](https://github.com/plamere/spotipy/issues/753) * Added `market` parameter to `album` and `albums` to address ([#753](https://github.com/plamere/spotipy/issues/753)
* Added 'show_featured_artists.py' to 'examples'. * Added 'show_featured_artists.py' to 'examples'.
* Expanded contribution and license sections of the documentation. * Expanded contribution and license sections of the documentation.
* Added `FlaskSessionCacheHandler`, a cache handler that stores the token info in a flask session.
### Fixed ### Fixed

View File

@ -235,6 +235,7 @@ The following handlers are available and defined in the URL above.
- ``CacheFileHandler`` - ``CacheFileHandler``
- ``MemoryCacheHandler`` - ``MemoryCacheHandler``
- ``DjangoSessionCacheHandler`` - ``DjangoSessionCacheHandler``
- ``FlaskSessionCacheHandler``
- ``RedisCacheHandler`` - ``RedisCacheHandler``
Feel free to contribute new cache handlers to the repo. Feel free to contribute new cache handlers to the repo.

View File

@ -27,7 +27,6 @@ import os
from flask import Flask, session, request, redirect from flask import Flask, session, request, redirect
from flask_session import Session from flask_session import Session
import spotipy import spotipy
import uuid
app = Flask(__name__) app = Flask(__name__)
app.config['SECRET_KEY'] = os.urandom(64) app.config['SECRET_KEY'] = os.urandom(64)
@ -35,57 +34,44 @@ app.config['SESSION_TYPE'] = 'filesystem'
app.config['SESSION_FILE_DIR'] = './.flask_session/' app.config['SESSION_FILE_DIR'] = './.flask_session/'
Session(app) Session(app)
caches_folder = './.spotify_caches/'
if not os.path.exists(caches_folder):
os.makedirs(caches_folder)
def session_cache_path():
return caches_folder + session.get('uuid')
@app.route('/') @app.route('/')
def index(): def index():
if not session.get('uuid'):
# Step 1. Visitor is unknown, give random ID
session['uuid'] = str(uuid.uuid4())
cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(scope='user-read-currently-playing playlist-modify-private', auth_manager = spotipy.oauth2.SpotifyOAuth(scope='user-read-currently-playing playlist-modify-private',
cache_handler=cache_handler, cache_handler=cache_handler,
show_dialog=True) show_dialog=True)
if request.args.get("code"): if request.args.get("code"):
# Step 3. Being redirected from Spotify auth page # Step 2. Being redirected from Spotify auth page
auth_manager.get_access_token(request.args.get("code")) auth_manager.get_access_token(request.args.get("code"))
return redirect('/') return redirect('/')
if not auth_manager.validate_token(cache_handler.get_cached_token()): if not auth_manager.validate_token(cache_handler.get_cached_token()):
# Step 2. Display sign in link when no token # Step 1. Display sign in link when no token
auth_url = auth_manager.get_authorize_url() auth_url = auth_manager.get_authorize_url()
return f'<h2><a href="{auth_url}">Sign in</a></h2>' return f'<h2><a href="{auth_url}">Sign in</a></h2>'
# Step 4. Signed in, display data # Step 3. Signed in, display data
spotify = spotipy.Spotify(auth_manager=auth_manager) spotify = spotipy.Spotify(auth_manager=auth_manager)
return f'<h2>Hi {spotify.me()["display_name"]}, ' \ return f'<h2>Hi {spotify.me()["display_name"]}, ' \
f'<small><a href="/sign_out">[sign out]<a/></small></h2>' \ f'<small><a href="/sign_out">[sign out]<a/></small></h2>' \
f'<a href="/playlists">my playlists</a> | ' \ f'<a href="/playlists">my playlists</a> | ' \
f'<a href="/currently_playing">currently playing</a> | ' \ f'<a href="/currently_playing">currently playing</a> | ' \
f'<a href="/current_user">me</a>' \ f'<a href="/current_user">me</a>' \
@app.route('/sign_out') @app.route('/sign_out')
def sign_out(): def sign_out():
try: session.pop("token_info", None)
# Remove the CACHE file (.cache-test) so that a new user can authorize.
os.remove(session_cache_path())
session.clear()
except OSError as e:
print ("Error: %s - %s." % (e.filename, e.strerror))
return redirect('/') return redirect('/')
@app.route('/playlists') @app.route('/playlists')
def playlists(): def playlists():
cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()): if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/') return redirect('/')
@ -96,7 +82,7 @@ def playlists():
@app.route('/currently_playing') @app.route('/currently_playing')
def currently_playing(): def currently_playing():
cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()): if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/') return redirect('/')
@ -109,7 +95,7 @@ def currently_playing():
@app.route('/current_user') @app.route('/current_user')
def current_user(): def current_user():
cache_handler = spotipy.cache_handler.CacheFileHandler(cache_path=session_cache_path()) cache_handler = spotipy.cache_handler.FlaskSessionCacheHandler(session)
auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler) auth_manager = spotipy.oauth2.SpotifyOAuth(cache_handler=cache_handler)
if not auth_manager.validate_token(cache_handler.get_cached_token()): if not auth_manager.validate_token(cache_handler.get_cached_token()):
return redirect('/') return redirect('/')

View File

@ -2,6 +2,7 @@ __all__ = [
'CacheHandler', 'CacheHandler',
'CacheFileHandler', 'CacheFileHandler',
'DjangoSessionCacheHandler', 'DjangoSessionCacheHandler',
'FlaskSessionCacheHandler',
'MemoryCacheHandler', 'MemoryCacheHandler',
'RedisCacheHandler'] 'RedisCacheHandler']
@ -147,6 +148,31 @@ class DjangoSessionCacheHandler(CacheHandler):
logger.warning("Error saving token to cache: " + str(e)) logger.warning("Error saving token to cache: " + str(e))
class FlaskSessionCacheHandler(CacheHandler):
"""
A cache handler that stores the token info in the session framework
provided by flask.
"""
def __init__(self, session):
self.session = session
def get_cached_token(self):
token_info = None
try:
token_info = self.session["token_info"]
except KeyError:
logger.debug("Token not found in the session")
return token_info
def save_token_to_cache(self, token_info):
try:
self.session["token_info"] = token_info
except Exception as e:
logger.warning("Error saving token to cache: " + str(e))
class RedisCacheHandler(CacheHandler): class RedisCacheHandler(CacheHandler):
""" """
A cache handler that stores the token info in the Redis. A cache handler that stores the token info in the Redis.