diff options
author | Andrew Godwin | 2022-12-12 07:22:11 -0700 |
---|---|---|
committer | Andrew Godwin | 2022-12-12 11:56:49 -0700 |
commit | 8ffe4bc1453660c1f211496074ebcc68c924327e (patch) | |
tree | 7503fdcd6aafd32e9ec75dc7190699e004cf2935 | |
parent | 35a45f1c55fba69d690929c9420df565e7c5efcc (diff) | |
download | takahe-8ffe4bc1453660c1f211496074ebcc68c924327e.tar.gz takahe-8ffe4bc1453660c1f211496074ebcc68c924327e.tar.bz2 takahe-8ffe4bc1453660c1f211496074ebcc68c924327e.zip |
A better way of handling URIs between local/remote
-rw-r--r-- | activities/models/post_attachment.py | 18 | ||||
-rw-r--r-- | core/uris.py | 34 | ||||
-rw-r--r-- | templates/activities/_identity.html | 2 | ||||
-rw-r--r-- | templates/activities/_image_uploaded.html | 2 | ||||
-rw-r--r-- | templates/activities/_mini_post.html | 2 | ||||
-rw-r--r-- | templates/activities/_post.html | 6 | ||||
-rw-r--r-- | templates/activities/follows.html | 2 | ||||
-rw-r--r-- | templates/base.html | 2 | ||||
-rw-r--r-- | templates/identity/select.html | 2 | ||||
-rw-r--r-- | templates/identity/view.html | 4 | ||||
-rw-r--r-- | users/models/identity.py | 28 |
11 files changed, 69 insertions, 33 deletions
diff --git a/activities/models/post_attachment.py b/activities/models/post_attachment.py index 7b1ad6b..3b1f425 100644 --- a/activities/models/post_attachment.py +++ b/activities/models/post_attachment.py @@ -1,9 +1,9 @@ from functools import partial -from django.conf import settings from django.db import models from core.uploads import upload_namer +from core.uris import AutoAbsoluteUrl, RelativeAbsoluteUrl from stator.models import State, StateField, StateGraph, StatorModel @@ -72,19 +72,19 @@ class PostAttachment(StatorModel): "image/webp", ] - def thumbnail_url(self): + def thumbnail_url(self) -> RelativeAbsoluteUrl: if self.thumbnail: - return self.thumbnail.url + return RelativeAbsoluteUrl(self.thumbnail.url) elif self.file: - return self.file.url + return RelativeAbsoluteUrl(self.file.url) else: - return f"https://{settings.MAIN_DOMAIN}/proxy/post_attachment/{self.pk}/" + return AutoAbsoluteUrl(f"/proxy/post_attachment/{self.pk}/") def full_url(self): if self.file: - return self.file.url + return RelativeAbsoluteUrl(self.file.url) else: - return f"https://{settings.MAIN_DOMAIN}/proxy/post_attachment/{self.pk}/" + return AutoAbsoluteUrl(f"/proxy/post_attachment/{self.pk}/") ### ActivityPub ### @@ -105,8 +105,8 @@ class PostAttachment(StatorModel): return { "id": self.pk, "type": "image" if self.is_image() else "unknown", - "url": self.full_url(), - "preview_url": self.thumbnail_url(), + "url": self.full_url().absolute, + "preview_url": self.thumbnail_url().absolute, "remote_url": None, "meta": { "original": { diff --git a/core/uris.py b/core/uris.py new file mode 100644 index 0000000..9ed2a32 --- /dev/null +++ b/core/uris.py @@ -0,0 +1,34 @@ +from urllib.parse import urljoin + +from django.conf import settings + + +class RelativeAbsoluteUrl: + """ + Represents a URL that can have both "relative" and "absolute" forms + for various use either locally or remotely. + """ + + absolute: str + relative: str + + def __init__(self, absolute: str, relative: str | None = None): + if "://" not in absolute: + raise ValueError(f"Absolute URL {absolute!r} is not absolute!") + self.absolute = absolute + self.relative = relative or absolute + + +class AutoAbsoluteUrl(RelativeAbsoluteUrl): + """ + Automatically makes the absolute variant by using either settings.MAIN_DOMAIN + or a passed identity's URI domain. + """ + + def __init__(self, relative: str, identity=None): + self.relative = relative + if identity: + absolute_prefix = f"https://{identity.domain.uri_domain}/" + else: + absolute_prefix = f"https://{settings.MAIN_DOMAIN}/" + self.absolute = urljoin(absolute_prefix, self.relative) diff --git a/templates/activities/_identity.html b/templates/activities/_identity.html index c48a645..feb3178 100644 --- a/templates/activities/_identity.html +++ b/templates/activities/_identity.html @@ -2,7 +2,7 @@ <div class="post user"> <a href="{{ identity.urls.view }}"> - <img src="{{ identity.local_icon_url }}" class="icon" alt="Avatar for {{ identity.name_or_handle }}"> + <img src="{{ identity.local_icon_url.relative }}" class="icon" alt="Avatar for {{ identity.name_or_handle }}"> </a> {% if created %} diff --git a/templates/activities/_image_uploaded.html b/templates/activities/_image_uploaded.html index 6821328..36bd7fe 100644 --- a/templates/activities/_image_uploaded.html +++ b/templates/activities/_image_uploaded.html @@ -1,6 +1,6 @@ <div class="uploaded-image"> <input type="hidden" name="attachment" value="{{ attachment.pk }}"> - <img src="{{ attachment.thumbnail_url }}"> + <img src="{{ attachment.thumbnail_url.relative }}"> <p> {{ attachment.name|default:"(no description)" }} </p> diff --git a/templates/activities/_mini_post.html b/templates/activities/_mini_post.html index 19fad76..9f83333 100644 --- a/templates/activities/_mini_post.html +++ b/templates/activities/_mini_post.html @@ -3,7 +3,7 @@ <div class="post mini" data-takahe-id="{{ post.id }}" role="article"> <a href="{{ post.author.urls.view }}" tabindex="-1"> - <img src="{{ post.author.local_icon_url }}" class="icon"> + <img src="{{ post.author.local_icon_url.relative }}" class="icon"> </a> <a href="{{ post.author.urls.view }}" class="handle"> diff --git a/templates/activities/_post.html b/templates/activities/_post.html index 099a35f..5802acd 100644 --- a/templates/activities/_post.html +++ b/templates/activities/_post.html @@ -3,7 +3,7 @@ <div class="post {% if reply %}reply{% endif %}" data-takahe-id="{{ post.id }}" role="article" tabindex="0"> <a href="{{ post.author.urls.view }}" tabindex="-1"> - <img src="{{ post.author.local_icon_url }}" class="icon"> + <img src="{{ post.author.local_icon_url.relative }}" class="icon"> </a> <time _="on click go url {% if link_original %}{{ post.url }}{% else %}{{ post.urls.view }}{% endif %} then halt"> @@ -75,8 +75,8 @@ <div class="attachments"> {% for attachment in post.attachments.all %} {% if attachment.is_image %} - <a href="{{ attachment.full_url }}" class="image"> - <img src="{{ attachment.thumbnail_url }}" title="{{ attachment.name }}" alt="{{ attachment.name }}" /> + <a href="{{ attachment.full_url.relative }}" class="image"> + <img src="{{ attachment.thumbnail_url.relative }}" title="{{ attachment.name }}" alt="{{ attachment.name }}" /> </a> {% endif %} {% endfor %} diff --git a/templates/activities/follows.html b/templates/activities/follows.html index 6116dd6..27a13d3 100644 --- a/templates/activities/follows.html +++ b/templates/activities/follows.html @@ -6,7 +6,7 @@ <section class="icon-menu"> {% for identity, details in identities %} <a class="option" href="{{ identity.urls.view }}"> - <img src="{{ identity.local_icon_url }}"> + <img src="{{ identity.local_icon_url.relative }}"> <span class="handle"> {{ identity.name_or_handle }} <small>@{{ identity.handle }}</small> diff --git a/templates/base.html b/templates/base.html index df8ebdf..4614223 100644 --- a/templates/base.html +++ b/templates/base.html @@ -48,7 +48,7 @@ <img src="{% static "img/unknown-icon-128.png" %}" title="No identity selected"> {% else %} {{ request.identity.username }} - <img src="{{ request.identity.local_icon_url }}" title="{{ request.identity.handle }}"> + <img src="{{ request.identity.local_icon_url.relative }}" title="{{ request.identity.handle }}"> {% endif %} </a> {% else %} diff --git a/templates/identity/select.html b/templates/identity/select.html index d63f886..b3fc41d 100644 --- a/templates/identity/select.html +++ b/templates/identity/select.html @@ -6,7 +6,7 @@ <section class="icon-menu"> {% for identity in identities %} <a class="option" href="{{ identity.urls.activate }}"> - <img src="{{ identity.local_icon_url }}"> + <img src="{{ identity.local_icon_url.relative }}"> <span class="handle"> {{ identity.name_or_handle }} <small>@{{ identity.handle }}</small> diff --git a/templates/identity/view.html b/templates/identity/view.html index 612e3d2..8d5806f 100644 --- a/templates/identity/view.html +++ b/templates/identity/view.html @@ -13,10 +13,10 @@ {% block content %} <h1 class="identity"> {% if identity.local_image_url %} - <img src="{{ identity.local_image_url }}" class="banner"> + <img src="{{ identity.local_image_url.relative }}" class="banner"> {% endif %} - <img src="{{ identity.local_icon_url }}" class="icon"> + <img src="{{ identity.local_icon_url.relative }}" class="icon"> {% if request.identity %} {% if identity == request.identity %} diff --git a/users/models/identity.py b/users/models/identity.py index a8937c9..1ece0fd 100644 --- a/users/models/identity.py +++ b/users/models/identity.py @@ -5,7 +5,6 @@ from urllib.parse import urlparse import httpx import urlman from asgiref.sync import async_to_sync, sync_to_async -from django.conf import settings from django.db import IntegrityError, models from django.template.defaultfilters import linebreaks_filter from django.templatetags.static import static @@ -18,6 +17,7 @@ from core.ld import canonicalise, format_ld_date, get_list, media_type_from_file from core.models import Config from core.signatures import HttpSignature, RsaKeys from core.uploads import upload_namer +from core.uris import AutoAbsoluteUrl, RelativeAbsoluteUrl from stator.models import State, StateField, StateGraph, StatorModel from users.models.domain import Domain from users.models.system_actor import SystemActor @@ -147,25 +147,26 @@ class Identity(StatorModel): else: return self.profile_uri - def local_icon_url(self): + def local_icon_url(self) -> RelativeAbsoluteUrl: """ - Returns an icon for us, with fallbacks to a placeholder + Returns an icon for use by us, with fallbacks to a placeholder """ if self.icon: - return self.icon.url + return RelativeAbsoluteUrl(self.icon.url) elif self.icon_uri: - return f"https://{settings.MAIN_DOMAIN}/proxy/identity_icon/{self.pk}/" + return AutoAbsoluteUrl(f"/proxy/identity_icon/{self.pk}/") else: - return static("img/unknown-icon-128.png") + return RelativeAbsoluteUrl(static("img/unknown-icon-128.png")) - def local_image_url(self): + def local_image_url(self) -> RelativeAbsoluteUrl | None: """ Returns a background image for us, returning None if there isn't one """ if self.image: - return self.image.url + return RelativeAbsoluteUrl(self.image.url) elif self.image_uri: - return f"https://{settings.MAIN_DOMAIN}/proxy/identity_image/{self.pk}/" + return AutoAbsoluteUrl(f"/proxy/identity_image/{self.pk}/") + return None @property def safe_summary(self): @@ -470,6 +471,7 @@ class Identity(StatorModel): ### Mastodon Client API ### def to_mastodon_json(self): + header_image = self.local_image_url() return { "id": self.pk, "username": self.username, @@ -477,10 +479,10 @@ class Identity(StatorModel): "url": self.absolute_profile_uri(), "display_name": self.name, "note": self.summary or "", - "avatar": self.local_icon_url(), - "avatar_static": self.local_icon_url(), - "header": self.local_image_url() or "", - "header_static": self.local_image_url() or "", + "avatar": self.local_icon_url().absolute, + "avatar_static": self.local_icon_url().absolute, + "header": header_image.absolute if header_image else None, + "header_static": header_image.absolute if header_image else None, "locked": False, "fields": ( [ |