Fix requeue: fallback to finding_ids_json when queue items are deleted or absent
The requeue endpoint now handles three scenarios: 1. Original queue items still exist — uses their finding data (ideal case) 2. Queue items deleted (Clear Completed) — looks up findings from ivanti_findings table using finding_ids_json 3. FP created outside dashboard (no queue_item_ids) — same fallback to finding_ids_json and ivanti_findings lookup 4. Last resort — creates queue items with just finding IDs if the findings aren't in ivanti_findings either
This commit is contained in:
@@ -1004,27 +1004,53 @@ function createIvantiFpWorkflowRouter() {
|
|||||||
let queueItemIds = [];
|
let queueItemIds = [];
|
||||||
try {
|
try {
|
||||||
queueItemIds = JSON.parse(submission.queue_item_ids_json || '[]');
|
queueItemIds = JSON.parse(submission.queue_item_ids_json || '[]');
|
||||||
} catch (e) {
|
} catch (e) { /* ignore parse errors */ }
|
||||||
return res.status(400).json({ error: 'Could not parse queue_item_ids_json.' });
|
|
||||||
|
// Parse finding IDs (always available, even for submissions created outside dashboard)
|
||||||
|
let findingIds = [];
|
||||||
|
try {
|
||||||
|
findingIds = JSON.parse(submission.finding_ids_json || '[]');
|
||||||
|
} catch (e) { /* ignore */ }
|
||||||
|
|
||||||
|
if ((!Array.isArray(queueItemIds) || queueItemIds.length === 0) &&
|
||||||
|
(!Array.isArray(findingIds) || findingIds.length === 0)) {
|
||||||
|
return res.status(400).json({ error: 'No findings associated with this submission.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(queueItemIds) || queueItemIds.length === 0) {
|
// Fetch original queue items to get finding data (if they still exist)
|
||||||
return res.status(400).json({ error: 'No queue items associated with this submission.' });
|
let findingsToQueue = [];
|
||||||
}
|
if (queueItemIds.length > 0) {
|
||||||
|
|
||||||
// Fetch original queue items to get finding data
|
|
||||||
const { rows: originalItems } = await pool.query(
|
const { rows: originalItems } = await pool.query(
|
||||||
`SELECT finding_id, finding_title, cves_json, ip_address, hostname FROM ivanti_todo_queue WHERE id = ANY($1)`,
|
`SELECT finding_id, finding_title, cves_json, ip_address, hostname FROM ivanti_todo_queue WHERE id = ANY($1)`,
|
||||||
[queueItemIds]
|
[queueItemIds]
|
||||||
);
|
);
|
||||||
|
findingsToQueue = originalItems;
|
||||||
|
}
|
||||||
|
|
||||||
if (originalItems.length === 0) {
|
// Fallback: if original queue items were deleted or never existed,
|
||||||
return res.status(400).json({ error: 'No original queue items found for this submission.' });
|
// use finding_ids_json to look up finding data from ivanti_findings
|
||||||
|
if (findingsToQueue.length === 0 && findingIds.length > 0) {
|
||||||
|
const { rows: findings } = await pool.query(
|
||||||
|
`SELECT id AS finding_id, title AS finding_title, cves AS cves_json, ip_address, host_name AS hostname FROM ivanti_findings WHERE id = ANY($1)`,
|
||||||
|
[findingIds.map(String)]
|
||||||
|
);
|
||||||
|
findingsToQueue = findings;
|
||||||
|
|
||||||
|
// Last resort: create items with just the finding IDs (minimal data)
|
||||||
|
if (findingsToQueue.length === 0) {
|
||||||
|
findingsToQueue = findingIds.map(id => ({
|
||||||
|
finding_id: String(id),
|
||||||
|
finding_title: null,
|
||||||
|
cves_json: null,
|
||||||
|
ip_address: null,
|
||||||
|
hostname: null,
|
||||||
|
}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// INSERT new pending queue items for each finding
|
// INSERT new pending queue items for each finding
|
||||||
const newItems = [];
|
const newItems = [];
|
||||||
for (const item of originalItems) {
|
for (const item of findingsToQueue) {
|
||||||
const { rows: inserted } = await pool.query(
|
const { rows: inserted } = await pool.query(
|
||||||
`INSERT INTO ivanti_todo_queue
|
`INSERT INTO ivanti_todo_queue
|
||||||
(user_id, finding_id, finding_title, cves_json, ip_address, hostname, vendor, workflow_type)
|
(user_id, finding_id, finding_title, cves_json, ip_address, hostname, vendor, workflow_type)
|
||||||
@@ -1042,12 +1068,12 @@ function createIvantiFpWorkflowRouter() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Audit log (fire-and-forget)
|
// Audit log (fire-and-forget)
|
||||||
const finding_ids = originalItems.map(i => i.finding_id).filter(Boolean);
|
const auditFindingIds = findingsToQueue.map(i => i.finding_id).filter(Boolean);
|
||||||
logAudit({
|
logAudit({
|
||||||
userId: req.user.id, username: req.user.username,
|
userId: req.user.id, username: req.user.username,
|
||||||
action: 'fp_submission_requeued', entityType: 'ivanti_fp_submissions',
|
action: 'fp_submission_requeued', entityType: 'ivanti_fp_submissions',
|
||||||
entityId: String(submission.id),
|
entityId: String(submission.id),
|
||||||
details: { target_workflow_type: workflow_type, items_created: newItems.length, finding_ids },
|
details: { target_workflow_type: workflow_type, items_created: newItems.length, finding_ids: auditFindingIds },
|
||||||
ipAddress: req.ip
|
ipAddress: req.ip
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user