From 00badfbbf87ccc352ae46d8886bb8f2be4b3a5c6 Mon Sep 17 00:00:00 2001 From: inexcode Date: Sat, 13 Aug 2022 01:29:18 +0400 Subject: [PATCH] Add some services endpoints --- selfprivacy_api/app.py | 1 + selfprivacy_api/graphql/common_types/dns.py | 13 ++ .../graphql/common_types/storage_usage.py | 24 ++++ .../graphql/queries/api_queries.py | 3 +- selfprivacy_api/graphql/queries/jobs.py | 45 +++++++ selfprivacy_api/graphql/queries/services.py | 117 ++++++++++++++++++ selfprivacy_api/graphql/queries/storage.py | 16 +-- selfprivacy_api/graphql/queries/system.py | 12 +- selfprivacy_api/graphql/schema.py | 15 ++- .../graphql/subscriptions/__init__.py | 0 selfprivacy_api/graphql/subscriptions/jobs.py | 76 ------------ selfprivacy_api/jobs/test.py | 4 +- selfprivacy_api/restic_controller/tasks.py | 4 +- selfprivacy_api/services/__init__.py | 39 ++++++ .../services/bitwarden/__init__.py | 12 +- .../services/generic_service_mover.py | 6 +- selfprivacy_api/services/gitea/__init__.py | 14 ++- .../services/mailserver/__init__.py | 9 +- .../services/nextcloud/__init__.py | 10 +- selfprivacy_api/services/ocserv/__init__.py | 9 ++ selfprivacy_api/services/pleroma/__init__.py | 8 +- selfprivacy_api/services/service.py | 5 + selfprivacy_api/utils/huey.py | 10 +- 23 files changed, 314 insertions(+), 138 deletions(-) create mode 100644 selfprivacy_api/graphql/common_types/dns.py create mode 100644 selfprivacy_api/graphql/common_types/storage_usage.py create mode 100644 selfprivacy_api/graphql/queries/jobs.py create mode 100644 selfprivacy_api/graphql/queries/services.py delete mode 100644 selfprivacy_api/graphql/subscriptions/__init__.py delete mode 100644 selfprivacy_api/graphql/subscriptions/jobs.py diff --git a/selfprivacy_api/app.py b/selfprivacy_api/app.py index 3a73346..b5ed512 100644 --- a/selfprivacy_api/app.py +++ b/selfprivacy_api/app.py @@ -52,5 +52,6 @@ async def startup(): run_migrations() init_restic() + if __name__ == "__main__": uvicorn.run("selfprivacy_api.app:app", host="0.0.0.0", port=5050, log_level="info") diff --git a/selfprivacy_api/graphql/common_types/dns.py b/selfprivacy_api/graphql/common_types/dns.py new file mode 100644 index 0000000..c9f8413 --- /dev/null +++ b/selfprivacy_api/graphql/common_types/dns.py @@ -0,0 +1,13 @@ +import typing +import strawberry + + +@strawberry.type +class DnsRecord: + """DNS record""" + + record_type: str + name: str + content: str + ttl: int + priority: typing.Optional[int] diff --git a/selfprivacy_api/graphql/common_types/storage_usage.py b/selfprivacy_api/graphql/common_types/storage_usage.py new file mode 100644 index 0000000..f45966e --- /dev/null +++ b/selfprivacy_api/graphql/common_types/storage_usage.py @@ -0,0 +1,24 @@ +import typing +import strawberry + + +@strawberry.type +class StorageVolume: + """Stats and basic info about a volume or a system disk.""" + + total_space: str + free_space: str + used_space: str + root: bool + name: str + model: typing.Optional[str] + serial: typing.Optional[str] + type: str + usages: list["StorageUsageInterface"] + + +@strawberry.interface +class StorageUsageInterface: + used_space: str + volume: typing.Optional[StorageVolume] + title: str diff --git a/selfprivacy_api/graphql/queries/api_queries.py b/selfprivacy_api/graphql/queries/api_queries.py index ccdf89f..cbe7690 100644 --- a/selfprivacy_api/graphql/queries/api_queries.py +++ b/selfprivacy_api/graphql/queries/api_queries.py @@ -7,6 +7,7 @@ from strawberry.types import Info from selfprivacy_api.actions.api_tokens import get_api_tokens_with_caller_flag from selfprivacy_api.graphql import IsAuthenticated from selfprivacy_api.utils import parse_date +from selfprivacy_api.dependencies import get_api_version as get_api_version_dependency from selfprivacy_api.utils.auth import ( get_recovery_token_status, @@ -17,7 +18,7 @@ from selfprivacy_api.utils.auth import ( def get_api_version() -> str: """Get API version""" - return "1.2.7" + return get_api_version_dependency() @strawberry.type diff --git a/selfprivacy_api/graphql/queries/jobs.py b/selfprivacy_api/graphql/queries/jobs.py new file mode 100644 index 0000000..4d2a3eb --- /dev/null +++ b/selfprivacy_api/graphql/queries/jobs.py @@ -0,0 +1,45 @@ +"""Jobs status""" +# pylint: disable=too-few-public-methods +import typing +import strawberry +import datetime + +from selfprivacy_api.jobs import Jobs + + +@strawberry.type +class ApiJob: + name: str + description: str + status: str + status_text: typing.Optional[str] + progress: typing.Optional[int] + created_at: datetime.datetime + updated_at: datetime.datetime + finished_at: typing.Optional[datetime.datetime] + error: typing.Optional[str] + result: typing.Optional[str] + + +@strawberry.type +class Job: + @strawberry.field + def get_jobs(self) -> typing.List[ApiJob]: + + Jobs.get_instance().get_jobs() + + return [ + ApiJob( + name=job.name, + description=job.description, + status=job.status.name, + status_text=job.status_text, + progress=job.progress, + created_at=job.created_at, + updated_at=job.updated_at, + finished_at=job.finished_at, + error=job.error, + result=job.result, + ) + for job in Jobs.get_instance().get_jobs() + ] diff --git a/selfprivacy_api/graphql/queries/services.py b/selfprivacy_api/graphql/queries/services.py new file mode 100644 index 0000000..f5c6fff --- /dev/null +++ b/selfprivacy_api/graphql/queries/services.py @@ -0,0 +1,117 @@ +"""Services status""" +# pylint: disable=too-few-public-methods +from enum import Enum +import typing +import strawberry +import datetime + +from selfprivacy_api.graphql.common_types.dns import DnsRecord +from selfprivacy_api.graphql.common_types.storage_usage import ( + StorageUsageInterface, + StorageVolume, +) +from selfprivacy_api.services import get_all_services, get_service_by_id +from selfprivacy_api.services import Service as ServiceInterface +from selfprivacy_api.utils.block_devices import BlockDevices + + +@strawberry.enum +class ServiceStatusEnum(Enum): + RUNNING = "RUNNING" + DEGRADED = "DEGRADED" + ERROR = "ERROR" + STOPPED = "STOPPED" + OFF = "OFF" + + +@strawberry.type +class ServiceStorageUsage(StorageUsageInterface): + """Storage usage for a service""" + + service: typing.Optional["Service"] + + +def get_storage_usage(root: "Service") -> ServiceStorageUsage: + """Get storage usage for a service""" + service = get_service_by_id(root.id) + if service is None: + return ServiceStorageUsage( + service=service, + title="Not found", + used_space="0", + volume=get_volume_by_id("sda1"), + ) + return ServiceStorageUsage( + service=service_to_graphql_service(service), + title=service.get_display_name(), + used_space=str(service.get_storage_usage()), + volume=get_volume_by_id(service.get_location()), + ) + + +@strawberry.type +class Service: + storage_usage: ServiceStorageUsage = strawberry.field(resolver=get_storage_usage) + id: str + display_name: str + description: str + svg_icon: str + is_movable: bool + is_required: bool + is_enabled: bool + status: ServiceStatusEnum + url: typing.Optional[str] + dns_records: typing.Optional[typing.List[DnsRecord]] + + +def service_to_graphql_service(service: ServiceInterface) -> Service: + """Convert service to graphql service""" + return Service( + id=service.get_id(), + display_name=service.get_display_name(), + description=service.get_description(), + svg_icon=service.get_svg_icon(), + is_movable=service.is_movable(), + is_required=service.is_required(), + is_enabled=service.is_enabled(), + status=ServiceStatusEnum(service.get_status().value), + url=service.get_url(), + dns_records=[ + DnsRecord( + record_type=record.type, + name=record.name, + content=record.content, + ttl=record.ttl, + priority=record.priority, + ) + for record in service.get_dns_records() + ], + ) + + +def get_volume_by_id(volume_id: str) -> typing.Optional[StorageVolume]: + """Get volume by id""" + volume = BlockDevices().get_block_device(volume_id) + if volume is None: + return None + return StorageVolume( + total_space=str(volume.fssize) + if volume.fssize is not None + else str(volume.size), + free_space=str(volume.fsavail), + used_space=str(volume.fsused), + root=volume.name == "sda1", + name=volume.name, + model=volume.model, + serial=volume.serial, + type=volume.type, + usages=[], + ) + + +@strawberry.type +class Services: + @strawberry.field + def all_services(self, info) -> typing.List[Service]: + services = get_all_services() + return [service_to_graphql_service(service) for service in services] diff --git a/selfprivacy_api/graphql/queries/storage.py b/selfprivacy_api/graphql/queries/storage.py index 6315b26..fcff066 100644 --- a/selfprivacy_api/graphql/queries/storage.py +++ b/selfprivacy_api/graphql/queries/storage.py @@ -2,23 +2,10 @@ # pylint: disable=too-few-public-methods import typing import strawberry +from selfprivacy_api.graphql.common_types.storage_usage import StorageVolume from selfprivacy_api.utils.block_devices import BlockDevices -@strawberry.type -class StorageVolume: - """Stats and basic info about a volume or a system disk.""" - - total_space: str - free_space: str - used_space: str - root: bool - name: str - model: typing.Optional[str] - serial: typing.Optional[str] - type: str - - @strawberry.type class Storage: """GraphQL queries to get storage information.""" @@ -38,6 +25,7 @@ class Storage: model=volume.model, serial=volume.serial, type=volume.type, + usages=[], ) for volume in BlockDevices().get_block_devices() ] diff --git a/selfprivacy_api/graphql/queries/system.py b/selfprivacy_api/graphql/queries/system.py index decb3f0..2997292 100644 --- a/selfprivacy_api/graphql/queries/system.py +++ b/selfprivacy_api/graphql/queries/system.py @@ -2,6 +2,7 @@ # pylint: disable=too-few-public-methods import typing import strawberry +from selfprivacy_api.graphql.common_types.dns import DnsRecord from selfprivacy_api.graphql.queries.common import Alert, Severity from selfprivacy_api.graphql.queries.providers import DnsProvider, ServerProvider @@ -10,17 +11,6 @@ import selfprivacy_api.actions.system as system_actions import selfprivacy_api.actions.ssh as ssh_actions -@strawberry.type -class DnsRecord: - """DNS record""" - - recordType: str - name: str - content: str - ttl: int - priority: typing.Optional[int] - - @strawberry.type class SystemDomainInfo: """Information about the system domain""" diff --git a/selfprivacy_api/graphql/schema.py b/selfprivacy_api/graphql/schema.py index 03d8021..aa7a6a4 100644 --- a/selfprivacy_api/graphql/schema.py +++ b/selfprivacy_api/graphql/schema.py @@ -10,12 +10,13 @@ from selfprivacy_api.graphql.mutations.storage_mutation import StorageMutations from selfprivacy_api.graphql.mutations.system_mutations import SystemMutations from selfprivacy_api.graphql.queries.api_queries import Api +from selfprivacy_api.graphql.queries.jobs import Job +from selfprivacy_api.graphql.queries.services import Services from selfprivacy_api.graphql.queries.storage import Storage from selfprivacy_api.graphql.queries.system import System from selfprivacy_api.graphql.mutations.users_mutations import UserMutations from selfprivacy_api.graphql.queries.users import Users -from selfprivacy_api.graphql.subscriptions.jobs import JobSubscription from selfprivacy_api.jobs.test import test_job @@ -43,6 +44,16 @@ class Query: """Storage queries""" return Storage() + @strawberry.field(permission_classes=[IsAuthenticated]) + def jobs(self) -> Job: + """Jobs queries""" + return Job() + + @strawberry.field(permission_classes=[IsAuthenticated]) + def services(self) -> Services: + """Services queries""" + return Services() + @strawberry.type class Mutation( @@ -67,4 +78,4 @@ class Mutation( pass -schema = strawberry.Schema(query=Query, mutation=Mutation, subscription=JobSubscription) +schema = strawberry.Schema(query=Query, mutation=Mutation) diff --git a/selfprivacy_api/graphql/subscriptions/__init__.py b/selfprivacy_api/graphql/subscriptions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/selfprivacy_api/graphql/subscriptions/jobs.py b/selfprivacy_api/graphql/subscriptions/jobs.py deleted file mode 100644 index 2dfca07..0000000 --- a/selfprivacy_api/graphql/subscriptions/jobs.py +++ /dev/null @@ -1,76 +0,0 @@ -import asyncio -import datetime -from typing import AsyncGenerator -import typing - -import strawberry -from selfprivacy_api.graphql import IsAuthenticated - -from selfprivacy_api.jobs import Job, Jobs - - -@strawberry.type -class ApiJob: - name: str - description: str - status: str - status_text: typing.Optional[str] - progress: typing.Optional[int] - created_at: datetime.datetime - updated_at: datetime.datetime - finished_at: typing.Optional[datetime.datetime] - error: typing.Optional[str] - result: typing.Optional[str] - - -@strawberry.type -class JobSubscription: - @strawberry.subscription - async def count(self, target: int = 100) -> AsyncGenerator[int, None]: - for i in range(target): - yield i - await asyncio.sleep(0.5) - - @strawberry.subscription() - async def job_subscription(self) -> AsyncGenerator[typing.List[ApiJob], None]: - is_updated = True - - def callback(jobs: typing.List[Job]): - nonlocal is_updated - is_updated = True - - print("Subscribing to job updates...") - Jobs.get_instance().add_observer(callback) - yield [ - ApiJob( - name=job.name, - description=job.description, - status=job.status.name, - status_text=job.status_text, - progress=job.progress, - created_at=job.created_at, - updated_at=job.updated_at, - finished_at=job.finished_at, - error=job.error, - result=job.result, - ) - for job in Jobs.get_instance().get_jobs() - ] - while True: - if is_updated: - is_updated = False - yield [ - ApiJob( - name=job.name, - description=job.description, - status=job.status.name, - status_text=job.status_text, - progress=job.progress, - created_at=job.created_at, - updated_at=job.updated_at, - finished_at=job.finished_at, - error=job.error, - result=job.result, - ) - for job in Jobs.get_instance().get_jobs() - ] diff --git a/selfprivacy_api/jobs/test.py b/selfprivacy_api/jobs/test.py index d07ea6c..f3c03af 100644 --- a/selfprivacy_api/jobs/test.py +++ b/selfprivacy_api/jobs/test.py @@ -1,9 +1,7 @@ import time -from selfprivacy_api.utils.huey import Huey +from selfprivacy_api.utils.huey import huey from selfprivacy_api.jobs import JobStatus, Jobs -huey = Huey() - @huey.task() def test_job(): diff --git a/selfprivacy_api/restic_controller/tasks.py b/selfprivacy_api/restic_controller/tasks.py index 32eb87d..f583d8b 100644 --- a/selfprivacy_api/restic_controller/tasks.py +++ b/selfprivacy_api/restic_controller/tasks.py @@ -1,10 +1,8 @@ """Tasks for the restic controller.""" from huey import crontab -from selfprivacy_api.utils.huey import Huey +from selfprivacy_api.utils.huey import huey from . import ResticController, ResticStates -huey = Huey() - @huey.task() def init_restic(): diff --git a/selfprivacy_api/services/__init__.py b/selfprivacy_api/services/__init__.py index e69de29..fbc2aed 100644 --- a/selfprivacy_api/services/__init__.py +++ b/selfprivacy_api/services/__init__.py @@ -0,0 +1,39 @@ +"""Services module.""" + +import typing +from selfprivacy_api.services.bitwarden import Bitwarden +from selfprivacy_api.services.gitea import Gitea +from selfprivacy_api.services.mailserver import MailServer +from selfprivacy_api.services.nextcloud import Nextcloud +from selfprivacy_api.services.pleroma import Pleroma +from selfprivacy_api.services.ocserv import Ocserv +from selfprivacy_api.services.service import Service + + +services = [ + Bitwarden(), + Gitea(), + MailServer(), + Nextcloud(), + Pleroma(), + Ocserv(), +] + + +def get_all_services() -> typing.List[Service]: + return services + + +def get_service_by_id(service_id: str) -> typing.Optional[Service]: + for service in services: + if service.get_id() == service_id: + return service + return None + + +def get_enabled_services() -> typing.List[Service]: + return [service for service in services if service.is_enabled()] + + +def get_disabled_services() -> typing.List[Service]: + return [service for service in services if not service.is_enabled()] diff --git a/selfprivacy_api/services/bitwarden/__init__.py b/selfprivacy_api/services/bitwarden/__init__.py index 599e0e4..9fe9995 100644 --- a/selfprivacy_api/services/bitwarden/__init__.py +++ b/selfprivacy_api/services/bitwarden/__init__.py @@ -8,13 +8,11 @@ from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move from selfprivacy_api.services.generic_size_counter import get_storage_usage from selfprivacy_api.services.generic_status_getter import get_service_status from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus -from selfprivacy_api.utils import ReadUserData, WriteUserData +from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain from selfprivacy_api.utils.block_devices import BlockDevice -from selfprivacy_api.utils.huey import Huey +from selfprivacy_api.utils.huey import huey from selfprivacy_api.utils.network import get_ip4 -huey = Huey() - class Bitwarden(Service): """Class representing Bitwarden service.""" @@ -40,6 +38,12 @@ class Bitwarden(Service): with open("selfprivacy_api/services/bitwarden/bitwarden.svg", "rb") as f: return base64.b64encode(f.read()).decode("utf-8") + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + domain = get_domain() + return f"https://password.{domain}" + @staticmethod def is_movable() -> bool: return True diff --git a/selfprivacy_api/services/generic_service_mover.py b/selfprivacy_api/services/generic_service_mover.py index 1a9c0ac..6831ed7 100644 --- a/selfprivacy_api/services/generic_service_mover.py +++ b/selfprivacy_api/services/generic_service_mover.py @@ -7,12 +7,10 @@ import shutil from pydantic import BaseModel from selfprivacy_api.jobs import Job, JobStatus, Jobs -from selfprivacy_api.utils.huey import Huey +from selfprivacy_api.utils.huey import huey from selfprivacy_api.utils.block_devices import BlockDevice from selfprivacy_api.utils import ReadUserData, WriteUserData -from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus - -huey = Huey() +from selfprivacy_api.services.service import Service, ServiceStatus class FolderMoveNames(BaseModel): diff --git a/selfprivacy_api/services/gitea/__init__.py b/selfprivacy_api/services/gitea/__init__.py index 9893bc8..ee0a058 100644 --- a/selfprivacy_api/services/gitea/__init__.py +++ b/selfprivacy_api/services/gitea/__init__.py @@ -3,18 +3,16 @@ import base64 import subprocess import typing -from selfprivacy_api.jobs import Job, JobStatus, Jobs +from selfprivacy_api.jobs import Jobs from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move_service from selfprivacy_api.services.generic_size_counter import get_storage_usage from selfprivacy_api.services.generic_status_getter import get_service_status from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus -from selfprivacy_api.utils import ReadUserData, WriteUserData +from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain from selfprivacy_api.utils.block_devices import BlockDevice -from selfprivacy_api.utils.huey import Huey +from selfprivacy_api.utils.huey import huey from selfprivacy_api.utils.network import get_ip4 -huey = Huey() - class Gitea(Service): """Class representing Gitea service""" @@ -40,6 +38,12 @@ class Gitea(Service): with open("selfprivacy_api/services/gitea/gitea.svg", "rb") as f: return base64.b64encode(f.read()).decode("utf-8") + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + domain = get_domain() + return f"https://git.{domain}" + @staticmethod def is_movable() -> bool: return True diff --git a/selfprivacy_api/services/mailserver/__init__.py b/selfprivacy_api/services/mailserver/__init__.py index 3eaf8c6..31e250b 100644 --- a/selfprivacy_api/services/mailserver/__init__.py +++ b/selfprivacy_api/services/mailserver/__init__.py @@ -12,11 +12,9 @@ from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceS from selfprivacy_api.utils import ReadUserData, WriteUserData, get_dkim_key, get_domain from selfprivacy_api.utils import huey from selfprivacy_api.utils.block_devices import BlockDevice -from selfprivacy_api.utils.huey import Huey +from selfprivacy_api.utils.huey import huey from selfprivacy_api.utils.network import get_ip4 -huey = Huey() - class MailServer(Service): """Class representing mail service""" @@ -38,6 +36,11 @@ class MailServer(Service): with open("selfprivacy_api/services/mailserver/mailserver.svg", "rb") as f: return base64.b64encode(f.read()).decode("utf-8") + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + return None + @staticmethod def is_movable() -> bool: return True diff --git a/selfprivacy_api/services/nextcloud/__init__.py b/selfprivacy_api/services/nextcloud/__init__.py index 40eaf7f..99efade 100644 --- a/selfprivacy_api/services/nextcloud/__init__.py +++ b/selfprivacy_api/services/nextcloud/__init__.py @@ -7,7 +7,7 @@ from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move from selfprivacy_api.services.generic_size_counter import get_storage_usage from selfprivacy_api.services.generic_status_getter import get_service_status from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus -from selfprivacy_api.utils import ReadUserData, WriteUserData +from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain from selfprivacy_api.utils.block_devices import BlockDevice from selfprivacy_api.utils.network import get_ip4 @@ -16,7 +16,7 @@ class Nextcloud(Service): """Class representing Nextcloud service.""" @staticmethod - def get_id(self) -> str: + def get_id() -> str: """Return service id.""" return "nextcloud" @@ -36,6 +36,12 @@ class Nextcloud(Service): with open("selfprivacy_api/services/nextcloud/nextcloud.svg", "rb") as f: return base64.b64encode(f.read()).decode("utf-8") + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + domain = get_domain() + return f"https://cloud.{domain}" + @staticmethod def is_movable() -> bool: return True diff --git a/selfprivacy_api/services/ocserv/__init__.py b/selfprivacy_api/services/ocserv/__init__.py index 9f1a9f6..e7bf74b 100644 --- a/selfprivacy_api/services/ocserv/__init__.py +++ b/selfprivacy_api/services/ocserv/__init__.py @@ -32,6 +32,11 @@ class Ocserv(Service): with open("selfprivacy_api/services/ocserv/ocserv.svg", "rb") as f: return base64.b64encode(f.read()).decode("utf-8") + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + return None + @staticmethod def is_movable() -> bool: return False @@ -79,6 +84,10 @@ class Ocserv(Service): def get_configuration(): return {} + @staticmethod + def set_configuration(config_items): + return super().set_configuration(config_items) + @staticmethod def get_logs(): return "" diff --git a/selfprivacy_api/services/pleroma/__init__.py b/selfprivacy_api/services/pleroma/__init__.py index c8b1bd5..97f76f9 100644 --- a/selfprivacy_api/services/pleroma/__init__.py +++ b/selfprivacy_api/services/pleroma/__init__.py @@ -7,7 +7,7 @@ from selfprivacy_api.services.generic_service_mover import FolderMoveNames, move from selfprivacy_api.services.generic_size_counter import get_storage_usage from selfprivacy_api.services.generic_status_getter import get_service_status from selfprivacy_api.services.service import Service, ServiceDnsRecord, ServiceStatus -from selfprivacy_api.utils import ReadUserData, WriteUserData +from selfprivacy_api.utils import ReadUserData, WriteUserData, get_domain from selfprivacy_api.utils.block_devices import BlockDevice from selfprivacy_api.utils.network import get_ip4 @@ -32,6 +32,12 @@ class Pleroma(Service): with open("selfprivacy_api/services/pleroma/pleroma.svg", "rb") as f: return base64.b64encode(f.read()).decode("utf-8") + @staticmethod + def get_url() -> typing.Optional[str]: + """Return service url.""" + domain = get_domain() + return f"https://social.{domain}" + @staticmethod def is_movable() -> bool: return True diff --git a/selfprivacy_api/services/service.py b/selfprivacy_api/services/service.py index 5627e17..bffa1a4 100644 --- a/selfprivacy_api/services/service.py +++ b/selfprivacy_api/services/service.py @@ -52,6 +52,11 @@ class Service(ABC): def get_svg_icon() -> str: pass + @staticmethod + @abstractmethod + def get_url() -> typing.Optional[str]: + pass + @staticmethod @abstractmethod def is_movable() -> bool: diff --git a/selfprivacy_api/utils/huey.py b/selfprivacy_api/utils/huey.py index f03435e..7b39d5a 100644 --- a/selfprivacy_api/utils/huey.py +++ b/selfprivacy_api/utils/huey.py @@ -4,13 +4,5 @@ from huey import SqliteHuey HUEY_DATABASE = "/etc/nixos/userdata/tasks.db" # Singleton instance containing the huey database. -class Huey: - """Huey singleton.""" - __instance = None - - def __new__(cls): - """Create a new instance of the huey singleton.""" - if Huey.__instance is None: - Huey.__instance = SqliteHuey(HUEY_DATABASE) - return Huey.__instance +huey = SqliteHuey(HUEY_DATABASE)