diff --git a/zerver/context_processors.py b/zerver/context_processors.py index c55d49b1d2..caac674f39 100644 --- a/zerver/context_processors.py +++ b/zerver/context_processors.py @@ -17,7 +17,7 @@ from version import ( from zerver.lib.exceptions import InvalidSubdomainError from zerver.lib.realm_description import get_realm_rendered_description, get_realm_text_description from zerver.lib.realm_icon import get_realm_icon_url -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes from zerver.lib.send_email import FromAddress from zerver.lib.subdomains import get_subdomain from zerver.models import Realm, UserProfile, get_realm @@ -50,7 +50,7 @@ def common_context(user: UserProfile) -> Dict[str, Any]: def get_realm_from_request(request: HttpRequest) -> Optional[Realm]: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if hasattr(request, "user") and hasattr(request.user, "realm"): return request.user.realm if not request_notes.has_fetched_realm: @@ -59,7 +59,7 @@ def get_realm_from_request(request: HttpRequest) -> Optional[Realm]: # need to do duplicate queries on the same realm while # processing a single request. subdomain = get_subdomain(request) - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) try: request_notes.realm = get_realm(subdomain) except Realm.DoesNotExist: @@ -169,7 +169,7 @@ def zulip_default_context(request: HttpRequest) -> Dict[str, Any]: "settings_path": settings_path, "secrets_path": secrets_path, "settings_comments_path": settings_comments_path, - "platform": get_request_notes(request).client_name, + "platform": RequestNotes.get_notes(request).client_name, "allow_search_engine_indexing": allow_search_engine_indexing, "landing_page_navbar_message": settings.LANDING_PAGE_NAVBAR_MESSAGE, "default_page_params": default_page_params, diff --git a/zerver/decorator.py b/zerver/decorator.py index a04abbd66c..dcf8f47635 100644 --- a/zerver/decorator.py +++ b/zerver/decorator.py @@ -40,7 +40,7 @@ from zerver.lib.exceptions import ( ) from zerver.lib.queue import queue_json_publish from zerver.lib.rate_limiter import RateLimitedIPAddr, RateLimitedUser -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_method_not_allowed, json_success, json_unauthorized from zerver.lib.subdomains import get_subdomain, user_matches_subdomain from zerver.lib.timestamp import datetime_to_timestamp, timestamp_to_datetime @@ -85,7 +85,7 @@ def update_user_activity( if request.META["PATH_INFO"] == "/json/users/me/presence": return - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if query is not None: pass elif request_notes.query is not None: @@ -115,7 +115,7 @@ def require_post(func: ViewFuncT) -> ViewFuncT: request.path, extra={"status_code": 405, "request": request}, ) - if get_request_notes(request).error_format == "JSON": + if RequestNotes.get_notes(request).error_format == "JSON": return json_method_not_allowed(["POST"]) else: return TemplateResponse( @@ -183,7 +183,7 @@ def process_client( skip_update_user_activity: bool = False, query: Optional[str] = None, ) -> None: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if client_name is None: client_name = request_notes.client_name @@ -438,7 +438,7 @@ def do_login(request: HttpRequest, user_profile: UserProfile) -> None: and also adds helpful data needed by our server logs. """ django_login(request, user_profile) - get_request_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() + RequestNotes.get_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() process_client(request, user_profile, is_browser_view=True) if settings.TWO_FACTOR_AUTHENTICATION_ENABLED: # Log in with two factor authentication as well. @@ -448,7 +448,7 @@ def do_login(request: HttpRequest, user_profile: UserProfile) -> None: def log_view_func(view_func: ViewFuncT) -> ViewFuncT: @wraps(view_func) def _wrapped_view_func(request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: - get_request_notes(request).query = view_func.__name__ + RequestNotes.get_notes(request).query = view_func.__name__ return view_func(request, *args, **kwargs) return cast(ViewFuncT, _wrapped_view_func) # https://github.com/python/mypy/issues/1927 @@ -808,7 +808,7 @@ def client_is_exempt_from_rate_limiting(request: HttpRequest) -> bool: # Don't rate limit requests from Django that come from our own servers, # and don't rate-limit dev instances - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client return (client is not None and client.name.lower() == "internal") and ( is_local_addr(request.META["REMOTE_ADDR"]) or settings.DEBUG_RATE_LIMITING ) @@ -832,7 +832,7 @@ def internal_notify_view( ) -> HttpResponse: if not authenticate_notify(request): raise AccessDeniedError() - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) is_tornado_request = request_notes.tornado_handler is not None # These next 2 are not security checks; they are internal # assertions to help us find bugs. diff --git a/zerver/lib/home.py b/zerver/lib/home.py index 46e2e504b5..1f795596a0 100644 --- a/zerver/lib/home.py +++ b/zerver/lib/home.py @@ -15,7 +15,7 @@ from zerver.lib.i18n import ( get_language_list, get_language_translation_data, ) -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes from zerver.models import Message, Realm, Stream, UserProfile from zerver.views.message_flags import get_latest_update_message_flag_activity @@ -139,7 +139,7 @@ def build_page_params_for_home_page_load( } if user_profile is not None: - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None register_ret = do_events_register( user_profile, diff --git a/zerver/lib/i18n.py b/zerver/lib/i18n.py index 5ab162ad74..c24d228108 100644 --- a/zerver/lib/i18n.py +++ b/zerver/lib/i18n.py @@ -10,7 +10,7 @@ from django.conf import settings from django.http import HttpRequest from django.utils import translation -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes @lru_cache() @@ -64,6 +64,6 @@ def get_and_set_request_language( # something reasonable will happen in logged-in portico pages. # We accomplish that by setting a flag on the request which signals # to LocaleMiddleware to set the cookie on the response. - get_request_notes(request).set_language = translation.get_language() + RequestNotes.get_notes(request).set_language = translation.get_language() return request_language diff --git a/zerver/lib/logging_util.py b/zerver/lib/logging_util.py index 1a863ac948..19d945df64 100644 --- a/zerver/lib/logging_util.py +++ b/zerver/lib/logging_util.py @@ -276,9 +276,9 @@ class ZulipWebhookFormatter(ZulipFormatter): ) header_message = header_text if header_text else None - from zerver.lib.request import get_request_notes + from zerver.lib.request import RequestNotes - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None setattr(record, "user", f"{request.user.delivery_email} ({request.user.realm.string_id})") diff --git a/zerver/lib/rate_limiter.py b/zerver/lib/rate_limiter.py index 6f9eb381c1..15e71ecdbb 100644 --- a/zerver/lib/rate_limiter.py +++ b/zerver/lib/rate_limiter.py @@ -42,10 +42,10 @@ class RateLimitedObject(ABC): ) def rate_limit_request(self, request: HttpRequest) -> None: - from zerver.lib.request import get_request_notes + from zerver.lib.request import RequestNotes ratelimited, time = self.rate_limit() - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) request_notes.ratelimits_applied.append( RateLimitResult( diff --git a/zerver/lib/request.py b/zerver/lib/request.py index eda9f5bd7c..4c9a323100 100644 --- a/zerver/lib/request.py +++ b/zerver/lib/request.py @@ -29,19 +29,21 @@ from typing_extensions import Literal import zerver.lib.rate_limiter as rate_limiter import zerver.tornado.handlers as handlers from zerver.lib.exceptions import ErrorCode, InvalidJSONError, JsonableError +from zerver.lib.notes import BaseNotes from zerver.lib.types import Validator, ViewFuncT from zerver.models import Client, Realm @dataclass -class ZulipRequestNotes: +class RequestNotes(BaseNotes[HttpRequest, "RequestNotes"]): """This class contains extra metadata that Zulip associated with a - Django HttpRequest object. + Django HttpRequest object. See the docstring for BaseNotes for + details on how it works. Note that most Optional fields will be definitely not None once middlware has run. In the future, we may want to express that in - the types by having different types ZulipEarlyRequestNotes and - post-middleware ZulipRequestNotes types, but for now we have a lot + the types by having different types EarlyRequestNotes and + post-middleware RequestNotes types, but for now we have a lot of `assert request_notes.foo is not None` when accessing them. """ @@ -68,16 +70,9 @@ class ZulipRequestNotes: processed_parameters: Set[str] = field(default_factory=set) ignored_parameters: Set[str] = field(default_factory=set) - -request_notes_map: MutableMapping[HttpRequest, ZulipRequestNotes] = weakref.WeakKeyDictionary() - - -def get_request_notes(request: HttpRequest) -> ZulipRequestNotes: - try: - return request_notes_map[request] - except KeyError: - request_notes_map[request] = ZulipRequestNotes() - return request_notes_map[request] + @classmethod + def init_notes(cls) -> "RequestNotes": + return RequestNotes() class RequestConfusingParmsError(JsonableError): @@ -358,7 +353,7 @@ def has_request_variables(view_func: ViewFuncT) -> ViewFuncT: @wraps(view_func) def _wrapped_view_func(request: HttpRequest, *args: object, **kwargs: object) -> HttpResponse: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) for param in post_params: func_var_name = param.func_var_name if param.path_only: diff --git a/zerver/lib/rest.py b/zerver/lib/rest.py index c26e69c7e3..3d2f1b1c6e 100644 --- a/zerver/lib/rest.py +++ b/zerver/lib/rest.py @@ -14,7 +14,7 @@ from zerver.decorator import ( process_as_post, ) from zerver.lib.exceptions import MissingAuthenticationError -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes from zerver.lib.response import json_method_not_allowed from zerver.lib.types import ViewFuncT @@ -66,7 +66,7 @@ def rest_dispatch(request: HttpRequest, **kwargs: Any) -> HttpResponse: etc, as that is where we route HTTP verbs to target functions. """ supported_methods: Dict[str, Any] = {} - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if request_notes.saved_response is not None: # For completing long-polled Tornado requests, we skip the # view function logic and just return the response. diff --git a/zerver/lib/test_helpers.py b/zerver/lib/test_helpers.py index bc11ad5e51..b779a83a13 100644 --- a/zerver/lib/test_helpers.py +++ b/zerver/lib/test_helpers.py @@ -45,7 +45,8 @@ from zerver.lib.avatar import avatar_url from zerver.lib.cache import get_cache_backend from zerver.lib.db import Params, ParamsT, Query, TimeTrackingCursor from zerver.lib.integrations import WEBHOOK_INTEGRATIONS -from zerver.lib.request import ZulipRequestNotes, request_notes_map +from zerver.lib.notes import BaseNotes +from zerver.lib.request import RequestNotes from zerver.lib.upload import LocalUploadBackend, S3UploadBackend from zerver.models import ( Client, @@ -320,12 +321,16 @@ class HostRequestMock(HttpRequest): self.user = user_profile self._body = b"" self.content_type = "" + BaseNotes[str, str].get_notes - request_notes_map[self] = ZulipRequestNotes( - client_name="", - log_data={}, - tornado_handler=None if tornado_handler is None else weakref.ref(tornado_handler), - client=get_client(client_name) if client_name is not None else None, + RequestNotes.set_notes( + self, + RequestNotes( + client_name="", + log_data={}, + tornado_handler=None if tornado_handler is None else weakref.ref(tornado_handler), + client=get_client(client_name) if client_name is not None else None, + ), ) @property diff --git a/zerver/lib/webhooks/common.py b/zerver/lib/webhooks/common.py index 345feda3f5..ba688182b7 100644 --- a/zerver/lib/webhooks/common.py +++ b/zerver/lib/webhooks/common.py @@ -14,7 +14,7 @@ from zerver.lib.actions import ( send_rate_limited_pm_notification_to_bot_owner, ) from zerver.lib.exceptions import ErrorCode, JsonableError, StreamDoesNotExistError -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.send_email import FromAddress from zerver.lib.timestamp import timestamp_to_datetime from zerver.lib.validator import check_list, check_string @@ -107,7 +107,7 @@ def check_send_webhook_message( ): return - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None if stream is None: assert user_profile.bot_owner is not None diff --git a/zerver/middleware.py b/zerver/middleware.py index 7c89c0c4c3..7aeb96a5c6 100644 --- a/zerver/middleware.py +++ b/zerver/middleware.py @@ -38,7 +38,7 @@ from zerver.lib.exceptions import ErrorCode, JsonableError, MissingAuthenticatio from zerver.lib.html_to_text import get_content_description from zerver.lib.markdown import get_markdown_requests, get_markdown_time from zerver.lib.rate_limiter import RateLimitResult -from zerver.lib.request import get_request_notes, set_request, unset_request +from zerver.lib.request import RequestNotes, set_request, unset_request from zerver.lib.response import json_response, json_response_from_error, json_unauthorized from zerver.lib.subdomains import get_subdomain from zerver.lib.types import ViewFuncT @@ -61,7 +61,7 @@ def record_request_stop_data(log_data: MutableMapping[str, Any]) -> None: def async_request_timer_stop(request: HttpRequest) -> None: - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None record_request_stop_data(log_data) @@ -77,7 +77,7 @@ def record_request_restart_data(log_data: MutableMapping[str, Any]) -> None: def async_request_timer_restart(request: HttpRequest) -> None: - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None if "time_restarted" in log_data: # Don't destroy data when being called from @@ -341,7 +341,7 @@ class LogRequests(MiddlewareMixin): # method here too def process_request(self, request: HttpRequest) -> None: maybe_tracemalloc_listen() - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if request_notes.log_data is not None: # Sanity check to ensure this is being called from the @@ -362,7 +362,7 @@ class LogRequests(MiddlewareMixin): args: List[str], kwargs: Dict[str, Any], ) -> None: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if request_notes.saved_response is not None: # The below logging adjustments are unnecessary (because # we've already imported everything) and incorrect @@ -394,7 +394,7 @@ class LogRequests(MiddlewareMixin): remote_ip = request.META["REMOTE_ADDR"] # Get the requestor's identifier and client, if available. - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) requestor_for_logs = request_notes.requestor_for_logs if requestor_for_logs is None: # Note that request.user is a Union[RemoteZulipServer, UserProfile, AnonymousUser], @@ -455,7 +455,7 @@ class JsonErrorHandler(MiddlewareMixin): if isinstance(exception, JsonableError): return json_response_from_error(exception) - if get_request_notes(request).error_format == "JSON": + if RequestNotes.get_notes(request).error_format == "JSON": capture_exception(exception) json_error_logger = logging.getLogger("zerver.middleware.json_error_handler") json_error_logger.error(traceback.format_exc(), extra=dict(request=request)) @@ -471,9 +471,9 @@ class TagRequests(MiddlewareMixin): def process_request(self, request: HttpRequest) -> None: if request.path.startswith("/api/") or request.path.startswith("/json/"): - get_request_notes(request).error_format = "JSON" + RequestNotes.get_notes(request).error_format = "JSON" else: - get_request_notes(request).error_format = "HTML" + RequestNotes.get_notes(request).error_format = "HTML" class CsrfFailureError(JsonableError): @@ -490,7 +490,7 @@ class CsrfFailureError(JsonableError): def csrf_failure(request: HttpRequest, reason: str = "") -> HttpResponse: - if get_request_notes(request).error_format == "JSON": + if RequestNotes.get_notes(request).error_format == "JSON": return json_response_from_error(CsrfFailureError(reason)) else: return html_csrf_failure(request, reason) @@ -517,7 +517,7 @@ class LocaleMiddleware(DjangoLocaleMiddleware): # An additional responsibility of our override of this middleware is to save the user's language # preference in a cookie. That determination is made by code handling the request # and saved in the set_language flag so that it can be used here. - set_language = get_request_notes(request).set_language + set_language = RequestNotes.get_notes(request).set_language if set_language is not None: response.set_cookie(settings.LANGUAGE_COOKIE_NAME, set_language) @@ -544,7 +544,7 @@ class RateLimitMiddleware(MiddlewareMixin): return response # Add X-RateLimit-*** headers - ratelimits_applied = get_request_notes(request).ratelimits_applied + ratelimits_applied = RequestNotes.get_notes(request).ratelimits_applied if len(ratelimits_applied) > 0: self.set_response_headers(response, ratelimits_applied) @@ -577,7 +577,7 @@ class HostDomainMiddleware(MiddlewareMixin): subdomain = get_subdomain(request) if subdomain != Realm.SUBDOMAIN_FOR_ROOT_DOMAIN: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) try: request_notes.realm = get_realm(subdomain) except Realm.DoesNotExist: @@ -614,7 +614,7 @@ class SetRemoteAddrFromRealIpHeader(MiddlewareMixin): def alter_content(request: HttpRequest, content: bytes) -> bytes: first_paragraph_text = get_content_description(content, request) - placeholder_open_graph_description = get_request_notes( + placeholder_open_graph_description = RequestNotes.get_notes( request ).placeholder_open_graph_description assert placeholder_open_graph_description is not None @@ -629,7 +629,7 @@ class FinalizeOpenGraphDescription(MiddlewareMixin): self, request: HttpRequest, response: StreamingHttpResponse ) -> StreamingHttpResponse: - if get_request_notes(request).placeholder_open_graph_description is not None: + if RequestNotes.get_notes(request).placeholder_open_graph_description is not None: assert not response.streaming response.content = alter_content(request, response.content) return response diff --git a/zerver/tests/test_decorators.py b/zerver/tests/test_decorators.py index ca1ad3f410..52ce09fd94 100644 --- a/zerver/tests/test_decorators.py +++ b/zerver/tests/test_decorators.py @@ -47,9 +47,9 @@ from zerver.lib.initial_password import initial_password from zerver.lib.request import ( REQ, RequestConfusingParmsError, + RequestNotes, RequestVariableConversionError, RequestVariableMissingError, - get_request_notes, has_request_variables, ) from zerver.lib.response import json_response, json_success @@ -1428,19 +1428,19 @@ class TestInternalNotifyView(ZulipTestCase): orjson.loads(self.internal_notify(False, request).content).get("msg"), self.BORING_RESULT, ) - self.assertEqual(get_request_notes(request).requestor_for_logs, "internal") + self.assertEqual(RequestNotes.get_notes(request).requestor_for_logs, "internal") with self.assertRaises(RuntimeError): self.internal_notify(True, request) - get_request_notes(request).tornado_handler = DummyHandler() + RequestNotes.get_notes(request).tornado_handler = DummyHandler() with self.settings(SHARED_SECRET=secret): self.assertTrue(authenticate_notify(request)) self.assertEqual( orjson.loads(self.internal_notify(True, request).content).get("msg"), self.BORING_RESULT, ) - self.assertEqual(get_request_notes(request).requestor_for_logs, "internal") + self.assertEqual(RequestNotes.get_notes(request).requestor_for_logs, "internal") with self.assertRaises(RuntimeError): self.internal_notify(False, request) diff --git a/zerver/tornado/handlers.py b/zerver/tornado/handlers.py index 6e24f3c8f8..8948786319 100644 --- a/zerver/tornado/handlers.py +++ b/zerver/tornado/handlers.py @@ -47,7 +47,7 @@ def finish_handler( try: # We do the import during runtime to avoid cyclic dependency # with zerver.lib.request - from zerver.lib.request import get_request_notes + from zerver.lib.request import RequestNotes from zerver.middleware import async_request_timer_restart # We call async_request_timer_restart here in case we are @@ -56,7 +56,7 @@ def finish_handler( handler = get_handler_by_id(handler_id) request = handler._request async_request_timer_restart(request) - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None if len(contents) != 1: log_data["extra"] = f"[{event_queue_id}/1]" @@ -113,11 +113,11 @@ class AsyncDjangoHandler(tornado.web.RequestHandler, base.BaseHandler): request = WSGIRequest(environ) # We do the import during runtime to avoid cyclic dependency - from zerver.lib.request import get_request_notes + from zerver.lib.request import RequestNotes # Provide a way for application code to access this handler # given the HttpRequest object. - get_request_notes(request).tornado_handler = weakref.ref(self) + RequestNotes.get_notes(request).tornado_handler = weakref.ref(self) return request @@ -228,12 +228,12 @@ class AsyncDjangoHandler(tornado.web.RequestHandler, base.BaseHandler): # HttpResponse with all Django middleware run. request = self.convert_tornado_request_to_django_request() - # We import get_request_notes during runtime to avoid + # We import RequestNotes during runtime to avoid # cyclic import - from zerver.lib.request import get_request_notes + from zerver.lib.request import RequestNotes - request_notes = get_request_notes(request) - old_request_notes = get_request_notes(old_request) + request_notes = RequestNotes.get_notes(request) + old_request_notes = RequestNotes.get_notes(old_request) # Add to this new HttpRequest logging data from the processing of # the original request; we will need these for logging. diff --git a/zerver/tornado/views.py b/zerver/tornado/views.py index 30e82fc14a..c51e245959 100644 --- a/zerver/tornado/views.py +++ b/zerver/tornado/views.py @@ -7,7 +7,7 @@ from django.utils.translation import gettext as _ from zerver.decorator import internal_notify_view, process_client from zerver.lib.exceptions import JsonableError -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.validator import ( check_bool, @@ -36,7 +36,7 @@ def cleanup_event_queue( raise BadEventQueueIdError(queue_id) if user_profile.id != client.user_profile_id: raise JsonableError(_("You are not authorized to access this queue")) - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{queue_id}]" client.cleanup() @@ -49,7 +49,7 @@ def get_events_internal( request: HttpRequest, user_profile_id: int = REQ(json_validator=check_int) ) -> HttpResponse: user_profile = get_user_profile_by_id(user_profile_id) - get_request_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() + RequestNotes.get_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() process_client(request, user_profile, client_name="internal") return get_events_backend(request, user_profile) @@ -111,13 +111,13 @@ def get_events_backend( raise JsonableError(_("User not authorized for this query")) # Extract the Tornado handler from the request - tornado_handler = get_request_notes(request).tornado_handler + tornado_handler = RequestNotes.get_notes(request).tornado_handler assert tornado_handler is not None handler = tornado_handler() assert handler is not None if user_client is None: - valid_user_client = get_request_notes(request).client + valid_user_client = RequestNotes.get_notes(request).client assert valid_user_client is not None else: valid_user_client = user_client @@ -155,7 +155,7 @@ def get_events_backend( result = fetch_events(events_query) if "extra_log_data" in result: - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = result["extra_log_data"] diff --git a/zerver/views/auth.py b/zerver/views/auth.py index 93eb0adaed..8282d55d9f 100644 --- a/zerver/views/auth.py +++ b/zerver/views/auth.py @@ -54,7 +54,7 @@ from zerver.lib.mobile_auth_otp import otp_encrypt_api_key from zerver.lib.push_notifications import push_notifications_enabled from zerver.lib.pysa import mark_sanitized from zerver.lib.realm_icon import realm_icon_url -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.sessions import set_expirable_session_var from zerver.lib.subdomains import get_subdomain, is_subdomain_root_or_alias @@ -358,7 +358,7 @@ def finish_mobile_flow(request: HttpRequest, user_profile: UserProfile, otp: str # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) - get_request_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() + RequestNotes.get_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() return response @@ -866,7 +866,7 @@ def api_fetch_api_key( # Mark this request as having a logged-in user for our server logs. process_client(request, user_profile) - get_request_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() + RequestNotes.get_notes(request).requestor_for_logs = user_profile.format_requestor_for_logs() api_key = get_api_key(user_profile) return json_success({"api_key": api_key, "email": user_profile.delivery_email}) diff --git a/zerver/views/documentation.py b/zerver/views/documentation.py index b6643bf6e7..701eb7acc7 100644 --- a/zerver/views/documentation.py +++ b/zerver/views/documentation.py @@ -13,7 +13,7 @@ from django.views.generic import TemplateView from zerver.context_processors import zulip_default_context from zerver.decorator import add_google_analytics_context from zerver.lib.integrations import CATEGORIES, INTEGRATIONS, HubotIntegration, WebhookIntegration -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.subdomains import get_subdomain from zerver.lib.templates import render_markdown_path from zerver.models import Realm @@ -168,7 +168,7 @@ class MarkdownDirectoryView(ApiURLView): context["OPEN_GRAPH_TITLE"] = f"{article_title} ({title_base})" else: context["OPEN_GRAPH_TITLE"] = title_base - request_notes = get_request_notes(self.request) + request_notes = RequestNotes.get_notes(self.request) request_notes.placeholder_open_graph_description = ( f"REPLACMENT_OPEN_GRAPH_DESCRIPTION_{int(2**24 * random.random())}" ) diff --git a/zerver/views/events_register.py b/zerver/views/events_register.py index 3ba701c564..45e9d6f274 100644 --- a/zerver/views/events_register.py +++ b/zerver/views/events_register.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext as _ from zerver.lib.events import do_events_register from zerver.lib.exceptions import JsonableError -from zerver.lib.request import REQ, get_request_notes, has_request_variables +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_list, check_string from zerver.models import Stream, UserProfile @@ -80,7 +80,7 @@ def events_register_backend( if client_capabilities is None: client_capabilities = {} - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None ret = do_events_register( diff --git a/zerver/views/home.py b/zerver/views/home.py index b27befb8e2..fb6732342a 100644 --- a/zerver/views/home.py +++ b/zerver/views/home.py @@ -14,7 +14,7 @@ from zerver.forms import ToSForm from zerver.lib.actions import do_change_tos_version, realm_user_count from zerver.lib.compatibility import is_outdated_desktop_app, is_unsupported_browser from zerver.lib.home import build_page_params_for_home_page_load, get_user_permission_info -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes from zerver.lib.streams import access_stream_by_name from zerver.lib.subdomains import get_subdomain from zerver.lib.utils import statsd @@ -192,7 +192,7 @@ def home_real(request: HttpRequest) -> HttpResponse: needs_tutorial=needs_tutorial, ) - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{queue_id}]" diff --git a/zerver/views/message_edit.py b/zerver/views/message_edit.py index e08f0e7df4..759fa78772 100644 --- a/zerver/views/message_edit.py +++ b/zerver/views/message_edit.py @@ -11,7 +11,7 @@ from zerver.lib.actions import check_update_message, do_delete_messages from zerver.lib.exceptions import JsonableError from zerver.lib.html_diff import highlight_html_differences from zerver.lib.message import access_message -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.timestamp import datetime_to_timestamp from zerver.lib.topic import LEGACY_PREV_TOPIC, REQ_topic @@ -117,7 +117,7 @@ def update_message_backend( ) # Include the number of messages changed in the logs - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{number_changed}]" diff --git a/zerver/views/message_fetch.py b/zerver/views/message_fetch.py index e0ac19c11b..69c14fb390 100644 --- a/zerver/views/message_fetch.py +++ b/zerver/views/message_fetch.py @@ -37,7 +37,7 @@ from zerver.lib.addressee import get_user_profiles, get_user_profiles_by_ids from zerver.lib.exceptions import ErrorCode, JsonableError, MissingAuthenticationError from zerver.lib.message import get_first_visible_message_id, messages_for_ids from zerver.lib.narrow import is_web_public_compatible, is_web_public_narrow -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.sqlalchemy_utils import get_sqlalchemy_connection from zerver.lib.streams import ( @@ -1040,7 +1040,7 @@ def get_messages_backend( verbose_operators.append("is:" + term["operand"]) else: verbose_operators.append(term["operator"]) - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = "[{}]".format(",".join(verbose_operators)) diff --git a/zerver/views/message_flags.py b/zerver/views/message_flags.py index 048e45b39c..6c14490c76 100644 --- a/zerver/views/message_flags.py +++ b/zerver/views/message_flags.py @@ -9,7 +9,7 @@ from zerver.lib.actions import ( do_update_message_flags, ) from zerver.lib.exceptions import JsonableError -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.streams import access_stream_by_id from zerver.lib.topic import user_message_exists_for_topic @@ -35,7 +35,7 @@ def update_message_flags( operation: str = REQ("op"), flag: str = REQ(), ) -> HttpResponse: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) assert request_notes.client is not None assert request_notes.log_data is not None @@ -50,7 +50,7 @@ def update_message_flags( @has_request_variables def mark_all_as_read(request: HttpRequest, user_profile: UserProfile) -> HttpResponse: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) assert request_notes.client is not None count = do_mark_all_as_read(user_profile, request_notes.client) @@ -69,7 +69,7 @@ def mark_stream_as_read( count = do_mark_stream_messages_as_read(user_profile, stream.recipient_id) log_data_str = f"[{count} updated]" - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = log_data_str @@ -98,7 +98,7 @@ def mark_topic_as_read( count = do_mark_stream_messages_as_read(user_profile, stream.recipient_id, topic_name) log_data_str = f"[{count} updated]" - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = log_data_str diff --git a/zerver/views/message_send.py b/zerver/views/message_send.py index f97878ea00..3e452d4baa 100644 --- a/zerver/views/message_send.py +++ b/zerver/views/message_send.py @@ -19,7 +19,7 @@ from zerver.lib.actions import ( ) from zerver.lib.exceptions import JsonableError from zerver.lib.message import render_markdown -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.timestamp import convert_to_UTC from zerver.lib.topic import REQ_topic @@ -53,7 +53,7 @@ def create_mirrored_message_users( for email in recipients: referenced_users.add(email.lower()) - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None if client.name == "zephyr_mirror": @@ -226,7 +226,7 @@ def send_message_backend( # `yes` to accepting `true` like all of our normal booleans. forged = forged_str is not None and forged_str in ["yes", "true"] - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None can_forge_sender = user_profile.can_forge_sender if forged and not can_forge_sender: @@ -330,7 +330,7 @@ def render_message_backend( message = Message() message.sender = user_profile message.content = content - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None message.sending_client = client diff --git a/zerver/views/presence.py b/zerver/views/presence.py index dcb74c9c8d..0b88318ff9 100644 --- a/zerver/views/presence.py +++ b/zerver/views/presence.py @@ -11,7 +11,7 @@ from zerver.lib.actions import do_update_user_status, update_user_presence from zerver.lib.emoji import check_emoji_request, emoji_name_to_emoji_code from zerver.lib.exceptions import JsonableError from zerver.lib.presence import get_presence_for_user, get_presence_response -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.timestamp import datetime_to_timestamp from zerver.lib.validator import check_bool, check_capped_string @@ -114,7 +114,7 @@ def update_user_status_backend( assert emoji_type is not None check_emoji_request(user_profile.realm, emoji_name, emoji_code, emoji_type) - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None do_update_user_status( user_profile=user_profile, @@ -143,7 +143,7 @@ def update_active_status_backend( if status_val is None: raise JsonableError(_("Invalid status: {}").format(status)) elif user_profile.presence_enabled: - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None update_user_presence(user_profile, client, timezone_now(), status_val, new_user_input) diff --git a/zerver/views/report.py b/zerver/views/report.py index cda60b00f3..29ae2ef4e3 100644 --- a/zerver/views/report.py +++ b/zerver/views/report.py @@ -14,7 +14,7 @@ from zerver.context_processors import get_valid_realm_from_request from zerver.decorator import human_users_only from zerver.lib.markdown import privacy_clean_markdown from zerver.lib.queue import queue_json_publish -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.storage import static_path from zerver.lib.unminify import SourceMap @@ -54,7 +54,7 @@ def report_send_times( if displayed > 0: displayed_str = str(displayed) - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data[ "extra" @@ -81,7 +81,7 @@ def report_narrow_times( initial_free: int = REQ(converter=to_non_negative_int), network: int = REQ(converter=to_non_negative_int), ) -> HttpResponse: - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{initial_core}ms/{initial_free}ms/{network}ms]" realm = get_valid_realm_from_request(request) @@ -99,7 +99,7 @@ def report_unnarrow_times( initial_core: int = REQ(converter=to_non_negative_int), initial_free: int = REQ(converter=to_non_negative_int), ) -> HttpResponse: - log_data = get_request_notes(request).log_data + log_data = RequestNotes.get_notes(request).log_data assert log_data is not None log_data["extra"] = f"[{initial_core}ms/{initial_free}ms]" realm = get_valid_realm_from_request(request) diff --git a/zerver/views/user_settings.py b/zerver/views/user_settings.py index 466b711fff..b220dfd57d 100644 --- a/zerver/views/user_settings.py +++ b/zerver/views/user_settings.py @@ -276,9 +276,9 @@ def json_change_settings( do_set_user_display_setting(user_profile, "timezone", timezone) # TODO: Do this more generally. - from zerver.lib.request import get_request_notes + from zerver.lib.request import RequestNotes - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) for req_var in request.POST: if req_var not in request_notes.processed_parameters: request_notes.ignored_parameters.add(req_var) diff --git a/zerver/webhooks/dialogflow/view.py b/zerver/webhooks/dialogflow/view.py index df69b4eb90..d45deacb9b 100644 --- a/zerver/webhooks/dialogflow/view.py +++ b/zerver/webhooks/dialogflow/view.py @@ -5,7 +5,7 @@ from django.http import HttpRequest, HttpResponse from zerver.decorator import webhook_view from zerver.lib.actions import check_send_private_message -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.models import UserProfile, get_user @@ -35,7 +35,7 @@ def api_dialogflow_webhook( body = f"{status} - {error_status}" receiving_user = get_user(email, user_profile.realm) - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None check_send_private_message(user_profile, client, receiving_user, body) return json_success() diff --git a/zerver/webhooks/slack/view.py b/zerver/webhooks/slack/view.py index e4fde46298..3c6a64f6a1 100644 --- a/zerver/webhooks/slack/view.py +++ b/zerver/webhooks/slack/view.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext as _ from zerver.decorator import webhook_view from zerver.lib.actions import check_send_stream_message from zerver.lib.exceptions import JsonableError -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.models import UserProfile @@ -35,7 +35,7 @@ def api_slack_webhook( subject = _("Message from Slack") content = ZULIP_MESSAGE_TEMPLATE.format(message_sender=user_name, text=text) - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None check_send_stream_message(user_profile, client, stream, subject, content) return json_success() diff --git a/zerver/webhooks/teamcity/view.py b/zerver/webhooks/teamcity/view.py index 87cd71f94c..25098e5673 100644 --- a/zerver/webhooks/teamcity/view.py +++ b/zerver/webhooks/teamcity/view.py @@ -10,7 +10,7 @@ from zerver.lib.actions import ( check_send_private_message, send_rate_limited_pm_notification_to_bot_owner, ) -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.lib.send_email import FromAddress from zerver.lib.webhooks.common import check_send_webhook_message @@ -137,7 +137,7 @@ def api_teamcity_webhook( return json_success() body = f"Your personal build for {body}" - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None check_send_private_message(user_profile, client, teamcity_user, body) diff --git a/zerver/webhooks/yo/view.py b/zerver/webhooks/yo/view.py index 4620b24e4f..b8335f1751 100644 --- a/zerver/webhooks/yo/view.py +++ b/zerver/webhooks/yo/view.py @@ -5,7 +5,7 @@ from django.http import HttpRequest, HttpResponse from zerver.decorator import webhook_view from zerver.lib.actions import check_send_private_message -from zerver.lib.request import REQ, get_request_notes, has_request_variables +from zerver.lib.request import REQ, RequestNotes, has_request_variables from zerver.lib.response import json_success from zerver.models import UserProfile, get_user @@ -22,7 +22,7 @@ def api_yo_app_webhook( ) -> HttpResponse: body = f"Yo from {username}" receiving_user = get_user(email, user_profile.realm) - client = get_request_notes(request).client + client = RequestNotes.get_notes(request).client assert client is not None check_send_private_message(user_profile, client, receiving_user, body) return json_success() diff --git a/zilencer/management/commands/profile_request.py b/zilencer/management/commands/profile_request.py index 862164fced..1c948c2eed 100644 --- a/zilencer/management/commands/profile_request.py +++ b/zilencer/management/commands/profile_request.py @@ -8,7 +8,7 @@ from django.core.management.base import CommandParser from django.http import HttpRequest, HttpResponse from zerver.lib.management import ZulipBaseCommand -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes from zerver.lib.test_helpers import HostRequestMock from zerver.middleware import LogRequests from zerver.models import UserMessage @@ -55,6 +55,6 @@ class Command(ZulipBaseCommand): path="/", ) mock_request.session = MockSession() - get_request_notes(mock_request).log_data = None + RequestNotes.get_notes(mock_request).log_data = None profile_request(mock_request) diff --git a/zproject/backends.py b/zproject/backends.py index 5de407d6ee..a3bd62261c 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -71,7 +71,7 @@ from zerver.lib.exceptions import JsonableError from zerver.lib.mobile_auth_otp import is_valid_otp from zerver.lib.rate_limiter import RateLimitedObject from zerver.lib.redis_utils import get_dict_from_redis, get_redis_client, put_dict_in_redis -from zerver.lib.request import get_request_notes +from zerver.lib.request import RequestNotes from zerver.lib.subdomains import get_subdomain from zerver.lib.users import check_full_name, validate_user_custom_profile_field from zerver.models import ( @@ -251,7 +251,7 @@ def rate_limit_authentication_by_username(request: HttpRequest, username: str) - def auth_rate_limiting_already_applied(request: HttpRequest) -> bool: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) return any( isinstance(r.entity, RateLimitedAuthenticationByUsername) @@ -270,7 +270,7 @@ def rate_limit_auth(auth_func: AuthFuncT, *args: Any, **kwargs: Any) -> Optional request = args[1] username = kwargs["username"] - if get_request_notes(request).client is None or not client_is_exempt_from_rate_limiting( + if RequestNotes.get_notes(request).client is None or not client_is_exempt_from_rate_limiting( request ): # Django cycles through enabled authentication backends until one succeeds, diff --git a/zproject/sentry.py b/zproject/sentry.py index 3f100cc28c..9a3483658a 100644 --- a/zproject/sentry.py +++ b/zproject/sentry.py @@ -22,7 +22,7 @@ def add_context(event: "Event", hint: "Hint") -> Optional["Event"]: return None from django.conf import settings - from zerver.lib.request import get_current_request, get_request_notes + from zerver.lib.request import RequestNotes, get_current_request from zerver.models import get_user_profile_by_id with capture_internal_exceptions(): @@ -47,7 +47,7 @@ def add_context(event: "Event", hint: "Hint") -> Optional["Event"]: request = get_current_request() if request: - request_notes = get_request_notes(request) + request_notes = RequestNotes.get_notes(request) if request_notes.client is not None: event["tags"]["client"] = request_notes.client.name if request_notes.realm is not None: