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
This commit is contained in:
alphaeusmote
2025-04-11 20:03:33 +00:00
parent e268c997a9
commit 3bb5305872
+432 -1
View File
@@ -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<Server> {
// Create HTTP server
@@ -323,6 +332,428 @@ export async function registerRoutes(app: Express): Promise<Server> {
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;
}