From 4cdc9f3e08f3e0ab3c710e933c91f401032197ae Mon Sep 17 00:00:00 2001 From: Inex Code Date: Sat, 21 Dec 2024 17:46:28 +0300 Subject: [PATCH] feat: Add support for service options weight --- selfprivacy_api/graphql/common_types/service.py | 5 ++++- selfprivacy_api/services/config_item.py | 14 ++++++++++++++ selfprivacy_api/services/templated_service.py | 8 ++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/selfprivacy_api/graphql/common_types/service.py b/selfprivacy_api/graphql/common_types/service.py index ec81945..0cc39d2 100644 --- a/selfprivacy_api/graphql/common_types/service.py +++ b/selfprivacy_api/graphql/common_types/service.py @@ -207,7 +207,10 @@ class Service: if not config_items: return None # By the "type" field convert every dict into a ConfigItem. In the future there will be more types. - return [config_item_to_graphql(config_items[item]) for item in config_items] + unsorted_config_items = [config_items[item] for item in config_items] + # Sort the items by their weight. If there is no weight, implicitly set it to 50. + config_items = sorted(unsorted_config_items, key=lambda x: x.get("weight", 50)) + return [config_item_to_graphql(item) for item in config_items] # TODO: fill this @strawberry.field diff --git a/selfprivacy_api/services/config_item.py b/selfprivacy_api/services/config_item.py index c65ead4..bb22c57 100644 --- a/selfprivacy_api/services/config_item.py +++ b/selfprivacy_api/services/config_item.py @@ -14,6 +14,7 @@ class ServiceConfigItem(ABC): description: str widget: str type: str + weight: int @abstractmethod def get_value(self, service_id): @@ -34,6 +35,7 @@ class ServiceConfigItem(ABC): "description": self.description, "widget": self.widget, "value": self.get_value(service_id), + "weight": self.weight, } @@ -46,6 +48,7 @@ class StringServiceConfigItem(ServiceConfigItem): regex: Optional[str] = None, widget: Optional[str] = None, allow_empty: bool = False, + weight: int = 50, ): if widget == "subdomain" and not regex: raise ValueError("Subdomain widget requires regex") @@ -56,6 +59,7 @@ class StringServiceConfigItem(ServiceConfigItem): self.regex = re.compile(regex) if regex else None self.widget = widget if widget else "text" self.allow_empty = allow_empty + self.weight = weight def get_value(self, service_id): with ReadUserData() as user_data: @@ -82,6 +86,7 @@ class StringServiceConfigItem(ServiceConfigItem): "value": self.get_value(service_id), "default_value": self.default_value, "regex": self.regex.pattern if self.regex else None, + "weight": self.weight, } def validate_value(self, value): @@ -104,12 +109,14 @@ class BoolServiceConfigItem(ServiceConfigItem): default_value: bool, description: str, widget: Optional[str] = None, + weight: int = 50, ): self.id = id self.type = "bool" self.default_value = default_value self.description = description self.widget = widget if widget else "switch" + self.weight = weight def get_value(self, service_id): with ReadUserData() as user_data: @@ -135,6 +142,7 @@ class BoolServiceConfigItem(ServiceConfigItem): "widget": self.widget, "value": self.get_value(service_id), "default_value": self.default_value, + "weight": self.weight, } def validate_value(self, value): @@ -149,6 +157,7 @@ class EnumServiceConfigItem(ServiceConfigItem): description: str, options: list[str], widget: Optional[str] = None, + weight: int = 50, ): self.id = id self.type = "enum" @@ -156,6 +165,7 @@ class EnumServiceConfigItem(ServiceConfigItem): self.description = description self.options = options self.widget = widget if widget else "select" + self.weight = weight def get_value(self, service_id): with ReadUserData() as user_data: @@ -182,6 +192,7 @@ class EnumServiceConfigItem(ServiceConfigItem): "value": self.get_value(service_id), "default_value": self.default_value, "options": self.options, + "weight": self.weight, } def validate_value(self, value): @@ -200,6 +211,7 @@ class IntServiceConfigItem(ServiceConfigItem): widget: Optional[str] = None, min_value: Optional[int] = None, max_value: Optional[int] = None, + weight: int = 50, ) -> None: self.id = id self.type = "int" @@ -208,6 +220,7 @@ class IntServiceConfigItem(ServiceConfigItem): self.widget = widget if widget else "number" self.min_value = min_value self.max_value = max_value + self.weight = weight def get_value(self, service_id): with ReadUserData() as user_data: @@ -235,6 +248,7 @@ class IntServiceConfigItem(ServiceConfigItem): "default_value": self.default_value, "min_value": self.min_value, "max_value": self.max_value, + "weight": self.weight, } def validate_value(self, value): diff --git a/selfprivacy_api/services/templated_service.py b/selfprivacy_api/services/templated_service.py index 20549a3..ad1fc75 100644 --- a/selfprivacy_api/services/templated_service.py +++ b/selfprivacy_api/services/templated_service.py @@ -245,6 +245,7 @@ class SupportLevel(Enum): def config_item_from_json(json_data: dict) -> Optional[ServiceConfigItem]: """Create a ServiceConfigItem from JSON data.""" + weight = json_data.get("meta", {}).get("weight", 50) if json_data["meta"]["type"] == "enable": return None if json_data["meta"]["type"] == "location": @@ -257,6 +258,7 @@ def config_item_from_json(json_data: dict) -> Optional[ServiceConfigItem]: regex=json_data["meta"].get("regex"), widget=json_data["meta"].get("widget"), allow_empty=json_data["meta"].get("allowEmpty", False), + weight=weight, ) if json_data["meta"]["type"] == "bool": return BoolServiceConfigItem( @@ -264,6 +266,7 @@ def config_item_from_json(json_data: dict) -> Optional[ServiceConfigItem]: default_value=json_data["default"], description=json_data["description"], widget=json_data["meta"].get("widget"), + weight=weight, ) if json_data["meta"]["type"] == "enum": return EnumServiceConfigItem( @@ -272,6 +275,7 @@ def config_item_from_json(json_data: dict) -> Optional[ServiceConfigItem]: description=json_data["description"], options=json_data["meta"]["options"], widget=json_data["meta"].get("widget"), + weight=weight, ) if json_data["meta"]["type"] == "int": return IntServiceConfigItem( @@ -281,6 +285,7 @@ def config_item_from_json(json_data: dict) -> Optional[ServiceConfigItem]: widget=json_data["meta"].get("widget"), min_value=json_data["meta"].get("minValue"), max_value=json_data["meta"].get("maxValue"), + weight=weight, ) raise ValueError("Unknown config item type") @@ -493,6 +498,9 @@ class TemplatedService(Service): subprocess.run(["systemctl", "restart", unit], check=False) def get_configuration(self) -> dict: + # If there are no options, return an empty dict + if not self.config_items: + return {} return { key: self.config_items[key].as_dict(self.get_id()) for key in self.config_items