events: Add support for spectator access to /register.

This is necessary for the mobile/terminal clients to build spectator
support down the line. We'll also be using it for the web application,
in an upcoming commit.
This commit is contained in:
Tim Abbott 2022-05-03 14:48:52 -07:00
parent 53518e8a24
commit 2e86ea6540
5 changed files with 73 additions and 10 deletions

View File

@ -1316,7 +1316,7 @@ def apply_event(
def do_events_register(
user_profile: UserProfile,
user_profile: Optional[UserProfile],
realm: Realm,
user_client: Client,
apply_markdown: bool = True,
@ -1356,6 +1356,33 @@ def do_events_register(
else:
event_types_set = None
if user_profile is None:
# TODO: Unify this with the below code path once if/when we
# support requesting an event queue for spectators.
#
# Doing so likely has a prerequisite of making this function's
# caller enforce client_gravatar=False,
# include_subscribers=False and include_streams=False.
ret = fetch_initial_state_data(
user_profile,
realm=realm,
event_types=event_types_set,
queue_id=None,
# Force client_gravatar=False for security reasons.
client_gravatar=False,
user_avatar_url_field_optional=user_avatar_url_field_optional,
user_settings_object=user_settings_object,
# slim_presence is a noop, because presence is not included.
slim_presence=True,
# Force include_subscribers=False for security reasons.
include_subscribers=False,
# Force include_streams=False for security reasons.
include_streams=False,
)
post_process_state(user_profile, ret, notification_settings_null=False)
return ret
# Fill up the UserMessage rows if a soft-deactivated user has returned
reactivate_user_if_soft_deactivated(user_profile)

View File

@ -9207,8 +9207,12 @@ paths:
msg: {}
queue_id:
type: string
nullable: true
description: |
The ID of the queue that has been allocated for your client.
Will be None only for unauthenticated access in realms that have
enabled the [public access option](/help/public-access-option).
last_event_id:
type: integer
description: |

View File

@ -143,6 +143,23 @@ class EventsEndpointTest(ZulipTestCase):
self.assertEqual(result_dict["realm_emoji"], [])
self.assertEqual(result_dict["queue_id"], "15:13")
def test_events_register_spectators(self) -> None:
# Verify that POST /register works for spectators, but not for
# normal users.
with self.settings(WEB_PUBLIC_STREAMS_ENABLED=False):
result = self.client_post("/json/register", dict())
self.assert_json_error(
result,
"Not logged in: API authentication or user session required",
status_code=401,
)
result = self.client_post("/json/register", dict())
self.assert_json_success(result)
result_dict = result.json()
self.assertEqual(result_dict["queue_id"], None)
self.assertEqual(result_dict["realm_uri"], "http://zulip.testserver")
def test_events_register_endpoint_all_public_streams_access(self) -> None:
guest_user = self.example_user("polonius")
normal_user = self.example_user("hamlet")

View File

@ -1,10 +1,12 @@
from typing import Dict, Optional, Sequence
from typing import Dict, Optional, Sequence, Union
from django.contrib.auth.models import AnonymousUser
from django.http import HttpRequest, HttpResponse
from django.utils.translation import gettext as _
from zerver.context_processors import get_valid_realm_from_request
from zerver.lib.events import do_events_register
from zerver.lib.exceptions import JsonableError
from zerver.lib.exceptions import JsonableError, MissingAuthenticationError
from zerver.lib.request import REQ, RequestNotes, has_request_variables
from zerver.lib.response import json_success
from zerver.lib.validator import check_bool, check_dict, check_int, check_list, check_string
@ -35,7 +37,7 @@ NarrowT = Sequence[Sequence[str]]
@has_request_variables
def events_register_backend(
request: HttpRequest,
user_profile: UserProfile,
maybe_user_profile: Union[UserProfile, AnonymousUser],
apply_markdown: bool = REQ(default=False, json_validator=check_bool),
client_gravatar: bool = REQ(default=True, json_validator=check_bool),
slim_presence: bool = REQ(default=False, json_validator=check_bool),
@ -71,11 +73,24 @@ def events_register_backend(
),
queue_lifespan_secs: int = REQ(json_validator=check_int, default=0, documentation_pending=True),
) -> HttpResponse:
if maybe_user_profile.is_authenticated:
user_profile = maybe_user_profile
assert isinstance(user_profile, UserProfile)
realm = user_profile.realm
if all_public_streams and not user_profile.can_access_public_streams():
raise JsonableError(_("User not authorized for this query"))
all_public_streams = _default_all_public_streams(user_profile, all_public_streams)
narrow = _default_narrow(user_profile, narrow)
else:
user_profile = None
realm = get_valid_realm_from_request(request)
if not realm.allow_web_public_streams_access():
raise MissingAuthenticationError()
all_public_streams = False
if client_capabilities is None:
client_capabilities = {}
@ -85,7 +100,7 @@ def events_register_backend(
ret = do_events_register(
user_profile,
user_profile.realm,
realm,
client,
apply_markdown,
client_gravatar,

View File

@ -469,7 +469,7 @@ v1_api_and_json_patterns = [
rest_path("users/me/subscriptions/muted_topics", PATCH=update_muted_topic),
rest_path("users/me/muted_users/<int:muted_user_id>", POST=mute_user, DELETE=unmute_user),
# used to register for an event queue in tornado
rest_path("register", POST=events_register_backend),
rest_path("register", POST=(events_register_backend, {"allow_anonymous_user_web"})),
# events -> zerver.tornado.views
rest_path("events", GET=get_events, DELETE=cleanup_event_queue),
# report -> zerver.views.report