commit b5727508bbbab5e2df855b44df11223520da451c Author: trinkey Date: Fri Dec 20 21:18:31 2024 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f8a110f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__/ +message.sqlite3 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..bda2103 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,7 @@ +{ + "cSpell.words": [ + "corsheaders", + "TAUTH", + "TCOMMON" + ] +} diff --git a/config.py b/config.py new file mode 100644 index 0000000..24633b2 --- /dev/null +++ b/config.py @@ -0,0 +1,19 @@ +from typing import Literal + +DEBUG = True + +# DON'T PUT A TRAILING SLASH ON URLS! +# Use a local url for faster communication for INTERNAL urls. +# --------------------------------------- +tCOMMON_URL_PUBLIC = "http://localhost:8888" +tCOMMON_URL_INTERNAL = "http://localhost:8888" + +# This token should match the tokens set in the config.py files for other services +tCOMMON_TOKEN = "Secret tCommon-specific token" + +ENABLED_APPLICATIONS: dict[str, Literal[False] | None | tuple[str, str, str]] = { +# The tokens set here should match the tokens in other services. If they don't, the service will refuse to start. +# "service": ("token", "internal_url", "public_url") + "auth": ("Secret tAuth-specific token", "http://localhost:8000", "http://localhost:8000"), + "message": ("Secret tMessage-specific token", "http://localhost:8001", "http://localhost:8001") +} diff --git a/manage.py b/manage.py new file mode 100755 index 0000000..3abf1a0 --- /dev/null +++ b/manage.py @@ -0,0 +1,14 @@ +import os +import sys + + +def main(): + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tcommon.settings") + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError("Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?") from exc + execute_from_command_line(sys.argv) + +if __name__ == "__main__": + main() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a1c7a40 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +django +django-cors-headers +requests diff --git a/tcommon/__init__.py b/tcommon/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tcommon/asgi.py b/tcommon/asgi.py new file mode 100644 index 0000000..c58516d --- /dev/null +++ b/tcommon/asgi.py @@ -0,0 +1,6 @@ +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tcommon.settings") +application = get_asgi_application() diff --git a/tcommon/settings.py b/tcommon/settings.py new file mode 100644 index 0000000..fda5e7e --- /dev/null +++ b/tcommon/settings.py @@ -0,0 +1,37 @@ +from pathlib import Path + +from config import DEBUG # noqa: F401 +from config import tCOMMON_TOKEN as SECRET_KEY # noqa: F401 + +BASE_DIR = Path(__file__).resolve().parent.parent + +STATIC_DIR = BASE_DIR / "tcommon/static" +ALLOWED_HOSTS = ["*"] + +INSTALLED_APPS = [ + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "corsheaders" +] + +MIDDLEWARE = [ + "corsheaders.middleware.CorsMiddleware", + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware" +] + +ROOT_URLCONF = "tcommon.urls" +WSGI_APPLICATION = "tcommon.wsgi.application" +LANGUAGE_CODE = "en-us" +TIME_ZONE = "UTC" +USE_I18N = True +USE_TZ = True + +CORS_ALLOW_ALL_ORIGINS = True +CORS_URLS_REGEX = r"^/static/.+$" diff --git a/tcommon/static/css/base.css b/tcommon/static/css/base.css new file mode 100644 index 0000000..e199477 --- /dev/null +++ b/tcommon/static/css/base.css @@ -0,0 +1,101 @@ +/* Colors */ +html { --rosewater: #f5e0dc; --flamingo: #f2cdcd; --pink: #f5c2e7; --mauve: #cba6f7; --red: #f38ba8; --maroon: #eba0ac; --peach: #fab387; --yellow: #f9e2af; --green: #a6e3a1; --teal: #94e2d5; --sky: #89dceb; --sapphire: #74c7ec; --blue: #89b4fa; --lavender: #b4befe; --text: #cdd6f4; --subtext1: #bac2de; --subtext0: #a6adc8; --overlay2: #9399b2; --overlay1: #7f849c; --overlay0: #6c7086; --surface2: #585b70; --surface1: #45475a; --surface0: #313244; --base: #1e1e2e; --mantle: #181825; --crust: #11111b; --base-low-op: #1e1e2ed0 } +html[data-light] { --rosewater: #dc8a78; --flamingo: #dd7878; --pink: #ea76cb; --mauve: #8839ef; --red: #d20f39; --maroon: #e64553; --peach: #fe640b; --yellow: #df8e1d; --green: #40a02b; --teal: #179299; --sky: #04a5e5; --sapphire: #209fb5; --blue: #1e66f5; --lavender: #7287fd; --text: #4c4f69; --subtext1: #5c5f77; --subtext0: #6c6f85; --overlay2: #7c7f93; --overlay1: #8c8fa1; --overlay0: #9ca0b0; --surface2: #acb0be; --surface1: #bcc0cc; --surface0: #ccd0da; --base: #eff1f5; --mantle: #e6e9ef; --crust: #dce0e8; --base-low-op: #eff1f5b0} + +/* Font */ +@font-face { font-family: 'DejaVu Sans'; font-style: normal; font-weight: 400; font-display: block; src: url("/static/font/DejaVuSans.ttf") format("truetype"); } +@font-face { font-family: 'DejaVu Sans'; font-style: normal; font-weight: 700; font-display: block; src: url("/static/font/DejaVuSans-Bold.ttf") format("truetype"); } +@font-face { font-family: 'DejaVu Sans'; font-style: italic; font-weight: 400; font-display: block; src: url("/static/font/DejaVuSans-Oblique.ttf") format("truetype"); } +@font-face { font-family: 'DejaVu Sans'; font-style: italic; font-weight: 700; font-display: block; src: url("/static/font/DejaVuSans-BoldOblique.ttf") format("truetype"); } +@font-face { font-family: 'DejaVu Sans'; font-style: normal; font-weight: 200; font-display: block; src: url("/static/font/DejaVuSans-ExtraLight.ttf") format("truetype"); } +@font-face { font-family: "Ubuntu Mono"; font-style: normal; font-weight: 400; font-display: block; src: url("/static/font/UbuntuMono-Regular.ttf") format("truetype"); } +@font-face { font-family: "Ubuntu Mono"; font-style: italic; font-weight: 400; font-display: block; src: url("/static/font/UbuntuMono-Italic.ttf") format("truetype"); } +@font-face { font-family: "Ubuntu Mono"; font-style: normal; font-weight: 700; font-display: block; src: url("/static/font/UbuntuMono-Bold.ttf") format("truetype"); } +@font-face { font-family: "Ubuntu Mono"; font-style: italic; font-weight: 700; font-display: block; src: url("/static/font/UbuntuMono-BoldItalic.ttf") format("truetype"); } + +body { + margin: 0; + width: 100vw; + min-height: 100vh; + overflow-x: hidden; + background-color: var(--base); + color: var(--text); + font-family: "DejaVu Sans"; + font-size: 18px; +} + +code, pre { + font-family: "Ubuntu Mono" +} + +small, i { + color: var(--subtext0); + font-size: 12px; +} + +h1 { + color: var(--accent); +} + +a:link, +a:visited { + color: var(--accent); + font-weight: 700; +} + +input:not( + [type="submit"] +) { + background-color: var(--mantle); + color: var(--text); + font-family: "DejaVu Sans"; + outline: 1px solid var(--surface0); + padding: 4px 6px; + border: none; + margin: 2px 0; + border-radius: 4px; + transition: outline-color 0.25s, background-color 0.25s; +} + +input:not( + [type="submit"] +):focus { + outline-color: var(--accent); + background-color: var(--crust); + transition: outline-color 0.1s, background-color 0.1s; +} + +input[type="submit"], +button { + background-color: var(--mantle); + color: var(--text); + font-family: "DejaVu Sans"; + outline: 1px solid var(--surface0); + padding: 4px 12px; + min-width: 75px; + border: none; + margin: 2px 0; + border-radius: 8px; + cursor: pointer; + transition: outline-color 0.25s, background-color 0.25s; +} + +input[type="submit"]:focus, +button:focus { + outline-color: var(--accent); + transition: outline-color 0.1s; +} + +input[type="submit"]:active, +button:active { + background-color: var(--crust); + transition: background-color 0.1s; +} + + +#container { + text-align: center; + padding: 10px; + width: calc(100vw - 20px); + max-width: calc(100vw - 20px); +} diff --git a/tcommon/static/font/DejaVuSans-Bold.ttf b/tcommon/static/font/DejaVuSans-Bold.ttf new file mode 100644 index 0000000..06db62c Binary files /dev/null and b/tcommon/static/font/DejaVuSans-Bold.ttf differ diff --git a/tcommon/static/font/DejaVuSans-BoldOblique.ttf b/tcommon/static/font/DejaVuSans-BoldOblique.ttf new file mode 100644 index 0000000..802137f Binary files /dev/null and b/tcommon/static/font/DejaVuSans-BoldOblique.ttf differ diff --git a/tcommon/static/font/DejaVuSans-ExtraLight.ttf b/tcommon/static/font/DejaVuSans-ExtraLight.ttf new file mode 100644 index 0000000..0c92b97 Binary files /dev/null and b/tcommon/static/font/DejaVuSans-ExtraLight.ttf differ diff --git a/tcommon/static/font/DejaVuSans-Oblique.ttf b/tcommon/static/font/DejaVuSans-Oblique.ttf new file mode 100644 index 0000000..6c5e38a Binary files /dev/null and b/tcommon/static/font/DejaVuSans-Oblique.ttf differ diff --git a/tcommon/static/font/DejaVuSans.ttf b/tcommon/static/font/DejaVuSans.ttf new file mode 100644 index 0000000..2fbbe69 Binary files /dev/null and b/tcommon/static/font/DejaVuSans.ttf differ diff --git a/tcommon/static/font/UbuntuMono-Bold.ttf b/tcommon/static/font/UbuntuMono-Bold.ttf new file mode 100644 index 0000000..01ad81b Binary files /dev/null and b/tcommon/static/font/UbuntuMono-Bold.ttf differ diff --git a/tcommon/static/font/UbuntuMono-BoldItalic.ttf b/tcommon/static/font/UbuntuMono-BoldItalic.ttf new file mode 100644 index 0000000..731884e Binary files /dev/null and b/tcommon/static/font/UbuntuMono-BoldItalic.ttf differ diff --git a/tcommon/static/font/UbuntuMono-Italic.ttf b/tcommon/static/font/UbuntuMono-Italic.ttf new file mode 100644 index 0000000..b89338d Binary files /dev/null and b/tcommon/static/font/UbuntuMono-Italic.ttf differ diff --git a/tcommon/static/font/UbuntuMono-Regular.ttf b/tcommon/static/font/UbuntuMono-Regular.ttf new file mode 100644 index 0000000..4977028 Binary files /dev/null and b/tcommon/static/font/UbuntuMono-Regular.ttf differ diff --git a/tcommon/static/js/theme.js b/tcommon/static/js/theme.js new file mode 100644 index 0000000..e0fd755 --- /dev/null +++ b/tcommon/static/js/theme.js @@ -0,0 +1,30 @@ +let _themeMM = matchMedia("(prefers-color-scheme: light)"); +let light, useAutoTheme; +// {% if theme == "auto" %} + light = _themeMM.matches; + useAutoTheme = true; +// {% else %} + // {% if theme == "light" %} + light = true; + // {% else %} + light = false; + // {% endif %} + useAutoTheme = false; +// {% endif %} + +function setTheme() { + if (light) { + document.documentElement.setAttribute("data-light", ""); + } else { + document.documentElement.removeAttribute("data-light"); + } +} + +_themeMM.addEventListener("change", function() { + if (useAutoTheme) { + light = _themeMM.matches; + setTheme(); + } +}); + +setTheme(); diff --git a/tcommon/urls.py b/tcommon/urls.py new file mode 100644 index 0000000..deebf4d --- /dev/null +++ b/tcommon/urls.py @@ -0,0 +1,8 @@ +from django.urls import include, path + +from .views import initialize + +urlpatterns = [ + path("api/initialize/", initialize), + path("static/", include("tcommon.views.static")) +] diff --git a/tcommon/views/__init__.py b/tcommon/views/__init__.py new file mode 100644 index 0000000..f3ad99a --- /dev/null +++ b/tcommon/views/__init__.py @@ -0,0 +1 @@ +from .api import initialize # noqa: F401 diff --git a/tcommon/views/api.py b/tcommon/views/api.py new file mode 100644 index 0000000..4aa19dd --- /dev/null +++ b/tcommon/views/api.py @@ -0,0 +1,52 @@ +import json + +from django.core.handlers.wsgi import WSGIRequest +from django.http import HttpResponse + +from config import (DEBUG, ENABLED_APPLICATIONS, tCOMMON_TOKEN, + tCOMMON_URL_INTERNAL, tCOMMON_URL_PUBLIC) + + +def initialize(request: WSGIRequest) -> HttpResponse: + if request.GET.get("token") != tCOMMON_TOKEN: + return HttpResponse( + json.dumps({ + "success": False + }), + content_type="application/json", + status=401 + ) + + resp = { + "debug": DEBUG, + "success": True, + "services": { + "common": { + "url": { + "pub": tCOMMON_URL_PUBLIC, + "int": tCOMMON_URL_INTERNAL + }, + "token": tCOMMON_TOKEN + } + } + } + + for service in [ + "auth", "message" + ]: + if service in ENABLED_APPLICATIONS and isinstance(s := ENABLED_APPLICATIONS[service], tuple): + resp["services"][service] = { + "url": { + "pub": s[2], + "int": s[1], + }, + "token": s[0] + } + else: + resp["services"][service] = None + + return HttpResponse( + json.dumps(resp), + content_type="application/json", + status=200 + ) diff --git a/tcommon/views/static.py b/tcommon/views/static.py new file mode 100644 index 0000000..90e1fbe --- /dev/null +++ b/tcommon/views/static.py @@ -0,0 +1,35 @@ +from django.http import HttpResponse +from django.urls import path + +from tcommon.settings import STATIC_DIR + + +def get_static_serve(path: str, content_type: str): + def x(request): + return HttpResponse( + open(STATIC_DIR / path, "rb").read(), + content_type=content_type + ) + + x.__name__ = path + return x + +file_associations = { + "js": "text/javascript", + "css": "text/css", + "ttf": "font/ttf" +} + +urlpatterns = [path(i, get_static_serve(i, file_associations[i.split(".")[-1]])) for i in [ + "css/base.css", + "js/theme.js", + "font/DejaVuSans-Bold.ttf", + "font/DejaVuSans-BoldItalic.ttf", + "font/DejaVuSans-Italic.ttf", + "font/DejaVuSans-Oblique.ttf", + "font/DejaVuSans.ttf", + "font/UbuntuMono-Bold.ttf", + "font/UbuntuMono-BoldItalic.ttf", + "font/UbuntuMono-Italic.ttf", + "font/UbuntuMono-Regular.ttf" +]] diff --git a/tcommon/wsgi.py b/tcommon/wsgi.py new file mode 100644 index 0000000..7d99db7 --- /dev/null +++ b/tcommon/wsgi.py @@ -0,0 +1,6 @@ +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tcommon.settings") +application = get_wsgi_application()