generate channels view

This commit is contained in:
Corban-Lee Jones 2024-10-02 23:32:45 +01:00
parent 6127233c0f
commit 9002eaf807
2 changed files with 93 additions and 17 deletions

View File

@ -3,10 +3,10 @@
from django.urls import path
from django.contrib.auth.decorators import login_required
from .views import IndexView, GuildsView, CheckBotPermissionView
from .views import IndexView, GuildsView, ChannelsView
urlpatterns = [
path("", login_required(IndexView.as_view()), name="index"),
path("generate-servers/", GuildsView.as_view(), name="generate-servers"),
path("bot-permissions/", CheckBotPermissionView.as_view(), name="bot-permissions")
path("generate-channels/", ChannelsView.as_view(), name="generate-channels"),
]

View File

@ -1,6 +1,7 @@
# -*- encoding: utf-8 -*-
import json
import logging
import httpx
from django.conf import settings
@ -9,10 +10,13 @@ from asgiref.sync import sync_to_async
from django.shortcuts import redirect
from django.http import JsonResponse, HttpResponse
from django.views.generic import TemplateView, View
from django.core.exceptions import PermissionDenied
from apps.home.models import Server
from apps.home.models import Server, DiscordChannel
from apps.authentication.models import DiscordUser, ServerMember
log = logging.getLogger(__name__)
class IndexView(TemplateView):
"""
@ -22,13 +26,22 @@ class IndexView(TemplateView):
template_name = "home/index.html"
@sync_to_async
def get_user_access_token(user: DiscordUser) -> str:
return user.access_token
@sync_to_async
def is_user_authenticated(user: DiscordUser) -> bool:
return user.is_authenticated
class GuildsView(View):
async def get(self, request, *args, **kwargs):
if not await self.is_user_authenticated(request.user):
if not await is_user_authenticated(request.user):
return redirect("/oauth2/login")
access_token = await self.get_user_access_token(request.user)
access_token = await get_user_access_token(request.user)
async with httpx.AsyncClient() as client:
response = await client.get(
@ -51,16 +64,6 @@ class GuildsView(View):
return JsonResponse(cleaned_guild_data, safe=False)
@staticmethod
@sync_to_async
def get_user_access_token(user: DiscordUser) -> str:
return user.access_token
@staticmethod
@sync_to_async
def is_user_authenticated(user: DiscordUser) -> bool:
return user.is_authenticated
async def setup_server(self, user: DiscordUser, data: dict):
is_owner = data["owner"]
permissions = data["permissions"]
@ -99,7 +102,80 @@ class GuildsView(View):
pass
class CheckBotPermissionView(View):
class ChannelsView(View):
async def get(self, request, *args, **kwargs):
return JsonResponse({"test": ""})
if not await is_user_authenticated(request.user):
return redirect("/oauth2/login")
guild_id = request.GET.get("guild")
server = await Server.objects.aget(pk=guild_id)
if not ServerMember.objects.filter(server=server, user=request.user).aexists():
raise PermissionDenied("You aren't a member of this server.")
channels_data, status = await self._get_channel_data(guild_id)
if status != 200:
return JsonResponse(channels_data, status=status, safe=False)
cleaned_channels_data = await self._clean_channels_data(server, channels_data)
await self._cleanup_dead_channels(server, cleaned_channels_data)
return JsonResponse(cleaned_channels_data, safe=False)
async def _get_channel_data(self, guild_id: int) -> tuple[list[dict], int]:
"""
Returns the raw channel data and a response status code
from the Discord API.
"""
async with httpx.AsyncClient() as client:
response = await client.get(
url=f"{settings.DISCORD_API_URL}/guilds/{guild_id}/channels",
headers={"Authorization": f"Bot {settings.BOT_TOKEN}"}
)
return response.json(), response.status_code
async def _clean_channels_data(self, server: Server, channels_data) -> list[dict]:
"""
Returns a sorted & cleaned list of channel data, also performs a
database setup for each channel to be stored.
"""
cleaned_channels_data = []
for item in channels_data:
cleaned_data = await self._setup_channel(server, item)
if cleaned_data:
cleaned_channels_data.append(cleaned_data)
cleaned_channels_data.sort(key=lambda ch: ch.get("position"))
return cleaned_channels_data
async def _setup_channel(self, server: Server, data: dict) -> dict:
"""
Create or update an instance of DiscordChannel representing the given
`data` dictionary, returns the data or `NoneType` if `data['type'] != 0`.
"""
if data.get("type") != 0:
return
await DiscordChannel.objects.aupdate_or_create(
id=data["id"],
server=server,
defaults={
"name": data["name"],
"is_nsfw": data["nsfw"]
}
)
return data
async def _cleanup_dead_channels(self, server: Server, channel_data: list[dict]):
"""
Deletes any unused instances of `DiscordChannel` against the given server.
"""
channel_ids = [item["id"] for item in channel_data]
count, _ = await DiscordChannel.objects.exclude(server=server, id__in=channel_ids).adelete()
log.info("Deleted %s dead DiscordChannel object(s)", count)