Release 2.8.2
This commit is contained in:
@@ -6,6 +6,10 @@ const { createSearchMatcher, getSearchQuery, getSortDirectionQuery, getSortQuery
|
||||
|
||||
const PAGE_SIZE = 25;
|
||||
|
||||
const SORTED_AUDIT_CATEGORY_KEYS = AUDIT_CATEGORY_KEYS.slice().sort(function (left, right) {
|
||||
return String(left).localeCompare(String(right));
|
||||
});
|
||||
|
||||
function requireAuditLogAccess(setAuthMessageCookie) {
|
||||
return function (req, res, next) {
|
||||
if (!req.currentUser) {
|
||||
@@ -44,11 +48,109 @@ function csvCell(value) {
|
||||
return '"' + text.replace(/"/g, '""').replace(/\r?\n/g, ' ') + '"';
|
||||
}
|
||||
|
||||
function isRecord(value) {
|
||||
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
|
||||
function formatAuditValue(value) {
|
||||
if (typeof value === 'string') {
|
||||
return value;
|
||||
}
|
||||
if (value === undefined) {
|
||||
return 'undefined';
|
||||
}
|
||||
if (value === null || typeof value !== 'object') {
|
||||
return String(value);
|
||||
}
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
function isPrimitiveArray(value) {
|
||||
return Array.isArray(value) && value.every(function (item) {
|
||||
return item === null || typeof item !== 'object';
|
||||
});
|
||||
}
|
||||
|
||||
function isMissingAuditValue(value) {
|
||||
return value === null || value === '';
|
||||
}
|
||||
|
||||
function collectAuditChangeRows(previousValue, nextValue, path, rows) {
|
||||
if (isMissingAuditValue(previousValue) && isMissingAuditValue(nextValue)) {
|
||||
return;
|
||||
}
|
||||
if (isMissingAuditValue(previousValue)) {
|
||||
rows.push({ path: path + ' added', direction: 'added', from: '', to: formatAuditValue(nextValue) });
|
||||
return;
|
||||
}
|
||||
if (isMissingAuditValue(nextValue)) {
|
||||
rows.push({ path: path + ' removed', direction: 'removed', from: formatAuditValue(previousValue), to: '' });
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPrimitiveArray(previousValue) && isPrimitiveArray(nextValue)) {
|
||||
const previousItems = new Set(previousValue.map(function (item) { return JSON.stringify(item); }));
|
||||
const nextItems = new Set(nextValue.map(function (item) { return JSON.stringify(item); }));
|
||||
const removedItems = previousValue.filter(function (item) { return !nextItems.has(JSON.stringify(item)); });
|
||||
const addedItems = nextValue.filter(function (item) { return !previousItems.has(JSON.stringify(item)); });
|
||||
if (removedItems.length) {
|
||||
rows.push({ path: path + ' removed', direction: 'removed', from: formatAuditValue(removedItems), to: '' });
|
||||
}
|
||||
if (addedItems.length) {
|
||||
rows.push({ path: path + ' added', direction: 'added', from: '', to: formatAuditValue(addedItems) });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (JSON.stringify(previousValue) === JSON.stringify(nextValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isRecord(previousValue) && isRecord(nextValue)) {
|
||||
const keys = new Set(Object.keys(previousValue).concat(Object.keys(nextValue)));
|
||||
keys.forEach(function (key) {
|
||||
collectAuditChangeRows(previousValue[key], nextValue[key], path ? path + '.' + key : key, rows);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (Array.isArray(previousValue) && Array.isArray(nextValue) && previousValue.length === nextValue.length && previousValue.some(isRecord)) {
|
||||
for (let index = 0; index < previousValue.length; index += 1) {
|
||||
collectAuditChangeRows(previousValue[index], nextValue[index], path + '[' + index + ']', rows);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
rows.push({
|
||||
path: path,
|
||||
direction: 'changed',
|
||||
from: formatAuditValue(previousValue),
|
||||
to: formatAuditValue(nextValue)
|
||||
});
|
||||
}
|
||||
|
||||
function buildAuditDetailView(details) {
|
||||
if (!isRecord(details) || !isRecord(details.changes)) {
|
||||
return { hasChanges: false, changeRows: [] };
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
Object.keys(details.changes).forEach(function (key) {
|
||||
const change = details.changes[key];
|
||||
if (isRecord(change) && Object.prototype.hasOwnProperty.call(change, 'from') && Object.prototype.hasOwnProperty.call(change, 'to')) {
|
||||
collectAuditChangeRows(change.from, change.to, key, rows);
|
||||
}
|
||||
});
|
||||
return { hasChanges: rows.length > 0, changeRows: rows };
|
||||
}
|
||||
|
||||
function mapAuditRow(row, formatDashboardDate) {
|
||||
let details = '';
|
||||
let parsedDetails = null;
|
||||
if (row.details_json) {
|
||||
try {
|
||||
details = JSON.stringify(typeof row.details_json === 'string' ? JSON.parse(row.details_json) : row.details_json);
|
||||
parsedDetails = typeof row.details_json === 'string' ? JSON.parse(row.details_json) : row.details_json;
|
||||
details = JSON.stringify(parsedDetails);
|
||||
} catch (_error) {
|
||||
details = String(row.details_json);
|
||||
}
|
||||
@@ -60,7 +162,8 @@ function mapAuditRow(row, formatDashboardDate) {
|
||||
actorLabel: row.actor_name || row.actor_username || 'System',
|
||||
eventLabel: String(row.event_type || '').replace(/[._-]+/g, ' '),
|
||||
targetLabelDisplay: row.target_label || (row.target_type && row.target_id ? row.target_type + ' #' + row.target_id : ''),
|
||||
detailsDisplay: details
|
||||
detailsDisplay: details,
|
||||
auditDetailView: buildAuditDetailView(parsedDetails)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -136,7 +239,7 @@ module.exports = function registerAuditLogRoutes(app, deps) {
|
||||
active: 'audit-log',
|
||||
currentUser: req.currentUser,
|
||||
events: events,
|
||||
categories: AUDIT_CATEGORY_KEYS,
|
||||
categories: SORTED_AUDIT_CATEGORY_KEYS,
|
||||
eventTypes: eventTypes,
|
||||
selectedCategory: category,
|
||||
selectedEventType: eventType,
|
||||
|
||||
Reference in New Issue
Block a user