user_groups: Populate membership audit logs during realm creation.

This tracks user group membership changes when the realm is first set
up, either through an import or not. This happens when we add users to
the system user groups by their roles.

For an imported realm, we do extra handling when the data doesn't include
user groups. This gets audited as well.
This commit is contained in:
Zixuan James Li
2023-07-12 13:13:17 -04:00
committed by Tim Abbott
parent 1af50548ae
commit e9e18454d2
5 changed files with 87 additions and 0 deletions

View File

@@ -1,6 +1,7 @@
from typing import Any, Collection, Dict, Iterable, List, Optional, Set, Tuple, Type, Union
from django.db.models import Model
from django.utils.timezone import now as timezone_now
from zerver.lib.create_user import create_user_profile, get_display_email_address
from zerver.lib.initial_password import initial_password
@@ -146,6 +147,18 @@ def bulk_create_users(
)
UserGroupMembership.objects.bulk_create(group_memberships_to_create)
now = timezone_now()
RealmAuditLog.objects.bulk_create(
RealmAuditLog(
realm=realm,
modified_user=membership.user_profile,
modified_user_group=membership.user_group,
event_type=RealmAuditLog.USER_GROUP_DIRECT_USER_MEMBERSHIP_ADDED,
event_time=now,
acting_user=None,
)
for membership in group_memberships_to_create
)
def bulk_set_users_or_streams_recipient_fields(

View File

@@ -1677,3 +1677,15 @@ def add_users_to_system_user_groups(
UserGroupMembership(user_profile=user_profile, user_group=full_members_system_group)
)
UserGroupMembership.objects.bulk_create(usergroup_memberships)
now = timezone_now()
RealmAuditLog.objects.bulk_create(
RealmAuditLog(
realm=realm,
modified_user=membership.user_profile,
modified_user_group=membership.user_group,
event_type=RealmAuditLog.USER_GROUP_DIRECT_USER_MEMBERSHIP_ADDED,
event_time=now,
acting_user=None,
)
for membership in usergroup_memberships
)

View File

@@ -1,6 +1,7 @@
import datetime
import os
import shutil
from collections import defaultdict
from typing import Any, Callable, Dict, FrozenSet, Iterable, List, Optional, Set, Tuple
from unittest.mock import patch
@@ -1550,6 +1551,35 @@ class RealmImportExportTest(ExportFile):
).exists()
)
def test_system_usergroup_audit_logs(self) -> None:
realm = get_realm("zulip")
self.export_realm(realm)
# Simulate an external export where user groups are missing.
data = read_json("realm.json")
data.pop("zerver_usergroup")
data.pop("zerver_realmauditlog")
with open(export_fn("realm.json"), "wb") as f:
f.write(orjson.dumps(data))
with self.assertLogs(level="INFO"):
imported_realm = do_import_realm(get_output_dir(), "test-zulip-1")
user_membership_logs = RealmAuditLog.objects.filter(
realm=imported_realm,
event_type=RealmAuditLog.USER_GROUP_DIRECT_USER_MEMBERSHIP_ADDED,
).values_list("modified_user_id", "modified_user_group__name")
logged_membership_by_user_id = defaultdict(set)
for user_id, user_group_name in user_membership_logs:
logged_membership_by_user_id[user_id].add(user_group_name)
# Make sure that all users get logged as a member in their
# corresponding system groups.
for user in UserProfile.objects.filter(realm=imported_realm):
expected_group_names = {UserGroup.SYSTEM_USER_GROUP_ROLE_MAP[user.role]["name"]}
if UserGroup.MEMBERS_GROUP_NAME in expected_group_names:
expected_group_names.add(UserGroup.FULL_MEMBERS_GROUP_NAME)
self.assertSetEqual(logged_membership_by_user_id[user.id], expected_group_names)
class SingleUserExportTest(ExportFile):
def do_files_test(self, is_s3: bool) -> None:

View File

@@ -1335,6 +1335,7 @@ class SlackImporter(ZulipTestCase):
RealmAuditLog.REALM_PLAN_TYPE_CHANGED,
RealmAuditLog.REALM_CREATED,
RealmAuditLog.USER_GROUP_CREATED,
RealmAuditLog.USER_GROUP_DIRECT_USER_MEMBERSHIP_ADDED,
RealmAuditLog.USER_GROUP_DIRECT_SUBGROUP_MEMBERSHIP_ADDED,
RealmAuditLog.USER_GROUP_DIRECT_SUPERGROUP_MEMBERSHIP_ADDED,
RealmAuditLog.USER_GROUP_GROUP_BASED_SETTING_CHANGED,

View File

@@ -55,12 +55,14 @@ from zerver.models import (
InvalidFakeEmailDomainError,
Message,
PreregistrationUser,
RealmAuditLog,
RealmDomain,
RealmUserDefault,
Recipient,
ScheduledEmail,
Stream,
Subscription,
UserGroup,
UserGroupMembership,
UserHotspot,
UserProfile,
@@ -850,13 +852,42 @@ class BulkCreateUserTest(ZulipTestCase):
("Cher", "cher@zulip.com"),
]
now = timezone_now()
expected_user_group_names = {
UserGroup.MEMBERS_GROUP_NAME,
UserGroup.FULL_MEMBERS_GROUP_NAME,
}
create_users(realm, name_list)
bono = get_user_by_delivery_email("bono@zulip.com", realm)
self.assertEqual(bono.email, "bono@zulip.com")
self.assertEqual(bono.delivery_email, "bono@zulip.com")
user_group_names = set(
RealmAuditLog.objects.filter(
realm=realm,
modified_user=bono,
event_type=RealmAuditLog.USER_GROUP_DIRECT_USER_MEMBERSHIP_ADDED,
event_time__gte=now,
).values_list("modified_user_group__name", flat=True)
)
self.assertSetEqual(
user_group_names,
expected_user_group_names,
)
cher = get_user_by_delivery_email("cher@zulip.com", realm)
self.assertEqual(cher.full_name, "Cher")
user_group_names = set(
RealmAuditLog.objects.filter(
realm=realm,
modified_user=cher,
event_type=RealmAuditLog.USER_GROUP_DIRECT_USER_MEMBERSHIP_ADDED,
event_time__gte=now,
).values_list("modified_user_group__name", flat=True)
)
self.assertSetEqual(
user_group_names,
expected_user_group_names,
)
class AdminCreateUserTest(ZulipTestCase):