Files
patchmon.net/backend/src/routes/hostGroupRoutes.js
Muhammad Ibrahim 5457a1e9bc Docker implementation
Profile fixes
Hostgroup fixes
TFA fixes
2025-10-31 15:24:53 +00:00

276 lines
6.1 KiB
JavaScript

const express = require("express");
const { body, validationResult } = require("express-validator");
const { getPrismaClient } = require("../config/prisma");
const { randomUUID } = require("node:crypto");
const { authenticateToken } = require("../middleware/auth");
const { requireManageHosts } = require("../middleware/permissions");
const router = express.Router();
const prisma = getPrismaClient();
// Get all host groups
router.get("/", authenticateToken, async (_req, res) => {
try {
const hostGroups = await prisma.host_groups.findMany({
include: {
_count: {
select: {
host_group_memberships: true,
},
},
},
orderBy: {
name: "asc",
},
});
// Transform the count field to match frontend expectations
const transformedGroups = hostGroups.map((group) => ({
...group,
_count: {
hosts: group._count.host_group_memberships,
},
}));
res.json(transformedGroups);
} catch (error) {
console.error("Error fetching host groups:", error);
res.status(500).json({ error: "Failed to fetch host groups" });
}
});
// Get a specific host group by ID
router.get("/:id", authenticateToken, async (req, res) => {
try {
const { id } = req.params;
const hostGroup = await prisma.host_groups.findUnique({
where: { id },
include: {
host_group_memberships: {
include: {
hosts: {
select: {
id: true,
friendly_name: true,
hostname: true,
ip: true,
os_type: true,
os_version: true,
status: true,
last_update: true,
},
},
},
},
},
});
if (!hostGroup) {
return res.status(404).json({ error: "Host group not found" });
}
res.json(hostGroup);
} catch (error) {
console.error("Error fetching host group:", error);
res.status(500).json({ error: "Failed to fetch host group" });
}
});
// Create a new host group
router.post(
"/",
authenticateToken,
requireManageHosts,
[
body("name").trim().isLength({ min: 1 }).withMessage("Name is required"),
body("description").optional().trim(),
body("color")
.optional()
.isHexColor()
.withMessage("Color must be a valid hex color"),
],
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { name, description, color } = req.body;
// Check if host group with this name already exists
const existingGroup = await prisma.host_groups.findUnique({
where: { name },
});
if (existingGroup) {
return res
.status(400)
.json({ error: "A host group with this name already exists" });
}
const hostGroup = await prisma.host_groups.create({
data: {
id: randomUUID(),
name,
description: description || null,
color: color || "#3B82F6",
updated_at: new Date(),
},
});
res.status(201).json(hostGroup);
} catch (error) {
console.error("Error creating host group:", error);
res.status(500).json({ error: "Failed to create host group" });
}
},
);
// Update a host group
router.put(
"/:id",
authenticateToken,
requireManageHosts,
[
body("name").trim().isLength({ min: 1 }).withMessage("Name is required"),
body("description").optional().trim(),
body("color")
.optional()
.isHexColor()
.withMessage("Color must be a valid hex color"),
],
async (req, res) => {
try {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const { id } = req.params;
const { name, description, color } = req.body;
// Check if host group exists
const existingGroup = await prisma.host_groups.findUnique({
where: { id },
});
if (!existingGroup) {
return res.status(404).json({ error: "Host group not found" });
}
// Check if another host group with this name already exists
const duplicateGroup = await prisma.host_groups.findFirst({
where: {
name,
id: { not: id },
},
});
if (duplicateGroup) {
return res
.status(400)
.json({ error: "A host group with this name already exists" });
}
const hostGroup = await prisma.host_groups.update({
where: { id },
data: {
name,
description: description || null,
color: color || "#3B82F6",
updated_at: new Date(),
},
});
res.json(hostGroup);
} catch (error) {
console.error("Error updating host group:", error);
res.status(500).json({ error: "Failed to update host group" });
}
},
);
// Delete a host group
router.delete(
"/:id",
authenticateToken,
requireManageHosts,
async (req, res) => {
try {
const { id } = req.params;
// Check if host group exists
const existingGroup = await prisma.host_groups.findUnique({
where: { id },
include: {
_count: {
select: {
host_group_memberships: true,
},
},
},
});
if (!existingGroup) {
return res.status(404).json({ error: "Host group not found" });
}
// If host group has memberships, remove them first
if (existingGroup._count.host_group_memberships > 0) {
await prisma.host_group_memberships.deleteMany({
where: { host_group_id: id },
});
}
await prisma.host_groups.delete({
where: { id },
});
res.json({ message: "Host group deleted successfully" });
} catch (error) {
console.error("Error deleting host group:", error);
res.status(500).json({ error: "Failed to delete host group" });
}
},
);
// Get hosts in a specific group
router.get("/:id/hosts", authenticateToken, async (req, res) => {
try {
const { id } = req.params;
const hosts = await prisma.hosts.findMany({
where: {
host_group_memberships: {
some: {
host_group_id: id,
},
},
},
select: {
id: true,
friendly_name: true,
ip: true,
os_type: true,
os_version: true,
architecture: true,
status: true,
last_update: true,
created_at: true,
},
orderBy: {
friendly_name: "asc",
},
});
res.json(hosts);
} catch (error) {
console.error("Error fetching hosts in group:", error);
res.status(500).json({ error: "Failed to fetch hosts in group" });
}
});
module.exports = router;