actions: Split out zerver.actions.submessage.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg 2022-04-14 14:31:40 -07:00
parent 62d3b5bfd5
commit 3a135b04d9
6 changed files with 68 additions and 63 deletions

View File

@ -0,0 +1,63 @@
from django.db import transaction
from django.utils.translation import gettext as _
from zerver.lib.exceptions import JsonableError
from zerver.models import Realm, SubMessage, UserMessage
from zerver.tornado.django_api import send_event
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 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()
event = dict(
type="submessage",
msg_type=msg_type,
message_id=message_id,
submessage_id=submessage.id,
sender_id=sender_id,
content=content,
)
ums = UserMessage.objects.filter(message_id=message_id)
target_user_ids = [um.user_profile_id for um in ums]
transaction.on_commit(lambda: send_event(realm, event, target_user_ids))

View File

@ -249,7 +249,6 @@ from zerver.models import (
ScheduledMessageNotificationEmail, ScheduledMessageNotificationEmail,
Service, Service,
Stream, Stream,
SubMessage,
Subscription, Subscription,
UserActivity, UserActivity,
UserActivityInterval, UserActivityInterval,
@ -2333,63 +2332,6 @@ def create_user_messages(
return user_messages return user_messages
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 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()
event = dict(
type="submessage",
msg_type=msg_type,
message_id=message_id,
submessage_id=submessage.id,
sender_id=sender_id,
content=content,
)
ums = UserMessage.objects.filter(message_id=message_id)
target_user_ids = [um.user_profile_id for um in ums]
transaction.on_commit(lambda: send_event(realm, event, target_user_ids))
def notify_reaction_update( def notify_reaction_update(
user_profile: UserProfile, message: Message, reaction: Reaction, op: str user_profile: UserProfile, message: Message, reaction: Reaction, op: str
) -> None: ) -> None:

View File

@ -13,6 +13,7 @@ from unittest import mock
import orjson import orjson
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from zerver.actions.submessage import do_add_submessage
from zerver.actions.typing import check_send_typing_notification, do_send_stream_typing_notification from zerver.actions.typing import check_send_typing_notification, do_send_stream_typing_notification
from zerver.actions.user_groups import ( from zerver.actions.user_groups import (
bulk_add_members_to_user_group, bulk_add_members_to_user_group,
@ -34,7 +35,6 @@ from zerver.lib.actions import (
do_add_realm_domain, do_add_realm_domain,
do_add_realm_playground, do_add_realm_playground,
do_add_streams_to_default_stream_group, do_add_streams_to_default_stream_group,
do_add_submessage,
do_change_avatar_fields, do_change_avatar_fields,
do_change_bot_owner, do_change_bot_owner,
do_change_default_all_public_streams, do_change_default_all_public_streams,

View File

@ -5,8 +5,8 @@ from unittest import mock
from django.conf import settings from django.conf import settings
from django.utils.timezone import now as timezone_now from django.utils.timezone import now as timezone_now
from zerver.actions.submessage import do_add_submessage
from zerver.lib.actions import ( from zerver.lib.actions import (
do_add_submessage,
do_create_realm, do_create_realm,
do_delete_messages, do_delete_messages,
do_set_realm_property, do_set_realm_property,

View File

@ -1,7 +1,7 @@
from typing import Any, Dict, List, Mapping from typing import Any, Dict, List, Mapping
from unittest import mock from unittest import mock
from zerver.lib.actions import do_add_submessage from zerver.actions.submessage import do_add_submessage
from zerver.lib.message import MessageDict from zerver.lib.message import MessageDict
from zerver.lib.test_classes import ZulipTestCase from zerver.lib.test_classes import ZulipTestCase
from zerver.models import Message, SubMessage from zerver.models import Message, SubMessage
@ -196,7 +196,7 @@ class TestBasics(ZulipTestCase):
message_id = self.send_stream_message(hamlet, "Denmark") message_id = self.send_stream_message(hamlet, "Denmark")
with self.tornado_redirected_to_list([], expected_num_events=1): with self.tornado_redirected_to_list([], expected_num_events=1):
with mock.patch("zerver.lib.actions.send_event") as m: with mock.patch("zerver.actions.submessage.send_event") as m:
m.side_effect = AssertionError( m.side_effect = AssertionError(
"Events should be sent only after the transaction commits." "Events should be sent only after the transaction commits."
) )

View File

@ -4,7 +4,7 @@ from django.db import transaction
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from zerver.lib.actions import do_add_submessage, verify_submessage_sender from zerver.actions.submessage import do_add_submessage, verify_submessage_sender
from zerver.lib.exceptions import JsonableError from zerver.lib.exceptions import JsonableError
from zerver.lib.message import access_message from zerver.lib.message import access_message
from zerver.lib.request import REQ, has_request_variables from zerver.lib.request import REQ, has_request_variables