feat: add governed public self-enrollment links

This commit is contained in:
2026-08-20 13:03:57 +02:00
parent 79cfaa951a
commit 539e3cbb5e
18 changed files with 2481 additions and 13 deletions
@@ -4,11 +4,13 @@ import { fileURLToPath } from "node:url";
const pagePath = fileURLToPath(new URL("../src/features/scheduling/SchedulingPage.tsx", import.meta.url));
const publicPagePath = fileURLToPath(new URL("../src/features/scheduling/SchedulingPublicPage.tsx", import.meta.url));
const enrollmentPagePath = fileURLToPath(new URL("../src/features/scheduling/SchedulingEnrollmentPage.tsx", import.meta.url));
const apiPath = fileURLToPath(new URL("../src/api/scheduling.ts", import.meta.url));
const modulePath = fileURLToPath(new URL("../src/module.ts", import.meta.url));
const widgetPath = fileURLToPath(new URL("../src/features/scheduling/SchedulingRequestsWidget.tsx", import.meta.url));
const page = readFileSync(pagePath, "utf8");
const publicPage = readFileSync(publicPagePath, "utf8");
const enrollmentPage = readFileSync(enrollmentPagePath, "utf8");
const api = readFileSync(apiPath, "utf8");
const moduleSource = readFileSync(modulePath, "utf8");
const widget = readFileSync(widgetPath, "utf8");
@@ -48,6 +50,11 @@ assert.match(page, /<StageRail[\s\S]*schedulingLifecycleStages\(selected\.status
assert.match(page, /topicId: "scheduling\.find-and-decide-meeting-time"/);
assert.match(page, /topicId: "scheduling\.calendar-coordination"/);
assert.match(page, /topicId: "scheduling\.participation-governance"/);
assert.match(page, /topicId: "scheduling\.public-self-enrollment"/);
assert.match(page, /function SelfEnrollmentLinksCard/);
assert.match(page, /createSchedulingEnrollmentLink/);
assert.match(page, /revokeSchedulingEnrollmentLink/);
assert.match(page, /title=\{I18N\.selfEnrollmentRevokeTitle\}[\s\S]*tone="danger"/);
assert.match(page, /public_participation_policy_enforcement_available === false[\s\S]*<ActionBlockerHint/);
assert.match(page, /<Card title=\{I18N\.generalSettings\}>/);
assert.match(page, /<Card title=\{I18N\.participantPrivacy\}>/);
@@ -161,11 +168,14 @@ assert.match(api, /issueSchedulingParticipantInvitation\([\s\S]*json\(\{ action,
assert.match(api, /revokeSchedulingParticipantInvitation\([\s\S]*method: "DELETE"[\s\S]*participant_revision: participantRevision/);
assert.match(api, /participants\/\$\{encodeURIComponent\(participantId\)\}\/invitation/);
assert.match(api, /\/api\/v1\/scheduling\/public\/\$\{encodeURIComponent\(requestId\)\}\/\$\{encodeURIComponent\(token\)\}/);
assert.match(api, /\/api\/v1\/scheduling\/public-enrollment\/\$\{encodeURIComponent\(requestId\)\}\/\$\{encodeURIComponent\(token\)\}/);
assert.match(page, /useSearchParams\(\)/);
assert.match(page, /Promise\.allSettled/);
assert.match(moduleSource, /publicRoutes:[\s\S]*path: "\/scheduling\/public\/:requestId\/:token"/);
assert.match(moduleSource, /SchedulingPublicPage/);
assert.match(moduleSource, /path: "\/scheduling\/enrol\/:requestId\/:token"/);
assert.match(moduleSource, /SchedulingEnrollmentPage/);
assert.match(publicPage, /Card,[\s\S]*DismissibleAlert,[\s\S]*DocumentationHelpLink,[\s\S]*FormField,[\s\S]*LoadingFrame,[\s\S]*PasswordField,[\s\S]*from "@govoplan\/core-webui"/);
assert.match(publicPage, /<PasswordField[\s\S]*autoComplete="current-password"/);
assert.doesNotMatch(publicPage, /<input[\s\S]{0,120}type="password"/);
@@ -178,6 +188,14 @@ assert.match(publicPage, /idempotency_key: newIdempotencyKey\(\)/);
assert.doesNotMatch(publicPage, /window\.(?:alert|confirm)\(/);
assert.doesNotMatch(publicPage, /(?:localStorage|sessionStorage).*token|token.*(?:localStorage|sessionStorage)/);
assert.match(enrollmentPage, /submitAuthenticatedSchedulingEnrollment/);
assert.match(enrollmentPage, /submitPublicSchedulingEnrollment/);
assert.match(enrollmentPage, /bind_account_confirmed: true/);
assert.match(enrollmentPage, /participant_proof:/);
assert.match(enrollmentPage, /topicId: "scheduling\.public-self-enrollment"/);
assert.doesNotMatch(enrollmentPage, /window\.(?:alert|confirm)\(/);
assert.doesNotMatch(enrollmentPage, /(?:localStorage|sessionStorage).*(?:token|proof)|(?:token|proof).*(?:localStorage|sessionStorage)/);
assert.match(widget, /DocumentationHelpLink/);
assert.match(widget, /to: `\/scheduling\?request_id=\$\{encodeURIComponent\(request\.id\)\}`/);
assert.match(widget, /label=\{request\.status === "collecting" \? I18N\.open : I18N\.draft\}/);