Graphs and tables for your Spotify account.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

143 lines
4.1 KiB

6 years ago
6 years ago
  1. # imports {{{ #
  2. import math
  3. import random
  4. import requests
  5. import os
  6. import urllib
  7. import secrets
  8. import pprint
  9. import string
  10. from datetime import datetime
  11. from django.shortcuts import render, redirect
  12. from django.http import HttpResponseBadRequest
  13. from .models import *
  14. from .utils import *
  15. # }}} imports #
  16. TIME_FORMAT = '%Y-%m-%d-%H-%M-%S'
  17. TRACKS_TO_QUERY = 200
  18. AUTH_SCOPE = ['user-library-read', 'user-read-recently-played',]
  19. # generate_random_string {{{ #
  20. def generate_random_string(length):
  21. """Generates a random string of a certain length
  22. Args:
  23. length: the desired length of the randomized string
  24. Returns:
  25. A random string
  26. """
  27. all_chars = string.ascii_letters + string.digits
  28. rand_str = "".join(random.choice(all_chars) for _ in range(length))
  29. return rand_str
  30. # }}} generate_random_string #
  31. # index {{{ #
  32. # Create your views here.
  33. def index(request):
  34. return render(request, 'login/index.html')
  35. # }}} index #
  36. # spotify_login {{{ #
  37. def spotify_login(request):
  38. """ Step 1 in authorization flow: Have your application request
  39. authorization; the user logs in and authorizes access.
  40. """
  41. # use a randomly generated state string to prevent cross-site request forgery attacks
  42. state_str = generate_random_string(16)
  43. request.session['state_string'] = state_str
  44. payload = {
  45. 'client_id': os.environ['SPOTIFY_CLIENT_ID'],
  46. 'response_type': 'code',
  47. 'redirect_uri': 'http://localhost:8000/login/callback',
  48. 'state': state_str,
  49. 'scope': " ".join(AUTH_SCOPE),
  50. 'show_dialog': False
  51. }
  52. params = urllib.parse.urlencode(payload) # turn the payload dict into a query string
  53. authorize_url = "https://accounts.spotify.com/authorize/?{}".format(params)
  54. return redirect(authorize_url)
  55. # }}} spotify_login #
  56. def callback(request):
  57. """ Step 2 in authorization flow: Have your application request refresh and
  58. access tokens; Spotify returns access and refresh tokens.
  59. """
  60. # Attempt to retrieve the authorization code from the query string
  61. try:
  62. code = request.GET['code']
  63. except KeyError:
  64. return HttpResponseBadRequest("<h1>Problem with login</h1>")
  65. payload = {
  66. 'grant_type': 'authorization_code',
  67. 'code': code,
  68. 'redirect_uri': 'http://localhost:8000/login/callback',
  69. 'client_id': os.environ['SPOTIFY_CLIENT_ID'],
  70. 'client_secret': os.environ['SPOTIFY_CLIENT_SECRET'],
  71. }
  72. token_response = requests.post('https://accounts.spotify.com/api/token', data=payload).json()
  73. user_obj = create_user(token_response['refresh_token'],
  74. token_response['access_token'],
  75. token_response['expires_in'])
  76. return render(request, 'login/scan.html', get_user_context(user_obj))
  77. # return redirect('user/' + user_obj.secret)
  78. def create_user(refresh_token, access_token, access_expires_in):
  79. """Create a User object based on information returned from Step 2 (callback
  80. function) of auth flow.
  81. :refresh_token: Used to renew access tokens.
  82. :access_token: Used in Spotify API calls.
  83. :access_expires_in: How long the access token last in seconds.
  84. :returns: The newly created User object.
  85. """
  86. profile_response = requests.get('https://api.spotify.com/v1/me',
  87. headers={'Authorization': "Bearer " + access_token}).json()
  88. user_id = profile_response['id']
  89. try:
  90. user_obj = User.objects.get(id=user_id)
  91. except User.DoesNotExist:
  92. # Python docs recommends 32 bytes of randomness against brute
  93. # force attacks
  94. user_obj = User.objects.create(
  95. id=user_id,
  96. secret=secrets.token_urlsafe(32),
  97. refresh_token=refresh_token,
  98. access_token=access_token,
  99. access_expires_in=access_expires_in,
  100. )
  101. return user_obj
  102. # admin_graphs {{{ #
  103. def admin_graphs(request):
  104. """TODO
  105. """
  106. user_id = "polarbier"
  107. # user_id = "chrisshyi13"
  108. user_obj = User.objects.get(id=user_id)
  109. return render(request, 'graphs/logged_in.html', get_user_context(user_obj))
  110. # }}} admin_graphs #