summaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
Diffstat (limited to 'core')
-rw-r--r--core/admin.py8
-rw-r--r--core/config.py20
-rw-r--r--core/context.py7
-rw-r--r--core/migrations/0001_initial.py63
-rw-r--r--core/migrations/__init__.py0
-rw-r--r--core/models/__init__.py1
-rw-r--r--core/models/config.py111
7 files changed, 188 insertions, 22 deletions
diff --git a/core/admin.py b/core/admin.py
new file mode 100644
index 0000000..e4a6ad0
--- /dev/null
+++ b/core/admin.py
@@ -0,0 +1,8 @@
+from django.contrib import admin
+
+from core.models import Config
+
+
+@admin.register(Config)
+class ConfigAdmin(admin.ModelAdmin):
+ list_display = ["id", "key", "user", "identity"]
diff --git a/core/config.py b/core/config.py
deleted file mode 100644
index b9f6878..0000000
--- a/core/config.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import pydantic
-
-
-class Config(pydantic.BaseModel):
-
- # Basic configuration options
- site_name: str = "takahē"
- identity_max_age: int = 24 * 60 * 60
-
- # Cached ORM object storage
- __singleton__ = None
-
- class Config:
- env_prefix = "takahe_"
-
- @classmethod
- def load(cls) -> "Config":
- if cls.__singleton__ is None:
- cls.__singleton__ = cls()
- return cls.__singleton__
diff --git a/core/context.py b/core/context.py
index 17617b9..4346cbb 100644
--- a/core/context.py
+++ b/core/context.py
@@ -1,7 +1,10 @@
-from core.config import Config
+from core.models import Config
def config_context(request):
return {
- "config": Config.load(),
+ "config": Config.load_system(),
+ "config_identity": (
+ Config.load_identity(request.identity) if request.identity else None
+ ),
}
diff --git a/core/migrations/0001_initial.py b/core/migrations/0001_initial.py
new file mode 100644
index 0000000..2c4731f
--- /dev/null
+++ b/core/migrations/0001_initial.py
@@ -0,0 +1,63 @@
+# Generated by Django 4.1.3 on 2022-11-16 21:23
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ("users", "0002_identity_public_key_id"),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name="Config",
+ fields=[
+ (
+ "id",
+ models.BigAutoField(
+ auto_created=True,
+ primary_key=True,
+ serialize=False,
+ verbose_name="ID",
+ ),
+ ),
+ ("key", models.CharField(max_length=500)),
+ ("json", models.JSONField(blank=True, null=True)),
+ (
+ "image",
+ models.ImageField(
+ blank=True, null=True, upload_to="config/%Y/%m/%d/"
+ ),
+ ),
+ (
+ "identity",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="configs",
+ to="users.identity",
+ ),
+ ),
+ (
+ "user",
+ models.ForeignKey(
+ blank=True,
+ null=True,
+ on_delete=django.db.models.deletion.CASCADE,
+ related_name="configs",
+ to=settings.AUTH_USER_MODEL,
+ ),
+ ),
+ ],
+ options={
+ "unique_together": {("key", "user", "identity")},
+ },
+ ),
+ ]
diff --git a/core/migrations/__init__.py b/core/migrations/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/core/migrations/__init__.py
diff --git a/core/models/__init__.py b/core/models/__init__.py
new file mode 100644
index 0000000..87bfe4e
--- /dev/null
+++ b/core/models/__init__.py
@@ -0,0 +1 @@
+from .config import Config # noqa
diff --git a/core/models/config.py b/core/models/config.py
new file mode 100644
index 0000000..8a2e40b
--- /dev/null
+++ b/core/models/config.py
@@ -0,0 +1,111 @@
+from typing import ClassVar
+
+import pydantic
+from django.db import models
+from django.utils.functional import classproperty
+
+
+class Config(models.Model):
+ """
+ A configuration setting for either the server or a specific user or identity.
+
+ The possible options and their defaults are defined at the bottom of the file.
+ """
+
+ key = models.CharField(max_length=500)
+
+ user = models.ForeignKey(
+ "users.user",
+ blank=True,
+ null=True,
+ related_name="configs",
+ on_delete=models.CASCADE,
+ )
+
+ identity = models.ForeignKey(
+ "users.identity",
+ blank=True,
+ null=True,
+ related_name="configs",
+ on_delete=models.CASCADE,
+ )
+
+ json = models.JSONField(blank=True, null=True)
+ image = models.ImageField(blank=True, null=True, upload_to="config/%Y/%m/%d/")
+
+ class Meta:
+ unique_together = [
+ ("key", "user", "identity"),
+ ]
+
+ @classproperty
+ def system(cls):
+ cls.system = cls.load_system()
+ return cls.system
+
+ system: ClassVar["Config.ConfigOptions"] # type: ignore
+
+ @classmethod
+ def load_system(cls):
+ """
+ Load all of the system config options and return an object with them
+ """
+ values = {}
+ for config in cls.objects.filter(user__isnull=True, identity__isnull=True):
+ values[config.key] = config.image or config.json
+ return cls.SystemOptions(**values)
+
+ @classmethod
+ def load_user(cls, user):
+ """
+ Load all of the user config options and return an object with them
+ """
+ values = {}
+ for config in cls.objects.filter(user=user, identity__isnull=True):
+ values[config.key] = config.image or config.json
+ return cls.UserOptions(**values)
+
+ @classmethod
+ def load_identity(cls, identity):
+ """
+ Load all of the identity config options and return an object with them
+ """
+ values = {}
+ for config in cls.objects.filter(user__isnull=True, identity=identity):
+ values[config.key] = config.image or config.json
+ return cls.IdentityOptions(**values)
+
+ @classmethod
+ def set_system(cls, key, value):
+ config_field = cls.SystemOptions.__fields__[key]
+ if not isinstance(value, config_field.type_):
+ raise ValueError(f"Invalid type for {key}: {type(value)}")
+ cls.objects.update_or_create(
+ key=key,
+ defaults={"json": value},
+ )
+
+ @classmethod
+ def set_identity(cls, identity, key, value):
+ config_field = cls.IdentityOptions.__fields__[key]
+ if not isinstance(value, config_field.type_):
+ raise ValueError(f"Invalid type for {key}: {type(value)}")
+ cls.objects.update_or_create(
+ identity=identity,
+ key=key,
+ defaults={"json": value},
+ )
+
+ class SystemOptions(pydantic.BaseModel):
+
+ site_name: str = "takahē"
+ highlight_color: str = "#449c8c"
+ identity_max_age: int = 24 * 60 * 60
+
+ class UserOptions(pydantic.BaseModel):
+
+ pass
+
+ class IdentityOptions(pydantic.BaseModel):
+
+ toot_mode: bool = False