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")
|
kind = result.get("kind")
|
||||||
|
|
||||||
if kind == MUT_KIND_UPLOADED:
|
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 {
|
return {
|
||||||
"kind": "uploaded",
|
"kind": "uploaded",
|
||||||
"provider_item_id": result.get("provider_item_id"),
|
"provider_item_id": provider_item_id,
|
||||||
"name": result.get("name", upload_filename),
|
"name": resolved_name,
|
||||||
"parent_ref": result.get("parent_ref", parent_ref),
|
"parent_ref": resolved_parent_ref,
|
||||||
"size": result.get("size", len(content)),
|
"size": resolved_size,
|
||||||
}
|
}
|
||||||
|
|
||||||
if kind == MUT_KIND_CONFLICT:
|
if kind == MUT_KIND_CONFLICT:
|
||||||
|
|||||||
Reference in New Issue
Block a user