selfprivacy-rest-api/selfprivacy_api/graphql/mutations/backup_mutations.py

198 lines
6.2 KiB
Python
Raw Permalink Normal View History

2023-05-29 15:34:26 +00:00
import typing
import strawberry
from selfprivacy_api.graphql import IsAuthenticated
from selfprivacy_api.graphql.mutations.mutation_interface import (
GenericMutationReturn,
GenericJobMutationReturn,
2023-05-29 15:34:26 +00:00
MutationReturnInterface,
)
from selfprivacy_api.graphql.queries.backup import BackupConfiguration
2023-05-29 18:24:38 +00:00
from selfprivacy_api.graphql.queries.backup import Backup
2023-05-29 15:34:26 +00:00
from selfprivacy_api.graphql.queries.providers import BackupProvider
from selfprivacy_api.graphql.common_types.jobs import job_to_api_job
from selfprivacy_api.graphql.common_types.backup import RestoreStrategy
2023-05-29 15:34:26 +00:00
from selfprivacy_api.backup import Backups
2023-07-20 15:24:26 +00:00
from selfprivacy_api.services import get_service_by_id
from selfprivacy_api.backup.tasks import start_backup, restore_snapshot
from selfprivacy_api.backup.jobs import add_backup_job, add_restore_job
2023-05-29 15:34:26 +00:00
@strawberry.input
class InitializeRepositoryInput:
"""Initialize repository input"""
provider: BackupProvider
# The following field may become optional for other providers?
# Backblaze takes bucket id and name
location_id: str
location_name: str
# Key ID and key for Backblaze
login: str
password: str
@strawberry.type
class GenericBackupConfigReturn(MutationReturnInterface):
"""Generic backup config return"""
configuration: typing.Optional[BackupConfiguration]
@strawberry.type
class BackupMutations:
@strawberry.mutation(permission_classes=[IsAuthenticated])
def initialize_repository(
self, repository: InitializeRepositoryInput
) -> GenericBackupConfigReturn:
"""Initialize a new repository"""
Backups.set_provider(
2023-06-23 09:40:10 +00:00
kind=repository.provider,
2023-05-29 15:34:26 +00:00
login=repository.login,
key=repository.password,
location=repository.location_name,
repo_id=repository.location_id,
)
Backups.init_repo()
return GenericBackupConfigReturn(
2023-06-23 09:40:10 +00:00
success=True,
message="",
code=200,
2023-06-23 09:40:10 +00:00
configuration=Backup().configuration(),
)
2023-05-29 18:24:38 +00:00
@strawberry.mutation(permission_classes=[IsAuthenticated])
def remove_repository(self) -> GenericBackupConfigReturn:
"""Remove repository"""
Backups.reset()
return GenericBackupConfigReturn(
2023-06-23 09:40:10 +00:00
success=True,
message="",
code=200,
2023-06-23 09:40:10 +00:00
configuration=Backup().configuration(),
)
@strawberry.mutation(permission_classes=[IsAuthenticated])
def set_autobackup_period(
self, period: typing.Optional[int] = None
) -> GenericBackupConfigReturn:
"""Set autobackup period. None is to disable autobackup"""
if period is not None:
Backups.set_autobackup_period_minutes(period)
else:
Backups.set_autobackup_period_minutes(0)
return GenericBackupConfigReturn(
2023-06-23 09:40:10 +00:00
success=True,
message="",
code=200,
2023-06-23 09:40:10 +00:00
configuration=Backup().configuration(),
)
@strawberry.mutation(permission_classes=[IsAuthenticated])
def start_backup(self, service_id: str) -> GenericJobMutationReturn:
"""Start backup"""
service = get_service_by_id(service_id)
if service is None:
return GenericJobMutationReturn(
success=False,
code=300,
message=f"nonexistent service: {service_id}",
job=None,
)
job = add_backup_job(service)
start_backup(service)
return GenericJobMutationReturn(
success=True,
code=200,
message="Backup job queued",
2023-06-23 09:40:10 +00:00
job=job_to_api_job(job),
)
@strawberry.mutation(permission_classes=[IsAuthenticated])
def restore_backup(
self,
snapshot_id: str,
strategy: RestoreStrategy = RestoreStrategy.DOWNLOAD_VERIFY_OVERWRITE,
) -> GenericJobMutationReturn:
"""Restore backup"""
snap = Backups.get_snapshot_by_id(snapshot_id)
if snap is None:
return GenericJobMutationReturn(
success=False,
2023-06-23 09:40:10 +00:00
code=404,
message=f"No such snapshot: {snapshot_id}",
job=None,
)
2023-06-23 09:40:10 +00:00
service = get_service_by_id(snap.service_name)
if service is None:
return GenericJobMutationReturn(
success=False,
code=404,
message=f"nonexistent service: {snap.service_name}",
job=None,
)
try:
job = add_restore_job(snap)
2023-07-20 15:24:26 +00:00
except ValueError as error:
2023-06-23 09:40:10 +00:00
return GenericJobMutationReturn(
success=False,
code=400,
2023-07-20 15:24:26 +00:00
message=str(error),
2023-06-23 09:40:10 +00:00
job=None,
)
restore_snapshot(snap, strategy)
return GenericJobMutationReturn(
success=True,
code=200,
message="restore job created",
2023-06-23 09:40:10 +00:00
job=job_to_api_job(job),
)
2023-07-28 10:40:40 +00:00
@strawberry.mutation(permission_classes=[IsAuthenticated])
def forget_snapshot(self, snapshot_id: str) -> GenericMutationReturn:
2023-08-04 09:57:31 +00:00
"""Forget a snapshot.
Makes it inaccessible from the server.
2023-07-28 10:40:40 +00:00
After some time, the data (encrypted) will not be recoverable
from the backup server too, but not immediately"""
snap = Backups.get_snapshot_by_id(snapshot_id)
if snap is None:
return GenericMutationReturn(
success=False,
code=404,
message=f"snapshot {snapshot_id} not found",
)
2023-08-04 09:57:31 +00:00
2023-07-28 10:40:40 +00:00
try:
Backups.forget_snapshot(snap)
return GenericMutationReturn(
success=True,
code=200,
message="",
)
except Exception as error:
return GenericMutationReturn(
success=False,
code=400,
message=str(error),
)
@strawberry.mutation(permission_classes=[IsAuthenticated])
def force_snapshots_reload(self) -> GenericMutationReturn:
"""Force snapshots reload"""
Backups.force_snapshot_cache_reload()
return GenericMutationReturn(
success=True,
code=200,
message="",
)