From 3bb5305872ed250636a4017775f8f0cb535397f5 Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Fri, 11 Apr 2025 20:03:33 +0000 Subject: [PATCH] Add user-customer assignment management API endpoints. 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/f61cca86-ab28-414a-8579-18e14f115a0f.jpg --- server/routes.simplified.ts | 433 +++++++++++++++++++++++++++++++++++- 1 file changed, 432 insertions(+), 1 deletion(-) diff --git a/server/routes.simplified.ts b/server/routes.simplified.ts index d0ba98b..02974b9 100644 --- a/server/routes.simplified.ts +++ b/server/routes.simplified.ts @@ -4,7 +4,16 @@ 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"; +import { + insertCustomerSchema, + insertDomainSchema, + insertDnsRecordSchema, + insertCustomerUserAssignmentSchema, + insertProviderSchema, + insertDomainCredentialsSchema, + insertApiTokenSchema, + insertCustomRoleSchema +} from "@shared/schema"; export async function registerRoutes(app: Express): Promise { // Create HTTP server @@ -323,6 +332,428 @@ export async function registerRoutes(app: Express): Promise { res.status(500).json({ message: "Internal server error" }); } }); + + // Customer-User Assignment routes - for managing user access to customers + app.get("/api/customer-users", requireRole(["admin", "manager"]), async (req, res) => { + try { + const { customerId, userId } = req.query; + + let assignments = []; + if (customerId) { + // Get all users assigned to a specific customer + assignments = await storage.getCustomerUsers(customerId as string); + } else if (userId) { + // Get all customers assigned to a specific user + assignments = await storage.getUserCustomers(userId as string); + } else { + return res.status(400).json({ message: "Either customerId or userId query parameter is required" }); + } + + res.json(assignments); + } catch (error) { + console.error("Error getting customer-user assignments:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/customer-users", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertCustomerUserAssignmentSchema.parse(req.body); + const assignment = await storage.assignUserToCustomer(validatedData); + res.status(201).json(assignment); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating customer-user assignment:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/customer-users", requireRole(["admin"]), async (req, res) => { + try { + const { customerId, userId, role } = req.body; + + if (!customerId || !userId || !role) { + return res.status(400).json({ message: "customerId, userId, and role are required" }); + } + + const assignment = await storage.updateUserCustomerRole(customerId, userId, role); + if (!assignment) { + return res.status(404).json({ message: "Customer-user assignment not found" }); + } + + res.json(assignment); + } catch (error) { + console.error("Error updating customer-user role:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.delete("/api/customer-users", requireRole(["admin"]), async (req, res) => { + try { + const { customerId, userId } = req.query; + + if (!customerId || !userId) { + return res.status(400).json({ message: "customerId and userId query parameters are required" }); + } + + const success = await storage.removeUserFromCustomer(customerId as string, userId as string); + if (!success) { + return res.status(404).json({ message: "Customer-user assignment not found" }); + } + + res.status(204).end(); + } catch (error) { + console.error("Error deleting customer-user assignment:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + // Provider routes + app.get("/api/providers", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const providers = await storage.getProviders(); + res.json(providers); + } catch (error) { + console.error("Error getting providers:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.get("/api/providers/:id", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => { + try { + const provider = await storage.getProvider(req.params.id); + if (!provider) { + return res.status(404).json({ message: "Provider not found" }); + } + res.json(provider); + } catch (error) { + console.error("Error getting provider:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/providers", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertProviderSchema.parse(req.body); + const provider = await storage.createProvider(validatedData); + res.status(201).json(provider); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating provider:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/providers/:id", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertProviderSchema.partial().parse(req.body); + const provider = await storage.updateProvider(req.params.id, validatedData); + if (!provider) { + return res.status(404).json({ message: "Provider not found" }); + } + res.json(provider); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating provider:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.delete("/api/providers/:id", requireRole(["admin"]), async (req, res) => { + try { + const success = await storage.deleteProvider(req.params.id); + if (!success) { + return res.status(404).json({ message: "Provider not found" }); + } + res.status(204).end(); + } catch (error) { + console.error("Error deleting provider:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + // Domain Credentials routes + app.get("/api/domain-credentials/:domainId", requireRole(["admin", "manager"]), async (req, res) => { + try { + const credentials = await storage.getDomainCredentials(req.params.domainId); + if (!credentials) { + return res.status(404).json({ message: "Domain credentials not found" }); + } + res.json(credentials); + } catch (error) { + console.error("Error getting domain credentials:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/domain-credentials", requireRole(["admin", "manager"]), async (req, res) => { + try { + const validatedData = insertDomainCredentialsSchema.parse(req.body); + const credentials = await storage.createDomainCredentials(validatedData); + res.status(201).json(credentials); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating domain credentials:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/domain-credentials/:domainId", requireRole(["admin", "manager"]), async (req, res) => { + try { + const validatedData = insertDomainCredentialsSchema.partial().parse(req.body); + const credentials = await storage.updateDomainCredentials(req.params.domainId, validatedData); + if (!credentials) { + return res.status(404).json({ message: "Domain credentials not found" }); + } + res.json(credentials); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating domain credentials:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + // API Token routes + app.get("/api/api-tokens", requireRole(["admin"]), async (req, res) => { + try { + const { customerId } = req.query; + + let tokens = []; + if (customerId) { + tokens = await storage.getApiTokensByCustomer(customerId as string); + } else { + tokens = await storage.getApiTokens(); + } + + // Mask the actual token values for security + const maskedTokens = tokens.map(token => ({ + ...token, + token: token.token ? token.token.substring(0, 6) + "************" : null + })); + + res.json(maskedTokens); + } catch (error) { + console.error("Error getting API tokens:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.get("/api/api-tokens/:id", requireRole(["admin"]), async (req, res) => { + try { + const token = await storage.getApiToken(req.params.id); + if (!token) { + return res.status(404).json({ message: "API token not found" }); + } + + // Mask the actual token value for security + const maskedToken = { + ...token, + token: token.token ? token.token.substring(0, 6) + "************" : null + }; + + res.json(maskedToken); + } catch (error) { + console.error("Error getting API token:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/api-tokens", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertApiTokenSchema.parse(req.body); + + // Add the current user as the creator if not specified + if (!validatedData.createdBy && req.user) { + validatedData.createdBy = req.user.id; + } + + const token = await storage.createApiToken(validatedData); + + // Return the full token value only once during creation + res.status(201).json(token); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating API token:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/api-tokens/:id", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertApiTokenSchema.partial().parse(req.body); + const token = await storage.updateApiToken(req.params.id, validatedData); + if (!token) { + return res.status(404).json({ message: "API token not found" }); + } + + // Mask the token value for security in the response + const maskedToken = { + ...token, + token: token.token ? token.token.substring(0, 6) + "************" : null + }; + + res.json(maskedToken); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating API token:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.delete("/api/api-tokens/:id", requireRole(["admin"]), async (req, res) => { + try { + const success = await storage.deleteApiToken(req.params.id); + if (!success) { + return res.status(404).json({ message: "API token not found" }); + } + res.status(204).end(); + } catch (error) { + console.error("Error deleting API token:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + // API Token Customer Access routes + app.get("/api/api-token-access/:tokenId", requireRole(["admin"]), async (req, res) => { + try { + const access = await storage.getApiTokenCustomerAccess(req.params.tokenId); + res.json(access); + } catch (error) { + console.error("Error getting API token customer access:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/api-token-access", requireRole(["admin"]), async (req, res) => { + try { + const { tokenId, customerId } = req.body; + + if (!tokenId || !customerId) { + return res.status(400).json({ message: "tokenId and customerId are required" }); + } + + const access = await storage.addApiTokenCustomerAccess({ + tokenId, + customerId + }); + + res.status(201).json(access); + } catch (error) { + console.error("Error adding API token customer access:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.delete("/api/api-token-access", requireRole(["admin"]), async (req, res) => { + try { + const { tokenId, customerId } = req.query; + + if (!tokenId || !customerId) { + return res.status(400).json({ message: "tokenId and customerId query parameters are required" }); + } + + const success = await storage.removeApiTokenCustomerAccess(tokenId as string, customerId as string); + if (!success) { + return res.status(404).json({ message: "API token customer access not found" }); + } + + res.status(204).end(); + } catch (error) { + console.error("Error removing API token customer access:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + // Custom Roles routes + app.get("/api/custom-roles", requireRole(["admin"]), async (req, res) => { + try { + const roles = await storage.getCustomRoles(); + res.json(roles); + } catch (error) { + console.error("Error getting custom roles:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.get("/api/custom-roles/:id", requireRole(["admin"]), async (req, res) => { + try { + const role = await storage.getCustomRole(req.params.id); + if (!role) { + return res.status(404).json({ message: "Custom role not found" }); + } + res.json(role); + } catch (error) { + console.error("Error getting custom role:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); + + app.post("/api/custom-roles", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertCustomRoleSchema.parse(req.body); + const role = await storage.createCustomRole(validatedData); + res.status(201).json(role); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error creating custom role:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.put("/api/custom-roles/:id", requireRole(["admin"]), async (req, res) => { + try { + const validatedData = insertCustomRoleSchema.partial().parse(req.body); + const role = await storage.updateCustomRole(req.params.id, validatedData); + if (!role) { + return res.status(404).json({ message: "Custom role not found" }); + } + res.json(role); + } catch (error) { + if (error instanceof z.ZodError) { + res.status(400).json({ message: "Validation error", errors: error.errors }); + } else { + console.error("Error updating custom role:", error); + res.status(500).json({ message: "Internal server error" }); + } + } + }); + + app.delete("/api/custom-roles/:id", requireRole(["admin"]), async (req, res) => { + try { + const success = await storage.deleteCustomRole(req.params.id); + if (!success) { + return res.status(404).json({ message: "Custom role not found" }); + } + res.status(204).end(); + } catch (error) { + console.error("Error deleting custom role:", error); + res.status(500).json({ message: "Internal server error" }); + } + }); return httpServer; } \ No newline at end of file