Password Policy/App rename/PM Scheduling Improvements

This commit is contained in:
2026-06-06 02:32:47 -05:00
parent dfd999b6a9
commit f024286b5e
59 changed files with 3814 additions and 299 deletions

View File

@@ -129,11 +129,18 @@ function categoryRow(row) {
const meta = parseJson(row.metadata, {});
const templateId = meta.id_template_id || null;
const template = templateId ? one('SELECT name, pattern FROM asset_id_templates WHERE id = ?', [templateId]) : null;
// Categories link to an asset class by its unique id (class numbers are NOT unique — e.g. 00.12
// covers both Computers and Casinos). The number/label are resolved from the linked class so the
// right one is always shown; a manually-typed number (no id) falls back to that text.
const classId = meta.asset_class_id || null;
const cls = classId ? one('SELECT id, class_number, description FROM asset_classes WHERE id = ?', [classId]) : null;
return {
id: row.id,
name: row.name,
code: row.code,
asset_class_number: meta.asset_class_number || null,
asset_class_id: cls ? cls.id : null,
asset_class_number: cls ? cls.class_number : (meta.asset_class_number || null),
asset_class_label: cls ? `${cls.class_number}${cls.description}` : null,
id_template_id: template ? templateId : null,
id_template_name: template ? template.name : null,
id_template_pattern: template ? template.pattern : null,
@@ -141,6 +148,20 @@ function categoryRow(row) {
};
}
// Resolve the class number a category should carry: the linked class's number wins; otherwise a
// manually-entered number. Returns { classId, classNumber }.
function resolveCategoryClass(body, prev = {}) {
if (body.asset_class_id !== undefined && body.asset_class_id !== null && body.asset_class_id !== '') {
const cls = one('SELECT class_number FROM asset_classes WHERE id = ?', [body.asset_class_id]);
if (cls) return { classId: Number(body.asset_class_id), classNumber: cls.class_number };
}
// Explicit null id, or a manual number with no id → manual override (clears the link).
if (body.asset_class_id === null || body.asset_class_id === '' || body.asset_class_number !== undefined) {
return { classId: null, classNumber: body.asset_class_number || null };
}
return { classId: prev.asset_class_id || null, classNumber: prev.asset_class_number || null };
}
const categoryEditor = requireCapability('config.manage');
router.get('/asset-categories', (req, res) => {
@@ -154,9 +175,10 @@ router.post('/asset-categories', categoryEditor, (req, res) => {
if (one("SELECT id FROM reference_values WHERE type = 'category' AND name = ?", [name])) {
return res.status(400).json({ error: 'That category already exists' });
}
const { classId, classNumber } = resolveCategoryClass(req.body);
const result = run(
"INSERT INTO reference_values (type, name, code, metadata) VALUES ('category', ?, ?, ?)",
[name, req.body.code || null, json({ id_template_id: req.body.id_template_id || null, asset_class_number: req.body.asset_class_number || null })]
[name, req.body.code || null, json({ id_template_id: req.body.id_template_id || null, asset_class_id: classId, asset_class_number: classNumber })]
);
audit(req.user.id, 'create', 'asset_category', result.lastInsertRowid, null, { name });
return res.status(201).json({ category: categoryRow(one('SELECT * FROM reference_values WHERE id = ?', [result.lastInsertRowid])) });
@@ -172,14 +194,19 @@ router.put('/asset-categories/:id', categoryEditor, (req, res) => {
}
const meta = parseJson(before.metadata, {});
if (req.body.id_template_id !== undefined) meta.id_template_id = req.body.id_template_id || null;
if (req.body.asset_class_number !== undefined) meta.asset_class_number = req.body.asset_class_number || null;
const classChanged = req.body.asset_class_id !== undefined || req.body.asset_class_number !== undefined;
if (classChanged) {
const resolved = resolveCategoryClass(req.body, meta);
meta.asset_class_id = resolved.classId;
meta.asset_class_number = resolved.classNumber;
}
run('UPDATE reference_values SET name = ?, code = ?, metadata = ? WHERE id = ?', [name, req.body.code ?? before.code, json(meta), req.params.id]);
let renamed = 0;
if (name !== before.name) {
renamed = run('UPDATE assets SET category = ?, updated_at = ? WHERE category = ?', [name, now(), before.name]).changes || 0;
}
// The class number is shared by every asset in the category — cascade any change.
if (req.body.asset_class_number !== undefined) {
if (classChanged) {
run('UPDATE assets SET asset_class_number = ?, updated_at = ? WHERE category = ?', [meta.asset_class_number, now(), name]);
}
audit(req.user.id, 'update', 'asset_category', req.params.id, before, { name, renamed_assets: renamed });