## What & why Third sub-slice of **S-11 · Withdrawal (Flow 3)** (#12) — the **owner-scoped BFF withdraw endpoint** (backend). S-11a/b made a withdrawal transition the aggregate and cancel the workflow; this adds the citizen-facing entry point through the BFF, gated to the registration's owner. - **Domain**: `WithdrawRegistrationCommand` carries the caller's `bsn`; the handler returns a `WithdrawOutcome` and refuses a bsn that doesn't own the registration. Unknown and not-owned are **both 404** (indistinguishable — ownership isn't revealed). `POST /registrations/{id}/withdraw` takes `{bsn}` and maps the outcome (204/404). - **BFF**: `POST /self-service/registrations/{id}/withdraw` (DigiD-authenticated) forwards the token's `bsn` to the domain and relays 204/404. The BFF authenticates; the domain owner-scopes (an aggregate invariant, not the domain doing auth). - OpenAPI spec + Angular client regenerated for the new endpoint. - `run-domain-check.sh` withdrawal step now sends the owner `bsn` (verify-stack). Refs #12 — the self-service "trek aanvraag in" button + e2e (S-11c-2) closes it. ## Definition of Done - [x] Linked Gitea issue (#12). - [x] Failing tests committed before the implementation. - [x] Implementation makes the tests pass. - [x] Conventional Commits referencing the issue (`refs #12`). - [ ] CI green — all Gitea Actions jobs. - [x] `docker compose up` unaffected. - [x] No ADR needed (owner-scoping is an aggregate invariant; no boundary change). - [x] Docs — the user-visible demo note lands with S-11c-2. ## Notes for reviewers - **Full local gate run before pushing this time** (lessons from #89): `dotnet format --verify-no-changes` clean; `make unit` green — Acl 27, EventSubscriber 19, BFF 30, Acceptance 9, Big 95; `api-client` lint+test green. - Owner mismatch returns 404 (not 403) so the portal can't be used to probe which references exist. Reviewed-on: #90
332 lines
10 KiB
TypeScript
332 lines
10 KiB
TypeScript
/**
|
|
* Generated by orval v8.19.0 🍺
|
|
* Do not edit manually.
|
|
* Bff.Api | v1
|
|
* OpenAPI spec version: 1.0.0
|
|
*/
|
|
import {
|
|
HttpClient,
|
|
HttpHeaders,
|
|
HttpResponse as AngularHttpResponse
|
|
} from '@angular/common/http';
|
|
import type {
|
|
HttpContext,
|
|
HttpEvent,
|
|
HttpParams
|
|
} from '@angular/common/http';
|
|
|
|
import {
|
|
Injectable,
|
|
inject
|
|
} from '@angular/core';
|
|
|
|
import {
|
|
Observable
|
|
} from 'rxjs';
|
|
|
|
export interface DecideRequest {
|
|
besluit: string;
|
|
}
|
|
|
|
export interface OpenbaarEntry {
|
|
id: string;
|
|
status: string;
|
|
/** @nullable */
|
|
reference: string | null;
|
|
}
|
|
|
|
export interface SubmitAccepted {
|
|
registrationId: string;
|
|
status: string;
|
|
}
|
|
|
|
export interface WerkbakItem {
|
|
registrationId: string;
|
|
bsn: string;
|
|
status: string;
|
|
}
|
|
|
|
export type GetOpenbaarRegisterParams = {
|
|
q?: string;
|
|
};
|
|
|
|
interface HttpClientOptions {
|
|
readonly headers?: HttpHeaders | Record<string, string | string[]>;
|
|
readonly context?: HttpContext;
|
|
readonly params?:
|
|
| HttpParams
|
|
| Record<string, string | number | boolean | Array<string | number | boolean>>;
|
|
readonly reportProgress?: boolean;
|
|
readonly withCredentials?: boolean;
|
|
readonly credentials?: RequestCredentials;
|
|
readonly keepalive?: boolean;
|
|
readonly priority?: RequestPriority;
|
|
readonly cache?: RequestCache;
|
|
readonly mode?: RequestMode;
|
|
readonly redirect?: RequestRedirect;
|
|
readonly referrer?: string;
|
|
readonly integrity?: string;
|
|
readonly referrerPolicy?: ReferrerPolicy;
|
|
readonly transferCache?: {includeHeaders?: string[]} | boolean;
|
|
readonly timeout?: number;
|
|
}
|
|
|
|
type HttpClientBodyOptions = HttpClientOptions & {
|
|
readonly observe?: 'body';
|
|
};
|
|
|
|
type HttpClientEventOptions = HttpClientOptions & {
|
|
readonly observe: 'events';
|
|
};
|
|
|
|
type HttpClientResponseOptions = HttpClientOptions & {
|
|
readonly observe: 'response';
|
|
};
|
|
|
|
type HttpClientObserveOptions = HttpClientOptions & {
|
|
readonly observe?: 'body' | 'events' | 'response';
|
|
};
|
|
|
|
type AngularHttpParamValue = string | number | boolean | Array<string | number | boolean>;
|
|
type AngularHttpParamValueWithNullable = AngularHttpParamValue | null;
|
|
|
|
function filterParams(
|
|
params: Record<string, unknown>,
|
|
requiredNullableKeys?: ReadonlySet<string>,
|
|
preserveRequiredNullables?: false,
|
|
passthroughKeys?: undefined,
|
|
): Record<string, AngularHttpParamValue>;
|
|
function filterParams(
|
|
params: Record<string, unknown>,
|
|
requiredNullableKeys: ReadonlySet<string> | undefined,
|
|
preserveRequiredNullables: true,
|
|
passthroughKeys?: undefined,
|
|
): Record<string, AngularHttpParamValueWithNullable>;
|
|
function filterParams(
|
|
params: Record<string, unknown>,
|
|
requiredNullableKeys: ReadonlySet<string> | undefined,
|
|
preserveRequiredNullables: boolean | undefined,
|
|
passthroughKeys: ReadonlySet<string>,
|
|
): Record<string, unknown>;
|
|
function filterParams(
|
|
params: Record<string, unknown>,
|
|
requiredNullableKeys: ReadonlySet<string> = new Set(),
|
|
preserveRequiredNullables = false,
|
|
passthroughKeys: ReadonlySet<string> = new Set(),
|
|
): Record<string, unknown> {
|
|
const filteredParams: Record<string, unknown> = {};
|
|
for (const [key, value] of Object.entries(params)) {
|
|
if (passthroughKeys.has(key)) {
|
|
if (value !== undefined) {
|
|
filteredParams[key] = value;
|
|
}
|
|
continue;
|
|
}
|
|
if (Array.isArray(value)) {
|
|
const filtered = value.filter(
|
|
(item) =>
|
|
item != null &&
|
|
(typeof item === 'string' ||
|
|
typeof item === 'number' ||
|
|
typeof item === 'boolean'),
|
|
) as Array<string | number | boolean>;
|
|
if (filtered.length) {
|
|
filteredParams[key] = filtered;
|
|
}
|
|
} else if (
|
|
preserveRequiredNullables &&
|
|
value === null &&
|
|
requiredNullableKeys.has(key)
|
|
) {
|
|
filteredParams[key] = null;
|
|
} else if (
|
|
value != null &&
|
|
(typeof value === 'string' ||
|
|
typeof value === 'number' ||
|
|
typeof value === 'boolean')
|
|
) {
|
|
filteredParams[key] = value;
|
|
}
|
|
}
|
|
return filteredParams;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Injectable({ providedIn: 'root' })
|
|
export class BffApiV1Service {
|
|
private readonly http = inject(HttpClient);
|
|
postSelfServiceRegistrations<TData = SubmitAccepted>( options?: HttpClientBodyOptions): Observable<TData>;
|
|
postSelfServiceRegistrations<TData = SubmitAccepted>( options?: HttpClientEventOptions): Observable<HttpEvent<TData>>;
|
|
postSelfServiceRegistrations<TData = SubmitAccepted>( options?: HttpClientResponseOptions): Observable<AngularHttpResponse<TData>>;
|
|
postSelfServiceRegistrations<TData = SubmitAccepted>(
|
|
options?: HttpClientObserveOptions): Observable<TData | HttpEvent<TData> | AngularHttpResponse<TData>> {
|
|
if (options?.observe === 'events') {
|
|
return this.http.post<TData>(
|
|
`/self-service/registrations`,
|
|
undefined,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'events',
|
|
}
|
|
);
|
|
}
|
|
|
|
if (options?.observe === 'response') {
|
|
return this.http.post<TData>(
|
|
`/self-service/registrations`,
|
|
undefined,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'response',
|
|
}
|
|
);
|
|
}
|
|
|
|
return this.http.post<TData>(
|
|
`/self-service/registrations`,
|
|
undefined,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'body',
|
|
}
|
|
);
|
|
}
|
|
|
|
postSelfServiceRegistrationsIdWithdraw<TData = void>(id: string, options?: HttpClientBodyOptions): Observable<TData>;
|
|
postSelfServiceRegistrationsIdWithdraw<TData = void>(id: string, options?: HttpClientEventOptions): Observable<HttpEvent<TData>>;
|
|
postSelfServiceRegistrationsIdWithdraw<TData = void>(id: string, options?: HttpClientResponseOptions): Observable<AngularHttpResponse<TData>>;
|
|
postSelfServiceRegistrationsIdWithdraw<TData = void>(
|
|
id: string, options?: HttpClientObserveOptions): Observable<TData | HttpEvent<TData> | AngularHttpResponse<TData>> {
|
|
if (options?.observe === 'events') {
|
|
return this.http.post<TData>(
|
|
`/self-service/registrations/${id}/withdraw`,
|
|
undefined,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'events',
|
|
}
|
|
);
|
|
}
|
|
|
|
if (options?.observe === 'response') {
|
|
return this.http.post<TData>(
|
|
`/self-service/registrations/${id}/withdraw`,
|
|
undefined,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'response',
|
|
}
|
|
);
|
|
}
|
|
|
|
return this.http.post<TData>(
|
|
`/self-service/registrations/${id}/withdraw`,
|
|
undefined,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'body',
|
|
}
|
|
);
|
|
}
|
|
|
|
getOpenbaarRegister<TData = OpenbaarEntry[]>(params?: GetOpenbaarRegisterParams, options?: HttpClientBodyOptions): Observable<TData>;
|
|
getOpenbaarRegister<TData = OpenbaarEntry[]>(params?: GetOpenbaarRegisterParams, options?: HttpClientEventOptions): Observable<HttpEvent<TData>>;
|
|
getOpenbaarRegister<TData = OpenbaarEntry[]>(params?: GetOpenbaarRegisterParams, options?: HttpClientResponseOptions): Observable<AngularHttpResponse<TData>>;
|
|
getOpenbaarRegister<TData = OpenbaarEntry[]>(
|
|
params?: GetOpenbaarRegisterParams, options?: HttpClientObserveOptions): Observable<TData | HttpEvent<TData> | AngularHttpResponse<TData>> {
|
|
const filteredParams = filterParams({...params, ...options?.params}, new Set<string>([]));
|
|
|
|
if (options?.observe === 'events') {
|
|
return this.http.get<TData>(
|
|
`/openbaar/register`,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'events',
|
|
params: filteredParams,}
|
|
);
|
|
}
|
|
|
|
if (options?.observe === 'response') {
|
|
return this.http.get<TData>(
|
|
`/openbaar/register`,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'response',
|
|
params: filteredParams,}
|
|
);
|
|
}
|
|
|
|
return this.http.get<TData>(
|
|
`/openbaar/register`,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'body',
|
|
params: filteredParams,}
|
|
);
|
|
}
|
|
|
|
getBehandelWerkbak<TData = WerkbakItem[]>( options?: HttpClientBodyOptions): Observable<TData>;
|
|
getBehandelWerkbak<TData = WerkbakItem[]>( options?: HttpClientEventOptions): Observable<HttpEvent<TData>>;
|
|
getBehandelWerkbak<TData = WerkbakItem[]>( options?: HttpClientResponseOptions): Observable<AngularHttpResponse<TData>>;
|
|
getBehandelWerkbak<TData = WerkbakItem[]>(
|
|
options?: HttpClientObserveOptions): Observable<TData | HttpEvent<TData> | AngularHttpResponse<TData>> {
|
|
if (options?.observe === 'events') {
|
|
return this.http.get<TData>(
|
|
`/behandel/werkbak`,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'events',
|
|
}
|
|
);
|
|
}
|
|
|
|
if (options?.observe === 'response') {
|
|
return this.http.get<TData>(
|
|
`/behandel/werkbak`,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'response',
|
|
}
|
|
);
|
|
}
|
|
|
|
return this.http.get<TData>(
|
|
`/behandel/werkbak`,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'body',
|
|
}
|
|
);
|
|
}
|
|
|
|
postBehandelRegistrationsIdDecide<TData = void>(id: string,
|
|
decideRequest: DecideRequest, options?: HttpClientBodyOptions): Observable<TData>;
|
|
postBehandelRegistrationsIdDecide<TData = void>(id: string,
|
|
decideRequest: DecideRequest, options?: HttpClientEventOptions): Observable<HttpEvent<TData>>;
|
|
postBehandelRegistrationsIdDecide<TData = void>(id: string,
|
|
decideRequest: DecideRequest, options?: HttpClientResponseOptions): Observable<AngularHttpResponse<TData>>;
|
|
postBehandelRegistrationsIdDecide<TData = void>(
|
|
id: string,
|
|
decideRequest: DecideRequest, options?: HttpClientObserveOptions): Observable<TData | HttpEvent<TData> | AngularHttpResponse<TData>> {
|
|
if (options?.observe === 'events') {
|
|
return this.http.post<TData>(
|
|
`/behandel/registrations/${id}/decide`,
|
|
decideRequest,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'events',
|
|
}
|
|
);
|
|
}
|
|
|
|
if (options?.observe === 'response') {
|
|
return this.http.post<TData>(
|
|
`/behandel/registrations/${id}/decide`,
|
|
decideRequest,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'response',
|
|
}
|
|
);
|
|
}
|
|
|
|
return this.http.post<TData>(
|
|
`/behandel/registrations/${id}/decide`,
|
|
decideRequest,{
|
|
...(options as Omit<NonNullable<typeof options>, 'observe'>),
|
|
observe: 'body',
|
|
}
|
|
);
|
|
}
|
|
|
|
};
|