streams: Allow specifying sender during channel email generation.

This commit adds a `sender_id` parameter to the
`GET /streams/{stream_id}/email_address` endpoint to specify the
ID of a user or bot which should appear as the sender when messages
are sent to a channel using the channel email address.

Earlier, Email gateway bot was always the sender.

Fixes part of #31566.
This commit is contained in:
Prakhar Pratyush
2024-12-05 18:45:21 +05:30
committed by Tim Abbott
parent 2bb4b70121
commit dc35e79701
10 changed files with 377 additions and 88 deletions

View File

@@ -13,9 +13,10 @@ from typing_extensions import override
from zerver.lib.email_mirror import mirror_email_message
from zerver.lib.email_mirror_helpers import encode_email_address, get_channel_email_token
from zerver.lib.management import ZulipBaseCommand
from zerver.models import Realm
from zerver.models import Realm, UserProfile
from zerver.models.realms import get_realm
from zerver.models.streams import get_stream
from zerver.models.users import get_system_bot, get_user_profile_by_email, get_user_profile_by_id
# This command loads an email from a specified file and sends it
# to the email mirror. Simple emails can be passed in a JSON file,
@@ -55,11 +56,17 @@ Example:
help="The name of the stream to which you'd like to send "
"the message. Default: Denmark",
)
parser.add_argument(
"--sender-id",
type=int,
help="The ID of a user or bot which should appear as the sender; "
"Default: ID of Email gateway bot",
)
self.add_realm_args(parser, help="Specify which realm to connect to; default is zulip")
@override
def handle(self, *args: Any, **options: str | None) -> None:
def handle(self, *args: Any, **options: Any) -> None:
if options["fixture"] is None:
self.print_help("./manage.py", "send_to_email_mirror")
raise CommandError
@@ -73,11 +80,25 @@ Example:
if realm is None:
realm = get_realm("zulip")
email_gateway_bot = get_system_bot(settings.EMAIL_GATEWAY_BOT, realm.id)
if options["sender_id"] is None:
sender = email_gateway_bot
else:
sender = get_user_profile_by_id(options["sender_id"])
full_fixture_path = os.path.join(settings.DEPLOY_ROOT, options["fixture"])
# parse the input email into EmailMessage type and prepare to process_message() it
message = self._parse_email_fixture(full_fixture_path)
self._prepare_message(message, realm, stream)
creator = get_user_profile_by_email(message["From"])
if (
sender.id not in [creator.id, email_gateway_bot.id]
and sender.bot_owner_id != creator.id
):
raise CommandError(
"The sender ID must be either the current user's ID, the email gateway bot's ID, or the ID of a bot owned by the user."
)
self._prepare_message(message, realm, stream, creator, sender)
mirror_email_message(
message["To"].addresses[0].addr_spec,
@@ -109,9 +130,16 @@ Example:
_class=EmailMessage, policy=email.policy.default
).parse(fp)
def _prepare_message(self, message: EmailMessage, realm: Realm, stream_name: str) -> None:
def _prepare_message(
self,
message: EmailMessage,
realm: Realm,
stream_name: str,
creator: UserProfile,
sender: UserProfile,
) -> None:
stream = get_stream(stream_name, realm)
email_token = get_channel_email_token(stream)
email_token = get_channel_email_token(stream, creator=creator, sender=sender)
# The block below ensures that the imported email message doesn't have any recipient-like
# headers that are inconsistent with the recipient we want (the stream address).