export
This commit is contained in:
@@ -139,6 +139,50 @@ async function httpBinary(path, { method = 'POST', body, contentType } = {}) {
|
||||
return json;
|
||||
}
|
||||
|
||||
/** GET a file (e.g. a ZIP download). Returns a Blob on success; JSON errors on failure. */
|
||||
async function httpGetBinary(path) {
|
||||
logApi('request', {
|
||||
method: 'GET',
|
||||
path,
|
||||
url: new URL(path, window.location.origin).href,
|
||||
origin: window.location.origin,
|
||||
credentials: 'include',
|
||||
});
|
||||
|
||||
const res = await fetch(path, { method: 'GET', credentials: 'include' });
|
||||
|
||||
logApi('response', {
|
||||
method: 'GET',
|
||||
path,
|
||||
status: res.status,
|
||||
statusText: res.statusText,
|
||||
ok: res.ok,
|
||||
contentType: res.headers.get('content-type'),
|
||||
responseHeaders: readableHeaders(res.headers),
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
let message = res.statusText;
|
||||
let data;
|
||||
try {
|
||||
data = await res.json();
|
||||
message = data.error || data.message || message;
|
||||
} catch {
|
||||
message = (await res.text().catch(() => message)) || message;
|
||||
}
|
||||
logApi('error-body', { method: 'GET', path, status: res.status, message, data });
|
||||
const err = new Error(message || `Request failed (${res.status})`);
|
||||
err.status = res.status;
|
||||
err.path = path;
|
||||
err.method = 'GET';
|
||||
err.data = data;
|
||||
throw err;
|
||||
}
|
||||
|
||||
const blob = await res.blob();
|
||||
return blob;
|
||||
}
|
||||
|
||||
export const article = {
|
||||
search({ target, filter, offset, maxCount } = {}) {
|
||||
const params = new URLSearchParams({ target });
|
||||
@@ -274,6 +318,20 @@ export const article = {
|
||||
body: { categoryIds },
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* GET /api/article/export.zip → application/zip (binary download)
|
||||
* `artikel.zip` = artikel.csv (semicolon-separated, Windows-1252) +
|
||||
* one `<fullHash>.avif` per article image (content-addressed, deduplicated).
|
||||
* Optional `categoryId` restricts the export to that category and below.
|
||||
* Errors: 400 No company selected, 401, 403, 404 (JSON { error }).
|
||||
*/
|
||||
exportZip(categoryId) {
|
||||
const params = new URLSearchParams();
|
||||
if (categoryId != null) params.set('categoryId', String(categoryId));
|
||||
const qs = params.toString();
|
||||
return httpGetBinary(`/api/article/export.zip${qs ? `?${qs}` : ''}`);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -419,6 +477,17 @@ export const category = {
|
||||
deleteImage(categoryId) {
|
||||
return http(`/api/category/${categoryId}/image`, { method: 'DELETE' });
|
||||
},
|
||||
|
||||
/**
|
||||
* GET /api/category/export.zip → application/zip (binary download)
|
||||
* `kategorien.zip` = kategorien.csv (semicolon-separated, Windows-1252,
|
||||
* depth-first, `Ebene N` name column per depth) + one `<fullHash>.avif`
|
||||
* entry per category image (content-addressed, deduplicated).
|
||||
* Errors: 400 No company selected, 401, 403, 404 (JSON { error }).
|
||||
*/
|
||||
exportZip() {
|
||||
return httpGetBinary('/api/category/export.zip');
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user