Changeset ef1853c in Klonkt for src/services


Ignore:
Timestamp:
07/26/2026 09:52:24 AM (6 weeks ago)
Author:
Robin Genis <roboburr@…>
Branches:
main
Children:
42e7616
Parents:
3597763
Message:

Web: custom-emoji ook in messages + threads (Shaer-pariteit)

Na de nieuwsfeed nu ook de andere note-surfaces: messages (msg-item) en
thread-replies (fedi-node) renderen custom-emoji's in de content en in de
auteur-naam. De emoji-tags werden voor replies nog niet bewaard; nu vangt
ap_interactions ze (emoji_json = content-emoji uit o.tag/child.tag,
actor_emoji_json = naam-emoji uit actorInfo) op inbound reply, like/boost en de
thread-crawl, en getNotifications/getInteractions serveren ze mee.

De .emoji-CSS staat nu globaal in shared-styles (was news-only), zodat alle
surfaces 'm delen.

Changed files:
src/config/database.js

  • ap_interactions.emoji_json + actor_emoji_json kolommen

src/services/ActivityPubService.js

  • INSERT ap_interactions + 3 callers (reply/like-boost/thread) vullen de emoji-kolommen
  • emojiJsonOf() helper
  • _listI + getNotifications SELECT en getInteractions-node geven emoji mee

src/views/partials/msg-item.ejs

  • naam + content via emojiName/emojiHtml

src/views/partials/fedi-node.ejs

  • auteur-naam + content via emojiName/emojiHtml

src/views/partials/shared-styles.ejs

  • globale img.emoji-regels (inline, geen media-styling)

src/views/pages/news.ejs

  • dubbele img.emoji-regels weg (nu globaal)

remarks: 187 tests groen. Visueel geverifieerd via standalone render van msg-item
+ fedi-node. Nieuwe replies vangen emoji direct; oude rijen niet (geen self-heal).
Quote-in-replies en de Cirkel-tegel-titels bewust nog niet meegenomen.

-robo
Co-Authored-By: Claude Opus 4.8 <noreply@…>

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r3597763 ref1853c  
    825825function iStmts() {
    826826  if (!_insI) {
    827     _insI = db.prepare('INSERT OR IGNORE INTO ap_interactions (kind, post_id, object_uri, actor_uri, actor_name, actor_handle, actor_url, actor_icon, content, published, parent_uri, visibility, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)');
     827    _insI = db.prepare('INSERT OR IGNORE INTO ap_interactions (kind, post_id, object_uri, actor_uri, actor_name, actor_handle, actor_url, actor_icon, content, published, parent_uri, visibility, emoji_json, actor_emoji_json, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)');
    828828    _delLA = db.prepare('DELETE FROM ap_interactions WHERE kind = ? AND post_id = ? AND actor_uri = ?');
    829829    _delReply = db.prepare("DELETE FROM ap_interactions WHERE kind = 'reply' AND object_uri = ?");
    830     _listI = db.prepare('SELECT id, kind, object_uri, parent_uri, actor_uri, actor_name, actor_handle, actor_url, actor_icon, content, published, created_at, acted_boost, acted_like, visibility FROM ap_interactions WHERE post_id = ? ORDER BY created_at ASC');
     830    _listI = db.prepare('SELECT id, kind, object_uri, parent_uri, actor_uri, actor_name, actor_handle, actor_url, actor_icon, content, published, created_at, acted_boost, acted_like, visibility, emoji_json, actor_emoji_json FROM ap_interactions WHERE post_id = ? ORDER BY created_at ASC');
    831831    _getI = db.prepare('SELECT * FROM ap_interactions WHERE id = ?');
    832832    _insO = db.prepare('INSERT INTO ap_outbox (id, site_slug, post_id, post_slug, in_reply_to, to_actor, to_handle, content, language, attachments, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,CURRENT_TIMESTAMP)');
     
    945945      actor_name: r.actor_name, actor_handle: r.actor_handle, actor_url: r.actor_url,
    946946      actor_icon: r.actor_icon, content: stripLeadingMentions(r.content), created_at: r.published || r.created_at,
     947      emoji_json: r.emoji_json, actor_emoji_json: r.actor_emoji_json,   // FEP-9098 (thread render)
    947948      acted_boost: !!r.acted_boost, acted_like: !!r.acted_like,
    948949      children: [],
     
    15121513      const html = HtmlSanitizerService.sanitize(o.content || '');
    15131514      if (isRejectedObject(o.id)) { console.log('[AP] reply skipped (tombstoned)', o.id); return 202; }
    1514       iStmts().ins.run('reply', tgt.post_id, o.id || '', actorUri, ai.name, ai.handle, ai.url, ai.icon, html, o.published || null, tgt.parent_uri, noteVisibility(o));
     1515      iStmts().ins.run('reply', tgt.post_id, o.id || '', actorUri, ai.name, ai.handle, ai.url, ai.icon, html, o.published || null, tgt.parent_uri, noteVisibility(o), extractEmojiTags(o.tag), emojiJsonOf(ai.emojis));
    15151516      console.log('[AP] reply', actorUri, '→', tgt.post_id);
    15161517      {
     
    16571658      }
    16581659      const ai = actorInfo(await resolveActor(actorUri), actorUri);
    1659       iStmts().ins.run(type.toLowerCase(), pid, '', actorUri, ai.name, ai.handle, ai.url, ai.icon, null, null, null, noteVisibility(act));
     1660      iStmts().ins.run(type.toLowerCase(), pid, '', actorUri, ai.name, ai.handle, ai.url, ai.icon, null, null, null, noteVisibility(act), null, emojiJsonOf(ai.emojis));
    16601661      console.log('[AP]', type === 'Like' ? 'like' : 'boost', actorUri, '→', pid);
    16611662      {
     
    27072708}
    27082709
     2710// A display-name emoji map (actorInfo().emojis) → JSON to store, or null.
     2711function emojiJsonOf(map) { return (map && Object.keys(map).length) ? JSON.stringify(map) : null; }
     2712
    27092713// ── Cirkel = posts from the accounts you auto-boost ("feature an artist") ──
    27102714let _abCount, _cirkelPosts, _cirkelMembers;
     
    29963000        const html = HtmlSanitizerService.sanitize(child.content || '');
    29973001        // The child replies to `note` by construction (it's in note's replies collection).
    2998         try { iStmts().ins.run('reply', postId, child.id, actorUri, ai.name, ai.handle, ai.url, ai.icon, html, child.published || null, note.id || noteUri, noteVisibility(child)); added++; } catch { /* ignore */ }
     3002        try { iStmts().ins.run('reply', postId, child.id, actorUri, ai.name, ai.handle, ai.url, ai.icon, html, child.published || null, note.id || noteUri, noteVisibility(child), extractEmojiTags(child.tag), emojiJsonOf(ai.emojis)); added++; } catch { /* ignore */ }
    29993003        nextFrontier.push(child.id); // expand this reply's own replies next depth
    30003004      }
     
    33093313    const rows = db.prepare(`
    33103314      SELECT i.kind, i.actor_name, i.actor_handle, i.actor_url, i.actor_icon, i.content, i.created_at, i.visibility,
     3315             i.emoji_json, i.actor_emoji_json,
    33113316             p.slug AS post_slug, p.title AS post_title
    33123317      FROM ap_interactions i LEFT JOIN posts p ON p.id = i.post_id
     
    33173322      type: r.kind, name: r.actor_name, handle: r.actor_handle, url: r.actor_url, icon: r.actor_icon,
    33183323      content: stripLeadingMentions(r.content), post_slug: r.post_slug, post_title: r.post_title, created_at: r.created_at,
     3324      emoji_json: r.emoji_json, actor_emoji_json: r.actor_emoji_json,   // FEP-9098 (messages render)
    33193325      // followers/direct = a private message to the owner (not on the public thread) → 🔒 in Messages
    33203326      visibility: r.visibility || 'public',
Note: See TracChangeset for help on using the changeset viewer.