Пример #1
0
    def send_message(self, message: Dict[str, Any]) -> None:
        if not self._rate_limit.is_legal():
            self._rate_limit.show_error_and_exit()

        if message['type'] == 'stream':
            internal_send_stream_message_by_name(
                self.user_profile.realm, self.user_profile,
                message['to'], message['topic'], message['content']
            )
            return

        assert message['type'] == 'private'
        # Ensure that it's a comma-separated list, even though the
        # usual 'to' field could be either a List[str] or a str.
        recipients = ','.join(message['to']).split(',')

        if len(message['to']) == 0:
            raise EmbeddedBotEmptyRecipientsList(_('Message must have recipients!'))
        elif len(message['to']) == 1:
            recipient_user = get_active_user(recipients[0], self.user_profile.realm)
            internal_send_private_message(self.user_profile.realm, self.user_profile,
                                          recipient_user, message['content'])
        else:
            internal_send_huddle_message(self.user_profile.realm, self.user_profile,
                                         recipients, message['content'])
Пример #2
0
def send_initial_pms(user):
    # type: (UserProfile) -> None
    content = """Welcome to Zulip!

This is a great place to test formatting, sending, and editing messages.
Click anywhere on this message to reply. A compose box will open at the bottom of the screen."""

    internal_send_private_message(user.realm, get_system_bot(settings.WELCOME_BOT),
                                  user.email, content)
Пример #3
0
def send_initial_pms(user):
    # type: (UserProfile) -> None
    content = (
        "Hello, and welcome to Zulip!\n\nThis is a private message from me, Welcome Bot. "
        "Here are some tips to get you started:\n"
        "* Download our [Desktop and mobile apps](/apps)\n"
        "* Customize your account and notifications on your [Settings page](#settings).\n"
        "* Check out our !modal_link(#keyboard-shortcuts, Keyboard shortcuts)\n\n"
        "The most important shortcut is `r` or `Enter` to reply.\n\n"
        "Practice sending a few messages by replying to this conversation. If you're not into "
        "keyboards, that's okay too; clicking anywhere on this message will also do the trick!")

    internal_send_private_message(user.realm, get_system_bot(settings.WELCOME_BOT),
                                  user.email, content)
Пример #4
0
    def test_cross_realm_file_access(self):
        # type: () -> None

        def create_user(email, realm_id):
            # type: (Text, Text) -> UserProfile
            self.register(email, 'test', subdomain=realm_id)
            return get_user(email, get_realm(realm_id))

        test_subdomain = "uploadtest.example.com"
        user1_email = '*****@*****.**'
        user2_email = '*****@*****.**'
        user3_email = '*****@*****.**'

        r1 = Realm.objects.create(string_id=test_subdomain, invite_required=False)
        RealmDomain.objects.create(realm=r1, domain=test_subdomain)

        create_user(user1_email, test_subdomain)
        create_user(user2_email, 'zulip')
        create_user(user3_email, test_subdomain)

        # Send a message from @zulip.com -> @uploadtest.example.com
        self.login(user2_email, 'test')
        fp = StringIO("zulip!")
        fp.name = "zulip.txt"
        result = self.client_post("/json/user_uploads", {'file': fp})
        uri = result.json()['uri']
        fp_path_id = re.sub('/user_uploads/', '', uri)
        body = "First message ...[zulip.txt](http://localhost:9991/user_uploads/" + fp_path_id + ")"
        with self.settings(CROSS_REALM_BOT_EMAILS = set((user2_email, user3_email))):
            internal_send_private_message(
                realm=r1,
                sender=get_system_bot(user2_email),
                recipient_user=get_user(user1_email, r1),
                content=body,
            )

        self.login(user1_email, 'test')
        response = self.client_get(uri, subdomain=test_subdomain)
        self.assertEqual(response.status_code, 200)
        data = b"".join(response.streaming_content)
        self.assertEqual(b"zulip!", data)
        self.logout()

        # Confirm other cross-realm users can't read it.
        self.login(user3_email, 'test')
        response = self.client_get(uri, subdomain=test_subdomain)
        self.assertEqual(response.status_code, 403)
        self.assert_in_response("You are not authorized to view this file.", response)
Пример #5
0
def approve_sponsorship(realm: Realm) -> None:
    from zerver.lib.actions import do_change_plan_type, internal_send_private_message
    do_change_plan_type(realm, Realm.STANDARD_FREE)
    customer = get_customer_by_realm(realm)
    if customer is not None and customer.sponsorship_pending:
        customer.sponsorship_pending = False
        customer.save(update_fields=["sponsorship_pending"])
    notification_bot = get_system_bot(settings.NOTIFICATION_BOT)
    for billing_admin in realm.get_human_billing_admin_users():
        with override_language(billing_admin.default_language):
            # Using variable to make life easier for translators if these details change.
            plan_name = "Zulip Cloud Standard"
            emoji = ":tada:"
            message = _(
                f"Your organization's request for sponsored hosting has been approved! {emoji}.\n"
                f"You have been upgraded to {plan_name}, free of charge.")
            internal_send_private_message(billing_admin.realm,
                                          notification_bot, billing_admin,
                                          message)
Пример #6
0
def process_missed_message(to: str, message: EmailMessage) -> None:
    mm_address = get_usable_missed_message_address(to)
    mm_address.increment_times_used()

    user_profile = mm_address.user_profile
    topic = mm_address.message.topic_name()

    if mm_address.message.recipient.type == Recipient.PERSONAL:
        # We need to reply to the sender so look up their personal recipient_id
        recipient = mm_address.message.sender.recipient
    else:
        recipient = mm_address.message.recipient

    if not is_user_active(user_profile):
        logger.warning("Sending user is not active. Ignoring this message notification email.")
        return

    body = construct_zulip_body(message, user_profile.realm)

    if recipient.type == Recipient.STREAM:
        stream = get_stream_by_id_in_realm(recipient.type_id, user_profile.realm)
        send_mm_reply_to_stream(user_profile, stream, topic, body)
        recipient_str = stream.name
    elif recipient.type == Recipient.PERSONAL:
        display_recipient = get_display_recipient(recipient)
        assert not isinstance(display_recipient, str)
        recipient_str = display_recipient[0]["email"]
        recipient_user = get_user(recipient_str, user_profile.realm)
        internal_send_private_message(user_profile, recipient_user, body)
    elif recipient.type == Recipient.HUDDLE:
        display_recipient = get_display_recipient(recipient)
        assert not isinstance(display_recipient, str)
        emails = [user_dict["email"] for user_dict in display_recipient]
        recipient_str = ", ".join(emails)
        internal_send_huddle_message(user_profile.realm, user_profile, emails, body)
    else:
        raise AssertionError("Invalid recipient type!")

    logger.info(
        "Successfully processed email from user %s to %s",
        user_profile.id,
        recipient_str,
    )
Пример #7
0
def send_mm_reply_to_stream(
    user_profile: UserProfile, stream: Stream, topic: str, body: str
) -> None:
    try:
        check_send_message(
            sender=user_profile,
            client=get_client("Internal"),
            message_type_name="stream",
            message_to=[stream.id],
            topic_name=topic,
            message_content=body,
        )
    except JsonableError as error:
        error_message = "Error sending message to stream {stream} via message notification email reply:\n{error}".format(
            stream=stream.name, error=error.msg
        )
        internal_send_private_message(
            get_system_bot(settings.NOTIFICATION_BOT), user_profile, error_message
        )
Пример #8
0
def send_to_missed_message_address(address: str, message: message.Message) -> None:
    token = get_missed_message_token_from_address(address)
    key = missed_message_redis_key(token)
    result = redis_client.hmget(key, 'user_profile_id', 'recipient_id', 'subject')
    if not all(val is not None for val in result):
        raise ZulipEmailForwardError('Missing missed message address data')
    user_profile_id, recipient_id, subject_b = result  # type: (bytes, bytes, bytes)

    user_profile = get_user_profile_by_id(user_profile_id)
    if not is_user_active(user_profile):
        logger.warning("Sending user is not active. Ignoring this missed message email.")
        return
    recipient = Recipient.objects.get(id=recipient_id)

    body = construct_zulip_body(message, user_profile.realm)

    if recipient.type == Recipient.STREAM:
        stream = get_stream_by_id_in_realm(recipient.type_id, user_profile.realm)
        internal_send_stream_message(
            user_profile.realm, user_profile, stream,
            subject_b.decode('utf-8'), body
        )
        recipient_str = stream.name
    elif recipient.type == Recipient.PERSONAL:
        display_recipient = get_display_recipient(recipient)
        assert not isinstance(display_recipient, str)
        recipient_str = display_recipient[0]['email']
        recipient_user = get_user(recipient_str, user_profile.realm)
        internal_send_private_message(user_profile.realm, user_profile,
                                      recipient_user, body)
    elif recipient.type == Recipient.HUDDLE:
        display_recipient = get_display_recipient(recipient)
        assert not isinstance(display_recipient, str)
        emails = [user_dict['email'] for user_dict in display_recipient]
        recipient_str = ', '.join(emails)
        internal_send_huddle_message(user_profile.realm, user_profile,
                                     emails, body)
    else:
        raise AssertionError("Invalid recipient type!")

    logger.info("Successfully processed email from user %s to %s" % (
        user_profile.id, recipient_str))
Пример #9
0
    def consume(self, event: Mapping[str, Any]) -> None:
        if event['type'] == 'mark_stream_messages_as_read':
            user_profile = get_user_profile_by_id(event['user_profile_id'])
            client = Client.objects.get(id=event['client_id'])

            for stream_id in event['stream_ids']:
                # Since the user just unsubscribed, we don't require
                # an active Subscription object (otherwise, private
                # streams would never be accessible)
                (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id,
                                                               require_active=False)
                do_mark_stream_messages_as_read(user_profile, client, stream)
        elif event['type'] == 'realm_exported':
            realm = Realm.objects.get(id=event['realm_id'])
            output_dir = tempfile.mkdtemp(prefix="zulip-export-")

            public_url = export_realm_wrapper(realm=realm, output_dir=output_dir,
                                              threads=6, upload=True, public_only=True,
                                              delete_after_upload=True)
            assert public_url is not None

            # TODO: This enables support for delete after access, and needs to be tested.
            export_event = RealmAuditLog.objects.get(id=event['id'])
            export_event.extra_data = public_url
            export_event.save(update_fields=['extra_data'])

            # Send a private message notification letting the user who
            # triggered the export know the export finished.
            user_profile = get_user_profile_by_id(event['user_profile_id'])
            content = "Your data export is complete and has been uploaded here:\n\n%s" % (
                public_url,)
            internal_send_private_message(
                realm=user_profile.realm,
                sender=get_system_bot(settings.NOTIFICATION_BOT),
                recipient_user=user_profile,
                content=content
            )

            # For future frontend use, also notify administrator
            # clients that the export happened, including sending the
            # url.
            notify_export_completed(user_profile, public_url)
Пример #10
0
 def _send_cross_realm_personal_message(self) -> int:
     # Send message from bot to users from different realm.
     bot_email = "*****@*****.**"
     zulip_user = self.example_user("hamlet")
     msg_id = internal_send_private_message(
         sender=get_system_bot(bot_email),
         recipient_user=zulip_user,
         content="test message",
     )
     assert msg_id is not None
     return msg_id
Пример #11
0
    def send_message(self, message: Dict[str, Any]) -> None:
        if not self._rate_limit.is_legal():
            self._rate_limit.show_error_and_exit()

        if message['type'] == 'stream':
            internal_send_stream_message(self.user_profile.realm, self.user_profile, message['to'],
                                         message['subject'], message['content'])
            return

        assert message['type'] == 'private'
        # Ensure that it's a comma-separated list, even though the
        # usual 'to' field could be either a List[str] or a str.
        recipients = ','.join(message['to']).split(',')

        if len(message['to']) == 1:
            recipient_user = get_user(recipients[0], self.user_profile.realm)
            internal_send_private_message(self.user_profile.realm, self.user_profile,
                                          recipient_user, message['content'])
        else:
            internal_send_huddle_message(self.user_profile.realm, self.user_profile,
                                         recipients, message['content'])
Пример #12
0
def send_initial_pms(user: UserProfile) -> None:
    organization_setup_text = ""
    if user.is_realm_admin:
        help_url = user.realm.uri + "/help/getting-your-organization-started-with-zulip"
        organization_setup_text = ("* " + _(
            "[Read the guide]({help_url}) for getting your organization started with Zulip"
        ) + "\n").format(help_url=help_url)

    welcome_msg = _("Hello, and welcome to Zulip!")
    if user.realm.demo_organization_scheduled_deletion_date is not None:
        welcome_msg += " " + _(
            "Note that this is a [demo organization]({demo_org_help_url}) and will be automatically deleted in 30 days."
        )

    content = "".join([
        welcome_msg + "\n\n",
        _("This is a private message from me, Welcome Bot.") + " ",
        _("Here are some tips to get you started:") + "\n",
        "* " + _("Download our [Desktop and mobile apps]({apps_url})") + "\n",
        "* " +
        _("Customize your account and notifications on your [Settings page]({settings_url})"
          ) + "\n",
        "* " + _("Type `?` to check out Zulip's keyboard shortcuts") +
        "\n {organization_setup_text}\n",
        _("The most important shortcut is `r` to reply.") + "\n\n",
        _("Practice sending a few messages by replying to this conversation.")
        + " ",
        _("If you're not into keyboards, that's okay too; "
          "clicking anywhere on this message will also do the trick!"),
    ])

    content = content.format(
        apps_url="/apps",
        settings_url="#settings",
        organization_setup_text=organization_setup_text,
        demo_org_help_url="/help/demo-organizations",
    )

    internal_send_private_message(
        get_system_bot(settings.WELCOME_BOT, user.realm_id), user, content)
Пример #13
0
def send_initial_pms(user: UserProfile) -> None:
    organization_setup_text = ""
    if user.is_realm_admin:
        help_url = user.realm.uri + "/help/getting-your-organization-started-with-axxess"
        organization_setup_text = ("* [Read the guide](%s) for getting your organization "
                                   "started with Axxess\n" % (help_url,))

    content = (
        "Hello, and welcome to Axxess!\n\nYour Privacy and Data are now Protected.\n"
        "\nGuaranteed\n"
        "Here are some tips to get you started:\n"
        "* Download our [Desktop and mobile apps](https://axxess.one/apps) \n"
        "* Customize your account and notifications on your [Settings page](#settings)\n"
        "* Type `?` to check out the Axxess keyboard shortcuts\n"
        "%s"
        "\n"
        "The most important shortcut is `r` to reply.\n\n"
        "Sign Up for our support\n") \
        % (organization_setup_text,)

    internal_send_private_message(user.realm, get_system_bot(settings.WELCOME_BOT),
                                  user, content)
Пример #14
0
def send_initial_pms(user: UserProfile) -> None:
    organization_setup_text = ""
    if user.is_realm_admin:
        help_url = user.realm.uri + "/help/getting-your-organization-started-with-zulip"
        organization_setup_text = ("* [Read the guide](%s) for getting your organization "
                                   "started with Zulip\n" % (help_url,))

    content = (
        "Hello, and welcome to Zulip!\n\nThis is a private message from me, Welcome Bot. "
        "Here are some tips to get you started:\n"
        "* Download our [Desktop and mobile apps](/apps)\n"
        "* Customize your account and notifications on your [Settings page](#settings)\n"
        "* Type `?` to check out Zulip's keyboard shortcuts\n"
        "%s"
        "\n"
        "The most important shortcut is `r` to reply.\n\n"
        "Practice sending a few messages by replying to this conversation. If you're not into "
        "keyboards, that's okay too; clicking anywhere on this message will also do the trick!") \
        % (organization_setup_text,)

    internal_send_private_message(user.realm, get_system_bot(settings.WELCOME_BOT),
                                  user, content)
Пример #15
0
 def _send_cross_realm_message(self) -> int:
     # Send message from bot to users from different realm.
     bot_email = '*****@*****.**'
     get_user_profile_by_email(bot_email)
     mit_user = UserProfile.objects.filter(realm=self.mit_realm).first()
     msg_id = internal_send_private_message(
         realm=mit_user.realm,
         sender=get_system_bot(bot_email),
         recipient_user=mit_user,
         content='test message',
     )
     assert msg_id is not None
     return msg_id
Пример #16
0
def send_initial_pms(user: UserProfile) -> None:
    organization_setup_text = ""
    if user.is_realm_admin:
        help_url = user.realm.uri + "/help/getting-your-organization-started-with-zulip"
        organization_setup_text = (
            "* [Read the guide](%s) for getting your organization "
            "started with Zulip\n" % (help_url, ))

    content = (
        "Hello, and welcome to Zineya!\n\nThis is a private message from me, Zineya Bot. "
        "Here are some tips to get you started:\n"
        "* Customize your account and notifications on your [Settings page](#settings)\n"
        "* Type `?` to check out Zineya's keyboard shortcuts\n"
        "%s"
        "\n"
        "The most important shortcut is `r` to reply.\n\n"
        "Practice sending a few messages by replying to this conversation. If you're not into "
        "keyboards, that's okay too; clicking anywhere on this message will also do the trick!") \
        % (organization_setup_text,)
    print(
        "////////////////////////HEY THERE THIS IS WELCOME BOT FUNCTION UPPPER //////////////////////"
    )
    print(
        "//////////// ///////////////////////////////////////////////////////////////////////////////"
    )
    print(
        "//////////// ///////////////////////////////////////////////////////////////////////////////"
    )
    welcome_bot = get_system_bot(settings.WELCOME_BOT)
    #welcome_bots = welcome_bot.replace('*****@*****.**',  'test-bot@localhost')
    print(welcome_bot.email)
    welcome_bot.email = "test-bot@localhost"
    welcome_bot.full_name = "Zineya"
    welcome_bot.short_name = "Zineya"
    welcome_bot.api_key = "cTVr9MrmB5OZQqOlx3vc7B5R6Ac3Hafd"
    welcome_bot.delivery_email = "test-bot@localhost"
    welcome_bot.id = 19
    print(welcome_bot.email)
    internal_send_private_message(user.realm, welcome_bot, user, content)
Пример #17
0
def send_to_missed_message_address(address: str, message: message.Message) -> None:
    token = get_missed_message_token_from_address(address)
    key = missed_message_redis_key(token)
    result = redis_client.hmget(key, 'user_profile_id', 'recipient_id', 'subject')
    if not all(val is not None for val in result):
        raise ZulipEmailForwardError('Missing missed message address data')
    user_profile_id, recipient_id, subject_b = result  # type: (bytes, bytes, bytes)

    user_profile = get_user_profile_by_id(user_profile_id)
    recipient = Recipient.objects.get(id=recipient_id)

    body = construct_zulip_body(message, user_profile.realm)

    if recipient.type == Recipient.STREAM:
        stream = get_stream_by_id_in_realm(recipient.type_id, user_profile.realm)
        internal_send_stream_message(
            user_profile.realm, user_profile, stream,
            subject_b.decode('utf-8'), body
        )
        recipient_str = stream.name
    elif recipient.type == Recipient.PERSONAL:
        display_recipient = get_display_recipient(recipient)
        assert not isinstance(display_recipient, str)
        recipient_str = display_recipient[0]['email']
        recipient_user = get_user(recipient_str, user_profile.realm)
        internal_send_private_message(user_profile.realm, user_profile,
                                      recipient_user, body)
    elif recipient.type == Recipient.HUDDLE:
        display_recipient = get_display_recipient(recipient)
        assert not isinstance(display_recipient, str)
        emails = [user_dict['email'] for user_dict in display_recipient]
        recipient_str = ', '.join(emails)
        internal_send_huddle_message(user_profile.realm, user_profile,
                                     emails, body)
    else:
        raise AssertionError("Invalid recipient type!")

    logger.info("Successfully processed email from %s to %s" % (
        user_profile.email, recipient_str))
Пример #18
0
def send_initial_pms(user: UserProfile) -> None:
    organization_setup_text = ""
    if user.is_realm_admin:
        help_url = user.realm.uri + "/help/getting-your-organization-started-with-zulip"
        organization_setup_text = ("* [Read the guide](%s) for getting your organization "
                                   "started with Zulip\n" % (help_url,))

    content = (
        "Hello, and welcome to Zulip!\n\nThis is a private message from me, Welcome Bot. "
        "Here are some tips to get you started:\n"
        "* Download our [Desktop and mobile apps](/apps)\n"
        "* Customize your account and notifications on your [Settings page](#settings)\n"
        "* Type `?` to check out Zulip's keyboard shortcuts\n"
        "%s"
        "\n"
        "The most important shortcut is `r` to reply.\n\n"
        "Practice sending a few messages by replying to this conversation. If you're not into "
        "keyboards, that's okay too; clicking anywhere on this message will also do the trick!") \
        % (organization_setup_text,)

    internal_send_private_message(user.realm, get_system_bot(settings.WELCOME_BOT),
                                  user, content)
Пример #19
0
def send_initial_pms(user: UserProfile) -> None:
    organization_setup_text = ""
    if user.is_realm_admin:
        help_url = user.realm.uri + "/help/getting-your-organization-started-with-zulip"
        organization_setup_text = (" " + _(
            "We also have a guide for [Setting up your organization]({help_url})."
        )).format(help_url=help_url)

    welcome_msg = _("Hello, and welcome to Zulip!") + "👋"
    demo_org_warning = ""
    if user.realm.demo_organization_scheduled_deletion_date is not None:
        demo_org_warning = (_(
            "Note that this is a [demo organization]({demo_org_help_url}) and will be "
            "**automatically deleted** in 30 days.") + "\n\n")

    content = "".join([
        welcome_msg + " ",
        _("This is a private message from me, Welcome Bot.") + "\n\n",
        _("If you are new to Zulip, check out our [Getting started guide]({getting_started_url})!"
          ),
        "{organization_setup_text}" + "\n\n",
        "{demo_org_warning}",
        _("I can also help you get set up! Just click anywhere on this message or press `r` to reply."
          ) + "\n\n",
        _("Here are a few messages I understand:") + " ",
        bot_commands(is_initial_pm=True),
    ])

    content = content.format(
        organization_setup_text=organization_setup_text,
        demo_org_warning=demo_org_warning,
        demo_org_help_url="/help/demo-organizations",
        getting_started_url="/help/getting-started-with-zulip",
    )

    internal_send_private_message(
        get_system_bot(settings.WELCOME_BOT, user.realm_id), user, content)
Пример #20
0
    def consume(self, event: Dict[str, Any]) -> None:
        start = time.time()
        if event["type"] == "mark_stream_messages_as_read":
            user_profile = get_user_profile_by_id(event["user_profile_id"])

            for recipient_id in event["stream_recipient_ids"]:
                count = do_mark_stream_messages_as_read(
                    user_profile, recipient_id)
                logger.info(
                    "Marked %s messages as read for user %s, stream_recipient_id %s",
                    count,
                    user_profile.id,
                    recipient_id,
                )
        elif event["type"] == "mark_stream_messages_as_read_for_everyone":
            # This event is generated by the stream deactivation code path.
            batch_size = 100
            offset = 0
            while True:
                messages = Message.objects.filter(
                    recipient_id=event["stream_recipient_id"]).order_by(
                        "id")[offset:offset + batch_size]
                UserMessage.objects.filter(message__in=messages).extra(
                    where=[UserMessage.where_unread()]).update(
                        flags=F("flags").bitor(UserMessage.flags.read))
                offset += len(messages)
                if len(messages) < batch_size:
                    break
            logger.info(
                "Marked %s messages as read for all users, stream_recipient_id %s",
                offset,
                event["stream_recipient_id"],
            )
        elif event["type"] == "clear_push_device_tokens":
            try:
                clear_push_device_tokens(event["user_profile_id"])
            except PushNotificationBouncerRetryLaterError:

                def failure_processor(event: Dict[str, Any]) -> None:
                    logger.warning(
                        "Maximum retries exceeded for trigger:%s event:clear_push_device_tokens",
                        event["user_profile_id"],
                    )

                retry_event(self.queue_name, event, failure_processor)
        elif event["type"] == "realm_export":
            realm = Realm.objects.get(id=event["realm_id"])
            output_dir = tempfile.mkdtemp(prefix="zulip-export-")
            export_event = RealmAuditLog.objects.get(id=event["id"])
            user_profile = get_user_profile_by_id(event["user_profile_id"])

            try:
                public_url = export_realm_wrapper(
                    realm=realm,
                    output_dir=output_dir,
                    threads=6,
                    upload=True,
                    public_only=True,
                    delete_after_upload=True,
                )
            except Exception:
                export_event.extra_data = orjson.dumps(
                    dict(failed_timestamp=timezone_now().timestamp(),
                         )).decode()
                export_event.save(update_fields=["extra_data"])
                logging.error(
                    "Data export for %s failed after %s",
                    user_profile.realm.string_id,
                    time.time() - start,
                )
                notify_realm_export(user_profile)
                return

            assert public_url is not None

            # Update the extra_data field now that the export is complete.
            export_event.extra_data = orjson.dumps(
                dict(export_path=urllib.parse.urlparse(public_url).path,
                     )).decode()
            export_event.save(update_fields=["extra_data"])

            # Send a private message notification letting the user who
            # triggered the export know the export finished.
            with override_language(user_profile.default_language):
                content = _(
                    "Your data export is complete and has been uploaded here:\n\n{public_url}"
                ).format(public_url=public_url)
            internal_send_private_message(
                sender=get_system_bot(settings.NOTIFICATION_BOT, realm.id),
                recipient_user=user_profile,
                content=content,
            )

            # For future frontend use, also notify administrator
            # clients that the export happened.
            notify_realm_export(user_profile)
            logging.info(
                "Completed data export for %s in %s",
                user_profile.realm.string_id,
                time.time() - start,
            )

        end = time.time()
        logger.info("deferred_work processed %s event (%dms)", event["type"],
                    (end - start) * 1000)
Пример #21
0
    def consume(self, event: Dict[str, Any]) -> None:
        if event['type'] == 'mark_stream_messages_as_read':
            user_profile = get_user_profile_by_id(event['user_profile_id'])
            client = Client.objects.get(id=event['client_id'])

            for stream_id in event['stream_ids']:
                # Since the user just unsubscribed, we don't require
                # an active Subscription object (otherwise, private
                # streams would never be accessible)
                (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id,
                                                               require_active=False)
                do_mark_stream_messages_as_read(user_profile, client, stream)
        elif event["type"] == 'mark_stream_messages_as_read_for_everyone':
            # This event is generated by the stream deactivation code path.
            batch_size = 100
            offset = 0
            while True:
                messages = Message.objects.filter(recipient_id=event["stream_recipient_id"]) \
                    .order_by("id")[offset:offset + batch_size]
                UserMessage.objects.filter(message__in=messages).extra(where=[UserMessage.where_unread()]) \
                    .update(flags=F('flags').bitor(UserMessage.flags.read))
                offset += len(messages)
                if len(messages) < batch_size:
                    break
        elif event['type'] == 'clear_push_device_tokens':
            try:
                clear_push_device_tokens(event["user_profile_id"])
            except PushNotificationBouncerRetryLaterError:
                def failure_processor(event: Dict[str, Any]) -> None:
                    logger.warning(
                        "Maximum retries exceeded for trigger:%s event:clear_push_device_tokens",
                        event['user_profile_id'])
                retry_event(self.queue_name, event, failure_processor)
        elif event['type'] == 'realm_export':
            start = time.time()
            realm = Realm.objects.get(id=event['realm_id'])
            output_dir = tempfile.mkdtemp(prefix="zulip-export-")
            export_event = RealmAuditLog.objects.get(id=event['id'])
            user_profile = get_user_profile_by_id(event['user_profile_id'])

            try:
                public_url = export_realm_wrapper(realm=realm, output_dir=output_dir,
                                                  threads=6, upload=True, public_only=True,
                                                  delete_after_upload=True)
            except Exception:
                export_event.extra_data = orjson.dumps(dict(
                    failed_timestamp=timezone_now().timestamp(),
                )).decode()
                export_event.save(update_fields=['extra_data'])
                logging.error(
                    "Data export for %s failed after %s",
                    user_profile.realm.string_id, time.time() - start,
                )
                notify_realm_export(user_profile)
                return

            assert public_url is not None

            # Update the extra_data field now that the export is complete.
            export_event.extra_data = orjson.dumps(dict(
                export_path=urllib.parse.urlparse(public_url).path,
            )).decode()
            export_event.save(update_fields=['extra_data'])

            # Send a private message notification letting the user who
            # triggered the export know the export finished.
            with override_language(user_profile.default_language):
                content = _("Your data export is complete and has been uploaded here:\n\n{public_url}").format(public_url=public_url)
            internal_send_private_message(
                realm=user_profile.realm,
                sender=get_system_bot(settings.NOTIFICATION_BOT),
                recipient_user=user_profile,
                content=content,
            )

            # For future frontend use, also notify administrator
            # clients that the export happened.
            notify_realm_export(user_profile)
            logging.info(
                "Completed data export for %s in %s",
                user_profile.realm.string_id, time.time() - start,
            )
Пример #22
0
    def consume(self, event: Dict[str, Any]) -> None:
        if event['type'] == 'mark_stream_messages_as_read':
            user_profile = get_user_profile_by_id(event['user_profile_id'])
            client = Client.objects.get(id=event['client_id'])

            for stream_id in event['stream_ids']:
                # Since the user just unsubscribed, we don't require
                # an active Subscription object (otherwise, private
                # streams would never be accessible)
                (stream, recipient,
                 sub) = access_stream_by_id(user_profile,
                                            stream_id,
                                            require_active=False)
                do_mark_stream_messages_as_read(user_profile, client, stream)
        elif event['type'] == 'clear_push_device_tokens':
            try:
                clear_push_device_tokens(event["user_profile_id"])
            except PushNotificationBouncerRetryLaterError:

                def failure_processor(event: Dict[str, Any]) -> None:
                    logger.warning(
                        "Maximum retries exceeded for trigger:%s event:clear_push_device_tokens",
                        event['user_profile_id'])

                retry_event(self.queue_name, event, failure_processor)
        elif event['type'] == 'realm_export':
            start = time.time()
            realm = Realm.objects.get(id=event['realm_id'])
            output_dir = tempfile.mkdtemp(prefix="zulip-export-")
            export_event = RealmAuditLog.objects.get(id=event['id'])
            user_profile = get_user_profile_by_id(event['user_profile_id'])

            try:
                public_url = export_realm_wrapper(realm=realm,
                                                  output_dir=output_dir,
                                                  threads=6,
                                                  upload=True,
                                                  public_only=True,
                                                  delete_after_upload=True)
            except Exception:
                export_event.extra_data = ujson.dumps(
                    dict(failed_timestamp=timezone_now().timestamp()))
                export_event.save(update_fields=['extra_data'])
                logging.error(
                    "Data export for %s failed after %s",
                    user_profile.realm.string_id,
                    time.time() - start,
                )
                notify_realm_export(user_profile)
                return

            assert public_url is not None

            # Update the extra_data field now that the export is complete.
            export_event.extra_data = ujson.dumps(
                dict(export_path=urllib.parse.urlparse(public_url).path, ))
            export_event.save(update_fields=['extra_data'])

            # Send a private message notification letting the user who
            # triggered the export know the export finished.
            content = "Your data export is complete and has been uploaded here:\n\n%s" % (
                public_url, )
            internal_send_private_message(realm=user_profile.realm,
                                          sender=get_system_bot(
                                              settings.NOTIFICATION_BOT),
                                          recipient_user=user_profile,
                                          content=content)

            # For future frontend use, also notify administrator
            # clients that the export happened.
            notify_realm_export(user_profile)
            logging.info(
                "Completed data export for %s in %s",
                user_profile.realm.string_id,
                time.time() - start,
            )