import { applicationImportSchema, applicationSchema } from '../forms/schemas.js'; import { createApplication, deleteApplication, listApplications, loadApplication, recordVersionCheck, updateApplication } from '../models/applicationModel.js'; import { getGraphConnection } from '../models/graphModel.js'; import { getGraphMobileApp } from '../services/graphService.js'; import { fetchLatestVersion, mapGraphAppToCatalog } from '../services/appVersionService.js'; import { runCatalogChecks } from '../services/catalogWorker.js'; export function index(req, res) { res.json(listApplications(req.user.id)); } export function create(req, res) { const parsed = applicationSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid application payload' }); res.status(201).json(createApplication(parsed.data, req.user.id)); } export function show(req, res) { const application = loadApplication(req.params.id, req.user.id); if (!application) return res.status(404).json({ error: 'Application not found' }); res.json(application); } export function update(req, res) { const parsed = applicationSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'Invalid application payload' }); const application = updateApplication(req.params.id, parsed.data, req.user.id); if (!application) return res.status(404).json({ error: 'Application not found' }); res.json(application); } export function destroy(req, res) { deleteApplication(req.params.id, req.user.id); res.status(204).end(); } // Look up the upstream version from the configured source and store it. The // update state (whether a newer version exists) is recomputed on read. export async function checkUpdate(req, res) { const application = loadApplication(req.params.id, req.user.id); if (!application) return res.status(404).json({ error: 'Application not found' }); try { const result = await fetchLatestVersion(application); const updated = recordVersionCheck(req.params.id, req.user.id, { latestKnownVersion: result.version || application.latestKnownVersion, message: result.message || '' }); res.json({ application: updated, check: result }); } catch (error) { recordVersionCheck(req.params.id, req.user.id, { latestKnownVersion: application.latestKnownVersion, message: error.message }); res.status(400).json({ error: error.message }); } } // Run an upstream check for every auto-check application now (admin trigger). export async function checkAll(req, res) { try { const summary = await runCatalogChecks(); res.json({ summary, applications: listApplications(req.user.id) }); } catch (error) { res.status(400).json({ error: error.message }); } } // Adopt an existing tenant Win32 app into the catalog (migration aid). Read-only // Graph access; no write-back gate required. export async function importFromTenant(req, res) { const parsed = applicationImportSchema.safeParse(req.body); if (!parsed.success) return res.status(400).json({ error: 'connectionId and graphAppId are required' }); const connection = getGraphConnection(parsed.data.connectionId, req.user.id, true); if (!connection) return res.status(404).json({ error: 'Graph connection not found' }); try { const graphApp = await getGraphMobileApp(connection, parsed.data.graphAppId); const mapped = mapGraphAppToCatalog(graphApp); const application = createApplication({ ...mapped, graphConnectionId: parsed.data.connectionId, versionSource: 'manual', visibility: parsed.data.visibility, groupId: parsed.data.groupId, notes: `Adopted from Intune mobileApp ${parsed.data.graphAppId}.` }, req.user.id); res.status(201).json(application); } catch (error) { res.status(400).json({ error: error.message }); } }