mirror of
https://github.com/freedbygrace/DynamoDNS.git
synced 2026-07-28 12:28:56 +00:00
Enhance webhook management by adding retry functionality, improved logging, and a new dashboard.
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/7f4a9e98-42c4-4202-9b7a-66fef8ee2905.jpg
This commit is contained in:
@@ -962,6 +962,50 @@ export async function registerRoutes(app: Express): Promise<Server> {
|
||||
res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Retry a failed webhook delivery
|
||||
app.post("/api/webhook-logs/:id/retry", requireRole(["admin", "manager"]), async (req, res) => {
|
||||
try {
|
||||
const log = await storage.getWebhookDeliveryLog(req.params.id);
|
||||
|
||||
if (!log) {
|
||||
return res.status(404).json({ message: "Webhook delivery log not found" });
|
||||
}
|
||||
|
||||
// Need to get the webhook to check permissions and retry
|
||||
const webhook = await storage.getWebhook(log.webhookId);
|
||||
|
||||
if (!webhook) {
|
||||
return res.status(404).json({ message: "Associated webhook not found" });
|
||||
}
|
||||
|
||||
// Permission check
|
||||
if (req.user?.role !== "admin" && webhook.organizationId !== req.user?.organizationId) {
|
||||
return res.status(403).json({ message: "Not authorized to retry this webhook" });
|
||||
}
|
||||
|
||||
// Only retry failed deliveries
|
||||
if (log.status) {
|
||||
return res.status(400).json({ message: "Cannot retry successful webhook delivery" });
|
||||
}
|
||||
|
||||
// Retry the webhook with the original payload but increment retry count
|
||||
const retrySuccess = await storage.triggerWebhook(
|
||||
webhook.id,
|
||||
log.payload,
|
||||
log.retryCount + 1
|
||||
);
|
||||
|
||||
if (retrySuccess) {
|
||||
res.status(200).json({ message: "Webhook delivery retried successfully" });
|
||||
} else {
|
||||
res.status(500).json({ message: "Failed to retry webhook delivery" });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error retrying webhook delivery:", error);
|
||||
res.status(500).json({ message: "Internal server error" });
|
||||
}
|
||||
});
|
||||
|
||||
return httpServer;
|
||||
}
|
||||
|
||||
+10
-6
@@ -69,7 +69,7 @@ export interface IStorage {
|
||||
createWebhook(webhook: InsertWebhook): Promise<Webhook>;
|
||||
updateWebhook(id: string, webhook: Partial<InsertWebhook>): Promise<Webhook | undefined>;
|
||||
deleteWebhook(id: string): Promise<boolean>;
|
||||
triggerWebhook(webhookId: string, payload: any): Promise<boolean>;
|
||||
triggerWebhook(webhookId: string, payload: any, retryCount?: number): Promise<boolean>;
|
||||
|
||||
// Webhook Delivery Logs
|
||||
addWebhookDeliveryLog(log: InsertWebhookDeliveryLog): Promise<WebhookDeliveryLog>;
|
||||
@@ -503,7 +503,7 @@ export class MemStorage implements IStorage {
|
||||
return this.webhooksMap.delete(parseInt(id));
|
||||
}
|
||||
|
||||
async triggerWebhook(webhookId: string, payload: any): Promise<boolean> {
|
||||
async triggerWebhook(webhookId: string, payload: any, retryCount: number = 0): Promise<boolean> {
|
||||
const webhook = await this.getWebhook(webhookId);
|
||||
if (!webhook || !webhook.isActive) return false;
|
||||
|
||||
@@ -517,15 +517,19 @@ export class MemStorage implements IStorage {
|
||||
// Generate signature for the payload if a secret is set
|
||||
const signature = webhook.secret ? generateSignature(payload, webhook.secret) : '';
|
||||
|
||||
// Determine if this is a retry
|
||||
const isRetry = retryCount > 0;
|
||||
console.log(`${isRetry ? 'Retrying' : 'Triggering'} webhook delivery (attempt ${retryCount + 1})`);
|
||||
|
||||
// In a real implementation, this would make the actual HTTP request
|
||||
// For now, simulate a successful delivery
|
||||
const deliveryResult = {
|
||||
success: true,
|
||||
statusCode: 200,
|
||||
message: 'Webhook delivered successfully (simulated)',
|
||||
message: `Webhook delivered successfully (simulated)${isRetry ? ' after retry' : ''}`,
|
||||
timestamp: new Date(),
|
||||
responseBody: JSON.stringify({ success: true }),
|
||||
retryCount: 0
|
||||
retryCount: retryCount
|
||||
};
|
||||
|
||||
// Log the delivery attempt
|
||||
@@ -538,7 +542,7 @@ export class MemStorage implements IStorage {
|
||||
statusCode: deliveryResult.statusCode,
|
||||
message: deliveryResult.message,
|
||||
responseBody: deliveryResult.responseBody,
|
||||
retryCount: deliveryResult.retryCount
|
||||
retryCount
|
||||
});
|
||||
|
||||
// Update the lastTriggered timestamp
|
||||
@@ -560,7 +564,7 @@ export class MemStorage implements IStorage {
|
||||
signature: '',
|
||||
status: false,
|
||||
message: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
||||
retryCount: 0
|
||||
retryCount
|
||||
});
|
||||
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user