1
0
Fork 0

store versioned configurations

Test manually:

```shell-session
$ manage shell
>>> from panel.models import Configuration
>>> Configuration().value
'{"enable":false,"domain":"fediversity.eu"}'
>>> Configuration().save()
>>> Configuration.objects.first().parsed_value
Configuration(enable=False, domain=<Domain.EU: 'fediversity.eu'>)
```
This commit is contained in:
Valentin Gagarin 2025-03-05 09:25:48 +01:00
parent 438f7d280a
commit 981ba011ab
5 changed files with 105 additions and 0 deletions
panel/src/panel

View file

@ -0,0 +1,31 @@
import os
import re
import sys
from importlib import import_module
from importlib.util import find_spec
from django.utils.functional import classproperty
from django.apps import apps
from django.db import models
class Version():
model: models.Model
@classproperty
def latest(cls):
current_dir = os.path.dirname(os.path.abspath(__file__))
version_pattern = re.compile(r'v(\d+)\.py$')
versions = []
for filename in os.listdir(current_dir):
match = version_pattern.match(filename)
if match:
versions.append(int(match.group(1)))
return max(versions)
def __init__(self, version: int):
module = import_module(f"{__name__}.v{version}")
self.model = getattr(module, "Configuration")

View file

@ -0,0 +1,19 @@
from pydantic import BaseModel, Field
from enum import Enum
class Configuration(BaseModel):
enable: bool = Field(
default=False,
description="Enable the configuration",
)
# XXX: hard-code available apex domains for now,
# they will be prefixed by the user name
class Domain(Enum):
EU = "fediversity.eu"
NET = "fediversity.net"
domain: Domain = Field(
default=Domain.EU,
description="DNS domain where to expose services"
)

View file

@ -0,0 +1,26 @@
# Generated by Django 4.2.16 on 2025-03-05 08:25
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Configuration',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('version', models.PositiveIntegerField(default=1, help_text='Configuration schema version')),
('value', models.JSONField(help_text='Stored configuration value', null=True)),
('operator', models.ForeignKey(help_text='Operator who owns the configuration', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='configurations', to=settings.AUTH_USER_MODEL)),
],
),
]

View file

29
panel/src/panel/models.py Normal file
View file

@ -0,0 +1,29 @@
from django.db import models
from django.contrib.auth.models import User
from panel.configuration import Version
from pydantic import BaseModel
class Configuration(models.Model):
operator = models.ForeignKey(
User,
on_delete=models.SET_NULL,
null=True,
related_name="configurations",
help_text="Operator who owns the configuration",
)
version = models.PositiveIntegerField(
help_text="Configuration schema version",
default=Version.latest,
)
value = models.JSONField(
help_text="Stored configuration value",
default=Version(Version.latest).model().model_dump_json,
)
@property
def parsed_value(self) -> BaseModel:
return Version(self.version).model.model_validate_json(self.value)