140 lines
3.7 KiB
Python

# -*- encoding: utf-8 -*-
import json
import logging
import requests
from django.conf import settings
from django.http import JsonResponse
from django.views.generic import View, TemplateView
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from .models import UserServerLink
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.
"""
code = request.GET.get("code")
access_token = self.exchange_code_for_token(code)
raw_user_data = self.get_raw_user_data(access_token)
raw_user_data["access_token"] = access_token
log.debug(raw_user_data)
discord_user = authenticate(request, discord_user_data=raw_user_data)
login(request, discord_user)
return redirect("home:index")
def exchange_code_for_token(self, code: str) -> dict:
"""
Exchanges the given code for an access token.
A call is made to the Discord API.
"""
request_data = settings.DISCORD_CODE_EXCHANGE_REQUEST
request_data["data"]["code"] = code
log.debug("request data: %s", request_data)
# Fetch the access token
response = requests.post(
url=f"{settings.DISCORD_API_URL}/oauth2/token",
data=request_data["data"],
headers=request_data["headers"]
)
log.debug(response)
return response.json()["access_token"]
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.
"""
response = requests.get(
url=f"{settings.DISCORD_API_URL}/users/@me",
headers={"Authorization": f"Bearer {access_token}"}
)
log.debug(response)
return response.json()
class Login(TemplateView):
template_name = "accounts/login.html"
class GuildsView(View):
def get(self, request, *args, **kwargs):
response = requests.get(
url=f"{settings.DISCORD_API_URL}/users/@me/guilds",
headers={"Authorization": f"Bearer {request.user.access_token}"}
)
content = response.json()
self.create_server_links(request.user, content)
return JsonResponse(content, safe=False)
def create_server_links(self, user, content: list[dict]):
"""
Creates objects representing the user's discord servers, storing
server info and the user's permissions within.
Parameters
----------
content : list[dict]
Raw data for the servers.
"""
servers = [
UserServerLink(
server_id=server["id"],
user=user,
name=server["name"],
permissions=server["permissions"]
)
for server in content
]
UserServerLink.objects.filter(user=user).delete()
UserServerLink.objects.bulk_create(servers)
class GuildChannelsView(View):
def get(self, request, *args, **kwargs):
guild_id = request.GET.get("guild")
log.debug("fetching channels from %s using token: %s", guild_id, settings.BOT_TOKEN)
response = requests.get(
url=f"{settings.DISCORD_API_URL}/guilds/{guild_id}/channels",
headers={"Authorization": f"Bot {settings.BOT_TOKEN}"}
)
return JsonResponse(response.json(), safe=False)