Fix follower links, HTMX follow/unfollow, update shared submodule
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 41s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 41s
- Follower profile links now go to https://domain/@username (web profile) instead of the AP actor URL which 404s - Follow Back/Unfollow buttons update via HTMX without full page refresh - Update shared submodule to decoupling branch with new protocol methods Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -157,6 +157,8 @@ def register(url_prefix="/social"):
|
|||||||
await services.federation.send_follow(
|
await services.federation.send_follow(
|
||||||
g.s, actor.preferred_username, remote_actor_url,
|
g.s, actor.preferred_username, remote_actor_url,
|
||||||
)
|
)
|
||||||
|
if request.headers.get("HX-Request"):
|
||||||
|
return await _actor_card_response(actor, remote_actor_url, is_followed=True)
|
||||||
return redirect(request.referrer or url_for("social.search"))
|
return redirect(request.referrer or url_for("social.search"))
|
||||||
|
|
||||||
@bp.post("/unfollow")
|
@bp.post("/unfollow")
|
||||||
@@ -168,8 +170,34 @@ def register(url_prefix="/social"):
|
|||||||
await services.federation.unfollow(
|
await services.federation.unfollow(
|
||||||
g.s, actor.preferred_username, remote_actor_url,
|
g.s, actor.preferred_username, remote_actor_url,
|
||||||
)
|
)
|
||||||
|
if request.headers.get("HX-Request"):
|
||||||
|
return await _actor_card_response(actor, remote_actor_url, is_followed=False)
|
||||||
return redirect(request.referrer or url_for("social.search"))
|
return redirect(request.referrer or url_for("social.search"))
|
||||||
|
|
||||||
|
async def _actor_card_response(actor, remote_actor_url, is_followed):
|
||||||
|
"""Re-render a single actor card after follow/unfollow via HTMX."""
|
||||||
|
remote_dto = await services.federation.get_or_fetch_remote_actor(
|
||||||
|
g.s, remote_actor_url,
|
||||||
|
)
|
||||||
|
if not remote_dto:
|
||||||
|
return Response("", status=200)
|
||||||
|
followed_urls = {remote_actor_url} if is_followed else set()
|
||||||
|
# Detect list context from referer
|
||||||
|
referer = request.referrer or ""
|
||||||
|
if "/followers" in referer:
|
||||||
|
list_type = "followers"
|
||||||
|
else:
|
||||||
|
list_type = "following"
|
||||||
|
return await render_template(
|
||||||
|
"federation/_actor_list_items.html",
|
||||||
|
actors=[remote_dto],
|
||||||
|
total=0,
|
||||||
|
page=1,
|
||||||
|
list_type=list_type,
|
||||||
|
followed_urls=followed_urls,
|
||||||
|
actor=actor,
|
||||||
|
)
|
||||||
|
|
||||||
# -- Interactions ---------------------------------------------------------
|
# -- Interactions ---------------------------------------------------------
|
||||||
|
|
||||||
@bp.post("/like")
|
@bp.post("/like")
|
||||||
|
|||||||
2
shared
2
shared
Submodule shared updated: bccfff0c69...04f7c5e85c
@@ -1,5 +1,6 @@
|
|||||||
{% for a in actors %}
|
{% for a in actors %}
|
||||||
<article class="bg-white rounded-lg shadow-sm border border-stone-200 p-4 mb-3 flex items-center gap-4">
|
<article class="bg-white rounded-lg shadow-sm border border-stone-200 p-4 mb-3 flex items-center gap-4"
|
||||||
|
id="actor-{{ a.actor_url | replace('/', '_') | replace(':', '_') }}">
|
||||||
{% if a.icon_url %}
|
{% if a.icon_url %}
|
||||||
<img src="{{ a.icon_url }}" alt="" class="w-12 h-12 rounded-full">
|
<img src="{{ a.icon_url }}" alt="" class="w-12 h-12 rounded-full">
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -14,7 +15,7 @@
|
|||||||
{{ a.display_name or a.preferred_username }}
|
{{ a.display_name or a.preferred_username }}
|
||||||
</a>
|
</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a href="{{ a.actor_url }}" target="_blank" rel="noopener" class="font-semibold text-stone-900 hover:underline">
|
<a href="https://{{ a.domain }}/@{{ a.preferred_username }}" target="_blank" rel="noopener" class="font-semibold text-stone-900 hover:underline">
|
||||||
{{ a.display_name or a.preferred_username }}
|
{{ a.display_name or a.preferred_username }}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -26,32 +27,28 @@
|
|||||||
|
|
||||||
{% if actor %}
|
{% if actor %}
|
||||||
<div class="flex-shrink-0">
|
<div class="flex-shrink-0">
|
||||||
{% if list_type == "following" %}
|
{% if list_type == "following" or a.actor_url in (followed_urls or set()) %}
|
||||||
<form method="post" action="{{ url_for('social.unfollow') }}">
|
<form method="post" action="{{ url_for('social.unfollow') }}"
|
||||||
|
hx-post="{{ url_for('social.unfollow') }}"
|
||||||
|
hx-target="closest article"
|
||||||
|
hx-swap="outerHTML">
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
<input type="hidden" name="actor_url" value="{{ a.actor_url }}">
|
<input type="hidden" name="actor_url" value="{{ a.actor_url }}">
|
||||||
<button type="submit" class="text-sm border border-stone-300 rounded px-3 py-1 hover:bg-stone-100">
|
<button type="submit" class="text-sm border border-stone-300 rounded px-3 py-1 hover:bg-stone-100">
|
||||||
Unfollow
|
Unfollow
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
{% elif list_type == "followers" %}
|
{% else %}
|
||||||
{% if a.actor_url in followed_urls %}
|
<form method="post" action="{{ url_for('social.follow') }}"
|
||||||
<form method="post" action="{{ url_for('social.unfollow') }}">
|
hx-post="{{ url_for('social.follow') }}"
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
hx-target="closest article"
|
||||||
<input type="hidden" name="actor_url" value="{{ a.actor_url }}">
|
hx-swap="outerHTML">
|
||||||
<button type="submit" class="text-sm border border-stone-300 rounded px-3 py-1 hover:bg-stone-100">
|
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||||
Unfollow
|
<input type="hidden" name="actor_url" value="{{ a.actor_url }}">
|
||||||
</button>
|
<button type="submit" class="text-sm bg-stone-800 text-white rounded px-3 py-1 hover:bg-stone-700">
|
||||||
</form>
|
Follow Back
|
||||||
{% else %}
|
</button>
|
||||||
<form method="post" action="{{ url_for('social.follow') }}">
|
</form>
|
||||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
|
||||||
<input type="hidden" name="actor_url" value="{{ a.actor_url }}">
|
|
||||||
<button type="submit" class="text-sm bg-stone-800 text-white rounded px-3 py-1 hover:bg-stone-700">
|
|
||||||
Follow Back
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
{% endif %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user