Write project.json to the storage owner prefix.

update_project used meta.user_id for the path, so JWT projects that still
have user_id=local never persisted pcb_status=queued and the PCB worker
exited as draft. Point writes at the prefix used to read the project.
This commit is contained in:
2026-09-20 00:57:15 +02:00
parent 344ecb3389
commit 3e2ba269f9
3 changed files with 63 additions and 6 deletions
+19 -5
View File
@@ -201,10 +201,24 @@ def _read_meta_with_generation(
return ProjectMeta.model_validate(data), gen
def _write_meta(storage: StorageBackend, meta: ProjectMeta) -> None:
def _write_meta(
storage: StorageBackend,
meta: ProjectMeta,
*,
owner_user_id: str | None = None,
) -> None:
"""Persist meta under ``users/{owner}/projects/{id}/``.
``meta.user_id`` can lag the storage prefix (local-auth accounts that
still have ``user_id: "local"`` in JSON while files live under
``users/usr_…/``). Writes must follow the prefix used to *read* the
project, not the stale field — otherwise ``update_project(pcb_status=…)``
lands in a different tree and the PCB worker still sees ``draft``.
"""
uid = owner_user_id or meta.user_id
meta.updated = datetime.now(timezone.utc).isoformat()
storage.write_json(
_meta_key(meta.user_id, meta.id),
_meta_key(uid, meta.id),
meta.model_dump(),
)
@@ -516,7 +530,7 @@ def update_project(
meta = _read_meta(storage, user_id, project_id)
for k, v in fields.items():
setattr(meta, k, v)
_write_meta(storage, meta)
_write_meta(storage, meta, owner_user_id=user_id)
return meta
@@ -691,7 +705,7 @@ def add_collaborator(
meta = _read_meta(storage, owner_user_id, project_id)
if collaborator_user_id not in meta.collaborators:
meta.collaborators.append(collaborator_user_id)
_write_meta(storage, meta)
_write_meta(storage, meta, owner_user_id=owner_user_id)
# Write reverse reference for the collaborator
ref_key = _shared_ref_key(collaborator_user_id, project_id)
storage.write_json(ref_key, {"owner_user_id": owner_user_id})
@@ -704,7 +718,7 @@ def remove_collaborator(
"""Remove a collaborator from a project and delete the shared reference."""
meta = _read_meta(storage, owner_user_id, project_id)
meta.collaborators = [c for c in meta.collaborators if c != collaborator_user_id]
_write_meta(storage, meta)
_write_meta(storage, meta, owner_user_id=owner_user_id)
# Delete reverse reference
ref_key = _shared_ref_key(collaborator_user_id, project_id)
if storage.exists(ref_key):