Add BlueskyProxy + handle requests

This commit is contained in:
Oliver Falk
2025-01-31 12:49:06 +01:00
parent 94b0fc2068
commit e1705cef36

View File

@@ -5,7 +5,7 @@ views under /
from io import BytesIO from io import BytesIO
from os import path from os import path
import hashlib import hashlib
from ivatar.utils import urlopen from ivatar.utils import urlopen, Bluesky
from urllib.error import HTTPError, URLError from urllib.error import HTTPError, URLError
from ssl import SSLError from ssl import SSLError
from django.views.generic.base import TemplateView, View from django.views.generic.base import TemplateView, View
@@ -121,7 +121,8 @@ class AvatarImageView(TemplateView):
if CACHE_RESPONSE: if CACHE_RESPONSE:
centry = caches["filesystem"].get(uri) centry = caches["filesystem"].get(uri)
if centry: if centry:
# For DEBUG purpose only print('Cached entry for %s' % uri) # For DEBUG purpose only
# print('Cached entry for %s' % uri)
return HttpResponse( return HttpResponse(
centry["content"], centry["content"],
content_type=centry["content_type"], content_type=centry["content_type"],
@@ -190,6 +191,12 @@ class AvatarImageView(TemplateView):
except Exception: # pylint: disable=bare-except except Exception: # pylint: disable=bare-except
pass pass
# Handle the special case of Bluesky
if obj:
if obj.bluesky_handle:
return HttpResponseRedirect(
reverse_lazy("blueskyproxy", args=[kwargs["digest"]])
)
# If that mail/openid doesn't exist, or has no photo linked to it # If that mail/openid doesn't exist, or has no photo linked to it
if not obj or not obj.photo or forcedefault: if not obj or not obj.photo or forcedefault:
gravatar_url = ( gravatar_url = (
@@ -448,6 +455,131 @@ class GravatarProxyView(View):
return redir_default(default) return redir_default(default)
class BlueskyProxyView(View):
"""
Proxy request to Bluesky and return the image from there
"""
def get(
self, request, *args, **kwargs
): # pylint: disable=too-many-branches,too-many-statements,too-many-locals,no-self-use,unused-argument,too-many-return-statements
"""
Override get from parent class
"""
def redir_default(default=None):
url = (
reverse_lazy("avatar_view", args=[kwargs["digest"]])
+ "?s=%i" % size
+ "&forcedefault=y"
)
if default is not None:
url += "&default=%s" % default
return HttpResponseRedirect(url)
size = get_size(request)
print(size)
blueskyimagedata = None
default = None
try:
if str(request.GET["default"]) != "None":
default = request.GET["default"]
except Exception: # pylint: disable=bare-except
pass
identity = None
# First check for email, as this is the most common
try:
identity = ConfirmedEmail.objects.filter(
Q(digest=kwargs["digest"]) | Q(digest_sha256=kwargs["digest"])
).first()
except Exception as exc:
print(exc)
# If no identity is found in the email table, try the openid table
if not identity:
try:
identity = ConfirmedOpenId.objects.filter(
Q(digest=kwargs["digest"])
| Q(alt_digest1=kwargs["digest"])
| Q(alt_digest2=kwargs["digest"])
| Q(alt_digest3=kwargs["digest"])
).first()
except Exception as exc:
print(exc)
# If still no identity is found, redirect to the default
if not identity:
return redir_default(default)
bs = Bluesky()
bluesky_url = None
# Try with the cache first
try:
if cache.get(identity.bluesky_handle):
bluesky_url = cache.get(identity.bluesky_handle)
except Exception: # pylint: disable=bare-except
pass
if not bluesky_url:
try:
bluesky_url = bs.get_avatar(identity.bluesky_handle)
cache.set(identity.bluesky_handle, bluesky_url)
except Exception: # pylint: disable=bare-except
return redir_default(default)
try:
if cache.get(bluesky_url) == "err":
print("Cached Bluesky fetch failed with URL error: %s" % bluesky_url)
return redir_default(default)
blueskyimagedata = urlopen(bluesky_url)
except HTTPError as exc:
if exc.code != 404 and exc.code != 503:
print(
"Bluesky fetch failed with an unexpected %s HTTP error: %s"
% (exc.code, bluesky_url)
)
cache.set(bluesky_url, "err", 30)
return redir_default(default)
except URLError as exc:
print("Bluesky fetch failed with URL error: %s" % exc.reason)
cache.set(bluesky_url, "err", 30)
return redir_default(default)
except SSLError as exc:
print("Bluesky fetch failed with SSL error: %s" % exc.reason)
cache.set(bluesky_url, "err", 30)
return redir_default(default)
try:
data = BytesIO(blueskyimagedata.read())
img = Image.open(data)
format = img.format
if max(img.size) > size:
aspect = img.size[0] / float(img.size[1])
if aspect > 1:
new_size = (size, int(size / aspect))
else:
new_size = (int(size * aspect), size)
img = img.resize(new_size)
data = BytesIO()
img.save(data, format=format)
data.seek(0)
response = HttpResponse(
data.read(), content_type="image/%s" % file_format(format)
)
response["Cache-Control"] = "max-age=%i" % CACHE_IMAGES_MAX_AGE
return response
except ValueError as exc:
print("Value error: %s" % exc)
return redir_default(default)
# We shouldn't reach this point... But make sure we do something
return redir_default(default)
class StatsView(TemplateView, JsonResponse): class StatsView(TemplateView, JsonResponse):
""" """
Return stats Return stats