mirror of
https://git.selfprivacy.org/SelfPrivacy/selfprivacy-rest-api.git
synced 2025-01-05 23:54:19 +00:00
Add some services endpoints
This commit is contained in:
parent
e7df559787
commit
00badfbbf8
|
@ -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")
|
||||
|
|
13
selfprivacy_api/graphql/common_types/dns.py
Normal file
13
selfprivacy_api/graphql/common_types/dns.py
Normal file
|
@ -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]
|
24
selfprivacy_api/graphql/common_types/storage_usage.py
Normal file
24
selfprivacy_api/graphql/common_types/storage_usage.py
Normal file
|
@ -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
|
|
@ -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
|
||||
|
|
45
selfprivacy_api/graphql/queries/jobs.py
Normal file
45
selfprivacy_api/graphql/queries/jobs.py
Normal file
|
@ -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()
|
||||
]
|
117
selfprivacy_api/graphql/queries/services.py
Normal file
117
selfprivacy_api/graphql/queries/services.py
Normal file
|
@ -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]
|
|
@ -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()
|
||||
]
|
||||
|
|
|
@ -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"""
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
]
|
|
@ -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():
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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()]
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue