From 506fbc02b5edace27eaca761b7e2459ac88b3425 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 11 Sep 2026 11:31:02 +0200 Subject: [PATCH 1/3] server: remove user-project mappings when delete a project --- .../main/java/com/cloud/projects/dao/ProjectAccountDao.java | 2 +- .../java/com/cloud/projects/dao/ProjectAccountDaoImpl.java | 6 ++++-- .../main/java/com/cloud/projects/ProjectManagerImpl.java | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java index f4b2f6460020..0ac48b6c6fd1 100644 --- a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java +++ b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java @@ -31,7 +31,7 @@ public interface ProjectAccountDao extends GenericDao { ProjectAccountVO findByProjectIdAccountId(long projectId, long accountId); - ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, long userId); + ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, Long userId); boolean canUserAccessProjectAccount(long accountId, long userId, long projectAccountId); diff --git a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java index b6eb6d44cea8..739882c03c5d 100644 --- a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java @@ -108,10 +108,12 @@ public ProjectAccountVO findByProjectIdAccountId(long projectId, long accountId) } @Override - public ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, long userId) { + public ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, Long userId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("projectId", projectId); - sc.setParameters("userId", userId); + if (userId != null) { + sc.setParameters("userId", userId); + } sc.setParameters("accountId", accountId); return findOneBy(sc); diff --git a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java index d165f0cd1b6b..fb00e7282bcc 100644 --- a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java @@ -449,7 +449,7 @@ public Boolean doInTransaction(TransactionStatus status) { @Override public boolean unassignAccountFromProject(long projectId, long accountId) { - ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountId); + ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdUserId(projectId, accountId, null); if (projectAccount == null) { logger.debug("Account id=" + accountId + " is not assigned to project id=" + projectId + " so no need to unassign"); return true; From a5a8aee99b1a7e38f30c17a27ab347e61aff96d9 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 26 Oct 2026 11:46:15 +0100 Subject: [PATCH 2/3] Revert "server: remove user-project mappings when delete a project" This reverts commit 506fbc02b5edace27eaca761b7e2459ac88b3425. --- .../main/java/com/cloud/projects/dao/ProjectAccountDao.java | 2 +- .../java/com/cloud/projects/dao/ProjectAccountDaoImpl.java | 6 ++---- .../main/java/com/cloud/projects/ProjectManagerImpl.java | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java index 0ac48b6c6fd1..f4b2f6460020 100644 --- a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java +++ b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java @@ -31,7 +31,7 @@ public interface ProjectAccountDao extends GenericDao { ProjectAccountVO findByProjectIdAccountId(long projectId, long accountId); - ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, Long userId); + ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, long userId); boolean canUserAccessProjectAccount(long accountId, long userId, long projectAccountId); diff --git a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java index 739882c03c5d..b6eb6d44cea8 100644 --- a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java @@ -108,12 +108,10 @@ public ProjectAccountVO findByProjectIdAccountId(long projectId, long accountId) } @Override - public ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, Long userId) { + public ProjectAccountVO findByProjectIdUserId(long projectId, long accountId, long userId) { SearchCriteria sc = AllFieldsSearch.create(); sc.setParameters("projectId", projectId); - if (userId != null) { - sc.setParameters("userId", userId); - } + sc.setParameters("userId", userId); sc.setParameters("accountId", accountId); return findOneBy(sc); diff --git a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java index fb00e7282bcc..d165f0cd1b6b 100644 --- a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java @@ -449,7 +449,7 @@ public Boolean doInTransaction(TransactionStatus status) { @Override public boolean unassignAccountFromProject(long projectId, long accountId) { - ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdUserId(projectId, accountId, null); + ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountId); if (projectAccount == null) { logger.debug("Account id=" + accountId + " is not assigned to project id=" + projectId + " so no need to unassign"); return true; From f4aa2c489638f76162c74ac3c769154d5ef9e89e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 26 Oct 2026 11:02:12 +0100 Subject: [PATCH 3/3] server: remove all project account mappings of an account in a project unassignAccountFromProject looked up a single project_account row with userId IS NULL and removed at most that one. Mappings created for users, and extra users of the same account, were left behind when a project was cleaned up. unassignAccountFromProject now removes every project_account row matching the project and account through ProjectAccountDao.removeByProjectIdAccountId. cleanupProject keeps its per-row loop and therefore covers user mappings too. --- .../com/cloud/projects/dao/ProjectAccountDao.java | 2 +- .../cloud/projects/dao/ProjectAccountDaoImpl.java | 12 +++++++----- .../java/com/cloud/projects/ProjectManagerImpl.java | 13 +++---------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java index f4b2f6460020..1df53cd26199 100644 --- a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java +++ b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDao.java @@ -47,7 +47,7 @@ public interface ProjectAccountDao extends GenericDao { void removeAccountFromProjects(long accountId); - void removeUserFromProjects(long userId); + int removeByProjectIdAccountId(long projectId, long accountId); boolean canUserModifyProject(long projectId, long accountId, long userId); diff --git a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java index b6eb6d44cea8..c09ac60bd215 100644 --- a/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/projects/dao/ProjectAccountDaoImpl.java @@ -193,14 +193,16 @@ public void removeAccountFromProjects(long accountId) { } @Override - public void removeUserFromProjects(long userId) { + public int removeByProjectIdAccountId(long projectId, long accountId) { SearchCriteria sc = AllFieldsSearch.create(); - sc.setParameters("userId", userId); + sc.setParameters("projectId", projectId); + sc.setParameters("accountId", accountId); - int removedCount = remove(sc); - if (removedCount > 0) { - logger.debug(String.format("Removed user [%s] from %s project(s).", userId, removedCount)); + int rowsRemoved = remove(sc); + if (rowsRemoved > 0) { + logger.debug("Removed {} mappings of account id={} from project id={}", rowsRemoved, accountId, projectId); } + return rowsRemoved; } @Override diff --git a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java index d165f0cd1b6b..85427ebf5f03 100644 --- a/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java +++ b/server/src/main/java/com/cloud/projects/ProjectManagerImpl.java @@ -449,18 +449,11 @@ public Boolean doInTransaction(TransactionStatus status) { @Override public boolean unassignAccountFromProject(long projectId, long accountId) { - ProjectAccountVO projectAccount = _projectAccountDao.findByProjectIdAccountId(projectId, accountId); - if (projectAccount == null) { + int removed = _projectAccountDao.removeByProjectIdAccountId(projectId, accountId); + if (removed == 0) { logger.debug("Account id=" + accountId + " is not assigned to project id=" + projectId + " so no need to unassign"); - return true; - } - - if (_projectAccountDao.remove(projectAccount.getId())) { - return true; - } else { - logger.warn("Failed to unassign account id=" + accountId + " from the project id=" + projectId); - return false; } + return true; } @Override