export: Handle RealmAuditLog with .acting_user in different realm.

This commit is contained in:
Mateusz Mandera 2023-05-18 20:33:12 +02:00 committed by Tim Abbott
parent c978bfaa32
commit b55adbef3d
2 changed files with 52 additions and 3 deletions

View File

@ -713,9 +713,8 @@ def get_realm_config() -> Config:
Config(
table="zerver_realmauditlog",
model=RealmAuditLog,
normal_parent=realm_config,
include_rows="realm_id__in",
virtual_parent=realm_config,
custom_fetch=custom_fetch_realm_audit_logs_for_realm,
)
Config(
@ -1152,6 +1151,30 @@ def custom_fetch_scheduled_messages(response: TableData, context: Context) -> No
response["zerver_scheduledmessage"] = rows
def custom_fetch_realm_audit_logs_for_realm(response: TableData, context: Context) -> None:
"""
Simple custom fetch function to fix up .acting_user for some RealmAuditLog objects.
Certain RealmAuditLog objects have an acting_user that is in a different .realm, due to
the possibility of server administrators (typically with the .is_staff permission) taking
certain actions to modify UserProfiles or Realms, which will set the .acting_user to
the administrator's UserProfile, which can be in a different realm. Such an acting_user
cannot be imported during organization import on another server, so we need to just set it
to None.
"""
realm = context["realm"]
query = RealmAuditLog.objects.filter(realm=realm).select_related("acting_user")
realmauditlog_objects = list(query)
for realmauditlog in realmauditlog_objects:
if realmauditlog.acting_user is not None and realmauditlog.acting_user.realm_id != realm.id:
realmauditlog.acting_user = None
rows = make_raw(realmauditlog_objects)
response["zerver_realmauditlog"] = rows
def fetch_usermessages(
realm: Realm,
message_ids: Set[int],

View File

@ -83,6 +83,8 @@ from zerver.models import (
get_huddle_hash,
get_realm,
get_stream,
get_system_bot,
get_user_by_delivery_email,
)
@ -708,6 +710,9 @@ class RealmImportExportTest(ExportFile):
cordelia = self.example_user("cordelia")
othello = self.example_user("othello")
internal_realm = get_realm(settings.SYSTEM_BOT_REALM)
cross_realm_bot = get_system_bot(settings.WELCOME_BOT, internal_realm.id)
with get_test_image_file("img.png") as img_file:
realm_emoji = check_add_realm_emoji(
realm=hamlet.realm, name="hawaii", author=hamlet, image_file=img_file
@ -728,6 +733,18 @@ class RealmImportExportTest(ExportFile):
original_realm, authentication_methods, acting_user=None
)
# Set up an edge-case RealmAuditLog with acting_user in a different realm. Such an acting_user can't be covered
# by the export, so we'll test that it is handled by getting set to None.
self.assertTrue(
RealmAuditLog.objects.filter(
modified_user=hamlet, event_type=RealmAuditLog.USER_CREATED
).count(),
1,
)
RealmAuditLog.objects.filter(
modified_user=hamlet, event_type=RealmAuditLog.USER_CREATED
).update(acting_user_id=cross_realm_bot.id)
# data to test import of huddles
huddle = [
self.example_user("hamlet"),
@ -989,6 +1006,15 @@ class RealmImportExportTest(ExportFile):
imported_realm.authentication_methods_dict(),
)
imported_hamlet = get_user_by_delivery_email(hamlet.delivery_email, imported_realm)
realmauditlog = RealmAuditLog.objects.get(
modified_user=imported_hamlet, event_type=RealmAuditLog.USER_CREATED
)
self.assertEqual(realmauditlog.realm, imported_realm)
# As explained above when setting up the RealmAuditLog row, the .acting_user should have been
# set to None due to being unexportable.
self.assertEqual(realmauditlog.acting_user, None)
self.assertEqual(
Message.objects.filter(realm=original_realm).count(),
Message.objects.filter(realm=imported_realm).count(),