mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
feat: FEP-8fcf/fe34 compliance, custom emoji, manual follow approval (v2.13.0)
- FEP-8fcf: add syncCollection to Undo(Announce) sendActivity - FEP-fe34: centralized lookupWithSecurity() helper with crossOrigin: "ignore" on all 23 lookupObject call sites - Custom emoji: replaceCustomEmoji() renders :shortcode: as inline <img> in content and actor display names - Manual follow approval: profile toggle, ap_pending_follows collection, approve/reject controllers with federation, pending tab on followers page, follow_request notification type - Coverage audit updated to v2.12.x (overall ~70% → ~82%) Confab-Link: http://localhost:8080/sessions/1f1e729b-0087-499e-a991-f36f46211fe4
This commit is contained in:
@@ -6,19 +6,67 @@
|
||||
{% from "pagination/macro.njk" import pagination with context %}
|
||||
|
||||
{% block content %}
|
||||
{% if followers.length > 0 %}
|
||||
{% for follower in followers %}
|
||||
{{ card({
|
||||
title: follower.name or follower.handle or follower.actorUrl,
|
||||
url: follower.actorUrl,
|
||||
photo: { url: follower.avatar, alt: follower.name } if follower.avatar,
|
||||
description: { text: "@" + follower.handle if follower.handle },
|
||||
published: follower.followedAt
|
||||
}) }}
|
||||
{% endfor %}
|
||||
{# Tab navigation — only show if there are pending requests #}
|
||||
{% if pendingCount > 0 %}
|
||||
{% set followersBase = mountPath + "/admin/followers" %}
|
||||
<nav class="ap-tabs">
|
||||
<a href="{{ followersBase }}" class="ap-tab{% if tab == 'followers' %} ap-tab--active{% endif %}">
|
||||
{{ __("activitypub.followers") }}
|
||||
{% if followerCount %}<span class="ap-tab__count">{{ followerCount }}</span>{% endif %}
|
||||
</a>
|
||||
<a href="{{ followersBase }}?tab=pending" class="ap-tab{% if tab == 'pending' %} ap-tab--active{% endif %}">
|
||||
{{ __("activitypub.pendingFollows") }}
|
||||
<span class="ap-tab__count">{{ pendingCount }}</span>
|
||||
</a>
|
||||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{{ pagination(cursor) if cursor }}
|
||||
{% if tab == "pending" %}
|
||||
{# Pending follow requests #}
|
||||
{% if pendingFollows.length > 0 %}
|
||||
{% for pending in pendingFollows %}
|
||||
<div class="ap-follow-request">
|
||||
{{ card({
|
||||
title: pending.name or pending.handle or pending.actorUrl,
|
||||
url: pending.actorUrl,
|
||||
photo: { url: pending.avatar, alt: pending.name } if pending.avatar,
|
||||
description: { text: "@" + pending.handle if pending.handle }
|
||||
}) }}
|
||||
<div class="ap-follow-request__actions">
|
||||
<form method="post" action="{{ mountPath }}/admin/followers/approve" class="ap-follow-request__form">
|
||||
<input type="hidden" name="_csrf" value="{{ csrfToken }}">
|
||||
<input type="hidden" name="actorUrl" value="{{ pending.actorUrl }}">
|
||||
<button type="submit" class="button">{{ __("activitypub.approve") }}</button>
|
||||
</form>
|
||||
<form method="post" action="{{ mountPath }}/admin/followers/reject" class="ap-follow-request__form">
|
||||
<input type="hidden" name="_csrf" value="{{ csrfToken }}">
|
||||
<input type="hidden" name="actorUrl" value="{{ pending.actorUrl }}">
|
||||
<button type="submit" class="button button--danger">{{ __("activitypub.reject") }}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{{ pagination(cursor) if cursor }}
|
||||
{% else %}
|
||||
{{ prose({ text: __("activitypub.noPendingFollows") }) }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{{ prose({ text: __("activitypub.noFollowers") }) }}
|
||||
{# Accepted followers #}
|
||||
{% if followers.length > 0 %}
|
||||
{% for follower in followers %}
|
||||
{{ card({
|
||||
title: follower.name or follower.handle or follower.actorUrl,
|
||||
url: follower.actorUrl,
|
||||
photo: { url: follower.avatar, alt: follower.name } if follower.avatar,
|
||||
description: { text: "@" + follower.handle if follower.handle },
|
||||
published: follower.followedAt
|
||||
}) }}
|
||||
{% endfor %}
|
||||
|
||||
{{ pagination(cursor) if cursor }}
|
||||
{% else %}
|
||||
{{ prose({ text: __("activitypub.noFollowers") }) }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
{% endif %}
|
||||
<span class="ap-notification__avatar ap-notification__avatar--default" aria-hidden="true">{{ item.actorName[0] | upper if item.actorName else "?" }}</span>
|
||||
<span class="ap-notification__type-badge">
|
||||
{% if item.type == "like" %}❤{% elif item.type == "boost" %}🔁{% elif item.type == "follow" %}👤{% elif item.type == "reply" %}💬{% elif item.type == "mention" %}@{% elif item.type == "dm" %}✉{% elif item.type == "report" %}⚑{% endif %}
|
||||
{% if item.type == "like" %}❤{% elif item.type == "boost" %}🔁{% elif item.type == "follow" or item.type == "follow_request" %}👤{% elif item.type == "reply" %}💬{% elif item.type == "mention" %}@{% elif item.type == "dm" %}✉{% elif item.type == "report" %}⚑{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
{{ __("activitypub.notifications.boostedPost") }}
|
||||
{% elif item.type == "follow" %}
|
||||
{{ __("activitypub.notifications.followedYou") }}
|
||||
{% elif item.type == "follow_request" %}
|
||||
{{ __("activitypub.followRequest") }}
|
||||
{% elif item.type == "reply" %}
|
||||
{{ __("activitypub.notifications.repliedTo") }}
|
||||
{% elif item.type == "mention" %}
|
||||
|
||||
Reference in New Issue
Block a user