Ga naar inhoud

Contracten

Modules kennen elkaars code niet. Wil je module iets van Tabbr of van een andere module — wie heeft de rol INSTRUCTEUR?, heeft deze persoon toestemming gegeven voor foto’s? — dan gaat dat via een contract: een .d.ts met een frontend- en/of backenddeel, en een eigen versienummer.

Zo kan een module bijgewerkt worden zonder dat een andere breekt, zolang het contract binnen zijn major blijft.

tabbr.config.json
"uses": { "sys.access": "^1" },
"optionalUses": { "tabbr.consent": "^1" }
  • uses: je module heeft het nodig; ze kan alleen geïnstalleerd worden waar de club het contract heeft.
  • optionalUses: je module gebruikt het als het er is (API 1.3).

GET /api/contracts geeft de contracten die er in een club zijn.

Kant Methode Wat ze doet
frontend + backend roles() De rollen van de club: { code, name, system }.
frontend + backend personsWithRole(code) Wie die rol heeft.
backend rolesOf(personId) De rollen van een persoon, met hun bron (roleCode, source).
backend setManagedRoles(personId, codes) De rollen die jouw module aan iemand geeft. Rollen die met de hand gegeven zijn, blijven.
backend managedRoles(personId), managedAssignments() Wat jouw module gegeven heeft.

De laatste drie vragen "manageRoles": true in je backend-blok. Een module kan nooit een systeemrol (ADMIN) geven.

Kant Methode Wat ze doet
frontend status(code) Het antwoord van de ingelogde gebruiker.
frontend + backend statusOf(code, personIds) De antwoorden van meerdere personen.
frontend ensure(code, { context }) Vraagt het als het nog niet beantwoord is; true als de persoon akkoord is.
frontend personFilter(code, status?) Een filter voor een lijst of ontvangers.
frontend openPending() Opent de openstaande vragen.
backend personsWith(code, status?) Wie akkoord is (of een andere status).

Een status is granted, refused, withdrawn, expired, open of unknownType. Alleen granted betekent toestemming.

Een module kan zelf een contract aanbieden (API 1.3), zoals de module Toestemmingen tabbr.consent aanbiedt.

  1. Kies de naam. Een contract heet naar zijn uitgever: het pakket acme/groups biedt acme.groups aan. sys. is voorbehouden aan Tabbr.

  2. Schrijf de .d.ts. Op zichzelf staand (geen imports), met een Frontend- en/of Backend-interface:

    contracts/acme.groups.d.ts
    export interface Frontend {
    /** de groepen waar de ingelogde gebruiker lid van is */
    myGroups(): Promise<{ id: string; name: string }[]>;
    }
    export interface Backend {
    membersOf(groupId: string): string[];
    }
  3. Declareer het in het manifest:

    "provides": { "acme.groups": { "version": "1.0.0", "types": "contracts/acme.groups.d.ts" } }
  4. Implementeer het. In de frontend als provides op je moduleklasse, in de backend als export const provides in je entry-bestand:

    src/app/module/module.ts
    readonly provides = { 'acme.groups': this.store.contract };
    backend/src/index.ts
    export const provides = {
    'acme.groups': {
    membersOf(groupId: string) { /* … */ return ids; },
    },
    };

Backend-oproepen draaien in de sandbox van de aanbieder, met JSON in en uit. Een lus (A roept B roept A) wordt geweigerd.