Update API to improve customer management and access control.

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/ed62e9a4-d893-4126-a108-546d113b5c99.jpg
This commit is contained in:
alphaeusmote
2025-04-12 00:43:52 +00:00
+99 -36
View File
@@ -677,6 +677,29 @@ export async function registerRoutes(app: Express): Promise<Server> {
} }
}); });
// Legacy endpoint for backward compatibility
app.get("/api/organizations", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
try {
const customers = await storage.getCustomers();
res.json(customers);
} catch (error) {
console.error("Error fetching customers:", error);
res.status(500).json({ message: "Internal server error" });
}
});
// Get all customers
app.get("/api/customers", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
try {
const customers = await storage.getCustomers();
res.json(customers);
} catch (error) {
console.error("Error fetching customers:", error);
res.status(500).json({ message: "Internal server error" });
}
});
// Delete a customer
app.delete("/api/customers/:id", requireRole(["admin"]), async (req, res) => { app.delete("/api/customers/:id", requireRole(["admin"]), async (req, res) => {
try { try {
const deleted = await storage.deleteCustomer(req.params.id); const deleted = await storage.deleteCustomer(req.params.id);
@@ -685,20 +708,9 @@ export async function registerRoutes(app: Express): Promise<Server> {
return res.status(404).json({ message: "Customer not found" }); return res.status(404).json({ message: "Customer not found" });
} }
// For backward compatibility - maintain the old API endpoints
app.get("/api/organizations", requireRole(["admin", "manager", "user", "readonly"]), async (req, res) => {
try {
const customers = await storage.getCustomers();
res.json(customers);
} catch (error) {
console.error("Error fetching organizations (customers):", error);
res.status(500).json({ message: "Internal server error" });
}
});
res.status(204).end(); res.status(204).end();
} catch (error) { } catch (error) {
console.error("Error deleting organization:", error); console.error("Error deleting customer:", error);
res.status(500).json({ message: "Internal server error" }); res.status(500).json({ message: "Internal server error" });
} }
}); });
@@ -1133,9 +1145,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
return res.status(404).json({ message: "API token not found" }); return res.status(404).json({ message: "API token not found" });
} }
// Verify permission: only admin can modify any token, managers can only modify their org's tokens // Verify permission: admins can modify any token, managers can only modify tokens for customers they have access to
if (req.user?.role !== "admin" && token.organizationId !== req.user?.organizationId) { if (req.user?.role !== "admin") {
return res.status(403).json({ message: "Insufficient permissions" }); // Get the customers the user has access to
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
const userCustomerIds = userCustomers.map(c => c.id);
// Get the customers this token has access to
const tokenCustomerAccess = await storage.getApiTokenCustomerAccess(token.id);
const tokenCustomerIds = tokenCustomerAccess.map(a => a.customerId);
// Check if user has access to any of the same customers as the token
const hasAccess = tokenCustomerIds.some(id => userCustomerIds.includes(id));
if (!hasAccess) {
return res.status(403).json({ message: "Insufficient permissions" });
}
} }
// Validate permissions // Validate permissions
@@ -1182,9 +1207,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
return res.status(404).json({ message: "API token not found" }); return res.status(404).json({ message: "API token not found" });
} }
// Verify permission: only admin can modify any token, managers can only modify their org's tokens // Verify permission: admins can modify any token, managers can only modify tokens for customers they have access to
if (req.user?.role !== "admin" && token.organizationId !== req.user?.organizationId) { if (req.user?.role !== "admin") {
return res.status(403).json({ message: "Insufficient permissions" }); // Get the customers the user has access to
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
const userCustomerIds = userCustomers.map(c => c.id);
// Get the customers this token has access to
const tokenCustomerAccess = await storage.getApiTokenCustomerAccess(token.id);
const tokenCustomerIds = tokenCustomerAccess.map(a => a.customerId);
// Check if user has access to any of the same customers as the token
const hasAccess = tokenCustomerIds.some(id => userCustomerIds.includes(id));
if (!hasAccess) {
return res.status(403).json({ message: "Insufficient permissions" });
}
} }
// For PATCH, we'll allow a simpler validation specifically for isActive status changes // For PATCH, we'll allow a simpler validation specifically for isActive status changes
@@ -1226,9 +1264,22 @@ export async function registerRoutes(app: Express): Promise<Server> {
return res.status(404).json({ message: "API token not found" }); return res.status(404).json({ message: "API token not found" });
} }
// Verify permission: only admin can delete any token, managers can only delete their org's tokens // Verify permission: admins can delete any token, managers can only delete tokens for customers they have access to
if (req.user?.role !== "admin" && token.organizationId !== req.user?.organizationId) { if (req.user?.role !== "admin") {
return res.status(403).json({ message: "Insufficient permissions" }); // Get the customers the user has access to
const userCustomers = await storage.getUserCustomers(req.user?.id || "");
const userCustomerIds = userCustomers.map(c => c.id);
// Get the customers this token has access to
const tokenCustomerAccess = await storage.getApiTokenCustomerAccess(token.id);
const tokenCustomerIds = tokenCustomerAccess.map(a => a.customerId);
// Check if user has access to any of the same customers as the token
const hasAccess = tokenCustomerIds.some(id => userCustomerIds.includes(id));
if (!hasAccess) {
return res.status(403).json({ message: "Insufficient permissions" });
}
} }
const deleted = await storage.deleteApiToken(id); const deleted = await storage.deleteApiToken(id);
@@ -1378,26 +1429,38 @@ export async function registerRoutes(app: Express): Promise<Server> {
return res.status(403).json({ message: "Insufficient permissions" }); return res.status(403).json({ message: "Insufficient permissions" });
} }
let webhooks; let webhooks = [];
const orgId = req.query.organizationId as string; const customerId = req.query.customerId as string;
if (orgId) { if (customerId) {
// For specific organization, check if user belongs to that org // For specific customer, check if user has access to that customer
if (userRole !== "admin" && req.user?.organizationId !== orgId) { if (userRole !== "admin") {
return res.status(403).json({ message: "Insufficient permissions" }); const userCustomers = await storage.getUserCustomers(req.user?.id || "");
const userCustomerIds = userCustomers.map(c => c.id);
if (!userCustomerIds.includes(customerId)) {
return res.status(403).json({ message: "Insufficient permissions" });
}
} }
webhooks = await storage.getWebhooksByOrganization(orgId);
webhooks = await storage.getWebhooksByCustomer(customerId);
} else if (userRole === "admin") { } else if (userRole === "admin") {
// Admins can see all webhooks // Admins can see all webhooks
const allOrgs = await storage.getOrganizations(); const allCustomers = await storage.getCustomers();
webhooks = await Promise.all( const webhookArrays = await Promise.all(
allOrgs.map(org => storage.getWebhooksByOrganization(org.id)) allCustomers.map(customer => storage.getWebhooksByCustomer(customer.id))
).then(results => results.flat()); );
webhooks = webhookArrays.flat();
} else { } else {
// Others can only see webhooks for their organization // Others can only see webhooks for customers they have access to
webhooks = req.user?.organizationId const userCustomers = await storage.getUserCustomers(req.user?.id || "");
? await storage.getWebhooksByOrganization(req.user.organizationId)
: []; if (userCustomers.length > 0) {
const webhookArrays = await Promise.all(
userCustomers.map(customer => storage.getWebhooksByCustomer(customer.id))
);
webhooks = webhookArrays.flat();
}
} }
res.json(webhooks); res.json(webhooks);