summaryrefslogtreecommitdiffstats
path: root/core/models/config.py
blob: 8a2e40bb6723b7e4bdc83beb6147b185c4e15114 (plain)
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