From 7744894aa0e3b5f05d204d02d299ab567b08f0f6 Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Fri, 11 Apr 2025 19:57:53 +0000 Subject: [PATCH] Add customer management functionality to the API Replit-Commit-Author: Agent Replit-Commit-Session-Id: 9111ef36-26c8-4085-84ca-a35dc1fec1b5 Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/7083d608-d6d3-4a6a-9a27-6286c5109627/ab3b9534-4d96-4109-8be8-f8dfcfd3cfb5.jpg --- server/auth.ts | 2 +- server/routes.simplified.ts | 301 +++++++++++++++++++++++++++++++++++- 2 files changed, 301 insertions(+), 2 deletions(-) diff --git a/server/auth.ts b/server/auth.ts index 8bffc58..990048b 100644 --- a/server/auth.ts +++ b/server/auth.ts @@ -305,7 +305,7 @@ export function setupAuth(app: Express) { password: z.string().min(8).max(100), email: z.string().email(), fullName: z.string().optional(), - organizationId: z.string().uuid().optional() + customerId: z.string().uuid().optional() }); // Registration endpoint diff --git a/server/routes.simplified.ts b/server/routes.simplified.ts index 56188e1..d0ba98b 100644 --- a/server/routes.simplified.ts +++ b/server/routes.simplified.ts @@ -1,11 +1,18 @@ -import type { Express } from "express"; +import type { Express, Request } from "express"; import { createServer, type Server } from "http"; +import { storage } from "./storage"; import { getCurrentIpAddress, getCurrentIpv6Address } from "./utils/ip-utils"; +import { setupAuth, requireRole } from "./auth"; +import { z } from "zod"; +import { insertCustomerSchema, insertDomainSchema, insertDnsRecordSchema } from "@shared/schema"; export async function registerRoutes(app: Express): Promise { // Create HTTP server const httpServer = createServer(app); + // Setup authentication routes + setupAuth(app); + // Add public IP endpoint for the frontend app.get('/api/public-ip', async (req, res) => { try { @@ -24,6 +31,298 @@ export async function registerRoutes(app: Express): Promise { res.status(500).json({ error: 'Failed to get public IP address' }); } }); + + // Customer routes + app.get("/api/customers", requireRole(["admin", "manager"]), async (req, res) => { + try { + const customers = await storage.getCustomers(); + res.json(customers); + } catch (error) { + console.error("Error getting customers:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.get("/api/customers/:id", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const customer = await storage.getCustomer(req.params.id); + if (!customer) { + return res.status(404).json({ message: "Customer not found" }); + } + res.json(customer); + } catch (error) { + console.error("Error getting customer:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/customers", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertCustomerSchema.parse(req.body); + const customer = await storage.createCustomer(validatedData); + res.status(201).json(customer); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating customer:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/customers/:id", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertCustomerSchema.partial().parse(req.body); + const customer = await storage.updateCustomer(req.params.id, validatedData); + if (!customer) { + return res.status(404).json({ message: "Customer not found" }); + } + res.json(customer); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating customer:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.delete("/api/customers/:id", requireRole(["admin"]), async (req, res) => { + try { + const success = await storage.deleteCustomer(req.params.id); + if (!success) { + return res.status(404).json({ message: "Customer not found" }); + } + res.status(204).end(); + } catch (error) { + console.error("Error deleting customer:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + // Domain routes + app.get("/api/domains", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const { customerId } = req.query; + + let domains; + if (customerId) { + domains = await storage.getDomainsByCustomer(customerId as string); + } else { + domains = await storage.getAllDomains(); + } + + res.json(domains); + } catch (error) { + console.error("Error getting domains:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.get("/api/domains/:id", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const domain = await storage.getDomain(req.params.id); + if (!domain) { + return res.status(404).json({ message: "Domain not found" }); + } + res.json(domain); + } catch (error) { + console.error("Error getting domain:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/domains", requireRole(["admin", "manager"]), async (req, res) => { + try { + const validatedData = insertDomainSchema.parse(req.body); + const domain = await storage.createDomain(validatedData); + res.status(201).json(domain); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating domain:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/domains/:id", requireRole(["admin", "manager"]), async (req, res) => { + try { + const validatedData = insertDomainSchema.partial().parse(req.body); + const domain = await storage.updateDomain(req.params.id, validatedData); + if (!domain) { + return res.status(404).json({ message: "Domain not found" }); + } + res.json(domain); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating domain:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.delete("/api/domains/:id", requireRole(["admin", "manager"]), async (req, res) => { + try { + const success = await storage.deleteDomain(req.params.id); + if (!success) { + return res.status(404).json({ message: "Domain not found" }); + } + res.status(204).end(); + } catch (error) { + console.error("Error deleting domain:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + // DNS Records routes + app.get("/api/dns-records", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const { domainId } = req.query; + + if (!domainId) { + return res.status(400).json({ message: "Domain ID is required" }); + } + + const records = await storage.getDnsRecordsByDomain(domainId as string); + res.json(records); + } catch (error) { + console.error("Error getting DNS records:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.get("/api/dns-records/:id", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const record = await storage.getDnsRecord(req.params.id); + if (!record) { + return res.status(404).json({ message: "DNS record not found" }); + } + res.json(record); + } catch (error) { + console.error("Error getting DNS record:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/dns-records", requireRole(["admin", "manager", "user"]), async (req, res) => { + try { + // Validate and parse input + const validatedData = insertDnsRecordSchema.parse(req.body); + + // Special handling for AutoIP records + if (validatedData.isAutoIP) { + try { + // Get the current IPv4 address + const ipv4 = await getCurrentIpAddress(); + + // If this is an A record, update the content with the current IP + if (validatedData.type === "A") { + validatedData.content = ipv4; + } + + // If this is an AAAA record, try to get IPv6 address + if (validatedData.type === "AAAA") { + const ipv6 = await getCurrentIpv6Address(); + if (ipv6) { + validatedData.content = ipv6; + } else { + // If no IPv6 available, return an error + return res.status(400).json({ + message: "Cannot create an AAAA record with Auto IP enabled - no IPv6 address detected" + }); + } + } + } catch (ipError) { + console.error("Error getting IP for AutoIP record:", ipError); + } + } + + // Create the record + const record = await storage.createDnsRecord(validatedData); + res.status(201).json(record); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating DNS record:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/dns-records/:id", requireRole(["admin", "manager", "user"]), async (req, res) => { + try { + // Validate and parse input + const validatedData = insertDnsRecordSchema.partial().parse(req.body); + + // Special handling for AutoIP records + if (validatedData.isAutoIP) { + // Get the current record to check its type + const currentRecord = await storage.getDnsRecord(req.params.id); + if (!currentRecord) { + return res.status(404).json({ message: "DNS record not found" }); + } + + try { + // Get the current IPv4 address + const ipv4 = await getCurrentIpAddress(); + + // If this is an A record, update the content with the current IP + if (currentRecord.type === "A") { + validatedData.content = ipv4; + } + + // If this is an AAAA record, try to get IPv6 address + if (currentRecord.type === "AAAA") { + const ipv6 = await getCurrentIpv6Address(); + if (ipv6) { + validatedData.content = ipv6; + } else { + // If no IPv6 available, return an error + return res.status(400).json({ + message: "Cannot update an AAAA record with Auto IP enabled - no IPv6 address detected" + }); + } + } + } catch (ipError) { + console.error("Error getting IP for AutoIP record:", ipError); + } + } + + // Update the record + const record = await storage.updateDnsRecord(req.params.id, validatedData); + if (!record) { + return res.status(404).json({ message: "DNS record not found" }); + } + res.json(record); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating DNS record:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.delete("/api/dns-records/:id", requireRole(["admin", "manager"]), async (req, res) => { + try { + const success = await storage.deleteDnsRecord(req.params.id); + if (!success) { + return res.status(404).json({ message: "DNS record not found" }); + } + res.status(204).end(); + } catch (error) { + console.error("Error deleting DNS record:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); return httpServer; } \ No newline at end of file