134 lines
3.9 KiB
Python
134 lines
3.9 KiB
Python
# -*- encoding: utf-8 -*-
|
|
|
|
import logging
|
|
import requests
|
|
from datetime import timedelta
|
|
|
|
from django.conf import settings
|
|
from django.utils import timezone
|
|
from django.http import JsonResponse
|
|
from django.views.generic import View, TemplateView
|
|
from django.shortcuts import redirect
|
|
from django.contrib.auth import authenticate, login
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
class DiscordLoginAction(View):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
return redirect(settings.DISCORD_OAUTH2_URL)
|
|
|
|
|
|
class DiscordLoginRedirect(View):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
"""
|
|
Endpoint function directed to once authorized from Discord.
|
|
This method will "login" the user.
|
|
"""
|
|
|
|
if request.GET.get("error"):
|
|
return redirect("auth:login")
|
|
|
|
code = request.GET.get("code")
|
|
exchange_data = self.exchange_code(code)
|
|
access_token = exchange_data["access_token"]
|
|
|
|
# Get raw user data from discord
|
|
raw_user_data = self.get_raw_user_data(access_token)
|
|
|
|
# Add the token and expires datetime to the user data
|
|
token_expire_datetime = timezone.now() + timedelta(seconds=exchange_data["expires_in"])
|
|
raw_user_data["token_expires"] = token_expire_datetime
|
|
raw_user_data["access_token"] = access_token
|
|
raw_user_data["refresh_token"] = exchange_data["refresh_token"]
|
|
|
|
# authenticate (creates user if not exists) and login
|
|
discord_user = authenticate(request, discord_user_data=raw_user_data)
|
|
login(request, discord_user)
|
|
|
|
redirect_url = request.GET.get("redirect") or "home:index"
|
|
return redirect(redirect_url)
|
|
|
|
def exchange_code(self, code: str) -> dict:
|
|
"""
|
|
Exchanges the given code for an access token.
|
|
A call is made to the Discord API.
|
|
"""
|
|
|
|
log.debug("exchanging code for access token")
|
|
|
|
request_data = settings.DISCORD_CODE_EXCHANGE_REQUEST
|
|
request_data["data"]["code"] = code
|
|
|
|
# Fetch the access token
|
|
response = requests.post(
|
|
url=f"{settings.DISCORD_API_URL}/oauth2/token",
|
|
data=request_data["data"],
|
|
headers=request_data["headers"]
|
|
)
|
|
|
|
return response.json()
|
|
|
|
def refresh_token(self, refresh_token: str) -> dict:
|
|
"""
|
|
Refresh the access token if expired, using the refresh
|
|
token. Returns a new access token, expire time and refresh
|
|
token.
|
|
"""
|
|
|
|
log.debug("refreshing access token")
|
|
|
|
request_data = settings.DISCORD_REFRESH_TOKEN_REQUEST
|
|
request_data["data"]["refresh_token"] = refresh_token
|
|
|
|
response = requests.post(
|
|
url=f"{settings.DISCORD_API_URL}/oauth2/token",
|
|
data=request_data["data"],
|
|
headers=request_data["headers"]
|
|
)
|
|
|
|
return response.json()
|
|
|
|
def get_raw_user_data(self, access_token: str):
|
|
"""
|
|
Fetches the raw user data using the given access token.
|
|
A call is made to the Discord API.
|
|
"""
|
|
|
|
log.debug("fetching raw user data")
|
|
|
|
response = requests.get(
|
|
url=f"{settings.DISCORD_API_URL}/users/@me",
|
|
headers={"Authorization": f"Bearer {access_token}"}
|
|
)
|
|
|
|
data = response.json()
|
|
|
|
# Assign the default avatar
|
|
if not data.get("avatar"):
|
|
data["avatar"] = int(data["id"]) % 5
|
|
|
|
return data
|
|
|
|
|
|
class Login(TemplateView):
|
|
|
|
template_name = "accounts/login.html"
|
|
|
|
|
|
class GuildChannelsView(View):
|
|
|
|
def get(self, request, *args, **kwargs):
|
|
log.debug("fetching channels from guid")
|
|
|
|
guild_id = request.GET.get("guild")
|
|
response = requests.get(
|
|
url=f"{settings.DISCORD_API_URL}/guilds/{guild_id}/channels",
|
|
headers={"Authorization": f"Bot {settings.BOT_TOKEN}"}
|
|
)
|
|
|
|
return JsonResponse(response.json(), status=response.status_code, safe=False)
|