feat(history): scope export tasks to owners

This commit is contained in:
lingniu
2026-07-16 17:00:33 +08:00
parent a2722e4afd
commit 38b056f5f1
18 changed files with 528 additions and 100 deletions

View File

@@ -141,6 +141,29 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
}
}
async function requestBlob(path: string, signal?: AbortSignal) {
const token = getAccessToken();
const init: RequestInit = token ? { signal, headers: withAuthorization(undefined, token) } : { signal };
const response = await fetch(path, init);
if (!response.ok) {
if (response.status === 401 && token) notifyUnauthorizedSession(token);
throw new Error(await responseErrorMessage(response));
}
const encodedFilename = response.headers.get('X-Export-Name')?.trim();
let filename = 'history-export.csv';
if (encodedFilename) {
try {
filename = decodeURIComponent(encodedFilename);
} catch {
filename = encodedFilename;
}
}
return {
blob: await response.blob(),
filename
};
}
function withAuthorization(headers: HeadersInit | undefined, token: string) {
const authorized = new Headers(headers);
authorized.set('Authorization', `Bearer ${token}`);
@@ -201,6 +224,7 @@ export const api = {
createHistoryExport: (query: HistoryExportRequest) => request<HistoryExportJob>('/api/v2/exports', {
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(query)
}),
downloadHistoryExport: (id: string, signal?: AbortSignal) => requestBlob(`/api/v2/exports/${encodeURIComponent(id)}/download`, signal),
accessSummary: (query: AccessQuery, signal?: AbortSignal) => request<AccessSummary>('/api/v2/access/summary', withSignal({
method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(query)
}, signal)),