Changeset 742ba7e in Klonkt for src/routes
- Timestamp:
- 07/28/2026 07:58:26 PM (6 weeks ago)
- Branches:
- main
- Children:
- 6c152a5
- Parents:
- 70677e96
- File:
-
- 1 edited
-
src/routes/guardian.js (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
src/routes/guardian.js
r70677e96 r742ba7e 45 45 'settings_title', 'panel_open', 'panel_close', 'panel_help', 'panel_help_empty', 46 46 'panel_follow', 'panel_follow_empty', 'panel_posts', 'panel_posts_empty', 47 'panel_actions', 'badge_help', 'badge_follow', 'badge_follow_one', 'help_empty']; 47 'panel_actions', 'badge_help', 'badge_follow', 'badge_follow_one', 'help_empty', 48 // Releasing a ward: a deliberate two-step answer, never one click. 49 'release_title', 'release_effect', 'release_local', 'release_step_down', 50 'release_last', 'release_unknown', 'release_yes', 'release_no']; 48 51 const s = Object.fromEntries(keys.map((k) => [k, i18nT(L, `guardian.${k}`)])); 49 52 s.wave = i18nT(L, 'guardian.wave'); … … 283 286 284 287 // ── Manage: release a committed ward (local Undo; federation is Fase 4). ── 288 /** 289 * What actually happens if this guardian releases this ward? 290 * 291 * Releasing is not one action but two very different ones, and the difference 292 * is the number of guardians the child has left (FEP-633c): 293 * - more than one → §3.3, you step down and the child stays a ward; 294 * - you are the last → §3.4, that is emancipation, and the FEP is explicit 295 * that no single guardian decides it alone (three consenting adults, or a 296 * majority plus two witnesses). 297 * On top of that, today's release is LOCAL: the Undo is not federated yet 298 * (relations.js, fase 4), so the ward's server keeps listing this guardian. 299 * A guardian pressing the button would otherwise believe the child is released. 300 * 301 * Answered on demand rather than in the dashboard state: for a ward we do not 302 * host this reaches out to that ward's server, and nobody should pay for that 303 * on every refresh. 304 */ 305 router.get('/wards/release-check', requireAuth, async (req, res) => { 306 const site = siteForUser(req); 307 if (!site) return res.status(404).json({ error: 'no_site' }); 308 const uri = String(req.query.uri || '').trim(); 309 if (!uri) return res.status(400).json({ error: 'empty_uri' }); 310 if (!Guardianship.listWards(site.slug).some((w) => w.other_uri === uri)) { 311 return res.status(403).json({ error: 'not_my_ward' }); 312 } 313 const base = (process.env.PUBLIC_BASE_URL || '').replace(/\/+$/, ''); 314 const local = !!base && uri.startsWith(`${base}/`); 315 let guardians = null; // null = we could not find out; say so rather than guess 316 if (local) { 317 const slug = uri.replace(/\/+$/, '').split('/').pop(); 318 try { guardians = Guardianship.listGuardians(slug).length; } catch { /* stays null */ } 319 } else { 320 const doc = await AP.fetchActor(uri).catch(() => null); 321 const g = doc && doc['shaer:guardians']; 322 if (Array.isArray(g)) guardians = g.length; 323 else if (typeof g === 'string') guardians = 1; 324 else if (g && Array.isArray(g.items)) guardians = g.items.length; 325 else if (doc) guardians = 0; // the actor answered and names no guardians 326 } 327 res.json({ 328 guardians, 329 last: guardians === null ? null : guardians <= 1, 330 local, 331 federates: false, // the Undo does not travel yet (§3.2, fase 4) 332 }); 333 }); 334 285 335 router.post('/wards/remove', requireAuth, express.json({ limit: '4kb' }), (req, res) => { 286 336 const site = siteForUser(req);
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)