forked from fediversity/fediversity
		
	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:
		
							parent
							
								
									438f7d280a
								
							
						
					
					
						commit
						981ba011ab
					
				
					 5 changed files with 105 additions and 0 deletions
				
			
		
							
								
								
									
										31
									
								
								panel/src/panel/configuration/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								panel/src/panel/configuration/__init__.py
									
										
									
									
									
										Normal 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") | ||||
							
								
								
									
										19
									
								
								panel/src/panel/configuration/v1.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								panel/src/panel/configuration/v1.py
									
										
									
									
									
										Normal 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" | ||||
|     ) | ||||
							
								
								
									
										26
									
								
								panel/src/panel/migrations/0001_initial.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								panel/src/panel/migrations/0001_initial.py
									
										
									
									
									
										Normal 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)), | ||||
|             ], | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										0
									
								
								panel/src/panel/migrations/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								panel/src/panel/migrations/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
								
								
									
										29
									
								
								panel/src/panel/models.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								panel/src/panel/models.py
									
										
									
									
									
										Normal 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) | ||||
		Loading…
	
	Add table
		
		Reference in a new issue