Changes in src/routes/posts.js [fb9a8ad:72ec6a4] in Klonkt


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    rfb9a8ad r72ec6a4  
    256256
    257257  renderPage(req, res, 'pages/post-edit', {
    258     // post-edit neemt de playlist-editor op.
    259     pageJs: 'post-edit playlist-editor',
    260258    post: {
    261259      id: uuid(),
     
    797795  }
    798796  renderPage(req, res, 'pages/authorize-interaction', {
    799     pageJs: 'authorize-interaction',
    800797    pageTitleKey: 'fedi.remote_interact', // i18n: was hardcoded Dutch on non-NL sites
    801798    bodyClass: 'on-special',
     
    809806    liked: !!req.query.liked,
    810807    boosted: !!req.query.boosted,
    811     reacted: (site && uri) ? ActivityPubService.getReaction(site.slug, uri) : { liked: false, boosted: false },
     808    reacted: (site && uri) ? ActivityPubService.getMyReactions(site.slug, uri) : { liked: false, boosted: false },
    812809    siteTitle: site ? site.title : '',
    813810  });
     
    842839  let on = false;
    843840  if (site && uri) {
    844     on = !ActivityPubService.getReaction(site.slug, uri).liked;
     841    on = !ActivityPubService.getMyReactions(site.slug, uri).liked;
    845842    ActivityPubService.resolveRemoteNote(uri)
    846843      .then((note) => note && ActivityPubService.sendInteraction(site, on ? 'like' : 'unlike', note.object_uri || uri, note.actor_uri))
    847844      .catch((e) => console.warn('[AP] remote like failed:', e.message));
    848     // Eén schrijfpad (shaer-9e9): tussentabel + afgeleide vlag.
    849     ActivityPubService.setReaction(site.slug, uri, 'like', on);
     845    ActivityPubService.setMyReaction(site.slug, uri, 'like', on);
    850846  }
    851847  if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
     
    860856  let on = false;
    861857  if (site && uri) {
    862     on = !ActivityPubService.getReaction(site.slug, uri).boosted;
     858    on = !ActivityPubService.getMyReactions(site.slug, uri).boosted;
    863859    ActivityPubService.resolveRemoteNote(uri)
    864860      .then((note) => {
     
    866862        const id = note.object_uri || uri;
    867863        return Promise.resolve(ActivityPubService.sendInteraction(site, on ? 'boost' : 'unboost', id, note.actor_uri))
    868           // De note gaat mee: een boost zet niet alleen een vlag maar trekt de
    869           // post je tijdlijn in, ook als je de auteur niet volgt, zodat hij in
    870           // de Cirkel verschijnt.
    871           .then(() => ActivityPubService.setReaction(site.slug, uri, 'boost', on, { flagUri: id, note: on ? note : null }));
     864          // Boost → store the post in the timeline (even if you don't follow the author) so it
     865          // surfaces in the Cirkel; unboost → just clear the flag.
     866          .then(() => on ? ActivityPubService.upsertBoostedNote(site.slug, note) : ActivityPubService.unmarkBoosted(site.slug, id));
    872867      })
    873868      .catch((e) => console.warn('[AP] remote boost failed:', e.message));
    874     // Meteen zetten, zodat de knop klopt voordat de resolve terug is. Via
    875     // setReaction en niet via setMyReaction: ook dit korte moment mag geen
    876     // halve schrijfactie zijn. De resolve hierboven werkt hem daarna bij met de
    877     // note, zodat de post ook in je tijdlijn belandt.
    878     ActivityPubService.setReaction(site.slug, uri, 'boost', on);
     869    ActivityPubService.setMyReaction(site.slug, uri, 'boost', on);
    879870  }
    880871  if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
     
    939930    : []).filter((o) => o['shaer:ward'] === gMe && o['shaer:needsMyAccept']);
    940931  renderPage(req, res, 'pages/messages', {
    941     pageTitleKey: 'msg.title', bodyClass: 'on-special', pageJs: 'messages', items, seenAt,
     932    pageTitleKey: 'msg.title', bodyClass: 'on-special', items, seenAt,
    942933    hasMore, nextOffset: offset + FEED_PAGE, moreBase, guardianOffers,
    943934    success: req.query.success || null, error: req.query.error || null,
     
    974965  } catch { /* fall through */ }
    975966  res.redirect(back + '?error=quickreply');
    976 });
    977 
    978 // Antwoorden vanuit een gesprek in Berichten. Twee paden, en welke het wordt
    979 // bepaalt de draad zelf (zie groupConversations → replyTo):
    980 //   - hangt de draad aan een post van jou, dan is dit een gewone reply op het
    981 //     nieuwste ontvangen bericht erin: deliverReply, publiek zoals de thread;
    982 //   - hangt hij aan een persoon, dan is het een direct bericht terug.
    983 // Rijk in beide gevallen: `content` is de HTML uit de reply-editor, `text` de
    984 // platte versie die de editor er altijd bij levert (en die het no-JS-formulier
    985 // als enige stuurt).
    986 router.post('/messages/reply', requireSiteManager, async (req, res) => {
    987   const site = res.locals.site;
    988   const back = `${res.locals.siteUrlBase || ''}/messages`;
    989   if (!site) return res.status(404).send('Site required');
    990   const text = String(req.body.text || '');
    991   const html = String(req.body.content || '');
    992   let attachments = [];
    993   try { attachments = JSON.parse(req.body.attachments || '[]'); } catch { /* geen media */ }
    994   let mentions;
    995   try { if (req.body.mentions !== undefined) mentions = JSON.parse(req.body.mentions || '[]'); } catch { mentions = undefined; }
    996   const language = String(req.body.language || '');
    997   // Leeg is leeg: een bericht zonder tekst EN zonder media is geen bericht.
    998   if (!text.trim() && !html.trim() && !attachments.length) return res.redirect(back + '?error=reply_empty');
    999 
    1000   const interactionId = parseInt(req.body.interaction_id, 10) || 0;
    1001   const postSlug = String(req.body.post_slug || '');
    1002   const toActor = String(req.body.to || '');
    1003   try {
    1004     if (interactionId && postSlug) {
    1005       const post = db.prepare('SELECT id, slug FROM posts WHERE site_id = ? AND slug = ?').get(site.id, postSlug);
    1006       const parent = ActivityPubService.getInteractionById(interactionId);
    1007       // De parent MOET bij deze post horen: anders zou een gemanipuleerd
    1008       // formulier een antwoord onder andermans draad kunnen hangen.
    1009       if (!post || !parent || parent.post_id !== post.id) return res.redirect(back + '?error=reply_target');
    1010       await ActivityPubService.deliverReply(site, {
    1011         postId: post.id, postSlug: post.slug, parent, text, html, attachments, mentions, language,
    1012       });
    1013     } else if (/^https?:\/\//i.test(toActor)) {
    1014       const r = await Guardianship.deliverDirectNote(site, { recipients: [toActor], text, html, language, attachments });
    1015       if (!r) return res.redirect(back + '?error=reply_failed');
    1016     } else {
    1017       return res.redirect(back + '?error=reply_target');
    1018     }
    1019   } catch (e) {
    1020     console.warn('[AP] reply from Berichten failed:', e.message);
    1021     return res.redirect(back + '?error=reply_failed');
    1022   }
    1023   res.redirect(back + '?success=reply_sent');
    1024967});
    1025968
     
    11961139  }
    11971140  renderPage(req, res, 'pages/news', {
    1198     pageJs: 'news',
    11991141    pageTitle: 'News', bodyClass: 'on-special',
    12001142    timeline, hasMore, nextOffset: offset + FEED_PAGE, moreBase,
     
    12871229  let on = false;
    12881230  if (site && note) {
    1289     on = !ActivityPubService.getReaction(site.slug, note).liked;
     1231    on = !ActivityPubService.getTimelineReaction(site.slug, note).liked;
    12901232    try { await ActivityPubService.sendInteraction(site, on ? 'like' : 'unlike', note, (req.body.author || '').toString()); } catch (e) { /* ignore */ }
    1291     ActivityPubService.setReaction(site.slug, note, 'like', on);
     1233    if (on) ActivityPubService.markLiked(site.slug, note); else ActivityPubService.unmarkLiked(site.slug, note);
    12921234  }
    12931235  if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
     
    13011243  let on = false;
    13021244  if (site && note) {
    1303     on = !ActivityPubService.getReaction(site.slug, note).boosted;
     1245    on = !ActivityPubService.getTimelineReaction(site.slug, note).boosted;
    13041246    try { await ActivityPubService.sendInteraction(site, on ? 'boost' : 'unboost', note, (req.body.author || '').toString()); } catch (e) { /* ignore */ }
    1305     ActivityPubService.setReaction(site.slug, note, 'boost', on); // instant UI state
    13061247    if (on) {
     1248      ActivityPubService.markBoosted(site.slug, note); // instant UI state
    13071249      // Fire-and-forget: re-resolve the note so the cached row is refreshed
    13081250      // (cover/content) — boosting again heals a stale copy from EVERY boost
    13091251      // path, not just the interact page.
    13101252      ActivityPubService.resolveRemoteNote(note)
    1311         .then((n) => { if (n) ActivityPubService.setReaction(site.slug, note, 'boost', true, { note: n }); })
     1253        .then((n) => { if (n) ActivityPubService.upsertBoostedNote(site.slug, n); })
    13121254        .catch(() => { /* best-effort */ });
     1255    } else {
     1256      ActivityPubService.unmarkBoosted(site.slug, note);
    13131257    }
    13141258  }
     
    13941338    const { newerPost, olderPost } = postNeighbors(site, post);
    13951339    return renderPage(req, res, 'pages/paid-gate', {
    1396     pageJs: 'paid-gate',
    13971340      pageTitle: post.title || 'Voor supporters',
    13981341      bodyClass: 'on-special',
     
    15111454
    15121455  renderPage(req, res, 'pages/post', {
    1513     pageJs: 'post',
    15141456    post,
    15151457    poll: ActivityPubService.ownPollView(post),
     
    15631505  const kind = req.body.kind === 'boost' ? 'boost' : 'like';
    15641506  if (parent && parent.post_id === post.id && parent.object_uri) {
    1565     // Toggle: react, or retract it (Undo Announce / Undo Like) if already on.
    1566     // De stand komt uit dezelfde bron als de knop die je zag; leest de toggle uit
    1567     // de kolom en de knop uit de tussentabel, dan draait een divergentie de
    1568     // richting om en stuur je een Undo voor iets dat nooit is verstuurd.
    1569     const ik = ActivityPubService.getReaction(site.slug, parent.object_uri);
    1570     const on = kind === 'boost' ? !ik.boosted : !ik.liked;
    1571     ActivityPubService.sendInteraction(site, on ? kind : `un${kind}`, parent.object_uri, parent.actor_uri)
    1572       .catch((e) => console.warn('[AP] reaction failed:', e.message));
    1573     // De tussentabel is de waarheid (shaer-ipb), gesleuteld op object_uri -- net
    1574     // als de Like die hierboven de fediverse in gaat. acted_* blijft voorlopig
    1575     // als afgeleide meelopen, hetzelfde vangnet dat ap_timeline.liked na
    1576     // shaer-9e9 is: pas weghalen als deze migratie een release heeft ingelopen.
    1577     ActivityPubService.setReaction(site.slug, parent.object_uri, kind, on);
    1578     if (kind === 'boost') ActivityPubService.setInteractionBoosted(parent.id, on);
    1579     else ActivityPubService.setInteractionLiked(parent.id, on);
     1507    if (kind === 'boost') {
     1508      // Toggle: boost an unboosted comment, or retract it (Undo Announce) if already boosted.
     1509      const on = !parent.acted_boost;
     1510      ActivityPubService.sendInteraction(site, on ? 'boost' : 'unboost', parent.object_uri, parent.actor_uri)
     1511        .catch((e) => console.warn('[AP] reaction failed:', e.message));
     1512      ActivityPubService.setInteractionBoosted(parent.id, on);
     1513    } else {
     1514      // Toggle: like an unliked comment, or un-favourite (Undo Like) if already liked.
     1515      const on = !parent.acted_like;
     1516      ActivityPubService.sendInteraction(site, on ? 'like' : 'unlike', parent.object_uri, parent.actor_uri)
     1517        .catch((e) => console.warn('[AP] reaction failed:', e.message));
     1518      ActivityPubService.setInteractionLiked(parent.id, on);
     1519    }
    15801520  }
    15811521  res.redirect(`${res.locals.siteUrlBase || ''}/${post.slug}#fediverse`);
Note: See TracChangeset for help on using the changeset viewer.