mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 13:33:24 +00:00
avatars: Serve /user_avatars/ through Django, which offloads to nginx.
Moving `/user_avatars/` to being served partially through Django removes the need for the `no_serve_uploads` nginx reconfiguring when switching between S3 and local backends. This is important because a subsequent commit will move S3 attachments to being served through nginx, which would make `no_serve_uploads` entirely nonsensical of a name. Serve the files through Django, with an offload for the actual image response to an internal nginx route. In development, serve the files directly in Django. We do _not_ mark the contents as immutable for caching purposes, since the path for avatar images is hashed only by their user-id and a salt, and as such are reused when a user's avatar is updated.
This commit is contained in:
committed by
Alex Vandiver
parent
f0f4aa66e0
commit
ed6d62a9e7
@@ -21,7 +21,11 @@ from django.utils.translation import gettext as _
|
||||
from zerver.context_processors import get_valid_realm_from_request
|
||||
from zerver.lib.exceptions import JsonableError
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.upload import check_upload_within_quota, upload_message_image_from_request
|
||||
from zerver.lib.upload import (
|
||||
check_upload_within_quota,
|
||||
get_public_upload_root_url,
|
||||
upload_message_image_from_request,
|
||||
)
|
||||
from zerver.lib.upload.base import INLINE_MIME_TYPES
|
||||
from zerver.lib.upload.local import (
|
||||
assert_is_local_storage_path,
|
||||
@@ -181,6 +185,39 @@ def serve_local_file_unauthed(request: HttpRequest, token: str, filename: str) -
|
||||
return serve_local(request, path_id, url_only=False)
|
||||
|
||||
|
||||
def serve_local_avatar_unauthed(request: HttpRequest, path: str) -> HttpResponseBase:
|
||||
"""Serves avatar images off disk, via nginx (or directly in dev), with no auth.
|
||||
|
||||
This is done unauthed because these need to be accessed from HTML
|
||||
emails, where the client does not have any auth. We rely on the
|
||||
URL being generated using the AVATAR_SALT secret.
|
||||
|
||||
"""
|
||||
if settings.LOCAL_AVATARS_DIR is None:
|
||||
# We do not expect clients to hit this URL when using the S3
|
||||
# backend; however, there is no reason to not serve the
|
||||
# redirect to S3 where the content lives.
|
||||
return redirect(
|
||||
get_public_upload_root_url() + path + "?" + request.GET.urlencode(), permanent=True
|
||||
)
|
||||
|
||||
local_path = os.path.join(settings.LOCAL_AVATARS_DIR, path)
|
||||
assert_is_local_storage_path("avatars", local_path)
|
||||
if not os.path.isfile(local_path):
|
||||
return HttpResponseNotFound("<p>File not found</p>")
|
||||
|
||||
if settings.DEVELOPMENT:
|
||||
response: HttpResponseBase = FileResponse(open(local_path, "rb"))
|
||||
else:
|
||||
response = internal_nginx_redirect(quote(f"/internal/user_avatars/{path}"))
|
||||
|
||||
# We do _not_ mark the contents as immutable for caching purposes,
|
||||
# since the path for avatar images is hashed only by their user-id
|
||||
# and a salt, and as such are reused when a user's avatar is
|
||||
# updated.
|
||||
return response
|
||||
|
||||
|
||||
def upload_file_backend(request: HttpRequest, user_profile: UserProfile) -> HttpResponse:
|
||||
if len(request.FILES) == 0:
|
||||
raise JsonableError(_("You must specify a file to upload"))
|
||||
|
||||
Reference in New Issue
Block a user