diff --git a/zerver/lib/actions.py b/zerver/lib/actions.py index a5158fb057..db19819260 100644 --- a/zerver/lib/actions.py +++ b/zerver/lib/actions.py @@ -1386,8 +1386,12 @@ def do_schedule_messages(messages: Sequence[Mapping[str, Any]]) -> List[int]: return [scheduled_message.id for scheduled_message in scheduled_messages] -def build_message_send_dict(message_dict: MutableMapping[str, Any], - email_gateway: bool=False) -> MutableMapping[str, Any]: +def build_message_send_dict(message_dict: Dict[str, Any], + email_gateway: bool=False) -> Dict[str, Any]: + """Returns a dictionary that can be passed into do_send_messages. In + production, this is always called by check_message, but some + testing code paths call it directly. + """ message_dict['stream'] = message_dict.get('stream', None) message_dict['local_id'] = message_dict.get('local_id', None) message_dict['sender_queue_id'] = message_dict.get('sender_queue_id', None) @@ -1488,9 +1492,6 @@ def do_send_messages(messages_maybe_none: Sequence[Optional[MutableMapping[str, new_messages.append(message) messages = new_messages - for message_dict in messages: - message_dict = build_message_send_dict(message_dict, email_gateway) - # Save the message receipts in the database user_message_flags: Dict[int, Dict[int, List[str]]] = defaultdict(dict) with transaction.atomic(): @@ -2296,7 +2297,8 @@ def check_message(sender: UserProfile, client: Client, addressee: Addressee, forwarder_user_profile: Optional[UserProfile]=None, local_id: Optional[str]=None, sender_queue_id: Optional[str]=None, - widget_content: Optional[str]=None) -> Dict[str, Any]: + widget_content: Optional[str]=None, + email_gateway: bool=False) -> Dict[str, Any]: """See https://zulip.readthedocs.io/en/latest/subsystems/sending-messages.html for high-level documentation on this subsystem. @@ -2396,14 +2398,16 @@ def check_message(sender: UserProfile, client: Client, addressee: Addressee, error_msg=error.message, )) - return {'message': message, 'stream': stream, 'local_id': local_id, - 'sender_queue_id': sender_queue_id, 'realm': realm, - 'widget_content': widget_content} + message_dict = {'message': message, 'stream': stream, 'local_id': local_id, + 'sender_queue_id': sender_queue_id, 'realm': realm, + 'widget_content': widget_content} + return build_message_send_dict(message_dict, email_gateway) def _internal_prep_message(realm: Realm, sender: UserProfile, addressee: Addressee, - content: str) -> Optional[Dict[str, Any]]: + content: str, + email_gateway: bool=False) -> Optional[Dict[str, Any]]: """ Create a message object and checks it, but doesn't send it or save it to the database. The internal function that calls this can therefore batch send a bunch of created @@ -2426,7 +2430,7 @@ def _internal_prep_message(realm: Realm, try: return check_message(sender, get_client("Internal"), addressee, - content, realm=realm) + content, realm=realm, email_gateway=email_gateway) except JsonableError as e: logging.exception("Error queueing internal message by %s: %s", sender.delivery_email, e.msg, stack_info=True) @@ -2435,6 +2439,7 @@ def _internal_prep_message(realm: Realm, def internal_prep_stream_message( realm: Realm, sender: UserProfile, stream: Stream, topic: str, content: str, + email_gateway: bool=False, ) -> Optional[Dict[str, Any]]: """ See _internal_prep_message for details of how this works. @@ -2446,6 +2451,7 @@ def internal_prep_stream_message( sender=sender, addressee=addressee, content=content, + email_gateway=email_gateway, ) def internal_prep_stream_message_by_name( @@ -2500,12 +2506,12 @@ def internal_send_stream_message( message = internal_prep_stream_message( realm, sender, stream, - topic, content, + topic, content, email_gateway ) if message is None: return None - message_ids = do_send_messages([message], email_gateway=email_gateway) + message_ids = do_send_messages([message]) return message_ids[0] def internal_send_stream_message_by_name( diff --git a/zerver/management/commands/deliver_scheduled_messages.py b/zerver/management/commands/deliver_scheduled_messages.py index fcfa2f9ec1..481762bde1 100644 --- a/zerver/management/commands/deliver_scheduled_messages.py +++ b/zerver/management/commands/deliver_scheduled_messages.py @@ -8,7 +8,7 @@ from django.core.management.base import BaseCommand from django.db import transaction from django.utils.timezone import now as timezone_now -from zerver.lib.actions import do_send_messages +from zerver.lib.actions import build_message_send_dict, do_send_messages from zerver.lib.logging_util import log_to_file from zerver.lib.management import sleep_forever from zerver.models import Message, ScheduledMessage, get_user_by_delivery_email @@ -44,8 +44,9 @@ Usage: ./manage.py deliver_scheduled_messages elif delivery_type == ScheduledMessage.REMIND: message.sender = get_user_by_delivery_email(settings.NOTIFICATION_BOT, original_sender.realm) - return {'message': message, 'stream': scheduled_message.stream, - 'realm': scheduled_message.realm} + message_dict = {'message': message, 'stream': scheduled_message.stream, + 'realm': scheduled_message.realm} + return build_message_send_dict(message_dict) def handle(self, *args: Any, **options: Any) -> None: diff --git a/zerver/tests/test_message_send.py b/zerver/tests/test_message_send.py index 9d4c04ead0..b8d6f8da56 100644 --- a/zerver/tests/test_message_send.py +++ b/zerver/tests/test_message_send.py @@ -11,6 +11,7 @@ from django.utils.timezone import now as timezone_now from zerver.decorator import JsonableError from zerver.lib.actions import ( + build_message_send_dict, check_message, check_send_stream_message, do_change_is_api_super_user, @@ -1142,7 +1143,8 @@ class StreamMessagesTest(ZulipTestCase): sending_client=sending_client, ) message.set_topic_name(topic_name) - do_send_messages([dict(message=message)]) + message_dict = build_message_send_dict({'message': message}) + do_send_messages([message_dict]) before_um_count = UserMessage.objects.count() diff --git a/zilencer/management/commands/populate_db.py b/zilencer/management/commands/populate_db.py index 17f57ac3f7..5292f8556c 100644 --- a/zilencer/management/commands/populate_db.py +++ b/zilencer/management/commands/populate_db.py @@ -17,6 +17,7 @@ from django.utils.timezone import timedelta as timezone_timedelta from scripts.lib.zulip_tools import get_or_create_dev_uuid_var_path from zerver.lib.actions import ( STREAM_ASSIGNMENT_COLORS, + build_message_send_dict, check_add_realm_emoji, do_change_user_role, do_send_messages, @@ -792,7 +793,11 @@ def send_messages(messages: List[Message]) -> None: # up with queued events that reference objects from a previous # life of the database, which naturally throws exceptions. settings.USING_RABBITMQ = False - do_send_messages([{'message': message} for message in messages]) + message_dict_list = [] + for message in messages: + message_dict = build_message_send_dict({'message': message}) + message_dict_list.append(message_dict) + do_send_messages(message_dict_list) bulk_create_reactions(messages) settings.USING_RABBITMQ = True