Files
gh-christianlouis-docuelevate/app/views/onboarding.py
T
copilot-swe-agent[bot] 30f06e0b32 feat(storage): add Apple iCloud Drive storage provider
Add iCloud Drive as a new storage destination using the pyicloud library.
Includes upload task, configuration, user integration handler, provider
status, onboarding support, and comprehensive tests.

Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
2026-03-11 23:38:35 +00:00

94 lines
3.6 KiB
Python

"""View route for the user onboarding wizard."""
import logging
from fastapi import Depends, Request
from sqlalchemy.orm import Session
from app.config import Settings
from app.config import settings as _settings
from app.models import UserProfile
from app.utils.subscription import get_all_tiers
from app.views.base import APIRouter, get_db, require_login, templates
logger = logging.getLogger(__name__)
router = APIRouter()
# ---------------------------------------------------------------------------
# Destination helper
# ---------------------------------------------------------------------------
_DESTINATION_META: list[dict] = [
{"id": "dropbox", "name": "Dropbox", "icon": "fab fa-dropbox"},
{"id": "gdrive", "name": "Google Drive", "icon": "fab fa-google-drive"},
{"id": "onedrive", "name": "OneDrive", "icon": "fab fa-microsoft"},
{"id": "s3", "name": "Amazon S3", "icon": "fab fa-aws"},
{"id": "nextcloud", "name": "Nextcloud", "icon": "fas fa-cloud"},
{"id": "webdav", "name": "WebDAV", "icon": "fas fa-server"},
{"id": "sftp", "name": "SFTP", "icon": "fas fa-terminal"},
{"id": "ftp", "name": "FTP", "icon": "fas fa-server"},
{"id": "icloud", "name": "iCloud Drive", "icon": "fab fa-apple"},
]
def _get_configured_destinations(cfg: Settings) -> list[dict]:
"""Return which storage providers are fully configured in the current settings.
Each entry is a dict with ``id``, ``name``, and ``icon`` keys.
Args:
cfg: The application settings object (``app.config.settings``).
Returns:
A list of destination dicts for providers that have the required
credentials set.
"""
checks: dict[str, bool] = {
"dropbox": bool(cfg.dropbox_refresh_token and cfg.dropbox_app_key),
"gdrive": bool(cfg.google_drive_credentials_json or cfg.google_drive_refresh_token),
"onedrive": bool(cfg.onedrive_refresh_token and cfg.onedrive_client_id),
"s3": bool(cfg.aws_access_key_id and cfg.s3_bucket_name),
"nextcloud": bool(cfg.nextcloud_upload_url and cfg.nextcloud_username),
"webdav": bool(cfg.webdav_url and cfg.webdav_username),
"sftp": bool(cfg.sftp_host and cfg.sftp_username),
"ftp": bool(cfg.ftp_host and cfg.ftp_username),
"icloud": bool(cfg.icloud_username and cfg.icloud_password),
}
return [meta for meta in _DESTINATION_META if checks.get(meta["id"], False)]
# ---------------------------------------------------------------------------
# Route
# ---------------------------------------------------------------------------
@router.get("/onboarding", include_in_schema=False)
@require_login
async def onboarding_page(request: Request, db: Session = Depends(get_db)):
"""Render the multi-step onboarding wizard.
Redirects to ``/upload`` when the user has already completed onboarding.
"""
user = request.session.get("user") or {}
user_id = user.get("sub") or user.get("preferred_username") or user.get("email") or user.get("id")
if user_id:
profile = db.query(UserProfile).filter(UserProfile.user_id == user_id).first()
if profile and profile.onboarding_completed:
from starlette.responses import RedirectResponse
return RedirectResponse(url="/upload", status_code=302)
configured_destinations = _get_configured_destinations(_settings)
tiers = get_all_tiers(db)
return templates.TemplateResponse(
"onboarding.html",
{
"request": request,
"user": user,
"configured_destinations": configured_destinations,
"tiers": tiers,
},
)