diff --git a/src/website/tracker/settings.py b/src/website/tracker/settings.py index 6b9c76d2..df79ebec 100644 --- a/src/website/tracker/settings.py +++ b/src/website/tracker/settings.py @@ -14,14 +14,27 @@ import sys from os import environ as env from pathlib import Path +from typing import Annotated import dj_database_url import sentry_sdk -from pydantic import BaseModel, DirectoryPath, Field +from pydantic import BaseModel, DirectoryPath, Field, PlainSerializer from pydantic_settings import BaseSettings, SettingsConfigDict from sentry_sdk.integrations.django import DjangoIntegration +def get_secret(name: str, encoding: str = "utf-8") -> str: + credentials_dir = Secrets().CREDENTIALS_DIRECTORY # type: ignore[reportCallIssue] + + try: + with open(f"{credentials_dir}/{name}", encoding=encoding) as f: + secret = f.read().removesuffix("\n") + except FileNotFoundError: + raise RuntimeError(f"No secret named {name} found in {credentials_dir}.") + + return secret + + class Secrets(BaseSettings): CREDENTIALS_DIRECTORY: DirectoryPath @@ -90,32 +103,43 @@ class DjangoSettings(BaseModel): default=[], ) - DJANGO_SETTINGS: DjangoSettings + class SocialAccountProviders(BaseModel): + class GitHub(BaseModel): + SCOPE: list[str] = Field( + description="Access scopes required by the application" + ) + class AppSettings(BaseModel): + client_id: Annotated[str, PlainSerializer(get_secret)] + secret: Annotated[str, PlainSerializer(get_secret)] + key: str = "" -for key, value in Settings().dict()["DJANGO_SETTINGS"].items(): # type: ignore[reportCallIssue] - setattr(sys.modules[__name__], key, value) + APPS: list[AppSettings] = [] -# TODO(@fricklerhandwerk): move all configuration over to pydantic-settings + github: GitHub | None -# Build paths inside the project like this: BASE_DIR / 'subdir'. -BASE_DIR = Path(__file__).resolve().parent.parent + _GitHub = SocialAccountProviders.GitHub + _App = SocialAccountProviders.GitHub.AppSettings + SOCIALACCOUNT_PROVIDERS: SocialAccountProviders = SocialAccountProviders( + github=_GitHub( + SCOPE=["read:user", "read:org"], + APPS=[_App(client_id="GH_CLIENT_ID", secret="GH_SECRET")], + ), + ) -def get_secret(name: str, encoding: str = "utf-8") -> str: - credentials_dir = Secrets().CREDENTIALS_DIRECTORY # type: ignore[reportCallIssue] + DJANGO_SETTINGS: DjangoSettings - try: - with open(f"{credentials_dir}/{name}", encoding=encoding) as f: - secret = f.read().removesuffix("\n") - except FileNotFoundError: - raise RuntimeError(f"No secret named {name} found in {credentials_dir}.") - return secret +for key, value in Settings().model_dump()["DJANGO_SETTINGS"].items(): # type: ignore[reportCallIssue] + setattr(sys.modules[__name__], key, value) +# TODO(@fricklerhandwerk): move all configuration over to pydantic-settings -## GlitchTip setup +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent +## GlitchTip setup if "GLITCHTIP_DSN" in env: sentry_sdk.init( dsn=get_secret("GLITCHTIP_DSN"), @@ -312,21 +336,6 @@ def get_secret(name: str, encoding: str = "utf-8") -> str: "allauth.account.auth_backends.AuthenticationBackend", ] -SOCIALACCOUNT_PROVIDERS = { - "github": { - "SCOPE": [ - "read:user", - "read:org", - ], - "APPS": [ - { - "client_id": get_secret("GH_CLIENT_ID"), - "secret": get_secret("GH_SECRET"), - "key": "", - } - ], - } -} REST_FRAMEWORK = { "DEFAULT_FILTER_BACKENDS": ["django_filters.rest_framework.DjangoFilterBackend"]