zulip/zerver/actions/submessage.py

97 lines
3.2 KiB
Python

from django.utils.translation import gettext as _
from zerver.actions.user_topics import do_set_user_topic_visibility_policy
from zerver.lib.exceptions import JsonableError
from zerver.lib.message import (
event_recipient_ids_for_action_on_messages,
set_visibility_policy_possible,
should_change_visibility_policy,
visibility_policy_for_participation,
)
from zerver.lib.streams import access_stream_by_id
from zerver.models import Realm, SubMessage, UserProfile
from zerver.tornado.django_api import send_event_on_commit
def verify_submessage_sender(
*,
message_id: int,
message_sender_id: int,
submessage_sender_id: int,
) -> None:
"""Even though our submessage architecture is geared toward
collaboration among all message readers, we still enforce
the first person to attach a submessage to the message
must be the original sender of the message.
"""
if message_sender_id == submessage_sender_id:
return
if SubMessage.objects.filter(
message_id=message_id,
sender_id=message_sender_id,
).exists():
return
raise JsonableError(_("You cannot attach a submessage to this message."))
def do_add_submessage(
realm: Realm,
sender_id: int,
message_id: int,
msg_type: str,
content: str,
) -> None:
"""Should be called while holding a SELECT FOR UPDATE lock
(e.g. via access_message(..., lock_message=True)) on the
Message row, to prevent race conditions.
"""
submessage = SubMessage(
sender_id=sender_id,
message_id=message_id,
msg_type=msg_type,
content=content,
)
submessage.save()
# Determine and set the visibility_policy depending on 'automatically_follow_topics_policy'
# and 'automatically_unmute_topics_policy'.
sender = submessage.sender
if set_visibility_policy_possible(
sender, submessage.message
) and UserProfile.AUTOMATICALLY_CHANGE_VISIBILITY_POLICY_ON_PARTICIPATION in [
sender.automatically_follow_topics_policy,
sender.automatically_unmute_topics_in_muted_streams_policy,
]:
stream_id = submessage.message.recipient.type_id
(stream, sub) = access_stream_by_id(sender, stream_id)
assert stream is not None
if sub:
new_visibility_policy = visibility_policy_for_participation(sender, sub.is_muted)
if new_visibility_policy and should_change_visibility_policy(
new_visibility_policy,
sender,
stream_id,
topic_name=submessage.message.topic_name(),
):
do_set_user_topic_visibility_policy(
user_profile=sender,
stream=stream,
topic_name=submessage.message.topic_name(),
visibility_policy=new_visibility_policy,
)
event = dict(
type="submessage",
msg_type=msg_type,
message_id=message_id,
submessage_id=submessage.id,
sender_id=sender_id,
content=content,
)
target_user_ids = event_recipient_ids_for_action_on_messages([submessage.message])
send_event_on_commit(realm, event, target_user_ids)