Refactor backend and frontend cleanup paths
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
"""Factory for user-scoped cloud storage backends."""
|
||||
|
||||
|
||||
def build_cloud_backend(provider: str, credentials: dict):
|
||||
if provider == "google_drive":
|
||||
from storage.google_drive_backend import GoogleDriveBackend # lazy import
|
||||
|
||||
return GoogleDriveBackend(credentials)
|
||||
|
||||
if provider == "onedrive":
|
||||
from storage.onedrive_backend import OneDriveBackend # lazy import
|
||||
|
||||
return OneDriveBackend(credentials)
|
||||
|
||||
if provider == "nextcloud":
|
||||
from storage.nextcloud_backend import NextcloudBackend # lazy import
|
||||
|
||||
return NextcloudBackend(
|
||||
credentials["server_url"],
|
||||
credentials["username"],
|
||||
credentials["password"],
|
||||
)
|
||||
|
||||
if provider == "webdav":
|
||||
from storage.webdav_backend import WebDAVBackend # lazy import
|
||||
|
||||
return WebDAVBackend(
|
||||
credentials["server_url"],
|
||||
credentials["username"],
|
||||
credentials["password"],
|
||||
)
|
||||
|
||||
raise ValueError(f"Unknown provider: {provider}")
|
||||
@@ -6,12 +6,8 @@ class CloudConnectionError(Exception):
|
||||
"""Raised when a cloud provider signals a non-retryable connection problem.
|
||||
|
||||
Attributes:
|
||||
reason: "token_expired" — access token expired; API layer can refresh and retry.
|
||||
reason: "token_expired" — access token expired.
|
||||
"invalid_grant" — refresh token revoked; user must reconnect.
|
||||
|
||||
The backend never updates the DB. The API layer (_call_cloud_op in cloud.py)
|
||||
catches this exception, performs the DB state transition, and decides whether
|
||||
to retry or surface a 503 to the client (B2 design, D-05/D-06).
|
||||
"""
|
||||
|
||||
def __init__(self, msg: str = "", *, reason: str = "") -> None:
|
||||
|
||||
@@ -11,10 +11,8 @@ Design notes:
|
||||
- D-14: presigned_get_url and generate_presigned_put_url raise
|
||||
NotImplementedError. The API upload endpoint detects cloud backends and
|
||||
uses the direct put_object() path instead.
|
||||
- B2 design: This backend is STATELESS. It raises CloudConnectionError but
|
||||
does NOT update the DB or CloudConnection objects. DB state transitions
|
||||
(e.g., REQUIRES_REAUTH) are handled by the _call_cloud_op() helper in
|
||||
cloud.py (Plan 05-05), which has the DB session.
|
||||
- This backend is stateless. It raises CloudConnectionError but does not
|
||||
update the DB or CloudConnection objects.
|
||||
- Token key format stored in credentials dict:
|
||||
access_token — current OAuth bearer token
|
||||
refresh_token — long-lived refresh token
|
||||
|
||||
@@ -10,9 +10,8 @@ Design notes:
|
||||
already async and awaited directly.
|
||||
- CloudConnectionError is imported from google_drive_backend (shared type).
|
||||
This keeps the exception hierarchy unified across all cloud backends.
|
||||
- B2 design: This backend is STATELESS. It raises CloudConnectionError but
|
||||
does NOT update the DB or CloudConnection objects. DB state transitions
|
||||
(e.g., REQUIRES_REAUTH) are handled by _call_cloud_op() in cloud.py.
|
||||
- This backend is stateless. It raises CloudConnectionError but does not
|
||||
update the DB or CloudConnection objects.
|
||||
- _ensure_valid_token() checks expiry before each API call and calls
|
||||
_refresh_token() if the token is within 60 seconds of expiry. If the
|
||||
refresh returns None (invalid_grant), CloudConnectionError is raised.
|
||||
|
||||
Reference in New Issue
Block a user