mirror of
https://github.com/svemagie/indiekit-endpoint-activitypub.git
synced 2026-04-02 15:44:58 +02:00
fix: ensure attachment is always an array for Mastodon compatibility
Fedify's JSON-LD compaction collapses single-element arrays to plain objects. Mastodon checks `attachment.is_a?(Array)` and silently skips non-array values, causing profile links to never display. Also adds profile links section to the my-profile admin page and fixes rel=me on the public profile page for bidirectional verification.
This commit is contained in:
@@ -1281,6 +1281,45 @@
|
|||||||
.ap-my-profile__bio .invisible { display: none; }
|
.ap-my-profile__bio .invisible { display: none; }
|
||||||
.ap-my-profile__bio .ellipsis::after { content: "…"; }
|
.ap-my-profile__bio .ellipsis::after { content: "…"; }
|
||||||
|
|
||||||
|
.ap-my-profile__fields {
|
||||||
|
border: var(--border-width-thin) solid var(--color-outline);
|
||||||
|
border-radius: var(--border-radius-small);
|
||||||
|
margin: var(--space-s) 0;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-my-profile__field {
|
||||||
|
border-bottom: var(--border-width-thin) solid var(--color-outline);
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 120px 1fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-my-profile__field:last-child {
|
||||||
|
border-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-my-profile__field-name {
|
||||||
|
background: var(--color-offset);
|
||||||
|
color: var(--color-on-offset);
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
font-weight: 600;
|
||||||
|
padding: var(--space-xs) var(--space-s);
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.03em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-my-profile__field-value {
|
||||||
|
font-size: var(--font-size-s);
|
||||||
|
overflow: hidden;
|
||||||
|
padding: var(--space-xs) var(--space-s);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ap-my-profile__field-value a {
|
||||||
|
color: var(--color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
.ap-my-profile__stats {
|
.ap-my-profile__stats {
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: var(--space-m);
|
gap: var(--space-m);
|
||||||
|
|||||||
@@ -89,6 +89,14 @@ async function sendFedifyResponse(res, response, request) {
|
|||||||
if (json.endpoints?.type) {
|
if (json.endpoints?.type) {
|
||||||
delete json.endpoints.type;
|
delete json.endpoints.type;
|
||||||
}
|
}
|
||||||
|
// WORKAROUND: Fedify's JSON-LD compaction collapses single-element
|
||||||
|
// arrays to a plain object. Mastodon's update_account_fields checks
|
||||||
|
// `attachment.is_a?(Array)` and skips if it's not an array, so
|
||||||
|
// profile links/PropertyValues are silently ignored.
|
||||||
|
// Force `attachment` to always be an array for Mastodon compatibility.
|
||||||
|
if (json.attachment && !Array.isArray(json.attachment)) {
|
||||||
|
json.attachment = [json.attachment];
|
||||||
|
}
|
||||||
const patched = JSON.stringify(json);
|
const patched = JSON.stringify(json);
|
||||||
res.setHeader("content-length", Buffer.byteLength(patched));
|
res.setHeader("content-length", Buffer.byteLength(patched));
|
||||||
res.end(patched);
|
res.end(patched);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@rmdes/indiekit-endpoint-activitypub",
|
"name": "@rmdes/indiekit-endpoint-activitypub",
|
||||||
"version": "2.0.20",
|
"version": "2.0.21",
|
||||||
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
|
"description": "ActivityPub federation endpoint for Indiekit via Fedify. Adds full fediverse support: actor, inbox, outbox, followers, following, syndication, and Mastodon migration.",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"indiekit",
|
"indiekit",
|
||||||
|
|||||||
@@ -26,6 +26,23 @@
|
|||||||
{% if profile.summary %}
|
{% if profile.summary %}
|
||||||
<div class="ap-my-profile__bio">{{ profile.summary | safe }}</div>
|
<div class="ap-my-profile__bio">{{ profile.summary | safe }}</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if profile.attachments and profile.attachments.length > 0 %}
|
||||||
|
<dl class="ap-my-profile__fields">
|
||||||
|
{% for field in profile.attachments %}
|
||||||
|
<div class="ap-my-profile__field">
|
||||||
|
<dt class="ap-my-profile__field-name">{{ field.name }}</dt>
|
||||||
|
<dd class="ap-my-profile__field-value">
|
||||||
|
{% if field.value and (field.value.startsWith("http://") or field.value.startsWith("https://")) %}
|
||||||
|
<a href="{{ field.value }}" rel="me noopener" target="_blank">{{ field.value | replace("https://", "") | replace("http://", "") }}</a>
|
||||||
|
{% else %}
|
||||||
|
{{ field.value }}
|
||||||
|
{% endif %}
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
</dl>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ap-my-profile__stats">
|
<div class="ap-my-profile__stats">
|
||||||
|
|||||||
@@ -480,7 +480,7 @@
|
|||||||
<dt class="ap-pub__field-name">{{ field.name }}</dt>
|
<dt class="ap-pub__field-name">{{ field.name }}</dt>
|
||||||
<dd class="ap-pub__field-value">
|
<dd class="ap-pub__field-value">
|
||||||
{% if field.value and (field.value.startsWith("http://") or field.value.startsWith("https://")) %}
|
{% if field.value and (field.value.startsWith("http://") or field.value.startsWith("https://")) %}
|
||||||
<a href="{{ field.value }}" rel="noopener nofollow" target="_blank">{{ field.value | replace("https://", "") | replace("http://", "") }}</a>
|
<a href="{{ field.value }}" rel="me noopener" target="_blank">{{ field.value | replace("https://", "") | replace("http://", "") }}</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
{{ field.value }}
|
{{ field.value }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user