149 lines
5.2 KiB
JavaScript
149 lines
5.2 KiB
JavaScript
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);
|
|
}
|