1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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
|