Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions backend/app/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from .assets import * # noqa: E402, F403
from .chats import * # noqa: E402, F403
from .cloud import * # noqa: E402, F403
from .cloud_backups import * # noqa: E402, F403
from .embedded_device import * # noqa: E402, F403
from .frame_bootstrap import * # noqa: E402, F403
from .frames import * # noqa: E402, F403
Expand Down
28 changes: 27 additions & 1 deletion backend/app/api/cloud.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from app.schemas.cloud import (
CloudConnectRequest,
CloudFeaturesRequest,
CloudBackupFeaturesRequest,
CloudLocalFallbackRequest,
CloudLoginOptionsResponse,
CloudLoginStartRequest,
Expand Down Expand Up @@ -125,6 +126,8 @@ def _status_payload(db: Session, link: CloudBackendLink | None, user: User | Non
"can_edit_provider": status == "disconnected",
"poll_error": link.poll_error if link else None,
"local_fallback_enabled": link.local_fallback_enabled if link else True,
"backup_scenes_enabled": link.backup_scenes_enabled if link else False,
"backup_frames_enabled": link.backup_frames_enabled if link else False,
"connection": None,
"link": None,
"identity": _identity_payload(db, user),
Expand Down Expand Up @@ -912,14 +915,37 @@ async def set_local_fallback(
return _status_payload(db, link, current_user)


@api_user.post("/cloud/backup-features", response_model=CloudStatusResponse)
async def set_backup_features(
data: CloudBackupFeaturesRequest,
db: Session = Depends(get_db),
current_user: User | None = Depends(get_current_user),
):
"""Turn cloud backups on or off locally. The backup scopes come with every
cloud account, but nothing is uploaded while these switches are off."""
if current_user is None:
raise HTTPException(status_code=HTTPStatus.UNAUTHORIZED, detail="Log in first")
link = current_cloud_backend_link(db)
if link is None:
raise HTTPException(status_code=HTTPStatus.CONFLICT, detail="This install is not linked to FrameOS Cloud")
if data.scenes is not None:
link.backup_scenes_enabled = data.scenes
if data.frames is not None:
link.backup_frames_enabled = data.frames
link.updated_at = _now()
db.commit()
return _status_payload(db, link, current_user)


# ---- enabled features (in-place scope changes) --------------------------------

BASE_LINK_SCOPES = ("backend:link", "backend:read")

# Features included with every cloud account. Only security-sensitive features
# (cloud login, later remote access/telemetry) get an opt-in toggle in the UI;
# these safe scopes are always kept on the link, so a feature change can never
# drop them.
# drop them. The backup scopes are a permission only: nothing is uploaded
# until the matching backup_*_enabled switch on the link is turned on.
INCLUDED_FEATURE_SCOPES = ("backup:scenes", "backup:frames", "store:publish")


Expand Down
Loading