示例#1
0
文件: streams.py 项目: gnprice/zulip
def update_stream_backend(
        request: HttpRequest, user_profile: UserProfile,
        stream_id: int,
        description: Optional[Text]=REQ(validator=check_string, default=None),
        is_private: Optional[bool]=REQ(validator=check_bool, default=None),
        new_name: Optional[Text]=REQ(validator=check_string, default=None),
) -> HttpResponse:
    # We allow realm administrators to to update the stream name and
    # description even for private streams.
    stream = access_stream_for_delete_or_update(user_profile, stream_id)
    if description is not None:
        do_change_stream_description(stream, description)
    if new_name is not None:
        new_name = new_name.strip()
        if stream.name == new_name:
            return json_error(_("Stream already has that name!"))
        if stream.name.lower() != new_name.lower():
            # Check that the stream name is available (unless we are
            # are only changing the casing of the stream name).
            check_stream_name_available(user_profile.realm, new_name)
        do_rename_stream(stream, new_name)

    # But we require even realm administrators to be actually
    # subscribed to make a private stream public.
    if is_private is not None:
        (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)
        do_change_stream_invite_only(stream, is_private)
    return json_success()
示例#2
0
    def test_add_bot_with_default_sending_stream_private_denied(self) -> None:
        self.login(self.example_email('hamlet'))
        realm = self.example_user('hamlet').realm
        stream = get_stream("Denmark", realm)
        self.unsubscribe(self.example_user('hamlet'), "Denmark")
        do_change_stream_invite_only(stream, True)

        bot_info = {
            'full_name': 'The Bot of Hamlet',
            'short_name': 'hambot',
            'default_sending_stream': 'Denmark',
        }
        result = self.client_post("/json/bots", bot_info)
        self.assert_json_error(result, "Invalid stream name 'Denmark'")
示例#3
0
    def test_patch_bot_events_register_stream_denied(self) -> None:
        self.login(self.example_email('hamlet'))
        realm = self.example_user('hamlet').realm
        stream = get_stream("Denmark", realm)
        self.unsubscribe(self.example_user('hamlet'), "Denmark")
        do_change_stream_invite_only(stream, True)

        bot_info = {
            'full_name': 'The Bot of Hamlet',
            'short_name': 'hambot',
        }
        result = self.client_post("/json/bots", bot_info)
        self.assert_json_success(result)
        bot_info = {
            'default_events_register_stream': 'Denmark',
        }
        result = self.client_patch("/json/bots/[email protected]", bot_info)
        self.assert_json_error(result, "Invalid stream name 'Denmark'")
示例#4
0
def update_stream_backend(request, user_profile, stream_id,
                          description=REQ(validator=check_string, default=None),
                          is_private=REQ(validator=check_bool, default=None),
                          new_name=REQ(validator=check_string, default=None)):
    # type: (HttpRequest, UserProfile, int, Optional[Text], Optional[bool], Optional[Text]) -> HttpResponse
    (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)

    if description is not None:
        do_change_stream_description(stream, description)
    if new_name is not None:
        new_name = new_name.strip()
        if stream.name == new_name:
            return json_error(_("Stream already has that name!"))
        if stream.name.lower() != new_name.lower():
            # Check that the stream name is available (unless we are
            # are only changing the casing of the stream name).
            check_stream_name_available(user_profile.realm, new_name)
        do_rename_stream(stream, new_name)
    if is_private is not None:
        do_change_stream_invite_only(stream, is_private)
    return json_success()
示例#5
0
    def test_patch_bot_events_register_stream_allowed(self) -> None:
        self.login(self.example_email('hamlet'))
        user_profile = self.example_user('hamlet')
        stream = self.subscribe(user_profile, "Denmark")
        do_change_stream_invite_only(stream, True)

        bot_info = {
            'full_name': 'The Bot of Hamlet',
            'short_name': 'hambot',
        }
        result = self.client_post("/json/bots", bot_info)
        self.assert_json_success(result)
        bot_info = {
            'default_events_register_stream': 'Denmark',
        }
        result = self.client_patch("/json/bots/[email protected]", bot_info)
        self.assert_json_success(result)

        self.assertEqual('Denmark', result.json()['default_events_register_stream'])

        bot = self.get_bot()
        self.assertEqual('Denmark', bot['default_events_register_stream'])
示例#6
0
    def test_add_bot_with_default_sending_stream_private_allowed(self) -> None:
        self.login(self.example_email('hamlet'))
        user_profile = self.example_user('hamlet')
        stream = get_stream("Denmark", user_profile.realm)
        self.subscribe(user_profile, stream.name)
        do_change_stream_invite_only(stream, True)

        self.assert_num_bots_equal(0)
        events = []  # type: List[Mapping[str, Any]]
        with tornado_redirected_to_list(events):
            result = self.create_bot(default_sending_stream='Denmark')
        self.assert_num_bots_equal(1)
        self.assertEqual(result['default_sending_stream'], 'Denmark')

        email = '*****@*****.**'
        realm = get_realm('zulip')
        profile = get_user(email, realm)
        self.assertEqual(profile.default_sending_stream.name, 'Denmark')

        event = [e for e in events if e['event']['type'] == 'realm_bot'][0]
        self.assertEqual(
            dict(
                type='realm_bot',
                op='add',
                bot=dict(email='*****@*****.**',
                         user_id=profile.id,
                         full_name='The Bot of Hamlet',
                         bot_type=profile.bot_type,
                         is_active=True,
                         api_key=result['api_key'],
                         avatar_url=result['avatar_url'],
                         default_sending_stream='Denmark',
                         default_events_register_stream=None,
                         default_all_public_streams=False,
                         owner=self.example_email('hamlet'))
            ),
            event['event']
        )
        self.assertEqual(event['users'], {user_profile.id, })
示例#7
0
    def test_add_bot_with_default_sending_stream_private_allowed(self) -> None:
        self.login(self.example_email('hamlet'))
        user_profile = self.example_user('hamlet')
        stream = get_stream("Denmark", user_profile.realm)
        self.subscribe(user_profile, stream.name)
        do_change_stream_invite_only(stream, True)

        self.assert_num_bots_equal(0)
        events = []  # type: List[Mapping[str, Any]]
        with tornado_redirected_to_list(events):
            result = self.create_bot(default_sending_stream='Denmark')
        self.assert_num_bots_equal(1)
        self.assertEqual(result['default_sending_stream'], 'Denmark')

        email = '*****@*****.**'
        realm = get_realm('zulip')
        profile = get_user(email, realm)
        self.assertEqual(profile.default_sending_stream.name, 'Denmark')

        event = [e for e in events if e['event']['type'] == 'realm_bot'][0]
        self.assertEqual(
            dict(type='realm_bot',
                 op='add',
                 bot=dict(email='*****@*****.**',
                          user_id=profile.id,
                          full_name='The Bot of Hamlet',
                          bot_type=profile.bot_type,
                          is_active=True,
                          api_key=result['api_key'],
                          avatar_url=result['avatar_url'],
                          default_sending_stream='Denmark',
                          default_events_register_stream=None,
                          default_all_public_streams=False,
                          owner=self.example_email('hamlet'))), event['event'])
        self.assertEqual(event['users'], {
            user_profile.id,
        })
示例#8
0
def update_stream_backend(
        request: HttpRequest, user_profile: UserProfile,
        stream_id: int,
        description: Optional[str]=REQ(validator=check_capped_string(
            Stream.MAX_DESCRIPTION_LENGTH), default=None),
        is_private: Optional[bool]=REQ(validator=check_bool, default=None),
        is_announcement_only: Optional[bool]=REQ(validator=check_bool, default=None),
        history_public_to_subscribers: Optional[bool]=REQ(validator=check_bool, default=None),
        new_name: Optional[str]=REQ(validator=check_string, default=None),
) -> HttpResponse:
    # We allow realm administrators to to update the stream name and
    # description even for private streams.
    stream = access_stream_for_delete_or_update(user_profile, stream_id)
    if description is not None:
        if '\n' in description:
            # We don't allow newline characters in stream descriptions.
            description = description.replace("\n", " ")
        do_change_stream_description(stream, description)
    if new_name is not None:
        new_name = new_name.strip()
        if stream.name == new_name:
            return json_error(_("Stream already has that name!"))
        if stream.name.lower() != new_name.lower():
            # Check that the stream name is available (unless we are
            # are only changing the casing of the stream name).
            check_stream_name_available(user_profile.realm, new_name)
        do_rename_stream(stream, new_name, user_profile)
    if is_announcement_only is not None:
        do_change_stream_announcement_only(stream, is_announcement_only)

    # But we require even realm administrators to be actually
    # subscribed to make a private stream public.
    if is_private is not None:
        (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)
        do_change_stream_invite_only(stream, is_private, history_public_to_subscribers)
    return json_success()
示例#9
0
文件: test_bots.py 项目: zonasw/zulip
    def test_patch_bot_events_register_stream_allowed(self) -> None:
        self.login(self.example_email('hamlet'))
        user_profile = self.example_user('hamlet')
        stream = self.subscribe(user_profile, "Denmark")
        do_change_stream_invite_only(stream, True)

        bot_info = {
            'full_name': 'The Bot of Hamlet',
            'short_name': 'hambot',
        }
        result = self.client_post("/json/bots", bot_info)
        self.assert_json_success(result)
        bot_info = {
            'default_events_register_stream': 'Denmark',
        }
        result = self.client_patch("/json/bots/[email protected]",
                                   bot_info)
        self.assert_json_success(result)

        self.assertEqual('Denmark',
                         result.json()['default_events_register_stream'])

        bot = self.get_bot()
        self.assertEqual('Denmark', bot['default_events_register_stream'])
示例#10
0
def update_stream_backend(request,
                          user_profile,
                          stream_id,
                          description=REQ(validator=check_string,
                                          default=None),
                          is_private=REQ(validator=check_bool, default=None),
                          new_name=REQ(validator=check_string, default=None)):
    # type: (HttpRequest, UserProfile, int, Optional[Text], Optional[bool], Optional[Text]) -> HttpResponse
    (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)

    if description is not None:
        do_change_stream_description(stream, description)
    if new_name is not None:
        new_name = new_name.strip()
        if stream.name == new_name:
            return json_error(_("Stream already has that name!"))
        if stream.name.lower() != new_name.lower():
            # Check that the stream name is available (unless we are
            # are only changing the casing of the stream name).
            check_stream_name_available(user_profile.realm, new_name)
        do_rename_stream(stream, new_name)
    if is_private is not None:
        do_change_stream_invite_only(stream, is_private)
    return json_success()
示例#11
0
def update_stream_backend(
        request: HttpRequest, user_profile: UserProfile,
        stream_id: int,
        description: Optional[str]=REQ(validator=check_capped_string(
            Stream.MAX_DESCRIPTION_LENGTH), default=None),
        is_private: Optional[bool]=REQ(validator=check_bool, default=None),
        is_announcement_only: Optional[bool]=REQ(validator=check_bool, default=None),
        history_public_to_subscribers: Optional[bool]=REQ(validator=check_bool, default=None),
        new_name: Optional[str]=REQ(validator=check_string, default=None),
) -> HttpResponse:
    # We allow realm administrators to to update the stream name and
    # description even for private streams.
    stream = access_stream_for_delete_or_update(user_profile, stream_id)
    if description is not None:
        if '\n' in description:
            # We don't allow newline characters in stream descriptions.
            description = description.replace("\n", " ")
        do_change_stream_description(stream, description)
    if new_name is not None:
        new_name = new_name.strip()
        if stream.name == new_name:
            return json_error(_("Stream already has that name!"))
        if stream.name.lower() != new_name.lower():
            # Check that the stream name is available (unless we are
            # are only changing the casing of the stream name).
            check_stream_name_available(user_profile.realm, new_name)
        do_rename_stream(stream, new_name, user_profile)
    if is_announcement_only is not None:
        do_change_stream_announcement_only(stream, is_announcement_only)

    # But we require even realm administrators to be actually
    # subscribed to make a private stream public.
    if is_private is not None:
        (stream, recipient, sub) = access_stream_by_id(user_profile, stream_id)
        do_change_stream_invite_only(stream, is_private, history_public_to_subscribers)
    return json_success()
示例#12
0
def update_stream_backend(
    request: HttpRequest,
    user_profile: UserProfile,
    stream_id: int,
    description: Optional[str] = REQ(str_validator=check_capped_string(
        Stream.MAX_DESCRIPTION_LENGTH),
                                     default=None),
    is_private: Optional[bool] = REQ(json_validator=check_bool, default=None),
    is_announcement_only: Optional[bool] = REQ(json_validator=check_bool,
                                               default=None),
    stream_post_policy: Optional[int] = REQ(json_validator=check_int_in(
        Stream.STREAM_POST_POLICY_TYPES),
                                            default=None),
    history_public_to_subscribers: Optional[bool] = REQ(
        json_validator=check_bool, default=None),
    new_name: Optional[str] = REQ(default=None),
    message_retention_days: Optional[Union[int, str]] = REQ(
        json_validator=check_string_or_int, default=None),
) -> HttpResponse:
    # We allow realm administrators to to update the stream name and
    # description even for private streams.
    (stream, sub) = access_stream_for_delete_or_update(user_profile, stream_id)

    if message_retention_days is not None:
        if not user_profile.is_realm_owner:
            raise OrganizationOwnerRequired()
        user_profile.realm.ensure_not_on_limited_plan()
        message_retention_days_value = parse_message_retention_days(
            message_retention_days,
            Stream.MESSAGE_RETENTION_SPECIAL_VALUES_MAP)
        do_change_stream_message_retention_days(stream,
                                                message_retention_days_value)

    if description is not None:
        if "\n" in description:
            # We don't allow newline characters in stream descriptions.
            description = description.replace("\n", " ")
        do_change_stream_description(stream, description)
    if new_name is not None:
        new_name = new_name.strip()
        if stream.name == new_name:
            return json_error(_("Stream already has that name!"))
        if stream.name.lower() != new_name.lower():
            # Check that the stream name is available (unless we are
            # are only changing the casing of the stream name).
            check_stream_name_available(user_profile.realm, new_name)
        do_rename_stream(stream, new_name, user_profile)
    if is_announcement_only is not None:
        # is_announcement_only is a legacy way to specify
        # stream_post_policy.  We can probably just delete this code,
        # since we're not aware of clients that used it, but we're
        # keeping it for backwards-compatibility for now.
        stream_post_policy = Stream.STREAM_POST_POLICY_EVERYONE
        if is_announcement_only:
            stream_post_policy = Stream.STREAM_POST_POLICY_ADMINS
    if stream_post_policy is not None:
        do_change_stream_post_policy(stream, stream_post_policy)

    # But we require even realm administrators to be actually
    # subscribed to make a private stream public.
    if is_private is not None:
        default_stream_ids = {
            s.id
            for s in get_default_streams_for_realm(stream.realm_id)
        }
        (stream, sub) = access_stream_by_id(user_profile, stream_id)
        if is_private and stream.id in default_stream_ids:
            return json_error(_("Default streams cannot be made private."))
        do_change_stream_invite_only(stream, is_private,
                                     history_public_to_subscribers)
    return json_success()
示例#13
0
    def test_reaction_event_scope(self) -> None:
        iago = self.example_user("iago")
        hamlet = self.example_user("hamlet")
        polonius = self.example_user("polonius")
        reaction_info = {
            "emoji_name": "smile",
        }

        # Test `invite_only` streams with `!history_public_to_subscribers` and `!is_web_public`
        stream = self.make_stream("test_reactions_stream",
                                  invite_only=True,
                                  history_public_to_subscribers=False)
        self.subscribe(iago, stream.name)
        message_before_id = self.send_stream_message(
            iago, "test_reactions_stream",
            "before subscription history private")
        self.subscribe(hamlet, stream.name)
        self.subscribe(polonius, stream.name)

        # Hamlet and Polonius joined after the message was sent, and
        # so only Iago should receive the event.
        events: List[Mapping[str, Any]] = []
        with tornado_redirected_to_list(events):
            result = self.api_post(
                iago, f"/api/v1/messages/{message_before_id}/reactions",
                reaction_info)
        self.assert_json_success(result)
        self.assert_length(events, 1)
        event = events[0]["event"]
        self.assertEqual(event["type"], "reaction")
        event_user_ids = set(events[0]["users"])
        self.assertEqual(event_user_ids, {iago.id})
        remove = self.api_delete(
            iago, f"/api/v1/messages/{message_before_id}/reactions",
            reaction_info)
        self.assert_json_success(remove)

        # Reaction to a Message sent after subscription, should
        # trigger events for all subscribers (Iago, Hamlet and Polonius).
        message_after_id = self.send_stream_message(
            iago, "test_reactions_stream",
            "after subscription history private")
        events = []
        with tornado_redirected_to_list(events):
            result = self.api_post(
                iago, f"/api/v1/messages/{message_after_id}/reactions",
                reaction_info)
        self.assert_json_success(result)
        self.assert_length(events, 1)
        event = events[0]["event"]
        self.assertEqual(event["type"], "reaction")
        event_user_ids = set(events[0]["users"])
        self.assertEqual(event_user_ids, {iago.id, hamlet.id, polonius.id})
        remove = self.api_delete(
            iago, f"/api/v1/messages/{message_after_id}/reactions",
            reaction_info)
        self.assert_json_success(remove)

        # Make stream history public to subscribers
        do_change_stream_invite_only(stream,
                                     False,
                                     history_public_to_subscribers=True)
        # Since stream history is public to subscribers, reacting to
        # message_before_id should notify all subscribers:
        # Iago and Hamlet.
        events = []
        with tornado_redirected_to_list(events):
            result = self.api_post(
                iago, f"/api/v1/messages/{message_before_id}/reactions",
                reaction_info)
        self.assert_json_success(result)
        self.assert_length(events, 1)
        event = events[0]["event"]
        self.assertEqual(event["type"], "reaction")
        event_user_ids = set(events[0]["users"])
        self.assertEqual(event_user_ids, {iago.id, hamlet.id, polonius.id})
        remove = self.api_delete(
            iago, f"/api/v1/messages/{message_before_id}/reactions",
            reaction_info)
        self.assert_json_success(remove)

        # Make stream web_public as well.
        do_make_stream_web_public(stream)
        # For is_web_public streams, events even on old messages
        # should go to all subscribers, including guests like polonius.
        events = []
        with tornado_redirected_to_list(events):
            result = self.api_post(
                iago, f"/api/v1/messages/{message_before_id}/reactions",
                reaction_info)
        self.assert_json_success(result)
        self.assert_length(events, 1)
        event = events[0]["event"]
        self.assertEqual(event["type"], "reaction")
        event_user_ids = set(events[0]["users"])
        self.assertEqual(event_user_ids, {iago.id, hamlet.id, polonius.id})
        remove = self.api_delete(
            iago, f"/api/v1/messages/{message_before_id}/reactions",
            reaction_info)
        self.assert_json_success(remove)

        # Private message, event should go to both participants.
        private_message_id = self.send_personal_message(
            iago,
            hamlet,
            "hello to single receiver",
        )
        events = []
        with tornado_redirected_to_list(events):
            result = self.api_post(
                hamlet, f"/api/v1/messages/{private_message_id}/reactions",
                reaction_info)
        self.assert_json_success(result)
        self.assert_length(events, 1)
        event = events[0]["event"]
        self.assertEqual(event["type"], "reaction")
        event_user_ids = set(events[0]["users"])
        self.assertEqual(event_user_ids, {iago.id, hamlet.id})

        # Group private message; event should go to all participants.
        huddle_message_id = self.send_huddle_message(
            hamlet,
            [polonius, iago],
            "hello message to muliple receiver",
        )
        events = []
        with tornado_redirected_to_list(events):
            result = self.api_post(
                polonius, f"/api/v1/messages/{huddle_message_id}/reactions",
                reaction_info)
        self.assert_json_success(result)
        self.assert_length(events, 1)
        event = events[0]["event"]
        self.assertEqual(event["type"], "reaction")
        event_user_ids = set(events[0]["users"])
        self.assertEqual(event_user_ids, {iago.id, hamlet.id, polonius.id})
    def test_topics_history(self) -> None:
        # verified: int(UserMessage.flags.read) == 1
        user_profile = self.example_user("iago")
        self.login_user(user_profile)
        stream_name = "Verona"

        stream = get_stream(stream_name, user_profile.realm)
        recipient = stream.recipient

        def create_test_message(topic: str) -> int:
            # TODO: Clean this up to send messages the normal way.

            hamlet = self.example_user("hamlet")
            message = Message(
                sender=hamlet,
                recipient=recipient,
                content="whatever",
                date_sent=timezone_now(),
                sending_client=get_client("whatever"),
            )
            message.set_topic_name(topic)
            message.save()

            UserMessage.objects.create(
                user_profile=user_profile,
                message=message,
                flags=0,
            )

            return message.id

        # our most recent topics are topic0, topic1, topic2

        # Create old messages with strange spellings.
        create_test_message("topic2")
        create_test_message("toPIc1")
        create_test_message("toPIc0")
        create_test_message("topic2")
        create_test_message("topic2")
        create_test_message("Topic2")

        # Create new messages
        topic2_msg_id = create_test_message("topic2")
        create_test_message("topic1")
        create_test_message("topic1")
        topic1_msg_id = create_test_message("topic1")
        topic0_msg_id = create_test_message("topic0")

        endpoint = f"/json/users/me/{stream.id}/topics"
        result = self.client_get(endpoint, {})
        self.assert_json_success(result)
        history = result.json()["topics"]

        # We only look at the most recent three topics, because
        # the prior fixture data may be unreliable.
        history = history[:3]

        self.assertEqual(
            [topic["name"] for topic in history],
            [
                "topic0",
                "topic1",
                "topic2",
            ],
        )

        self.assertEqual(
            [topic["max_id"] for topic in history],
            [
                topic0_msg_id,
                topic1_msg_id,
                topic2_msg_id,
            ],
        )

        # Now try as cordelia, who we imagine as a totally new user in
        # that she doesn't have UserMessage rows.  We should see the
        # same results for a public stream.
        self.login("cordelia")
        result = self.client_get(endpoint, {})
        self.assert_json_success(result)
        history = result.json()["topics"]

        # We only look at the most recent three topics, because
        # the prior fixture data may be unreliable.
        history = history[:3]

        self.assertEqual(
            [topic["name"] for topic in history],
            [
                "topic0",
                "topic1",
                "topic2",
            ],
        )
        self.assertIn("topic0", [topic["name"] for topic in history])

        self.assertEqual(
            [topic["max_id"] for topic in history],
            [
                topic0_msg_id,
                topic1_msg_id,
                topic2_msg_id,
            ],
        )

        # Now make stream private, but subscribe cordelia
        do_change_stream_invite_only(stream, True)
        self.subscribe(self.example_user("cordelia"), stream.name)

        result = self.client_get(endpoint, {})
        self.assert_json_success(result)
        history = result.json()["topics"]
        history = history[:3]

        # Cordelia doesn't have these recent history items when we
        # wasn't subscribed in her results.
        self.assertNotIn("topic0", [topic["name"] for topic in history])
        self.assertNotIn("topic1", [topic["name"] for topic in history])
        self.assertNotIn("topic2", [topic["name"] for topic in history])
    def test_topic_delete(self) -> None:
        initial_last_msg_id = self.get_last_message().id
        stream_name = "new_stream"
        topic_name = "new topic 2"

        # NON-ADMIN USER
        user_profile = self.example_user("hamlet")
        self.subscribe(user_profile, stream_name)

        # Send message
        stream = get_stream(stream_name, user_profile.realm)
        self.send_stream_message(user_profile, stream_name, topic_name=topic_name)
        last_msg_id = self.send_stream_message(user_profile, stream_name, topic_name=topic_name)

        # Deleting the topic
        self.login_user(user_profile)
        endpoint = "/json/streams/" + str(stream.id) + "/delete_topic"
        result = self.client_post(
            endpoint,
            {
                "topic_name": topic_name,
            },
        )
        self.assert_json_error(result, "Must be an organization administrator")
        self.assertEqual(self.get_last_message().id, last_msg_id)

        # Make stream private with limited history
        do_change_stream_invite_only(stream, invite_only=True, history_public_to_subscribers=False)

        # ADMIN USER subscribed now
        user_profile = self.example_user("iago")
        self.subscribe(user_profile, stream_name)
        self.login_user(user_profile)
        new_last_msg_id = self.send_stream_message(user_profile, stream_name, topic_name=topic_name)

        # Now admin deletes all messages in topic -- which should only
        # delete new_last_msg_id, i.e. the one sent since they joined.
        self.assertEqual(self.get_last_message().id, new_last_msg_id)
        result = self.client_post(
            endpoint,
            {
                "topic_name": topic_name,
            },
        )
        self.assert_json_success(result)
        self.assertEqual(self.get_last_message().id, last_msg_id)

        # Try to delete all messages in the topic again. There are no messages accessible
        # to the administrator, so this should do nothing.
        result = self.client_post(
            endpoint,
            {
                "topic_name": topic_name,
            },
        )
        self.assert_json_success(result)
        self.assertEqual(self.get_last_message().id, last_msg_id)

        # Make the stream's history public to subscribers
        do_change_stream_invite_only(stream, invite_only=True, history_public_to_subscribers=True)
        # Delete the topic should now remove all messages
        result = self.client_post(
            endpoint,
            {
                "topic_name": topic_name,
            },
        )
        self.assert_json_success(result)
        self.assertEqual(self.get_last_message().id, initial_last_msg_id)

        # Delete again, to test the edge case of deleting an empty topic.
        result = self.client_post(
            endpoint,
            {
                "topic_name": topic_name,
            },
        )
        self.assert_json_success(result)
        self.assertEqual(self.get_last_message().id, initial_last_msg_id)