@mxpicture/print-backlog 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/public/assets/index-BnhoKdrs.css +1 -0
- package/dist/public/assets/index-j0LpYaft.js +1 -0
- package/dist/public/index.html +2 -2
- package/dist/server/api/items.d.ts +49 -0
- package/dist/server/api/items.d.ts.map +1 -0
- package/dist/server/api/items.js +552 -0
- package/dist/server/api/items.js.map +1 -0
- package/dist/server/api/queues.d.ts +12 -0
- package/dist/server/api/queues.d.ts.map +1 -1
- package/dist/server/api/queues.js +88 -0
- package/dist/server/api/queues.js.map +1 -1
- package/dist/server/app.d.ts +3 -1
- package/dist/server/app.d.ts.map +1 -1
- package/dist/server/app.js +30 -6
- package/dist/server/app.js.map +1 -1
- package/dist/server/cli.js +4 -1
- package/dist/server/cli.js.map +1 -1
- package/dist/server/multipart.d.ts +17 -0
- package/dist/server/multipart.d.ts.map +1 -0
- package/dist/server/multipart.js +72 -0
- package/dist/server/multipart.js.map +1 -0
- package/dist/server/positions.d.ts +21 -0
- package/dist/server/positions.d.ts.map +1 -0
- package/dist/server/positions.js +79 -0
- package/dist/server/positions.js.map +1 -0
- package/dist/server/storage.d.ts +79 -0
- package/dist/server/storage.d.ts.map +1 -0
- package/dist/server/storage.js +199 -0
- package/dist/server/storage.js.map +1 -0
- package/dist/server/zip.d.ts +35 -0
- package/dist/server/zip.d.ts.map +1 -0
- package/dist/server/zip.js +190 -0
- package/dist/server/zip.js.map +1 -0
- package/dist/shared/types.d.ts +99 -0
- package/dist/shared/types.d.ts.map +1 -1
- package/package.json +9 -1
- package/dist/public/assets/index-CLP1jBWd.js +0 -1
- package/dist/public/assets/index-DxpzozYw.css +0 -1
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { ITEM_STATUSES, } from "../../shared/types.js";
|
|
3
|
+
import { HANDLED, HttpError } from "../http.js";
|
|
4
|
+
import { MAX_FILES, readMultipart } from "../multipart.js";
|
|
5
|
+
import { itemPosition } from "../positions.js";
|
|
6
|
+
import { BAMBUDDY_EXTENSIONS, FileStore, isModel, titleFromFilename, } from "../storage.js";
|
|
7
|
+
import { exportZip, extract3mfThumbnail, unpackZip, } from "../zip.js";
|
|
8
|
+
const idParam = (v, what = "id") => {
|
|
9
|
+
const n = Number(v);
|
|
10
|
+
if (!Number.isSafeInteger(n) || n <= 0)
|
|
11
|
+
throw new HttpError(400, `bad ${what}`);
|
|
12
|
+
return n;
|
|
13
|
+
};
|
|
14
|
+
const toVersion = (r, currentId) => ({
|
|
15
|
+
n: r.n,
|
|
16
|
+
filename: r.filename,
|
|
17
|
+
ext: r.ext,
|
|
18
|
+
size: Number(r.size),
|
|
19
|
+
sha256: r.sha256,
|
|
20
|
+
comment: r.comment,
|
|
21
|
+
uploadedAt: r.uploaded_at.toISOString(),
|
|
22
|
+
uploadedBy: r.uploaded_by,
|
|
23
|
+
hasThumbnail: r.has_thumbnail,
|
|
24
|
+
current: r.id === currentId,
|
|
25
|
+
});
|
|
26
|
+
const toItem = (r) => {
|
|
27
|
+
const current = r.v_n === null
|
|
28
|
+
? null
|
|
29
|
+
: {
|
|
30
|
+
n: r.v_n,
|
|
31
|
+
filename: r.v_filename,
|
|
32
|
+
ext: r.v_ext,
|
|
33
|
+
size: Number(r.v_size),
|
|
34
|
+
sha256: r.v_sha256,
|
|
35
|
+
comment: r.v_comment,
|
|
36
|
+
uploadedAt: r.v_uploaded_at.toISOString(),
|
|
37
|
+
uploadedBy: r.v_uploaded_by,
|
|
38
|
+
hasThumbnail: r.v_has_thumbnail ?? false,
|
|
39
|
+
current: true,
|
|
40
|
+
};
|
|
41
|
+
return {
|
|
42
|
+
id: Number(r.id),
|
|
43
|
+
queueId: Number(r.queue_id),
|
|
44
|
+
position: Number(r.position),
|
|
45
|
+
title: r.title,
|
|
46
|
+
status: r.status,
|
|
47
|
+
statusChangedAt: r.status_changed_at.toISOString(),
|
|
48
|
+
needsConfirm: r.needs_confirm,
|
|
49
|
+
notes: r.notes,
|
|
50
|
+
sourceUrl: r.source_url,
|
|
51
|
+
versionCount: r.version_count,
|
|
52
|
+
current,
|
|
53
|
+
sendable: current !== null && BAMBUDDY_EXTENSIONS.has(current.ext),
|
|
54
|
+
bambuddyFileId: r.bambuddy_file_id,
|
|
55
|
+
bambuddySentAt: r.bambuddy_sent_at?.toISOString() ?? null,
|
|
56
|
+
deletedAt: r.deleted_at?.toISOString() ?? null,
|
|
57
|
+
createdAt: r.created_at.toISOString(),
|
|
58
|
+
createdBy: r.created_by,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/** Items matching `where` (a fragment over alias i), in list order. */
|
|
62
|
+
const selectItems = (db, where) => db `
|
|
63
|
+
SELECT i.*,
|
|
64
|
+
(SELECT count(*)::int FROM backlog.version vc WHERE vc.item_id = i.id) AS version_count,
|
|
65
|
+
v.n AS v_n, v.filename AS v_filename, v.ext AS v_ext, v.size AS v_size, v.sha256 AS v_sha256,
|
|
66
|
+
v.comment AS v_comment, v.uploaded_at AS v_uploaded_at, v.uploaded_by AS v_uploaded_by, v.has_thumbnail AS v_has_thumbnail
|
|
67
|
+
FROM backlog.item i
|
|
68
|
+
LEFT JOIN backlog.version v ON v.id = i.current_version_id
|
|
69
|
+
WHERE ${where}
|
|
70
|
+
ORDER BY i.position, i.id
|
|
71
|
+
`;
|
|
72
|
+
const loadItem = async (db, id) => {
|
|
73
|
+
const [row] = await selectItems(db, db `i.id = ${id}`);
|
|
74
|
+
if (!row)
|
|
75
|
+
throw new HttpError(404, `item ${id} not found`);
|
|
76
|
+
return toItem(row);
|
|
77
|
+
};
|
|
78
|
+
const loadDetail = async (db, id) => {
|
|
79
|
+
const item = await loadItem(db, id);
|
|
80
|
+
const [{ current_version_id: currentId } = { current_version_id: null }] = await db `
|
|
81
|
+
SELECT current_version_id FROM backlog.item WHERE id = ${id}
|
|
82
|
+
`;
|
|
83
|
+
const versions = await db `
|
|
84
|
+
SELECT * FROM backlog.version WHERE item_id = ${id} ORDER BY n DESC
|
|
85
|
+
`;
|
|
86
|
+
const alsoIn = item.current
|
|
87
|
+
? await db `
|
|
88
|
+
SELECT DISTINCT i.id, i.title FROM backlog.version v JOIN backlog.item i ON i.id = v.item_id
|
|
89
|
+
WHERE v.sha256 = ${item.current.sha256} AND i.id <> ${id} AND i.deleted_at IS NULL
|
|
90
|
+
ORDER BY i.id
|
|
91
|
+
`
|
|
92
|
+
: [];
|
|
93
|
+
return {
|
|
94
|
+
...item,
|
|
95
|
+
versions: versions.map((v) => toVersion(v, currentId)),
|
|
96
|
+
alsoIn: alsoIn.map((r) => ({ id: Number(r.id), title: r.title })),
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
const listQuery = z.object({
|
|
100
|
+
queue: z.coerce.number().int().positive().optional(),
|
|
101
|
+
status: z.enum(ITEM_STATUSES).optional(),
|
|
102
|
+
q: z.string().trim().max(200).optional(),
|
|
103
|
+
trash: z.enum(["0", "1"]).optional(),
|
|
104
|
+
});
|
|
105
|
+
/** GET /api/v1/items?queue=&status=&q=&trash=1 */
|
|
106
|
+
export const listItems = ({ sql }) => async ({ url }) => {
|
|
107
|
+
const p = listQuery.parse(Object.fromEntries(url.searchParams));
|
|
108
|
+
const conds = [
|
|
109
|
+
p.trash === "1"
|
|
110
|
+
? sql `i.deleted_at IS NOT NULL`
|
|
111
|
+
: sql `i.deleted_at IS NULL`,
|
|
112
|
+
];
|
|
113
|
+
if (p.queue)
|
|
114
|
+
conds.push(sql `i.queue_id = ${p.queue}`);
|
|
115
|
+
if (p.status)
|
|
116
|
+
conds.push(sql `i.status = ${p.status}::text::backlog.item_status`);
|
|
117
|
+
if (p.q)
|
|
118
|
+
conds.push(sql `i.title ILIKE ${"%" + p.q.replace(/[\\%_]/g, (c) => "\\" + c) + "%"}`);
|
|
119
|
+
const where = conds.reduce((acc, c) => sql `${acc} AND ${c}`);
|
|
120
|
+
return (await selectItems(sql, where)).map(toItem);
|
|
121
|
+
};
|
|
122
|
+
/** GET /api/v1/items/:id */
|
|
123
|
+
export const getItem = ({ sql }) => ({ params }) => loadDetail(sql, idParam(params.id));
|
|
124
|
+
/** GET /api/v1/items/:id/history: status changes, versions and matched prints, oldest first. */
|
|
125
|
+
export const itemHistory = ({ sql }) => async ({ params }) => {
|
|
126
|
+
const id = idParam(params.id);
|
|
127
|
+
await loadItem(sql, id);
|
|
128
|
+
const [statuses, versions, prints] = await Promise.all([
|
|
129
|
+
sql `
|
|
130
|
+
SELECT at, by, source, from_status::text AS from_status, to_status::text AS to_status, detail
|
|
131
|
+
FROM backlog.status_event WHERE item_id = ${id}
|
|
132
|
+
`,
|
|
133
|
+
sql `
|
|
134
|
+
SELECT uploaded_at, uploaded_by, n, filename FROM backlog.version WHERE item_id = ${id}
|
|
135
|
+
`,
|
|
136
|
+
sql `
|
|
137
|
+
SELECT received_at, event, printer, filename, resolution FROM backlog.print_event WHERE matched_item_id = ${id}
|
|
138
|
+
`,
|
|
139
|
+
]);
|
|
140
|
+
const entries = [
|
|
141
|
+
...statuses.map((s) => ({
|
|
142
|
+
kind: "status",
|
|
143
|
+
at: s.at.toISOString(),
|
|
144
|
+
by: s.by,
|
|
145
|
+
source: s.source,
|
|
146
|
+
from: s.from_status,
|
|
147
|
+
to: s.to_status,
|
|
148
|
+
detail: s.detail,
|
|
149
|
+
})),
|
|
150
|
+
...versions.map((v) => ({
|
|
151
|
+
kind: "version",
|
|
152
|
+
at: v.uploaded_at.toISOString(),
|
|
153
|
+
by: v.uploaded_by,
|
|
154
|
+
n: v.n,
|
|
155
|
+
filename: v.filename,
|
|
156
|
+
})),
|
|
157
|
+
...prints.map((p) => ({
|
|
158
|
+
kind: "print",
|
|
159
|
+
at: p.received_at.toISOString(),
|
|
160
|
+
event: p.event,
|
|
161
|
+
printer: p.printer,
|
|
162
|
+
filename: p.filename,
|
|
163
|
+
resolution: p.resolution,
|
|
164
|
+
})),
|
|
165
|
+
];
|
|
166
|
+
return entries.sort((a, b) => a.at.localeCompare(b.at));
|
|
167
|
+
};
|
|
168
|
+
// --- Writing ---------------------------------------------------------------------
|
|
169
|
+
/** Lock a queue row for the transaction (serialises positions in it). */
|
|
170
|
+
const lockQueue = async (tx, queueId) => {
|
|
171
|
+
const [q] = await tx `SELECT id FROM backlog.queue WHERE id = ${queueId} FOR UPDATE`;
|
|
172
|
+
if (!q)
|
|
173
|
+
throw new HttpError(404, `queue ${queueId} not found`);
|
|
174
|
+
};
|
|
175
|
+
/** Lock an item row; refuses a deleted item unless `allowDeleted`. */
|
|
176
|
+
const lockItem = async (tx, id, allowDeleted = false) => {
|
|
177
|
+
const [row] = await tx `
|
|
178
|
+
SELECT id, queue_id, status::text AS status, deleted_at, current_version_id FROM backlog.item WHERE id = ${id} FOR UPDATE
|
|
179
|
+
`;
|
|
180
|
+
if (!row)
|
|
181
|
+
throw new HttpError(404, `item ${id} not found`);
|
|
182
|
+
if (row.deleted_at && !allowDeleted)
|
|
183
|
+
throw new HttpError(409, `item ${id} is in the trash; restore it first`);
|
|
184
|
+
return {
|
|
185
|
+
queueId: Number(row.queue_id),
|
|
186
|
+
status: row.status,
|
|
187
|
+
deletedAt: row.deleted_at,
|
|
188
|
+
currentVersionId: row.current_version_id,
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
/** Where a version's preview image is stored, next to the file. */
|
|
192
|
+
export const thumbnailPath = (rel) => `${rel}.thumb.png`;
|
|
193
|
+
const insertVersion = async (tx, store, itemId, n, f, user, comment) => {
|
|
194
|
+
const rel = FileStore.relativePath(itemId, n, f.sha256, f.filename);
|
|
195
|
+
// A 3MF carries its own preview; anything else has none (no renderer here).
|
|
196
|
+
const thumbnail = f.ext === "3mf" ? await extract3mfThumbnail(f.tmpPath) : null;
|
|
197
|
+
const [v] = await tx `
|
|
198
|
+
INSERT INTO backlog.version (item_id, n, filename, ext, size, sha256, stored_path, comment, uploaded_by, has_thumbnail)
|
|
199
|
+
VALUES (${itemId}, ${n}, ${f.filename}, ${f.ext}, ${f.size}, ${f.sha256}, ${rel}, ${comment}, ${user}, ${thumbnail !== null})
|
|
200
|
+
RETURNING id
|
|
201
|
+
`;
|
|
202
|
+
// Placed inside the transaction: if it fails, the rows roll back with it.
|
|
203
|
+
await store.place(f, rel);
|
|
204
|
+
if (thumbnail)
|
|
205
|
+
await store.placeBuffer(thumbnail, thumbnailPath(rel));
|
|
206
|
+
return v.id;
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* Unpack the dropped ZIPs among `files`: every model file in them becomes
|
|
210
|
+
* one more file of the upload. All-or-nothing like the rest: on an error,
|
|
211
|
+
* every staged file is discarded.
|
|
212
|
+
*/
|
|
213
|
+
const expandZips = async (store, files) => {
|
|
214
|
+
const models = [];
|
|
215
|
+
const skipped = [];
|
|
216
|
+
const pending = [...files];
|
|
217
|
+
try {
|
|
218
|
+
while (pending.length) {
|
|
219
|
+
const f = pending.shift();
|
|
220
|
+
if (isModel(f)) {
|
|
221
|
+
models.push(f);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
const room = MAX_FILES - models.length - pending.filter(isModel).length;
|
|
225
|
+
const u = await unpackZip(store, f, Math.max(room, 0));
|
|
226
|
+
models.push(...u.models);
|
|
227
|
+
skipped.push(...u.skipped.map((name) => `${f.filename}: ${name}`));
|
|
228
|
+
}
|
|
229
|
+
if (models.length > MAX_FILES)
|
|
230
|
+
throw new HttpError(413, `at most ${MAX_FILES} model files per upload`);
|
|
231
|
+
return { models, skipped };
|
|
232
|
+
}
|
|
233
|
+
catch (e) {
|
|
234
|
+
await Promise.all([...models, ...pending].map((m) => store.discard(m)));
|
|
235
|
+
throw e;
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* POST /api/v1/queues/:id/items (multipart, field `file`, 1..50 files): one
|
|
240
|
+
* new `queued` item per file, appended in drop order, each with version 1.
|
|
241
|
+
* All or nothing: one rejected file rejects the whole upload.
|
|
242
|
+
*/
|
|
243
|
+
export const uploadItems = ({ sql, store }) => async ({ req, params, user }) => {
|
|
244
|
+
const queueId = idParam(params.id, "queue id");
|
|
245
|
+
const received = await readMultipart(req, store, { allowZip: true });
|
|
246
|
+
if (received.files.length === 0)
|
|
247
|
+
throw new HttpError(400, "no file in the upload");
|
|
248
|
+
const { models: files, skipped } = await expandZips(store, received.files);
|
|
249
|
+
try {
|
|
250
|
+
const ids = await sql.begin(async (tx) => {
|
|
251
|
+
await lockQueue(tx, queueId);
|
|
252
|
+
const out = [];
|
|
253
|
+
for (const f of files) {
|
|
254
|
+
const [last] = await tx `
|
|
255
|
+
SELECT id FROM backlog.item WHERE queue_id = ${queueId} AND deleted_at IS NULL
|
|
256
|
+
ORDER BY position DESC, id DESC LIMIT 1
|
|
257
|
+
`;
|
|
258
|
+
const position = await itemPosition(tx, queueId, last ? Number(last.id) : null, null);
|
|
259
|
+
const [item] = await tx `
|
|
260
|
+
INSERT INTO backlog.item (queue_id, position, title, created_by)
|
|
261
|
+
VALUES (${queueId}, ${position}, ${titleFromFilename(f.filename)}, ${user})
|
|
262
|
+
RETURNING id
|
|
263
|
+
`;
|
|
264
|
+
const itemId = Number(item.id);
|
|
265
|
+
const versionId = await insertVersion(tx, store, itemId, 1, f, user, null);
|
|
266
|
+
await tx `UPDATE backlog.item SET current_version_id = ${versionId} WHERE id = ${itemId}`;
|
|
267
|
+
await tx `
|
|
268
|
+
INSERT INTO backlog.status_event (item_id, from_status, to_status, by, source, detail)
|
|
269
|
+
VALUES (${itemId}, NULL, 'queued', ${user}, 'ui', ${tx.json({ created: f.filename })})
|
|
270
|
+
`;
|
|
271
|
+
out.push(itemId);
|
|
272
|
+
}
|
|
273
|
+
return out;
|
|
274
|
+
});
|
|
275
|
+
const items = await Promise.all(ids.map((id) => loadItem(sql, id)));
|
|
276
|
+
return { items, skipped };
|
|
277
|
+
}
|
|
278
|
+
catch (e) {
|
|
279
|
+
await Promise.all(files.map((f) => store.discard(f)));
|
|
280
|
+
throw e;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
/**
|
|
284
|
+
* POST /api/v1/items/:id/versions (multipart, exactly one `file`, optional
|
|
285
|
+
* field `comment`): a new version that becomes current. The same content as
|
|
286
|
+
* an existing version of the item stores nothing (`duplicate: true`).
|
|
287
|
+
*/
|
|
288
|
+
export const uploadVersion = ({ sql, store }) => async ({ req, params, user }) => {
|
|
289
|
+
const id = idParam(params.id);
|
|
290
|
+
const { files, fields } = await readMultipart(req, store);
|
|
291
|
+
if (files.length !== 1) {
|
|
292
|
+
await Promise.all(files.map((f) => store.discard(f)));
|
|
293
|
+
throw new HttpError(400, "a new version is exactly one file");
|
|
294
|
+
}
|
|
295
|
+
const f = files[0];
|
|
296
|
+
if (!isModel(f))
|
|
297
|
+
throw new HttpError(415, "a version is one model file, not a ZIP");
|
|
298
|
+
const comment = fields.comment?.trim()
|
|
299
|
+
? fields.comment.trim().slice(0, 2000)
|
|
300
|
+
: null;
|
|
301
|
+
try {
|
|
302
|
+
const { duplicate, n } = await sql.begin(async (tx) => {
|
|
303
|
+
await lockItem(tx, id);
|
|
304
|
+
const [same] = await tx `SELECT n FROM backlog.version WHERE item_id = ${id} AND sha256 = ${f.sha256}`;
|
|
305
|
+
if (same)
|
|
306
|
+
return { duplicate: true, n: same.n };
|
|
307
|
+
const [{ next } = { next: 1 }] = await tx `
|
|
308
|
+
SELECT coalesce(max(n), 0) + 1 AS next FROM backlog.version WHERE item_id = ${id}
|
|
309
|
+
`;
|
|
310
|
+
const versionId = await insertVersion(tx, store, id, next, f, user, comment);
|
|
311
|
+
await tx `UPDATE backlog.item SET current_version_id = ${versionId} WHERE id = ${id}`;
|
|
312
|
+
return { duplicate: false, n: next };
|
|
313
|
+
});
|
|
314
|
+
if (duplicate)
|
|
315
|
+
await store.discard(f);
|
|
316
|
+
const item = await loadDetail(sql, id);
|
|
317
|
+
return {
|
|
318
|
+
item,
|
|
319
|
+
duplicate,
|
|
320
|
+
version: item.versions.find((v) => v.n === n),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
catch (e) {
|
|
324
|
+
await store.discard(f);
|
|
325
|
+
throw e;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
const versionPatch = z
|
|
329
|
+
.object({
|
|
330
|
+
comment: z.string().max(2000).nullable().optional(),
|
|
331
|
+
current: z.literal(true).optional(),
|
|
332
|
+
})
|
|
333
|
+
.strict();
|
|
334
|
+
/** PATCH /api/v1/items/:id/versions/:n: the comment, or make it the current version. */
|
|
335
|
+
export const patchVersion = ({ sql }) => async ({ params, body }) => {
|
|
336
|
+
const id = idParam(params.id);
|
|
337
|
+
const n = idParam(params.n, "version");
|
|
338
|
+
const p = versionPatch.parse(body);
|
|
339
|
+
await sql.begin(async (tx) => {
|
|
340
|
+
await lockItem(tx, id);
|
|
341
|
+
const [v] = await tx `SELECT id FROM backlog.version WHERE item_id = ${id} AND n = ${n}`;
|
|
342
|
+
if (!v)
|
|
343
|
+
throw new HttpError(404, `version ${n} of item ${id} not found`);
|
|
344
|
+
if (p.comment !== undefined)
|
|
345
|
+
await tx `UPDATE backlog.version SET comment = ${p.comment?.trim() || null} WHERE id = ${v.id}`;
|
|
346
|
+
if (p.current)
|
|
347
|
+
await tx `UPDATE backlog.item SET current_version_id = ${v.id} WHERE id = ${id}`;
|
|
348
|
+
});
|
|
349
|
+
return loadDetail(sql, id);
|
|
350
|
+
};
|
|
351
|
+
/** GET /api/v1/items/:id/versions/:n/download: the file under its original name. */
|
|
352
|
+
export const downloadVersion = ({ sql, store }) => async ({ params, res, req }) => {
|
|
353
|
+
const id = idParam(params.id);
|
|
354
|
+
const n = idParam(params.n, "version");
|
|
355
|
+
const [v] = await sql `
|
|
356
|
+
SELECT filename, size, stored_path FROM backlog.version WHERE item_id = ${id} AND n = ${n}
|
|
357
|
+
`;
|
|
358
|
+
if (!v)
|
|
359
|
+
throw new HttpError(404, `version ${n} of item ${id} not found`);
|
|
360
|
+
if (!(await store.exists(v.stored_path)))
|
|
361
|
+
throw new HttpError(410, `the file of version ${n} is missing on disk`);
|
|
362
|
+
res.writeHead(200, {
|
|
363
|
+
"Content-Type": "application/octet-stream",
|
|
364
|
+
"Content-Length": v.size,
|
|
365
|
+
"Content-Disposition": contentDisposition(v.filename),
|
|
366
|
+
"Cache-Control": "private, max-age=31536000, immutable",
|
|
367
|
+
"X-Content-Type-Options": "nosniff",
|
|
368
|
+
});
|
|
369
|
+
if (req.method === "HEAD") {
|
|
370
|
+
res.end();
|
|
371
|
+
return HANDLED;
|
|
372
|
+
}
|
|
373
|
+
await new Promise((resolve) => {
|
|
374
|
+
const s = store.read(v.stored_path);
|
|
375
|
+
s.on("error", () => {
|
|
376
|
+
res.destroy();
|
|
377
|
+
resolve();
|
|
378
|
+
});
|
|
379
|
+
res.on("close", resolve);
|
|
380
|
+
s.pipe(res);
|
|
381
|
+
});
|
|
382
|
+
return HANDLED;
|
|
383
|
+
};
|
|
384
|
+
/** attachment; an ASCII fallback plus the RFC 5987 UTF-8 name. */
|
|
385
|
+
export const contentDisposition = (filename) => {
|
|
386
|
+
const ascii = filename.replace(/[^\x20-\x7e]/g, "_").replace(/["\\]/g, "_");
|
|
387
|
+
return `attachment; filename="${ascii}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
388
|
+
};
|
|
389
|
+
const itemPatch = z
|
|
390
|
+
.object({
|
|
391
|
+
title: z.string().trim().min(1).max(300).optional(),
|
|
392
|
+
notes: z.string().max(20_000).nullable().optional(),
|
|
393
|
+
sourceUrl: z.url().max(2000).nullable().optional(),
|
|
394
|
+
status: z.enum(ITEM_STATUSES).optional(),
|
|
395
|
+
reason: z.string().trim().max(2000).optional(),
|
|
396
|
+
move: z
|
|
397
|
+
.object({
|
|
398
|
+
queueId: z.number().int().positive().optional(),
|
|
399
|
+
afterId: z.number().int().positive().nullable(),
|
|
400
|
+
})
|
|
401
|
+
.strict()
|
|
402
|
+
.optional(),
|
|
403
|
+
})
|
|
404
|
+
.strict();
|
|
405
|
+
/** PATCH /api/v1/items/:id (see ItemPatch). A status change is recorded in the history. */
|
|
406
|
+
export const patchItem = ({ sql }) => async ({ params, body, user }) => {
|
|
407
|
+
const id = idParam(params.id);
|
|
408
|
+
const p = itemPatch.parse(body);
|
|
409
|
+
if (p.reason !== undefined && p.status === undefined)
|
|
410
|
+
throw new HttpError(400, "reason: only with a status change");
|
|
411
|
+
await sql.begin(async (tx) => {
|
|
412
|
+
const item = await lockItem(tx, id);
|
|
413
|
+
if (p.title !== undefined)
|
|
414
|
+
await tx `UPDATE backlog.item SET title = ${p.title} WHERE id = ${id}`;
|
|
415
|
+
if (p.notes !== undefined)
|
|
416
|
+
await tx `UPDATE backlog.item SET notes = ${p.notes?.trim() || null} WHERE id = ${id}`;
|
|
417
|
+
if (p.sourceUrl !== undefined)
|
|
418
|
+
await tx `UPDATE backlog.item SET source_url = ${p.sourceUrl} WHERE id = ${id}`;
|
|
419
|
+
if (p.status !== undefined && p.status !== item.status) {
|
|
420
|
+
await tx `
|
|
421
|
+
UPDATE backlog.item
|
|
422
|
+
SET status = ${p.status}::text::backlog.item_status, status_changed_at = now(), needs_confirm = false
|
|
423
|
+
WHERE id = ${id}
|
|
424
|
+
`;
|
|
425
|
+
await tx `
|
|
426
|
+
INSERT INTO backlog.status_event (item_id, from_status, to_status, by, source, detail)
|
|
427
|
+
VALUES (${id}, ${item.status}::text::backlog.item_status, ${p.status}::text::backlog.item_status, ${user}, 'ui',
|
|
428
|
+
${p.reason ? tx.json({ reason: p.reason }) : null})
|
|
429
|
+
`;
|
|
430
|
+
}
|
|
431
|
+
if (p.move) {
|
|
432
|
+
const target = p.move.queueId ?? item.queueId;
|
|
433
|
+
if (p.move.afterId === id)
|
|
434
|
+
throw new HttpError(400, "an item cannot follow itself");
|
|
435
|
+
// Lock in id order, so two moves between the same queues cannot deadlock.
|
|
436
|
+
for (const q of [...new Set([item.queueId, target])].sort((a, b) => a - b))
|
|
437
|
+
await lockQueue(tx, q);
|
|
438
|
+
const position = await itemPosition(tx, target, p.move.afterId, id);
|
|
439
|
+
await tx `UPDATE backlog.item SET queue_id = ${target}, position = ${position} WHERE id = ${id}`;
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
return loadDetail(sql, id);
|
|
443
|
+
};
|
|
444
|
+
/** DELETE /api/v1/items/:id: to the trash (rows and files stay until the purge). */
|
|
445
|
+
export const deleteItem = ({ sql }) => async ({ params }) => {
|
|
446
|
+
const id = idParam(params.id);
|
|
447
|
+
await sql.begin(async (tx) => {
|
|
448
|
+
await lockItem(tx, id);
|
|
449
|
+
await tx `UPDATE backlog.item SET deleted_at = now() WHERE id = ${id}`;
|
|
450
|
+
});
|
|
451
|
+
return loadItem(sql, id);
|
|
452
|
+
};
|
|
453
|
+
/** POST /api/v1/items/:id/restore: back from the trash, at the end of its queue. */
|
|
454
|
+
export const restoreItem = ({ sql }) => async ({ params }) => {
|
|
455
|
+
const id = idParam(params.id);
|
|
456
|
+
await sql.begin(async (tx) => {
|
|
457
|
+
const item = await lockItem(tx, id, true);
|
|
458
|
+
if (!item.deletedAt)
|
|
459
|
+
return;
|
|
460
|
+
await lockQueue(tx, item.queueId);
|
|
461
|
+
const [last] = await tx `
|
|
462
|
+
SELECT id FROM backlog.item WHERE queue_id = ${item.queueId} AND deleted_at IS NULL
|
|
463
|
+
ORDER BY position DESC, id DESC LIMIT 1
|
|
464
|
+
`;
|
|
465
|
+
const position = await itemPosition(tx, item.queueId, last ? Number(last.id) : null, id);
|
|
466
|
+
await tx `UPDATE backlog.item SET deleted_at = NULL, position = ${position} WHERE id = ${id}`;
|
|
467
|
+
});
|
|
468
|
+
return loadItem(sql, id);
|
|
469
|
+
};
|
|
470
|
+
/** GET /api/v1/items/:id/versions/:n/thumbnail: the 3MF's preview PNG, or 404. */
|
|
471
|
+
export const versionThumbnail = ({ sql, store }) => async ({ params, res, req }) => {
|
|
472
|
+
const id = idParam(params.id);
|
|
473
|
+
const n = idParam(params.n, "version");
|
|
474
|
+
const [v] = await sql `
|
|
475
|
+
SELECT stored_path, has_thumbnail FROM backlog.version WHERE item_id = ${id} AND n = ${n}
|
|
476
|
+
`;
|
|
477
|
+
if (!v?.has_thumbnail)
|
|
478
|
+
throw new HttpError(404, "no thumbnail");
|
|
479
|
+
const rel = thumbnailPath(v.stored_path);
|
|
480
|
+
if (!(await store.exists(rel)))
|
|
481
|
+
throw new HttpError(404, "no thumbnail");
|
|
482
|
+
const data = await new Promise((resolve, reject) => {
|
|
483
|
+
const chunks = [];
|
|
484
|
+
store
|
|
485
|
+
.read(rel)
|
|
486
|
+
.on("data", (c) => chunks.push(c))
|
|
487
|
+
.on("end", () => resolve(Buffer.concat(chunks)))
|
|
488
|
+
.on("error", reject);
|
|
489
|
+
});
|
|
490
|
+
res.writeHead(200, {
|
|
491
|
+
"Content-Type": "image/png",
|
|
492
|
+
"Content-Length": data.length,
|
|
493
|
+
// Write-once: the image of a version never changes.
|
|
494
|
+
"Cache-Control": "private, max-age=31536000, immutable",
|
|
495
|
+
"X-Content-Type-Options": "nosniff",
|
|
496
|
+
});
|
|
497
|
+
res.end(req.method === "HEAD" ? undefined : data);
|
|
498
|
+
return HANDLED;
|
|
499
|
+
};
|
|
500
|
+
const exportQuery = z.object({
|
|
501
|
+
status: z.enum(ITEM_STATUSES).optional(),
|
|
502
|
+
});
|
|
503
|
+
/**
|
|
504
|
+
* GET /api/v1/queues/:id/export.zip?status=queued: the current version of
|
|
505
|
+
* every item in the queue (trash excluded), in list order, as one ZIP built
|
|
506
|
+
* while it is sent. Items whose file is missing on disk are left out.
|
|
507
|
+
*/
|
|
508
|
+
export const exportQueue = ({ sql, store }) => async ({ params, url, res, req }) => {
|
|
509
|
+
const queueId = idParam(params.id, "queue id");
|
|
510
|
+
const p = exportQuery.parse(Object.fromEntries(url.searchParams));
|
|
511
|
+
const [queue] = await sql `SELECT name FROM backlog.queue WHERE id = ${queueId}`;
|
|
512
|
+
if (!queue)
|
|
513
|
+
throw new HttpError(404, `queue ${queueId} not found`);
|
|
514
|
+
const rows = await sql `
|
|
515
|
+
SELECT v.filename, v.stored_path, v.ext, v.uploaded_at
|
|
516
|
+
FROM backlog.item i JOIN backlog.version v ON v.id = i.current_version_id
|
|
517
|
+
WHERE i.queue_id = ${queueId} AND i.deleted_at IS NULL
|
|
518
|
+
${p.status ? sql `AND i.status = ${p.status}::text::backlog.item_status` : sql ``}
|
|
519
|
+
ORDER BY i.position, i.id
|
|
520
|
+
`;
|
|
521
|
+
const files = [];
|
|
522
|
+
for (const r of rows)
|
|
523
|
+
if (await store.exists(r.stored_path))
|
|
524
|
+
files.push({
|
|
525
|
+
name: r.filename,
|
|
526
|
+
relPath: r.stored_path,
|
|
527
|
+
ext: r.ext,
|
|
528
|
+
mtime: r.uploaded_at,
|
|
529
|
+
});
|
|
530
|
+
const name = `${queue.name}${p.status ? `-${p.status}` : ""}.zip`;
|
|
531
|
+
res.writeHead(200, {
|
|
532
|
+
"Content-Type": "application/zip",
|
|
533
|
+
"Content-Disposition": contentDisposition(name),
|
|
534
|
+
"Cache-Control": "no-store",
|
|
535
|
+
"X-Content-Type-Options": "nosniff",
|
|
536
|
+
});
|
|
537
|
+
if (req.method === "HEAD") {
|
|
538
|
+
res.end();
|
|
539
|
+
return HANDLED;
|
|
540
|
+
}
|
|
541
|
+
await new Promise((resolve) => {
|
|
542
|
+
const zip = exportZip(store, files);
|
|
543
|
+
zip.on("error", () => {
|
|
544
|
+
res.destroy();
|
|
545
|
+
resolve();
|
|
546
|
+
});
|
|
547
|
+
res.on("close", resolve);
|
|
548
|
+
zip.pipe(res);
|
|
549
|
+
});
|
|
550
|
+
return HANDLED;
|
|
551
|
+
};
|
|
552
|
+
//# sourceMappingURL=items.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"items.js","sourceRoot":"","sources":["../../../src/server/api/items.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { type QueueSummary } from "../../shared/types.js";
|
|
2
2
|
import type { Sql } from "../db.js";
|
|
3
|
+
import { type Ctx } from "../http.js";
|
|
3
4
|
/** GET /api/v1/queues: every queue with its item counts per status (deleted items excluded). */
|
|
4
5
|
export declare const listQueues: (sql: Sql) => () => Promise<QueueSummary[]>;
|
|
6
|
+
/** POST /api/v1/queues {name, autoStatus?, afterId?}: a new queue, last unless afterId says otherwise. */
|
|
7
|
+
export declare const createQueue: (sql: Sql) => ({ body }: Ctx) => Promise<QueueSummary>;
|
|
8
|
+
/** PATCH /api/v1/queues/:id {name?, autoStatus?, afterId?} */
|
|
9
|
+
export declare const patchQueue: (sql: Sql) => ({ params, body }: Ctx) => Promise<QueueSummary>;
|
|
10
|
+
/**
|
|
11
|
+
* DELETE /api/v1/queues/:id: only an empty queue (its trash included), and
|
|
12
|
+
* never the last one.
|
|
13
|
+
*/
|
|
14
|
+
export declare const deleteQueue: (sql: Sql) => ({ params }: Ctx) => Promise<{
|
|
15
|
+
deleted: number;
|
|
16
|
+
}>;
|
|
5
17
|
//# sourceMappingURL=queues.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queues.d.ts","sourceRoot":"","sources":["../../../src/server/api/queues.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"queues.d.ts","sourceRoot":"","sources":["../../../src/server/api/queues.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,KAAK,GAAG,EAAa,MAAM,YAAY,CAAC;AAGjD,gGAAgG;AAChG,eAAO,MAAM,UAAU,GAAI,KAAK,GAAG,WAAe,OAAO,CAAC,YAAY,EAAE,CAqCvE,CAAC;AAuBF,0GAA0G;AAC1G,eAAO,MAAM,WAAW,GACrB,KAAK,GAAG,MACF,UAAU,GAAG,KAAG,OAAO,CAAC,YAAY,CAoB1C,CAAC;AAEJ,8DAA8D;AAC9D,eAAO,MAAM,UAAU,GACpB,KAAK,GAAG,MACF,kBAAkB,GAAG,KAAG,OAAO,CAAC,YAAY,CAmBlD,CAAC;AAEJ;;;GAGG;AACH,eAAO,MAAM,WAAW,GACrB,KAAK,GAAG,MACF,YAAY,GAAG,KAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAsBnD,CAAC"}
|