Changeset d56d471 in Klonkt for src/routes
- Timestamp:
- 07/29/2026 12:36:50 PM (6 weeks ago)
- Branches:
- main
- Children:
- 7a93fcf
- Parents:
- 6100ce9
- File:
-
- 1 edited
-
src/routes/guardian.js (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/guardian.js
r6100ce9 rd56d471 55 55 // A gated-setting proposal from a fellow guardian (5.6). 56 56 'gated_title', 'gated_line_on', 'gated_line_off', 'gated_agree', 'gated_disagree', 57 'play_propose', 'play_on', 'play_off']; 57 'play_propose', 'play_on', 'play_off', 58 // The status of a proposal this guardian sent (5.6). 59 'prop_line', 'prop_embeds', 'prop_play', 'prop_on', 'prop_off', 60 'prop_st_open', 'prop_st_accepted', 'prop_st_rejected', 'prop_st_expired', 61 'panel_guards_far']; 58 62 const s = Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)])); 59 63 s.wave = i18nT(L, 'guardian.wave'); … … 93 97 playback: wardPlaybackSetting(w.other_uri), 94 98 guardians: wardGuardianStatuses(w.other_uri), 99 // What THIS guardian proposed for this ward and how it stands (5.6): 100 // open, accepted, rejected, or expired when the window ran out and the 101 // ward's server had nothing to write home. The answer is a real 102 // Accept/Reject from the ward's server, not a guess from here. 103 proposals: Guardianship.gated.listSent(site.slug, w.other_uri).map((p) => ({ 104 feature: p.feature, value: !!p.value, created: p.created_at, 105 status: Guardianship.gated.sentStatus(p, Date.now()), 106 })), 95 107 })), 96 108 offers: Guardianship.offersCollection(`${me}/queues/offers`, site.slug, me).orderedItems, … … 443 455 }); 444 456 457 // ── The fellow guardians of a ward, wherever it lives ───────────────────── 458 // A guardian looking at a ward's panel should see who else holds a seat: that 459 // is the child's safety net, and "dit kind woont op een andere server" is not 460 // an answer. For a local ward the availability rides along (we do that 461 // bookkeeping). For a remote ward we read the PUBLIC membership from its 462 // actor document (shaer:guardians, §2.1) and nothing more: availability is 463 // the ward's server's private ledger (§3.6.1) and stays there. Fetched on 464 // panel-open rather than into the dashboard, so one slow remote server does 465 // not hold the whole screen hostage. 466 router.get('/wards/guardians', requireAuth, async (req, res) => { 467 const site = siteForUser(req); 468 if (!site) return res.status(404).json({ error: 'no_site' }); 469 const uri = String(req.query.uri || '').trim(); 470 if (!Guardianship.listWards(site.slug).some((w) => w.other_uri === uri)) { 471 return res.status(403).json({ error: 'not_my_ward' }); 472 } 473 const local = wardGuardianStatuses(uri); 474 if (local) return res.json({ local: true, guardians: local }); 475 const doc = await AP.fetchActor(uri).catch(() => null); 476 let g = doc && doc['shaer:guardians']; 477 if (g && Array.isArray(g.items)) g = g.items; // a Collection 478 const guardians = (Array.isArray(g) ? g : (typeof g === 'string' ? [g] : [])) 479 .filter((x) => typeof x === 'string') 480 .map((u) => { 481 try { const p = new URL(u); return { uri: u, handle: `@${p.pathname.replace(/\/+$/, '').split('/').pop()}@${p.host}` }; } 482 catch { return { uri: u, handle: u }; } 483 }); 484 res.json({ local: false, guardians }); 485 }); 486 445 487 router.post('/wards/remove', requireAuth, express.json({ limit: '4kb' }), async (req, res) => { 446 488 const site = siteForUser(req); … … 507 549 // nothing else. The old shortcut recorded the vote here directly, which is 508 550 // how the remote path stayed broken for a month without anyone noticing. 551 // Our own record of what we sent (5.6): the ward's server answers this Offer 552 // once the decision settles, and that answer needs a row to land in. It is 553 // also the only way the proposer's screen can say more than a button caption. 554 Guardianship.gated.recordSent(offerId, site.slug, uri, feature, allow); 509 555 AP.deliverToActor(site, uri, offer).catch(() => { /* queued, best-effort */ }); 510 556 const localSlug = (base && uri.startsWith(`${base}/`)) ? uri.replace(/\/+$/, '').split('/').pop() : null;
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)