This commit is contained in:
seb
2026-10-23 22:22:30 +02:00
parent e83116c83d
commit 1a5e3f23e2
6 changed files with 141 additions and 69 deletions

View File

@@ -602,6 +602,7 @@ export function register(app, basePath = '') {
* summary: Get article history by SKU
* description: |
* Returns `articlehistory` rows for the article, newest first (`date` DESC, `id` DESC).
* Supports pagination, search filter, and date cutoff via `seekMonths`.
* Auth like GET by SKU.
* security:
* - cookieAuth: []
@@ -614,29 +615,51 @@ export function register(app, basePath = '') {
* type: string
* description: Article SKU
* - in: query
* name: offset
* schema:
* type: integer
* minimum: 0
* default: 0
* description: Paging offset
* - in: query
* name: limit
* required: false
* schema:
* type: integer
* minimum: 1
* maximum: 1000
* description: Maximum number of entries to return (newest first). Omit for all entries.
* default: 50
* description: Page size
* - in: query
* name: search
* schema:
* type: string
* description: Optional search filter for history text
* - in: query
* name: seekMonths
* schema:
* type: integer
* description: Negative integer cutoff months ago (e.g. -13)
* responses:
* 200:
* description: Article history (newest first)
* description: Paged article history list
* content:
* application/json:
* schema:
* type: object
* required: [history, truncated]
* required: [history, total, unfilteredTotal, offset, limit]
* properties:
* history:
* type: array
* items:
* $ref: '#/components/schemas/ArticleHistoryEntry'
* truncated:
* type: boolean
* description: True when a limit was applied and the result set was exactly that size (more entries may exist).
* total:
* type: integer
* unfilteredTotal:
* type: integer
* offset:
* type: integer
* limit:
* type: integer
* example:
* history:
* - id: 42
@@ -645,8 +668,12 @@ export function register(app, basePath = '') {
* - id: 41
* date: '2026-08-01T09:00:00.000Z'
* text: 'Name geändert von "" auf "Tee"'
* total: 2
* unfilteredTotal: 2
* offset: 0
* limit: 50
* 400:
* description: Missing sku
* description: Missing sku or invalid query parameters
* content:
* application/json:
* schema:
@@ -678,8 +705,19 @@ export function register(app, basePath = '') {
return res.status(400).json({ error: 'sku is required' });
}
const rawOffset = req.query.offset;
const rawLimit = req.query.limit;
let limit = null;
let offset = 0;
let limit = 50;
if (rawOffset !== undefined) {
offset = parseInt(rawOffset, 10);
if (!Number.isInteger(offset) || offset < 0) {
return res.status(400).json({ error: 'offset must be an integer >= 0' });
}
}
if (rawLimit !== undefined) {
limit = parseInt(rawLimit, 10);
if (!Number.isInteger(limit) || limit < 1 || limit > 1000) {
@@ -687,10 +725,26 @@ export function register(app, basePath = '') {
}
}
const search = typeof req.query.search === 'string' && req.query.search.trim() !== ''
? req.query.search.trim()
: undefined;
let seekMonths = undefined;
if (req.query.seekMonths !== undefined) {
seekMonths = parseInt(req.query.seekMonths, 10);
if (!Number.isInteger(seekMonths)) {
return res.status(400).json({ error: 'seekMonths must be an integer' });
}
}
try {
const history = await db.getHistoryBySku(req.user.id, decodeURIComponent(sku), limit != null ? { limit } : undefined);
const truncated = limit != null && history.length === limit;
res.status(200).json({ history, truncated });
const result = await db.getHistoryBySku(req.user.id, decodeURIComponent(sku), {
offset,
limit,
search,
seekMonths,
});
res.status(200).json(result);
} catch (error) {
const status = articleErrorStatus(error);
if (status === 500) console.error('Get article history by sku failed:', error);