feat(13-06): route upload success through centralized reconciliation before returning
- Upsert uploaded item into cloud_items for stable row identity and navigation - Invalidate parent folder state (warning/upload_mutated) so next browse re-fetches - Reconcile-before-return: session committed before response returned - Failed/conflict uploads bypass reconciliation path (T-13-19)
This commit is contained in:
@@ -637,12 +637,60 @@ async def upload_cloud_file(
|
||||
kind = result.get("kind")
|
||||
|
||||
if kind == MUT_KIND_UPLOADED:
|
||||
# Route authoritative upload success through centralized reconciliation
|
||||
# before returning (Plan 06, Task 1: T-13-19).
|
||||
# upsert_cloud_item gives the new item stable row identity in cloud_items,
|
||||
# so navigation can show it immediately without a full provider re-list.
|
||||
# update_folder_state invalidates the parent folder so the next browse
|
||||
# triggers a provider re-list and reflects the new content truthfully.
|
||||
# These calls are intentionally in-request — the response is not returned
|
||||
# until reconciliation completes (reconcile-before-return contract).
|
||||
provider_item_id = result.get("provider_item_id")
|
||||
resolved_name = result.get("name", upload_filename)
|
||||
resolved_parent_ref = result.get("parent_ref", parent_ref)
|
||||
resolved_size = result.get("size", len(content))
|
||||
|
||||
if provider_item_id:
|
||||
from storage.cloud_base import CloudResource
|
||||
from services.cloud_items import upsert_cloud_item, update_folder_state
|
||||
|
||||
resource = CloudResource(
|
||||
id=uuid.uuid4(),
|
||||
provider_item_id=provider_item_id,
|
||||
connection_id=connection_id,
|
||||
user_id=current_user.id,
|
||||
name=resolved_name,
|
||||
kind="file",
|
||||
parent_ref=resolved_parent_ref,
|
||||
content_type=content_type,
|
||||
size=resolved_size,
|
||||
)
|
||||
# Upsert item — establishes stable row identity for navigation
|
||||
await upsert_cloud_item(session, user_id=str(current_user.id), resource=resource)
|
||||
|
||||
# Invalidate parent folder so next browse triggers a provider re-list.
|
||||
# We do NOT call apply_listing_and_finalize — that requires a full provider
|
||||
# listing which we don't have. Instead we mark the folder stale with a
|
||||
# controlled reason so the browse endpoint knows to re-fetch.
|
||||
invalidate_parent = resolved_parent_ref if resolved_parent_ref is not None else ""
|
||||
await update_folder_state(
|
||||
session,
|
||||
user_id=str(current_user.id),
|
||||
connection_id=str(connection_id),
|
||||
parent_ref=invalidate_parent,
|
||||
refresh_state="warning",
|
||||
error_code="upload_mutated",
|
||||
error_message="Folder contents changed by upload — re-listing required.",
|
||||
)
|
||||
|
||||
await session.commit()
|
||||
|
||||
return {
|
||||
"kind": "uploaded",
|
||||
"provider_item_id": result.get("provider_item_id"),
|
||||
"name": result.get("name", upload_filename),
|
||||
"parent_ref": result.get("parent_ref", parent_ref),
|
||||
"size": result.get("size", len(content)),
|
||||
"provider_item_id": provider_item_id,
|
||||
"name": resolved_name,
|
||||
"parent_ref": resolved_parent_ref,
|
||||
"size": resolved_size,
|
||||
}
|
||||
|
||||
if kind == MUT_KIND_CONFLICT:
|
||||
|
||||
Reference in New Issue
Block a user