lib: improve caching of gravatar status

closes #4711

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens Langhammer 2023-02-20 12:41:09 +01:00
parent b415e9b773
commit 327d87355d
No known key found for this signature in database
1 changed files with 21 additions and 17 deletions

View File

@ -1,10 +1,11 @@
"""Avatar utils""" """Avatar utils"""
from base64 import b64encode from base64 import b64encode
from functools import cache from functools import cache as funccache
from hashlib import md5 from hashlib import md5
from typing import TYPE_CHECKING, Optional from typing import TYPE_CHECKING, Optional
from urllib.parse import urlencode from urllib.parse import urlencode
from django.core.cache import cache
from django.templatetags.static import static from django.templatetags.static import static
from lxml import etree # nosec from lxml import etree # nosec
from lxml.etree import Element, SubElement # nosec from lxml.etree import Element, SubElement # nosec
@ -15,6 +16,7 @@ from authentik.lib.utils.http import get_http_session
GRAVATAR_URL = "https://secure.gravatar.com" GRAVATAR_URL = "https://secure.gravatar.com"
DEFAULT_AVATAR = static("dist/assets/images/user_default.png") DEFAULT_AVATAR = static("dist/assets/images/user_default.png")
CACHE_KEY_GRAVATAR = "goauthentik.io/lib/avatars/"
if TYPE_CHECKING: if TYPE_CHECKING:
from authentik.core.models import User from authentik.core.models import User
@ -50,22 +52,24 @@ def avatar_mode_gravatar(user: "User", mode: str) -> Optional[str]:
parameters = [("size", "158"), ("rating", "g"), ("default", "404")] parameters = [("size", "158"), ("rating", "g"), ("default", "404")]
gravatar_url = f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}" gravatar_url = f"{GRAVATAR_URL}/avatar/{mail_hash}?{urlencode(parameters, doseq=True)}"
@cache full_key = CACHE_KEY_GRAVATAR + mail_hash
def check_non_default(url: str): if cache.has_key(full_key):
"""Cache HEAD check, based on URL""" cache.touch(full_key)
return cache.get(full_key)
try: try:
# Since we specify a default of 404, do a HEAD request # Since we specify a default of 404, do a HEAD request
# (HEAD since we don't need the body) # (HEAD since we don't need the body)
# so if that returns a 404, move onto the next mode # so if that returns a 404, move onto the next mode
res = get_http_session().head(url, timeout=5) res = get_http_session().head(gravatar_url, timeout=5)
if res.status_code == 404: if res.status_code == 404:
cache.set(full_key, None)
return None return None
res.raise_for_status() res.raise_for_status()
except RequestException: except RequestException:
return url return gravatar_url
return url cache.set(full_key, gravatar_url)
return gravatar_url
return check_non_default(gravatar_url)
def generate_colors(text: str) -> tuple[str, str]: def generate_colors(text: str) -> tuple[str, str]:
@ -83,7 +87,7 @@ def generate_colors(text: str) -> tuple[str, str]:
return bg_hex, text_hex return bg_hex, text_hex
@cache @funccache
# pylint: disable=too-many-arguments,too-many-locals # pylint: disable=too-many-arguments,too-many-locals
def generate_avatar_from_name( def generate_avatar_from_name(
name: str, name: str,