Files
poshmanager/server/models/hostModel.js
2026-06-25 16:51:56 -05:00

114 lines
4.2 KiB
JavaScript

import { db, id, json, now, parseJson, visibleClause } from '../db.js';
import { camelHost } from './mappers.js';
import { normalizeOsFamily } from '../utils/osFamily.js';
export function listHosts(userId) {
return db.prepare(`
SELECT h.*, c.name AS credential_name, g.name AS group_name, vc.name AS source_connection_name
FROM hosts h
LEFT JOIN credentials c ON c.id = h.credential_id
LEFT JOIN groups g ON g.id = h.group_id
LEFT JOIN vcenter_connections vc ON vc.id = h.source_connection_id
WHERE ${visibleClause('h')}
ORDER BY h.name
`).all(userId, userId).map(camelHost);
}
function scopedGroupId(payload) {
return payload.visibility === 'group' ? payload.groupId || null : null;
}
export function createHost(payload, userId) {
const hostId = id('hst');
db.prepare(`
INSERT INTO hosts (id, name, fqdn, address, os_family, transport, port, credential_id, tags, notes,
visibility, owner_user_id, group_id, source_type, source_connection_id, source_ref,
created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
hostId,
payload.name,
payload.fqdn || '',
payload.address,
normalizeOsFamily(payload.osFamily, 'windows'),
payload.transport,
payload.port || null,
payload.credentialId || null,
json(payload.tags),
payload.notes || '',
payload.visibility || 'shared',
userId,
scopedGroupId(payload),
payload.sourceType || 'manual',
payload.sourceConnectionId || null,
payload.sourceRef || '',
now(),
now()
);
return camelHost(db.prepare('SELECT * FROM hosts WHERE id = ?').get(hostId));
}
export function findVisibleHostByIdentity(payload, userId) {
const values = [payload.name, payload.address, payload.fqdn]
.map((value) => String(value || '').trim().toLowerCase())
.filter(Boolean);
if (!values.length) return null;
const placeholders = values.map(() => '?').join(', ');
const row = db.prepare(`
SELECT *
FROM hosts
WHERE ${visibleClause()}
AND (
lower(name) IN (${placeholders})
OR lower(address) IN (${placeholders})
OR lower(coalesce(fqdn, '')) IN (${placeholders})
)
LIMIT 1
`).get(userId, userId, ...values, ...values, ...values);
return row ? camelHost(row) : null;
}
export function updateHost(hostId, payload, userId) {
const existing = db.prepare(`SELECT * FROM hosts WHERE id = ? AND ${visibleClause()}`).get(hostId, userId, userId);
if (!existing) return null;
const visibility = payload.visibility || existing.visibility;
db.prepare(`
UPDATE hosts
SET name = ?, fqdn = ?, address = ?, os_family = ?, transport = ?, port = ?, credential_id = ?,
tags = ?, notes = ?, visibility = ?, group_id = ?, source_type = ?, source_connection_id = ?, source_ref = ?, updated_at = ?
WHERE id = ?
`).run(
payload.name || existing.name,
payload.fqdn ?? existing.fqdn,
payload.address || existing.address,
normalizeOsFamily(payload.osFamily ?? existing.os_family, 'windows'),
payload.transport || existing.transport,
payload.port ?? existing.port,
payload.credentialId ?? existing.credential_id,
json(payload.tags ?? parseJson(existing.tags)),
payload.notes ?? existing.notes,
visibility,
visibility === 'group' ? (payload.groupId ?? existing.group_id) : null,
payload.sourceType ?? existing.source_type ?? 'manual',
payload.sourceConnectionId ?? existing.source_connection_id,
payload.sourceRef ?? existing.source_ref ?? '',
now(),
hostId
);
return camelHost(db.prepare('SELECT * FROM hosts WHERE id = ?').get(hostId));
}
export function deleteHost(hostId, userId) {
db.prepare(`DELETE FROM hosts WHERE id = ? AND ${visibleClause()}`).run(hostId, userId, userId);
}
// Return only the host IDs from the requested set that are visible to the user.
// Used to stop a RunPlan from targeting hosts the operator cannot see.
export function filterVisibleHostIds(hostIds = [], userId) {
if (!hostIds.length) return [];
const visible = new Set(
db.prepare(`SELECT id FROM hosts WHERE ${visibleClause()}`).all(userId, userId).map((row) => row.id)
);
return hostIds.filter((hostId) => visible.has(hostId));
}