Files
poshmanager/server/controllers/governanceController.js
2026-06-25 12:05:53 -05:00

61 lines
2.6 KiB
JavaScript

import { decideChangeRequest, getChangeRequest, listChangeRequests } from '../models/changeRequestModel.js';
import { getConnectionGovernance, intuneReportingOverview, listGraphAudit } from '../models/graphModel.js';
import { loadIntuneDeployment } from '../models/psadtModel.js';
import { canApprove } from '../services/graphRbac.js';
export function changeRequests(req, res) {
res.json(listChangeRequests(req.user.id, { status: req.query.status, isAdmin: req.user.role === 'admin' }));
}
// Admins can always decide; otherwise the user must be a named approver on the
// request's Graph connection.
function authorizedApprover(req, request) {
if (req.user.role === 'admin') return true;
const governance = request.connectionId ? getConnectionGovernance(request.connectionId) : null;
return canApprove({ approverIds: governance?.approverIds || [] }, req.user);
}
function decide(req, res, status) {
const request = getChangeRequest(req.params.id);
if (!request || request.status !== 'pending') return res.status(404).json({ error: 'Pending change request not found' });
if (!authorizedApprover(req, request)) return res.status(403).json({ error: 'You are not an authorized approver for this connection.' });
const decided = decideChangeRequest(req.params.id, {
status,
approverUserId: req.user.id,
approverEmail: req.user.email,
reason: req.body?.reason || ''
});
if (!decided) return res.status(404).json({ error: 'Pending change request not found' });
res.json(decided);
}
export function approveChangeRequest(req, res) {
decide(req, res, 'approved');
}
export function rejectChangeRequest(req, res) {
decide(req, res, 'rejected');
}
export function reportingOverview(req, res) {
res.json(intuneReportingOverview(req.user.id, req.user.role === 'admin'));
}
function toCsv(rows) {
const headers = ['createdAt', 'action', 'status', 'actorEmail', 'targetGraphId', 'message'];
const escape = (value) => `"${String(value ?? '').replace(/"/g, '""')}"`;
const lines = [headers.join(',')];
for (const row of rows) lines.push(headers.map((h) => escape(row[h])).join(','));
return lines.join('\n');
}
// CSV export of the tenant write-back audit trail for one deployment.
export function auditExport(req, res) {
const deployment = loadIntuneDeployment(req.params.id, req.user.id);
if (!deployment) return res.status(404).json({ error: 'Intune deployment not found' });
const rows = listGraphAudit({ deploymentId: deployment.id, limit: 1000 });
res.setHeader('Content-Type', 'text/csv; charset=utf-8');
res.setHeader('Content-Disposition', `attachment; filename="audit-${deployment.id}.csv"`);
res.send(toCsv(rows));
}