Changeset 952baf3 in Klonkt for src/routes/guardian.js
- Timestamp:
- 08/07/2026 05:15:52 PM (5 weeks ago)
- Branches:
- main
- Children:
- ba76bf5
- Parents:
- f85b2c3 (diff), 0d5bd2c (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the(diff)links above to see all the changes relative to each parent. - File:
-
- 1 edited
-
src/routes/guardian.js (modified) (8 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/guardian.js
rf85b2c3 r952baf3 57 57 'prop_line', 'prop_embeds', 'prop_play', 'prop_on', 'prop_off', 58 58 'prop_st_open', 'prop_st_accepted', 'prop_st_rejected', 'prop_st_expired', 59 'panel_guards_far']; 59 'panel_guards_far', 60 // Het gate-paneel per ward (shaer-ahy.1): een rij per gate, met het soort en 61 // de drempel erbij. De namen volgen de catalogus in gated.js. 62 'gate_externalEmbeds', 'gate_externalPlayback', 'gate_follows', 63 'gate_kind_setting', 'gate_kind_perRequest', 'gate_kind_handover', 64 'gate_unknown', 'gate_threshold', 'gate_threshold_unknown', 65 'gate_irreversible', 'gate_waiting', 'gate_blocked', 'gate_propose', 66 // Oppikken en afhandelen van een hulpvraag (shaer-lgo). 67 'help_pick', 'help_close', 'help_picked_by', 'help_handled_by', 'help_handled_note', 68 'help_close_ask', 'help_close_yes', 'help_just_now', 'help_hours', 'help_days', 69 'help_archive', 'help_archive_hide']; 60 70 const s = Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)])); 61 71 s.wave = i18nT(L, 'guardian.wave'); … … 71 81 emoji_json, actor_emoji_json, media_json, quote_json, embed_json 72 82 FROM ap_mentions WHERE slug = ? AND help_request = 1 ORDER BY created_at DESC LIMIT 50` 73 ).all(site.slug).map((h) => ({ 83 ).all(site.slug); 84 // De gedeelde staat in EEN query (shaer-lgo): wie er al op af is en of het is 85 // afgesloten. Per kaart vragen zou hier een N+1 opleveren, en dit is precies 86 // het scherm dat een guardian in een haast openslaat. 87 const helpStaat = Guardianship.help.statusFor(help.map((h) => h.object_uri)); 88 const helpItems = help.map((h) => ({ 74 89 ...h, 90 // Bij twijfel OPEN. Een hulpvraag die er afgehandeld uitziet terwijl hij dat 91 // niet is, is de gevaarlijke fout -- niet andersom. 92 state: helpStaat.get(h.object_uri) || { open: true, pickedUpBy: [], handled: null, ageMs: null }, 75 93 // The dashboard is built in the browser, so it gets the body finished: the 76 94 // same partial de Krant and Berichten use. A 🛟 often carries a screenshot … … 103 121 status: Guardianship.gated.sentStatus(p, Date.now()), 104 122 })), 123 // Alles wat voor dit kind gated is op EEN plek, met per gate het soort en 124 // de drempel (shaer-ahy.1). Losse knoppen lieten een guardian zelf 125 // uitzoeken wat er allemaal geldt; wat niet verstelbaar is stond nergens. 126 gates: wardGates(site.slug, w.other_uri), 105 127 })), 106 128 offers: Guardianship.offersCollection(`${me}/queues/offers`, site.slug, me).orderedItems, … … 113 135 id: r.id, ward: r.ward_uri, proposer: r.proposer, feature: r.feature, value: !!r.value, 114 136 })), 115 help ,137 help: helpItems, 116 138 strings: uiStrings(L), 117 139 }; … … 192 214 const site = siteForUser(req); 193 215 if (!site) return res.status(404).json({ error: 'no_site' }); 216 const L = resolveLang(req); 194 217 ensureWardConnections(site); 195 218 const wardUris = new Set(Guardianship.listWards(site.slug).map((w) => w.other_uri)); … … 209 232 cw: p.cw || null, 210 233 media: p.media_json ? JSON.parse(p.media_json) : [], 234 // Een post van je ward hoort er hetzelfde uit te zien als in de Krant en 235 // in Berichten: dezelfde partial, dus opmaak, media, quote-kaart en 236 // embed. Tot nu toe kreeg de PWA alleen kale content -- een guardian zag 237 // een lege regel waar een foto stond. `content` blijft ernaast staan voor 238 // een client die nog uit de cache draait. 239 body_html: renderNoteBody(p, L), 211 240 })); 212 241 res.json({ items, following: wardUris.size }); … … 319 348 if (!r) return res.status(502).json({ error: 'delivery' }); 320 349 res.json({ ok: true, delivered: r.delivered }); 350 }); 351 352 // ── Een hulpvraag oppikken of afsluiten (shaer-lgo) ─────────────── 353 // Gaat naar de WARD en naar de MEDE-GUARDIANS. De ward hoort te weten dat er 354 // iemand komt -- dat is de helft van de gerustheid -- en de anderen dat het 355 // loopt, zodat niemand denkt dat de ander het al doet. 356 // 357 // OPPIKKEN mag stapelen: twee mensen die tegelijk reageren is geen probleem. 358 // AFSLUITEN kent geen terugdraai; leeft de vraag nog, dan wordt hij opnieuw 359 // gesteld. De stevige bevestiging zit in de client, net als bij het loslaten van 360 // een ward: nooit een window.confirm. 361 router.post('/api/help/:kind', requireAuth, express.json({ limit: '2kb' }), async (req, res) => { 362 const site = siteForUser(req); 363 if (!site) return res.status(404).json({ error: 'no_site' }); 364 const kind = req.params.kind === 'handled' ? 'handled' : 'pickup'; 365 const noteUri = String(req.body?.note || '').trim(); 366 const wardUri = String(req.body?.ward || '').trim(); 367 if (!noteUri || !/^https?:\/\//i.test(noteUri)) return res.status(400).json({ error: 'no_note' }); 368 // Alleen over een hulpvraag van een kind dat je echt bewaakt. 369 const isWard = Guardianship.listWards(site.slug).some((w) => w.other_uri === wardUri); 370 if (!isWard) return res.status(403).json({ error: 'not_your_ward' }); 371 372 const me = AP.actorId((process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''), site.slug); 373 // Onze eigen kopie meteen, zonder op bezorging te wachten: het scherm van 374 // degene die klikt hoort niet te liegen omdat een andere server traag is. 375 Guardianship.help.record(noteUri, me, kind, null); 376 377 const anderen = Guardianship.listGuardians(wardUri.replace(/.*\/ap\/users\//, '')) || []; 378 const ontvangers = [wardUri, ...anderen.map((g) => g.other_uri)].filter((u) => u && u !== me); 379 const r = await AP.deliverDirectNote(site, { 380 recipients: ontvangers, 381 text: kind === 'handled' ? 'Deze hulpvraag is afgehandeld.' : 'Ik kijk hiernaar.', 382 helpMark: { kind, noteUri }, 383 }).catch(() => null); 384 // Bezorging kan mislukken; de eigen staat staat er dan toch. Dat melden we, 385 // want "verstuurd" zeggen terwijl het niet aankwam is hier het ergste soort 386 // stilte. 387 res.json({ ok: true, delivered: r ? r.delivered : 0, recipients: ontvangers.length }); 321 388 }); 322 389 … … 531 598 /** The playback gate of a ward we host (5.6): the heavier sibling. */ 532 599 function wardPlaybackSetting(uri) { return wardGateSetting(uri, 'external_playback'); } 600 /** 601 * De gate-rijen van een ward voor het paneel. 602 * 603 * De standen komen uit onze eigen kolommen als we het kind hosten; bij een ward 604 * elders weten we ze niet en blijft het NULL -- onbekend, niet uit. Het aantal 605 * guardians idem: dat wordt op de server van die ward bijgehouden, en zonder dat 606 * getal wordt er geen drempel verzonnen. 607 */ 608 function wardGates(mySlug, wardUri) { 609 const statuses = wardGuardianStatuses(wardUri); 610 const wachtend = Guardianship.follows.listReviewsByDirection(mySlug, 'incoming') 611 .filter((r) => r.ward_uri === wardUri).length; 612 return Guardianship.gated.gateRows({ 613 settings: { 614 'shaer:externalEmbeds': wardEmbedSetting(wardUri), 615 'shaer:externalPlayback': wardPlaybackSetting(wardUri), 616 }, 617 guardianCount: statuses ? statuses.length : null, 618 proposals: Guardianship.gated.listSent(mySlug, wardUri).map((p) => ({ 619 feature: p.feature, value: !!p.value, status: Guardianship.gated.sentStatus(p, Date.now()), 620 })), 621 waiting: { 'shaer:follows': wachtend || undefined }, 622 }); 623 } 624 533 625 function wardGateSetting(uri, column) { 534 626 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, '');
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)