user_groups: Prevent cycles when adding subgroups for a user group.

The user group depedency graph should always be a DAG.
This commit adds code to make sure we keep the graph DAG
while adding subgroups to a user group.

Fixes #25913.
This commit is contained in:
Sahil Batra
2023-06-10 13:30:56 +05:30
committed by Tim Abbott
parent 4a18552ff8
commit ea1357be66
3 changed files with 42 additions and 0 deletions

View File

@@ -216,6 +216,16 @@ def get_subgroup_ids(user_group: UserGroup, *, direct_subgroup_only: bool = Fals
return list(subgroup_ids)
def get_recursive_subgroups_for_groups(user_group_ids: List[int]) -> List[int]:
cte = With.recursive(
lambda cte: UserGroup.objects.filter(id__in=user_group_ids)
.values(group_id=F("id"))
.union(cte.join(UserGroup, direct_supergroups=cte.col.group_id).values(group_id=F("id")))
)
recursive_subgroups = cte.join(UserGroup, id=cte.col.group_id).with_cte(cte)
return list(recursive_subgroups.values_list("id", flat=True))
@transaction.atomic(savepoint=False)
def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
"""Any changes to this function likely require a migration to adjust