Files
leave-agent/src/index.ts
purvarao 1ecaf8ff95
Some checks failed
Cloudflare Worker API Template / Deploy to ${{ github.ref_name }} environment (pull_request) Failing after 15s
api
2025-11-27 19:14:46 +05:30

206 lines
6.3 KiB
TypeScript

import { Hono } from 'hono';
import { cors } from 'hono/cors';
import { getCookie } from 'hono/cookie';
import { Context } from 'hono';
import { decryptAuthCookie } from './services/decrypt-service';
import { handleSwaggerRequest } from './swagger-ui';
import { authMiddleware } from './middleware/auth';
import { saveUserData, getUserByUid } from './services/db-service';
// Create a new Hono app
const app = new Hono();
// Add middleware
app.use('*', async (c, next) => {
console.log(`[${c.req.method}] ${c.req.url}`);
await next();
});
// Add CORS middleware
app.use('*', cors());
// Create a group for protected routes with auth middleware
// Exclude Swagger docs routes from auth middleware
app.use('/api/leave-agent/*', async (c, next) => {
const path = new URL(c.req.url).pathname;
// Skip auth for Swagger docs routes
if (path.includes('/docs') || path.includes('/swagger.json') || path.includes('/openapi.json')) {
return next();
}
// Apply auth middleware for all other routes
return authMiddleware(c, next);
});
// Add auth validation endpoint (GET method)
app.get('/api/leave-agent/auth/validate', async (c) => {
try {
// Get auth from query parameter
const authToken = c.req.query('auth');
if (!authToken) {
return c.json({ error: 'No auth parameter found' }, 401);
}
// Decrypt the auth token
const decryptedData = await decryptAuthCookie(authToken, c.env);
// Check if the decrypted data contains the expected fields
if (!decryptedData || !decryptedData.firstname || !decryptedData.lastname) {
console.error('Invalid decrypted data format:', decryptedData);
return c.json({ error: 'Invalid auth parameter' }, 401);
}
return c.json(decryptedData, 200);
} catch (error) {
console.error('Authentication error:', error);
return c.json({ error: 'Authentication failed' }, 500);
}
});
// Add auth validation endpoint (POST method)
app.post('/api/leave-agent/auth/validate', async (c) => {
try {
// Get auth from request body
const body = await c.req.json();
const authToken = body.auth;
if (!authToken) {
return c.json({ error: 'No auth parameter found in request body' }, 401);
}
// Decrypt the auth token
const decryptedData = await decryptAuthCookie(authToken, c.env);
// Check if the decrypted data contains the expected fields
if (!decryptedData || !decryptedData.firstname || !decryptedData.lastname) {
console.error('Invalid decrypted data format:', decryptedData);
return c.json({ error: 'Invalid auth parameter' }, 401);
}
return c.json(decryptedData, 200);
} catch (error) {
console.error('Authentication error:', error);
return c.json({ error: 'Authentication failed' }, 500);
}
});
// Define types for the user data
interface UserData {
id: number;
uid: string;
email: string;
firstname?: string;
lastname?: string;
company_name?: string;
created_at: string;
updated_at: string;
}
// Define types for the context
interface UserContext extends Context {
get: (key: string) => string | undefined;
env: {
CF_TEMPLATE_DB?: any; // Replace 'any' with proper D1Database type if available
};
}
// Get current user's profile with leave balances
app.get('/api/leave-agent/employees/me', async (c: UserContext) => {
try {
// Get user ID from the auth middleware
const userId = c.get('userId');
if (!userId) {
return c.json({ error: 'User not authenticated' }, 401);
}
// Get user data from the database
const userData = await getUserByUid(userId, c.env);
if (!userData) {
return c.json({ error: 'User not found' }, 404);
}
// TODO: Replace with actual leave balance calculation from your database
// This is a mock implementation
const leaveBalances = {
"Annual Leave": 24,
"Maternity Leave": 182,
"Paternity Leave": 0,
"Bereavement Leave": 5,
"Marriage Leave": 5
};
// Format the response
const response = {
id: userData.id,
name: `${userData.firstname || ''} ${userData.lastname || ''}`.trim(),
email: userData.email,
color: '#3b82f6', // Default color, can be customized per user
leaveBalances: leaveBalances
};
return c.json(response);
} catch (error) {
console.error('Error fetching user profile:', error);
return c.json({ error: 'Failed to fetch user profile' }, 500);
}
});
// Add endpoint to decrypt and save cookie data to D1 database
app.post('/api/leave-agent/auth/decrypt-and-save', async (c) => {
try {
// Get auth token from request body
const body = await c.req.json();
const authToken = body.auth;
if (!authToken) {
return c.json({ error: 'No auth parameter found in request body' }, 401);
}
// Decrypt the auth token
const decryptedData = await decryptAuthCookie(authToken, c.env);
// Check if the decrypted data contains the expected fields
if (!decryptedData || !decryptedData.uid || !decryptedData.email) {
console.error('Invalid decrypted data format:', decryptedData);
return c.json({ error: 'Invalid auth parameter' }, 401);
}
// Save the decrypted data to the D1 database
const result = await saveUserData(decryptedData, c.env);
if (!result.success) {
return c.json({ error: result.error || 'Failed to save user data' }, 500);
}
// Return success response with the saved data
return c.json({
success: true,
message: result.message,
updated: result.updated,
uid: result.uid,
userData: decryptedData
}, 200);
} catch (error) {
console.error('Error processing request:', error);
return c.json({ error: 'Failed to process request', details: error.message }, 500);
}
});
// Add health check endpoint
app.get('/api/leave-agent/health', (c) => {
return c.json({ status: 'ok' });
});
// Add Swagger UI routes
app.get('/api/leave-agent/docs', (c) => handleSwaggerRequest(c.req.raw, '/api/leave-agent'));
app.get('/api/leave-agent/docs/', (c) => handleSwaggerRequest(c.req.raw, '/api/leave-agent'));
app.get('/api/leave-agent/swagger.json', (c) => handleSwaggerRequest(c.req.raw, '/api/leave-agent'));
app.get('/api/leave-agent/openapi.json', (c) => handleSwaggerRequest(c.req.raw, '/api/leave-agent'));
// Export the app
export default {
fetch: app.fetch,
};