direct_messages: Add support for DMs to use DM group if exists.

This commit adds support for 1:1 DMs to be represented using
`DirectMessageGroup` object, if there already exists a
`DirectMessageGroup` for that pair of users. If no such group
exists, we fall back to the legacy code.

This is done as a part of migrating 1:1 DMs to be represented
using `DirectMessageGroup`.

Part of #25713
This commit is contained in:
roanster007 2024-10-16 11:35:46 +05:30
parent 746042915a
commit 941a224bb6
8 changed files with 49 additions and 13 deletions

View File

@ -5,6 +5,7 @@ from django.utils.translation import gettext as _
from zerver.models import DirectMessageGroup, Recipient, UserProfile
from zerver.models.recipients import (
check_direct_message_group_exists,
get_direct_message_group_hash,
get_or_create_direct_message_group,
)
@ -34,12 +35,18 @@ def get_recipient_from_user_profiles(
if forwarder_user_profile.id not in recipient_profiles_map:
raise ValidationError(_("User not authorized for this query"))
# If the direct message is just between the sender and
# another person, force it to be a personal internally
if len(recipient_profiles_map) == 2 and sender.id in recipient_profiles_map:
# Make sure the sender is included in the recipient
# profiles map.
recipient_profiles_map[sender.id] = sender
# If the direct message is just between the sender and another
# person or a self DM, and there is no corresponding direct
# message group, force it to be a personal internally.
if len(recipient_profiles_map) <= 2 and not check_direct_message_group_exists(
list(recipient_profiles_map)
):
del recipient_profiles_map[sender.id]
assert recipient_profiles_map
if len(recipient_profiles_map) == 1:
[user_profile] = recipient_profiles_map.values()
return Recipient(
@ -48,8 +55,6 @@ def get_recipient_from_user_profiles(
type_id=user_profile.id,
)
# Otherwise, we need a direct message group. Make sure the sender
# is included in the group direct messages
recipient_profiles_map[sender.id] = sender
user_ids = list(recipient_profiles_map)

View File

@ -149,6 +149,15 @@ class DirectMessageGroup(models.Model):
db_table = "zerver_huddle"
def check_direct_message_group_exists(id_list: list[int]) -> bool:
direct_message_group_hash = get_direct_message_group_hash(id_list)
direct_message_group_exists = DirectMessageGroup.objects.filter(
huddle_hash=direct_message_group_hash
).exists()
return direct_message_group_exists
def get_direct_message_group_hash(id_list: list[int]) -> str:
id_list = sorted(set(id_list))
hash_key = ",".join(str(x) for x in id_list)

View File

@ -1025,7 +1025,7 @@ class TestMissedMessageEmailMessages(ZulipTestCase):
incoming_valid_message["To"] = mm_address
incoming_valid_message["Reply-to"] = self.example_email("othello")
with self.assert_database_query_count(16):
with self.assert_database_query_count(17):
process_message(incoming_valid_message)
# confirm that Hamlet got the message

View File

@ -362,7 +362,7 @@ class TestQueryCounts(ZulipTestCase):
hamlet = self.example_user("hamlet")
cordelia = self.example_user("cordelia")
with self.assert_database_query_count(15):
with self.assert_database_query_count(16):
self.send_personal_message(
from_user=hamlet,
to_user=cordelia,

View File

@ -2463,7 +2463,7 @@ class PersonalMessageSendTest(ZulipTestCase):
# Have the administrator send a message, and verify that allows the user to reply.
self.send_personal_message(admin, user_profile)
with self.assert_database_query_count(16):
with self.assert_database_query_count(17):
self.send_personal_message(user_profile, admin)
# Tests that user cannot initiate direct message thread in groups.
@ -2526,7 +2526,7 @@ class PersonalMessageSendTest(ZulipTestCase):
acting_user=None,
)
# Tests if the user is allowed to send to administrators.
with self.assert_database_query_count(16):
with self.assert_database_query_count(17):
self.send_personal_message(user_profile, admin)
self.send_personal_message(admin, user_profile)
# Tests if we can send messages to self irrespective of the value of the setting.
@ -2586,6 +2586,28 @@ class PersonalMessageSendTest(ZulipTestCase):
"Direct messages are disabled in this organization.",
)
def test_direct_message_represented_as_direct_message_group(self) -> None:
hamlet = self.example_user("hamlet")
iago = self.example_user("iago")
user_ids = [iago.id, hamlet.id]
# A direct message between two users with no corresponding direct message
# group is forced to be personal internally
message_id = self.send_personal_message(iago, hamlet)
message = Message.objects.filter(id=message_id).first()
assert message is not None
self.assertEqual(message.recipient.type, Recipient.PERSONAL)
# A direct message between two users with a direct message group existing,
# becomes a group direct message.
get_or_create_direct_message_group(user_ids)
message_id = self.send_personal_message(iago, hamlet, "test")
message = Message.objects.filter(id=message_id).first()
assert message is not None
self.assertEqual(message.recipient.type, Recipient.DIRECT_MESSAGE_GROUP)
def test_non_ascii_personal(self) -> None:
"""
Sending a direct message containing non-ASCII characters succeeds.

View File

@ -1053,7 +1053,7 @@ class LoginTest(ZulipTestCase):
# to sending messages, such as getting the welcome bot, looking up
# the alert words for a realm, etc.
with (
self.assert_database_query_count(94),
self.assert_database_query_count(95),
self.assert_memcached_count(14),
self.captureOnCommitCallbacks(execute=True),
):

View File

@ -6058,7 +6058,7 @@ class GetSubscribersTest(ZulipTestCase):
polonius.id,
]
with self.assert_database_query_count(43):
with self.assert_database_query_count(46):
self.common_subscribe_to_streams(
self.user_profile,
streams,

View File

@ -1018,7 +1018,7 @@ class QueryCountTest(ZulipTestCase):
prereg_user = PreregistrationUser.objects.get(email="fred@zulip.com")
with (
self.assert_database_query_count(84),
self.assert_database_query_count(86),
self.assert_memcached_count(19),
self.capture_send_event_calls(expected_num_events=10) as events,
):