Skip to content

Commit 072eaeb

Browse files
sandereggkaiser
authored andcommitted
šŸ› Hot-fix: Ensure synchronization between projects/workbench and projects_nodes (#4617)
1 parent 1cff8e7 commit 072eaeb

File tree

1 file changed

+78
-72
lines changed
  • services/web/server/src/simcore_service_webserver/projects

1 file changed

+78
-72
lines changed

ā€Žservices/web/server/src/simcore_service_webserver/projects/db.pyā€Ž

Lines changed: 78 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -434,90 +434,96 @@ async def replace_project(
434434
product_name: str,
435435
project_uuid: str,
436436
) -> dict[str, Any]:
437-
"""replaces a project from a user
437+
"""DEPRECATED!!
438+
replaces a project from a user
438439
this method completely replaces a user project with new_project_data only keeping
439440
the old entries from the project workbench if they exists in the new project workbench.
440441
441442
:raises ProjectInvalidRightsError
442443
"""
443444
log.info("Updating project %s for user %s", project_uuid, user_id)
444445

445-
async with self.engine.acquire() as conn:
446-
async with conn.begin():
447-
current_project: dict = await self._get_project(
448-
conn,
449-
user_id,
450-
project_uuid,
451-
exclude_foreign=["tags"],
452-
for_update=True,
453-
)
454-
user_groups: list[RowProxy] = await self._list_user_groups(
455-
conn, user_id
456-
)
457-
check_project_permissions(
458-
current_project, user_id, user_groups, "write"
459-
)
460-
# uuid can ONLY be set upon creation
461-
if current_project["uuid"] != new_project_data["uuid"]:
462-
raise ProjectInvalidRightsError(user_id, new_project_data["uuid"])
463-
# ensure the prj owner is always in the access rights
464-
owner_primary_gid = await self._get_user_primary_group_gid(
465-
conn, current_project[projects.c.prj_owner.key]
466-
)
467-
new_project_data.setdefault("accessRights", {}).update(
468-
create_project_access_rights(
469-
owner_primary_gid, ProjectAccessRights.OWNER
470-
)
446+
async with self.engine.acquire() as conn, conn.begin():
447+
current_project: dict = await self._get_project(
448+
conn,
449+
user_id,
450+
project_uuid,
451+
exclude_foreign=["tags"],
452+
for_update=True,
453+
)
454+
user_groups: list[RowProxy] = await self._list_user_groups(conn, user_id)
455+
check_project_permissions(current_project, user_id, user_groups, "write")
456+
# uuid can ONLY be set upon creation
457+
if current_project["uuid"] != new_project_data["uuid"]:
458+
raise ProjectInvalidRightsError(user_id, new_project_data["uuid"])
459+
# ensure the prj owner is always in the access rights
460+
owner_primary_gid = await self._get_user_primary_group_gid(
461+
conn, current_project[projects.c.prj_owner.key]
462+
)
463+
new_project_data.setdefault("accessRights", {}).update(
464+
create_project_access_rights(
465+
owner_primary_gid, ProjectAccessRights.OWNER
471466
)
467+
)
472468

473-
# update the workbench
474-
def _update_workbench(
475-
old_project: ProjectDict, new_project: ProjectDict
476-
) -> None:
477-
# any non set entry in the new workbench is taken from the old one if available
478-
old_workbench = old_project["workbench"]
479-
new_workbench = new_project["workbench"]
480-
for node_key, node in new_workbench.items():
481-
old_node = old_workbench.get(node_key)
482-
if not old_node:
483-
continue
484-
for prop in old_node:
485-
# check if the key is missing in the new node
486-
if prop not in node:
487-
# use the old value
488-
node[prop] = old_node[prop]
489-
490-
_update_workbench(current_project, new_project_data)
491-
# update timestamps
492-
new_project_data["lastChangeDate"] = now_str()
469+
# update the workbench
470+
def _update_workbench(
471+
old_project: ProjectDict, new_project: ProjectDict
472+
) -> None:
473+
# any non set entry in the new workbench is taken from the old one if available
474+
old_workbench = old_project["workbench"]
475+
new_workbench = new_project["workbench"]
476+
for node_key, node in new_workbench.items():
477+
old_node = old_workbench.get(node_key)
478+
if not old_node:
479+
continue
480+
for prop in old_node:
481+
# check if the key is missing in the new node
482+
if prop not in node:
483+
# use the old value
484+
node[prop] = old_node[prop]
485+
486+
_update_workbench(current_project, new_project_data)
487+
# update timestamps
488+
new_project_data["lastChangeDate"] = now_str()
493489

494-
# now update it
490+
# now update it
495491

496-
log.debug(
497-
"DB updating with new_project_data=%s", json_dumps(new_project_data)
498-
)
499-
result = await conn.execute(
500-
# pylint: disable=no-value-for-parameter
501-
projects.update()
502-
.values(**convert_to_db_names(new_project_data))
503-
.where(projects.c.id == current_project[projects.c.id.key])
504-
.returning(literal_column("*"))
505-
)
506-
project = await result.fetchone()
507-
assert project # nosec
508-
await self.upsert_project_linked_product(
509-
ProjectID(project_uuid), product_name, conn=conn
510-
)
511-
log.debug(
512-
"DB updated returned row project=%s",
513-
json_dumps(dict(project.items())),
514-
)
515-
user_email = await self._get_user_email(conn, project.prj_owner)
492+
log.debug(
493+
"DB updating with new_project_data=%s", json_dumps(new_project_data)
494+
)
495+
result = await conn.execute(
496+
# pylint: disable=no-value-for-parameter
497+
projects.update()
498+
.values(**convert_to_db_names(new_project_data))
499+
.where(projects.c.id == current_project[projects.c.id.key])
500+
.returning(literal_column("*"))
501+
)
502+
project = await result.fetchone()
503+
assert project # nosec
504+
await self.upsert_project_linked_product(
505+
ProjectID(project_uuid), product_name, conn=conn
506+
)
507+
# ensure project_nodes are in sync
508+
project_nodes_repo = ProjectNodesRepo(project_uuid=ProjectID(project_uuid))
509+
list_of_nodes = await project_nodes_repo.list(conn)
510+
new_workbench = project.get("workbench", {})
511+
node_ids_to_delete = [
512+
n.node_id for n in list_of_nodes if f"{n.node_id}" not in new_workbench
513+
]
514+
for node_id in node_ids_to_delete:
515+
await project_nodes_repo.delete(conn, node_id=node_id)
516+
# NOTE: missing nodes are NOT taken care of in this quick fix.
517+
log.debug(
518+
"DB updated returned row project=%s",
519+
json_dumps(dict(project.items())),
520+
)
521+
user_email = await self._get_user_email(conn, project.prj_owner)
516522

517-
tags = await self._get_tags_by_project(
518-
conn, project_id=project[projects.c.id]
519-
)
520-
return convert_to_schema_names(project, user_email, tags=tags)
523+
tags = await self._get_tags_by_project(
524+
conn, project_id=project[projects.c.id]
525+
)
526+
return convert_to_schema_names(project, user_email, tags=tags)
521527

522528
async def update_project_without_checking_permissions(
523529
self,

0 commit comments

Comments
Ā (0)