from dataclasses import asdict from django.db import transaction from django.utils.timezone import now as timezone_now from django.utils.translation import gettext as _ from zerver.lib.channel_folders import get_channel_folder_data, render_channel_folder_description from zerver.lib.exceptions import JsonableError from zerver.models import ChannelFolder, Realm, RealmAuditLog, UserProfile from zerver.models.realm_audit_logs import AuditLogEventType from zerver.models.users import active_user_ids from zerver.tornado.django_api import send_event_on_commit @transaction.atomic(durable=True) def check_add_channel_folder( realm: Realm, name: str, description: str, *, acting_user: UserProfile ) -> ChannelFolder: rendered_description = render_channel_folder_description( description, realm, acting_user=acting_user ) channel_folder = ChannelFolder.objects.create( realm=realm, name=name, description=description, rendered_description=rendered_description, creator_id=acting_user.id, ) channel_folder.order = channel_folder.id channel_folder.save(update_fields=["order"]) creation_time = timezone_now() RealmAuditLog.objects.create( realm=realm, acting_user=acting_user, event_type=AuditLogEventType.CHANNEL_FOLDER_CREATED, event_time=creation_time, modified_channel_folder=channel_folder, ) event = dict( type="channel_folder", op="add", channel_folder=asdict(get_channel_folder_data(channel_folder)), ) send_event_on_commit(realm, event, active_user_ids(realm.id)) return channel_folder @transaction.atomic(durable=True) def try_reorder_realm_channel_folders(realm: Realm, order: list[int]) -> None: order_mapping = {_[1]: _[0] for _ in enumerate(order)} channel_folders = ChannelFolder.objects.filter(realm=realm) for channel_folder in channel_folders: if channel_folder.id not in order_mapping: raise JsonableError(_("Invalid order mapping.")) for channel_folder in channel_folders: channel_folder.order = order_mapping[channel_folder.id] channel_folder.save(update_fields=["order"]) event = dict( type="channel_folder", op="reorder", order=order, ) send_event_on_commit(realm, event, active_user_ids(realm.id)) def do_send_channel_folder_update_event( channel_folder: ChannelFolder, data: dict[str, str | bool] ) -> None: realm = channel_folder.realm event = dict(type="channel_folder", op="update", channel_folder_id=channel_folder.id, data=data) send_event_on_commit(realm, event, active_user_ids(realm.id)) @transaction.atomic(durable=True) def do_change_channel_folder_name( channel_folder: ChannelFolder, name: str, *, acting_user: UserProfile ) -> None: old_value = channel_folder.name channel_folder.name = name channel_folder.save(update_fields=["name"]) RealmAuditLog.objects.create( realm=acting_user.realm, acting_user=acting_user, event_type=AuditLogEventType.CHANNEL_FOLDER_NAME_CHANGED, event_time=timezone_now(), modified_channel_folder=channel_folder, extra_data={ RealmAuditLog.OLD_VALUE: old_value, RealmAuditLog.NEW_VALUE: name, }, ) do_send_channel_folder_update_event(channel_folder, dict(name=name)) @transaction.atomic(durable=True) def do_change_channel_folder_description( channel_folder: ChannelFolder, description: str, *, acting_user: UserProfile ) -> None: old_value = channel_folder.description rendered_description = render_channel_folder_description( description, acting_user.realm, acting_user=acting_user ) channel_folder.description = description channel_folder.rendered_description = rendered_description channel_folder.save(update_fields=["description", "rendered_description"]) RealmAuditLog.objects.create( realm=acting_user.realm, acting_user=acting_user, event_type=AuditLogEventType.CHANNEL_FOLDER_DESCRIPTION_CHANGED, event_time=timezone_now(), modified_channel_folder=channel_folder, extra_data={ RealmAuditLog.OLD_VALUE: old_value, RealmAuditLog.NEW_VALUE: description, }, ) do_send_channel_folder_update_event( channel_folder, dict(description=description, rendered_description=rendered_description) ) @transaction.atomic(durable=True) def do_archive_channel_folder(channel_folder: ChannelFolder, *, acting_user: UserProfile) -> None: channel_folder.is_archived = True channel_folder.save(update_fields=["is_archived"]) RealmAuditLog.objects.create( realm=acting_user.realm, acting_user=acting_user, event_type=AuditLogEventType.CHANNEL_FOLDER_ARCHIVED, event_time=timezone_now(), modified_channel_folder=channel_folder, ) do_send_channel_folder_update_event(channel_folder, dict(is_archived=True)) @transaction.atomic(durable=True) def do_unarchive_channel_folder(channel_folder: ChannelFolder, *, acting_user: UserProfile) -> None: channel_folder.is_archived = False channel_folder.save(update_fields=["is_archived"]) RealmAuditLog.objects.create( realm=acting_user.realm, acting_user=acting_user, event_type=AuditLogEventType.CHANNEL_FOLDER_UNARCHIVED, event_time=timezone_now(), modified_channel_folder=channel_folder, ) do_send_channel_folder_update_event(channel_folder, dict(is_archived=False))