This commit is contained in:
2026-06-25 12:05:53 -05:00
commit b58e50e423
141 changed files with 28190 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
import { db, id, now, visibleClause } from '../db.js';
import { applicationSchema } from '../forms/schemas.js';
import { evaluateUpdateState } from '../services/appVersionService.js';
function camelApplication(row) {
if (!row) return null;
const base = {
id: row.id,
name: row.name,
vendor: row.vendor || '',
publisher: row.publisher || '',
currentVersion: row.current_version || '',
latestKnownVersion: row.latest_known_version || '',
versionSource: row.version_source || 'manual',
versionSourceRef: row.version_source_ref || '',
graphConnectionId: row.graph_connection_id || null,
currentGraphAppId: row.current_graph_app_id || '',
autoCheck: Boolean(row.auto_check),
lastCheckedAt: row.last_checked_at || '',
lastCheckMessage: row.last_check_message || '',
notes: row.notes || '',
visibility: row.visibility,
ownerUserId: row.owner_user_id,
groupId: row.group_id,
groupName: row.group_name || null,
deploymentCount: row.deployment_count ?? 0,
createdAt: row.created_at,
updatedAt: row.updated_at
};
// Surface the computed update state so callers don't re-derive it.
base.updateState = evaluateUpdateState(base);
return base;
}
function scopedGroupId(payload) {
return payload.visibility === 'group' ? payload.groupId || null : null;
}
export function listApplications(userId) {
return db.prepare(`
SELECT a.*, g.name AS group_name,
(SELECT COUNT(*) FROM intune_deployments d WHERE d.application_id = a.id) AS deployment_count
FROM applications a
LEFT JOIN groups g ON g.id = a.group_id
WHERE ${visibleClause('a')}
ORDER BY a.name
`).all(userId, userId).map(camelApplication);
}
export function loadApplication(applicationId, userId) {
const row = db.prepare(`
SELECT a.*, g.name AS group_name,
(SELECT COUNT(*) FROM intune_deployments d WHERE d.application_id = a.id) AS deployment_count
FROM applications a
LEFT JOIN groups g ON g.id = a.group_id
WHERE a.id = ? AND ${visibleClause('a')}
`).get(applicationId, userId, userId);
return camelApplication(row);
}
export function createApplication(body, userId) {
const payload = applicationSchema.parse(body);
const applicationId = id('app');
db.prepare(`
INSERT INTO applications (
id, name, vendor, publisher, current_version, latest_known_version, version_source,
version_source_ref, graph_connection_id, current_graph_app_id, auto_check, notes,
visibility, owner_user_id, group_id, created_by, created_at, updated_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`).run(
applicationId,
payload.name,
payload.vendor,
payload.publisher,
payload.currentVersion,
payload.latestKnownVersion,
payload.versionSource,
payload.versionSourceRef,
payload.graphConnectionId || null,
payload.currentGraphAppId,
payload.autoCheck ? 1 : 0,
payload.notes,
payload.visibility,
userId,
scopedGroupId(payload),
userId,
now(),
now()
);
return loadApplication(applicationId, userId);
}
export function updateApplication(applicationId, body, userId) {
const existing = loadApplication(applicationId, userId);
if (!existing) return null;
const payload = applicationSchema.parse({ ...existing, ...body });
db.prepare(`
UPDATE applications
SET name = ?, vendor = ?, publisher = ?, current_version = ?, latest_known_version = ?,
version_source = ?, version_source_ref = ?, graph_connection_id = ?, current_graph_app_id = ?,
auto_check = ?, notes = ?, visibility = ?, group_id = ?, updated_at = ?
WHERE id = ?
`).run(
payload.name,
payload.vendor,
payload.publisher,
payload.currentVersion,
payload.latestKnownVersion,
payload.versionSource,
payload.versionSourceRef,
payload.graphConnectionId || null,
payload.currentGraphAppId,
payload.autoCheck ? 1 : 0,
payload.notes,
payload.visibility,
scopedGroupId(payload),
now(),
applicationId
);
return loadApplication(applicationId, userId);
}
export function deleteApplication(applicationId, userId) {
db.prepare(`DELETE FROM applications WHERE id = ? AND ${visibleClause()}`).run(applicationId, userId, userId);
}
// Record the outcome of an upstream version check on the catalog entry.
export function recordVersionCheck(applicationId, userId, { latestKnownVersion, message }) {
const existing = loadApplication(applicationId, userId);
if (!existing) return null;
applyVersionCheck(applicationId, { latestKnownVersion: latestKnownVersion ?? existing.latestKnownVersion, message });
return loadApplication(applicationId, userId);
}
// System-level write used by the background worker (no visibility scope).
export function applyVersionCheck(applicationId, { latestKnownVersion, message }) {
db.prepare(`
UPDATE applications
SET latest_known_version = COALESCE(?, latest_known_version), last_checked_at = ?, last_check_message = ?, updated_at = ?
WHERE id = ?
`).run(latestKnownVersion ?? null, now(), message || '', now(), applicationId);
}
// Applications opted into automatic upstream version checks. System context.
export function listAutoCheckApplications() {
return db.prepare('SELECT * FROM applications WHERE auto_check = 1').all().map(camelApplication);
}