Files
patchmon.net/backend/src/routes/dashboardPreferencesRoutes.js
2025-10-07 22:46:55 +01:00

380 lines
8.8 KiB
JavaScript

const express = require("express");
const { body, validationResult } = require("express-validator");
const { PrismaClient } = require("@prisma/client");
const { authenticateToken } = require("../middleware/auth");
const { v4: uuidv4 } = require("uuid");
const router = express.Router();
const prisma = new PrismaClient();
// Helper function to get user permissions based on role
async function getUserPermissions(userRole) {
try {
const permissions = await prisma.role_permissions.findUnique({
where: { role: userRole },
});
// If no specific permissions found, return default admin permissions (for backward compatibility)
if (!permissions) {
console.warn(
`No permissions found for role: ${userRole}, defaulting to admin access`,
);
return {
can_view_dashboard: true,
can_view_hosts: true,
can_manage_hosts: true,
can_view_packages: true,
can_manage_packages: true,
can_view_users: true,
can_manage_users: true,
can_view_reports: true,
can_export_data: true,
can_manage_settings: true,
};
}
return permissions;
} catch (error) {
console.error("Error fetching user permissions:", error);
// Return admin permissions as fallback
return {
can_view_dashboard: true,
can_view_hosts: true,
can_manage_hosts: true,
can_view_packages: true,
can_manage_packages: true,
can_view_users: true,
can_manage_users: true,
can_view_reports: true,
can_export_data: true,
can_manage_settings: true,
};
}
}
// Helper function to create permission-based dashboard preferences for a new user
async function createDefaultDashboardPreferences(userId, userRole = "user") {
try {
// Get user's actual permissions
const permissions = await getUserPermissions(userRole);
// Define all possible dashboard cards with their required permissions
// Order aligned with preferred layout
const allCards = [
// Host-related cards
{ cardId: "totalHosts", requiredPermission: "can_view_hosts", order: 0 },
{
cardId: "hostsNeedingUpdates",
requiredPermission: "can_view_hosts",
order: 1,
},
// Package-related cards
{
cardId: "totalOutdatedPackages",
requiredPermission: "can_view_packages",
order: 2,
},
{
cardId: "securityUpdates",
requiredPermission: "can_view_packages",
order: 3,
},
// Host-related cards (continued)
{
cardId: "totalHostGroups",
requiredPermission: "can_view_hosts",
order: 4,
},
{
cardId: "upToDateHosts",
requiredPermission: "can_view_hosts",
order: 5,
},
// Repository-related cards
{ cardId: "totalRepos", requiredPermission: "can_view_hosts", order: 6 },
// User management cards (admin only)
{ cardId: "totalUsers", requiredPermission: "can_view_users", order: 7 },
// System/Report cards
{
cardId: "osDistribution",
requiredPermission: "can_view_reports",
order: 8,
},
{
cardId: "osDistributionBar",
requiredPermission: "can_view_reports",
order: 9,
},
{
cardId: "osDistributionDoughnut",
requiredPermission: "can_view_reports",
order: 10,
},
{
cardId: "recentCollection",
requiredPermission: "can_view_hosts",
order: 11,
},
{
cardId: "updateStatus",
requiredPermission: "can_view_reports",
order: 12,
},
{
cardId: "packagePriority",
requiredPermission: "can_view_packages",
order: 13,
},
{
cardId: "packageTrends",
requiredPermission: "can_view_packages",
order: 14,
},
{
cardId: "recentUsers",
requiredPermission: "can_view_users",
order: 15,
},
{
cardId: "quickStats",
requiredPermission: "can_view_dashboard",
order: 16,
},
];
// Filter cards based on user's permissions
const allowedCards = allCards.filter((card) => {
return permissions[card.requiredPermission] === true;
});
// Create preferences data
const preferencesData = allowedCards.map((card) => ({
id: uuidv4(),
user_id: userId,
card_id: card.cardId,
enabled: true,
order: card.order, // Preserve original order from allCards
created_at: new Date(),
updated_at: new Date(),
}));
await prisma.dashboard_preferences.createMany({
data: preferencesData,
});
console.log(
`Permission-based dashboard preferences created for user ${userId} with role ${userRole}: ${allowedCards.length} cards`,
);
} catch (error) {
console.error("Error creating default dashboard preferences:", error);
// Don't throw error - this shouldn't break user creation
}
}
// Get user's dashboard preferences
router.get("/", authenticateToken, async (req, res) => {
try {
const preferences = await prisma.dashboard_preferences.findMany({
where: { user_id: req.user.id },
orderBy: { order: "asc" },
});
res.json(preferences);
} catch (error) {
console.error("Dashboard preferences fetch error:", error);
res.status(500).json({ error: "Failed to fetch dashboard preferences" });
}
});
// Update dashboard preferences (bulk update)
router.put(
"/",
authenticateToken,
[
body("preferences").isArray().withMessage("Preferences must be an array"),
body("preferences.*.cardId").isString().withMessage("Card ID is required"),
body("preferences.*.enabled")
.isBoolean()
.withMessage("Enabled must be boolean"),
body("preferences.*.order").isInt().withMessage("Order must be integer"),
],
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { preferences } = req.body;
const userId = req.user.id;
// Delete existing preferences for this user
await prisma.dashboard_preferences.deleteMany({
where: { user_id: userId },
});
// Create new preferences
const newPreferences = preferences.map((pref) => ({
id: require("uuid").v4(),
user_id: userId,
card_id: pref.cardId,
enabled: pref.enabled,
order: pref.order,
updated_at: new Date(),
}));
await prisma.dashboard_preferences.createMany({
data: newPreferences,
});
res.json({
message: "Dashboard preferences updated successfully",
preferences: newPreferences,
});
} catch (error) {
console.error("Dashboard preferences update error:", error);
res.status(500).json({ error: "Failed to update dashboard preferences" });
}
},
);
// Get default dashboard card configuration
router.get("/defaults", authenticateToken, async (_req, res) => {
try {
// This provides a comprehensive dashboard view for all new users
const defaultCards = [
{
cardId: "totalHosts",
title: "Total Hosts",
icon: "Server",
enabled: true,
order: 0,
},
{
cardId: "hostsNeedingUpdates",
title: "Needs Updating",
icon: "AlertTriangle",
enabled: true,
order: 1,
},
{
cardId: "totalOutdatedPackages",
title: "Outdated Packages",
icon: "Package",
enabled: true,
order: 2,
},
{
cardId: "securityUpdates",
title: "Security Updates",
icon: "Shield",
enabled: true,
order: 3,
},
{
cardId: "totalHostGroups",
title: "Host Groups",
icon: "Folder",
enabled: true,
order: 4,
},
{
cardId: "upToDateHosts",
title: "Up to date",
icon: "CheckCircle",
enabled: true,
order: 5,
},
{
cardId: "totalRepos",
title: "Repositories",
icon: "GitBranch",
enabled: true,
order: 6,
},
{
cardId: "totalUsers",
title: "Users",
icon: "Users",
enabled: true,
order: 7,
},
{
cardId: "osDistribution",
title: "OS Distribution",
icon: "BarChart3",
enabled: true,
order: 8,
},
{
cardId: "osDistributionBar",
title: "OS Distribution (Bar)",
icon: "BarChart3",
enabled: true,
order: 9,
},
{
cardId: "osDistributionDoughnut",
title: "OS Distribution (Doughnut)",
icon: "PieChart",
enabled: true,
order: 10,
},
{
cardId: "recentCollection",
title: "Recent Collection",
icon: "Server",
enabled: true,
order: 11,
},
{
cardId: "updateStatus",
title: "Update Status",
icon: "BarChart3",
enabled: true,
order: 12,
},
{
cardId: "packagePriority",
title: "Package Priority",
icon: "BarChart3",
enabled: true,
order: 13,
},
{
cardId: "packageTrends",
title: "Package Trends",
icon: "TrendingUp",
enabled: true,
order: 14,
},
{
cardId: "recentUsers",
title: "Recent Users Logged in",
icon: "Users",
enabled: true,
order: 15,
},
{
cardId: "quickStats",
title: "Quick Stats",
icon: "TrendingUp",
enabled: true,
order: 16,
},
];
res.json(defaultCards);
} catch (error) {
console.error("Default dashboard cards error:", error);
res.status(500).json({ error: "Failed to fetch default dashboard cards" });
}
});
module.exports = { router, createDefaultDashboardPreferences };