selfprivacy-rest-api/selfprivacy_api/services/config_item.py

246 lines
7.8 KiB
Python

from abc import ABC, abstractmethod
import re
from typing import Optional
from selfprivacy_api.utils import (
ReadUserData,
WriteUserData,
check_if_subdomain_is_taken,
)
class ServiceConfigItem(ABC):
id: str
description: str
widget: str
type: str
@abstractmethod
def get_value(self, service_id):
pass
@abstractmethod
def set_value(self, value, service_id):
pass
@abstractmethod
def validate_value(self, value):
return True
def as_dict(self, service_options):
return {
"id": self.id,
"type": self.type,
"description": self.description,
"widget": self.widget,
"value": self.get_value(service_options),
}
class StringServiceConfigItem(ServiceConfigItem):
def __init__(
self,
id: str,
default_value: str,
description: str,
regex: Optional[str] = None,
widget: Optional[str] = None,
allow_empty: bool = False,
):
if widget == "subdomain" and not regex:
raise ValueError("Subdomain widget requires regex")
self.id = id
self.type = "string"
self.default_value = default_value
self.description = description
self.regex = re.compile(regex) if regex else None
self.widget = widget if widget else "text"
self.allow_empty = allow_empty
def get_value(self, service_id):
with ReadUserData() as user_data:
if "modules" in user_data and service_id in user_data["modules"]:
return user_data["modules"][service_id].get(self.id, self.default_value)
return self.default_value
def set_value(self, value, service_id):
if not self.validate_value(value):
raise ValueError(f"Value {value} is not valid")
with WriteUserData() as user_data:
if "modules" not in user_data:
user_data["modules"] = {}
if service_id not in user_data["modules"]:
user_data["modules"][service_id] = {}
user_data["modules"][service_id][self.id] = value
def as_dict(self, service_options):
return {
"id": self.id,
"type": self.type,
"description": self.description,
"widget": self.widget,
"value": self.get_value(service_options),
"default_value": self.default_value,
"regex": self.regex.pattern if self.regex else None,
}
def validate_value(self, value):
if not isinstance(value, str):
return False
if not self.allow_empty and not value:
return False
if self.regex and not self.regex.match(value):
return False
if self.widget == "subdomain":
if check_if_subdomain_is_taken(value):
return False
return True
class BoolServiceConfigItem(ServiceConfigItem):
def __init__(
self,
id: str,
default_value: bool,
description: str,
widget: Optional[str] = None,
):
self.id = id
self.type = "bool"
self.default_value = default_value
self.description = description
self.widget = widget if widget else "switch"
def get_value(self, service_id):
with ReadUserData() as user_data:
if "modules" in user_data and service_id in user_data["modules"]:
return user_data["modules"][service_id].get(self.id, self.default_value)
return self.default_value
def set_value(self, value, service_id):
if not self.validate_value(value):
raise ValueError(f"Value {value} is not a boolean")
with WriteUserData() as user_data:
if "modules" not in user_data:
user_data["modules"] = {}
if service_id not in user_data["modules"]:
user_data["modules"][service_id] = {}
user_data["modules"][service_id][self.id] = value
def as_dict(self, service_options):
return {
"id": self.id,
"type": self.type,
"description": self.description,
"widget": self.widget,
"value": self.get_value(service_options),
"default_value": self.default_value,
}
def validate_value(self, value):
return isinstance(value, bool)
class EnumServiceConfigItem(ServiceConfigItem):
def __init__(
self,
id: str,
default_value: str,
description: str,
options: list[str],
widget: Optional[str] = None,
):
self.id = id
self.type = "enum"
self.default_value = default_value
self.description = description
self.options = options
self.widget = widget if widget else "select"
def get_value(self, service_id):
with ReadUserData() as user_data:
if "modules" in user_data and service_id in user_data["modules"]:
return user_data["modules"][service_id].get(self.id, self.default_value)
return self.default_value
def set_value(self, value, service_id):
if not self.validate_value(value):
raise ValueError(f"Value {value} is not in options")
with WriteUserData() as user_data:
if "modules" not in user_data:
user_data["modules"] = {}
if service_id not in user_data["modules"]:
user_data["modules"][service_id] = {}
user_data["modules"][service_id][self.id] = value
def as_dict(self, service_options):
return {
"id": self.id,
"type": self.type,
"description": self.description,
"widget": self.widget,
"value": self.get_value(service_options),
"default_value": self.default_value,
"options": self.options,
}
def validate_value(self, value):
if not isinstance(value, str):
return False
return value in self.options
# TODO: unused for now
class IntServiceConfigItem(ServiceConfigItem):
def __init__(
self,
id: str,
default_value: int,
description: str,
widget: Optional[str] = None,
min_value: Optional[int] = None,
max_value: Optional[int] = None,
) -> None:
self.id = id
self.type = "int"
self.default_value = default_value
self.description = description
self.widget = widget if widget else "number"
self.min_value = min_value
self.max_value = max_value
def get_value(self, service_id):
with ReadUserData() as user_data:
if "modules" in user_data and service_id in user_data["modules"]:
return user_data["modules"][service_id].get(self.id, self.default_value)
return self.default_value
def set_value(self, value, service_id):
if not self.validate_value(value):
raise ValueError(f"Value {value} is not valid")
with WriteUserData() as user_data:
if "modules" not in user_data:
user_data["modules"] = {}
if service_id not in user_data["modules"]:
user_data["modules"][service_id] = {}
user_data["modules"][service_id][self.id] = value
def as_dict(self, service_options):
return {
"id": self.id,
"type": self.type,
"description": self.description,
"widget": self.widget,
"value": self.get_value(service_options),
"default_value": self.default_value,
"min_value": self.min_value,
"max_value": self.max_value,
}
def validate_value(self, value):
if not isinstance(value, int):
return False
return (self.min_value is None or value >= self.min_value) and (
self.max_value is None or value <= self.max_value
)