Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/services/ActivityPubService.js

    r4f19322 rf59a46c  
    280280 * Funkwhale hoeft te weten.
    281281 */
    282 /**
    283  * De waarschuwingstekst van een object, of niets.
    284  *
    285  * `summary` IS in AS2 een SAMENVATTING -- "a natural language summarization of
    286  * the object". Dat Mastodon dat veld hergebruikt als waarschuwing is Mastodons
    287  * conventie, en die zet er `sensitive` bij. Zonder `sensitive` is een summary
    288  * dus gewoon een samenvatting.
    289  *
    290  * WordPress + ActivityPub stuurt daar de EXCERPT van een artikel in, netjes
    291  * afgekapt voor Mastodon. Wij lazen dat als waarschuwing en verborgen de post
    292  * daarmee achter zijn eigen eerste alinea (Barts melding, 13-8:
    293  * europeanpirates.eu). Niemand krijgt dan te zien wat er staat, en de
    294  * waarschuwing waarschuwt nergens voor.
    295  */
    296 export function contentWarning(o) {
    297   if (!o || !o.sensitive) return null;
    298   const s = typeof o.summary === 'string' ? o.summary.trim() : '';
    299   return s || null;
    300 }
    301 
    302282export function timelineFields(o) {
    303283  // De hoes: een `image` op het object. Bij een Note alleen als terugval (daar
     
    328308  }
    329309
    330   // Een ARTIKEL heeft een titel, en die is het eerste wat je wilt zien. Zonder
    331   // dit kwam een WordPress-post binnen als kale body: de titel zit in `name` en
    332   // die gooiden we weg, terwijl de excerpt in `summary` ten onrechte als
    333   // waarschuwing dienstdeed. Nu allebei goed -- en dit is dezelfde greep die
    334   // resolveRemoteNote al doet voor niet-Note-objecten, dus de tijdlijn en het
    335   // antwoordpad zeggen eindelijk hetzelfde.
    336   if (o.type && o.type !== 'Note' && typeof o.name === 'string' && o.name.trim()) {
    337     const kop = `<p><strong>${HtmlSanitizerService.escape ? HtmlSanitizerService.escape(o.name) : o.name}</strong></p>`;
    338     const atts = mediaFromNote(o);
    339     const pagina = pickLink(o.url, (mt) => !mt || /html/i.test(mt));
    340     return {
    341       html: HtmlSanitizerService.sanitize(kop + (o.content || '')),
    342       atts,
    343       url: pagina ? pagina.href : null,
    344     };
    345   }
    346 
    347   // Note / Question -- ongewijzigd gedrag.
     310  // Note / Article / Question -- ongewijzigd gedrag.
    348311  const atts = (Array.isArray(o.attachment) ? o.attachment : [])
    349312    .map((a) => ({ url: safeUrl(a && a.url), type: (a && a.mediaType) || '' }))
     
    25002463        // the timeline).
    25012464        for (const s of subs) {
    2502           tlStmts().ins.run(o.id, s.slug, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, _url, o.published || null, media, o.sensitive ? 1 : 0, contentWarning(o));
     2465          tlStmts().ins.run(o.id, s.slug, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, _url, o.published || null, media, o.sensitive ? 1 : 0, o.summary || null);
    25032466          // FEP-633c ยง2.2: register the ward hint on the stored object (no action yet).
    25042467          if (Guardianship.objectHasGuardians(o)) { try { db.prepare('UPDATE ap_timeline SET has_guardians = 1 WHERE id = ? AND slug = ?').run(o.id, s.slug); } catch { /* ignore */ } }
     
    26522615        // post would keep linking to the old, now-dead URL.
    26532616        const r = db.prepare('UPDATE ap_timeline SET content = ?, media_json = ?, nsfw = ?, cw = ?, url = COALESCE(?, url) WHERE id = ? AND author_uri = ?')
    2654           .run(html, media, o.sensitive ? 1 : 0, contentWarning(o), o.url || null, o.id, claimedActor);
     2617          .run(html, media, o.sensitive ? 1 : 0, o.summary || null, o.url || null, o.id, claimedActor);
    26552618        if (r.changes) console.log('[AP] timeline update', claimedActor, 'โ†’', o.id);
    26562619        // A poll's Update carries the fresh vote counts / closed state. Refresh per-row so each
     
    27162679            // have the note (e.g. we also follow the author), keep it and DON'T relabel it.
    27172680            let inserted = false;
    2718             try { const r = tlStmts().ins.run(bn.id, s.slug, origUri || '', oai.name, oai.handle, oai.icon, oai.url, html, bn.url || null, new Date().toISOString(), media, bn.sensitive ? 1 : 0, contentWarning(bn)); inserted = r.changes > 0; } catch { /* ignore */ }
     2681            try { const r = tlStmts().ins.run(bn.id, s.slug, origUri || '', oai.name, oai.handle, oai.icon, oai.url, html, bn.url || null, new Date().toISOString(), media, bn.sensitive ? 1 : 0, bn.summary || null); inserted = r.changes > 0; } catch { /* ignore */ }
    27192682            if (inserted) { try { db.prepare('UPDATE ap_timeline SET reblog_name = ?, reblog_handle = ?, reblog_icon = ?, reblog_emoji_json = ? WHERE slug = ? AND id = ?').run(booster.name, booster.handle, booster.icon, (booster.emojis && Object.keys(booster.emojis).length) ? JSON.stringify(booster.emojis) : null, s.slug, bn.id); } catch { /* ignore */ } }
    27202683            storeAuthorEmoji(bn.id, s.slug, oai);   // custom-emoji display name for the byline
     
    38793842    published: typeof o.published === 'string' ? o.published : undefined,
    38803843    sensitive: !!o.sensitive,
    3881     summary: (contentWarning(o) || '').slice(0, 500) || undefined,
     3844    summary: typeof o.summary === 'string' ? o.summary.slice(0, 500) : undefined,
    38823845    attachment: (() => {
    38833846      const arr = Array.isArray(o.attachment) ? o.attachment : (o.attachment ? [o.attachment] : []);
     
    39953958    content: HtmlSanitizerService.sanitize(rawHtml),       // full, sanitized
    39963959    sensitive: !!note.sensitive,                            // remote CW โ†’ blur in the Cirkel
    3997     cw: contentWarning(note) || '',
     3960    cw: note.summary || '',
    39983961    images,
    39993962    // Full typed media (incl. video/mp4) for the timeline cache. `images` above is
     
    50254988// during a flux window, e.g. a fleet-wide update), and drops notes that are gone
    50264989// (404/410). Bump SELFHEAL_VERSION only on a release that warrants a re-sync.
    5027 const SELFHEAL_VERSION = 22; // v22: summary is pas een waarschuwing MET sensitive, en een artikel houdt zijn titel
     4990const SELFHEAL_VERSION = 21; // v21: drop direct notes (๐Ÿ›Ÿ help requests, waves) that were cached as timeline posts
    50284991async function fetchNoteAP(url) {
    50294992  try {
     
    54125375      const poll = parsePoll(o); // a Question (poll) โ†’ carry its options/counts on backfill too
    54135376      try {
    5414         const r = tlStmts().ins.run(o.id, slug, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.url || null, o.published || null, mediaFromNote(o), o.sensitive ? 1 : 0, contentWarning(o));
     5377        const r = tlStmts().ins.run(o.id, slug, actorUri, ai.name, ai.handle, ai.icon, ai.url, html, o.url || null, o.published || null, mediaFromNote(o), o.sensitive ? 1 : 0, o.summary || null);
    54155378        if (r && r.changes > 0) added++;
    54165379        // FEP-9098: keep custom-emoji tags from backfilled posts too.
     
    55715534        if (note === 404) { db.prepare('DELETE FROM ap_timeline WHERE id = ?').run(r.id); healed++; continue; }
    55725535        if (!note || typeof note !== 'object') { failed++; continue; } // origin unreachable right now
    5573         // Door DEZELFDE bouwer als de innamekant (v22). Hij bouwde de inhoud
    5574         // hier zelf op, en daardoor miste een gerepareerde rij precies wat de
    5575         // inname wel doet -- de titel van een artikel bijvoorbeeld. Een
    5576         // zelfherstel dat een andere vorm oplevert dan de inname repareert naar
    5577         // een derde toestand.
    5578         const velden = timelineFields(note);
    5579         const html = velden.html;
    5580         const media = velden.atts.length ? JSON.stringify(velden.atts) : mediaFromNote(note);
     5536        const html = HtmlSanitizerService.sanitize(note.content || '');
     5537        const media = mediaFromNote(note);
    55815538        const nsfw = note.sensitive ? 1 : 0;   // re-sync NSFW/sensitive + CW onto already-cached posts
    5582         const cw = contentWarning(note);
     5539        const cw = note.summary || null;
    55835540        const url = note.url || null;          // re-sync the human url (catches a remote slug rename)
    55845541        const emoji = extractEmojiTags(note.tag);   // FEP-9098: re-capture custom-emoji tags (v8)
     
    66336590  getInteractions, getInteractionById, setInteractionBoosted, setInteractionLiked, buildReplyNote, getOutboxNote, getSentNotes, deliverReply, resolveRemoteNote, noteAudience, mayReadNote,
    66346591  listOutbox, deliverOutboxDelete, deliverOutboxUpdate, deliverDirectNote,
    6635   webfingerResolve, followActor, resolveRemoteActor, unfollowActor, handleMoveInbox, moveAccount, listFollowing, setAutoBoost, backfillFromOutbox, getTimeline, timelineRowsByIds, contentWarning, getDirectMessages, readMarkers, markRead, unreadPerConversation, messageRowsByUri, replyRowsByUri, conversationHeads, conversationHistory, isoStamp, timelineAttachments, timelineEmojis, timelineObjectLinks, timelineQuote, timelineEmbed, applyQuoteProps, deliverToActor, sendInteraction, voteOnPoll, voteOnRemotePoll,
     6592  webfingerResolve, followActor, resolveRemoteActor, unfollowActor, handleMoveInbox, moveAccount, listFollowing, setAutoBoost, backfillFromOutbox, getTimeline, timelineRowsByIds, getDirectMessages, readMarkers, markRead, unreadPerConversation, messageRowsByUri, replyRowsByUri, conversationHeads, conversationHistory, isoStamp, timelineAttachments, timelineEmojis, timelineObjectLinks, timelineQuote, timelineEmbed, applyQuoteProps, deliverToActor, sendInteraction, voteOnPoll, voteOnRemotePoll,
    66366593  acceptGatedFollow, rejectGatedFollow, isWardGuardian, outboxAudience, sendFollowDecision,
    66376594  gateOutgoingFollow, performApprovedFollow, recordGuardianEvent, listGuardianEvents, GUARDIAN_EVENT_KEEP,
Note: See TracChangeset for help on using the changeset viewer.