source: Klonkt/src/services/guardianship/relations.js@ 86e6a45

main
Last change on this file since 86e6a45 was 86e6a45, checked in by roboburr <roboburr@…>, 5 weeks ago

De apps krijgen de hulpstaat, en kunnen afhandelen (shaer-lgo)

Barts melding: afgehandelde hulpverzoeken blijven zichtbaar in de Shaer
GuardianshipView, en kan het afhandelen daar ook?

DIE TWEE ZIJN HETZELFDE PROBLEEM. De apps lazen hulpvragen uit de FEED -- losse
notes met een helpRequest-vlag -- en kregen de staat helemaal niet. Ze konden dus
niet weten of er al iemand op af was, en dan is een afgehandeld verzoek laten
staan nog het eerlijkste dat een app kan doen. Klonkt bewaarde de staat wel; hij
reisde alleen nergens heen.

Nu een queue help op de actor, met de staat PLAT erin: open, wie hem oppakte,
wie hem afsloot en wanneer. Een app hoeft hem niet af te leiden en kan hem dus
ook niet anders afleiden dan het paneel -- helpItemsFor is een plek, net als
wardGates. Twee berekeningen zouden twee guardians een ander beeld geven van
hetzelfde kind, en bij een reddingsboei is dat het gevaarlijkste dat er mis kan
gaan.

AFHANDELEN HOEFDE GEEN NIEUWE VORM. De markering IS al een gewone directe note
met shaer:helpPickup of shaer:helpHandled, precies zoals de zwaai. De outbox
herkent hem nu, dus de app stuurt letterlijk wat de PWA stuurt en het reist over
dezelfde bezorging naar de mede-guardians. Geen tweede weg.

Wel LOKAAL boeken, en daar staat een toets op: zonder dat zag de guardian die de
knop indrukt zijn eigen markering pas als hij bij zichzelf terugkwam, en die weg
bestaat niet.

Oppikken blijft OPEN. De faalstand hier is "iedereen denkt dat het geregeld is",
en die is gevaarlijker dan geen markering.

De AS2-toets ving dat help nog niet gedeclareerd stond op de actor -- precies
waarvoor die toets er is. Suite 718/718; zonder de lokale boeking valt er een om.

  • Property mode set to 100644
File size: 4.4 KB
Line 
1/**
2 * Guardianship (FEP-633c) — the COMMITTED ward ↔ guardian relations
3 * (ap_guardianships). Pending offers live in offers.js; a row here means the
4 * handshake committed (§3.1.4). Every row is one relation seen from a LOCAL
5 * site: role 'guardian' = the site guards other_uri; role 'ward' = other_uri
6 * guards the site.
7 */
8import db from '../../config/database.js';
9
10let _s = null;
11function stmts() {
12 if (!_s) {
13 _s = {
14 commit: db.prepare(`INSERT INTO ap_guardianships (slug, role, other_uri, other_handle, status, offer_id, created_at)
15 VALUES (?,?,?,?, 'accepted', ?, CURRENT_TIMESTAMP)
16 ON CONFLICT(slug, role, other_uri) DO UPDATE SET status='accepted', offer_id=excluded.offer_id`),
17 del: db.prepare('DELETE FROM ap_guardianships WHERE slug=? AND role=? AND other_uri=?'),
18 bySlugRole: db.prepare("SELECT * FROM ap_guardianships WHERE slug=? AND role=? AND status='accepted' ORDER BY created_at DESC"),
19 one: db.prepare('SELECT * FROM ap_guardianships WHERE slug=? AND role=? AND other_uri=?'),
20 };
21 }
22 return _s;
23}
24
25// ── Reads ────────────────────────────────────────────────────────────────
26
27/** Accepted guardian URIs of a local ward (feeds shaer:guardians). */
28export function listGuardians(slug) { return stmts().bySlugRole.all(slug, 'ward'); }
29
30/** Accepted wards of a local guardian (the wards queue). */
31export function listWards(slug) { return stmts().bySlugRole.all(slug, 'guardian'); }
32
33/** A site is a guardian once it stands in any accepted guardian relation. */
34export function isGuardian(slug) { return listWards(slug).length > 0; }
35
36export function getRelation(slug, role, otherUri) { return stmts().one.get(slug, role, otherUri); }
37
38// ── Writes (only the handshake commit lands here) ────────────────────────
39
40/** The local ward gains a guardian (commit, §3.1.4). */
41export function commitGuardianForWard(wardSlug, guardianUri, { handle = null, offerId = null } = {}) {
42 stmts().commit.run(wardSlug, 'ward', guardianUri, handle, offerId);
43 return stmts().one.get(wardSlug, 'ward', guardianUri);
44}
45
46/** The local guardian gains a ward (commit, §3.1.4). */
47export function commitWardForGuardian(guardianSlug, wardUri, { handle = null, offerId = null } = {}) {
48 stmts().commit.run(guardianSlug, 'guardian', wardUri, handle, offerId);
49 return stmts().one.get(guardianSlug, 'guardian', wardUri);
50}
51
52/** End a relation locally (Undo, §3.2 — federation of the Undo is Fase 4). */
53export function removeRelation(slug, role, otherUri) {
54 stmts().del.run(slug, role, otherUri);
55 return { ok: true };
56}
57
58// ── Actor document (FEP-633c §2) ─────────────────────────────────────────
59
60/**
61 * Guardianship props for a local actor doc. `id` is the actor URI.
62 * - shaer:guardians: accepted guardians of this ward (omitted when none, §2.1)
63 * - shaer:isGuardian: true once the site guards anyone
64 * - shaer:queues: the owner-only dashboard collections
65 *
66 * §1 mutual exclusion: a ward (has guardians) is never a guardian, so
67 * shaer:isGuardian is suppressed if guardians exist; the offer path already
68 * bars a ward from offering.
69 */
70export function actorProps(id, slug) {
71 const props = {
72 'shaer:queues': {
73 offers: `${id}/queues/offers`,
74 follows: `${id}/queues/follows`,
75 // Both directions of §5.3, kept apart on purpose: a guardian must be able
76 // to tell "someone wants to follow your ward" from "your ward wants to
77 // follow someone". Same mechanism, opposite question, different words in
78 // the interface (shaer-p729).
79 outgoingFollows: `${id}/queues/outgoing-follows`,
80 wards: `${id}/queues/wards`,
81 guardians: `${id}/queues/guardians`,
82 help: `${id}/queues/help`,
83 },
84 };
85 const guardians = listGuardians(slug).map((r) => r.other_uri);
86 if (guardians.length) {
87 props['shaer:guardians'] = guardians; // a ward
88 } else if (isGuardian(slug)) {
89 props['shaer:isGuardian'] = true; // a guardian (never both, §1)
90 }
91 return props;
92}
93
94export default {
95 listGuardians, listWards, isGuardian, getRelation,
96 commitGuardianForWard, commitWardForGuardian, removeRelation, actorProps,
97};
Note: See TracBrowser for help on using the repository browser.