import { db, id, now, visibleClause } from '../db.js'; import { normalizeRunPlanPayload } from '../forms/schemas.js'; import { camelRunPlan } from './mappers.js'; import { filterVisibleHostIds } from './hostModel.js'; import { filterVisibleHostGroupIds } from './hostGroupModel.js'; export function listRunPlans(userId) { return db.prepare(` SELECT r.*, s.name AS script_name, g.name AS group_name, (SELECT COUNT(DISTINCT host_id) FROM ( SELECT rh.host_id AS host_id FROM runplan_hosts rh WHERE rh.runplan_id = r.id UNION SELECT hgm.host_id AS host_id FROM runplan_host_groups rhg JOIN host_group_members hgm ON hgm.host_group_id = rhg.host_group_id WHERE rhg.runplan_id = r.id )) AS host_count, (SELECT COUNT(*) FROM runplan_host_groups rhg WHERE rhg.runplan_id = r.id) AS host_group_count FROM runplans r JOIN scripts s ON s.id = r.script_id LEFT JOIN groups g ON g.id = r.group_id WHERE ${visibleClause('r')} ORDER BY r.updated_at DESC `).all(userId, userId).map(camelRunPlan); } export function createRunPlan(body, userId) { const payload = normalizeRunPlanPayload(body); const runplanId = id('run'); db.prepare(` INSERT INTO runplans (id, name, description, script_id, visibility, owner_user_id, group_id, parallel, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `).run(runplanId, payload.name, payload.description, payload.scriptId, payload.visibility, userId, payload.groupId, payload.parallel ? 1 : 0, now(), now()); replaceRunPlanHosts(runplanId, filterVisibleHostIds(payload.hostIds, userId)); replaceRunPlanHostGroups(runplanId, filterVisibleHostGroupIds(payload.hostGroupIds, userId)); return loadRunPlan(runplanId); } export function loadRunPlan(runplanId) { const runplan = db.prepare(` SELECT r.*, s.name AS script_name, g.name AS group_name, (SELECT COUNT(DISTINCT host_id) FROM ( SELECT rh.host_id AS host_id FROM runplan_hosts rh WHERE rh.runplan_id = r.id UNION SELECT hgm.host_id AS host_id FROM runplan_host_groups rhg JOIN host_group_members hgm ON hgm.host_group_id = rhg.host_group_id WHERE rhg.runplan_id = r.id )) AS host_count, (SELECT COUNT(*) FROM runplan_host_groups rhg WHERE rhg.runplan_id = r.id) AS host_group_count FROM runplans r JOIN scripts s ON s.id = r.script_id LEFT JOIN groups g ON g.id = r.group_id WHERE r.id = ? `).get(runplanId); if (!runplan) return null; const hostIds = db.prepare('SELECT host_id FROM runplan_hosts WHERE runplan_id = ? ORDER BY host_id').all(runplanId).map((row) => row.host_id); const hostGroupIds = db.prepare('SELECT host_group_id FROM runplan_host_groups WHERE runplan_id = ? ORDER BY host_group_id').all(runplanId).map((row) => row.host_group_id); return { ...camelRunPlan(runplan), hostIds, hostGroupIds }; } export function loadVisibleRunPlan(runplanId, userId) { const visible = db.prepare(`SELECT id FROM runplans WHERE id = ? AND ${visibleClause()}`).get(runplanId, userId, userId); return visible ? loadRunPlan(runplanId) : null; } export function updateRunPlan(runplanId, body, userId) { const existing = db.prepare(`SELECT * FROM runplans WHERE id = ? AND ${visibleClause()}`).get(runplanId, userId, userId); if (!existing) return null; const payload = normalizeRunPlanPayload({ ...existing, ...body, hostIds: body.hostIds || undefined, hostGroupIds: body.hostGroupIds || undefined }); db.prepare(` UPDATE runplans SET name = ?, description = ?, script_id = ?, visibility = ?, group_id = ?, parallel = ?, updated_at = ? WHERE id = ? `).run(payload.name, payload.description, payload.scriptId, payload.visibility, payload.groupId, payload.parallel ? 1 : 0, now(), runplanId); if (body.hostIds) replaceRunPlanHosts(runplanId, filterVisibleHostIds(payload.hostIds, userId)); if (body.hostGroupIds) replaceRunPlanHostGroups(runplanId, filterVisibleHostGroupIds(payload.hostGroupIds, userId)); return loadRunPlan(runplanId); } export function deleteRunPlan(runplanId, userId) { db.prepare(`DELETE FROM runplans WHERE id = ? AND ${visibleClause()}`).run(runplanId, userId, userId); } function replaceRunPlanHosts(runplanId, hostIds) { db.prepare('DELETE FROM runplan_hosts WHERE runplan_id = ?').run(runplanId); const stmt = db.prepare('INSERT OR IGNORE INTO runplan_hosts (runplan_id, host_id) VALUES (?, ?)'); for (const hostId of hostIds) stmt.run(runplanId, hostId); } function replaceRunPlanHostGroups(runplanId, hostGroupIds) { db.prepare('DELETE FROM runplan_host_groups WHERE runplan_id = ?').run(runplanId); const stmt = db.prepare('INSERT OR IGNORE INTO runplan_host_groups (runplan_id, host_group_id) VALUES (?, ?)'); for (const groupId of hostGroupIds) stmt.run(runplanId, groupId); }