django-avatar/avatar/providers.py
Alex Iribarren 14495e8106
Enable parameters for LibRavatar (#255)
* Enable parameters for LibRavatar

Added support for default parameters to LibRavatar

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-01-07 21:46:42 +01:00

137 lines
4.4 KiB
Python

import hashlib
import re
from urllib.parse import urlencode, urljoin
import dns.resolver
from django.utils.module_loading import import_string
from avatar.conf import settings
from avatar.utils import force_bytes, get_default_avatar_url, get_primary_avatar
# If the FacebookAvatarProvider is used, a mechanism needs to be defined on
# how to obtain the user's Facebook UID. This is done via
# ``AVATAR_FACEBOOK_GET_ID``.
get_facebook_id = None
if "avatar.providers.FacebookAvatarProvider" in settings.AVATAR_PROVIDERS:
if callable(settings.AVATAR_FACEBOOK_GET_ID):
get_facebook_id = settings.AVATAR_FACEBOOK_GET_ID
else:
get_facebook_id = import_string(settings.AVATAR_FACEBOOK_GET_ID)
class DefaultAvatarProvider(object):
"""
Returns the default url defined by ``settings.DEFAULT_AVATAR_URL``.
"""
@classmethod
def get_avatar_url(cls, user, width, height=None):
return get_default_avatar_url()
class PrimaryAvatarProvider(object):
"""
Returns the primary Avatar from the users avatar set.
"""
@classmethod
def get_avatar_url(cls, user, width, height=None):
if not height:
height = width
avatar = get_primary_avatar(user, width, height)
if avatar:
return avatar.avatar_url(width, height)
class GravatarAvatarProvider(object):
"""
Returns the url for an avatar by the Gravatar service.
"""
@classmethod
def get_avatar_url(cls, user, width, _height=None):
params = {"s": str(width)}
if settings.AVATAR_GRAVATAR_DEFAULT:
params["d"] = settings.AVATAR_GRAVATAR_DEFAULT
if settings.AVATAR_GRAVATAR_FORCEDEFAULT:
params["f"] = "y"
path = "%s/?%s" % (
hashlib.md5(
force_bytes(getattr(user, settings.AVATAR_GRAVATAR_FIELD))
).hexdigest(),
urlencode(params),
)
return urljoin(settings.AVATAR_GRAVATAR_BASE_URL, path)
class LibRAvatarProvider:
"""
Returns the url of an avatar by the LibRavatar service.
"""
@classmethod
def get_avatar_url(cls, user, width, _height=None):
email = getattr(user, settings.AVATAR_GRAVATAR_FIELD).encode("utf-8")
try:
_, domain = email.split(b"@")
answers = dns.resolver.query("_avatars._tcp." + domain, "SRV")
hostname = re.sub(r"\.$", "", str(answers[0].target))
# query returns "example.com." and while http requests are fine with this,
# https most certainly do not consider "example.com." and "example.com" to be the same.
port = str(answers[0].port)
if port == "443":
baseurl = "https://" + hostname + "/avatar/"
else:
baseurl = "http://" + hostname + ":" + port + "/avatar/"
except Exception:
baseurl = "https://seccdn.libravatar.org/avatar/"
params = {"s": str(width)}
if settings.AVATAR_GRAVATAR_DEFAULT:
params["d"] = settings.AVATAR_GRAVATAR_DEFAULT
if settings.AVATAR_GRAVATAR_FORCEDEFAULT:
params["f"] = "y"
path = "%s/?%s" % (
hashlib.md5(force_bytes(email.strip().lower())).hexdigest(),
urlencode(params),
)
return urljoin(baseurl, path)
class FacebookAvatarProvider(object):
"""
Returns the url of a Facebook profile image.
"""
@classmethod
def get_avatar_url(cls, user, width, height=None):
if not height:
height = width
fb_id = get_facebook_id(user)
if fb_id:
url = "https://graph.facebook.com/{fb_id}/picture?type=square&width={width}&height={height}"
return url.format(fb_id=fb_id, width=width, height=height)
class InitialsAvatarProvider(object):
"""
Returns a tuple with template_name and context for rendering the given user's avatar as their
initials in white against a background with random hue based on their primary key.
"""
@classmethod
def get_avatar_url(cls, user, width, _height=None):
initials = user.first_name[:1] + user.last_name[:1]
if not initials:
initials = user.username[:1]
initials = initials.upper()
context = {
"fontsize": (width * 1.1) / 2,
"initials": initials,
"hue": user.pk % 360,
"saturation": "65%",
"lightness": "60%",
}
return ("avatar/initials.html", context)