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


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/routes/posts.js

    r72ec6a4 rfb9a8ad  
    256256
    257257  renderPage(req, res, 'pages/post-edit', {
     258    // post-edit neemt de playlist-editor op.
     259    pageJs: 'post-edit playlist-editor',
    258260    post: {
    259261      id: uuid(),
     
    795797  }
    796798  renderPage(req, res, 'pages/authorize-interaction', {
     799    pageJs: 'authorize-interaction',
    797800    pageTitleKey: 'fedi.remote_interact', // i18n: was hardcoded Dutch on non-NL sites
    798801    bodyClass: 'on-special',
     
    806809    liked: !!req.query.liked,
    807810    boosted: !!req.query.boosted,
    808     reacted: (site && uri) ? ActivityPubService.getMyReactions(site.slug, uri) : { liked: false, boosted: false },
     811    reacted: (site && uri) ? ActivityPubService.getReaction(site.slug, uri) : { liked: false, boosted: false },
    809812    siteTitle: site ? site.title : '',
    810813  });
     
    839842  let on = false;
    840843  if (site && uri) {
    841     on = !ActivityPubService.getMyReactions(site.slug, uri).liked;
     844    on = !ActivityPubService.getReaction(site.slug, uri).liked;
    842845    ActivityPubService.resolveRemoteNote(uri)
    843846      .then((note) => note && ActivityPubService.sendInteraction(site, on ? 'like' : 'unlike', note.object_uri || uri, note.actor_uri))
    844847      .catch((e) => console.warn('[AP] remote like failed:', e.message));
    845     ActivityPubService.setMyReaction(site.slug, uri, 'like', on);
     848    // Eén schrijfpad (shaer-9e9): tussentabel + afgeleide vlag.
     849    ActivityPubService.setReaction(site.slug, uri, 'like', on);
    846850  }
    847851  if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
     
    856860  let on = false;
    857861  if (site && uri) {
    858     on = !ActivityPubService.getMyReactions(site.slug, uri).boosted;
     862    on = !ActivityPubService.getReaction(site.slug, uri).boosted;
    859863    ActivityPubService.resolveRemoteNote(uri)
    860864      .then((note) => {
     
    862866        const id = note.object_uri || uri;
    863867        return Promise.resolve(ActivityPubService.sendInteraction(site, on ? 'boost' : 'unboost', id, note.actor_uri))
    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));
     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 }));
    867872      })
    868873      .catch((e) => console.warn('[AP] remote boost failed:', e.message));
    869     ActivityPubService.setMyReaction(site.slug, uri, 'boost', on);
     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);
    870879  }
    871880  if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
     
    930939    : []).filter((o) => o['shaer:ward'] === gMe && o['shaer:needsMyAccept']);
    931940  renderPage(req, res, 'pages/messages', {
    932     pageTitleKey: 'msg.title', bodyClass: 'on-special', items, seenAt,
     941    pageTitleKey: 'msg.title', bodyClass: 'on-special', pageJs: 'messages', items, seenAt,
    933942    hasMore, nextOffset: offset + FEED_PAGE, moreBase, guardianOffers,
    934943    success: req.query.success || null, error: req.query.error || null,
     
    965974  } catch { /* fall through */ }
    966975  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).
     986router.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');
    9671024});
    9681025
     
    11391196  }
    11401197  renderPage(req, res, 'pages/news', {
     1198    pageJs: 'news',
    11411199    pageTitle: 'News', bodyClass: 'on-special',
    11421200    timeline, hasMore, nextOffset: offset + FEED_PAGE, moreBase,
     
    12291287  let on = false;
    12301288  if (site && note) {
    1231     on = !ActivityPubService.getTimelineReaction(site.slug, note).liked;
     1289    on = !ActivityPubService.getReaction(site.slug, note).liked;
    12321290    try { await ActivityPubService.sendInteraction(site, on ? 'like' : 'unlike', note, (req.body.author || '').toString()); } catch (e) { /* ignore */ }
    1233     if (on) ActivityPubService.markLiked(site.slug, note); else ActivityPubService.unmarkLiked(site.slug, note);
     1291    ActivityPubService.setReaction(site.slug, note, 'like', on);
    12341292  }
    12351293  if (req.get('X-Requested-With') === 'fetch') return res.json({ ok: true, on });
     
    12431301  let on = false;
    12441302  if (site && note) {
    1245     on = !ActivityPubService.getTimelineReaction(site.slug, note).boosted;
     1303    on = !ActivityPubService.getReaction(site.slug, note).boosted;
    12461304    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
    12471306    if (on) {
    1248       ActivityPubService.markBoosted(site.slug, note); // instant UI state
    12491307      // Fire-and-forget: re-resolve the note so the cached row is refreshed
    12501308      // (cover/content) — boosting again heals a stale copy from EVERY boost
    12511309      // path, not just the interact page.
    12521310      ActivityPubService.resolveRemoteNote(note)
    1253         .then((n) => { if (n) ActivityPubService.upsertBoostedNote(site.slug, n); })
     1311        .then((n) => { if (n) ActivityPubService.setReaction(site.slug, note, 'boost', true, { note: n }); })
    12541312        .catch(() => { /* best-effort */ });
    1255     } else {
    1256       ActivityPubService.unmarkBoosted(site.slug, note);
    12571313    }
    12581314  }
     
    13381394    const { newerPost, olderPost } = postNeighbors(site, post);
    13391395    return renderPage(req, res, 'pages/paid-gate', {
     1396    pageJs: 'paid-gate',
    13401397      pageTitle: post.title || 'Voor supporters',
    13411398      bodyClass: 'on-special',
     
    14541511
    14551512  renderPage(req, res, 'pages/post', {
     1513    pageJs: 'post',
    14561514    post,
    14571515    poll: ActivityPubService.ownPollView(post),
     
    15051563  const kind = req.body.kind === 'boost' ? 'boost' : 'like';
    15061564  if (parent && parent.post_id === post.id && parent.object_uri) {
    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     }
     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);
    15201580  }
    15211581  res.redirect(`${res.locals.siteUrlBase || ''}/${post.slug}#fediverse`);
Note: See TracChangeset for help on using the changeset viewer.