mirror of https://github.com/zulip/zulip.git
storage: Rework static avatar files hashing logic.
Previously, the hashing logic for static avatar files hashed the default and medium files separately, which didn’t match how user-uploaded avatars work—where you just add the "-medium.png" suffix to get the medium version. Since we don’t have clear documentation for avatars yet, this caused some issues for the mobile apps. This commit makes sure the default and its medium variation share the same hash.
This commit is contained in:
parent
2109d3d1ab
commit
c3017e55d2
|
@ -24,15 +24,36 @@ else:
|
||||||
return os.path.join(settings.STATIC_ROOT, path)
|
return os.path.join(settings.STATIC_ROOT, path)
|
||||||
|
|
||||||
|
|
||||||
def reformat_medium_filename(hashed_name: str) -> str:
|
class IgnoreBundlesManifestStaticFilesStorage(ManifestStaticFilesStorage):
|
||||||
|
hashed_static_avatar_file_map: dict[str, str] = {}
|
||||||
|
|
||||||
|
def process_static_avatars_name(
|
||||||
|
self,
|
||||||
|
name: str,
|
||||||
|
content: Optional["File[bytes]"] = None,
|
||||||
|
filename: str | None = None,
|
||||||
|
) -> str:
|
||||||
"""
|
"""
|
||||||
Because the protocol for getting medium-size avatar URLs
|
Because the protocol for getting medium-size avatar URLs
|
||||||
was never fully documented, the mobile apps use a
|
was never fully documented, the mobile apps use a
|
||||||
substitution of the form s/.png/-medium.png/ to get the
|
substitution of the form s/.png/-medium.png/ to get the
|
||||||
medium-size avatar URLs. Thus, we must ensure the hashed
|
medium-size avatar URLs.
|
||||||
filenames for system bot avatars follow this naming convention.
|
|
||||||
|
This function hashes system bots' avatar files in a way
|
||||||
|
that follows the pattern used for user-uploaded avatars.
|
||||||
|
|
||||||
|
It ensures the following:
|
||||||
|
|
||||||
|
* Hashed filenames for system bot avatars follow this
|
||||||
|
naming convention:
|
||||||
|
- avatar.png -> avatar-medium.png
|
||||||
|
|
||||||
|
* The system bots' default avatar file and its medium
|
||||||
|
version share the same hash:
|
||||||
|
- bot.36f721bad3d0.png -> bot.36f721bad3d0-medium.png
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def reformat_medium_filename(hashed_name: str) -> str:
|
||||||
name_parts = hashed_name.rsplit(".", 1)
|
name_parts = hashed_name.rsplit(".", 1)
|
||||||
base_name = name_parts[0]
|
base_name = name_parts[0]
|
||||||
|
|
||||||
|
@ -42,8 +63,23 @@ def reformat_medium_filename(hashed_name: str) -> str:
|
||||||
base_name = base_name.replace("-medium", "")
|
base_name = base_name.replace("-medium", "")
|
||||||
return f"{base_name}-{extension}"
|
return f"{base_name}-{extension}"
|
||||||
|
|
||||||
|
if name.endswith("-medium.png"):
|
||||||
|
# This logic relies on the fact that the medium files will
|
||||||
|
# be hashed first due to the "-medium" string, which places
|
||||||
|
# them earlier in the naming order. So, adhering to the
|
||||||
|
# medium file naming convention is crucial for this logic.
|
||||||
|
hashed_medium_file: str = reformat_medium_filename(
|
||||||
|
super().hashed_name(name, content, filename)
|
||||||
|
)
|
||||||
|
|
||||||
|
default_file = name.replace("-medium.png", ".png")
|
||||||
|
hashed_default_file = hashed_medium_file.replace("-medium.png", ".png")
|
||||||
|
|
||||||
|
self.hashed_static_avatar_file_map[default_file] = hashed_default_file
|
||||||
|
return hashed_medium_file
|
||||||
|
assert name in self.hashed_static_avatar_file_map
|
||||||
|
return self.hashed_static_avatar_file_map[name]
|
||||||
|
|
||||||
class IgnoreBundlesManifestStaticFilesStorage(ManifestStaticFilesStorage):
|
|
||||||
@override
|
@override
|
||||||
def hashed_name(
|
def hashed_name(
|
||||||
self, name: str, content: Optional["File[bytes]"] = None, filename: str | None = None
|
self, name: str, content: Optional["File[bytes]"] = None, filename: str | None = None
|
||||||
|
@ -64,11 +100,8 @@ class IgnoreBundlesManifestStaticFilesStorage(ManifestStaticFilesStorage):
|
||||||
# so they can hit our Nginx caching block for static files.
|
# so they can hit our Nginx caching block for static files.
|
||||||
# We don't need to worry about stale caches since these are
|
# We don't need to worry about stale caches since these are
|
||||||
# only used by the system bots.
|
# only used by the system bots.
|
||||||
if not name.endswith("-medium.png"):
|
return self.process_static_avatars_name(name, content, filename)
|
||||||
return super().hashed_name(name, content, filename)
|
|
||||||
|
|
||||||
hashed_medium_file = super().hashed_name(name, content, filename)
|
|
||||||
return reformat_medium_filename(hashed_medium_file)
|
|
||||||
if name == "generated/emoji/emoji_api.json":
|
if name == "generated/emoji/emoji_api.json":
|
||||||
# Unlike most .json files, we do want to hash this file;
|
# Unlike most .json files, we do want to hash this file;
|
||||||
# its hashed URL is returned as part of the API. See
|
# its hashed URL is returned as part of the API. See
|
||||||
|
|
Loading…
Reference in New Issue