request: Use Django 5.2 HttpRequest.get_preferred_type.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2025-06-10 10:48:35 -07:00
committed by Tim Abbott
parent 6006ba4c44
commit d24eab02d2
4 changed files with 10 additions and 57 deletions

View File

@@ -16,7 +16,6 @@ from corporate.lib.remote_billing_util import (
get_remote_server_and_user_from_session,
)
from zerver.lib.exceptions import RemoteBillingAuthenticationError
from zerver.lib.request import get_preferred_type
from zerver.lib.subdomains import get_subdomain
from zerver.lib.url_encoding import append_url_query_string
from zilencer.models import RemoteRealm
@@ -125,7 +124,7 @@ def authenticated_remote_realm_management_endpoint(
# Return error for AJAX requests with url.
if (
get_preferred_type(request, ["application/json", "text/html"]) != "text/html"
request.get_preferred_type(["application/json", "text/html"]) != "text/html"
): # nocoverage
return session_expired_ajax_response(url)
@@ -211,7 +210,7 @@ def authenticated_remote_server_management_endpoint(
# Return error for AJAX requests with url.
if (
get_preferred_type(request, ["application/json", "text/html"]) != "text/html"
request.get_preferred_type(["application/json", "text/html"]) != "text/html"
): # nocoverage
return session_expired_ajax_response(url)

View File

@@ -98,22 +98,3 @@ class RequestVariableConversionError(JsonableError):
arguments_map: dict[str, list[str]] = defaultdict(list)
# Equivalent to request.get_preferred_type() in Django 5.2.
def get_preferred_type(request: HttpRequest, media_types: list[str]) -> str | None:
best_type = None
best_score = 0.0, True, True
for accepted_type in request.accepted_types:
score = (
float(accepted_type.params.get("q", "1")),
accepted_type.main_type != "*",
accepted_type.sub_type != "*",
)
if best_score < score:
for media_type in media_types:
if accepted_type.match(media_type):
best_type = media_type
best_score = score
break
return best_type

View File

@@ -33,7 +33,7 @@ from zerver.lib.exceptions import ErrorCode, JsonableError, MissingAuthenticatio
from zerver.lib.markdown import get_markdown_requests, get_markdown_time
from zerver.lib.per_request_cache import flush_per_request_caches
from zerver.lib.rate_limiter import RateLimitResult
from zerver.lib.request import RequestNotes, get_preferred_type
from zerver.lib.request import RequestNotes
from zerver.lib.response import (
AsynchronousResponse,
json_response,
@@ -377,7 +377,7 @@ class LogRequests(MiddlewareMixin):
class JsonErrorHandler(MiddlewareMixin):
def process_exception(self, request: HttpRequest, exception: Exception) -> HttpResponse | None:
if isinstance(exception, MissingAuthenticationError):
if get_preferred_type(request, ["application/json", "text/html"]) == "text/html":
if request.get_preferred_type(["application/json", "text/html"]) == "text/html":
# If this looks like a request from a top-level page in a
# browser, send the user to the login page.
#

View File

@@ -193,40 +193,11 @@ def serve_file_url_backend(
return serve_file(request, user_profile, realm_id_str, filename, url_only=True)
def preferred_accept(request: HttpRequest, served_types: list[str]) -> str | None:
# Returns the first of the served_types which the browser will
# accept, based on the browser's stated quality preferences.
# Returns None if none of the served_types are accepted by the
# browser.
accepted_types = sorted(
request.accepted_types,
key=lambda e: float(e.params.get("q", "1.0")),
reverse=True,
)
for potential_type in accepted_types:
for served_type in served_types:
if potential_type.match(served_type):
return served_type
return None
def closest_thumbnail_format(
requested_format: BaseThumbnailFormat,
request: HttpRequest,
rendered_formats: list[StoredThumbnailFormat],
) -> StoredThumbnailFormat:
accepted_types = sorted(
request.accepted_types,
key=lambda e: float(e.params.get("q", "1.0")),
reverse=True,
)
def q_for(content_type: str) -> float:
for potential_type in accepted_types:
if potential_type.match(content_type):
return float(potential_type.params.get("q", "1.0"))
return 0.0
# Serve a "close" format -- preferring animated which
# matches, followed by the format they requested, or one
# their browser supports, in the size closest to what they
@@ -237,12 +208,14 @@ def closest_thumbnail_format(
return (
possible_format.animated != requested_format.animated,
possible_format.extension != requested_format.extension,
1.0 - q_for(possible_format.content_type),
0.0
if (accepted_type := request.accepted_type(possible_format.content_type)) is None
else -accepted_type.quality,
abs(requested_format.max_width - possible_format.max_width),
possible_format.byte_size,
)
return sorted(rendered_formats, key=grade_format)[0]
return min(rendered_formats, key=grade_format)
def serve_file(
@@ -265,7 +238,7 @@ def serve_file(
return FileResponse(open(static_path(image_path), "rb"), status=status)
if attachment is None:
if preferred_accept(request, ["text/html", "image/png"]) == "image/png":
if request.get_preferred_type(["text/html", "image/png"]) == "image/png":
response = serve_image_error(404, "images/errors/image-not-exist.png")
else:
response = HttpResponseNotFound(
@@ -274,7 +247,7 @@ def serve_file(
patch_vary_headers(response, ("Accept",))
return response
if not is_authorized:
if preferred_accept(request, ["text/html", "image/png"]) == "image/png":
if request.get_preferred_type(["text/html", "image/png"]) == "image/png":
response = serve_image_error(403, "images/errors/image-no-auth.png")
elif isinstance(maybe_user_profile, AnonymousUser):
response = zulip_redirect_to_login(request)