From fbc0464b0051595c3e7dca8b370453ca937fbd73 Mon Sep 17 00:00:00 2001 From: alphaeusmote <41258468-alphaeusmote@users.noreply.replit.com> Date: Fri, 11 Apr 2025 17:33:23 +0000 Subject: [PATCH] Fix API token creation issues by improving data handling and default values. 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/61cfb37c-5c5b-400f-b068-24cfbbdc7a23.jpg --- server/routes.ts | 80 ++++++++++++++++++++++++----------------------- server/storage.ts | 49 ++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 46 deletions(-) diff --git a/server/routes.ts b/server/routes.ts index de85707..4ab0586 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -974,100 +974,102 @@ export async function registerRoutes(app: Express): Promise { // Generate a random token const tokenValue = randomBytes(32).toString('hex'); - // Extract fields from request body, with defaults where needed - const name = req.body.name || "Unnamed Token"; - const role = req.body.role || "readonly"; - const organizationId = req.body.organizationId || "1"; - const isActive = req.body.isActive !== undefined ? req.body.isActive : true; - - // Set default permissions based on the role - let permissions = []; - if (role === 'admin') { - permissions = ['admin', 'manager', 'user', 'readonly']; - } else if (role === 'manager') { - permissions = ['manager', 'user', 'readonly']; - } else if (role === 'user') { - permissions = ['user', 'readonly']; - } else { - permissions = ['readonly']; - } - - // Create token data as a plain object (bypass schema validation) - const tokenData = { - name: name, + // Get data directly from the form + let tokenData: any = { + // Required fields + name: req.body.name || "Unnamed Token", token: tokenValue, - organizationId: organizationId, - permissions: permissions, - role: role, - createdBy: req.user?.id || '1', - isActive: isActive + organizationId: req.body.organizationId || "1", + role: req.body.role || "readonly", + createdBy: req.user?.id || "1", + + // Optional fields + isActive: req.body.isActive !== undefined ? req.body.isActive : true, + permissions: [] // Will be populated in storage.ts }; - // Handle expiration date directly from form data + // Handle expiration date if (req.body.expiresIn && req.body.expiresIn !== 'never') { const now = new Date(); if (req.body.expiresIn === 'custom' && req.body.customDate) { - // For custom date/time try { + console.log("Custom date received:", req.body.customDate); + console.log("Custom time received:", req.body.customTime || "none"); + + // Create date from input const customDate = new Date(req.body.customDate); + console.log("Parsed customDate:", customDate); // If time was selected, add it to the date if (req.body.customTime) { const [hours, minutes] = req.body.customTime.split(':').map(Number); if (!isNaN(hours) && !isNaN(minutes)) { customDate.setHours(hours, minutes, 0, 0); + console.log(`Setting time to ${hours}:${minutes}`); } else { customDate.setHours(23, 59, 59, 999); + console.log("Invalid time format, setting to end of day"); } } else { customDate.setHours(23, 59, 59, 999); + console.log("No time specified, setting to end of day"); } tokenData.expiresAt = customDate; - console.log("Custom expiration date set to:", customDate); + console.log("Final custom expiration date:", customDate); } catch (e) { console.error("Error parsing custom date:", e); } } else { // For preset expiration options - let daysToAdd = 0; + let expirationDate: Date | null = null; switch (req.body.expiresIn) { case '1hour': - tokenData.expiresAt = new Date(now.getTime() + 60 * 60 * 1000); + expirationDate = new Date(now.getTime() + 60 * 60 * 1000); break; case '1day': - tokenData.expiresAt = new Date(now.getTime() + 24 * 60 * 60 * 1000); + expirationDate = new Date(now.getTime() + 24 * 60 * 60 * 1000); break; case '7days': - tokenData.expiresAt = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); + expirationDate = new Date(now.getTime() + 7 * 24 * 60 * 60 * 1000); break; case '30days': - tokenData.expiresAt = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); + expirationDate = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000); break; case '90days': - tokenData.expiresAt = new Date(now.getTime() + 90 * 24 * 60 * 60 * 1000); + expirationDate = new Date(now.getTime() + 90 * 24 * 60 * 60 * 1000); break; case '1year': - tokenData.expiresAt = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000); + expirationDate = new Date(now.getTime() + 365 * 24 * 60 * 60 * 1000); break; } + + if (expirationDate) { + tokenData.expiresAt = expirationDate; + console.log(`Setting expiration to ${req.body.expiresIn}:`, expirationDate); + } } + } else { + console.log("No expiration set (never expires)"); } - console.log("Final token data for storage:", tokenData); + console.log("Final token data for storage:", JSON.stringify(tokenData, null, 2)); - // Skip schema validation, call storage directly + // Pass data directly to storage const token = await storage.createApiToken(tokenData); + console.log("Token created successfully:", JSON.stringify(token, null, 2)); // Return the full token only on creation res.status(201).json(token); } catch (error) { console.error("Error creating API token:", error); + // Return detailed error to help debugging res.status(500).json({ message: "Error creating token", - details: error instanceof Error ? error.message : String(error) + error: error instanceof Error ? error.message : String(error), + stack: error instanceof Error ? error.stack : undefined }); } }); diff --git a/server/storage.ts b/server/storage.ts index 7d981c5..8532b4b 100644 --- a/server/storage.ts +++ b/server/storage.ts @@ -480,21 +480,56 @@ export class MemStorage implements IStorage { .filter(token => token.organizationId === organizationId); } - async createApiToken(token: InsertApiToken): Promise { + async createApiToken(token: any): Promise { + console.log("Storage createApiToken received:", JSON.stringify(token, null, 2)); const numId = this.apiTokenIdCounter++; const createdAt = new Date(); + + // Generate default permissions if none provided + let permissions: string[] = []; + if (token.permissions && Array.isArray(token.permissions)) { + permissions = token.permissions; + } else if (token.role) { + // Default permissions based on role if not explicitly provided + if (token.role === 'admin') { + permissions = ['admin', 'manager', 'user', 'readonly']; + } else if (token.role === 'manager') { + permissions = ['manager', 'user', 'readonly']; + } else if (token.role === 'user') { + permissions = ['user', 'readonly']; + } else { + permissions = ['readonly']; + } + } + + // Handle expiresAt + let expiresAt = null; + if (token.expiresAt) { + if (token.expiresAt instanceof Date) { + expiresAt = token.expiresAt; + } else if (typeof token.expiresAt === 'string') { + try { + expiresAt = new Date(token.expiresAt); + } catch (e) { + console.error("Failed to parse expiresAt date string:", token.expiresAt); + } + } + } + const newToken: ApiToken = { id: numId.toString(), - name: token.name, - token: token.token, - organizationId: token.organizationId, - permissions: token.permissions ?? null, + name: token.name || "Unnamed Token", + token: token.token || "test_token_" + numId, + organizationId: token.organizationId || "1", + permissions: permissions, role: token.role || 'readonly', - createdBy: token.createdBy, + createdBy: token.createdBy || "1", isActive: token.isActive ?? true, - expiresAt: token.expiresAt ?? null, + expiresAt: expiresAt, createdAt }; + + console.log("Storing new token:", JSON.stringify(newToken, null, 2)); this.apiTokensMap.set(numId, newToken); return newToken; }