user_groups: Audit UserGroup supergroup memberships changes.

This is mostly the same as tracking subgroup changes, except that now
modified_user_group is the subgroup.

Signed-off-by: Zixuan James Li <p359101898@gmail.com>
This commit is contained in:
Zixuan James Li
2022-12-11 21:29:10 -05:00
committed by Tim Abbott
parent ad698d597a
commit 3035854dca
4 changed files with 106 additions and 25 deletions

View File

@@ -300,7 +300,8 @@ def add_subgroups_to_user_group(
subgroup_ids = [subgroup.id for subgroup in subgroups]
now = timezone_now()
RealmAuditLog.objects.create(
audit_log_entries = [
RealmAuditLog(
realm=user_group.realm,
modified_user_group=user_group,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUBGROUP_MEMBERSHIP_ADDED,
@@ -308,6 +309,19 @@ def add_subgroups_to_user_group(
acting_user=acting_user,
extra_data=orjson.dumps({"subgroup_ids": subgroup_ids}).decode(),
)
]
for subgroup_id in subgroup_ids:
audit_log_entries.append(
RealmAuditLog(
realm=user_group.realm,
modified_user_group_id=subgroup_id,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_ADDED,
event_time=now,
acting_user=acting_user,
extra_data=orjson.dumps({"supergroup_ids": [user_group.id]}).decode(),
)
)
RealmAuditLog.objects.bulk_create(audit_log_entries)
do_send_subgroups_update_event("add_subgroups", user_group, subgroup_ids)
@@ -320,7 +334,8 @@ def remove_subgroups_from_user_group(
subgroup_ids = [subgroup.id for subgroup in subgroups]
now = timezone_now()
RealmAuditLog.objects.create(
audit_log_entries = [
RealmAuditLog(
realm=user_group.realm,
modified_user_group=user_group,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUBGROUP_MEMBERSHIP_REMOVED,
@@ -328,6 +343,19 @@ def remove_subgroups_from_user_group(
acting_user=acting_user,
extra_data=orjson.dumps({"subgroup_ids": subgroup_ids}).decode(),
)
]
for subgroup_id in subgroup_ids:
audit_log_entries.append(
RealmAuditLog(
realm=user_group.realm,
modified_user_group_id=subgroup_id,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_REMOVED,
event_time=now,
acting_user=acting_user,
extra_data=orjson.dumps({"supergroup_ids": [user_group.id]}).decode(),
)
)
RealmAuditLog.objects.bulk_create(audit_log_entries)
do_send_subgroups_update_event("remove_subgroups", user_group, subgroup_ids)

View File

@@ -352,15 +352,26 @@ def create_system_user_groups_for_realm(realm: Realm) -> Dict[int, UserGroup]:
subgroup, remaining_groups = system_user_groups_list[1], system_user_groups_list[2:]
for supergroup in remaining_groups:
subgroup_objects.append(GroupGroupMembership(subgroup=subgroup, supergroup=supergroup))
realmauditlog_objects.append(
now = timezone_now()
realmauditlog_objects.extend(
[
RealmAuditLog(
realm=realm,
modified_user_group=supergroup,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUBGROUP_MEMBERSHIP_ADDED,
event_time=timezone_now(),
event_time=now,
acting_user=None,
extra_data=orjson.dumps({"subgroup_ids": [subgroup.id]}).decode(),
)
),
RealmAuditLog(
realm=realm,
modified_user_group=subgroup,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_ADDED,
event_time=now,
acting_user=None,
extra_data=orjson.dumps({"supergroup_ids": [supergroup.id]}).decode(),
),
]
)
subgroup = supergroup

View File

@@ -1100,9 +1100,18 @@ class TestRealmAuditLog(ZulipTestCase):
acting_user=None,
).values_list("modified_user_group_id", "extra_data")
)
logged_supergroup_entries = sorted(
RealmAuditLog.objects.filter(
realm=realm,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_ADDED,
event_time__gte=now,
acting_user=None,
).values_list("modified_user_group_id", "extra_data")
)
# Excluding nobody_system_group, the rest of the user groups should have
# a chain of subgroup memberships in between.
self.assert_length(logged_subgroup_entries, expected_system_user_group_count - 2)
self.assert_length(logged_supergroup_entries, expected_system_user_group_count - 2)
for i in range(len(logged_subgroup_entries)):
# The offset of 1 is due to nobody_system_group being skipped as
# the first user group in the list.
@@ -1112,11 +1121,17 @@ class TestRealmAuditLog(ZulipTestCase):
expected_supergroup_id = system_user_group_ids[i + 2]
supergroup_id, subgroup_extra_data = logged_subgroup_entries[i]
subgroup_id, supergroup_extra_data = logged_supergroup_entries[i]
assert subgroup_extra_data is not None
assert supergroup_extra_data is not None
self.assertEqual(
orjson.loads(subgroup_extra_data)["subgroup_ids"][0], expected_subgroup_id
)
self.assertEqual(
orjson.loads(supergroup_extra_data)["supergroup_ids"][0], expected_supergroup_id
)
self.assertEqual(supergroup_id, expected_supergroup_id)
self.assertEqual(subgroup_id, expected_subgroup_id)
def test_user_group_creation(self) -> None:
hamlet = self.example_user("hamlet")
@@ -1197,6 +1212,19 @@ class TestRealmAuditLog(ZulipTestCase):
orjson.loads(assert_is_not_none(audit_log_entry.extra_data)),
{"subgroup_ids": [subgroup.id for subgroup in subgroups]},
)
audit_log_entries = RealmAuditLog.objects.filter(
realm=hamlet.realm,
event_time__gte=now,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_ADDED,
).order_by("id")
self.assert_length(audit_log_entries, 3)
for i in range(3):
self.assertEqual(audit_log_entries[i].modified_user_group, subgroups[i])
self.assertEqual(audit_log_entries[i].acting_user, hamlet)
self.assertDictEqual(
orjson.loads(assert_is_not_none(audit_log_entries[i].extra_data)),
{"supergroup_ids": [user_group.id]},
)
remove_subgroups_from_user_group(user_group, subgroups[:2], acting_user=hamlet)
audit_log_entry = RealmAuditLog.objects.get(
@@ -1210,3 +1238,16 @@ class TestRealmAuditLog(ZulipTestCase):
orjson.loads(assert_is_not_none(audit_log_entry.extra_data)),
{"subgroup_ids": [subgroup.id for subgroup in subgroups[:2]]},
)
audit_log_entries = RealmAuditLog.objects.filter(
realm=hamlet.realm,
event_time__gte=now,
event_type=RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_REMOVED,
).order_by("id")
self.assert_length(audit_log_entries, 2)
for i in range(2):
self.assertEqual(audit_log_entries[i].modified_user_group, subgroups[i])
self.assertEqual(audit_log_entries[i].acting_user, hamlet)
self.assertDictEqual(
orjson.loads(assert_is_not_none(audit_log_entries[i].extra_data)),
{"supergroup_ids": [user_group.id]},
)

View File

@@ -1336,6 +1336,7 @@ class SlackImporter(ZulipTestCase):
RealmAuditLog.REALM_CREATED,
RealmAuditLog.USER_GROUP_CREATED,
RealmAuditLog.USER_GROUP_DIRECT_SUBGROUP_MEMBERSHIP_ADDED,
RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_ADDED,
},
)