feat: add DSAR administration
This commit is contained in:
+159
-1
@@ -1,5 +1,5 @@
|
||||
import type { ApiSettings, DeltaDeletedItem, PrivacyRetentionPolicy } from "@govoplan/core-webui";
|
||||
import { apiFetch, apiPath, apiQuery } from "@govoplan/core-webui";
|
||||
import { apiDownload, apiFetch, apiPath, apiQuery } from "@govoplan/core-webui";
|
||||
export { fetchAdminOverview, fetchPermissionCatalog, fetchTenants } from "@govoplan/core-webui";
|
||||
export type {
|
||||
AdminOverview,
|
||||
@@ -565,6 +565,102 @@ export type GovernanceTemplateItem = {
|
||||
updated_at: string;
|
||||
};
|
||||
|
||||
export type DataSubjectSelector = {
|
||||
account_id?: string | null;
|
||||
identity_id?: string | null;
|
||||
membership_id?: string | null;
|
||||
email?: string | null;
|
||||
external_references?: Record<string, string>;
|
||||
};
|
||||
|
||||
export type DataSubjectRequestSummary = {
|
||||
id: string;
|
||||
tenant_id: string;
|
||||
reference: string;
|
||||
request_kind: "access" | "erasure" | "access_and_erasure";
|
||||
status: string;
|
||||
subject: DataSubjectSelector;
|
||||
purpose: string;
|
||||
legal_basis?: string | null;
|
||||
due_at?: string | null;
|
||||
requested_by_account_id: string;
|
||||
record_count: number;
|
||||
executable_action_count: number;
|
||||
coverage: {
|
||||
covered_modules?: string[];
|
||||
modules_without_provider?: string[];
|
||||
provider_discovery_failures?: Array<Record<string, unknown>>;
|
||||
};
|
||||
evidence_sha256?: string | null;
|
||||
resource_revision: number;
|
||||
etag: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
completed_at?: string | null;
|
||||
notes?: string | null;
|
||||
};
|
||||
|
||||
export type DataSubjectRecord = {
|
||||
provider_id: string;
|
||||
module_id: string;
|
||||
resource_type: string;
|
||||
resource_id: string;
|
||||
category: string;
|
||||
title: string;
|
||||
data: Record<string, unknown>;
|
||||
observed_at?: string | null;
|
||||
immutable_evidence: boolean;
|
||||
retention_reason?: string | null;
|
||||
source_path?: string | null;
|
||||
};
|
||||
|
||||
export type DataSubjectErasureAction = {
|
||||
action_id: string;
|
||||
provider_id: string;
|
||||
module_id: string;
|
||||
kind: string;
|
||||
resource_type: string;
|
||||
resource_id: string;
|
||||
title: string;
|
||||
rationale: string;
|
||||
executable: boolean;
|
||||
irreversible: boolean;
|
||||
metadata: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type DataSubjectRequestDetail = {
|
||||
request: DataSubjectRequestSummary;
|
||||
search: {
|
||||
records?: DataSubjectRecord[];
|
||||
provider_runs?: Array<Record<string, unknown>>;
|
||||
searched_at?: string;
|
||||
record_count?: number;
|
||||
};
|
||||
erasure_plan: {
|
||||
actions?: DataSubjectErasureAction[];
|
||||
provider_runs?: Array<Record<string, unknown>>;
|
||||
planned_at?: string;
|
||||
executable_count?: number;
|
||||
retained_count?: number;
|
||||
};
|
||||
execution: {
|
||||
results?: Array<{ action_id: string; status: string; summary: string; evidence?: Record<string, unknown> }>;
|
||||
executed_at?: string;
|
||||
successful_count?: number;
|
||||
failed_count?: number;
|
||||
};
|
||||
};
|
||||
|
||||
export type DataSubjectRequestCreatePayload = {
|
||||
reference: string;
|
||||
request_kind: DataSubjectRequestSummary["request_kind"];
|
||||
subject: DataSubjectSelector;
|
||||
purpose: string;
|
||||
legal_basis?: string | null;
|
||||
due_at?: string | null;
|
||||
notes?: string | null;
|
||||
};
|
||||
|
||||
export function fetchSystemSettings(settings: ApiSettings): Promise<SystemSettingsItem> {
|
||||
return apiFetch(settings, "/api/v1/admin/system/settings");
|
||||
}
|
||||
@@ -713,6 +809,68 @@ export function deleteGovernanceTemplate(settings: ApiSettings, templateId: stri
|
||||
return apiFetch(settings, apiPath(`/api/v1/admin/system/governance-templates/${templateId}`, { change_request_id: changeRequestId }), { method: "DELETE" });
|
||||
}
|
||||
|
||||
export async function fetchDataSubjectRequests(settings: ApiSettings): Promise<DataSubjectRequestSummary[]> {
|
||||
const response = await apiFetch<{ items: DataSubjectRequestSummary[] }>(settings, "/api/v1/admin/privacy/data-subject-requests");
|
||||
return response.items;
|
||||
}
|
||||
|
||||
export function fetchDataSubjectRequest(settings: ApiSettings, requestId: string): Promise<DataSubjectRequestDetail> {
|
||||
return apiFetch(settings, `/api/v1/admin/privacy/data-subject-requests/${encodeURIComponent(requestId)}`);
|
||||
}
|
||||
|
||||
export function createDataSubjectRequest(settings: ApiSettings, payload: DataSubjectRequestCreatePayload): Promise<DataSubjectRequestDetail> {
|
||||
return apiFetch(settings, "/api/v1/admin/privacy/data-subject-requests", {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
}
|
||||
|
||||
export function searchDataSubjectRequest(settings: ApiSettings, request: DataSubjectRequestSummary): Promise<DataSubjectRequestDetail> {
|
||||
return mutateDataSubjectRequest(settings, request, "search", {});
|
||||
}
|
||||
|
||||
export function planDataSubjectErasure(settings: ApiSettings, request: DataSubjectRequestSummary): Promise<DataSubjectRequestDetail> {
|
||||
return mutateDataSubjectRequest(settings, request, "erasure-plan", {});
|
||||
}
|
||||
|
||||
export function executeDataSubjectErasure(
|
||||
settings: ApiSettings,
|
||||
request: DataSubjectRequestSummary,
|
||||
actionIds: string[],
|
||||
confirmation: string
|
||||
): Promise<DataSubjectRequestDetail> {
|
||||
return mutateDataSubjectRequest(settings, request, "execute", {
|
||||
action_ids: actionIds,
|
||||
confirmation
|
||||
});
|
||||
}
|
||||
|
||||
export function exportDataSubjectRequest(settings: ApiSettings, request: DataSubjectRequestSummary): Promise<void> {
|
||||
const safeReference = request.reference.replace(/[^A-Za-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
||||
return apiDownload(
|
||||
settings,
|
||||
`/api/v1/admin/privacy/data-subject-requests/${encodeURIComponent(request.id)}/export`,
|
||||
`dsar-${safeReference || request.id}.json`
|
||||
);
|
||||
}
|
||||
|
||||
function mutateDataSubjectRequest(
|
||||
settings: ApiSettings,
|
||||
request: DataSubjectRequestSummary,
|
||||
operation: string,
|
||||
payload: Record<string, unknown>
|
||||
): Promise<DataSubjectRequestDetail> {
|
||||
return apiFetch(
|
||||
settings,
|
||||
`/api/v1/admin/privacy/data-subject-requests/${encodeURIComponent(request.id)}/${operation}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: { "If-Match": request.etag },
|
||||
body: JSON.stringify({ base_revision: request.resource_revision, ...payload })
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function fetchConfigurationChanges(settings: ApiSettings): Promise<{ requests: ConfigurationChangeRequest[]; history: ConfigurationChangeRecord[] }> {
|
||||
return apiFetch(settings, "/api/v1/admin/configuration-changes");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user