2023-08-01 02:38:55 +02:00
|
|
|
"""User management."""
|
|
|
|
|
2023-08-21 20:58:05 +02:00
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
|
2023-08-23 23:27:09 +02:00
|
|
|
from helpers import errors
|
|
|
|
|
2023-08-21 20:58:05 +02:00
|
|
|
project_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
sys.path.append(project_root)
|
|
|
|
|
|
|
|
# the code above is to allow importing from the root folder
|
|
|
|
|
2023-08-01 02:38:55 +02:00
|
|
|
import os
|
|
|
|
import json
|
2023-08-21 21:09:22 +02:00
|
|
|
import hmac
|
2023-08-01 02:38:55 +02:00
|
|
|
import fastapi
|
|
|
|
|
2023-08-04 03:30:56 +02:00
|
|
|
from dhooks import Webhook, Embed
|
2023-08-01 02:38:55 +02:00
|
|
|
from dotenv import load_dotenv
|
|
|
|
|
2023-08-21 20:58:05 +02:00
|
|
|
import checks.client
|
|
|
|
|
|
|
|
from db.users import UserManager
|
|
|
|
|
2023-08-01 02:38:55 +02:00
|
|
|
load_dotenv()
|
|
|
|
router = fastapi.APIRouter(tags=['core'])
|
|
|
|
|
|
|
|
async def check_core_auth(request):
|
2023-08-23 23:27:09 +02:00
|
|
|
"""Checks the core API key. Returns nothing if it's valid, otherwise returns an error.
|
2023-08-13 11:16:23 +02:00
|
|
|
"""
|
2023-08-01 02:38:55 +02:00
|
|
|
received_auth = request.headers.get('Authorization')
|
|
|
|
|
2023-08-21 21:09:22 +02:00
|
|
|
correct_core_api = os.environ['CORE_API_KEY']
|
|
|
|
|
|
|
|
# use hmac.compare_digest to prevent timing attacks
|
2023-08-23 23:27:09 +02:00
|
|
|
if not (received_auth and hmac.compare_digest(received_auth, correct_core_api)):
|
|
|
|
return await errors.error(401, 'The core API key you provided is invalid.', 'Check the `Authorization` header.')
|
|
|
|
|
|
|
|
return None
|
2023-08-01 02:38:55 +02:00
|
|
|
|
|
|
|
@router.get('/users')
|
|
|
|
async def get_users(discord_id: int, incoming_request: fastapi.Request):
|
2023-08-21 20:58:05 +02:00
|
|
|
"""Returns a user by their discord ID. Requires a core API key."""
|
|
|
|
|
2023-08-13 11:16:23 +02:00
|
|
|
auth = await check_core_auth(incoming_request)
|
|
|
|
if auth:
|
2023-08-14 05:11:15 +02:00
|
|
|
return auth
|
2023-08-01 02:38:55 +02:00
|
|
|
|
2023-08-13 11:16:23 +02:00
|
|
|
# Get user by discord ID
|
2023-08-14 05:11:15 +02:00
|
|
|
manager = UserManager()
|
|
|
|
user = await manager.user_by_discord_id(discord_id)
|
|
|
|
if not user:
|
2023-08-23 23:27:09 +02:00
|
|
|
return await errors.error(404, 'Discord user not found in the API database.', 'Check the `discord_id` parameter.')
|
2023-08-03 01:46:49 +02:00
|
|
|
|
2023-08-01 02:38:55 +02:00
|
|
|
return user
|
|
|
|
|
2023-08-21 20:58:05 +02:00
|
|
|
async def new_user_webhook(user: dict) -> None:
|
|
|
|
"""Runs when a new user is created."""
|
|
|
|
|
|
|
|
dhook = Webhook(os.environ['DISCORD_WEBHOOK__USER_CREATED'])
|
2023-08-04 03:30:56 +02:00
|
|
|
|
|
|
|
embed = Embed(
|
|
|
|
description='New User',
|
|
|
|
color=0x90ee90,
|
2023-08-06 00:43:36 +02:00
|
|
|
)
|
2023-08-04 03:30:56 +02:00
|
|
|
|
2023-08-06 21:42:07 +02:00
|
|
|
embed.add_field(name='ID', value=str(user['_id']), inline=False)
|
2023-08-06 23:20:14 +02:00
|
|
|
embed.add_field(name='Discord', value=user['auth']['discord'] or '-')
|
|
|
|
embed.add_field(name='Github', value=user['auth']['github'] or '-')
|
2023-08-04 03:30:56 +02:00
|
|
|
|
|
|
|
dhook.send(embed=embed)
|
|
|
|
|
2023-08-01 02:38:55 +02:00
|
|
|
@router.post('/users')
|
|
|
|
async def create_user(incoming_request: fastapi.Request):
|
2023-08-21 20:58:05 +02:00
|
|
|
"""Creates a user. Requires a core API key."""
|
|
|
|
|
2023-08-01 02:38:55 +02:00
|
|
|
auth_error = await check_core_auth(incoming_request)
|
|
|
|
|
|
|
|
if auth_error:
|
|
|
|
return auth_error
|
|
|
|
|
|
|
|
try:
|
|
|
|
payload = await incoming_request.json()
|
|
|
|
discord_id = payload.get('discord_id')
|
|
|
|
except (json.decoder.JSONDecodeError, AttributeError):
|
2023-08-23 23:27:09 +02:00
|
|
|
return await errors.error(400, 'Invalid or no payload received.', 'The payload must be a JSON object with a `discord_id` key.')
|
2023-08-21 20:58:05 +02:00
|
|
|
|
2023-08-14 05:11:15 +02:00
|
|
|
# Create the user
|
|
|
|
manager = UserManager()
|
|
|
|
user = await manager.create(discord_id)
|
2023-08-06 21:42:07 +02:00
|
|
|
await new_user_webhook(user)
|
2023-08-04 03:30:56 +02:00
|
|
|
|
2023-08-01 02:38:55 +02:00
|
|
|
return user
|
2023-08-18 21:23:00 +02:00
|
|
|
|
|
|
|
@router.put('/users')
|
|
|
|
async def update_user(incoming_request: fastapi.Request):
|
2023-08-21 20:58:05 +02:00
|
|
|
"""Updates a user. Requires a core API key."""
|
|
|
|
|
2023-08-18 21:23:00 +02:00
|
|
|
auth_error = await check_core_auth(incoming_request)
|
|
|
|
|
|
|
|
if auth_error:
|
|
|
|
return auth_error
|
|
|
|
|
|
|
|
try:
|
|
|
|
payload = await incoming_request.json()
|
|
|
|
discord_id = payload.get('discord_id')
|
|
|
|
updates = payload.get('updates')
|
|
|
|
except (json.decoder.JSONDecodeError, AttributeError):
|
2023-08-23 23:27:09 +02:00
|
|
|
return await errors.error(
|
|
|
|
400, 'Invalid or no payload received.',
|
|
|
|
'The payload must be a JSON object with a `discord_id` key and an `updates` key.'
|
|
|
|
)
|
2023-08-21 20:58:05 +02:00
|
|
|
|
2023-08-23 23:27:09 +02:00
|
|
|
# Update the user
|
2023-08-18 21:23:00 +02:00
|
|
|
manager = UserManager()
|
|
|
|
user = await manager.update_by_discord_id(discord_id, updates)
|
|
|
|
|
|
|
|
return user
|
2023-08-21 20:58:05 +02:00
|
|
|
|
|
|
|
@router.get('/checks')
|
|
|
|
async def run_checks(incoming_request: fastapi.Request):
|
|
|
|
"""Tests the API. Requires a core API key."""
|
|
|
|
|
|
|
|
auth_error = await check_core_auth(incoming_request)
|
|
|
|
|
|
|
|
if auth_error:
|
|
|
|
return auth_error
|
|
|
|
|
2023-08-23 23:27:09 +02:00
|
|
|
try:
|
|
|
|
chat = await checks.client.test_chat()
|
2023-08-23 23:31:43 +02:00
|
|
|
except Exception as exc
|
|
|
|
print(exc)
|
2023-08-23 23:27:09 +02:00
|
|
|
chat = None
|
|
|
|
|
|
|
|
try:
|
|
|
|
moderation = await checks.client.test_api_moderation()
|
|
|
|
except Exception:
|
|
|
|
moderation = None
|
|
|
|
|
|
|
|
try:
|
|
|
|
models = await checks.client.test_models()
|
|
|
|
except Exception:
|
|
|
|
models = None
|
|
|
|
|
2023-08-21 20:58:05 +02:00
|
|
|
return {
|
2023-08-23 23:27:09 +02:00
|
|
|
'chat/completions': chat,
|
|
|
|
'models': models,
|
|
|
|
'moderations': moderation,
|
2023-08-21 20:58:05 +02:00
|
|
|
}
|