Major Enhancement: NestJS Migration + CASL Authorization + Error Handling
Some checks failed
CI/CD Pipeline / Backend Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Tests (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
Some checks failed
CI/CD Pipeline / Backend Tests (push) Has been cancelled
CI/CD Pipeline / Frontend Tests (push) Has been cancelled
CI/CD Pipeline / Build Docker Images (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
Complete rewrite from Express to NestJS with enterprise-grade features: ## Backend Improvements - Migrated from Express to NestJS 11.0.1 with TypeScript - Implemented Prisma ORM 7.3.0 for type-safe database access - Added CASL authorization system replacing role-based guards - Created global exception filters with structured logging - Implemented Auth0 JWT authentication with Passport.js - Added vehicle management with conflict detection - Enhanced event scheduling with driver/vehicle assignment - Comprehensive error handling and logging ## Frontend Improvements - Upgraded to React 19.2.0 with Vite 7.2.4 - Implemented CASL-based permission system - Added AbilityContext for declarative permissions - Created ErrorHandler utility for consistent error messages - Enhanced API client with request/response logging - Added War Room (Command Center) dashboard - Created VIP Schedule view with complete itineraries - Implemented Vehicle Management UI - Added mock data generators for testing (288 events across 20 VIPs) ## New Features - Vehicle fleet management (types, capacity, status tracking) - Complete 3-day Jamboree schedule generation - Individual VIP schedule pages with PDF export (planned) - Real-time War Room dashboard with auto-refresh - Permission-based navigation filtering - First user auto-approval as administrator ## Documentation - Created CASL_AUTHORIZATION.md (comprehensive guide) - Created ERROR_HANDLING.md (error handling patterns) - Updated CLAUDE.md with new architecture - Added migration guides and best practices ## Technical Debt Resolved - Removed custom authentication in favor of Auth0 - Replaced role checks with CASL abilities - Standardized error responses across API - Implemented proper TypeScript typing - Added comprehensive logging Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
37
backend-old-20260125/.env.example
Normal file
37
backend-old-20260125/.env.example
Normal file
@@ -0,0 +1,37 @@
|
||||
# ============================================
|
||||
# Auth0 Configuration (NEW)
|
||||
# ============================================
|
||||
AUTH0_DOMAIN=your-tenant.us.auth0.com
|
||||
AUTH0_CLIENT_ID=your_client_id_here
|
||||
AUTH0_CLIENT_SECRET=your_client_secret_here
|
||||
AUTH0_AUDIENCE=https://vip-coordinator-api
|
||||
AUTH0_API_ID=6910ee5a03672ebf6f04fc1c
|
||||
AUTH0_CALLBACK_URL=http://localhost:3000/auth/auth0/callback
|
||||
AUTH0_LOGOUT_URL=http://localhost:5173/login
|
||||
|
||||
# ============================================
|
||||
# Application Configuration
|
||||
# ============================================
|
||||
PORT=3000
|
||||
NODE_ENV=development
|
||||
FRONTEND_URL=http://localhost:5173
|
||||
|
||||
# ============================================
|
||||
# Database Configuration
|
||||
# ============================================
|
||||
DATABASE_URL=postgresql://postgres:changeme@db:5432/vip_coordinator
|
||||
|
||||
# ============================================
|
||||
# Redis Configuration
|
||||
# ============================================
|
||||
REDIS_URL=redis://redis:6379
|
||||
|
||||
# ============================================
|
||||
# Legacy Google OAuth (REMOVE THESE)
|
||||
# These are no longer needed with Auth0
|
||||
# ============================================
|
||||
# GOOGLE_CLIENT_ID=
|
||||
# GOOGLE_CLIENT_SECRET=
|
||||
# GOOGLE_REDIRECT_URI=
|
||||
# JWT_SECRET=
|
||||
# ADMIN_PASSWORD=
|
||||
46
backend-old-20260125/Dockerfile
Normal file
46
backend-old-20260125/Dockerfile
Normal file
@@ -0,0 +1,46 @@
|
||||
# Multi-stage build for development and production
|
||||
FROM node:22-alpine AS base
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Development stage
|
||||
FROM base AS development
|
||||
RUN npm install
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["npm", "run", "dev"]
|
||||
|
||||
# Production stage
|
||||
FROM base AS production
|
||||
|
||||
# Install dependencies (including dev dependencies for build)
|
||||
RUN npm install
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN npx tsc --version && npx tsc
|
||||
|
||||
# Remove dev dependencies to reduce image size
|
||||
RUN npm prune --omit=dev
|
||||
|
||||
# Create non-root user for security
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S nodejs -u 1001
|
||||
|
||||
# Change ownership of the app directory
|
||||
RUN chown -R nodejs:nodejs /app
|
||||
USER nodejs
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node -e "require('http').get('http://localhost:3000/api/health', (res) => { process.exit(res.statusCode === 200 ? 0 : 1) })" || exit 1
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
# Start the production server
|
||||
CMD ["npm", "start"]
|
||||
4
backend-old-20260125/dist/config/database.d.ts
vendored
Normal file
4
backend-old-20260125/dist/config/database.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { Pool } from 'pg';
|
||||
declare const pool: Pool;
|
||||
export default pool;
|
||||
//# sourceMappingURL=database.d.ts.map
|
||||
1
backend-old-20260125/dist/config/database.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/config/database.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/config/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAK1B,QAAA,MAAM,IAAI,MAKR,CAAC;AAWH,eAAe,IAAI,CAAC"}
|
||||
23
backend-old-20260125/dist/config/database.js
vendored
Normal file
23
backend-old-20260125/dist/config/database.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const pg_1 = require("pg");
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
dotenv_1.default.config();
|
||||
const pool = new pg_1.Pool({
|
||||
connectionString: process.env.DATABASE_URL || 'postgresql://postgres:changeme@localhost:5432/vip_coordinator',
|
||||
max: 20,
|
||||
idleTimeoutMillis: 30000,
|
||||
connectionTimeoutMillis: 2000,
|
||||
});
|
||||
// Test the connection
|
||||
pool.on('connect', () => {
|
||||
console.log('✅ Connected to PostgreSQL database');
|
||||
});
|
||||
pool.on('error', (err) => {
|
||||
console.error('❌ PostgreSQL connection error:', err);
|
||||
});
|
||||
exports.default = pool;
|
||||
//# sourceMappingURL=database.js.map
|
||||
1
backend-old-20260125/dist/config/database.js.map
vendored
Normal file
1
backend-old-20260125/dist/config/database.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/config/database.ts"],"names":[],"mappings":";;;;;AAAA,2BAA0B;AAC1B,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,IAAI,GAAG,IAAI,SAAI,CAAC;IACpB,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,+DAA+D;IAC7G,GAAG,EAAE,EAAE;IACP,iBAAiB,EAAE,KAAK;IACxB,uBAAuB,EAAE,IAAI;CAC9B,CAAC,CAAC;AAEH,sBAAsB;AACtB,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IACtB,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;AACpD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;IACvB,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;AACvD,CAAC,CAAC,CAAC;AAEH,kBAAe,IAAI,CAAC"}
|
||||
17
backend-old-20260125/dist/config/mockDatabase.d.ts
vendored
Normal file
17
backend-old-20260125/dist/config/mockDatabase.d.ts
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
declare class MockDatabase {
|
||||
private users;
|
||||
private vips;
|
||||
private drivers;
|
||||
private scheduleEvents;
|
||||
private adminSettings;
|
||||
constructor();
|
||||
query(text: string, params?: any[]): Promise<any>;
|
||||
connect(): Promise<{
|
||||
query: (text: string, params?: any[]) => Promise<any>;
|
||||
release: () => void;
|
||||
}>;
|
||||
end(): Promise<void>;
|
||||
on(event: string, callback: Function): void;
|
||||
}
|
||||
export default MockDatabase;
|
||||
//# sourceMappingURL=mockDatabase.d.ts.map
|
||||
1
backend-old-20260125/dist/config/mockDatabase.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/config/mockDatabase.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"mockDatabase.d.ts","sourceRoot":"","sources":["../../src/config/mockDatabase.ts"],"names":[],"mappings":"AAyBA,cAAM,YAAY;IAChB,OAAO,CAAC,KAAK,CAAoC;IACjD,OAAO,CAAC,IAAI,CAAmC;IAC/C,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,aAAa,CAAkC;;IA8BjD,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC;IAiGjD,OAAO;sBAjGK,MAAM,WAAW,GAAG,EAAE,KAAG,OAAO,CAAC,GAAG,CAAC;;;IAyGjD,GAAG;IAIT,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ;CAKrC;AAED,eAAe,YAAY,CAAC"}
|
||||
137
backend-old-20260125/dist/config/mockDatabase.js
vendored
Normal file
137
backend-old-20260125/dist/config/mockDatabase.js
vendored
Normal file
@@ -0,0 +1,137 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class MockDatabase {
|
||||
constructor() {
|
||||
this.users = new Map();
|
||||
this.vips = new Map();
|
||||
this.drivers = new Map();
|
||||
this.scheduleEvents = new Map();
|
||||
this.adminSettings = new Map();
|
||||
// Add a test admin user
|
||||
const adminId = '1';
|
||||
this.users.set(adminId, {
|
||||
id: adminId,
|
||||
email: 'admin@example.com',
|
||||
name: 'Test Admin',
|
||||
role: 'admin',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
});
|
||||
// Add some test VIPs
|
||||
this.vips.set('1', {
|
||||
id: '1',
|
||||
name: 'John Doe',
|
||||
organization: 'Test Org',
|
||||
department: 'Office of Development',
|
||||
transport_mode: 'flight',
|
||||
expected_arrival: '2025-07-25 14:00',
|
||||
needs_airport_pickup: true,
|
||||
needs_venue_transport: true,
|
||||
notes: 'Test VIP',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
});
|
||||
}
|
||||
async query(text, params) {
|
||||
console.log('Mock DB Query:', text.substring(0, 50) + '...');
|
||||
// Handle user queries
|
||||
if (text.includes('COUNT(*) FROM users')) {
|
||||
return { rows: [{ count: this.users.size.toString() }] };
|
||||
}
|
||||
if (text.includes('SELECT * FROM users WHERE email')) {
|
||||
const email = params?.[0];
|
||||
const user = Array.from(this.users.values()).find(u => u.email === email);
|
||||
return { rows: user ? [user] : [] };
|
||||
}
|
||||
if (text.includes('SELECT * FROM users WHERE id')) {
|
||||
const id = params?.[0];
|
||||
const user = this.users.get(id);
|
||||
return { rows: user ? [user] : [] };
|
||||
}
|
||||
if (text.includes('SELECT * FROM users WHERE google_id')) {
|
||||
const google_id = params?.[0];
|
||||
const user = Array.from(this.users.values()).find(u => u.google_id === google_id);
|
||||
return { rows: user ? [user] : [] };
|
||||
}
|
||||
if (text.includes('INSERT INTO users')) {
|
||||
const id = Date.now().toString();
|
||||
const user = {
|
||||
id,
|
||||
email: params?.[0],
|
||||
name: params?.[1],
|
||||
role: params?.[2] || 'coordinator',
|
||||
google_id: params?.[4],
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
this.users.set(id, user);
|
||||
return { rows: [user] };
|
||||
}
|
||||
// Handle VIP queries
|
||||
if (text.includes('SELECT v.*') && text.includes('FROM vips')) {
|
||||
const vips = Array.from(this.vips.values());
|
||||
return {
|
||||
rows: vips.map(v => ({
|
||||
...v,
|
||||
flights: []
|
||||
}))
|
||||
};
|
||||
}
|
||||
// Handle admin settings queries
|
||||
if (text.includes('SELECT * FROM admin_settings')) {
|
||||
const settings = Array.from(this.adminSettings.entries()).map(([key, value]) => ({
|
||||
key,
|
||||
value
|
||||
}));
|
||||
return { rows: settings };
|
||||
}
|
||||
// Handle drivers queries
|
||||
if (text.includes('SELECT * FROM drivers')) {
|
||||
const drivers = Array.from(this.drivers.values());
|
||||
return { rows: drivers };
|
||||
}
|
||||
// Handle schedule events queries
|
||||
if (text.includes('SELECT * FROM schedule_events')) {
|
||||
const events = Array.from(this.scheduleEvents.values());
|
||||
return { rows: events };
|
||||
}
|
||||
if (text.includes('INSERT INTO vips')) {
|
||||
const id = Date.now().toString();
|
||||
const vip = {
|
||||
id,
|
||||
name: params?.[0],
|
||||
organization: params?.[1],
|
||||
department: params?.[2] || 'Office of Development',
|
||||
transport_mode: params?.[3] || 'flight',
|
||||
expected_arrival: params?.[4],
|
||||
needs_airport_pickup: params?.[5] !== false,
|
||||
needs_venue_transport: params?.[6] !== false,
|
||||
notes: params?.[7] || '',
|
||||
created_at: new Date(),
|
||||
updated_at: new Date()
|
||||
};
|
||||
this.vips.set(id, vip);
|
||||
return { rows: [vip] };
|
||||
}
|
||||
// Default empty result
|
||||
console.log('Unhandled query:', text);
|
||||
return { rows: [] };
|
||||
}
|
||||
async connect() {
|
||||
return {
|
||||
query: this.query.bind(this),
|
||||
release: () => { }
|
||||
};
|
||||
}
|
||||
// Make compatible with pg Pool interface
|
||||
async end() {
|
||||
console.log('Mock database connection closed');
|
||||
}
|
||||
on(event, callback) {
|
||||
if (event === 'connect') {
|
||||
setTimeout(() => callback(), 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = MockDatabase;
|
||||
//# sourceMappingURL=mockDatabase.js.map
|
||||
1
backend-old-20260125/dist/config/mockDatabase.js.map
vendored
Normal file
1
backend-old-20260125/dist/config/mockDatabase.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
292
backend-old-20260125/dist/config/redis.d.ts
vendored
Normal file
292
backend-old-20260125/dist/config/redis.d.ts
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
declare const redisClient: import("@redis/client").RedisClientType<{
|
||||
graph: {
|
||||
CONFIG_GET: typeof import("@redis/graph/dist/commands/CONFIG_GET");
|
||||
configGet: typeof import("@redis/graph/dist/commands/CONFIG_GET");
|
||||
CONFIG_SET: typeof import("@redis/graph/dist/commands/CONFIG_SET");
|
||||
configSet: typeof import("@redis/graph/dist/commands/CONFIG_SET");
|
||||
DELETE: typeof import("@redis/graph/dist/commands/DELETE");
|
||||
delete: typeof import("@redis/graph/dist/commands/DELETE");
|
||||
EXPLAIN: typeof import("@redis/graph/dist/commands/EXPLAIN");
|
||||
explain: typeof import("@redis/graph/dist/commands/EXPLAIN");
|
||||
LIST: typeof import("@redis/graph/dist/commands/LIST");
|
||||
list: typeof import("@redis/graph/dist/commands/LIST");
|
||||
PROFILE: typeof import("@redis/graph/dist/commands/PROFILE");
|
||||
profile: typeof import("@redis/graph/dist/commands/PROFILE");
|
||||
QUERY: typeof import("@redis/graph/dist/commands/QUERY");
|
||||
query: typeof import("@redis/graph/dist/commands/QUERY");
|
||||
RO_QUERY: typeof import("@redis/graph/dist/commands/RO_QUERY");
|
||||
roQuery: typeof import("@redis/graph/dist/commands/RO_QUERY");
|
||||
SLOWLOG: typeof import("@redis/graph/dist/commands/SLOWLOG");
|
||||
slowLog: typeof import("@redis/graph/dist/commands/SLOWLOG");
|
||||
};
|
||||
json: {
|
||||
ARRAPPEND: typeof import("@redis/json/dist/commands/ARRAPPEND");
|
||||
arrAppend: typeof import("@redis/json/dist/commands/ARRAPPEND");
|
||||
ARRINDEX: typeof import("@redis/json/dist/commands/ARRINDEX");
|
||||
arrIndex: typeof import("@redis/json/dist/commands/ARRINDEX");
|
||||
ARRINSERT: typeof import("@redis/json/dist/commands/ARRINSERT");
|
||||
arrInsert: typeof import("@redis/json/dist/commands/ARRINSERT");
|
||||
ARRLEN: typeof import("@redis/json/dist/commands/ARRLEN");
|
||||
arrLen: typeof import("@redis/json/dist/commands/ARRLEN");
|
||||
ARRPOP: typeof import("@redis/json/dist/commands/ARRPOP");
|
||||
arrPop: typeof import("@redis/json/dist/commands/ARRPOP");
|
||||
ARRTRIM: typeof import("@redis/json/dist/commands/ARRTRIM");
|
||||
arrTrim: typeof import("@redis/json/dist/commands/ARRTRIM");
|
||||
DEBUG_MEMORY: typeof import("@redis/json/dist/commands/DEBUG_MEMORY");
|
||||
debugMemory: typeof import("@redis/json/dist/commands/DEBUG_MEMORY");
|
||||
DEL: typeof import("@redis/json/dist/commands/DEL");
|
||||
del: typeof import("@redis/json/dist/commands/DEL");
|
||||
FORGET: typeof import("@redis/json/dist/commands/FORGET");
|
||||
forget: typeof import("@redis/json/dist/commands/FORGET");
|
||||
GET: typeof import("@redis/json/dist/commands/GET");
|
||||
get: typeof import("@redis/json/dist/commands/GET");
|
||||
MERGE: typeof import("@redis/json/dist/commands/MERGE");
|
||||
merge: typeof import("@redis/json/dist/commands/MERGE");
|
||||
MGET: typeof import("@redis/json/dist/commands/MGET");
|
||||
mGet: typeof import("@redis/json/dist/commands/MGET");
|
||||
MSET: typeof import("@redis/json/dist/commands/MSET");
|
||||
mSet: typeof import("@redis/json/dist/commands/MSET");
|
||||
NUMINCRBY: typeof import("@redis/json/dist/commands/NUMINCRBY");
|
||||
numIncrBy: typeof import("@redis/json/dist/commands/NUMINCRBY");
|
||||
NUMMULTBY: typeof import("@redis/json/dist/commands/NUMMULTBY");
|
||||
numMultBy: typeof import("@redis/json/dist/commands/NUMMULTBY");
|
||||
OBJKEYS: typeof import("@redis/json/dist/commands/OBJKEYS");
|
||||
objKeys: typeof import("@redis/json/dist/commands/OBJKEYS");
|
||||
OBJLEN: typeof import("@redis/json/dist/commands/OBJLEN");
|
||||
objLen: typeof import("@redis/json/dist/commands/OBJLEN");
|
||||
RESP: typeof import("@redis/json/dist/commands/RESP");
|
||||
resp: typeof import("@redis/json/dist/commands/RESP");
|
||||
SET: typeof import("@redis/json/dist/commands/SET");
|
||||
set: typeof import("@redis/json/dist/commands/SET");
|
||||
STRAPPEND: typeof import("@redis/json/dist/commands/STRAPPEND");
|
||||
strAppend: typeof import("@redis/json/dist/commands/STRAPPEND");
|
||||
STRLEN: typeof import("@redis/json/dist/commands/STRLEN");
|
||||
strLen: typeof import("@redis/json/dist/commands/STRLEN");
|
||||
TYPE: typeof import("@redis/json/dist/commands/TYPE");
|
||||
type: typeof import("@redis/json/dist/commands/TYPE");
|
||||
};
|
||||
ft: {
|
||||
_LIST: typeof import("@redis/search/dist/commands/_LIST");
|
||||
_list: typeof import("@redis/search/dist/commands/_LIST");
|
||||
ALTER: typeof import("@redis/search/dist/commands/ALTER");
|
||||
alter: typeof import("@redis/search/dist/commands/ALTER");
|
||||
AGGREGATE_WITHCURSOR: typeof import("@redis/search/dist/commands/AGGREGATE_WITHCURSOR");
|
||||
aggregateWithCursor: typeof import("@redis/search/dist/commands/AGGREGATE_WITHCURSOR");
|
||||
AGGREGATE: typeof import("@redis/search/dist/commands/AGGREGATE");
|
||||
aggregate: typeof import("@redis/search/dist/commands/AGGREGATE");
|
||||
ALIASADD: typeof import("@redis/search/dist/commands/ALIASADD");
|
||||
aliasAdd: typeof import("@redis/search/dist/commands/ALIASADD");
|
||||
ALIASDEL: typeof import("@redis/search/dist/commands/ALIASDEL");
|
||||
aliasDel: typeof import("@redis/search/dist/commands/ALIASDEL");
|
||||
ALIASUPDATE: typeof import("@redis/search/dist/commands/ALIASUPDATE");
|
||||
aliasUpdate: typeof import("@redis/search/dist/commands/ALIASUPDATE");
|
||||
CONFIG_GET: typeof import("@redis/search/dist/commands/CONFIG_GET");
|
||||
configGet: typeof import("@redis/search/dist/commands/CONFIG_GET");
|
||||
CONFIG_SET: typeof import("@redis/search/dist/commands/CONFIG_SET");
|
||||
configSet: typeof import("@redis/search/dist/commands/CONFIG_SET");
|
||||
CREATE: typeof import("@redis/search/dist/commands/CREATE");
|
||||
create: typeof import("@redis/search/dist/commands/CREATE");
|
||||
CURSOR_DEL: typeof import("@redis/search/dist/commands/CURSOR_DEL");
|
||||
cursorDel: typeof import("@redis/search/dist/commands/CURSOR_DEL");
|
||||
CURSOR_READ: typeof import("@redis/search/dist/commands/CURSOR_READ");
|
||||
cursorRead: typeof import("@redis/search/dist/commands/CURSOR_READ");
|
||||
DICTADD: typeof import("@redis/search/dist/commands/DICTADD");
|
||||
dictAdd: typeof import("@redis/search/dist/commands/DICTADD");
|
||||
DICTDEL: typeof import("@redis/search/dist/commands/DICTDEL");
|
||||
dictDel: typeof import("@redis/search/dist/commands/DICTDEL");
|
||||
DICTDUMP: typeof import("@redis/search/dist/commands/DICTDUMP");
|
||||
dictDump: typeof import("@redis/search/dist/commands/DICTDUMP");
|
||||
DROPINDEX: typeof import("@redis/search/dist/commands/DROPINDEX");
|
||||
dropIndex: typeof import("@redis/search/dist/commands/DROPINDEX");
|
||||
EXPLAIN: typeof import("@redis/search/dist/commands/EXPLAIN");
|
||||
explain: typeof import("@redis/search/dist/commands/EXPLAIN");
|
||||
EXPLAINCLI: typeof import("@redis/search/dist/commands/EXPLAINCLI");
|
||||
explainCli: typeof import("@redis/search/dist/commands/EXPLAINCLI");
|
||||
INFO: typeof import("@redis/search/dist/commands/INFO");
|
||||
info: typeof import("@redis/search/dist/commands/INFO");
|
||||
PROFILESEARCH: typeof import("@redis/search/dist/commands/PROFILE_SEARCH");
|
||||
profileSearch: typeof import("@redis/search/dist/commands/PROFILE_SEARCH");
|
||||
PROFILEAGGREGATE: typeof import("@redis/search/dist/commands/PROFILE_AGGREGATE");
|
||||
profileAggregate: typeof import("@redis/search/dist/commands/PROFILE_AGGREGATE");
|
||||
SEARCH: typeof import("@redis/search/dist/commands/SEARCH");
|
||||
search: typeof import("@redis/search/dist/commands/SEARCH");
|
||||
SEARCH_NOCONTENT: typeof import("@redis/search/dist/commands/SEARCH_NOCONTENT");
|
||||
searchNoContent: typeof import("@redis/search/dist/commands/SEARCH_NOCONTENT");
|
||||
SPELLCHECK: typeof import("@redis/search/dist/commands/SPELLCHECK");
|
||||
spellCheck: typeof import("@redis/search/dist/commands/SPELLCHECK");
|
||||
SUGADD: typeof import("@redis/search/dist/commands/SUGADD");
|
||||
sugAdd: typeof import("@redis/search/dist/commands/SUGADD");
|
||||
SUGDEL: typeof import("@redis/search/dist/commands/SUGDEL");
|
||||
sugDel: typeof import("@redis/search/dist/commands/SUGDEL");
|
||||
SUGGET_WITHPAYLOADS: typeof import("@redis/search/dist/commands/SUGGET_WITHPAYLOADS");
|
||||
sugGetWithPayloads: typeof import("@redis/search/dist/commands/SUGGET_WITHPAYLOADS");
|
||||
SUGGET_WITHSCORES_WITHPAYLOADS: typeof import("@redis/search/dist/commands/SUGGET_WITHSCORES_WITHPAYLOADS");
|
||||
sugGetWithScoresWithPayloads: typeof import("@redis/search/dist/commands/SUGGET_WITHSCORES_WITHPAYLOADS");
|
||||
SUGGET_WITHSCORES: typeof import("@redis/search/dist/commands/SUGGET_WITHSCORES");
|
||||
sugGetWithScores: typeof import("@redis/search/dist/commands/SUGGET_WITHSCORES");
|
||||
SUGGET: typeof import("@redis/search/dist/commands/SUGGET");
|
||||
sugGet: typeof import("@redis/search/dist/commands/SUGGET");
|
||||
SUGLEN: typeof import("@redis/search/dist/commands/SUGLEN");
|
||||
sugLen: typeof import("@redis/search/dist/commands/SUGLEN");
|
||||
SYNDUMP: typeof import("@redis/search/dist/commands/SYNDUMP");
|
||||
synDump: typeof import("@redis/search/dist/commands/SYNDUMP");
|
||||
SYNUPDATE: typeof import("@redis/search/dist/commands/SYNUPDATE");
|
||||
synUpdate: typeof import("@redis/search/dist/commands/SYNUPDATE");
|
||||
TAGVALS: typeof import("@redis/search/dist/commands/TAGVALS");
|
||||
tagVals: typeof import("@redis/search/dist/commands/TAGVALS");
|
||||
};
|
||||
ts: {
|
||||
ADD: typeof import("@redis/time-series/dist/commands/ADD");
|
||||
add: typeof import("@redis/time-series/dist/commands/ADD");
|
||||
ALTER: typeof import("@redis/time-series/dist/commands/ALTER");
|
||||
alter: typeof import("@redis/time-series/dist/commands/ALTER");
|
||||
CREATE: typeof import("@redis/time-series/dist/commands/CREATE");
|
||||
create: typeof import("@redis/time-series/dist/commands/CREATE");
|
||||
CREATERULE: typeof import("@redis/time-series/dist/commands/CREATERULE");
|
||||
createRule: typeof import("@redis/time-series/dist/commands/CREATERULE");
|
||||
DECRBY: typeof import("@redis/time-series/dist/commands/DECRBY");
|
||||
decrBy: typeof import("@redis/time-series/dist/commands/DECRBY");
|
||||
DEL: typeof import("@redis/time-series/dist/commands/DEL");
|
||||
del: typeof import("@redis/time-series/dist/commands/DEL");
|
||||
DELETERULE: typeof import("@redis/time-series/dist/commands/DELETERULE");
|
||||
deleteRule: typeof import("@redis/time-series/dist/commands/DELETERULE");
|
||||
GET: typeof import("@redis/time-series/dist/commands/GET");
|
||||
get: typeof import("@redis/time-series/dist/commands/GET");
|
||||
INCRBY: typeof import("@redis/time-series/dist/commands/INCRBY");
|
||||
incrBy: typeof import("@redis/time-series/dist/commands/INCRBY");
|
||||
INFO_DEBUG: typeof import("@redis/time-series/dist/commands/INFO_DEBUG");
|
||||
infoDebug: typeof import("@redis/time-series/dist/commands/INFO_DEBUG");
|
||||
INFO: typeof import("@redis/time-series/dist/commands/INFO");
|
||||
info: typeof import("@redis/time-series/dist/commands/INFO");
|
||||
MADD: typeof import("@redis/time-series/dist/commands/MADD");
|
||||
mAdd: typeof import("@redis/time-series/dist/commands/MADD");
|
||||
MGET: typeof import("@redis/time-series/dist/commands/MGET");
|
||||
mGet: typeof import("@redis/time-series/dist/commands/MGET");
|
||||
MGET_WITHLABELS: typeof import("@redis/time-series/dist/commands/MGET_WITHLABELS");
|
||||
mGetWithLabels: typeof import("@redis/time-series/dist/commands/MGET_WITHLABELS");
|
||||
QUERYINDEX: typeof import("@redis/time-series/dist/commands/QUERYINDEX");
|
||||
queryIndex: typeof import("@redis/time-series/dist/commands/QUERYINDEX");
|
||||
RANGE: typeof import("@redis/time-series/dist/commands/RANGE");
|
||||
range: typeof import("@redis/time-series/dist/commands/RANGE");
|
||||
REVRANGE: typeof import("@redis/time-series/dist/commands/REVRANGE");
|
||||
revRange: typeof import("@redis/time-series/dist/commands/REVRANGE");
|
||||
MRANGE: typeof import("@redis/time-series/dist/commands/MRANGE");
|
||||
mRange: typeof import("@redis/time-series/dist/commands/MRANGE");
|
||||
MRANGE_WITHLABELS: typeof import("@redis/time-series/dist/commands/MRANGE_WITHLABELS");
|
||||
mRangeWithLabels: typeof import("@redis/time-series/dist/commands/MRANGE_WITHLABELS");
|
||||
MREVRANGE: typeof import("@redis/time-series/dist/commands/MREVRANGE");
|
||||
mRevRange: typeof import("@redis/time-series/dist/commands/MREVRANGE");
|
||||
MREVRANGE_WITHLABELS: typeof import("@redis/time-series/dist/commands/MREVRANGE_WITHLABELS");
|
||||
mRevRangeWithLabels: typeof import("@redis/time-series/dist/commands/MREVRANGE_WITHLABELS");
|
||||
};
|
||||
bf: {
|
||||
ADD: typeof import("@redis/bloom/dist/commands/bloom/ADD");
|
||||
add: typeof import("@redis/bloom/dist/commands/bloom/ADD");
|
||||
CARD: typeof import("@redis/bloom/dist/commands/bloom/CARD");
|
||||
card: typeof import("@redis/bloom/dist/commands/bloom/CARD");
|
||||
EXISTS: typeof import("@redis/bloom/dist/commands/bloom/EXISTS");
|
||||
exists: typeof import("@redis/bloom/dist/commands/bloom/EXISTS");
|
||||
INFO: typeof import("@redis/bloom/dist/commands/bloom/INFO");
|
||||
info: typeof import("@redis/bloom/dist/commands/bloom/INFO");
|
||||
INSERT: typeof import("@redis/bloom/dist/commands/bloom/INSERT");
|
||||
insert: typeof import("@redis/bloom/dist/commands/bloom/INSERT");
|
||||
LOADCHUNK: typeof import("@redis/bloom/dist/commands/bloom/LOADCHUNK");
|
||||
loadChunk: typeof import("@redis/bloom/dist/commands/bloom/LOADCHUNK");
|
||||
MADD: typeof import("@redis/bloom/dist/commands/bloom/MADD");
|
||||
mAdd: typeof import("@redis/bloom/dist/commands/bloom/MADD");
|
||||
MEXISTS: typeof import("@redis/bloom/dist/commands/bloom/MEXISTS");
|
||||
mExists: typeof import("@redis/bloom/dist/commands/bloom/MEXISTS");
|
||||
RESERVE: typeof import("@redis/bloom/dist/commands/bloom/RESERVE");
|
||||
reserve: typeof import("@redis/bloom/dist/commands/bloom/RESERVE");
|
||||
SCANDUMP: typeof import("@redis/bloom/dist/commands/bloom/SCANDUMP");
|
||||
scanDump: typeof import("@redis/bloom/dist/commands/bloom/SCANDUMP");
|
||||
};
|
||||
cms: {
|
||||
INCRBY: typeof import("@redis/bloom/dist/commands/count-min-sketch/INCRBY");
|
||||
incrBy: typeof import("@redis/bloom/dist/commands/count-min-sketch/INCRBY");
|
||||
INFO: typeof import("@redis/bloom/dist/commands/count-min-sketch/INFO");
|
||||
info: typeof import("@redis/bloom/dist/commands/count-min-sketch/INFO");
|
||||
INITBYDIM: typeof import("@redis/bloom/dist/commands/count-min-sketch/INITBYDIM");
|
||||
initByDim: typeof import("@redis/bloom/dist/commands/count-min-sketch/INITBYDIM");
|
||||
INITBYPROB: typeof import("@redis/bloom/dist/commands/count-min-sketch/INITBYPROB");
|
||||
initByProb: typeof import("@redis/bloom/dist/commands/count-min-sketch/INITBYPROB");
|
||||
MERGE: typeof import("@redis/bloom/dist/commands/count-min-sketch/MERGE");
|
||||
merge: typeof import("@redis/bloom/dist/commands/count-min-sketch/MERGE");
|
||||
QUERY: typeof import("@redis/bloom/dist/commands/count-min-sketch/QUERY");
|
||||
query: typeof import("@redis/bloom/dist/commands/count-min-sketch/QUERY");
|
||||
};
|
||||
cf: {
|
||||
ADD: typeof import("@redis/bloom/dist/commands/cuckoo/ADD");
|
||||
add: typeof import("@redis/bloom/dist/commands/cuckoo/ADD");
|
||||
ADDNX: typeof import("@redis/bloom/dist/commands/cuckoo/ADDNX");
|
||||
addNX: typeof import("@redis/bloom/dist/commands/cuckoo/ADDNX");
|
||||
COUNT: typeof import("@redis/bloom/dist/commands/cuckoo/COUNT");
|
||||
count: typeof import("@redis/bloom/dist/commands/cuckoo/COUNT");
|
||||
DEL: typeof import("@redis/bloom/dist/commands/cuckoo/DEL");
|
||||
del: typeof import("@redis/bloom/dist/commands/cuckoo/DEL");
|
||||
EXISTS: typeof import("@redis/bloom/dist/commands/cuckoo/EXISTS");
|
||||
exists: typeof import("@redis/bloom/dist/commands/cuckoo/EXISTS");
|
||||
INFO: typeof import("@redis/bloom/dist/commands/cuckoo/INFO");
|
||||
info: typeof import("@redis/bloom/dist/commands/cuckoo/INFO");
|
||||
INSERT: typeof import("@redis/bloom/dist/commands/cuckoo/INSERT");
|
||||
insert: typeof import("@redis/bloom/dist/commands/cuckoo/INSERT");
|
||||
INSERTNX: typeof import("@redis/bloom/dist/commands/cuckoo/INSERTNX");
|
||||
insertNX: typeof import("@redis/bloom/dist/commands/cuckoo/INSERTNX");
|
||||
LOADCHUNK: typeof import("@redis/bloom/dist/commands/cuckoo/LOADCHUNK");
|
||||
loadChunk: typeof import("@redis/bloom/dist/commands/cuckoo/LOADCHUNK");
|
||||
RESERVE: typeof import("@redis/bloom/dist/commands/cuckoo/RESERVE");
|
||||
reserve: typeof import("@redis/bloom/dist/commands/cuckoo/RESERVE");
|
||||
SCANDUMP: typeof import("@redis/bloom/dist/commands/cuckoo/SCANDUMP");
|
||||
scanDump: typeof import("@redis/bloom/dist/commands/cuckoo/SCANDUMP");
|
||||
};
|
||||
tDigest: {
|
||||
ADD: typeof import("@redis/bloom/dist/commands/t-digest/ADD");
|
||||
add: typeof import("@redis/bloom/dist/commands/t-digest/ADD");
|
||||
BYRANK: typeof import("@redis/bloom/dist/commands/t-digest/BYRANK");
|
||||
byRank: typeof import("@redis/bloom/dist/commands/t-digest/BYRANK");
|
||||
BYREVRANK: typeof import("@redis/bloom/dist/commands/t-digest/BYREVRANK");
|
||||
byRevRank: typeof import("@redis/bloom/dist/commands/t-digest/BYREVRANK");
|
||||
CDF: typeof import("@redis/bloom/dist/commands/t-digest/CDF");
|
||||
cdf: typeof import("@redis/bloom/dist/commands/t-digest/CDF");
|
||||
CREATE: typeof import("@redis/bloom/dist/commands/t-digest/CREATE");
|
||||
create: typeof import("@redis/bloom/dist/commands/t-digest/CREATE");
|
||||
INFO: typeof import("@redis/bloom/dist/commands/t-digest/INFO");
|
||||
info: typeof import("@redis/bloom/dist/commands/t-digest/INFO");
|
||||
MAX: typeof import("@redis/bloom/dist/commands/t-digest/MAX");
|
||||
max: typeof import("@redis/bloom/dist/commands/t-digest/MAX");
|
||||
MERGE: typeof import("@redis/bloom/dist/commands/t-digest/MERGE");
|
||||
merge: typeof import("@redis/bloom/dist/commands/t-digest/MERGE");
|
||||
MIN: typeof import("@redis/bloom/dist/commands/t-digest/MIN");
|
||||
min: typeof import("@redis/bloom/dist/commands/t-digest/MIN");
|
||||
QUANTILE: typeof import("@redis/bloom/dist/commands/t-digest/QUANTILE");
|
||||
quantile: typeof import("@redis/bloom/dist/commands/t-digest/QUANTILE");
|
||||
RANK: typeof import("@redis/bloom/dist/commands/t-digest/RANK");
|
||||
rank: typeof import("@redis/bloom/dist/commands/t-digest/RANK");
|
||||
RESET: typeof import("@redis/bloom/dist/commands/t-digest/RESET");
|
||||
reset: typeof import("@redis/bloom/dist/commands/t-digest/RESET");
|
||||
REVRANK: typeof import("@redis/bloom/dist/commands/t-digest/REVRANK");
|
||||
revRank: typeof import("@redis/bloom/dist/commands/t-digest/REVRANK");
|
||||
TRIMMED_MEAN: typeof import("@redis/bloom/dist/commands/t-digest/TRIMMED_MEAN");
|
||||
trimmedMean: typeof import("@redis/bloom/dist/commands/t-digest/TRIMMED_MEAN");
|
||||
};
|
||||
topK: {
|
||||
ADD: typeof import("@redis/bloom/dist/commands/top-k/ADD");
|
||||
add: typeof import("@redis/bloom/dist/commands/top-k/ADD");
|
||||
COUNT: typeof import("@redis/bloom/dist/commands/top-k/COUNT");
|
||||
count: typeof import("@redis/bloom/dist/commands/top-k/COUNT");
|
||||
INCRBY: typeof import("@redis/bloom/dist/commands/top-k/INCRBY");
|
||||
incrBy: typeof import("@redis/bloom/dist/commands/top-k/INCRBY");
|
||||
INFO: typeof import("@redis/bloom/dist/commands/top-k/INFO");
|
||||
info: typeof import("@redis/bloom/dist/commands/top-k/INFO");
|
||||
LIST_WITHCOUNT: typeof import("@redis/bloom/dist/commands/top-k/LIST_WITHCOUNT");
|
||||
listWithCount: typeof import("@redis/bloom/dist/commands/top-k/LIST_WITHCOUNT");
|
||||
LIST: typeof import("@redis/bloom/dist/commands/top-k/LIST");
|
||||
list: typeof import("@redis/bloom/dist/commands/top-k/LIST");
|
||||
QUERY: typeof import("@redis/bloom/dist/commands/top-k/QUERY");
|
||||
query: typeof import("@redis/bloom/dist/commands/top-k/QUERY");
|
||||
RESERVE: typeof import("@redis/bloom/dist/commands/top-k/RESERVE");
|
||||
reserve: typeof import("@redis/bloom/dist/commands/top-k/RESERVE");
|
||||
};
|
||||
} & import("redis").RedisModules, import("redis").RedisFunctions, import("redis").RedisScripts>;
|
||||
export default redisClient;
|
||||
//# sourceMappingURL=redis.d.ts.map
|
||||
1
backend-old-20260125/dist/config/redis.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/config/redis.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/config/redis.ts"],"names":[],"mappings":"AAKA,QAAA,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+FAEf,CAAC;AAeH,eAAe,WAAW,CAAC"}
|
||||
23
backend-old-20260125/dist/config/redis.js
vendored
Normal file
23
backend-old-20260125/dist/config/redis.js
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const redis_1 = require("redis");
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
dotenv_1.default.config();
|
||||
const redisClient = (0, redis_1.createClient)({
|
||||
url: process.env.REDIS_URL || 'redis://localhost:6379'
|
||||
});
|
||||
redisClient.on('connect', () => {
|
||||
console.log('✅ Connected to Redis');
|
||||
});
|
||||
redisClient.on('error', (err) => {
|
||||
console.error('❌ Redis connection error:', err);
|
||||
});
|
||||
// Connect to Redis
|
||||
redisClient.connect().catch((err) => {
|
||||
console.error('❌ Failed to connect to Redis:', err);
|
||||
});
|
||||
exports.default = redisClient;
|
||||
//# sourceMappingURL=redis.js.map
|
||||
1
backend-old-20260125/dist/config/redis.js.map
vendored
Normal file
1
backend-old-20260125/dist/config/redis.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/config/redis.ts"],"names":[],"mappings":";;;;;AAAA,iCAAqC;AACrC,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEhB,MAAM,WAAW,GAAG,IAAA,oBAAY,EAAC;IAC/B,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,wBAAwB;CACvD,CAAC,CAAC;AAEH,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;IAC7B,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC;AAEH,WAAW,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;IACrC,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,GAAG,CAAC,CAAC;AAClD,CAAC,CAAC,CAAC;AAEH,mBAAmB;AACnB,WAAW,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,GAAU,EAAE,EAAE;IACzC,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,GAAG,CAAC,CAAC;AACtD,CAAC,CAAC,CAAC;AAEH,kBAAe,WAAW,CAAC"}
|
||||
9
backend-old-20260125/dist/config/simpleAuth.d.ts
vendored
Normal file
9
backend-old-20260125/dist/config/simpleAuth.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
import { User } from '../services/jwtKeyManager';
|
||||
export { User } from '../services/jwtKeyManager';
|
||||
export declare function generateToken(user: User): string;
|
||||
export declare function verifyToken(token: string): User | null;
|
||||
export declare function verifyGoogleToken(googleToken: string): Promise<any>;
|
||||
export declare function getGoogleAuthUrl(): string;
|
||||
export declare function exchangeCodeForTokens(code: string): Promise<any>;
|
||||
export declare function getGoogleUserInfo(accessToken: string): Promise<any>;
|
||||
//# sourceMappingURL=simpleAuth.d.ts.map
|
||||
1
backend-old-20260125/dist/config/simpleAuth.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/config/simpleAuth.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"simpleAuth.d.ts","sourceRoot":"","sources":["../../src/config/simpleAuth.ts"],"names":[],"mappings":"AAAA,OAAsB,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAKhE,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAC;AAEjD,wBAAgB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAEhD;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,CAEtD;AAGD,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAWzE;AAGD,wBAAgB,gBAAgB,IAAI,MAAM,CAiCzC;AAGD,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAgGtE;AAGD,wBAAsB,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAsEzE"}
|
||||
217
backend-old-20260125/dist/config/simpleAuth.js
vendored
Normal file
217
backend-old-20260125/dist/config/simpleAuth.js
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.User = void 0;
|
||||
exports.generateToken = generateToken;
|
||||
exports.verifyToken = verifyToken;
|
||||
exports.verifyGoogleToken = verifyGoogleToken;
|
||||
exports.getGoogleAuthUrl = getGoogleAuthUrl;
|
||||
exports.exchangeCodeForTokens = exchangeCodeForTokens;
|
||||
exports.getGoogleUserInfo = getGoogleUserInfo;
|
||||
const jwtKeyManager_1 = __importDefault(require("../services/jwtKeyManager"));
|
||||
// JWT Key Manager now handles all token operations with automatic rotation
|
||||
// No more static JWT_SECRET needed!
|
||||
var jwtKeyManager_2 = require("../services/jwtKeyManager");
|
||||
Object.defineProperty(exports, "User", { enumerable: true, get: function () { return jwtKeyManager_2.User; } });
|
||||
function generateToken(user) {
|
||||
return jwtKeyManager_1.default.generateToken(user);
|
||||
}
|
||||
function verifyToken(token) {
|
||||
return jwtKeyManager_1.default.verifyToken(token);
|
||||
}
|
||||
// Simple Google OAuth2 client using fetch
|
||||
async function verifyGoogleToken(googleToken) {
|
||||
try {
|
||||
const response = await fetch(`https://www.googleapis.com/oauth2/v1/userinfo?access_token=${googleToken}`);
|
||||
if (!response.ok) {
|
||||
throw new Error('Invalid Google token');
|
||||
}
|
||||
return await response.json();
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error verifying Google token:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Get Google OAuth2 URL
|
||||
function getGoogleAuthUrl() {
|
||||
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||
const redirectUri = process.env.GOOGLE_REDIRECT_URI || 'http://localhost:3000/auth/google/callback';
|
||||
console.log('🔗 Generating Google OAuth URL:', {
|
||||
client_id_present: !!clientId,
|
||||
redirect_uri: redirectUri,
|
||||
environment: process.env.NODE_ENV || 'development'
|
||||
});
|
||||
if (!clientId) {
|
||||
console.error('❌ GOOGLE_CLIENT_ID not configured');
|
||||
throw new Error('GOOGLE_CLIENT_ID not configured');
|
||||
}
|
||||
if (!redirectUri.startsWith('http')) {
|
||||
console.error('❌ Invalid redirect URI:', redirectUri);
|
||||
throw new Error('GOOGLE_REDIRECT_URI must be a valid HTTP/HTTPS URL');
|
||||
}
|
||||
const params = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
redirect_uri: redirectUri,
|
||||
response_type: 'code',
|
||||
scope: 'openid email profile',
|
||||
access_type: 'offline',
|
||||
prompt: 'consent'
|
||||
});
|
||||
const authUrl = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
||||
console.log('✅ Google OAuth URL generated successfully');
|
||||
return authUrl;
|
||||
}
|
||||
// Exchange authorization code for tokens
|
||||
async function exchangeCodeForTokens(code) {
|
||||
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
||||
const redirectUri = process.env.GOOGLE_REDIRECT_URI || 'http://localhost:3000/auth/google/callback';
|
||||
console.log('🔄 Exchanging OAuth code for tokens:', {
|
||||
client_id_present: !!clientId,
|
||||
client_secret_present: !!clientSecret,
|
||||
redirect_uri: redirectUri,
|
||||
code_length: code?.length || 0
|
||||
});
|
||||
if (!clientId || !clientSecret) {
|
||||
console.error('❌ Google OAuth credentials not configured:', {
|
||||
client_id: !!clientId,
|
||||
client_secret: !!clientSecret
|
||||
});
|
||||
throw new Error('Google OAuth credentials not configured');
|
||||
}
|
||||
if (!code || code.length < 10) {
|
||||
console.error('❌ Invalid authorization code:', { code_length: code?.length || 0 });
|
||||
throw new Error('Invalid authorization code provided');
|
||||
}
|
||||
try {
|
||||
const tokenUrl = 'https://oauth2.googleapis.com/token';
|
||||
const requestBody = new URLSearchParams({
|
||||
client_id: clientId,
|
||||
client_secret: clientSecret,
|
||||
code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: redirectUri,
|
||||
});
|
||||
console.log('📡 Making token exchange request to Google:', {
|
||||
url: tokenUrl,
|
||||
redirect_uri: redirectUri,
|
||||
grant_type: 'authorization_code'
|
||||
});
|
||||
const response = await fetch(tokenUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
body: requestBody,
|
||||
});
|
||||
const responseText = await response.text();
|
||||
console.log('📨 Token exchange response:', {
|
||||
status: response.status,
|
||||
ok: response.ok,
|
||||
content_type: response.headers.get('content-type'),
|
||||
response_length: responseText.length
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.error('❌ Token exchange failed:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
response: responseText
|
||||
});
|
||||
throw new Error(`Failed to exchange code for tokens: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
let tokenData;
|
||||
try {
|
||||
tokenData = JSON.parse(responseText);
|
||||
}
|
||||
catch (parseError) {
|
||||
console.error('❌ Failed to parse token response:', { response: responseText });
|
||||
throw new Error('Invalid JSON response from Google token endpoint');
|
||||
}
|
||||
if (!tokenData.access_token) {
|
||||
console.error('❌ No access token in response:', tokenData);
|
||||
throw new Error('No access token received from Google');
|
||||
}
|
||||
console.log('✅ Token exchange successful:', {
|
||||
has_access_token: !!tokenData.access_token,
|
||||
has_refresh_token: !!tokenData.refresh_token,
|
||||
token_type: tokenData.token_type,
|
||||
expires_in: tokenData.expires_in
|
||||
});
|
||||
return tokenData;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error exchanging code for tokens:', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
stack: error instanceof Error ? error.stack : undefined
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// Get user info from Google
|
||||
async function getGoogleUserInfo(accessToken) {
|
||||
console.log('👤 Getting user info from Google:', {
|
||||
token_length: accessToken?.length || 0,
|
||||
token_prefix: accessToken ? accessToken.substring(0, 10) + '...' : 'none'
|
||||
});
|
||||
if (!accessToken || accessToken.length < 10) {
|
||||
console.error('❌ Invalid access token for user info request');
|
||||
throw new Error('Invalid access token provided');
|
||||
}
|
||||
try {
|
||||
const userInfoUrl = `https://www.googleapis.com/oauth2/v2/userinfo?access_token=${accessToken}`;
|
||||
console.log('📡 Making user info request to Google');
|
||||
const response = await fetch(userInfoUrl, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': `Bearer ${accessToken}`
|
||||
}
|
||||
});
|
||||
const responseText = await response.text();
|
||||
console.log('📨 User info response:', {
|
||||
status: response.status,
|
||||
ok: response.ok,
|
||||
content_type: response.headers.get('content-type'),
|
||||
response_length: responseText.length
|
||||
});
|
||||
if (!response.ok) {
|
||||
console.error('❌ Failed to get user info:', {
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
response: responseText
|
||||
});
|
||||
throw new Error(`Failed to get user info: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
let userData;
|
||||
try {
|
||||
userData = JSON.parse(responseText);
|
||||
}
|
||||
catch (parseError) {
|
||||
console.error('❌ Failed to parse user info response:', { response: responseText });
|
||||
throw new Error('Invalid JSON response from Google user info endpoint');
|
||||
}
|
||||
if (!userData.email) {
|
||||
console.error('❌ No email in user info response:', userData);
|
||||
throw new Error('No email address received from Google');
|
||||
}
|
||||
console.log('✅ User info retrieved successfully:', {
|
||||
email: userData.email,
|
||||
name: userData.name,
|
||||
verified_email: userData.verified_email,
|
||||
has_picture: !!userData.picture
|
||||
});
|
||||
return userData;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error getting Google user info:', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
stack: error instanceof Error ? error.stack : undefined
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=simpleAuth.js.map
|
||||
1
backend-old-20260125/dist/config/simpleAuth.js.map
vendored
Normal file
1
backend-old-20260125/dist/config/simpleAuth.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
backend-old-20260125/dist/index.d.ts
vendored
Normal file
2
backend-old-20260125/dist/index.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=index.d.ts.map
|
||||
1
backend-old-20260125/dist/index.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/index.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
||||
271
backend-old-20260125/dist/index.js
vendored
Normal file
271
backend-old-20260125/dist/index.js
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const cors_1 = __importDefault(require("cors"));
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
const authService_1 = __importDefault(require("./services/authService"));
|
||||
const unifiedDataService_1 = __importDefault(require("./services/unifiedDataService"));
|
||||
const simpleValidation_1 = require("./middleware/simpleValidation");
|
||||
const errorHandler_1 = require("./middleware/errorHandler");
|
||||
dotenv_1.default.config();
|
||||
// Log environment variables status on startup
|
||||
console.log('Environment variables loaded:');
|
||||
console.log('- GOOGLE_CLIENT_ID:', process.env.GOOGLE_CLIENT_ID ? 'Set' : 'Not set');
|
||||
console.log('- GOOGLE_CLIENT_SECRET:', process.env.GOOGLE_CLIENT_SECRET ? 'Set' : 'Not set');
|
||||
console.log('- GOOGLE_REDIRECT_URI:', process.env.GOOGLE_REDIRECT_URI || 'Not set');
|
||||
const app = (0, express_1.default)();
|
||||
const port = process.env.PORT || 3000;
|
||||
// Middleware
|
||||
app.use((0, cors_1.default)({
|
||||
origin: [
|
||||
process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||
'https://bsa.madeamess.online'
|
||||
],
|
||||
credentials: true
|
||||
}));
|
||||
app.use(express_1.default.json());
|
||||
app.use(express_1.default.static('public'));
|
||||
// Health check
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'OK',
|
||||
timestamp: new Date().toISOString(),
|
||||
version: '2.0.0' // Simplified version
|
||||
});
|
||||
});
|
||||
// Auth routes
|
||||
app.get('/auth/setup', async (req, res) => {
|
||||
try {
|
||||
// Check if any users exist in the system
|
||||
const userCount = await unifiedDataService_1.default.getUserCount();
|
||||
res.json({
|
||||
needsSetup: userCount === 0,
|
||||
hasUsers: userCount > 0
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error in /auth/setup:', error);
|
||||
res.status(500).json({ error: 'Failed to check setup status' });
|
||||
}
|
||||
});
|
||||
app.get('/auth/google', (req, res) => {
|
||||
res.redirect(authService_1.default.getGoogleAuthUrl());
|
||||
});
|
||||
app.get('/auth/google/url', (req, res) => {
|
||||
try {
|
||||
// Return the Google OAuth URL as JSON for the frontend
|
||||
const url = authService_1.default.getGoogleAuthUrl();
|
||||
res.json({ url });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error generating Google Auth URL:', error);
|
||||
res.status(500).json({
|
||||
error: 'Google OAuth configuration error',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
app.post('/auth/google/callback', async (req, res) => {
|
||||
try {
|
||||
const { code } = req.body;
|
||||
const { user, token } = await authService_1.default.handleGoogleAuth(code);
|
||||
res.json({ user, token });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(400).json({ error: 'Authentication failed' });
|
||||
}
|
||||
});
|
||||
app.post('/auth/google/exchange', async (req, res) => {
|
||||
try {
|
||||
const { code } = req.body;
|
||||
const { user, token } = await authService_1.default.handleGoogleAuth(code);
|
||||
res.json({ user, token });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(400).json({ error: 'Authentication failed' });
|
||||
}
|
||||
});
|
||||
app.post('/auth/google/verify', async (req, res) => {
|
||||
try {
|
||||
const { credential } = req.body;
|
||||
const { user, token } = await authService_1.default.verifyGoogleToken(credential);
|
||||
res.json({ user, token });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Google token verification error:', error);
|
||||
res.status(400).json({ error: 'Authentication failed' });
|
||||
}
|
||||
});
|
||||
app.get('/auth/me', authService_1.default.requireAuth, (req, res) => {
|
||||
res.json(req.user);
|
||||
});
|
||||
app.post('/auth/logout', (req, res) => {
|
||||
res.json({ message: 'Logged out successfully' });
|
||||
});
|
||||
// VIP routes
|
||||
app.get('/api/vips', async (req, res, next) => {
|
||||
try {
|
||||
const vips = await unifiedDataService_1.default.getVips();
|
||||
res.json(vips);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.get('/api/vips/:id', async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.getVipById(req.params.id);
|
||||
if (!vip)
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
res.json(vip);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/vips', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.createVip), async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.createVip(req.body);
|
||||
res.status(201).json(vip);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.put('/api/vips/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.updateVip), async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.updateVip(req.params.id, req.body);
|
||||
if (!vip)
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
res.json(vip);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.delete('/api/vips/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.deleteVip(req.params.id);
|
||||
if (!vip)
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
res.json({ message: 'VIP deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Driver routes
|
||||
app.get('/api/drivers', async (req, res, next) => {
|
||||
try {
|
||||
const drivers = await unifiedDataService_1.default.getDrivers();
|
||||
res.json(drivers);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/drivers', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.createDriver), async (req, res, next) => {
|
||||
try {
|
||||
const driver = await unifiedDataService_1.default.createDriver(req.body);
|
||||
res.status(201).json(driver);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.put('/api/drivers/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.updateDriver), async (req, res, next) => {
|
||||
try {
|
||||
const driver = await unifiedDataService_1.default.updateDriver(req.params.id, req.body);
|
||||
if (!driver)
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
res.json(driver);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.delete('/api/drivers/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const driver = await unifiedDataService_1.default.deleteDriver(req.params.id);
|
||||
if (!driver)
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
res.json({ message: 'Driver deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Schedule routes
|
||||
app.get('/api/vips/:vipId/schedule', authService_1.default.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const schedule = await unifiedDataService_1.default.getScheduleByVipId(req.params.vipId);
|
||||
res.json(schedule);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/vips/:vipId/schedule', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.createScheduleEvent), async (req, res, next) => {
|
||||
try {
|
||||
const event = await unifiedDataService_1.default.createScheduleEvent(req.params.vipId, req.body);
|
||||
res.status(201).json(event);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.put('/api/vips/:vipId/schedule/:eventId', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.updateScheduleEvent), async (req, res, next) => {
|
||||
try {
|
||||
const event = await unifiedDataService_1.default.updateScheduleEvent(req.params.eventId, req.body);
|
||||
if (!event)
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
res.json(event);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.delete('/api/vips/:vipId/schedule/:eventId', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const event = await unifiedDataService_1.default.deleteScheduleEvent(req.params.eventId);
|
||||
if (!event)
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
res.json({ message: 'Event deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Admin routes (simplified)
|
||||
app.get('/api/admin/settings', authService_1.default.requireAuth, authService_1.default.requireRole(['administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const settings = await unifiedDataService_1.default.getAdminSettings();
|
||||
res.json(settings);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/admin/settings', authService_1.default.requireAuth, authService_1.default.requireRole(['administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const { key, value } = req.body;
|
||||
await unifiedDataService_1.default.updateAdminSetting(key, value);
|
||||
res.json({ message: 'Setting updated successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Error handling
|
||||
app.use(errorHandler_1.notFoundHandler);
|
||||
app.use(errorHandler_1.errorHandler);
|
||||
// Start server
|
||||
app.listen(port, () => {
|
||||
console.log(`🚀 Server running on port ${port}`);
|
||||
console.log(`🏥 Health check: http://localhost:${port}/api/health`);
|
||||
console.log(`📚 API docs: http://localhost:${port}/api-docs.html`);
|
||||
});
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
backend-old-20260125/dist/index.js.map
vendored
Normal file
1
backend-old-20260125/dist/index.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
backend-old-20260125/dist/index.original.d.ts
vendored
Normal file
2
backend-old-20260125/dist/index.original.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=index.original.d.ts.map
|
||||
1
backend-old-20260125/dist/index.original.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/index.original.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.original.d.ts","sourceRoot":"","sources":["../src/index.original.ts"],"names":[],"mappings":""}
|
||||
765
backend-old-20260125/dist/index.original.js
vendored
Normal file
765
backend-old-20260125/dist/index.original.js
vendored
Normal file
@@ -0,0 +1,765 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || (function () {
|
||||
var ownKeys = function(o) {
|
||||
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||
var ar = [];
|
||||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||
return ar;
|
||||
};
|
||||
return ownKeys(o);
|
||||
};
|
||||
return function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
})();
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
const cors_1 = __importDefault(require("cors"));
|
||||
const simpleAuth_1 = __importStar(require("./routes/simpleAuth"));
|
||||
const flightService_1 = __importDefault(require("./services/flightService"));
|
||||
const driverConflictService_1 = __importDefault(require("./services/driverConflictService"));
|
||||
const scheduleValidationService_1 = __importDefault(require("./services/scheduleValidationService"));
|
||||
const flightTrackingScheduler_1 = __importDefault(require("./services/flightTrackingScheduler"));
|
||||
const enhancedDataService_1 = __importDefault(require("./services/enhancedDataService"));
|
||||
const databaseService_1 = __importDefault(require("./services/databaseService"));
|
||||
const jwtKeyManager_1 = __importDefault(require("./services/jwtKeyManager")); // Initialize JWT Key Manager
|
||||
const errorHandler_1 = require("./middleware/errorHandler");
|
||||
const logger_1 = require("./middleware/logger");
|
||||
const validation_1 = require("./middleware/validation");
|
||||
const schemas_1 = require("./types/schemas");
|
||||
dotenv_1.default.config();
|
||||
const app = (0, express_1.default)();
|
||||
const port = process.env.PORT ? parseInt(process.env.PORT) : 3000;
|
||||
// Middleware
|
||||
app.use((0, cors_1.default)({
|
||||
origin: [
|
||||
process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||
'http://localhost:5173',
|
||||
'http://localhost:3000',
|
||||
'http://localhost', // Frontend Docker container (local testing)
|
||||
'https://bsa.madeamess.online' // Production frontend domain (where users access the site)
|
||||
],
|
||||
credentials: true
|
||||
}));
|
||||
app.use(express_1.default.json());
|
||||
app.use(express_1.default.urlencoded({ extended: true }));
|
||||
// Add request logging
|
||||
app.use(logger_1.requestLogger);
|
||||
// Simple JWT-based authentication - no passport needed
|
||||
// Authentication routes
|
||||
app.use('/auth', simpleAuth_1.default);
|
||||
// Temporary admin bypass route (remove after setup)
|
||||
app.get('/admin-bypass', (req, res) => {
|
||||
res.redirect(`${process.env.FRONTEND_URL || 'http://localhost:5173'}/admin?bypass=true`);
|
||||
});
|
||||
// Serve static files from public directory
|
||||
app.use(express_1.default.static('public'));
|
||||
// Enhanced health check endpoint with authentication system status
|
||||
app.get('/api/health', (0, errorHandler_1.asyncHandler)(async (req, res) => {
|
||||
const timestamp = new Date().toISOString();
|
||||
// Check JWT Key Manager status
|
||||
const jwtStatus = jwtKeyManager_1.default.getStatus();
|
||||
// Check environment variables
|
||||
const envCheck = {
|
||||
google_client_id: !!process.env.GOOGLE_CLIENT_ID,
|
||||
google_client_secret: !!process.env.GOOGLE_CLIENT_SECRET,
|
||||
google_redirect_uri: !!process.env.GOOGLE_REDIRECT_URI,
|
||||
frontend_url: !!process.env.FRONTEND_URL,
|
||||
database_url: !!process.env.DATABASE_URL,
|
||||
admin_password: !!process.env.ADMIN_PASSWORD
|
||||
};
|
||||
// Check database connectivity
|
||||
let databaseStatus = 'unknown';
|
||||
let userCount = 0;
|
||||
try {
|
||||
userCount = await databaseService_1.default.getUserCount();
|
||||
databaseStatus = 'connected';
|
||||
}
|
||||
catch (dbError) {
|
||||
databaseStatus = 'disconnected';
|
||||
console.error('Health check - Database error:', dbError);
|
||||
}
|
||||
// Overall system health
|
||||
const isHealthy = databaseStatus === 'connected' &&
|
||||
jwtStatus.hasCurrentKey &&
|
||||
envCheck.google_client_id &&
|
||||
envCheck.google_client_secret;
|
||||
const healthData = {
|
||||
status: isHealthy ? 'OK' : 'DEGRADED',
|
||||
timestamp,
|
||||
version: '1.0.0',
|
||||
environment: process.env.NODE_ENV || 'development',
|
||||
services: {
|
||||
database: {
|
||||
status: databaseStatus,
|
||||
user_count: databaseStatus === 'connected' ? userCount : null
|
||||
},
|
||||
authentication: {
|
||||
jwt_key_manager: jwtStatus,
|
||||
oauth_configured: envCheck.google_client_id && envCheck.google_client_secret,
|
||||
environment_variables: envCheck
|
||||
}
|
||||
},
|
||||
uptime: process.uptime(),
|
||||
memory: process.memoryUsage()
|
||||
};
|
||||
// Log health check for monitoring
|
||||
console.log(`🏥 Health Check [${timestamp}]:`, {
|
||||
status: healthData.status,
|
||||
database: databaseStatus,
|
||||
jwt_keys: jwtStatus.hasCurrentKey,
|
||||
oauth: envCheck.google_client_id && envCheck.google_client_secret
|
||||
});
|
||||
res.status(isHealthy ? 200 : 503).json(healthData);
|
||||
}));
|
||||
// Data is now persisted using dataService - no more in-memory storage!
|
||||
// Admin password - MUST be set via environment variable in production
|
||||
const ADMIN_PASSWORD = process.env.ADMIN_PASSWORD || 'CHANGE_ME_ADMIN_PASSWORD';
|
||||
// Initialize flight tracking scheduler
|
||||
const flightTracker = new flightTrackingScheduler_1.default(flightService_1.default);
|
||||
// VIP routes (protected)
|
||||
app.post('/api/vips', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), (0, validation_1.validate)(schemas_1.createVipSchema), (0, errorHandler_1.asyncHandler)(async (req, res) => {
|
||||
// Create a new VIP - data is already validated
|
||||
const { name, organization, department, // New: Office of Development or Admin
|
||||
transportMode, flightNumber, // Legacy single flight
|
||||
flights, // New: array of flights
|
||||
expectedArrival, needsAirportPickup, needsVenueTransport, notes } = req.body;
|
||||
const newVip = {
|
||||
id: Date.now().toString(), // Simple ID generation
|
||||
name,
|
||||
organization,
|
||||
department: department || 'Office of Development', // Default to Office of Development
|
||||
transportMode: transportMode || 'flight',
|
||||
// Support both legacy single flight and new multiple flights
|
||||
flightNumber: transportMode === 'flight' && !flights ? flightNumber : undefined,
|
||||
flights: transportMode === 'flight' && flights ? flights : undefined,
|
||||
expectedArrival: transportMode === 'self-driving' ? expectedArrival : undefined,
|
||||
arrivalTime: transportMode === 'flight' ? undefined : expectedArrival, // Legacy field for flight arrivals
|
||||
needsAirportPickup: transportMode === 'flight' ? (needsAirportPickup !== false) : false,
|
||||
needsVenueTransport: needsVenueTransport !== false, // Default to true
|
||||
assignedDriverIds: [],
|
||||
notes: notes || '',
|
||||
schedule: []
|
||||
};
|
||||
const savedVip = await enhancedDataService_1.default.addVip(newVip);
|
||||
// Add flights to tracking scheduler if applicable
|
||||
if (savedVip.transportMode === 'flight' && savedVip.flights && savedVip.flights.length > 0) {
|
||||
flightTracker.addVipFlights(savedVip.id, savedVip.name, savedVip.flights);
|
||||
}
|
||||
res.status(201).json(savedVip);
|
||||
}));
|
||||
app.get('/api/vips', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
try {
|
||||
// Fetch all VIPs
|
||||
const vips = await enhancedDataService_1.default.getVips();
|
||||
res.json(vips);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch VIPs' });
|
||||
}
|
||||
});
|
||||
app.put('/api/vips/:id', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), (0, validation_1.validate)(schemas_1.updateVipSchema), (0, errorHandler_1.asyncHandler)(async (req, res) => {
|
||||
// Update a VIP - data is already validated
|
||||
const { id } = req.params;
|
||||
const { name, organization, department, // New: Office of Development or Admin
|
||||
transportMode, flightNumber, // Legacy single flight
|
||||
flights, // New: array of flights
|
||||
expectedArrival, needsAirportPickup, needsVenueTransport, notes } = req.body;
|
||||
const updatedVip = {
|
||||
name,
|
||||
organization,
|
||||
department: department || 'Office of Development',
|
||||
transportMode: transportMode || 'flight',
|
||||
// Support both legacy single flight and new multiple flights
|
||||
flights: transportMode === 'flight' && flights ? flights : undefined,
|
||||
expectedArrival: transportMode === 'self-driving' ? expectedArrival : undefined,
|
||||
needsAirportPickup: transportMode === 'flight' ? (needsAirportPickup !== false) : false,
|
||||
needsVenueTransport: needsVenueTransport !== false,
|
||||
notes: notes || ''
|
||||
};
|
||||
const savedVip = await enhancedDataService_1.default.updateVip(id, updatedVip);
|
||||
if (!savedVip) {
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
}
|
||||
// Update flight tracking if needed
|
||||
if (savedVip.transportMode === 'flight') {
|
||||
// Remove old flights
|
||||
flightTracker.removeVipFlights(id);
|
||||
// Add new flights if any
|
||||
if (savedVip.flights && savedVip.flights.length > 0) {
|
||||
flightTracker.addVipFlights(savedVip.id, savedVip.name, savedVip.flights);
|
||||
}
|
||||
}
|
||||
res.json(savedVip);
|
||||
}));
|
||||
app.delete('/api/vips/:id', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), async (req, res) => {
|
||||
// Delete a VIP
|
||||
const { id } = req.params;
|
||||
try {
|
||||
const deletedVip = await enhancedDataService_1.default.deleteVip(id);
|
||||
if (!deletedVip) {
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
}
|
||||
// Remove from flight tracking
|
||||
flightTracker.removeVipFlights(id);
|
||||
res.json({ message: 'VIP deleted successfully', vip: deletedVip });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to delete VIP' });
|
||||
}
|
||||
});
|
||||
// Driver routes (protected)
|
||||
app.post('/api/drivers', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), (0, validation_1.validate)(schemas_1.createDriverSchema), (0, errorHandler_1.asyncHandler)(async (req, res) => {
|
||||
// Create a new driver - data is already validated
|
||||
const { name, phone, email, vehicleInfo, status } = req.body;
|
||||
const newDriver = {
|
||||
id: Date.now().toString(),
|
||||
name,
|
||||
phone,
|
||||
email,
|
||||
vehicleInfo,
|
||||
status: status || 'available',
|
||||
department: 'Office of Development', // Default to Office of Development
|
||||
currentLocation: { lat: 0, lng: 0 },
|
||||
assignedVipIds: []
|
||||
};
|
||||
const savedDriver = await enhancedDataService_1.default.addDriver(newDriver);
|
||||
res.status(201).json(savedDriver);
|
||||
}));
|
||||
app.get('/api/drivers', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
try {
|
||||
// Fetch all drivers
|
||||
const drivers = await enhancedDataService_1.default.getDrivers();
|
||||
res.json(drivers);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch drivers' });
|
||||
}
|
||||
});
|
||||
app.put('/api/drivers/:id', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), async (req, res) => {
|
||||
// Update a driver
|
||||
const { id } = req.params;
|
||||
const { name, phone, currentLocation, department } = req.body;
|
||||
try {
|
||||
const updatedDriver = {
|
||||
name,
|
||||
phone,
|
||||
department: department || 'Office of Development',
|
||||
currentLocation: currentLocation || { lat: 0, lng: 0 }
|
||||
};
|
||||
const savedDriver = await enhancedDataService_1.default.updateDriver(id, updatedDriver);
|
||||
if (!savedDriver) {
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
}
|
||||
res.json(savedDriver);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to update driver' });
|
||||
}
|
||||
});
|
||||
app.delete('/api/drivers/:id', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), async (req, res) => {
|
||||
// Delete a driver
|
||||
const { id } = req.params;
|
||||
try {
|
||||
const deletedDriver = await enhancedDataService_1.default.deleteDriver(id);
|
||||
if (!deletedDriver) {
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
}
|
||||
res.json({ message: 'Driver deleted successfully', driver: deletedDriver });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to delete driver' });
|
||||
}
|
||||
});
|
||||
// Enhanced flight tracking routes with date specificity
|
||||
app.get('/api/flights/:flightNumber', async (req, res) => {
|
||||
try {
|
||||
const { flightNumber } = req.params;
|
||||
const { date, departureAirport, arrivalAirport } = req.query;
|
||||
// Default to today if no date provided
|
||||
const flightDate = date || new Date().toISOString().split('T')[0];
|
||||
const flightData = await flightService_1.default.getFlightInfo({
|
||||
flightNumber,
|
||||
date: flightDate,
|
||||
departureAirport: departureAirport,
|
||||
arrivalAirport: arrivalAirport
|
||||
});
|
||||
if (flightData) {
|
||||
// Always return flight data for validation, even if date doesn't match
|
||||
res.json(flightData);
|
||||
}
|
||||
else {
|
||||
// Only return 404 if the flight number itself is invalid
|
||||
res.status(404).json({ error: 'Invalid flight number - this flight does not exist' });
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch flight data' });
|
||||
}
|
||||
});
|
||||
// Start periodic updates for a flight
|
||||
app.post('/api/flights/:flightNumber/track', async (req, res) => {
|
||||
try {
|
||||
const { flightNumber } = req.params;
|
||||
const { date, intervalMinutes = 5 } = req.body;
|
||||
if (!date) {
|
||||
return res.status(400).json({ error: 'Flight date is required' });
|
||||
}
|
||||
flightService_1.default.startPeriodicUpdates({
|
||||
flightNumber,
|
||||
date
|
||||
}, intervalMinutes);
|
||||
res.json({ message: `Started tracking ${flightNumber} on ${date}` });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to start flight tracking' });
|
||||
}
|
||||
});
|
||||
// Stop periodic updates for a flight
|
||||
app.delete('/api/flights/:flightNumber/track', async (req, res) => {
|
||||
try {
|
||||
const { flightNumber } = req.params;
|
||||
const { date } = req.query;
|
||||
if (!date) {
|
||||
return res.status(400).json({ error: 'Flight date is required' });
|
||||
}
|
||||
const key = `${flightNumber}_${date}`;
|
||||
flightService_1.default.stopPeriodicUpdates(key);
|
||||
res.json({ message: `Stopped tracking ${flightNumber} on ${date}` });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to stop flight tracking' });
|
||||
}
|
||||
});
|
||||
app.post('/api/flights/batch', async (req, res) => {
|
||||
try {
|
||||
const { flights } = req.body;
|
||||
if (!Array.isArray(flights)) {
|
||||
return res.status(400).json({ error: 'flights must be an array of {flightNumber, date} objects' });
|
||||
}
|
||||
// Validate flight objects
|
||||
for (const flight of flights) {
|
||||
if (!flight.flightNumber || !flight.date) {
|
||||
return res.status(400).json({ error: 'Each flight must have flightNumber and date' });
|
||||
}
|
||||
}
|
||||
const flightData = await flightService_1.default.getMultipleFlights(flights);
|
||||
res.json(flightData);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch flight data' });
|
||||
}
|
||||
});
|
||||
// Get flight tracking status
|
||||
app.get('/api/flights/tracking/status', (req, res) => {
|
||||
const status = flightTracker.getTrackingStatus();
|
||||
res.json(status);
|
||||
});
|
||||
// Schedule management routes (protected)
|
||||
app.get('/api/vips/:vipId/schedule', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
const { vipId } = req.params;
|
||||
try {
|
||||
const vipSchedule = await enhancedDataService_1.default.getSchedule(vipId);
|
||||
res.json(vipSchedule);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch schedule' });
|
||||
}
|
||||
});
|
||||
app.post('/api/vips/:vipId/schedule', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), async (req, res) => {
|
||||
const { vipId } = req.params;
|
||||
const { title, location, startTime, endTime, description, type, assignedDriverId } = req.body;
|
||||
// Validate the event
|
||||
const validationErrors = scheduleValidationService_1.default.validateEvent({
|
||||
title: title || '',
|
||||
location: location || '',
|
||||
startTime: startTime || '',
|
||||
endTime: endTime || '',
|
||||
type: type || ''
|
||||
}, false);
|
||||
const { critical, warnings } = scheduleValidationService_1.default.categorizeErrors(validationErrors);
|
||||
// Return validation errors if any critical errors exist
|
||||
if (critical.length > 0) {
|
||||
return res.status(400).json({
|
||||
error: 'Validation failed',
|
||||
validationErrors: critical,
|
||||
warnings: warnings,
|
||||
message: scheduleValidationService_1.default.getErrorSummary(critical)
|
||||
});
|
||||
}
|
||||
const newEvent = {
|
||||
id: Date.now().toString(),
|
||||
title,
|
||||
location,
|
||||
startTime,
|
||||
endTime,
|
||||
description: description || '',
|
||||
assignedDriverId: assignedDriverId || '',
|
||||
status: 'scheduled',
|
||||
type
|
||||
};
|
||||
try {
|
||||
const savedEvent = await enhancedDataService_1.default.addScheduleEvent(vipId, newEvent);
|
||||
// Include warnings in the response if any
|
||||
const response = { ...savedEvent };
|
||||
if (warnings.length > 0) {
|
||||
response.warnings = warnings;
|
||||
}
|
||||
res.status(201).json(response);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to create schedule event' });
|
||||
}
|
||||
});
|
||||
app.put('/api/vips/:vipId/schedule/:eventId', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), async (req, res) => {
|
||||
const { vipId, eventId } = req.params;
|
||||
const { title, location, startTime, endTime, description, type, assignedDriverId, status } = req.body;
|
||||
// Validate the updated event (with edit flag for grace period)
|
||||
const validationErrors = scheduleValidationService_1.default.validateEvent({
|
||||
title: title || '',
|
||||
location: location || '',
|
||||
startTime: startTime || '',
|
||||
endTime: endTime || '',
|
||||
type: type || ''
|
||||
}, true);
|
||||
const { critical, warnings } = scheduleValidationService_1.default.categorizeErrors(validationErrors);
|
||||
// Return validation errors if any critical errors exist
|
||||
if (critical.length > 0) {
|
||||
return res.status(400).json({
|
||||
error: 'Validation failed',
|
||||
validationErrors: critical,
|
||||
warnings: warnings,
|
||||
message: scheduleValidationService_1.default.getErrorSummary(critical)
|
||||
});
|
||||
}
|
||||
const updatedEvent = {
|
||||
id: eventId,
|
||||
title,
|
||||
location,
|
||||
startTime,
|
||||
endTime,
|
||||
description: description || '',
|
||||
assignedDriverId: assignedDriverId || '',
|
||||
type,
|
||||
status: status || 'scheduled'
|
||||
};
|
||||
try {
|
||||
const savedEvent = await enhancedDataService_1.default.updateScheduleEvent(vipId, eventId, updatedEvent);
|
||||
if (!savedEvent) {
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
}
|
||||
// Include warnings in the response if any
|
||||
const response = { ...savedEvent };
|
||||
if (warnings.length > 0) {
|
||||
response.warnings = warnings;
|
||||
}
|
||||
res.json(response);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to update schedule event' });
|
||||
}
|
||||
});
|
||||
app.patch('/api/vips/:vipId/schedule/:eventId/status', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
const { vipId, eventId } = req.params;
|
||||
const { status } = req.body;
|
||||
try {
|
||||
const currentSchedule = await enhancedDataService_1.default.getSchedule(vipId);
|
||||
const currentEvent = currentSchedule.find((event) => event.id === eventId);
|
||||
if (!currentEvent) {
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
}
|
||||
const updatedEvent = { ...currentEvent, status };
|
||||
const savedEvent = await enhancedDataService_1.default.updateScheduleEvent(vipId, eventId, updatedEvent);
|
||||
if (!savedEvent) {
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
}
|
||||
res.json(savedEvent);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to update event status' });
|
||||
}
|
||||
});
|
||||
app.delete('/api/vips/:vipId/schedule/:eventId', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['coordinator', 'administrator']), async (req, res) => {
|
||||
const { vipId, eventId } = req.params;
|
||||
try {
|
||||
const deletedEvent = await enhancedDataService_1.default.deleteScheduleEvent(vipId, eventId);
|
||||
if (!deletedEvent) {
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
}
|
||||
res.json({ message: 'Event deleted successfully', event: deletedEvent });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to delete schedule event' });
|
||||
}
|
||||
});
|
||||
// Driver availability and conflict checking (protected)
|
||||
app.post('/api/drivers/availability', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
const { startTime, endTime, location } = req.body;
|
||||
if (!startTime || !endTime) {
|
||||
return res.status(400).json({ error: 'startTime and endTime are required' });
|
||||
}
|
||||
try {
|
||||
const allSchedules = await enhancedDataService_1.default.getAllSchedules();
|
||||
const drivers = await enhancedDataService_1.default.getDrivers();
|
||||
const availability = driverConflictService_1.default.getDriverAvailability({ startTime, endTime, location: location || '' }, allSchedules, drivers);
|
||||
res.json(availability);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to check driver availability' });
|
||||
}
|
||||
});
|
||||
// Check conflicts for specific driver assignment (protected)
|
||||
app.post('/api/drivers/:driverId/conflicts', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
const { driverId } = req.params;
|
||||
const { startTime, endTime, location } = req.body;
|
||||
if (!startTime || !endTime) {
|
||||
return res.status(400).json({ error: 'startTime and endTime are required' });
|
||||
}
|
||||
try {
|
||||
const allSchedules = await enhancedDataService_1.default.getAllSchedules();
|
||||
const drivers = await enhancedDataService_1.default.getDrivers();
|
||||
const conflicts = driverConflictService_1.default.checkDriverConflicts(driverId, { startTime, endTime, location: location || '' }, allSchedules, drivers);
|
||||
res.json({ conflicts });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to check driver conflicts' });
|
||||
}
|
||||
});
|
||||
// Get driver's complete schedule (protected)
|
||||
app.get('/api/drivers/:driverId/schedule', simpleAuth_1.requireAuth, async (req, res) => {
|
||||
const { driverId } = req.params;
|
||||
try {
|
||||
const drivers = await enhancedDataService_1.default.getDrivers();
|
||||
const driver = drivers.find((d) => d.id === driverId);
|
||||
if (!driver) {
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
}
|
||||
// Get all events assigned to this driver across all VIPs
|
||||
const driverSchedule = [];
|
||||
const allSchedules = await enhancedDataService_1.default.getAllSchedules();
|
||||
const vips = await enhancedDataService_1.default.getVips();
|
||||
Object.entries(allSchedules).forEach(([vipId, events]) => {
|
||||
events.forEach((event) => {
|
||||
if (event.assignedDriverId === driverId) {
|
||||
// Get VIP name
|
||||
const vip = vips.find((v) => v.id === vipId);
|
||||
driverSchedule.push({
|
||||
...event,
|
||||
vipId,
|
||||
vipName: vip ? vip.name : 'Unknown VIP'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// Sort by start time
|
||||
driverSchedule.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime());
|
||||
res.json({
|
||||
driver: {
|
||||
id: driver.id,
|
||||
name: driver.name,
|
||||
phone: driver.phone,
|
||||
department: driver.department
|
||||
},
|
||||
schedule: driverSchedule
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch driver schedule' });
|
||||
}
|
||||
});
|
||||
// Admin routes
|
||||
app.post('/api/admin/authenticate', (req, res) => {
|
||||
const { password } = req.body;
|
||||
if (password === ADMIN_PASSWORD) {
|
||||
res.json({ success: true });
|
||||
}
|
||||
else {
|
||||
res.status(401).json({ error: 'Invalid password' });
|
||||
}
|
||||
});
|
||||
app.get('/api/admin/settings', async (req, res) => {
|
||||
const adminAuth = req.headers['admin-auth'];
|
||||
if (adminAuth !== 'true') {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
try {
|
||||
const adminSettings = await enhancedDataService_1.default.getAdminSettings();
|
||||
// Return settings but mask API keys for display only
|
||||
// IMPORTANT: Don't return the actual keys, just indicate they exist
|
||||
const maskedSettings = {
|
||||
apiKeys: {
|
||||
aviationStackKey: adminSettings.apiKeys.aviationStackKey ? '***' + adminSettings.apiKeys.aviationStackKey.slice(-4) : '',
|
||||
googleMapsKey: adminSettings.apiKeys.googleMapsKey ? '***' + adminSettings.apiKeys.googleMapsKey.slice(-4) : '',
|
||||
twilioKey: adminSettings.apiKeys.twilioKey ? '***' + adminSettings.apiKeys.twilioKey.slice(-4) : '',
|
||||
googleClientId: adminSettings.apiKeys.googleClientId ? '***' + adminSettings.apiKeys.googleClientId.slice(-4) : '',
|
||||
googleClientSecret: adminSettings.apiKeys.googleClientSecret ? '***' + adminSettings.apiKeys.googleClientSecret.slice(-4) : ''
|
||||
},
|
||||
systemSettings: adminSettings.systemSettings
|
||||
};
|
||||
res.json(maskedSettings);
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to fetch admin settings' });
|
||||
}
|
||||
});
|
||||
app.post('/api/admin/settings', async (req, res) => {
|
||||
const adminAuth = req.headers['admin-auth'];
|
||||
if (adminAuth !== 'true') {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
try {
|
||||
const { apiKeys, systemSettings } = req.body;
|
||||
const currentSettings = await enhancedDataService_1.default.getAdminSettings();
|
||||
// Update API keys (only if provided and not masked)
|
||||
if (apiKeys) {
|
||||
if (apiKeys.aviationStackKey && !apiKeys.aviationStackKey.startsWith('***')) {
|
||||
currentSettings.apiKeys.aviationStackKey = apiKeys.aviationStackKey;
|
||||
// Update the environment variable for the flight service
|
||||
process.env.AVIATIONSTACK_API_KEY = apiKeys.aviationStackKey;
|
||||
}
|
||||
if (apiKeys.googleMapsKey && !apiKeys.googleMapsKey.startsWith('***')) {
|
||||
currentSettings.apiKeys.googleMapsKey = apiKeys.googleMapsKey;
|
||||
}
|
||||
if (apiKeys.twilioKey && !apiKeys.twilioKey.startsWith('***')) {
|
||||
currentSettings.apiKeys.twilioKey = apiKeys.twilioKey;
|
||||
}
|
||||
if (apiKeys.googleClientId && !apiKeys.googleClientId.startsWith('***')) {
|
||||
currentSettings.apiKeys.googleClientId = apiKeys.googleClientId;
|
||||
// Update the environment variable for Google OAuth
|
||||
process.env.GOOGLE_CLIENT_ID = apiKeys.googleClientId;
|
||||
}
|
||||
if (apiKeys.googleClientSecret && !apiKeys.googleClientSecret.startsWith('***')) {
|
||||
currentSettings.apiKeys.googleClientSecret = apiKeys.googleClientSecret;
|
||||
// Update the environment variable for Google OAuth
|
||||
process.env.GOOGLE_CLIENT_SECRET = apiKeys.googleClientSecret;
|
||||
}
|
||||
}
|
||||
// Update system settings
|
||||
if (systemSettings) {
|
||||
currentSettings.systemSettings = { ...currentSettings.systemSettings, ...systemSettings };
|
||||
}
|
||||
// Save the updated settings
|
||||
await enhancedDataService_1.default.updateAdminSettings(currentSettings);
|
||||
res.json({ success: true });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to update admin settings' });
|
||||
}
|
||||
});
|
||||
app.post('/api/admin/test-api/:apiType', async (req, res) => {
|
||||
const adminAuth = req.headers['admin-auth'];
|
||||
if (adminAuth !== 'true') {
|
||||
return res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
const { apiType } = req.params;
|
||||
const { apiKey } = req.body;
|
||||
try {
|
||||
switch (apiType) {
|
||||
case 'aviationStackKey':
|
||||
// Test AviationStack API
|
||||
const testUrl = `http://api.aviationstack.com/v1/flights?access_key=${apiKey}&limit=1`;
|
||||
const response = await fetch(testUrl);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
if (data.error) {
|
||||
res.status(400).json({ error: data.error.message || 'Invalid API key' });
|
||||
}
|
||||
else {
|
||||
res.json({ success: true, message: 'API key is valid!' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
res.status(400).json({ error: 'Failed to validate API key' });
|
||||
}
|
||||
break;
|
||||
case 'googleMapsKey':
|
||||
res.json({ success: true, message: 'Google Maps API testing not yet implemented' });
|
||||
break;
|
||||
case 'twilioKey':
|
||||
res.json({ success: true, message: 'Twilio API testing not yet implemented' });
|
||||
break;
|
||||
default:
|
||||
res.status(400).json({ error: 'Unknown API type' });
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to test API connection' });
|
||||
}
|
||||
});
|
||||
// JWT Key Management endpoints (admin only)
|
||||
app.get('/api/admin/jwt-status', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['administrator']), (req, res) => {
|
||||
const jwtKeyManager = require('./services/jwtKeyManager').default;
|
||||
const status = jwtKeyManager.getStatus();
|
||||
res.json({
|
||||
keyRotationEnabled: true,
|
||||
rotationInterval: '24 hours',
|
||||
gracePeriod: '24 hours',
|
||||
...status,
|
||||
message: 'JWT keys are automatically rotated every 24 hours for enhanced security'
|
||||
});
|
||||
});
|
||||
app.post('/api/admin/jwt-rotate', simpleAuth_1.requireAuth, (0, simpleAuth_1.requireRole)(['administrator']), (req, res) => {
|
||||
const jwtKeyManager = require('./services/jwtKeyManager').default;
|
||||
try {
|
||||
jwtKeyManager.forceRotation();
|
||||
res.json({
|
||||
success: true,
|
||||
message: 'JWT key rotation triggered successfully. New tokens will use the new key.'
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
res.status(500).json({ error: 'Failed to rotate JWT keys' });
|
||||
}
|
||||
});
|
||||
// Initialize database and start server
|
||||
// Add 404 handler for undefined routes
|
||||
app.use(errorHandler_1.notFoundHandler);
|
||||
// Add error logging middleware
|
||||
app.use(logger_1.errorLogger);
|
||||
// Add global error handler (must be last!)
|
||||
app.use(errorHandler_1.errorHandler);
|
||||
async function startServer() {
|
||||
try {
|
||||
// Initialize database schema and migrate data
|
||||
await databaseService_1.default.initializeDatabase();
|
||||
console.log('✅ Database initialization completed');
|
||||
// Start the server
|
||||
app.listen(port, () => {
|
||||
console.log(`🚀 Server is running on port ${port}`);
|
||||
console.log(`🔐 Admin password: ${ADMIN_PASSWORD}`);
|
||||
console.log(`📊 Admin dashboard: http://localhost:${port === 3000 ? 5173 : port}/admin`);
|
||||
console.log(`🏥 Health check: http://localhost:${port}/api/health`);
|
||||
console.log(`📚 API docs: http://localhost:${port}/api-docs.html`);
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Failed to start server:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
startServer();
|
||||
//# sourceMappingURL=index.original.js.map
|
||||
1
backend-old-20260125/dist/index.original.js.map
vendored
Normal file
1
backend-old-20260125/dist/index.original.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
backend-old-20260125/dist/indexSimplified.d.ts
vendored
Normal file
2
backend-old-20260125/dist/indexSimplified.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {};
|
||||
//# sourceMappingURL=indexSimplified.d.ts.map
|
||||
1
backend-old-20260125/dist/indexSimplified.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/indexSimplified.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"indexSimplified.d.ts","sourceRoot":"","sources":["../src/indexSimplified.ts"],"names":[],"mappings":""}
|
||||
217
backend-old-20260125/dist/indexSimplified.js
vendored
Normal file
217
backend-old-20260125/dist/indexSimplified.js
vendored
Normal file
@@ -0,0 +1,217 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const cors_1 = __importDefault(require("cors"));
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
const authService_1 = __importDefault(require("./services/authService"));
|
||||
const unifiedDataService_1 = __importDefault(require("./services/unifiedDataService"));
|
||||
const simpleValidation_1 = require("./middleware/simpleValidation");
|
||||
const errorHandler_1 = require("./middleware/errorHandler");
|
||||
dotenv_1.default.config();
|
||||
const app = (0, express_1.default)();
|
||||
const port = process.env.PORT || 3000;
|
||||
// Middleware
|
||||
app.use((0, cors_1.default)({
|
||||
origin: [
|
||||
process.env.FRONTEND_URL || 'http://localhost:5173',
|
||||
'https://bsa.madeamess.online'
|
||||
],
|
||||
credentials: true
|
||||
}));
|
||||
app.use(express_1.default.json());
|
||||
app.use(express_1.default.static('public'));
|
||||
// Health check
|
||||
app.get('/api/health', (req, res) => {
|
||||
res.json({
|
||||
status: 'OK',
|
||||
timestamp: new Date().toISOString(),
|
||||
version: '2.0.0' // Simplified version
|
||||
});
|
||||
});
|
||||
// Auth routes
|
||||
app.get('/auth/google', (req, res) => {
|
||||
res.redirect(authService_1.default.getGoogleAuthUrl());
|
||||
});
|
||||
app.post('/auth/google/callback', async (req, res) => {
|
||||
try {
|
||||
const { code } = req.body;
|
||||
const { user, token } = await authService_1.default.handleGoogleAuth(code);
|
||||
res.json({ user, token });
|
||||
}
|
||||
catch (error) {
|
||||
res.status(400).json({ error: 'Authentication failed' });
|
||||
}
|
||||
});
|
||||
app.get('/auth/me', authService_1.default.requireAuth, (req, res) => {
|
||||
res.json(req.user);
|
||||
});
|
||||
app.post('/auth/logout', (req, res) => {
|
||||
res.json({ message: 'Logged out successfully' });
|
||||
});
|
||||
// VIP routes
|
||||
app.get('/api/vips', authService_1.default.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const vips = await unifiedDataService_1.default.getVips();
|
||||
res.json(vips);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.get('/api/vips/:id', authService_1.default.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.getVipById(req.params.id);
|
||||
if (!vip)
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
res.json(vip);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/vips', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.createVip), async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.createVip(req.body);
|
||||
res.status(201).json(vip);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.put('/api/vips/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.updateVip), async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.updateVip(req.params.id, req.body);
|
||||
if (!vip)
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
res.json(vip);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.delete('/api/vips/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const vip = await unifiedDataService_1.default.deleteVip(req.params.id);
|
||||
if (!vip)
|
||||
return res.status(404).json({ error: 'VIP not found' });
|
||||
res.json({ message: 'VIP deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Driver routes
|
||||
app.get('/api/drivers', authService_1.default.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const drivers = await unifiedDataService_1.default.getDrivers();
|
||||
res.json(drivers);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/drivers', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.createDriver), async (req, res, next) => {
|
||||
try {
|
||||
const driver = await unifiedDataService_1.default.createDriver(req.body);
|
||||
res.status(201).json(driver);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.put('/api/drivers/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.updateDriver), async (req, res, next) => {
|
||||
try {
|
||||
const driver = await unifiedDataService_1.default.updateDriver(req.params.id, req.body);
|
||||
if (!driver)
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
res.json(driver);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.delete('/api/drivers/:id', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const driver = await unifiedDataService_1.default.deleteDriver(req.params.id);
|
||||
if (!driver)
|
||||
return res.status(404).json({ error: 'Driver not found' });
|
||||
res.json({ message: 'Driver deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Schedule routes
|
||||
app.get('/api/vips/:vipId/schedule', authService_1.default.requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const schedule = await unifiedDataService_1.default.getScheduleByVipId(req.params.vipId);
|
||||
res.json(schedule);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/vips/:vipId/schedule', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.createScheduleEvent), async (req, res, next) => {
|
||||
try {
|
||||
const event = await unifiedDataService_1.default.createScheduleEvent(req.params.vipId, req.body);
|
||||
res.status(201).json(event);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.put('/api/vips/:vipId/schedule/:eventId', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), (0, simpleValidation_1.validate)(simpleValidation_1.schemas.updateScheduleEvent), async (req, res, next) => {
|
||||
try {
|
||||
const event = await unifiedDataService_1.default.updateScheduleEvent(req.params.eventId, req.body);
|
||||
if (!event)
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
res.json(event);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.delete('/api/vips/:vipId/schedule/:eventId', authService_1.default.requireAuth, authService_1.default.requireRole(['coordinator', 'administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const event = await unifiedDataService_1.default.deleteScheduleEvent(req.params.eventId);
|
||||
if (!event)
|
||||
return res.status(404).json({ error: 'Event not found' });
|
||||
res.json({ message: 'Event deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Admin routes (simplified)
|
||||
app.get('/api/admin/settings', authService_1.default.requireAuth, authService_1.default.requireRole(['administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const settings = await unifiedDataService_1.default.getAdminSettings();
|
||||
res.json(settings);
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
app.post('/api/admin/settings', authService_1.default.requireAuth, authService_1.default.requireRole(['administrator']), async (req, res, next) => {
|
||||
try {
|
||||
const { key, value } = req.body;
|
||||
await unifiedDataService_1.default.updateAdminSetting(key, value);
|
||||
res.json({ message: 'Setting updated successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
// Error handling
|
||||
app.use(errorHandler_1.notFoundHandler);
|
||||
app.use(errorHandler_1.errorHandler);
|
||||
// Start server
|
||||
app.listen(port, () => {
|
||||
console.log(`🚀 Server running on port ${port}`);
|
||||
console.log(`🏥 Health check: http://localhost:${port}/api/health`);
|
||||
console.log(`📚 API docs: http://localhost:${port}/api-docs.html`);
|
||||
});
|
||||
//# sourceMappingURL=indexSimplified.js.map
|
||||
1
backend-old-20260125/dist/indexSimplified.js.map
vendored
Normal file
1
backend-old-20260125/dist/indexSimplified.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
6
backend-old-20260125/dist/middleware/errorHandler.d.ts
vendored
Normal file
6
backend-old-20260125/dist/middleware/errorHandler.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { AppError } from '../types/errors';
|
||||
export declare const errorHandler: (err: Error | AppError, req: Request, res: Response, next: NextFunction) => void;
|
||||
export declare const asyncHandler: (fn: Function) => (req: Request, res: Response, next: NextFunction) => void;
|
||||
export declare const notFoundHandler: (req: Request, res: Response) => void;
|
||||
//# sourceMappingURL=errorHandler.d.ts.map
|
||||
1
backend-old-20260125/dist/middleware/errorHandler.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/errorHandler.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"errorHandler.d.ts","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,QAAQ,EAAiB,MAAM,iBAAiB,CAAC;AAE1D,eAAO,MAAM,YAAY,GACvB,KAAK,KAAK,GAAG,QAAQ,EACrB,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,MAAM,YAAY,KACjB,IA+CF,CAAC;AAGF,eAAO,MAAM,YAAY,GAAI,IAAI,QAAQ,MAC/B,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,SAGxD,CAAC;AAGF,eAAO,MAAM,eAAe,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,KAAG,IAY7D,CAAC"}
|
||||
75
backend-old-20260125/dist/middleware/errorHandler.js
vendored
Normal file
75
backend-old-20260125/dist/middleware/errorHandler.js
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.notFoundHandler = exports.asyncHandler = exports.errorHandler = void 0;
|
||||
const errors_1 = require("../types/errors");
|
||||
const errorHandler = (err, req, res, next) => {
|
||||
// Default error values
|
||||
let statusCode = 500;
|
||||
let message = 'Internal server error';
|
||||
let isOperational = false;
|
||||
// If it's an AppError, use its properties
|
||||
if (err instanceof errors_1.AppError) {
|
||||
statusCode = err.statusCode;
|
||||
message = err.message;
|
||||
isOperational = err.isOperational;
|
||||
}
|
||||
else if (err.name === 'ValidationError') {
|
||||
// Handle validation errors (e.g., from libraries)
|
||||
statusCode = 400;
|
||||
message = err.message;
|
||||
isOperational = true;
|
||||
}
|
||||
else if (err.name === 'JsonWebTokenError') {
|
||||
statusCode = 401;
|
||||
message = 'Invalid token';
|
||||
isOperational = true;
|
||||
}
|
||||
else if (err.name === 'TokenExpiredError') {
|
||||
statusCode = 401;
|
||||
message = 'Token expired';
|
||||
isOperational = true;
|
||||
}
|
||||
// Log error details (in production, use proper logging service)
|
||||
if (!isOperational) {
|
||||
console.error('ERROR 💥:', err);
|
||||
}
|
||||
else {
|
||||
console.error(`Operational error: ${message}`);
|
||||
}
|
||||
// Create error response
|
||||
const errorResponse = {
|
||||
success: false,
|
||||
error: {
|
||||
message,
|
||||
...(process.env.NODE_ENV === 'development' && {
|
||||
details: err.stack
|
||||
})
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
path: req.path
|
||||
};
|
||||
res.status(statusCode).json(errorResponse);
|
||||
};
|
||||
exports.errorHandler = errorHandler;
|
||||
// Async error wrapper to catch errors in async route handlers
|
||||
const asyncHandler = (fn) => {
|
||||
return (req, res, next) => {
|
||||
Promise.resolve(fn(req, res, next)).catch(next);
|
||||
};
|
||||
};
|
||||
exports.asyncHandler = asyncHandler;
|
||||
// 404 Not Found handler
|
||||
const notFoundHandler = (req, res) => {
|
||||
const errorResponse = {
|
||||
success: false,
|
||||
error: {
|
||||
message: `Route ${req.originalUrl} not found`,
|
||||
code: 'ROUTE_NOT_FOUND'
|
||||
},
|
||||
timestamp: new Date().toISOString(),
|
||||
path: req.path
|
||||
};
|
||||
res.status(404).json(errorResponse);
|
||||
};
|
||||
exports.notFoundHandler = notFoundHandler;
|
||||
//# sourceMappingURL=errorHandler.js.map
|
||||
1
backend-old-20260125/dist/middleware/errorHandler.js.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/errorHandler.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"errorHandler.js","sourceRoot":"","sources":["../../src/middleware/errorHandler.ts"],"names":[],"mappings":";;;AACA,4CAA0D;AAEnD,MAAM,YAAY,GAAG,CAC1B,GAAqB,EACrB,GAAY,EACZ,GAAa,EACb,IAAkB,EACZ,EAAE;IACR,uBAAuB;IACvB,IAAI,UAAU,GAAG,GAAG,CAAC;IACrB,IAAI,OAAO,GAAG,uBAAuB,CAAC;IACtC,IAAI,aAAa,GAAG,KAAK,CAAC;IAE1B,0CAA0C;IAC1C,IAAI,GAAG,YAAY,iBAAQ,EAAE,CAAC;QAC5B,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;QAC5B,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QACtB,aAAa,GAAG,GAAG,CAAC,aAAa,CAAC;IACpC,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;QAC1C,kDAAkD;QAClD,UAAU,GAAG,GAAG,CAAC;QACjB,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;QACtB,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QAC5C,UAAU,GAAG,GAAG,CAAC;QACjB,OAAO,GAAG,eAAe,CAAC;QAC1B,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;SAAM,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QAC5C,UAAU,GAAG,GAAG,CAAC;QACjB,OAAO,GAAG,eAAe,CAAC;QAC1B,aAAa,GAAG,IAAI,CAAC;IACvB,CAAC;IAED,gEAAgE;IAChE,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,sBAAsB,OAAO,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,wBAAwB;IACxB,MAAM,aAAa,GAAkB;QACnC,OAAO,EAAE,KAAK;QACd,KAAK,EAAE;YACL,OAAO;YACP,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI;gBAC5C,OAAO,EAAE,GAAG,CAAC,KAAK;aACnB,CAAC;SACH;QACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,GAAG,CAAC,IAAI;KACf,CAAC;IAEF,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAC7C,CAAC,CAAC;AApDW,QAAA,YAAY,gBAoDvB;AAEF,8DAA8D;AACvD,MAAM,YAAY,GAAG,CAAC,EAAY,EAAE,EAAE;IAC3C,OAAO,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QACzD,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC,CAAC;AACJ,CAAC,CAAC;AAJW,QAAA,YAAY,gBAIvB;AAEF,wBAAwB;AACjB,MAAM,eAAe,GAAG,CAAC,GAAY,EAAE,GAAa,EAAQ,EAAE;IACnE,MAAM,aAAa,GAAkB;QACnC,OAAO,EAAE,KAAK;QACd,KAAK,EAAE;YACL,OAAO,EAAE,SAAS,GAAG,CAAC,WAAW,YAAY;YAC7C,IAAI,EAAE,iBAAiB;SACxB;QACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,IAAI,EAAE,GAAG,CAAC,IAAI;KACf,CAAC;IAEF,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AACtC,CAAC,CAAC;AAZW,QAAA,eAAe,mBAY1B"}
|
||||
15
backend-old-20260125/dist/middleware/logger.d.ts
vendored
Normal file
15
backend-old-20260125/dist/middleware/logger.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
declare module 'express' {
|
||||
interface Request {
|
||||
requestId?: string;
|
||||
user?: {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
role: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
export declare const requestLogger: (req: Request, res: Response, next: NextFunction) => void;
|
||||
export declare const errorLogger: (err: Error, req: Request, res: Response, next: NextFunction) => void;
|
||||
//# sourceMappingURL=logger.d.ts.map
|
||||
1
backend-old-20260125/dist/middleware/logger.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/logger.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAa1D,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,OAAO;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,IAAI,CAAC,EAAE;YACL,EAAE,EAAE,MAAM,CAAC;YACX,KAAK,EAAE,MAAM,CAAC;YACd,IAAI,EAAE,MAAM,CAAC;YACb,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;KACH;CACF;AAQD,eAAO,MAAM,aAAa,GAAI,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAkC/E,CAAC;AAGF,eAAO,MAAM,WAAW,GAAI,KAAK,KAAK,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,KAAG,IAmBzF,CAAC"}
|
||||
58
backend-old-20260125/dist/middleware/logger.js
vendored
Normal file
58
backend-old-20260125/dist/middleware/logger.js
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.errorLogger = exports.requestLogger = void 0;
|
||||
// Generate a simple request ID
|
||||
const generateRequestId = () => {
|
||||
return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
||||
};
|
||||
// Request logger middleware
|
||||
const requestLogger = (req, res, next) => {
|
||||
const requestId = generateRequestId();
|
||||
// Attach request ID to request object
|
||||
req.requestId = requestId;
|
||||
const startTime = Date.now();
|
||||
// Log request
|
||||
const logContext = {
|
||||
requestId,
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
ip: req.ip || 'unknown',
|
||||
userAgent: req.get('user-agent'),
|
||||
userId: req.user?.id
|
||||
};
|
||||
console.log(`[${new Date().toISOString()}] REQUEST:`, JSON.stringify(logContext));
|
||||
// Log response
|
||||
const originalSend = res.send;
|
||||
res.send = function (data) {
|
||||
const duration = Date.now() - startTime;
|
||||
console.log(`[${new Date().toISOString()}] RESPONSE:`, JSON.stringify({
|
||||
requestId,
|
||||
statusCode: res.statusCode,
|
||||
duration: `${duration}ms`
|
||||
}));
|
||||
return originalSend.call(this, data);
|
||||
};
|
||||
next();
|
||||
};
|
||||
exports.requestLogger = requestLogger;
|
||||
// Error logger (to be used before error handler)
|
||||
const errorLogger = (err, req, res, next) => {
|
||||
const requestId = req.requestId || 'unknown';
|
||||
console.error(`[${new Date().toISOString()}] ERROR:`, JSON.stringify({
|
||||
requestId,
|
||||
error: {
|
||||
name: err.name,
|
||||
message: err.message,
|
||||
stack: err.stack
|
||||
},
|
||||
request: {
|
||||
method: req.method,
|
||||
url: req.originalUrl,
|
||||
headers: req.headers,
|
||||
body: req.body
|
||||
}
|
||||
}));
|
||||
next(err);
|
||||
};
|
||||
exports.errorLogger = errorLogger;
|
||||
//# sourceMappingURL=logger.js.map
|
||||
1
backend-old-20260125/dist/middleware/logger.js.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/logger.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/middleware/logger.ts"],"names":[],"mappings":";;;AAyBA,+BAA+B;AAC/B,MAAM,iBAAiB,GAAG,GAAW,EAAE;IACrC,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AACpE,CAAC,CAAC;AAEF,4BAA4B;AACrB,MAAM,aAAa,GAAG,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;IACrF,MAAM,SAAS,GAAG,iBAAiB,EAAE,CAAC;IAEtC,sCAAsC;IACtC,GAAG,CAAC,SAAS,GAAG,SAAS,CAAC;IAE1B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,cAAc;IACd,MAAM,UAAU,GAAe;QAC7B,SAAS;QACT,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,GAAG,EAAE,GAAG,CAAC,WAAW;QACpB,EAAE,EAAE,GAAG,CAAC,EAAE,IAAI,SAAS;QACvB,SAAS,EAAE,GAAG,CAAC,GAAG,CAAC,YAAY,CAAC;QAChC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,EAAE;KACrB,CAAC;IAEF,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;IAElF,eAAe;IACf,MAAM,YAAY,GAAG,GAAG,CAAC,IAAI,CAAC;IAC9B,GAAG,CAAC,IAAI,GAAG,UAAS,IAAa;QAC/B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,aAAa,EAAE,IAAI,CAAC,SAAS,CAAC;YACpE,SAAS;YACT,UAAU,EAAE,GAAG,CAAC,UAAU;YAC1B,QAAQ,EAAE,GAAG,QAAQ,IAAI;SAC1B,CAAC,CAAC,CAAC;QAEJ,OAAO,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,CAAC,CAAC;IAEF,IAAI,EAAE,CAAC;AACT,CAAC,CAAC;AAlCW,QAAA,aAAa,iBAkCxB;AAEF,iDAAiD;AAC1C,MAAM,WAAW,GAAG,CAAC,GAAU,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAQ,EAAE;IAC/F,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC;IAE7C,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC;QACnE,SAAS;QACT,KAAK,EAAE;YACL,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,KAAK,EAAE,GAAG,CAAC,KAAK;SACjB;QACD,OAAO,EAAE;YACP,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,GAAG,EAAE,GAAG,CAAC,WAAW;YACpB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;SACf;KACF,CAAC,CAAC,CAAC;IAEJ,IAAI,CAAC,GAAG,CAAC,CAAC;AACZ,CAAC,CAAC;AAnBW,QAAA,WAAW,eAmBtB"}
|
||||
197
backend-old-20260125/dist/middleware/simpleValidation.d.ts
vendored
Normal file
197
backend-old-20260125/dist/middleware/simpleValidation.d.ts
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
import { z } from 'zod';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
export declare const schemas: {
|
||||
createVip: z.ZodObject<{
|
||||
name: z.ZodString;
|
||||
organization: z.ZodOptional<z.ZodString>;
|
||||
department: z.ZodDefault<z.ZodEnum<["Office of Development", "Admin"]>>;
|
||||
transportMode: z.ZodDefault<z.ZodEnum<["flight", "self-driving"]>>;
|
||||
flights: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
||||
flightNumber: z.ZodString;
|
||||
airline: z.ZodOptional<z.ZodString>;
|
||||
scheduledArrival: z.ZodString;
|
||||
scheduledDeparture: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}>, "many">>;
|
||||
expectedArrival: z.ZodOptional<z.ZodString>;
|
||||
needsAirportPickup: z.ZodDefault<z.ZodBoolean>;
|
||||
needsVenueTransport: z.ZodDefault<z.ZodBoolean>;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name: string;
|
||||
department: "Office of Development" | "Admin";
|
||||
transportMode: "flight" | "self-driving";
|
||||
needsAirportPickup: boolean;
|
||||
needsVenueTransport: boolean;
|
||||
organization?: string | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | undefined;
|
||||
notes?: string | undefined;
|
||||
}, {
|
||||
name: string;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}>;
|
||||
updateVip: z.ZodObject<{
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
organization: z.ZodOptional<z.ZodString>;
|
||||
department: z.ZodOptional<z.ZodEnum<["Office of Development", "Admin"]>>;
|
||||
transportMode: z.ZodOptional<z.ZodEnum<["flight", "self-driving"]>>;
|
||||
flights: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
||||
flightNumber: z.ZodString;
|
||||
airline: z.ZodOptional<z.ZodString>;
|
||||
scheduledArrival: z.ZodString;
|
||||
scheduledDeparture: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}>, "many">>;
|
||||
expectedArrival: z.ZodOptional<z.ZodString>;
|
||||
needsAirportPickup: z.ZodOptional<z.ZodBoolean>;
|
||||
needsVenueTransport: z.ZodOptional<z.ZodBoolean>;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name?: string | undefined;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}, {
|
||||
name?: string | undefined;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}>;
|
||||
createDriver: z.ZodObject<{
|
||||
name: z.ZodString;
|
||||
email: z.ZodOptional<z.ZodString>;
|
||||
phone: z.ZodString;
|
||||
vehicleInfo: z.ZodOptional<z.ZodString>;
|
||||
status: z.ZodDefault<z.ZodEnum<["available", "assigned", "unavailable"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name: string;
|
||||
phone: string;
|
||||
status: "available" | "assigned" | "unavailable";
|
||||
email?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
}, {
|
||||
name: string;
|
||||
phone: string;
|
||||
email?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
status?: "available" | "assigned" | "unavailable" | undefined;
|
||||
}>;
|
||||
updateDriver: z.ZodObject<{
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
email: z.ZodOptional<z.ZodString>;
|
||||
phone: z.ZodOptional<z.ZodString>;
|
||||
vehicleInfo: z.ZodOptional<z.ZodString>;
|
||||
status: z.ZodOptional<z.ZodEnum<["available", "assigned", "unavailable"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name?: string | undefined;
|
||||
email?: string | undefined;
|
||||
phone?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
status?: "available" | "assigned" | "unavailable" | undefined;
|
||||
}, {
|
||||
name?: string | undefined;
|
||||
email?: string | undefined;
|
||||
phone?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
status?: "available" | "assigned" | "unavailable" | undefined;
|
||||
}>;
|
||||
createScheduleEvent: z.ZodObject<{
|
||||
driverId: z.ZodOptional<z.ZodString>;
|
||||
eventTime: z.ZodString;
|
||||
eventType: z.ZodEnum<["pickup", "dropoff", "custom"]>;
|
||||
location: z.ZodString;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
eventTime: string;
|
||||
eventType: "custom" | "pickup" | "dropoff";
|
||||
location: string;
|
||||
notes?: string | undefined;
|
||||
driverId?: string | undefined;
|
||||
}, {
|
||||
eventTime: string;
|
||||
eventType: "custom" | "pickup" | "dropoff";
|
||||
location: string;
|
||||
notes?: string | undefined;
|
||||
driverId?: string | undefined;
|
||||
}>;
|
||||
updateScheduleEvent: z.ZodObject<{
|
||||
driverId: z.ZodOptional<z.ZodString>;
|
||||
eventTime: z.ZodOptional<z.ZodString>;
|
||||
eventType: z.ZodOptional<z.ZodEnum<["pickup", "dropoff", "custom"]>>;
|
||||
location: z.ZodOptional<z.ZodString>;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
status: z.ZodOptional<z.ZodEnum<["scheduled", "in_progress", "completed", "cancelled"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
notes?: string | undefined;
|
||||
status?: "scheduled" | "in_progress" | "completed" | "cancelled" | undefined;
|
||||
driverId?: string | undefined;
|
||||
eventTime?: string | undefined;
|
||||
eventType?: "custom" | "pickup" | "dropoff" | undefined;
|
||||
location?: string | undefined;
|
||||
}, {
|
||||
notes?: string | undefined;
|
||||
status?: "scheduled" | "in_progress" | "completed" | "cancelled" | undefined;
|
||||
driverId?: string | undefined;
|
||||
eventTime?: string | undefined;
|
||||
eventType?: "custom" | "pickup" | "dropoff" | undefined;
|
||||
location?: string | undefined;
|
||||
}>;
|
||||
};
|
||||
export declare const validate: (schema: z.ZodSchema) => (req: Request, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
|
||||
//# sourceMappingURL=simpleValidation.d.ts.map
|
||||
1
backend-old-20260125/dist/middleware/simpleValidation.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/simpleValidation.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"simpleValidation.d.ts","sourceRoot":"","sources":["../../src/middleware/simpleValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG1D,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsEnB,CAAC;AAGF,eAAO,MAAM,QAAQ,GAAI,QAAQ,CAAC,CAAC,SAAS,MAC5B,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,4DAc9D,CAAC"}
|
||||
91
backend-old-20260125/dist/middleware/simpleValidation.js
vendored
Normal file
91
backend-old-20260125/dist/middleware/simpleValidation.js
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.validate = exports.schemas = void 0;
|
||||
const zod_1 = require("zod");
|
||||
// Simplified validation schemas - removed unnecessary complexity
|
||||
exports.schemas = {
|
||||
// VIP schemas
|
||||
createVip: zod_1.z.object({
|
||||
name: zod_1.z.string().min(1).max(100),
|
||||
organization: zod_1.z.string().max(100).optional(),
|
||||
department: zod_1.z.enum(['Office of Development', 'Admin']).default('Office of Development'),
|
||||
transportMode: zod_1.z.enum(['flight', 'self-driving']).default('flight'),
|
||||
flights: zod_1.z.array(zod_1.z.object({
|
||||
flightNumber: zod_1.z.string(),
|
||||
airline: zod_1.z.string().optional(),
|
||||
scheduledArrival: zod_1.z.string(),
|
||||
scheduledDeparture: zod_1.z.string().optional()
|
||||
})).optional(),
|
||||
expectedArrival: zod_1.z.string().optional(),
|
||||
needsAirportPickup: zod_1.z.boolean().default(true),
|
||||
needsVenueTransport: zod_1.z.boolean().default(true),
|
||||
notes: zod_1.z.string().max(500).optional()
|
||||
}),
|
||||
updateVip: zod_1.z.object({
|
||||
name: zod_1.z.string().min(1).max(100).optional(),
|
||||
organization: zod_1.z.string().max(100).optional(),
|
||||
department: zod_1.z.enum(['Office of Development', 'Admin']).optional(),
|
||||
transportMode: zod_1.z.enum(['flight', 'self-driving']).optional(),
|
||||
flights: zod_1.z.array(zod_1.z.object({
|
||||
flightNumber: zod_1.z.string(),
|
||||
airline: zod_1.z.string().optional(),
|
||||
scheduledArrival: zod_1.z.string(),
|
||||
scheduledDeparture: zod_1.z.string().optional()
|
||||
})).optional(),
|
||||
expectedArrival: zod_1.z.string().optional(),
|
||||
needsAirportPickup: zod_1.z.boolean().optional(),
|
||||
needsVenueTransport: zod_1.z.boolean().optional(),
|
||||
notes: zod_1.z.string().max(500).optional()
|
||||
}),
|
||||
// Driver schemas
|
||||
createDriver: zod_1.z.object({
|
||||
name: zod_1.z.string().min(1).max(100),
|
||||
email: zod_1.z.string().email().optional(),
|
||||
phone: zod_1.z.string(),
|
||||
vehicleInfo: zod_1.z.string().max(200).optional(),
|
||||
status: zod_1.z.enum(['available', 'assigned', 'unavailable']).default('available')
|
||||
}),
|
||||
updateDriver: zod_1.z.object({
|
||||
name: zod_1.z.string().min(1).max(100).optional(),
|
||||
email: zod_1.z.string().email().optional(),
|
||||
phone: zod_1.z.string().optional(),
|
||||
vehicleInfo: zod_1.z.string().max(200).optional(),
|
||||
status: zod_1.z.enum(['available', 'assigned', 'unavailable']).optional()
|
||||
}),
|
||||
// Schedule schemas
|
||||
createScheduleEvent: zod_1.z.object({
|
||||
driverId: zod_1.z.string().optional(),
|
||||
eventTime: zod_1.z.string(),
|
||||
eventType: zod_1.z.enum(['pickup', 'dropoff', 'custom']),
|
||||
location: zod_1.z.string().min(1).max(200),
|
||||
notes: zod_1.z.string().max(500).optional()
|
||||
}),
|
||||
updateScheduleEvent: zod_1.z.object({
|
||||
driverId: zod_1.z.string().optional(),
|
||||
eventTime: zod_1.z.string().optional(),
|
||||
eventType: zod_1.z.enum(['pickup', 'dropoff', 'custom']).optional(),
|
||||
location: zod_1.z.string().min(1).max(200).optional(),
|
||||
notes: zod_1.z.string().max(500).optional(),
|
||||
status: zod_1.z.enum(['scheduled', 'in_progress', 'completed', 'cancelled']).optional()
|
||||
})
|
||||
};
|
||||
// Single validation middleware
|
||||
const validate = (schema) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
req.body = await schema.parseAsync(req.body);
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof zod_1.z.ZodError) {
|
||||
const message = error.errors
|
||||
.map(err => `${err.path.join('.')}: ${err.message}`)
|
||||
.join(', ');
|
||||
return res.status(400).json({ error: message });
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
};
|
||||
};
|
||||
exports.validate = validate;
|
||||
//# sourceMappingURL=simpleValidation.js.map
|
||||
1
backend-old-20260125/dist/middleware/simpleValidation.js.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/simpleValidation.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"simpleValidation.js","sourceRoot":"","sources":["../../src/middleware/simpleValidation.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAGxB,iEAAiE;AACpD,QAAA,OAAO,GAAG;IACrB,cAAc;IACd,SAAS,EAAE,OAAC,CAAC,MAAM,CAAC;QAClB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QAChC,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC5C,UAAU,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC;QACvF,aAAa,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;QACnE,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,CAAC;YACxB,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;YACxB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC9B,gBAAgB,EAAE,OAAC,CAAC,MAAM,EAAE;YAC5B,kBAAkB,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC1C,CAAC,CAAC,CAAC,QAAQ,EAAE;QACd,eAAe,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACtC,kBAAkB,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QAC7C,mBAAmB,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QAC9C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;KACtC,CAAC;IAEF,SAAS,EAAE,OAAC,CAAC,MAAM,CAAC;QAClB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC3C,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC5C,UAAU,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,uBAAuB,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE;QACjE,aAAa,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC5D,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,CAAC;YACxB,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE;YACxB,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;YAC9B,gBAAgB,EAAE,OAAC,CAAC,MAAM,EAAE;YAC5B,kBAAkB,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;SAC1C,CAAC,CAAC,CAAC,QAAQ,EAAE;QACd,eAAe,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACtC,kBAAkB,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC1C,mBAAmB,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC3C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;KACtC,CAAC;IAEF,iBAAiB;IACjB,YAAY,EAAE,OAAC,CAAC,MAAM,CAAC;QACrB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QAChC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;QACpC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE;QACjB,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC3C,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;KAC9E,CAAC;IAEF,YAAY,EAAE,OAAC,CAAC,MAAM,CAAC;QACrB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC3C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE;QACpC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC5B,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC3C,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE;KACpE,CAAC;IAEF,mBAAmB;IACnB,mBAAmB,EAAE,OAAC,CAAC,MAAM,CAAC;QAC5B,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE;QACrB,SAAS,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;QAClD,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACpC,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;KACtC,CAAC;IAEF,mBAAmB,EAAE,OAAC,CAAC,MAAM,CAAC;QAC5B,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAChC,SAAS,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAE;QAC7D,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC/C,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QACrC,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE;KAClF,CAAC;CACH,CAAC;AAEF,+BAA+B;AACxB,MAAM,QAAQ,GAAG,CAAC,MAAmB,EAAE,EAAE;IAC9C,OAAO,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;QAC/D,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC7C,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,OAAC,CAAC,QAAQ,EAAE,CAAC;gBAChC,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM;qBACzB,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;qBACnD,IAAI,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC,CAAC;AAfW,QAAA,QAAQ,YAenB"}
|
||||
6
backend-old-20260125/dist/middleware/validation.d.ts
vendored
Normal file
6
backend-old-20260125/dist/middleware/validation.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { z } from 'zod';
|
||||
export declare const validate: (schema: z.ZodSchema) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
||||
export declare const validateQuery: (schema: z.ZodSchema) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
||||
export declare const validateParams: (schema: z.ZodSchema) => (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
||||
//# sourceMappingURL=validation.d.ts.map
|
||||
1
backend-old-20260125/dist/middleware/validation.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/validation.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../src/middleware/validation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAC1D,OAAO,EAAE,CAAC,EAAY,MAAM,KAAK,CAAC;AAGlC,eAAO,MAAM,QAAQ,GAAI,QAAQ,CAAC,CAAC,SAAS,MAC5B,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,kBAqB9D,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,QAAQ,CAAC,CAAC,SAAS,MACjC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,kBAqB9D,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,QAAQ,CAAC,CAAC,SAAS,MAClC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,kBAqB9D,CAAC"}
|
||||
78
backend-old-20260125/dist/middleware/validation.js
vendored
Normal file
78
backend-old-20260125/dist/middleware/validation.js
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.validateParams = exports.validateQuery = exports.validate = void 0;
|
||||
const zod_1 = require("zod");
|
||||
const errors_1 = require("../types/errors");
|
||||
const validate = (schema) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
// Validate request body
|
||||
req.body = await schema.parseAsync(req.body);
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof zod_1.ZodError) {
|
||||
// Format Zod errors into a user-friendly message
|
||||
const errors = error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message
|
||||
}));
|
||||
const message = errors.map(e => `${e.field}: ${e.message}`).join(', ');
|
||||
next(new errors_1.ValidationError(message));
|
||||
}
|
||||
else {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
exports.validate = validate;
|
||||
const validateQuery = (schema) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
// Validate query parameters
|
||||
req.query = await schema.parseAsync(req.query);
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof zod_1.ZodError) {
|
||||
// Format Zod errors into a user-friendly message
|
||||
const errors = error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message
|
||||
}));
|
||||
const message = errors.map(e => `${e.field}: ${e.message}`).join(', ');
|
||||
next(new errors_1.ValidationError(`Invalid query parameters: ${message}`));
|
||||
}
|
||||
else {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
exports.validateQuery = validateQuery;
|
||||
const validateParams = (schema) => {
|
||||
return async (req, res, next) => {
|
||||
try {
|
||||
// Validate route parameters
|
||||
req.params = await schema.parseAsync(req.params);
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof zod_1.ZodError) {
|
||||
// Format Zod errors into a user-friendly message
|
||||
const errors = error.errors.map(err => ({
|
||||
field: err.path.join('.'),
|
||||
message: err.message
|
||||
}));
|
||||
const message = errors.map(e => `${e.field}: ${e.message}`).join(', ');
|
||||
next(new errors_1.ValidationError(`Invalid route parameters: ${message}`));
|
||||
}
|
||||
else {
|
||||
next(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
exports.validateParams = validateParams;
|
||||
//# sourceMappingURL=validation.js.map
|
||||
1
backend-old-20260125/dist/middleware/validation.js.map
vendored
Normal file
1
backend-old-20260125/dist/middleware/validation.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../../src/middleware/validation.ts"],"names":[],"mappings":"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"}
|
||||
6
backend-old-20260125/dist/routes/simpleAuth.d.ts
vendored
Normal file
6
backend-old-20260125/dist/routes/simpleAuth.d.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import express, { Request, Response, NextFunction } from 'express';
|
||||
declare const router: import("express-serve-static-core").Router;
|
||||
export declare function requireAuth(req: Request, res: Response, next: NextFunction): express.Response<any, Record<string, any>> | undefined;
|
||||
export declare function requireRole(roles: string[]): (req: Request, res: Response, next: NextFunction) => express.Response<any, Record<string, any>> | undefined;
|
||||
export default router;
|
||||
//# sourceMappingURL=simpleAuth.d.ts.map
|
||||
1
backend-old-20260125/dist/routes/simpleAuth.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/routes/simpleAuth.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"simpleAuth.d.ts","sourceRoot":"","sources":["../../src/routes/simpleAuth.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAWnE,QAAA,MAAM,MAAM,4CAAmB,CAAC;AA8ChC,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,0DAwD1E;AAGD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,IACjC,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,4DASxD;AAseD,eAAe,MAAM,CAAC"}
|
||||
534
backend-old-20260125/dist/routes/simpleAuth.js
vendored
Normal file
534
backend-old-20260125/dist/routes/simpleAuth.js
vendored
Normal file
@@ -0,0 +1,534 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.requireAuth = requireAuth;
|
||||
exports.requireRole = requireRole;
|
||||
const express_1 = __importDefault(require("express"));
|
||||
const simpleAuth_1 = require("../config/simpleAuth");
|
||||
const databaseService_1 = __importDefault(require("../services/databaseService"));
|
||||
const router = express_1.default.Router();
|
||||
// Enhanced logging for production debugging
|
||||
function logAuthEvent(event, details = {}) {
|
||||
const timestamp = new Date().toISOString();
|
||||
console.log(`🔐 [AUTH ${timestamp}] ${event}:`, JSON.stringify(details, null, 2));
|
||||
}
|
||||
// Validate environment variables on startup
|
||||
function validateAuthEnvironment() {
|
||||
const required = ['GOOGLE_CLIENT_ID', 'GOOGLE_CLIENT_SECRET', 'GOOGLE_REDIRECT_URI', 'FRONTEND_URL'];
|
||||
const missing = required.filter(key => !process.env[key]);
|
||||
if (missing.length > 0) {
|
||||
logAuthEvent('ENVIRONMENT_ERROR', { missing_variables: missing });
|
||||
return false;
|
||||
}
|
||||
// Validate URLs
|
||||
const frontendUrl = process.env.FRONTEND_URL;
|
||||
const redirectUri = process.env.GOOGLE_REDIRECT_URI;
|
||||
if (!frontendUrl?.startsWith('http')) {
|
||||
logAuthEvent('ENVIRONMENT_ERROR', { error: 'FRONTEND_URL must start with http/https' });
|
||||
return false;
|
||||
}
|
||||
if (!redirectUri?.startsWith('http')) {
|
||||
logAuthEvent('ENVIRONMENT_ERROR', { error: 'GOOGLE_REDIRECT_URI must start with http/https' });
|
||||
return false;
|
||||
}
|
||||
logAuthEvent('ENVIRONMENT_VALIDATED', {
|
||||
frontend_url: frontendUrl,
|
||||
redirect_uri: redirectUri,
|
||||
client_id_configured: !!process.env.GOOGLE_CLIENT_ID,
|
||||
client_secret_configured: !!process.env.GOOGLE_CLIENT_SECRET
|
||||
});
|
||||
return true;
|
||||
}
|
||||
// Validate environment on module load
|
||||
const isEnvironmentValid = validateAuthEnvironment();
|
||||
// Middleware to check authentication
|
||||
function requireAuth(req, res, next) {
|
||||
try {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
logAuthEvent('AUTH_FAILED', {
|
||||
reason: 'no_token',
|
||||
ip: req.ip,
|
||||
path: req.path,
|
||||
headers_present: !!req.headers.authorization
|
||||
});
|
||||
return res.status(401).json({ error: 'No token provided' });
|
||||
}
|
||||
const token = authHeader.substring(7);
|
||||
if (!token || token.length < 10) {
|
||||
logAuthEvent('AUTH_FAILED', {
|
||||
reason: 'invalid_token_format',
|
||||
ip: req.ip,
|
||||
path: req.path,
|
||||
token_length: token?.length || 0
|
||||
});
|
||||
return res.status(401).json({ error: 'Invalid token format' });
|
||||
}
|
||||
const user = (0, simpleAuth_1.verifyToken)(token);
|
||||
if (!user) {
|
||||
logAuthEvent('AUTH_FAILED', {
|
||||
reason: 'token_verification_failed',
|
||||
ip: req.ip,
|
||||
path: req.path,
|
||||
token_prefix: token.substring(0, 10) + '...'
|
||||
});
|
||||
return res.status(401).json({ error: 'Invalid or expired token' });
|
||||
}
|
||||
logAuthEvent('AUTH_SUCCESS', {
|
||||
user_id: user.id,
|
||||
user_email: user.email,
|
||||
user_role: user.role,
|
||||
ip: req.ip,
|
||||
path: req.path
|
||||
});
|
||||
req.user = user;
|
||||
next();
|
||||
}
|
||||
catch (error) {
|
||||
logAuthEvent('AUTH_ERROR', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
ip: req.ip,
|
||||
path: req.path
|
||||
});
|
||||
return res.status(500).json({ error: 'Authentication system error' });
|
||||
}
|
||||
}
|
||||
// Middleware to check role
|
||||
function requireRole(roles) {
|
||||
return (req, res, next) => {
|
||||
const user = req.user;
|
||||
if (!user || !roles.includes(user.role)) {
|
||||
return res.status(403).json({ error: 'Insufficient permissions' });
|
||||
}
|
||||
next();
|
||||
};
|
||||
}
|
||||
// Get current user
|
||||
router.get('/me', requireAuth, (req, res) => {
|
||||
res.json(req.user);
|
||||
});
|
||||
// Setup status endpoint (required by frontend)
|
||||
router.get('/setup', async (req, res) => {
|
||||
try {
|
||||
const clientId = process.env.GOOGLE_CLIENT_ID;
|
||||
const clientSecret = process.env.GOOGLE_CLIENT_SECRET;
|
||||
const redirectUri = process.env.GOOGLE_REDIRECT_URI;
|
||||
const frontendUrl = process.env.FRONTEND_URL;
|
||||
logAuthEvent('SETUP_CHECK', {
|
||||
client_id_present: !!clientId,
|
||||
client_secret_present: !!clientSecret,
|
||||
redirect_uri_present: !!redirectUri,
|
||||
frontend_url_present: !!frontendUrl,
|
||||
environment_valid: isEnvironmentValid
|
||||
});
|
||||
// Check database connectivity
|
||||
let userCount = 0;
|
||||
let databaseConnected = false;
|
||||
try {
|
||||
userCount = await databaseService_1.default.getUserCount();
|
||||
databaseConnected = true;
|
||||
logAuthEvent('DATABASE_CHECK', { status: 'connected', user_count: userCount });
|
||||
}
|
||||
catch (dbError) {
|
||||
logAuthEvent('DATABASE_ERROR', {
|
||||
error: dbError instanceof Error ? dbError.message : 'Unknown database error'
|
||||
});
|
||||
return res.status(500).json({
|
||||
error: 'Database connection failed',
|
||||
details: 'Cannot connect to PostgreSQL database'
|
||||
});
|
||||
}
|
||||
const setupCompleted = !!(clientId &&
|
||||
clientSecret &&
|
||||
redirectUri &&
|
||||
frontendUrl &&
|
||||
clientId !== 'your-google-client-id-from-console' &&
|
||||
clientId !== 'your-google-client-id' &&
|
||||
isEnvironmentValid);
|
||||
const response = {
|
||||
setupCompleted,
|
||||
firstAdminCreated: userCount > 0,
|
||||
oauthConfigured: !!(clientId && clientSecret),
|
||||
databaseConnected,
|
||||
environmentValid: isEnvironmentValid,
|
||||
configuration: {
|
||||
google_oauth: !!(clientId && clientSecret),
|
||||
redirect_uri_configured: !!redirectUri,
|
||||
frontend_url_configured: !!frontendUrl,
|
||||
production_ready: setupCompleted && databaseConnected
|
||||
}
|
||||
};
|
||||
logAuthEvent('SETUP_STATUS', response);
|
||||
res.json(response);
|
||||
}
|
||||
catch (error) {
|
||||
logAuthEvent('SETUP_ERROR', {
|
||||
error: error instanceof Error ? error.message : 'Unknown setup error'
|
||||
});
|
||||
res.status(500).json({
|
||||
error: 'Setup check failed',
|
||||
details: error instanceof Error ? error.message : 'Unknown error'
|
||||
});
|
||||
}
|
||||
});
|
||||
// Start Google OAuth flow
|
||||
router.get('/google', (req, res) => {
|
||||
try {
|
||||
const authUrl = (0, simpleAuth_1.getGoogleAuthUrl)();
|
||||
res.redirect(authUrl);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error starting Google OAuth:', error);
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:5173';
|
||||
res.redirect(`${frontendUrl}?error=oauth_not_configured`);
|
||||
}
|
||||
});
|
||||
// Handle Google OAuth callback (this is where Google redirects back to)
|
||||
router.get('/google/callback', async (req, res) => {
|
||||
const { code, error, state } = req.query;
|
||||
const frontendUrl = process.env.FRONTEND_URL || 'http://localhost:5173';
|
||||
logAuthEvent('OAUTH_CALLBACK', {
|
||||
has_code: !!code,
|
||||
has_error: !!error,
|
||||
error_type: error,
|
||||
state,
|
||||
frontend_url: frontendUrl,
|
||||
ip: req.ip,
|
||||
user_agent: req.get('User-Agent')
|
||||
});
|
||||
// Validate environment before proceeding
|
||||
if (!isEnvironmentValid) {
|
||||
logAuthEvent('OAUTH_CALLBACK_ERROR', { reason: 'invalid_environment' });
|
||||
return res.redirect(`${frontendUrl}?error=configuration_error&message=OAuth not properly configured`);
|
||||
}
|
||||
if (error) {
|
||||
logAuthEvent('OAUTH_ERROR', { error, ip: req.ip });
|
||||
return res.redirect(`${frontendUrl}?error=${error}&message=OAuth authorization failed`);
|
||||
}
|
||||
if (!code) {
|
||||
logAuthEvent('OAUTH_ERROR', { reason: 'no_authorization_code', ip: req.ip });
|
||||
return res.redirect(`${frontendUrl}?error=no_code&message=No authorization code received`);
|
||||
}
|
||||
try {
|
||||
logAuthEvent('OAUTH_TOKEN_EXCHANGE_START', { code_length: code.length });
|
||||
// Exchange code for tokens
|
||||
const tokens = await (0, simpleAuth_1.exchangeCodeForTokens)(code);
|
||||
if (!tokens || !tokens.access_token) {
|
||||
logAuthEvent('OAUTH_TOKEN_EXCHANGE_FAILED', { tokens_received: !!tokens });
|
||||
return res.redirect(`${frontendUrl}?error=token_exchange_failed&message=Failed to exchange authorization code`);
|
||||
}
|
||||
logAuthEvent('OAUTH_TOKEN_EXCHANGE_SUCCESS', { has_access_token: !!tokens.access_token });
|
||||
// Get user info
|
||||
const googleUser = await (0, simpleAuth_1.getGoogleUserInfo)(tokens.access_token);
|
||||
if (!googleUser || !googleUser.email) {
|
||||
logAuthEvent('OAUTH_USER_INFO_FAILED', { user_data: !!googleUser });
|
||||
return res.redirect(`${frontendUrl}?error=user_info_failed&message=Failed to get user information from Google`);
|
||||
}
|
||||
logAuthEvent('OAUTH_USER_INFO_SUCCESS', {
|
||||
email: googleUser.email,
|
||||
name: googleUser.name,
|
||||
verified_email: googleUser.verified_email
|
||||
});
|
||||
// Check if user exists or create new user
|
||||
let user = await databaseService_1.default.getUserByEmail(googleUser.email);
|
||||
if (!user) {
|
||||
// Determine role - first user becomes admin, others need approval
|
||||
const approvedUserCount = await databaseService_1.default.getApprovedUserCount();
|
||||
const role = approvedUserCount === 0 ? 'administrator' : 'coordinator';
|
||||
logAuthEvent('USER_CREATION', {
|
||||
email: googleUser.email,
|
||||
role,
|
||||
is_first_user: approvedUserCount === 0
|
||||
});
|
||||
user = await databaseService_1.default.createUser({
|
||||
id: googleUser.id,
|
||||
google_id: googleUser.id,
|
||||
email: googleUser.email,
|
||||
name: googleUser.name,
|
||||
profile_picture_url: googleUser.picture,
|
||||
role
|
||||
});
|
||||
// Auto-approve first admin, others need approval
|
||||
if (approvedUserCount === 0) {
|
||||
await databaseService_1.default.updateUserApprovalStatus(googleUser.email, 'approved');
|
||||
user.approval_status = 'approved';
|
||||
logAuthEvent('FIRST_ADMIN_CREATED', { email: googleUser.email });
|
||||
}
|
||||
else {
|
||||
logAuthEvent('USER_PENDING_APPROVAL', { email: googleUser.email });
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Update last sign in
|
||||
await databaseService_1.default.updateUserLastSignIn(googleUser.email);
|
||||
logAuthEvent('USER_LOGIN', {
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
approval_status: user.approval_status
|
||||
});
|
||||
}
|
||||
// Check if user is approved
|
||||
if (user.approval_status !== 'approved') {
|
||||
logAuthEvent('USER_NOT_APPROVED', { email: user.email, status: user.approval_status });
|
||||
return res.redirect(`${frontendUrl}?error=pending_approval&message=Your account is pending administrator approval`);
|
||||
}
|
||||
// Generate JWT token
|
||||
const token = (0, simpleAuth_1.generateToken)(user);
|
||||
logAuthEvent('JWT_TOKEN_GENERATED', {
|
||||
user_id: user.id,
|
||||
email: user.email,
|
||||
role: user.role,
|
||||
token_length: token.length
|
||||
});
|
||||
// Redirect to frontend with token
|
||||
const callbackUrl = `${frontendUrl}/auth/callback?token=${token}`;
|
||||
logAuthEvent('OAUTH_SUCCESS_REDIRECT', { callback_url: callbackUrl });
|
||||
res.redirect(callbackUrl);
|
||||
}
|
||||
catch (error) {
|
||||
logAuthEvent('OAUTH_CALLBACK_ERROR', {
|
||||
error: error instanceof Error ? error.message : 'Unknown error',
|
||||
stack: error instanceof Error ? error.stack : undefined,
|
||||
ip: req.ip
|
||||
});
|
||||
res.redirect(`${frontendUrl}?error=oauth_failed&message=Authentication failed due to server error`);
|
||||
}
|
||||
});
|
||||
// Exchange OAuth code for JWT token (alternative endpoint for frontend)
|
||||
router.post('/google/exchange', async (req, res) => {
|
||||
const { code } = req.body;
|
||||
if (!code) {
|
||||
return res.status(400).json({ error: 'Authorization code is required' });
|
||||
}
|
||||
try {
|
||||
// Exchange code for tokens
|
||||
const tokens = await (0, simpleAuth_1.exchangeCodeForTokens)(code);
|
||||
// Get user info
|
||||
const googleUser = await (0, simpleAuth_1.getGoogleUserInfo)(tokens.access_token);
|
||||
// Check if user exists or create new user
|
||||
let user = await databaseService_1.default.getUserByEmail(googleUser.email);
|
||||
if (!user) {
|
||||
// Determine role - first user becomes admin
|
||||
const userCount = await databaseService_1.default.getUserCount();
|
||||
const role = userCount === 0 ? 'administrator' : 'coordinator';
|
||||
user = await databaseService_1.default.createUser({
|
||||
id: googleUser.id,
|
||||
google_id: googleUser.id,
|
||||
email: googleUser.email,
|
||||
name: googleUser.name,
|
||||
profile_picture_url: googleUser.picture,
|
||||
role
|
||||
});
|
||||
}
|
||||
else {
|
||||
// Update last sign in
|
||||
await databaseService_1.default.updateUserLastSignIn(googleUser.email);
|
||||
console.log(`✅ User logged in: ${user.name} (${user.email})`);
|
||||
}
|
||||
// Generate JWT token
|
||||
const token = (0, simpleAuth_1.generateToken)(user);
|
||||
// Return token to frontend
|
||||
res.json({
|
||||
token,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
picture: user.profile_picture_url,
|
||||
role: user.role
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error in OAuth exchange:', error);
|
||||
res.status(500).json({ error: 'Failed to exchange authorization code' });
|
||||
}
|
||||
});
|
||||
// Get OAuth URL for frontend to redirect to
|
||||
router.get('/google/url', (req, res) => {
|
||||
try {
|
||||
const authUrl = (0, simpleAuth_1.getGoogleAuthUrl)();
|
||||
res.json({ url: authUrl });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error getting Google OAuth URL:', error);
|
||||
res.status(500).json({ error: 'OAuth not configured' });
|
||||
}
|
||||
});
|
||||
// Logout
|
||||
router.post('/logout', (req, res) => {
|
||||
// With JWT, logout is handled client-side by removing the token
|
||||
res.json({ message: 'Logged out successfully' });
|
||||
});
|
||||
// Get auth status
|
||||
router.get('/status', (req, res) => {
|
||||
const authHeader = req.headers.authorization;
|
||||
if (!authHeader || !authHeader.startsWith('Bearer ')) {
|
||||
return res.json({ authenticated: false });
|
||||
}
|
||||
const token = authHeader.substring(7);
|
||||
const user = (0, simpleAuth_1.verifyToken)(token);
|
||||
if (!user) {
|
||||
return res.json({ authenticated: false });
|
||||
}
|
||||
res.json({
|
||||
authenticated: true,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
picture: user.profile_picture_url,
|
||||
role: user.role
|
||||
}
|
||||
});
|
||||
});
|
||||
// USER MANAGEMENT ENDPOINTS
|
||||
// List all users (admin only)
|
||||
router.get('/users', requireAuth, requireRole(['administrator']), async (req, res) => {
|
||||
try {
|
||||
const users = await databaseService_1.default.getAllUsers();
|
||||
const userList = users.map(user => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
picture: user.profile_picture_url,
|
||||
role: user.role,
|
||||
created_at: user.created_at,
|
||||
last_login: user.last_login,
|
||||
provider: 'google'
|
||||
}));
|
||||
res.json(userList);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching users:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch users' });
|
||||
}
|
||||
});
|
||||
// Update user role (admin only)
|
||||
router.patch('/users/:email/role', requireAuth, requireRole(['administrator']), async (req, res) => {
|
||||
const { email } = req.params;
|
||||
const { role } = req.body;
|
||||
if (!['administrator', 'coordinator', 'driver'].includes(role)) {
|
||||
return res.status(400).json({ error: 'Invalid role' });
|
||||
}
|
||||
try {
|
||||
const user = await databaseService_1.default.updateUserRole(email, role);
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
role: user.role
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error updating user role:', error);
|
||||
res.status(500).json({ error: 'Failed to update user role' });
|
||||
}
|
||||
});
|
||||
// Delete user (admin only)
|
||||
router.delete('/users/:email', requireAuth, requireRole(['administrator']), async (req, res) => {
|
||||
const { email } = req.params;
|
||||
const currentUser = req.user;
|
||||
// Prevent admin from deleting themselves
|
||||
if (email === currentUser.email) {
|
||||
return res.status(400).json({ error: 'Cannot delete your own account' });
|
||||
}
|
||||
try {
|
||||
const deletedUser = await databaseService_1.default.deleteUser(email);
|
||||
if (!deletedUser) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
res.json({ success: true, message: 'User deleted successfully' });
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error deleting user:', error);
|
||||
res.status(500).json({ error: 'Failed to delete user' });
|
||||
}
|
||||
});
|
||||
// Get user by email (admin only)
|
||||
router.get('/users/:email', requireAuth, requireRole(['administrator']), async (req, res) => {
|
||||
const { email } = req.params;
|
||||
try {
|
||||
const user = await databaseService_1.default.getUserByEmail(email);
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
res.json({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
picture: user.profile_picture_url,
|
||||
role: user.role,
|
||||
created_at: user.created_at,
|
||||
last_login: user.last_login,
|
||||
provider: 'google',
|
||||
approval_status: user.approval_status
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching user:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch user' });
|
||||
}
|
||||
});
|
||||
// USER APPROVAL ENDPOINTS
|
||||
// Get pending users (admin only)
|
||||
router.get('/users/pending/list', requireAuth, requireRole(['administrator']), async (req, res) => {
|
||||
try {
|
||||
const pendingUsers = await databaseService_1.default.getPendingUsers();
|
||||
const userList = pendingUsers.map(user => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
picture: user.profile_picture_url,
|
||||
role: user.role,
|
||||
created_at: user.created_at,
|
||||
provider: 'google',
|
||||
approval_status: user.approval_status
|
||||
}));
|
||||
res.json(userList);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching pending users:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch pending users' });
|
||||
}
|
||||
});
|
||||
// Approve or deny user (admin only)
|
||||
router.patch('/users/:email/approval', requireAuth, requireRole(['administrator']), async (req, res) => {
|
||||
const { email } = req.params;
|
||||
const { status } = req.body;
|
||||
if (!['approved', 'denied'].includes(status)) {
|
||||
return res.status(400).json({ error: 'Invalid approval status. Must be "approved" or "denied"' });
|
||||
}
|
||||
try {
|
||||
const user = await databaseService_1.default.updateUserApprovalStatus(email, status);
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
message: `User ${status} successfully`,
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
approval_status: user.approval_status
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error updating user approval:', error);
|
||||
res.status(500).json({ error: 'Failed to update user approval' });
|
||||
}
|
||||
});
|
||||
exports.default = router;
|
||||
//# sourceMappingURL=simpleAuth.js.map
|
||||
1
backend-old-20260125/dist/routes/simpleAuth.js.map
vendored
Normal file
1
backend-old-20260125/dist/routes/simpleAuth.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
29
backend-old-20260125/dist/services/authService.d.ts
vendored
Normal file
29
backend-old-20260125/dist/services/authService.d.ts
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
declare class AuthService {
|
||||
private jwtSecret;
|
||||
private jwtExpiry;
|
||||
private googleClient;
|
||||
constructor();
|
||||
generateToken(user: any): string;
|
||||
verifyGoogleToken(credential: string): Promise<{
|
||||
user: any;
|
||||
token: string;
|
||||
}>;
|
||||
verifyToken(token: string): any;
|
||||
requireAuth: (req: Request & {
|
||||
user?: any;
|
||||
}, res: Response, next: NextFunction) => Promise<Response<any, Record<string, any>> | undefined>;
|
||||
requireRole: (roles: string[]) => (req: Request & {
|
||||
user?: any;
|
||||
}, res: Response, next: NextFunction) => Response<any, Record<string, any>> | undefined;
|
||||
getGoogleAuthUrl(): string;
|
||||
exchangeGoogleCode(code: string): Promise<any>;
|
||||
getGoogleUserInfo(accessToken: string): Promise<any>;
|
||||
handleGoogleAuth(code: string): Promise<{
|
||||
user: any;
|
||||
token: string;
|
||||
}>;
|
||||
}
|
||||
declare const _default: AuthService;
|
||||
export default _default;
|
||||
//# sourceMappingURL=authService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/authService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/authService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"authService.d.ts","sourceRoot":"","sources":["../../src/services/authService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAK1D,cAAM,WAAW;IACf,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,YAAY,CAAe;;IAoBnC,aAAa,CAAC,IAAI,EAAE,GAAG,GAAG,MAAM;IAM1B,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAqClF,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG;IAS/B,WAAW,GAAU,KAAK,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAA;KAAE,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,6DAoBnF;IAGF,WAAW,GAAI,OAAO,MAAM,EAAE,MACpB,KAAK,OAAO,GAAG;QAAE,IAAI,CAAC,EAAE,GAAG,CAAA;KAAE,EAAE,KAAK,QAAQ,EAAE,MAAM,YAAY,oDAWxE;IAGF,gBAAgB,IAAI,MAAM;IAiBpB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAoB9C,iBAAiB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAapD,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAyB5E;;AAED,wBAAiC"}
|
||||
168
backend-old-20260125/dist/services/authService.js
vendored
Normal file
168
backend-old-20260125/dist/services/authService.js
vendored
Normal file
@@ -0,0 +1,168 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const jwt = require('jsonwebtoken');
|
||||
const google_auth_library_1 = require("google-auth-library");
|
||||
const unifiedDataService_1 = __importDefault(require("./unifiedDataService"));
|
||||
// Simplified authentication service - removes excessive logging and complexity
|
||||
class AuthService {
|
||||
constructor() {
|
||||
this.jwtExpiry = '24h';
|
||||
// Middleware to check authentication
|
||||
this.requireAuth = async (req, res, next) => {
|
||||
const token = req.headers.authorization?.replace('Bearer ', '');
|
||||
if (!token) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
const decoded = this.verifyToken(token);
|
||||
if (!decoded) {
|
||||
return res.status(401).json({ error: 'Invalid or expired token' });
|
||||
}
|
||||
// Get fresh user data
|
||||
const user = await unifiedDataService_1.default.getUserById(decoded.id);
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'User not found' });
|
||||
}
|
||||
req.user = user;
|
||||
next();
|
||||
};
|
||||
// Middleware to check role
|
||||
this.requireRole = (roles) => {
|
||||
return (req, res, next) => {
|
||||
if (!req.user) {
|
||||
return res.status(401).json({ error: 'Authentication required' });
|
||||
}
|
||||
if (!roles.includes(req.user.role)) {
|
||||
return res.status(403).json({ error: 'Insufficient permissions' });
|
||||
}
|
||||
next();
|
||||
};
|
||||
};
|
||||
// Auto-generate a secure JWT secret if not provided
|
||||
if (process.env.JWT_SECRET) {
|
||||
this.jwtSecret = process.env.JWT_SECRET;
|
||||
console.log('Using JWT_SECRET from environment');
|
||||
}
|
||||
else {
|
||||
// Generate a cryptographically secure random secret
|
||||
const crypto = require('crypto');
|
||||
this.jwtSecret = crypto.randomBytes(64).toString('hex');
|
||||
console.log('Generated new JWT_SECRET (this will change on restart)');
|
||||
console.log('To persist sessions across restarts, set JWT_SECRET in .env');
|
||||
}
|
||||
// Initialize Google OAuth client
|
||||
this.googleClient = new google_auth_library_1.OAuth2Client(process.env.GOOGLE_CLIENT_ID);
|
||||
}
|
||||
// Generate JWT token
|
||||
generateToken(user) {
|
||||
const payload = { id: user.id, email: user.email, role: user.role };
|
||||
return jwt.sign(payload, this.jwtSecret, { expiresIn: this.jwtExpiry });
|
||||
}
|
||||
// Verify Google ID token from frontend
|
||||
async verifyGoogleToken(credential) {
|
||||
try {
|
||||
// Verify the token with Google
|
||||
const ticket = await this.googleClient.verifyIdToken({
|
||||
idToken: credential,
|
||||
audience: process.env.GOOGLE_CLIENT_ID,
|
||||
});
|
||||
const payload = ticket.getPayload();
|
||||
if (!payload || !payload.email) {
|
||||
throw new Error('Invalid token payload');
|
||||
}
|
||||
// Find or create user
|
||||
let user = await unifiedDataService_1.default.getUserByEmail(payload.email);
|
||||
if (!user) {
|
||||
// Auto-create user with coordinator role
|
||||
user = await unifiedDataService_1.default.createUser({
|
||||
email: payload.email,
|
||||
name: payload.name || payload.email,
|
||||
role: 'coordinator',
|
||||
googleId: payload.sub
|
||||
});
|
||||
}
|
||||
// Generate our JWT
|
||||
const token = this.generateToken(user);
|
||||
return { user, token };
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Token verification error:', error);
|
||||
throw new Error('Failed to verify Google token');
|
||||
}
|
||||
}
|
||||
// Verify JWT token
|
||||
verifyToken(token) {
|
||||
try {
|
||||
return jwt.verify(token, this.jwtSecret);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Google OAuth helpers
|
||||
getGoogleAuthUrl() {
|
||||
if (!process.env.GOOGLE_CLIENT_ID || !process.env.GOOGLE_REDIRECT_URI) {
|
||||
throw new Error('Google OAuth not configured. Please set GOOGLE_CLIENT_ID and GOOGLE_REDIRECT_URI in .env file');
|
||||
}
|
||||
const params = new URLSearchParams({
|
||||
client_id: process.env.GOOGLE_CLIENT_ID,
|
||||
redirect_uri: process.env.GOOGLE_REDIRECT_URI,
|
||||
response_type: 'code',
|
||||
scope: 'email profile',
|
||||
access_type: 'offline',
|
||||
prompt: 'consent'
|
||||
});
|
||||
return `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
|
||||
}
|
||||
async exchangeGoogleCode(code) {
|
||||
const response = await fetch('https://oauth2.googleapis.com/token', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
code,
|
||||
client_id: process.env.GOOGLE_CLIENT_ID,
|
||||
client_secret: process.env.GOOGLE_CLIENT_SECRET,
|
||||
redirect_uri: process.env.GOOGLE_REDIRECT_URI,
|
||||
grant_type: 'authorization_code'
|
||||
})
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to exchange authorization code');
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
async getGoogleUserInfo(accessToken) {
|
||||
const response = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
|
||||
headers: { Authorization: `Bearer ${accessToken}` }
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to get user info');
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
// Simplified login/signup
|
||||
async handleGoogleAuth(code) {
|
||||
// Exchange code for tokens
|
||||
const tokens = await this.exchangeGoogleCode(code);
|
||||
// Get user info
|
||||
const googleUser = await this.getGoogleUserInfo(tokens.access_token);
|
||||
// Find or create user
|
||||
let user = await unifiedDataService_1.default.getUserByEmail(googleUser.email);
|
||||
if (!user) {
|
||||
// Auto-create user with coordinator role
|
||||
user = await unifiedDataService_1.default.createUser({
|
||||
email: googleUser.email,
|
||||
name: googleUser.name,
|
||||
role: 'coordinator',
|
||||
googleId: googleUser.id
|
||||
});
|
||||
}
|
||||
// Generate JWT
|
||||
const token = this.generateToken(user);
|
||||
return { user, token };
|
||||
}
|
||||
}
|
||||
exports.default = new AuthService();
|
||||
//# sourceMappingURL=authService.js.map
|
||||
1
backend-old-20260125/dist/services/authService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/authService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
39
backend-old-20260125/dist/services/dataService.d.ts
vendored
Normal file
39
backend-old-20260125/dist/services/dataService.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
declare class DataService {
|
||||
private dataDir;
|
||||
private dataFile;
|
||||
private data;
|
||||
constructor();
|
||||
private loadData;
|
||||
private saveData;
|
||||
getVips(): any[];
|
||||
addVip(vip: any): any;
|
||||
updateVip(id: string, updatedVip: any): any | null;
|
||||
deleteVip(id: string): any | null;
|
||||
getDrivers(): any[];
|
||||
addDriver(driver: any): any;
|
||||
updateDriver(id: string, updatedDriver: any): any | null;
|
||||
deleteDriver(id: string): any | null;
|
||||
getSchedule(vipId: string): any[];
|
||||
addScheduleEvent(vipId: string, event: any): any;
|
||||
updateScheduleEvent(vipId: string, eventId: string, updatedEvent: any): any | null;
|
||||
deleteScheduleEvent(vipId: string, eventId: string): any | null;
|
||||
getAllSchedules(): {
|
||||
[vipId: string]: any[];
|
||||
};
|
||||
getAdminSettings(): any;
|
||||
updateAdminSettings(settings: any): void;
|
||||
createBackup(): string;
|
||||
getUsers(): any[];
|
||||
getUserByEmail(email: string): any | null;
|
||||
getUserById(id: string): any | null;
|
||||
addUser(user: any): any;
|
||||
updateUser(email: string, updatedUser: any): any | null;
|
||||
updateUserRole(email: string, role: string): any | null;
|
||||
updateUserLastSignIn(email: string): any | null;
|
||||
deleteUser(email: string): any | null;
|
||||
getUserCount(): number;
|
||||
getDataStats(): any;
|
||||
}
|
||||
declare const _default: DataService;
|
||||
export default _default;
|
||||
//# sourceMappingURL=dataService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/dataService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/dataService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dataService.d.ts","sourceRoot":"","sources":["../../src/services/dataService.ts"],"names":[],"mappings":"AAWA,cAAM,WAAW;IACf,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,IAAI,CAAY;;IAcxB,OAAO,CAAC,QAAQ;IA6ChB,OAAO,CAAC,QAAQ;IAWhB,OAAO,IAAI,GAAG,EAAE;IAIhB,MAAM,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG;IAMrB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI;IAUlD,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAajC,UAAU,IAAI,GAAG,EAAE;IAInB,SAAS,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG;IAM3B,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI;IAUxD,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAWpC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE;IAIjC,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAAG,GAAG;IAShD,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI;IAclF,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAc/D,eAAe,IAAI;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,EAAE,CAAA;KAAE;IAK7C,gBAAgB,IAAI,GAAG;IAIvB,mBAAmB,CAAC,QAAQ,EAAE,GAAG,GAAG,IAAI;IAMxC,YAAY,IAAI,MAAM;IAetB,QAAQ,IAAI,GAAG,EAAE;IAIjB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAIzC,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAInC,OAAO,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG;IAcvB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,IAAI;IAWvD,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAWvD,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAU/C,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI;IAWrC,YAAY,IAAI,MAAM;IAItB,YAAY,IAAI,GAAG;CAWpB;;AAED,wBAAiC"}
|
||||
264
backend-old-20260125/dist/services/dataService.js
vendored
Normal file
264
backend-old-20260125/dist/services/dataService.js
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const fs_1 = __importDefault(require("fs"));
|
||||
const path_1 = __importDefault(require("path"));
|
||||
class DataService {
|
||||
constructor() {
|
||||
this.dataDir = path_1.default.join(process.cwd(), 'data');
|
||||
this.dataFile = path_1.default.join(this.dataDir, 'vip-coordinator.json');
|
||||
// Ensure data directory exists
|
||||
if (!fs_1.default.existsSync(this.dataDir)) {
|
||||
fs_1.default.mkdirSync(this.dataDir, { recursive: true });
|
||||
}
|
||||
this.data = this.loadData();
|
||||
}
|
||||
loadData() {
|
||||
try {
|
||||
if (fs_1.default.existsSync(this.dataFile)) {
|
||||
const fileContent = fs_1.default.readFileSync(this.dataFile, 'utf8');
|
||||
const loadedData = JSON.parse(fileContent);
|
||||
console.log(`✅ Loaded data from ${this.dataFile}`);
|
||||
console.log(` - VIPs: ${loadedData.vips?.length || 0}`);
|
||||
console.log(` - Drivers: ${loadedData.drivers?.length || 0}`);
|
||||
console.log(` - Users: ${loadedData.users?.length || 0}`);
|
||||
console.log(` - Schedules: ${Object.keys(loadedData.schedules || {}).length} VIPs with schedules`);
|
||||
// Ensure users array exists for backward compatibility
|
||||
if (!loadedData.users) {
|
||||
loadedData.users = [];
|
||||
}
|
||||
return loadedData;
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error loading data file:', error);
|
||||
}
|
||||
// Return default empty data structure
|
||||
console.log('📝 Starting with empty data store');
|
||||
return {
|
||||
vips: [],
|
||||
drivers: [],
|
||||
schedules: {},
|
||||
users: [],
|
||||
adminSettings: {
|
||||
apiKeys: {
|
||||
aviationStackKey: process.env.AVIATIONSTACK_API_KEY || '',
|
||||
googleMapsKey: '',
|
||||
twilioKey: ''
|
||||
},
|
||||
systemSettings: {
|
||||
defaultPickupLocation: '',
|
||||
defaultDropoffLocation: '',
|
||||
timeZone: 'America/New_York',
|
||||
notificationsEnabled: false
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
saveData() {
|
||||
try {
|
||||
const dataToSave = JSON.stringify(this.data, null, 2);
|
||||
fs_1.default.writeFileSync(this.dataFile, dataToSave, 'utf8');
|
||||
console.log(`💾 Data saved to ${this.dataFile}`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error saving data file:', error);
|
||||
}
|
||||
}
|
||||
// VIP operations
|
||||
getVips() {
|
||||
return this.data.vips;
|
||||
}
|
||||
addVip(vip) {
|
||||
this.data.vips.push(vip);
|
||||
this.saveData();
|
||||
return vip;
|
||||
}
|
||||
updateVip(id, updatedVip) {
|
||||
const index = this.data.vips.findIndex(vip => vip.id === id);
|
||||
if (index !== -1) {
|
||||
this.data.vips[index] = updatedVip;
|
||||
this.saveData();
|
||||
return this.data.vips[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
deleteVip(id) {
|
||||
const index = this.data.vips.findIndex(vip => vip.id === id);
|
||||
if (index !== -1) {
|
||||
const deletedVip = this.data.vips.splice(index, 1)[0];
|
||||
// Also delete the VIP's schedule
|
||||
delete this.data.schedules[id];
|
||||
this.saveData();
|
||||
return deletedVip;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Driver operations
|
||||
getDrivers() {
|
||||
return this.data.drivers;
|
||||
}
|
||||
addDriver(driver) {
|
||||
this.data.drivers.push(driver);
|
||||
this.saveData();
|
||||
return driver;
|
||||
}
|
||||
updateDriver(id, updatedDriver) {
|
||||
const index = this.data.drivers.findIndex(driver => driver.id === id);
|
||||
if (index !== -1) {
|
||||
this.data.drivers[index] = updatedDriver;
|
||||
this.saveData();
|
||||
return this.data.drivers[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
deleteDriver(id) {
|
||||
const index = this.data.drivers.findIndex(driver => driver.id === id);
|
||||
if (index !== -1) {
|
||||
const deletedDriver = this.data.drivers.splice(index, 1)[0];
|
||||
this.saveData();
|
||||
return deletedDriver;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Schedule operations
|
||||
getSchedule(vipId) {
|
||||
return this.data.schedules[vipId] || [];
|
||||
}
|
||||
addScheduleEvent(vipId, event) {
|
||||
if (!this.data.schedules[vipId]) {
|
||||
this.data.schedules[vipId] = [];
|
||||
}
|
||||
this.data.schedules[vipId].push(event);
|
||||
this.saveData();
|
||||
return event;
|
||||
}
|
||||
updateScheduleEvent(vipId, eventId, updatedEvent) {
|
||||
if (!this.data.schedules[vipId]) {
|
||||
return null;
|
||||
}
|
||||
const index = this.data.schedules[vipId].findIndex(event => event.id === eventId);
|
||||
if (index !== -1) {
|
||||
this.data.schedules[vipId][index] = updatedEvent;
|
||||
this.saveData();
|
||||
return this.data.schedules[vipId][index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
deleteScheduleEvent(vipId, eventId) {
|
||||
if (!this.data.schedules[vipId]) {
|
||||
return null;
|
||||
}
|
||||
const index = this.data.schedules[vipId].findIndex(event => event.id === eventId);
|
||||
if (index !== -1) {
|
||||
const deletedEvent = this.data.schedules[vipId].splice(index, 1)[0];
|
||||
this.saveData();
|
||||
return deletedEvent;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getAllSchedules() {
|
||||
return this.data.schedules;
|
||||
}
|
||||
// Admin settings operations
|
||||
getAdminSettings() {
|
||||
return this.data.adminSettings;
|
||||
}
|
||||
updateAdminSettings(settings) {
|
||||
this.data.adminSettings = { ...this.data.adminSettings, ...settings };
|
||||
this.saveData();
|
||||
}
|
||||
// Backup and restore operations
|
||||
createBackup() {
|
||||
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
||||
const backupFile = path_1.default.join(this.dataDir, `backup-${timestamp}.json`);
|
||||
try {
|
||||
fs_1.default.copyFileSync(this.dataFile, backupFile);
|
||||
console.log(`📦 Backup created: ${backupFile}`);
|
||||
return backupFile;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error creating backup:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// User operations
|
||||
getUsers() {
|
||||
return this.data.users;
|
||||
}
|
||||
getUserByEmail(email) {
|
||||
return this.data.users.find(user => user.email === email) || null;
|
||||
}
|
||||
getUserById(id) {
|
||||
return this.data.users.find(user => user.id === id) || null;
|
||||
}
|
||||
addUser(user) {
|
||||
// Add timestamps
|
||||
const userWithTimestamps = {
|
||||
...user,
|
||||
created_at: new Date().toISOString(),
|
||||
last_sign_in_at: new Date().toISOString()
|
||||
};
|
||||
this.data.users.push(userWithTimestamps);
|
||||
this.saveData();
|
||||
console.log(`👤 Added user: ${user.name} (${user.email}) as ${user.role}`);
|
||||
return userWithTimestamps;
|
||||
}
|
||||
updateUser(email, updatedUser) {
|
||||
const index = this.data.users.findIndex(user => user.email === email);
|
||||
if (index !== -1) {
|
||||
this.data.users[index] = { ...this.data.users[index], ...updatedUser };
|
||||
this.saveData();
|
||||
console.log(`👤 Updated user: ${this.data.users[index].name} (${email})`);
|
||||
return this.data.users[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
updateUserRole(email, role) {
|
||||
const index = this.data.users.findIndex(user => user.email === email);
|
||||
if (index !== -1) {
|
||||
this.data.users[index].role = role;
|
||||
this.saveData();
|
||||
console.log(`👤 Updated user role: ${this.data.users[index].name} (${email}) -> ${role}`);
|
||||
return this.data.users[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
updateUserLastSignIn(email) {
|
||||
const index = this.data.users.findIndex(user => user.email === email);
|
||||
if (index !== -1) {
|
||||
this.data.users[index].last_sign_in_at = new Date().toISOString();
|
||||
this.saveData();
|
||||
return this.data.users[index];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
deleteUser(email) {
|
||||
const index = this.data.users.findIndex(user => user.email === email);
|
||||
if (index !== -1) {
|
||||
const deletedUser = this.data.users.splice(index, 1)[0];
|
||||
this.saveData();
|
||||
console.log(`👤 Deleted user: ${deletedUser.name} (${email})`);
|
||||
return deletedUser;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getUserCount() {
|
||||
return this.data.users.length;
|
||||
}
|
||||
getDataStats() {
|
||||
return {
|
||||
vips: this.data.vips.length,
|
||||
drivers: this.data.drivers.length,
|
||||
users: this.data.users.length,
|
||||
scheduledEvents: Object.values(this.data.schedules).reduce((total, events) => total + events.length, 0),
|
||||
vipsWithSchedules: Object.keys(this.data.schedules).length,
|
||||
dataFile: this.dataFile,
|
||||
lastModified: fs_1.default.existsSync(this.dataFile) ? fs_1.default.statSync(this.dataFile).mtime : null
|
||||
};
|
||||
}
|
||||
}
|
||||
exports.default = new DataService();
|
||||
//# sourceMappingURL=dataService.js.map
|
||||
1
backend-old-20260125/dist/services/dataService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/dataService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
56
backend-old-20260125/dist/services/databaseService.d.ts
vendored
Normal file
56
backend-old-20260125/dist/services/databaseService.d.ts
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
import { PoolClient } from 'pg';
|
||||
declare class EnhancedDatabaseService {
|
||||
private backupService;
|
||||
constructor();
|
||||
query(text: string, params?: any[]): Promise<any>;
|
||||
getClient(): Promise<PoolClient>;
|
||||
close(): Promise<void>;
|
||||
initializeTables(): Promise<void>;
|
||||
createUser(user: any): Promise<any>;
|
||||
getUserByEmail(email: string): Promise<any>;
|
||||
getUserById(id: string): Promise<any>;
|
||||
updateUserRole(email: string, role: string): Promise<any>;
|
||||
updateUserLastSignIn(email: string): Promise<any>;
|
||||
getUserCount(): Promise<number>;
|
||||
updateUserApprovalStatus(email: string, status: 'pending' | 'approved' | 'denied'): Promise<any>;
|
||||
getApprovedUserCount(): Promise<number>;
|
||||
getAllUsers(): Promise<any[]>;
|
||||
deleteUser(email: string): Promise<boolean>;
|
||||
getPendingUsers(): Promise<any[]>;
|
||||
completeUserOnboarding(email: string, onboardingData: any): Promise<any>;
|
||||
approveUser(userEmail: string, approvedBy: string, newRole?: string): Promise<any>;
|
||||
rejectUser(userEmail: string, rejectedBy: string, reason?: string): Promise<any>;
|
||||
deactivateUser(userEmail: string, deactivatedBy: string): Promise<any>;
|
||||
reactivateUser(userEmail: string, reactivatedBy: string): Promise<any>;
|
||||
createAuditLog(action: string, userEmail: string, performedBy: string, details: any): Promise<void>;
|
||||
getUserAuditLog(userEmail: string): Promise<any[]>;
|
||||
getUsersWithFilters(filters: {
|
||||
status?: string;
|
||||
role?: string;
|
||||
search?: string;
|
||||
}): Promise<any[]>;
|
||||
getActiveUserCount(): Promise<number>;
|
||||
isFirstUser(): Promise<boolean>;
|
||||
createVip(vip: any): Promise<any>;
|
||||
getVipById(id: string): Promise<any>;
|
||||
getAllVips(): Promise<any[]>;
|
||||
updateVip(id: string, vip: any): Promise<any>;
|
||||
deleteVip(id: string): Promise<boolean>;
|
||||
getVipsByDepartment(department: string): Promise<any[]>;
|
||||
createDriver(driver: any): Promise<any>;
|
||||
getDriverById(id: string): Promise<any>;
|
||||
getAllDrivers(): Promise<any[]>;
|
||||
updateDriver(id: string, driver: any): Promise<any>;
|
||||
deleteDriver(id: string): Promise<boolean>;
|
||||
getDriversByDepartment(department: string): Promise<any[]>;
|
||||
updateDriverLocation(id: string, location: any): Promise<any>;
|
||||
createScheduleEvent(vipId: string, event: any): Promise<any>;
|
||||
getScheduleByVipId(vipId: string): Promise<any[]>;
|
||||
updateScheduleEvent(vipId: string, eventId: string, event: any): Promise<any>;
|
||||
deleteScheduleEvent(vipId: string, eventId: string): Promise<boolean>;
|
||||
getAllScheduleEvents(): Promise<any[]>;
|
||||
getScheduleEventsByDateRange(startDate: Date, endDate: Date): Promise<any[]>;
|
||||
}
|
||||
declare const databaseService: EnhancedDatabaseService;
|
||||
export default databaseService;
|
||||
//# sourceMappingURL=databaseService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/databaseService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/databaseService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"databaseService.d.ts","sourceRoot":"","sources":["../../src/services/databaseService.ts"],"names":[],"mappings":"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"}
|
||||
265
backend-old-20260125/dist/services/databaseService.js
vendored
Normal file
265
backend-old-20260125/dist/services/databaseService.js
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// Import the existing backup service
|
||||
const databaseService_1 = __importDefault(require("./backup-services/databaseService"));
|
||||
// Extend the backup service with new user management methods
|
||||
class EnhancedDatabaseService {
|
||||
constructor() {
|
||||
this.backupService = databaseService_1.default;
|
||||
}
|
||||
// Delegate all existing methods to backup service
|
||||
async query(text, params) {
|
||||
return this.backupService.query(text, params);
|
||||
}
|
||||
async getClient() {
|
||||
return this.backupService.getClient();
|
||||
}
|
||||
async close() {
|
||||
return this.backupService.close();
|
||||
}
|
||||
async initializeTables() {
|
||||
return this.backupService.initializeTables();
|
||||
}
|
||||
// User methods from backup service
|
||||
async createUser(user) {
|
||||
return this.backupService.createUser(user);
|
||||
}
|
||||
async getUserByEmail(email) {
|
||||
return this.backupService.getUserByEmail(email);
|
||||
}
|
||||
async getUserById(id) {
|
||||
return this.backupService.getUserById(id);
|
||||
}
|
||||
async updateUserRole(email, role) {
|
||||
return this.backupService.updateUserRole(email, role);
|
||||
}
|
||||
async updateUserLastSignIn(email) {
|
||||
return this.backupService.updateUserLastSignIn(email);
|
||||
}
|
||||
async getUserCount() {
|
||||
return this.backupService.getUserCount();
|
||||
}
|
||||
async updateUserApprovalStatus(email, status) {
|
||||
return this.backupService.updateUserApprovalStatus(email, status);
|
||||
}
|
||||
async getApprovedUserCount() {
|
||||
return this.backupService.getApprovedUserCount();
|
||||
}
|
||||
async getAllUsers() {
|
||||
return this.backupService.getAllUsers();
|
||||
}
|
||||
async deleteUser(email) {
|
||||
return this.backupService.deleteUser(email);
|
||||
}
|
||||
async getPendingUsers() {
|
||||
return this.backupService.getPendingUsers();
|
||||
}
|
||||
// NEW: Enhanced user management methods
|
||||
async completeUserOnboarding(email, onboardingData) {
|
||||
const query = `
|
||||
UPDATE users
|
||||
SET phone = $1,
|
||||
organization = $2,
|
||||
onboarding_data = $3,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE email = $4
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await this.query(query, [
|
||||
onboardingData.phone,
|
||||
onboardingData.organization,
|
||||
JSON.stringify(onboardingData),
|
||||
email
|
||||
]);
|
||||
return result.rows[0] || null;
|
||||
}
|
||||
async approveUser(userEmail, approvedBy, newRole) {
|
||||
const query = `
|
||||
UPDATE users
|
||||
SET status = 'active',
|
||||
approval_status = 'approved',
|
||||
approved_by = $1,
|
||||
approved_at = CURRENT_TIMESTAMP,
|
||||
role = COALESCE($2, role),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE email = $3
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await this.query(query, [approvedBy, newRole, userEmail]);
|
||||
// Log audit
|
||||
if (result.rows[0]) {
|
||||
await this.createAuditLog('user_approved', userEmail, approvedBy, { newRole });
|
||||
}
|
||||
return result.rows[0] || null;
|
||||
}
|
||||
async rejectUser(userEmail, rejectedBy, reason) {
|
||||
const query = `
|
||||
UPDATE users
|
||||
SET status = 'deactivated',
|
||||
approval_status = 'denied',
|
||||
rejected_by = $1,
|
||||
rejected_at = CURRENT_TIMESTAMP,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE email = $2
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await this.query(query, [rejectedBy, userEmail]);
|
||||
// Log audit
|
||||
if (result.rows[0]) {
|
||||
await this.createAuditLog('user_rejected', userEmail, rejectedBy, { reason });
|
||||
}
|
||||
return result.rows[0] || null;
|
||||
}
|
||||
async deactivateUser(userEmail, deactivatedBy) {
|
||||
const query = `
|
||||
UPDATE users
|
||||
SET status = 'deactivated',
|
||||
deactivated_by = $1,
|
||||
deactivated_at = CURRENT_TIMESTAMP,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE email = $2
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await this.query(query, [deactivatedBy, userEmail]);
|
||||
// Log audit
|
||||
if (result.rows[0]) {
|
||||
await this.createAuditLog('user_deactivated', userEmail, deactivatedBy, {});
|
||||
}
|
||||
return result.rows[0] || null;
|
||||
}
|
||||
async reactivateUser(userEmail, reactivatedBy) {
|
||||
const query = `
|
||||
UPDATE users
|
||||
SET status = 'active',
|
||||
deactivated_by = NULL,
|
||||
deactivated_at = NULL,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE email = $1
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await this.query(query, [userEmail]);
|
||||
// Log audit
|
||||
if (result.rows[0]) {
|
||||
await this.createAuditLog('user_reactivated', userEmail, reactivatedBy, {});
|
||||
}
|
||||
return result.rows[0] || null;
|
||||
}
|
||||
async createAuditLog(action, userEmail, performedBy, details) {
|
||||
const query = `
|
||||
INSERT INTO user_audit_log (action, user_email, performed_by, action_details)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
`;
|
||||
await this.query(query, [action, userEmail, performedBy, JSON.stringify(details)]);
|
||||
}
|
||||
async getUserAuditLog(userEmail) {
|
||||
const query = `
|
||||
SELECT * FROM user_audit_log
|
||||
WHERE user_email = $1
|
||||
ORDER BY created_at DESC
|
||||
`;
|
||||
const result = await this.query(query, [userEmail]);
|
||||
return result.rows;
|
||||
}
|
||||
async getUsersWithFilters(filters) {
|
||||
let query = 'SELECT * FROM users WHERE 1=1';
|
||||
const params = [];
|
||||
let paramIndex = 1;
|
||||
if (filters.status) {
|
||||
query += ` AND status = $${paramIndex}`;
|
||||
params.push(filters.status);
|
||||
paramIndex++;
|
||||
}
|
||||
if (filters.role) {
|
||||
query += ` AND role = $${paramIndex}`;
|
||||
params.push(filters.role);
|
||||
paramIndex++;
|
||||
}
|
||||
if (filters.search) {
|
||||
query += ` AND (LOWER(name) LIKE LOWER($${paramIndex}) OR LOWER(email) LIKE LOWER($${paramIndex}) OR LOWER(organization) LIKE LOWER($${paramIndex}))`;
|
||||
params.push(`%${filters.search}%`);
|
||||
paramIndex++;
|
||||
}
|
||||
query += ' ORDER BY created_at DESC';
|
||||
const result = await this.query(query, params);
|
||||
return result.rows;
|
||||
}
|
||||
// Fix for first user admin issue
|
||||
async getActiveUserCount() {
|
||||
const query = "SELECT COUNT(*) as count FROM users WHERE status = 'active'";
|
||||
const result = await this.query(query);
|
||||
return parseInt(result.rows[0].count);
|
||||
}
|
||||
async isFirstUser() {
|
||||
// Check if there are any active or approved users
|
||||
const query = "SELECT COUNT(*) as count FROM users WHERE status = 'active' OR approval_status = 'approved'";
|
||||
const result = await this.query(query);
|
||||
return parseInt(result.rows[0].count) === 0;
|
||||
}
|
||||
// VIP methods from backup service
|
||||
async createVip(vip) {
|
||||
return this.backupService.createVip(vip);
|
||||
}
|
||||
async getVipById(id) {
|
||||
return this.backupService.getVipById(id);
|
||||
}
|
||||
async getAllVips() {
|
||||
return this.backupService.getAllVips();
|
||||
}
|
||||
async updateVip(id, vip) {
|
||||
return this.backupService.updateVip(id, vip);
|
||||
}
|
||||
async deleteVip(id) {
|
||||
return this.backupService.deleteVip(id);
|
||||
}
|
||||
async getVipsByDepartment(department) {
|
||||
return this.backupService.getVipsByDepartment(department);
|
||||
}
|
||||
// Driver methods from backup service
|
||||
async createDriver(driver) {
|
||||
return this.backupService.createDriver(driver);
|
||||
}
|
||||
async getDriverById(id) {
|
||||
return this.backupService.getDriverById(id);
|
||||
}
|
||||
async getAllDrivers() {
|
||||
return this.backupService.getAllDrivers();
|
||||
}
|
||||
async updateDriver(id, driver) {
|
||||
return this.backupService.updateDriver(id, driver);
|
||||
}
|
||||
async deleteDriver(id) {
|
||||
return this.backupService.deleteDriver(id);
|
||||
}
|
||||
async getDriversByDepartment(department) {
|
||||
return this.backupService.getDriversByDepartment(department);
|
||||
}
|
||||
async updateDriverLocation(id, location) {
|
||||
return this.backupService.updateDriverLocation(id, location);
|
||||
}
|
||||
// Schedule methods from backup service
|
||||
async createScheduleEvent(vipId, event) {
|
||||
return this.backupService.createScheduleEvent(vipId, event);
|
||||
}
|
||||
async getScheduleByVipId(vipId) {
|
||||
return this.backupService.getScheduleByVipId(vipId);
|
||||
}
|
||||
async updateScheduleEvent(vipId, eventId, event) {
|
||||
return this.backupService.updateScheduleEvent(vipId, eventId, event);
|
||||
}
|
||||
async deleteScheduleEvent(vipId, eventId) {
|
||||
return this.backupService.deleteScheduleEvent(vipId, eventId);
|
||||
}
|
||||
async getAllScheduleEvents() {
|
||||
return this.backupService.getAllScheduleEvents();
|
||||
}
|
||||
async getScheduleEventsByDateRange(startDate, endDate) {
|
||||
return this.backupService.getScheduleEventsByDateRange(startDate, endDate);
|
||||
}
|
||||
}
|
||||
// Export singleton instance
|
||||
const databaseService = new EnhancedDatabaseService();
|
||||
exports.default = databaseService;
|
||||
//# sourceMappingURL=databaseService.js.map
|
||||
1
backend-old-20260125/dist/services/databaseService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/databaseService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
49
backend-old-20260125/dist/services/driverConflictService.d.ts
vendored
Normal file
49
backend-old-20260125/dist/services/driverConflictService.d.ts
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
interface ScheduleEvent {
|
||||
id: string;
|
||||
title: string;
|
||||
location: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
assignedDriverId?: string;
|
||||
vipId: string;
|
||||
vipName: string;
|
||||
}
|
||||
interface ConflictInfo {
|
||||
type: 'overlap' | 'tight_turnaround' | 'back_to_back';
|
||||
severity: 'low' | 'medium' | 'high';
|
||||
message: string;
|
||||
conflictingEvent: ScheduleEvent;
|
||||
timeDifference?: number;
|
||||
}
|
||||
interface DriverAvailability {
|
||||
driverId: string;
|
||||
driverName: string;
|
||||
status: 'available' | 'scheduled' | 'overlapping' | 'tight_turnaround';
|
||||
assignmentCount: number;
|
||||
conflicts: ConflictInfo[];
|
||||
currentAssignments: ScheduleEvent[];
|
||||
}
|
||||
declare class DriverConflictService {
|
||||
checkDriverConflicts(driverId: string, newEvent: {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
location: string;
|
||||
}, allSchedules: {
|
||||
[vipId: string]: ScheduleEvent[];
|
||||
}, drivers: any[]): ConflictInfo[];
|
||||
getDriverAvailability(eventTime: {
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
location: string;
|
||||
}, allSchedules: {
|
||||
[vipId: string]: ScheduleEvent[];
|
||||
}, drivers: any[]): DriverAvailability[];
|
||||
private getDriverEvents;
|
||||
private hasTimeOverlap;
|
||||
private getTimeBetweenEvents;
|
||||
getDriverStatusSummary(availability: DriverAvailability): string;
|
||||
}
|
||||
declare const _default: DriverConflictService;
|
||||
export default _default;
|
||||
export { DriverAvailability, ConflictInfo, ScheduleEvent };
|
||||
//# sourceMappingURL=driverConflictService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/driverConflictService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/driverConflictService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"driverConflictService.d.ts","sourceRoot":"","sources":["../../src/services/driverConflictService.ts"],"names":[],"mappings":"AAAA,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,YAAY;IACpB,IAAI,EAAE,SAAS,GAAG,kBAAkB,GAAG,cAAc,CAAC;IACtD,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,aAAa,CAAC;IAChC,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,kBAAkB;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,WAAW,GAAG,WAAW,GAAG,aAAa,GAAG,kBAAkB,CAAC;IACvE,eAAe,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,kBAAkB,EAAE,aAAa,EAAE,CAAC;CACrC;AAED,cAAM,qBAAqB;IAGzB,oBAAoB,CAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAClE,YAAY,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,CAAA;KAAE,EAClD,OAAO,EAAE,GAAG,EAAE,GACb,YAAY,EAAE;IA8CjB,qBAAqB,CACnB,SAAS,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EACnE,YAAY,EAAE;QAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,EAAE,CAAA;KAAE,EAClD,OAAO,EAAE,GAAG,EAAE,GACb,kBAAkB,EAAE;IAgCvB,OAAO,CAAC,eAAe;IAsBvB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,oBAAoB;IAiB5B,sBAAsB,CAAC,YAAY,EAAE,kBAAkB,GAAG,MAAM;CAejE;;AAED,wBAA2C;AAC3C,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC"}
|
||||
123
backend-old-20260125/dist/services/driverConflictService.js
vendored
Normal file
123
backend-old-20260125/dist/services/driverConflictService.js
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class DriverConflictService {
|
||||
// Check for conflicts when assigning a driver to an event
|
||||
checkDriverConflicts(driverId, newEvent, allSchedules, drivers) {
|
||||
const conflicts = [];
|
||||
const driver = drivers.find(d => d.id === driverId);
|
||||
if (!driver)
|
||||
return conflicts;
|
||||
// Get all events assigned to this driver
|
||||
const driverEvents = this.getDriverEvents(driverId, allSchedules);
|
||||
const newStartTime = new Date(newEvent.startTime);
|
||||
const newEndTime = new Date(newEvent.endTime);
|
||||
for (const existingEvent of driverEvents) {
|
||||
const existingStart = new Date(existingEvent.startTime);
|
||||
const existingEnd = new Date(existingEvent.endTime);
|
||||
// Check for direct time overlap
|
||||
if (this.hasTimeOverlap(newStartTime, newEndTime, existingStart, existingEnd)) {
|
||||
conflicts.push({
|
||||
type: 'overlap',
|
||||
severity: 'high',
|
||||
message: `Direct time conflict with "${existingEvent.title}" for ${existingEvent.vipName}`,
|
||||
conflictingEvent: existingEvent
|
||||
});
|
||||
}
|
||||
// Check for tight turnaround (less than 15 minutes between events)
|
||||
else {
|
||||
const timeBetween = this.getTimeBetweenEvents(newStartTime, newEndTime, existingStart, existingEnd);
|
||||
if (timeBetween !== null && timeBetween < 15) {
|
||||
conflicts.push({
|
||||
type: 'tight_turnaround',
|
||||
severity: timeBetween < 5 ? 'high' : 'medium',
|
||||
message: `Only ${timeBetween} minutes between events. Previous: "${existingEvent.title}"`,
|
||||
conflictingEvent: existingEvent,
|
||||
timeDifference: timeBetween
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return conflicts;
|
||||
}
|
||||
// Get availability status for all drivers for a specific time slot
|
||||
getDriverAvailability(eventTime, allSchedules, drivers) {
|
||||
return drivers.map(driver => {
|
||||
const conflicts = this.checkDriverConflicts(driver.id, eventTime, allSchedules, drivers);
|
||||
const driverEvents = this.getDriverEvents(driver.id, allSchedules);
|
||||
let status = 'available';
|
||||
if (conflicts.length > 0) {
|
||||
const hasOverlap = conflicts.some(c => c.type === 'overlap');
|
||||
const hasTightTurnaround = conflicts.some(c => c.type === 'tight_turnaround');
|
||||
if (hasOverlap) {
|
||||
status = 'overlapping';
|
||||
}
|
||||
else if (hasTightTurnaround) {
|
||||
status = 'tight_turnaround';
|
||||
}
|
||||
}
|
||||
else if (driverEvents.length > 0) {
|
||||
status = 'scheduled';
|
||||
}
|
||||
return {
|
||||
driverId: driver.id,
|
||||
driverName: driver.name,
|
||||
status,
|
||||
assignmentCount: driverEvents.length,
|
||||
conflicts,
|
||||
currentAssignments: driverEvents
|
||||
};
|
||||
});
|
||||
}
|
||||
// Get all events assigned to a specific driver
|
||||
getDriverEvents(driverId, allSchedules) {
|
||||
const driverEvents = [];
|
||||
Object.entries(allSchedules).forEach(([vipId, events]) => {
|
||||
events.forEach(event => {
|
||||
if (event.assignedDriverId === driverId) {
|
||||
driverEvents.push({
|
||||
...event,
|
||||
vipId,
|
||||
vipName: event.title // We'll need to get actual VIP name from VIP data
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
// Sort by start time
|
||||
return driverEvents.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime());
|
||||
}
|
||||
// Check if two time periods overlap
|
||||
hasTimeOverlap(start1, end1, start2, end2) {
|
||||
return start1 < end2 && start2 < end1;
|
||||
}
|
||||
// Get minutes between two events (null if they overlap)
|
||||
getTimeBetweenEvents(newStart, newEnd, existingStart, existingEnd) {
|
||||
// If new event is after existing event
|
||||
if (newStart >= existingEnd) {
|
||||
return Math.floor((newStart.getTime() - existingEnd.getTime()) / (1000 * 60));
|
||||
}
|
||||
// If new event is before existing event
|
||||
else if (newEnd <= existingStart) {
|
||||
return Math.floor((existingStart.getTime() - newEnd.getTime()) / (1000 * 60));
|
||||
}
|
||||
// Events overlap
|
||||
return null;
|
||||
}
|
||||
// Generate summary message for driver status
|
||||
getDriverStatusSummary(availability) {
|
||||
switch (availability.status) {
|
||||
case 'available':
|
||||
return `✅ Fully available (${availability.assignmentCount} assignments)`;
|
||||
case 'scheduled':
|
||||
return `🟡 Has ${availability.assignmentCount} assignment(s) but available for this time`;
|
||||
case 'tight_turnaround':
|
||||
const tightConflict = availability.conflicts.find(c => c.type === 'tight_turnaround');
|
||||
return `⚡ Tight turnaround - ${tightConflict?.timeDifference} min between events`;
|
||||
case 'overlapping':
|
||||
return `🔴 Time conflict with existing assignment`;
|
||||
default:
|
||||
return 'Unknown status';
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = new DriverConflictService();
|
||||
//# sourceMappingURL=driverConflictService.js.map
|
||||
1
backend-old-20260125/dist/services/driverConflictService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/driverConflictService.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"driverConflictService.js","sourceRoot":"","sources":["../../src/services/driverConflictService.ts"],"names":[],"mappings":"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"}
|
||||
60
backend-old-20260125/dist/services/enhancedDataService.d.ts
vendored
Normal file
60
backend-old-20260125/dist/services/enhancedDataService.d.ts
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
interface VipData {
|
||||
id: string;
|
||||
name: string;
|
||||
organization: string;
|
||||
department?: string;
|
||||
transportMode: 'flight' | 'self-driving';
|
||||
expectedArrival?: string;
|
||||
needsAirportPickup?: boolean;
|
||||
needsVenueTransport: boolean;
|
||||
notes?: string;
|
||||
flights?: Array<{
|
||||
flightNumber: string;
|
||||
flightDate: string;
|
||||
segment: number;
|
||||
}>;
|
||||
}
|
||||
interface DriverData {
|
||||
id: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
department?: string;
|
||||
currentLocation?: {
|
||||
lat: number;
|
||||
lng: number;
|
||||
};
|
||||
assignedVipIds?: string[];
|
||||
}
|
||||
interface ScheduleEventData {
|
||||
id: string;
|
||||
title: string;
|
||||
location: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
description?: string;
|
||||
assignedDriverId?: string;
|
||||
status: string;
|
||||
type: string;
|
||||
}
|
||||
declare class EnhancedDataService {
|
||||
getVips(): Promise<VipData[]>;
|
||||
addVip(vip: VipData): Promise<VipData>;
|
||||
updateVip(id: string, vip: Partial<VipData>): Promise<VipData | null>;
|
||||
deleteVip(id: string): Promise<VipData | null>;
|
||||
getDrivers(): Promise<DriverData[]>;
|
||||
addDriver(driver: DriverData): Promise<DriverData>;
|
||||
updateDriver(id: string, driver: Partial<DriverData>): Promise<DriverData | null>;
|
||||
deleteDriver(id: string): Promise<DriverData | null>;
|
||||
getSchedule(vipId: string): Promise<ScheduleEventData[]>;
|
||||
addScheduleEvent(vipId: string, event: ScheduleEventData): Promise<ScheduleEventData>;
|
||||
updateScheduleEvent(vipId: string, eventId: string, event: ScheduleEventData): Promise<ScheduleEventData | null>;
|
||||
deleteScheduleEvent(vipId: string, eventId: string): Promise<ScheduleEventData | null>;
|
||||
getAllSchedules(): Promise<{
|
||||
[vipId: string]: ScheduleEventData[];
|
||||
}>;
|
||||
getAdminSettings(): Promise<any>;
|
||||
updateAdminSettings(settings: any): Promise<void>;
|
||||
}
|
||||
declare const _default: EnhancedDataService;
|
||||
export default _default;
|
||||
//# sourceMappingURL=enhancedDataService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/enhancedDataService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/enhancedDataService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"enhancedDataService.d.ts","sourceRoot":"","sources":["../../src/services/enhancedDataService.ts"],"names":[],"mappings":"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"}
|
||||
571
backend-old-20260125/dist/services/enhancedDataService.js
vendored
Normal file
571
backend-old-20260125/dist/services/enhancedDataService.js
vendored
Normal file
@@ -0,0 +1,571 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const database_1 = __importDefault(require("../config/database"));
|
||||
const databaseService_1 = __importDefault(require("./databaseService"));
|
||||
class EnhancedDataService {
|
||||
// VIP operations
|
||||
async getVips() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT v.*,
|
||||
COALESCE(
|
||||
json_agg(
|
||||
json_build_object(
|
||||
'flightNumber', f.flight_number,
|
||||
'flightDate', f.flight_date,
|
||||
'segment', f.segment
|
||||
) ORDER BY f.segment
|
||||
) FILTER (WHERE f.id IS NOT NULL),
|
||||
'[]'::json
|
||||
) as flights
|
||||
FROM vips v
|
||||
LEFT JOIN flights f ON v.id = f.vip_id
|
||||
GROUP BY v.id
|
||||
ORDER BY v.name
|
||||
`;
|
||||
const result = await database_1.default.query(query);
|
||||
return result.rows.map(row => ({
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
organization: row.organization,
|
||||
department: row.department,
|
||||
transportMode: row.transport_mode,
|
||||
expectedArrival: row.expected_arrival,
|
||||
needsAirportPickup: row.needs_airport_pickup,
|
||||
needsVenueTransport: row.needs_venue_transport,
|
||||
notes: row.notes,
|
||||
flights: row.flights
|
||||
}));
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error fetching VIPs:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async addVip(vip) {
|
||||
const client = await database_1.default.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
// Insert VIP
|
||||
const vipQuery = `
|
||||
INSERT INTO vips (id, name, organization, department, transport_mode, expected_arrival, needs_airport_pickup, needs_venue_transport, notes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
RETURNING *
|
||||
`;
|
||||
const vipResult = await client.query(vipQuery, [
|
||||
vip.id,
|
||||
vip.name,
|
||||
vip.organization,
|
||||
vip.department || 'Office of Development',
|
||||
vip.transportMode,
|
||||
vip.expectedArrival || null,
|
||||
vip.needsAirportPickup || false,
|
||||
vip.needsVenueTransport,
|
||||
vip.notes || ''
|
||||
]);
|
||||
// Insert flights if any
|
||||
if (vip.flights && vip.flights.length > 0) {
|
||||
for (const flight of vip.flights) {
|
||||
const flightQuery = `
|
||||
INSERT INTO flights (vip_id, flight_number, flight_date, segment)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
`;
|
||||
await client.query(flightQuery, [
|
||||
vip.id,
|
||||
flight.flightNumber,
|
||||
flight.flightDate,
|
||||
flight.segment
|
||||
]);
|
||||
}
|
||||
}
|
||||
await client.query('COMMIT');
|
||||
const savedVip = {
|
||||
...vip,
|
||||
department: vipResult.rows[0].department,
|
||||
transportMode: vipResult.rows[0].transport_mode,
|
||||
expectedArrival: vipResult.rows[0].expected_arrival,
|
||||
needsAirportPickup: vipResult.rows[0].needs_airport_pickup,
|
||||
needsVenueTransport: vipResult.rows[0].needs_venue_transport
|
||||
};
|
||||
return savedVip;
|
||||
}
|
||||
catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
console.error('❌ Error adding VIP:', error);
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
async updateVip(id, vip) {
|
||||
const client = await database_1.default.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
// Update VIP
|
||||
const vipQuery = `
|
||||
UPDATE vips
|
||||
SET name = $2, organization = $3, department = $4, transport_mode = $5,
|
||||
expected_arrival = $6, needs_airport_pickup = $7, needs_venue_transport = $8, notes = $9
|
||||
WHERE id = $1
|
||||
RETURNING *
|
||||
`;
|
||||
const vipResult = await client.query(vipQuery, [
|
||||
id,
|
||||
vip.name,
|
||||
vip.organization,
|
||||
vip.department || 'Office of Development',
|
||||
vip.transportMode,
|
||||
vip.expectedArrival || null,
|
||||
vip.needsAirportPickup || false,
|
||||
vip.needsVenueTransport,
|
||||
vip.notes || ''
|
||||
]);
|
||||
if (vipResult.rows.length === 0) {
|
||||
await client.query('ROLLBACK');
|
||||
return null;
|
||||
}
|
||||
// Delete existing flights and insert new ones
|
||||
await client.query('DELETE FROM flights WHERE vip_id = $1', [id]);
|
||||
if (vip.flights && vip.flights.length > 0) {
|
||||
for (const flight of vip.flights) {
|
||||
const flightQuery = `
|
||||
INSERT INTO flights (vip_id, flight_number, flight_date, segment)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
`;
|
||||
await client.query(flightQuery, [
|
||||
id,
|
||||
flight.flightNumber,
|
||||
flight.flightDate,
|
||||
flight.segment
|
||||
]);
|
||||
}
|
||||
}
|
||||
await client.query('COMMIT');
|
||||
const updatedVip = {
|
||||
id: vipResult.rows[0].id,
|
||||
name: vipResult.rows[0].name,
|
||||
organization: vipResult.rows[0].organization,
|
||||
department: vipResult.rows[0].department,
|
||||
transportMode: vipResult.rows[0].transport_mode,
|
||||
expectedArrival: vipResult.rows[0].expected_arrival,
|
||||
needsAirportPickup: vipResult.rows[0].needs_airport_pickup,
|
||||
needsVenueTransport: vipResult.rows[0].needs_venue_transport,
|
||||
notes: vipResult.rows[0].notes,
|
||||
flights: vip.flights || []
|
||||
};
|
||||
return updatedVip;
|
||||
}
|
||||
catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
console.error('❌ Error updating VIP:', error);
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
async deleteVip(id) {
|
||||
try {
|
||||
const query = `
|
||||
DELETE FROM vips WHERE id = $1 RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [id]);
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const deletedVip = {
|
||||
id: result.rows[0].id,
|
||||
name: result.rows[0].name,
|
||||
organization: result.rows[0].organization,
|
||||
department: result.rows[0].department,
|
||||
transportMode: result.rows[0].transport_mode,
|
||||
expectedArrival: result.rows[0].expected_arrival,
|
||||
needsAirportPickup: result.rows[0].needs_airport_pickup,
|
||||
needsVenueTransport: result.rows[0].needs_venue_transport,
|
||||
notes: result.rows[0].notes
|
||||
};
|
||||
return deletedVip;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error deleting VIP:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// Driver operations
|
||||
async getDrivers() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT d.*,
|
||||
COALESCE(
|
||||
json_agg(DISTINCT se.vip_id) FILTER (WHERE se.vip_id IS NOT NULL),
|
||||
'[]'::json
|
||||
) as assigned_vip_ids
|
||||
FROM drivers d
|
||||
LEFT JOIN schedule_events se ON d.id = se.assigned_driver_id
|
||||
GROUP BY d.id
|
||||
ORDER BY d.name
|
||||
`;
|
||||
const result = await database_1.default.query(query);
|
||||
// Get current locations from Redis
|
||||
const driversWithLocations = await Promise.all(result.rows.map(async (row) => {
|
||||
const location = await databaseService_1.default.getDriverLocation(row.id);
|
||||
return {
|
||||
id: row.id,
|
||||
name: row.name,
|
||||
phone: row.phone,
|
||||
department: row.department,
|
||||
currentLocation: location ? { lat: location.lat, lng: location.lng } : { lat: 0, lng: 0 },
|
||||
assignedVipIds: row.assigned_vip_ids || []
|
||||
};
|
||||
}));
|
||||
return driversWithLocations;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error fetching drivers:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async addDriver(driver) {
|
||||
try {
|
||||
const query = `
|
||||
INSERT INTO drivers (id, name, phone, department)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [
|
||||
driver.id,
|
||||
driver.name,
|
||||
driver.phone,
|
||||
driver.department || 'Office of Development'
|
||||
]);
|
||||
// Store location in Redis if provided
|
||||
if (driver.currentLocation) {
|
||||
await databaseService_1.default.updateDriverLocation(driver.id, driver.currentLocation);
|
||||
}
|
||||
const savedDriver = {
|
||||
id: result.rows[0].id,
|
||||
name: result.rows[0].name,
|
||||
phone: result.rows[0].phone,
|
||||
department: result.rows[0].department,
|
||||
currentLocation: driver.currentLocation || { lat: 0, lng: 0 }
|
||||
};
|
||||
return savedDriver;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error adding driver:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async updateDriver(id, driver) {
|
||||
try {
|
||||
const query = `
|
||||
UPDATE drivers
|
||||
SET name = $2, phone = $3, department = $4
|
||||
WHERE id = $1
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [
|
||||
id,
|
||||
driver.name,
|
||||
driver.phone,
|
||||
driver.department || 'Office of Development'
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
// Update location in Redis if provided
|
||||
if (driver.currentLocation) {
|
||||
await databaseService_1.default.updateDriverLocation(id, driver.currentLocation);
|
||||
}
|
||||
const updatedDriver = {
|
||||
id: result.rows[0].id,
|
||||
name: result.rows[0].name,
|
||||
phone: result.rows[0].phone,
|
||||
department: result.rows[0].department,
|
||||
currentLocation: driver.currentLocation || { lat: 0, lng: 0 }
|
||||
};
|
||||
return updatedDriver;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error updating driver:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async deleteDriver(id) {
|
||||
try {
|
||||
const query = `
|
||||
DELETE FROM drivers WHERE id = $1 RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [id]);
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const deletedDriver = {
|
||||
id: result.rows[0].id,
|
||||
name: result.rows[0].name,
|
||||
phone: result.rows[0].phone,
|
||||
department: result.rows[0].department
|
||||
};
|
||||
return deletedDriver;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error deleting driver:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// Schedule operations
|
||||
async getSchedule(vipId) {
|
||||
try {
|
||||
const query = `
|
||||
SELECT * FROM schedule_events
|
||||
WHERE vip_id = $1
|
||||
ORDER BY start_time
|
||||
`;
|
||||
const result = await database_1.default.query(query, [vipId]);
|
||||
return result.rows.map(row => ({
|
||||
id: row.id,
|
||||
title: row.title,
|
||||
location: row.location,
|
||||
startTime: row.start_time,
|
||||
endTime: row.end_time,
|
||||
description: row.description,
|
||||
assignedDriverId: row.assigned_driver_id,
|
||||
status: row.status,
|
||||
type: row.event_type
|
||||
}));
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error fetching schedule:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async addScheduleEvent(vipId, event) {
|
||||
try {
|
||||
const query = `
|
||||
INSERT INTO schedule_events (id, vip_id, title, location, start_time, end_time, description, assigned_driver_id, status, event_type)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [
|
||||
event.id,
|
||||
vipId,
|
||||
event.title,
|
||||
event.location,
|
||||
event.startTime,
|
||||
event.endTime,
|
||||
event.description || '',
|
||||
event.assignedDriverId || null,
|
||||
event.status,
|
||||
event.type
|
||||
]);
|
||||
const savedEvent = {
|
||||
id: result.rows[0].id,
|
||||
title: result.rows[0].title,
|
||||
location: result.rows[0].location,
|
||||
startTime: result.rows[0].start_time,
|
||||
endTime: result.rows[0].end_time,
|
||||
description: result.rows[0].description,
|
||||
assignedDriverId: result.rows[0].assigned_driver_id,
|
||||
status: result.rows[0].status,
|
||||
type: result.rows[0].event_type
|
||||
};
|
||||
return savedEvent;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error adding schedule event:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async updateScheduleEvent(vipId, eventId, event) {
|
||||
try {
|
||||
const query = `
|
||||
UPDATE schedule_events
|
||||
SET title = $3, location = $4, start_time = $5, end_time = $6, description = $7, assigned_driver_id = $8, status = $9, event_type = $10
|
||||
WHERE id = $1 AND vip_id = $2
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [
|
||||
eventId,
|
||||
vipId,
|
||||
event.title,
|
||||
event.location,
|
||||
event.startTime,
|
||||
event.endTime,
|
||||
event.description || '',
|
||||
event.assignedDriverId || null,
|
||||
event.status,
|
||||
event.type
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const updatedEvent = {
|
||||
id: result.rows[0].id,
|
||||
title: result.rows[0].title,
|
||||
location: result.rows[0].location,
|
||||
startTime: result.rows[0].start_time,
|
||||
endTime: result.rows[0].end_time,
|
||||
description: result.rows[0].description,
|
||||
assignedDriverId: result.rows[0].assigned_driver_id,
|
||||
status: result.rows[0].status,
|
||||
type: result.rows[0].event_type
|
||||
};
|
||||
return updatedEvent;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error updating schedule event:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async deleteScheduleEvent(vipId, eventId) {
|
||||
try {
|
||||
const query = `
|
||||
DELETE FROM schedule_events
|
||||
WHERE id = $1 AND vip_id = $2
|
||||
RETURNING *
|
||||
`;
|
||||
const result = await database_1.default.query(query, [eventId, vipId]);
|
||||
if (result.rows.length === 0) {
|
||||
return null;
|
||||
}
|
||||
const deletedEvent = {
|
||||
id: result.rows[0].id,
|
||||
title: result.rows[0].title,
|
||||
location: result.rows[0].location,
|
||||
startTime: result.rows[0].start_time,
|
||||
endTime: result.rows[0].end_time,
|
||||
description: result.rows[0].description,
|
||||
assignedDriverId: result.rows[0].assigned_driver_id,
|
||||
status: result.rows[0].status,
|
||||
type: result.rows[0].event_type
|
||||
};
|
||||
return deletedEvent;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error deleting schedule event:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async getAllSchedules() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT * FROM schedule_events
|
||||
ORDER BY vip_id, start_time
|
||||
`;
|
||||
const result = await database_1.default.query(query);
|
||||
const schedules = {};
|
||||
for (const row of result.rows) {
|
||||
const vipId = row.vip_id;
|
||||
if (!schedules[vipId]) {
|
||||
schedules[vipId] = [];
|
||||
}
|
||||
schedules[vipId].push({
|
||||
id: row.id,
|
||||
title: row.title,
|
||||
location: row.location,
|
||||
startTime: row.start_time,
|
||||
endTime: row.end_time,
|
||||
description: row.description,
|
||||
assignedDriverId: row.assigned_driver_id,
|
||||
status: row.status,
|
||||
type: row.event_type
|
||||
});
|
||||
}
|
||||
return schedules;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error fetching all schedules:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
// Admin settings operations
|
||||
async getAdminSettings() {
|
||||
try {
|
||||
const query = `
|
||||
SELECT setting_key, setting_value FROM admin_settings
|
||||
`;
|
||||
const result = await database_1.default.query(query);
|
||||
// Default settings structure
|
||||
const defaultSettings = {
|
||||
apiKeys: {
|
||||
aviationStackKey: '',
|
||||
googleMapsKey: '',
|
||||
twilioKey: '',
|
||||
googleClientId: '',
|
||||
googleClientSecret: ''
|
||||
},
|
||||
systemSettings: {
|
||||
defaultPickupLocation: '',
|
||||
defaultDropoffLocation: '',
|
||||
timeZone: 'America/New_York',
|
||||
notificationsEnabled: false
|
||||
}
|
||||
};
|
||||
// If no settings exist, return defaults
|
||||
if (result.rows.length === 0) {
|
||||
return defaultSettings;
|
||||
}
|
||||
// Reconstruct nested object from flattened keys
|
||||
const settings = { ...defaultSettings };
|
||||
for (const row of result.rows) {
|
||||
const keys = row.setting_key.split('.');
|
||||
let current = settings;
|
||||
for (let i = 0; i < keys.length - 1; i++) {
|
||||
if (!current[keys[i]]) {
|
||||
current[keys[i]] = {};
|
||||
}
|
||||
current = current[keys[i]];
|
||||
}
|
||||
// Parse boolean values
|
||||
let value = row.setting_value;
|
||||
if (value === 'true')
|
||||
value = true;
|
||||
else if (value === 'false')
|
||||
value = false;
|
||||
current[keys[keys.length - 1]] = value;
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error fetching admin settings:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async updateAdminSettings(settings) {
|
||||
try {
|
||||
// Flatten settings and update
|
||||
const flattenSettings = (obj, prefix = '') => {
|
||||
const result = [];
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||
if (typeof value === 'object' && value !== null) {
|
||||
result.push(...flattenSettings(value, fullKey));
|
||||
}
|
||||
else {
|
||||
result.push({ key: fullKey, value: String(value) });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
const flatSettings = flattenSettings(settings);
|
||||
for (const setting of flatSettings) {
|
||||
const query = `
|
||||
INSERT INTO admin_settings (setting_key, setting_value)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (setting_key) DO UPDATE SET setting_value = $2
|
||||
`;
|
||||
await database_1.default.query(query, [setting.key, setting.value]);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
console.error('❌ Error updating admin settings:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = new EnhancedDataService();
|
||||
//# sourceMappingURL=enhancedDataService.js.map
|
||||
1
backend-old-20260125/dist/services/enhancedDataService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/enhancedDataService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
53
backend-old-20260125/dist/services/flightService.d.ts
vendored
Normal file
53
backend-old-20260125/dist/services/flightService.d.ts
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
interface FlightData {
|
||||
flightNumber: string;
|
||||
flightDate: string;
|
||||
status: string;
|
||||
airline?: string;
|
||||
aircraft?: string;
|
||||
departure: {
|
||||
airport: string;
|
||||
airportName?: string;
|
||||
scheduled: string;
|
||||
estimated?: string;
|
||||
actual?: string;
|
||||
terminal?: string;
|
||||
gate?: string;
|
||||
};
|
||||
arrival: {
|
||||
airport: string;
|
||||
airportName?: string;
|
||||
scheduled: string;
|
||||
estimated?: string;
|
||||
actual?: string;
|
||||
terminal?: string;
|
||||
gate?: string;
|
||||
};
|
||||
delay?: number;
|
||||
lastUpdated: string;
|
||||
source: 'google' | 'aviationstack' | 'not_found';
|
||||
}
|
||||
interface FlightSearchParams {
|
||||
flightNumber: string;
|
||||
date: string;
|
||||
departureAirport?: string;
|
||||
arrivalAirport?: string;
|
||||
}
|
||||
declare class FlightService {
|
||||
private flightCache;
|
||||
private updateIntervals;
|
||||
constructor();
|
||||
getFlightInfo(params: FlightSearchParams): Promise<FlightData | null>;
|
||||
private scrapeGoogleFlights;
|
||||
private getFromAviationStack;
|
||||
startPeriodicUpdates(params: FlightSearchParams, intervalMinutes?: number): void;
|
||||
stopPeriodicUpdates(key: string): void;
|
||||
getMultipleFlights(flightParams: FlightSearchParams[]): Promise<{
|
||||
[key: string]: FlightData | null;
|
||||
}>;
|
||||
private normalizeStatus;
|
||||
cleanup(): void;
|
||||
}
|
||||
declare const _default: FlightService;
|
||||
export default _default;
|
||||
export { FlightData, FlightSearchParams };
|
||||
//# sourceMappingURL=flightService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/flightService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/flightService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"flightService.d.ts","sourceRoot":"","sources":["../../src/services/flightService.ts"],"names":[],"mappings":"AAGA,UAAU,UAAU;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE;QACT,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,OAAO,EAAE;QACP,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,QAAQ,GAAG,eAAe,GAAG,WAAW,CAAC;CAClD;AAED,UAAU,kBAAkB;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,cAAM,aAAa;IACjB,OAAO,CAAC,WAAW,CAAiE;IACpF,OAAO,CAAC,eAAe,CAA0C;;IAO3D,aAAa,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;YAkC7D,mBAAmB;YAiBnB,oBAAoB;IAiGlC,oBAAoB,CAAC,MAAM,EAAE,kBAAkB,EAAE,eAAe,GAAE,MAAU,GAAG,IAAI;IAoBnF,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAShC,kBAAkB,CAAC,YAAY,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAAA;KAAE,CAAC;IAY3G,OAAO,CAAC,eAAe;IAcvB,OAAO,IAAI,IAAI;CAOhB;;AAED,wBAAmC;AACnC,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC"}
|
||||
196
backend-old-20260125/dist/services/flightService.js
vendored
Normal file
196
backend-old-20260125/dist/services/flightService.js
vendored
Normal file
@@ -0,0 +1,196 @@
|
||||
"use strict";
|
||||
// Real Flight tracking service with Google scraping
|
||||
// No mock data - only real flight information
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class FlightService {
|
||||
constructor() {
|
||||
this.flightCache = new Map();
|
||||
this.updateIntervals = new Map();
|
||||
// No API keys needed for Google scraping
|
||||
}
|
||||
// Real flight lookup - no mock data
|
||||
async getFlightInfo(params) {
|
||||
const cacheKey = `${params.flightNumber}_${params.date}`;
|
||||
// Check cache first (shorter cache for real data)
|
||||
const cached = this.flightCache.get(cacheKey);
|
||||
if (cached && cached.expires > Date.now()) {
|
||||
return cached.data;
|
||||
}
|
||||
try {
|
||||
// Try Google scraping first
|
||||
let flightData = await this.scrapeGoogleFlights(params);
|
||||
// If Google fails, try AviationStack (if API key available)
|
||||
if (!flightData) {
|
||||
flightData = await this.getFromAviationStack(params);
|
||||
}
|
||||
// Cache the result for 2 minutes (shorter for real data)
|
||||
if (flightData) {
|
||||
this.flightCache.set(cacheKey, {
|
||||
data: flightData,
|
||||
expires: Date.now() + (2 * 60 * 1000)
|
||||
});
|
||||
}
|
||||
return flightData;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error fetching flight data:', error);
|
||||
return null; // Return null instead of mock data
|
||||
}
|
||||
}
|
||||
// Google Flights scraping implementation
|
||||
async scrapeGoogleFlights(params) {
|
||||
try {
|
||||
// Google Flights URL format
|
||||
const googleUrl = `https://www.google.com/travel/flights/search?tfs=CBwQAhoeEgoyMDI1LTA3LTAxagcIARIDTEFYcgcIARIDSkZLQAFIAXABggELCP___________wFAAUgBmAEB&hl=en`;
|
||||
// For now, return null to indicate no real scraping implementation
|
||||
// In production, you would implement actual web scraping here
|
||||
console.log(`Would scrape Google for flight ${params.flightNumber} on ${params.date}`);
|
||||
return null;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Google scraping error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// AviationStack API integration (only if API key available)
|
||||
async getFromAviationStack(params) {
|
||||
const apiKey = process.env.AVIATIONSTACK_API_KEY;
|
||||
console.log('Checking AviationStack API key:', apiKey ? `Key present (${apiKey.length} chars)` : 'No key');
|
||||
if (!apiKey || apiKey === 'demo_key' || apiKey === '') {
|
||||
console.log('No valid AviationStack API key available');
|
||||
return null; // No API key available
|
||||
}
|
||||
try {
|
||||
// Format flight number: Remove spaces and convert to uppercase
|
||||
const formattedFlightNumber = params.flightNumber.replace(/\s+/g, '').toUpperCase();
|
||||
console.log(`Formatted flight number: ${params.flightNumber} -> ${formattedFlightNumber}`);
|
||||
// Note: Free tier doesn't support date filtering, so we get recent flights
|
||||
// For future dates, this won't work well - consider upgrading subscription
|
||||
const url = `http://api.aviationstack.com/v1/flights?access_key=${apiKey}&flight_iata=${formattedFlightNumber}&limit=10`;
|
||||
console.log('AviationStack API URL:', url.replace(apiKey, '***'));
|
||||
console.log('Note: Free tier returns recent flights only, not future scheduled flights');
|
||||
const response = await fetch(url);
|
||||
const data = await response.json();
|
||||
console.log('AviationStack response status:', response.status);
|
||||
if (!response.ok) {
|
||||
console.error('AviationStack API error - HTTP status:', response.status);
|
||||
return null;
|
||||
}
|
||||
// Check for API errors in response
|
||||
if (data.error) {
|
||||
console.error('AviationStack API error:', data.error);
|
||||
return null;
|
||||
}
|
||||
if (data.data && data.data.length > 0) {
|
||||
// This is a valid flight number that exists!
|
||||
console.log(`✅ Valid flight number: ${formattedFlightNumber} exists in the system`);
|
||||
// Try to find a flight matching the requested date
|
||||
let flight = data.data.find((f) => f.flight_date === params.date);
|
||||
// If no exact date match, use most recent for validation
|
||||
if (!flight) {
|
||||
flight = data.data[0];
|
||||
console.log(`ℹ️ Flight ${formattedFlightNumber} is valid`);
|
||||
console.log(`Recent flight: ${flight.departure.airport} → ${flight.arrival.airport}`);
|
||||
console.log(`Operated by: ${flight.airline?.name || 'Unknown'}`);
|
||||
console.log(`Note: Showing recent data from ${flight.flight_date} for validation`);
|
||||
}
|
||||
else {
|
||||
console.log(`✅ Flight found for exact date: ${params.date}`);
|
||||
}
|
||||
console.log('Flight route:', `${flight.departure.iata} → ${flight.arrival.iata}`);
|
||||
console.log('Status:', flight.flight_status);
|
||||
return {
|
||||
flightNumber: flight.flight.iata,
|
||||
flightDate: flight.flight_date,
|
||||
status: this.normalizeStatus(flight.flight_status),
|
||||
airline: flight.airline?.name,
|
||||
aircraft: flight.aircraft?.registration,
|
||||
departure: {
|
||||
airport: flight.departure.iata,
|
||||
airportName: flight.departure.airport,
|
||||
scheduled: flight.departure.scheduled,
|
||||
estimated: flight.departure.estimated,
|
||||
actual: flight.departure.actual,
|
||||
terminal: flight.departure.terminal,
|
||||
gate: flight.departure.gate
|
||||
},
|
||||
arrival: {
|
||||
airport: flight.arrival.iata,
|
||||
airportName: flight.arrival.airport,
|
||||
scheduled: flight.arrival.scheduled,
|
||||
estimated: flight.arrival.estimated,
|
||||
actual: flight.arrival.actual,
|
||||
terminal: flight.arrival.terminal,
|
||||
gate: flight.arrival.gate
|
||||
},
|
||||
delay: flight.departure.delay || 0,
|
||||
lastUpdated: new Date().toISOString(),
|
||||
source: 'aviationstack'
|
||||
};
|
||||
}
|
||||
console.log(`❌ Invalid flight number: ${formattedFlightNumber} not found`);
|
||||
console.log('This flight number does not exist or has not operated recently');
|
||||
return null;
|
||||
}
|
||||
catch (error) {
|
||||
console.error('AviationStack API error:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Start periodic updates for a flight
|
||||
startPeriodicUpdates(params, intervalMinutes = 5) {
|
||||
const key = `${params.flightNumber}_${params.date}`;
|
||||
// Clear existing interval if any
|
||||
this.stopPeriodicUpdates(key);
|
||||
// Set up new interval
|
||||
const interval = setInterval(async () => {
|
||||
try {
|
||||
await this.getFlightInfo(params); // This will update the cache
|
||||
console.log(`Updated flight data for ${params.flightNumber} on ${params.date}`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Error updating flight ${params.flightNumber}:`, error);
|
||||
}
|
||||
}, intervalMinutes * 60 * 1000);
|
||||
this.updateIntervals.set(key, interval);
|
||||
}
|
||||
// Stop periodic updates for a flight
|
||||
stopPeriodicUpdates(key) {
|
||||
const interval = this.updateIntervals.get(key);
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
this.updateIntervals.delete(key);
|
||||
}
|
||||
}
|
||||
// Get multiple flights with date specificity
|
||||
async getMultipleFlights(flightParams) {
|
||||
const results = {};
|
||||
for (const params of flightParams) {
|
||||
const key = `${params.flightNumber}_${params.date}`;
|
||||
results[key] = await this.getFlightInfo(params);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
// Normalize flight status across different APIs
|
||||
normalizeStatus(status) {
|
||||
const statusMap = {
|
||||
'scheduled': 'scheduled',
|
||||
'active': 'active',
|
||||
'landed': 'landed',
|
||||
'cancelled': 'cancelled',
|
||||
'incident': 'delayed',
|
||||
'diverted': 'diverted'
|
||||
};
|
||||
return statusMap[status.toLowerCase()] || status;
|
||||
}
|
||||
// Clean up resources
|
||||
cleanup() {
|
||||
for (const [key, interval] of this.updateIntervals) {
|
||||
clearInterval(interval);
|
||||
}
|
||||
this.updateIntervals.clear();
|
||||
this.flightCache.clear();
|
||||
}
|
||||
}
|
||||
exports.default = new FlightService();
|
||||
//# sourceMappingURL=flightService.js.map
|
||||
1
backend-old-20260125/dist/services/flightService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/flightService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
16
backend-old-20260125/dist/services/flightTrackingScheduler.d.ts
vendored
Normal file
16
backend-old-20260125/dist/services/flightTrackingScheduler.d.ts
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
declare class FlightTrackingScheduler {
|
||||
private trackingSchedule;
|
||||
private checkIntervals;
|
||||
private flightService;
|
||||
constructor(flightService: any);
|
||||
addVipFlights(vipId: string, vipName: string, flights: any[]): void;
|
||||
removeVipFlights(vipId: string): void;
|
||||
private updateTrackingSchedules;
|
||||
private setupDateTracking;
|
||||
private performBatchCheck;
|
||||
private stopDateTracking;
|
||||
getTrackingStatus(): any;
|
||||
cleanup(): void;
|
||||
}
|
||||
export default FlightTrackingScheduler;
|
||||
//# sourceMappingURL=flightTrackingScheduler.d.ts.map
|
||||
1
backend-old-20260125/dist/services/flightTrackingScheduler.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/flightTrackingScheduler.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"flightTrackingScheduler.d.ts","sourceRoot":"","sources":["../../src/services/flightTrackingScheduler.ts"],"names":[],"mappings":"AAoBA,cAAM,uBAAuB;IAC3B,OAAO,CAAC,gBAAgB,CAAwB;IAChD,OAAO,CAAC,cAAc,CAA0C;IAChE,OAAO,CAAC,aAAa,CAAM;gBAEf,aAAa,EAAE,GAAG;IAK9B,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE;IAoC5D,gBAAgB,CAAC,KAAK,EAAE,MAAM;IAgB9B,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,iBAAiB;YAsDX,iBAAiB;IAwF/B,OAAO,CAAC,gBAAgB;IAcxB,iBAAiB,IAAI,GAAG;IA0BxB,OAAO;CAKR;AAED,eAAe,uBAAuB,CAAC"}
|
||||
219
backend-old-20260125/dist/services/flightTrackingScheduler.js
vendored
Normal file
219
backend-old-20260125/dist/services/flightTrackingScheduler.js
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
"use strict";
|
||||
// Flight Tracking Scheduler Service
|
||||
// Efficiently batches flight API calls and manages tracking schedules
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class FlightTrackingScheduler {
|
||||
constructor(flightService) {
|
||||
this.trackingSchedule = {};
|
||||
this.checkIntervals = new Map();
|
||||
this.flightService = flightService;
|
||||
}
|
||||
// Add flights for a VIP to the tracking schedule
|
||||
addVipFlights(vipId, vipName, flights) {
|
||||
flights.forEach(flight => {
|
||||
const key = flight.flightDate;
|
||||
if (!this.trackingSchedule[key]) {
|
||||
this.trackingSchedule[key] = [];
|
||||
}
|
||||
// Check if this flight is already being tracked
|
||||
const existingIndex = this.trackingSchedule[key].findIndex(f => f.flightNumber === flight.flightNumber && f.vipId === vipId);
|
||||
const scheduledFlight = {
|
||||
vipId,
|
||||
vipName,
|
||||
flightNumber: flight.flightNumber,
|
||||
flightDate: flight.flightDate,
|
||||
segment: flight.segment,
|
||||
scheduledDeparture: flight.validationData?.departure?.scheduled
|
||||
};
|
||||
if (existingIndex >= 0) {
|
||||
// Update existing entry
|
||||
this.trackingSchedule[key][existingIndex] = scheduledFlight;
|
||||
}
|
||||
else {
|
||||
// Add new entry
|
||||
this.trackingSchedule[key].push(scheduledFlight);
|
||||
}
|
||||
});
|
||||
// Start or update tracking for affected dates
|
||||
this.updateTrackingSchedules();
|
||||
}
|
||||
// Remove VIP flights from tracking
|
||||
removeVipFlights(vipId) {
|
||||
Object.keys(this.trackingSchedule).forEach(date => {
|
||||
this.trackingSchedule[date] = this.trackingSchedule[date].filter(f => f.vipId !== vipId);
|
||||
// Remove empty dates
|
||||
if (this.trackingSchedule[date].length === 0) {
|
||||
delete this.trackingSchedule[date];
|
||||
}
|
||||
});
|
||||
this.updateTrackingSchedules();
|
||||
}
|
||||
// Update tracking schedules based on current flights
|
||||
updateTrackingSchedules() {
|
||||
// Clear existing intervals
|
||||
this.checkIntervals.forEach(interval => clearInterval(interval));
|
||||
this.checkIntervals.clear();
|
||||
// Set up tracking for each date
|
||||
Object.keys(this.trackingSchedule).forEach(date => {
|
||||
this.setupDateTracking(date);
|
||||
});
|
||||
}
|
||||
// Set up tracking for a specific date
|
||||
setupDateTracking(date) {
|
||||
const flights = this.trackingSchedule[date];
|
||||
if (!flights || flights.length === 0)
|
||||
return;
|
||||
// Check if we should start tracking (4 hours before first flight)
|
||||
const now = new Date();
|
||||
const dateObj = new Date(date + 'T00:00:00');
|
||||
// Find earliest departure time
|
||||
let earliestDeparture = null;
|
||||
flights.forEach(flight => {
|
||||
if (flight.scheduledDeparture) {
|
||||
const depTime = new Date(flight.scheduledDeparture);
|
||||
if (!earliestDeparture || depTime < earliestDeparture) {
|
||||
earliestDeparture = depTime;
|
||||
}
|
||||
}
|
||||
});
|
||||
// If no departure times, assume noon
|
||||
if (!earliestDeparture) {
|
||||
earliestDeparture = new Date(date + 'T12:00:00');
|
||||
}
|
||||
// Start tracking 4 hours before earliest departure
|
||||
const trackingStartTime = new Date(earliestDeparture.getTime() - 4 * 60 * 60 * 1000);
|
||||
// If tracking should have started, begin immediately
|
||||
if (now >= trackingStartTime) {
|
||||
this.performBatchCheck(date);
|
||||
// Set up recurring checks every 60 minutes (or 30 if any delays)
|
||||
const interval = setInterval(() => {
|
||||
this.performBatchCheck(date);
|
||||
}, 60 * 60 * 1000); // 60 minutes
|
||||
this.checkIntervals.set(date, interval);
|
||||
}
|
||||
else {
|
||||
// Schedule first check for tracking start time
|
||||
const timeUntilStart = trackingStartTime.getTime() - now.getTime();
|
||||
setTimeout(() => {
|
||||
this.performBatchCheck(date);
|
||||
// Then set up recurring checks
|
||||
const interval = setInterval(() => {
|
||||
this.performBatchCheck(date);
|
||||
}, 60 * 60 * 1000);
|
||||
this.checkIntervals.set(date, interval);
|
||||
}, timeUntilStart);
|
||||
}
|
||||
}
|
||||
// Perform batch check for all flights on a date
|
||||
async performBatchCheck(date) {
|
||||
const flights = this.trackingSchedule[date];
|
||||
if (!flights || flights.length === 0)
|
||||
return;
|
||||
console.log(`\n=== Batch Flight Check for ${date} ===`);
|
||||
console.log(`Checking ${flights.length} flights...`);
|
||||
// Filter out flights that have already landed
|
||||
const activeFlights = flights.filter(f => !f.hasLanded);
|
||||
if (activeFlights.length === 0) {
|
||||
console.log('All flights have landed. Stopping tracking for this date.');
|
||||
this.stopDateTracking(date);
|
||||
return;
|
||||
}
|
||||
// Get unique flight numbers to check
|
||||
const uniqueFlights = Array.from(new Set(activeFlights.map(f => f.flightNumber)));
|
||||
console.log(`Unique flight numbers to check: ${uniqueFlights.join(', ')}`);
|
||||
try {
|
||||
// Make batch API call
|
||||
const flightParams = uniqueFlights.map(flightNumber => ({
|
||||
flightNumber,
|
||||
date
|
||||
}));
|
||||
const results = await this.flightService.getMultipleFlights(flightParams);
|
||||
// Update flight statuses
|
||||
let hasDelays = false;
|
||||
let allLanded = true;
|
||||
activeFlights.forEach(flight => {
|
||||
const key = `${flight.flightNumber}_${date}`;
|
||||
const data = results[key];
|
||||
if (data) {
|
||||
flight.lastChecked = new Date();
|
||||
flight.status = data.status;
|
||||
if (data.status === 'landed') {
|
||||
flight.hasLanded = true;
|
||||
console.log(`✅ ${flight.flightNumber} has landed`);
|
||||
}
|
||||
else {
|
||||
allLanded = false;
|
||||
if (data.delay && data.delay > 0) {
|
||||
hasDelays = true;
|
||||
console.log(`⚠️ ${flight.flightNumber} is delayed by ${data.delay} minutes`);
|
||||
}
|
||||
}
|
||||
// Log status for each VIP
|
||||
console.log(` VIP: ${flight.vipName} - Flight ${flight.segment}: ${flight.flightNumber} - Status: ${data.status}`);
|
||||
}
|
||||
});
|
||||
// Update check frequency if delays detected
|
||||
if (hasDelays && this.checkIntervals.has(date)) {
|
||||
console.log('Delays detected - increasing check frequency to 30 minutes');
|
||||
clearInterval(this.checkIntervals.get(date));
|
||||
const interval = setInterval(() => {
|
||||
this.performBatchCheck(date);
|
||||
}, 30 * 60 * 1000); // 30 minutes
|
||||
this.checkIntervals.set(date, interval);
|
||||
}
|
||||
// Stop tracking if all flights have landed
|
||||
if (allLanded) {
|
||||
console.log('All flights have landed. Stopping tracking for this date.');
|
||||
this.stopDateTracking(date);
|
||||
}
|
||||
// Calculate next check time
|
||||
const nextCheckTime = new Date(Date.now() + (hasDelays ? 30 : 60) * 60 * 1000);
|
||||
console.log(`Next check scheduled for: ${nextCheckTime.toLocaleTimeString()}`);
|
||||
}
|
||||
catch (error) {
|
||||
console.error('Error performing batch flight check:', error);
|
||||
}
|
||||
}
|
||||
// Stop tracking for a specific date
|
||||
stopDateTracking(date) {
|
||||
const interval = this.checkIntervals.get(date);
|
||||
if (interval) {
|
||||
clearInterval(interval);
|
||||
this.checkIntervals.delete(date);
|
||||
}
|
||||
// Mark all flights as completed
|
||||
if (this.trackingSchedule[date]) {
|
||||
this.trackingSchedule[date].forEach(f => f.hasLanded = true);
|
||||
}
|
||||
}
|
||||
// Get current tracking status
|
||||
getTrackingStatus() {
|
||||
const status = {};
|
||||
Object.entries(this.trackingSchedule).forEach(([date, flights]) => {
|
||||
const activeFlights = flights.filter(f => !f.hasLanded);
|
||||
const landedFlights = flights.filter(f => f.hasLanded);
|
||||
status[date] = {
|
||||
totalFlights: flights.length,
|
||||
activeFlights: activeFlights.length,
|
||||
landedFlights: landedFlights.length,
|
||||
flights: flights.map(f => ({
|
||||
vipName: f.vipName,
|
||||
flightNumber: f.flightNumber,
|
||||
segment: f.segment,
|
||||
status: f.status || 'Not checked yet',
|
||||
lastChecked: f.lastChecked,
|
||||
hasLanded: f.hasLanded
|
||||
}))
|
||||
};
|
||||
});
|
||||
return status;
|
||||
}
|
||||
// Clean up all tracking
|
||||
cleanup() {
|
||||
this.checkIntervals.forEach(interval => clearInterval(interval));
|
||||
this.checkIntervals.clear();
|
||||
this.trackingSchedule = {};
|
||||
}
|
||||
}
|
||||
exports.default = FlightTrackingScheduler;
|
||||
//# sourceMappingURL=flightTrackingScheduler.js.map
|
||||
1
backend-old-20260125/dist/services/flightTrackingScheduler.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/flightTrackingScheduler.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
38
backend-old-20260125/dist/services/jwtKeyManager.d.ts
vendored
Normal file
38
backend-old-20260125/dist/services/jwtKeyManager.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
export interface User {
|
||||
id: string;
|
||||
google_id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
profile_picture_url?: string;
|
||||
role: 'driver' | 'coordinator' | 'administrator';
|
||||
status?: 'pending' | 'active' | 'deactivated';
|
||||
created_at?: string;
|
||||
last_login?: string;
|
||||
is_active?: boolean;
|
||||
updated_at?: string;
|
||||
approval_status?: string;
|
||||
onboardingData?: any;
|
||||
}
|
||||
declare class JWTKeyManager {
|
||||
private currentSecret;
|
||||
private previousSecret;
|
||||
private rotationInterval;
|
||||
private gracePeriodTimeout;
|
||||
constructor();
|
||||
private generateSecret;
|
||||
private startRotation;
|
||||
private rotateKey;
|
||||
generateToken(user: User): string;
|
||||
verifyToken(token: string): User | null;
|
||||
getStatus(): {
|
||||
hasCurrentKey: boolean;
|
||||
hasPreviousKey: boolean;
|
||||
rotationActive: boolean;
|
||||
gracePeriodActive: boolean;
|
||||
};
|
||||
destroy(): void;
|
||||
forceRotation(): void;
|
||||
}
|
||||
export declare const jwtKeyManager: JWTKeyManager;
|
||||
export default jwtKeyManager;
|
||||
//# sourceMappingURL=jwtKeyManager.d.ts.map
|
||||
1
backend-old-20260125/dist/services/jwtKeyManager.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/jwtKeyManager.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jwtKeyManager.d.ts","sourceRoot":"","sources":["../../src/services/jwtKeyManager.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,IAAI,EAAE,QAAQ,GAAG,aAAa,GAAG,eAAe,CAAC;IACjD,MAAM,CAAC,EAAE,SAAS,GAAG,QAAQ,GAAG,aAAa,CAAC;IAC9C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,GAAG,CAAC;CACtB;AAED,cAAM,aAAa;IACjB,OAAO,CAAC,aAAa,CAAS;IAC9B,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,kBAAkB,CAA+B;;IAQzD,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,SAAS;IAuBjB,aAAa,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAqBjC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAqDvC,SAAS;;;;;;IAUT,OAAO;IAiBP,aAAa;CAId;AAGD,eAAO,MAAM,aAAa,eAAsB,CAAC;AAWjD,eAAe,aAAa,CAAC"}
|
||||
158
backend-old-20260125/dist/services/jwtKeyManager.js
vendored
Normal file
158
backend-old-20260125/dist/services/jwtKeyManager.js
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.jwtKeyManager = void 0;
|
||||
const crypto_1 = __importDefault(require("crypto"));
|
||||
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
||||
class JWTKeyManager {
|
||||
constructor() {
|
||||
this.previousSecret = null;
|
||||
this.rotationInterval = null;
|
||||
this.gracePeriodTimeout = null;
|
||||
console.log('🔑 Initializing JWT Key Manager with automatic rotation');
|
||||
this.currentSecret = this.generateSecret();
|
||||
this.startRotation();
|
||||
}
|
||||
generateSecret() {
|
||||
const secret = crypto_1.default.randomBytes(64).toString('hex');
|
||||
console.log('🔄 Generated new JWT signing key (length:', secret.length, 'chars)');
|
||||
return secret;
|
||||
}
|
||||
startRotation() {
|
||||
// Rotate every 24 hours (86400000 ms)
|
||||
this.rotationInterval = setInterval(() => {
|
||||
this.rotateKey();
|
||||
}, 24 * 60 * 60 * 1000);
|
||||
console.log('⏰ JWT key rotation scheduled every 24 hours');
|
||||
// Also rotate on startup after 1 hour to test the system
|
||||
setTimeout(() => {
|
||||
console.log('🧪 Performing initial key rotation test...');
|
||||
this.rotateKey();
|
||||
}, 60 * 60 * 1000); // 1 hour
|
||||
}
|
||||
rotateKey() {
|
||||
console.log('🔄 Rotating JWT signing key...');
|
||||
// Store current secret as previous
|
||||
this.previousSecret = this.currentSecret;
|
||||
// Generate new current secret
|
||||
this.currentSecret = this.generateSecret();
|
||||
console.log('✅ JWT key rotation completed. Grace period: 24 hours');
|
||||
// Clear any existing grace period timeout
|
||||
if (this.gracePeriodTimeout) {
|
||||
clearTimeout(this.gracePeriodTimeout);
|
||||
}
|
||||
// Clean up previous secret after 24 hours (grace period)
|
||||
this.gracePeriodTimeout = setTimeout(() => {
|
||||
this.previousSecret = null;
|
||||
console.log('🧹 Grace period ended. Previous JWT key cleaned up');
|
||||
}, 24 * 60 * 60 * 1000);
|
||||
}
|
||||
generateToken(user) {
|
||||
const payload = {
|
||||
id: user.id,
|
||||
google_id: user.google_id,
|
||||
email: user.email,
|
||||
name: user.name,
|
||||
profile_picture_url: user.profile_picture_url,
|
||||
role: user.role,
|
||||
status: user.status,
|
||||
approval_status: user.approval_status,
|
||||
onboardingData: user.onboardingData,
|
||||
iat: Math.floor(Date.now() / 1000) // Issued at time
|
||||
};
|
||||
return jsonwebtoken_1.default.sign(payload, this.currentSecret, {
|
||||
expiresIn: '24h',
|
||||
issuer: 'vip-coordinator',
|
||||
audience: 'vip-coordinator-users'
|
||||
});
|
||||
}
|
||||
verifyToken(token) {
|
||||
try {
|
||||
// Try current secret first
|
||||
const decoded = jsonwebtoken_1.default.verify(token, this.currentSecret, {
|
||||
issuer: 'vip-coordinator',
|
||||
audience: 'vip-coordinator-users'
|
||||
});
|
||||
return {
|
||||
id: decoded.id,
|
||||
google_id: decoded.google_id,
|
||||
email: decoded.email,
|
||||
name: decoded.name,
|
||||
profile_picture_url: decoded.profile_picture_url,
|
||||
role: decoded.role,
|
||||
status: decoded.status,
|
||||
approval_status: decoded.approval_status,
|
||||
onboardingData: decoded.onboardingData
|
||||
};
|
||||
}
|
||||
catch (error) {
|
||||
// Try previous secret during grace period
|
||||
if (this.previousSecret) {
|
||||
try {
|
||||
const decoded = jsonwebtoken_1.default.verify(token, this.previousSecret, {
|
||||
issuer: 'vip-coordinator',
|
||||
audience: 'vip-coordinator-users'
|
||||
});
|
||||
console.log('🔄 Token verified using previous key (grace period)');
|
||||
return {
|
||||
id: decoded.id,
|
||||
google_id: decoded.google_id,
|
||||
email: decoded.email,
|
||||
name: decoded.name,
|
||||
profile_picture_url: decoded.profile_picture_url,
|
||||
role: decoded.role,
|
||||
status: decoded.status,
|
||||
approval_status: decoded.approval_status,
|
||||
onboardingData: decoded.onboardingData
|
||||
};
|
||||
}
|
||||
catch (gracePeriodError) {
|
||||
console.log('❌ Token verification failed with both current and previous keys');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
console.log('❌ Token verification failed:', error instanceof Error ? error.message : 'Unknown error');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// Get status for monitoring/debugging
|
||||
getStatus() {
|
||||
return {
|
||||
hasCurrentKey: !!this.currentSecret,
|
||||
hasPreviousKey: !!this.previousSecret,
|
||||
rotationActive: !!this.rotationInterval,
|
||||
gracePeriodActive: !!this.gracePeriodTimeout
|
||||
};
|
||||
}
|
||||
// Cleanup on shutdown
|
||||
destroy() {
|
||||
console.log('🛑 Shutting down JWT Key Manager...');
|
||||
if (this.rotationInterval) {
|
||||
clearInterval(this.rotationInterval);
|
||||
this.rotationInterval = null;
|
||||
}
|
||||
if (this.gracePeriodTimeout) {
|
||||
clearTimeout(this.gracePeriodTimeout);
|
||||
this.gracePeriodTimeout = null;
|
||||
}
|
||||
console.log('✅ JWT Key Manager shutdown complete');
|
||||
}
|
||||
// Manual rotation for testing/emergency
|
||||
forceRotation() {
|
||||
console.log('🚨 Manual key rotation triggered');
|
||||
this.rotateKey();
|
||||
}
|
||||
}
|
||||
// Singleton instance
|
||||
exports.jwtKeyManager = new JWTKeyManager();
|
||||
// Graceful shutdown handling
|
||||
process.on('SIGTERM', () => {
|
||||
exports.jwtKeyManager.destroy();
|
||||
});
|
||||
process.on('SIGINT', () => {
|
||||
exports.jwtKeyManager.destroy();
|
||||
});
|
||||
exports.default = exports.jwtKeyManager;
|
||||
//# sourceMappingURL=jwtKeyManager.js.map
|
||||
1
backend-old-20260125/dist/services/jwtKeyManager.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/jwtKeyManager.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"jwtKeyManager.js","sourceRoot":"","sources":["../../src/services/jwtKeyManager.ts"],"names":[],"mappings":"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"}
|
||||
30
backend-old-20260125/dist/services/scheduleValidationService.d.ts
vendored
Normal file
30
backend-old-20260125/dist/services/scheduleValidationService.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
interface ValidationError {
|
||||
field: string;
|
||||
message: string;
|
||||
code: string;
|
||||
}
|
||||
interface ScheduleEvent {
|
||||
title: string;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
location: string;
|
||||
type: string;
|
||||
}
|
||||
declare class ScheduleValidationService {
|
||||
validateEvent(event: ScheduleEvent, isEdit?: boolean): ValidationError[];
|
||||
validateEventSequence(events: ScheduleEvent[]): ValidationError[];
|
||||
getErrorSummary(errors: ValidationError[]): string;
|
||||
isCriticalError(error: ValidationError): boolean;
|
||||
categorizeErrors(errors: ValidationError[]): {
|
||||
critical: ValidationError[];
|
||||
warnings: ValidationError[];
|
||||
};
|
||||
validateTimeFormat(timeString: string): {
|
||||
isValid: boolean;
|
||||
suggestion?: string;
|
||||
};
|
||||
}
|
||||
declare const _default: ScheduleValidationService;
|
||||
export default _default;
|
||||
export { ValidationError, ScheduleEvent };
|
||||
//# sourceMappingURL=scheduleValidationService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/scheduleValidationService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/scheduleValidationService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"scheduleValidationService.d.ts","sourceRoot":"","sources":["../../src/services/scheduleValidationService.ts"],"names":[],"mappings":"AAAA,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,cAAM,yBAAyB;IAG7B,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,MAAM,GAAE,OAAe,GAAG,eAAe,EAAE;IAuJ/E,qBAAqB,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,eAAe,EAAE;IA6BjE,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM;IAalD,eAAe,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO;IAMhD,gBAAgB,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG;QAAE,QAAQ,EAAE,eAAe,EAAE,CAAC;QAAC,QAAQ,EAAE,eAAe,EAAE,CAAA;KAAE;IAgBzG,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;CAYlF;;AAED,wBAA+C;AAC/C,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,CAAC"}
|
||||
200
backend-old-20260125/dist/services/scheduleValidationService.js
vendored
Normal file
200
backend-old-20260125/dist/services/scheduleValidationService.js
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
class ScheduleValidationService {
|
||||
// Validate a single schedule event
|
||||
validateEvent(event, isEdit = false) {
|
||||
const errors = [];
|
||||
const now = new Date();
|
||||
const startTime = new Date(event.startTime);
|
||||
const endTime = new Date(event.endTime);
|
||||
// 1. Check if dates are valid
|
||||
if (isNaN(startTime.getTime())) {
|
||||
errors.push({
|
||||
field: 'startTime',
|
||||
message: 'Start time is not a valid date',
|
||||
code: 'INVALID_START_DATE'
|
||||
});
|
||||
}
|
||||
if (isNaN(endTime.getTime())) {
|
||||
errors.push({
|
||||
field: 'endTime',
|
||||
message: 'End time is not a valid date',
|
||||
code: 'INVALID_END_DATE'
|
||||
});
|
||||
}
|
||||
// If dates are invalid, return early
|
||||
if (errors.length > 0) {
|
||||
return errors;
|
||||
}
|
||||
// 2. Check if start time is in the future (with 5-minute grace period for edits)
|
||||
const graceMinutes = isEdit ? 5 : 0;
|
||||
const minimumStartTime = new Date(now.getTime() + (graceMinutes * 60 * 1000));
|
||||
if (startTime < minimumStartTime) {
|
||||
errors.push({
|
||||
field: 'startTime',
|
||||
message: isEdit
|
||||
? 'Start time must be at least 5 minutes in the future for edits'
|
||||
: 'Start time must be in the future',
|
||||
code: 'START_TIME_IN_PAST'
|
||||
});
|
||||
}
|
||||
// 3. Check if end time is after start time
|
||||
if (endTime <= startTime) {
|
||||
errors.push({
|
||||
field: 'endTime',
|
||||
message: 'End time must be after start time',
|
||||
code: 'END_BEFORE_START'
|
||||
});
|
||||
}
|
||||
// 4. Check minimum event duration (5 minutes)
|
||||
const durationMinutes = (endTime.getTime() - startTime.getTime()) / (1000 * 60);
|
||||
if (durationMinutes < 5) {
|
||||
errors.push({
|
||||
field: 'endTime',
|
||||
message: 'Event must be at least 5 minutes long',
|
||||
code: 'DURATION_TOO_SHORT'
|
||||
});
|
||||
}
|
||||
// 5. Check maximum event duration (24 hours)
|
||||
if (durationMinutes > (24 * 60)) {
|
||||
errors.push({
|
||||
field: 'endTime',
|
||||
message: 'Event cannot be longer than 24 hours',
|
||||
code: 'DURATION_TOO_LONG'
|
||||
});
|
||||
}
|
||||
// 6. Check if end time is in the future
|
||||
if (endTime < now) {
|
||||
errors.push({
|
||||
field: 'endTime',
|
||||
message: 'End time must be in the future',
|
||||
code: 'END_TIME_IN_PAST'
|
||||
});
|
||||
}
|
||||
// 7. Validate required fields
|
||||
if (!event.title || event.title.trim().length === 0) {
|
||||
errors.push({
|
||||
field: 'title',
|
||||
message: 'Event title is required',
|
||||
code: 'TITLE_REQUIRED'
|
||||
});
|
||||
}
|
||||
if (!event.location || event.location.trim().length === 0) {
|
||||
errors.push({
|
||||
field: 'location',
|
||||
message: 'Event location is required',
|
||||
code: 'LOCATION_REQUIRED'
|
||||
});
|
||||
}
|
||||
if (!event.type || event.type.trim().length === 0) {
|
||||
errors.push({
|
||||
field: 'type',
|
||||
message: 'Event type is required',
|
||||
code: 'TYPE_REQUIRED'
|
||||
});
|
||||
}
|
||||
// 8. Validate title length
|
||||
if (event.title && event.title.length > 100) {
|
||||
errors.push({
|
||||
field: 'title',
|
||||
message: 'Event title cannot exceed 100 characters',
|
||||
code: 'TITLE_TOO_LONG'
|
||||
});
|
||||
}
|
||||
// 9. Validate location length
|
||||
if (event.location && event.location.length > 200) {
|
||||
errors.push({
|
||||
field: 'location',
|
||||
message: 'Event location cannot exceed 200 characters',
|
||||
code: 'LOCATION_TOO_LONG'
|
||||
});
|
||||
}
|
||||
// 10. Check for reasonable scheduling (not more than 2 years in the future)
|
||||
const twoYearsFromNow = new Date();
|
||||
twoYearsFromNow.setFullYear(twoYearsFromNow.getFullYear() + 2);
|
||||
if (startTime > twoYearsFromNow) {
|
||||
errors.push({
|
||||
field: 'startTime',
|
||||
message: 'Event cannot be scheduled more than 2 years in the future',
|
||||
code: 'START_TIME_TOO_FAR'
|
||||
});
|
||||
}
|
||||
// 11. Check for business hours validation (optional warning)
|
||||
const startHour = startTime.getHours();
|
||||
const endHour = endTime.getHours();
|
||||
if (startHour < 6 || startHour > 23) {
|
||||
// This is a warning, not an error - we'll add it but with a different severity
|
||||
errors.push({
|
||||
field: 'startTime',
|
||||
message: 'Event starts outside typical business hours (6 AM - 11 PM)',
|
||||
code: 'OUTSIDE_BUSINESS_HOURS'
|
||||
});
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
// Validate multiple events for conflicts and logical sequencing
|
||||
validateEventSequence(events) {
|
||||
const errors = [];
|
||||
// Sort events by start time
|
||||
const sortedEvents = events
|
||||
.map((event, index) => ({ ...event, originalIndex: index }))
|
||||
.sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime());
|
||||
// Check for overlapping events
|
||||
for (let i = 0; i < sortedEvents.length - 1; i++) {
|
||||
const currentEvent = sortedEvents[i];
|
||||
const nextEvent = sortedEvents[i + 1];
|
||||
const currentEnd = new Date(currentEvent.endTime);
|
||||
const nextStart = new Date(nextEvent.startTime);
|
||||
if (currentEnd > nextStart) {
|
||||
errors.push({
|
||||
field: 'schedule',
|
||||
message: `Event "${currentEvent.title}" overlaps with "${nextEvent.title}"`,
|
||||
code: 'EVENTS_OVERLAP'
|
||||
});
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
// Get user-friendly error messages
|
||||
getErrorSummary(errors) {
|
||||
if (errors.length === 0)
|
||||
return '';
|
||||
const errorMessages = errors.map(error => error.message);
|
||||
if (errors.length === 1) {
|
||||
return errorMessages[0];
|
||||
}
|
||||
return `Multiple validation errors:\n• ${errorMessages.join('\n• ')}`;
|
||||
}
|
||||
// Check if errors are warnings vs critical errors
|
||||
isCriticalError(error) {
|
||||
const warningCodes = ['OUTSIDE_BUSINESS_HOURS'];
|
||||
return !warningCodes.includes(error.code);
|
||||
}
|
||||
// Separate critical errors from warnings
|
||||
categorizeErrors(errors) {
|
||||
const critical = [];
|
||||
const warnings = [];
|
||||
errors.forEach(error => {
|
||||
if (this.isCriticalError(error)) {
|
||||
critical.push(error);
|
||||
}
|
||||
else {
|
||||
warnings.push(error);
|
||||
}
|
||||
});
|
||||
return { critical, warnings };
|
||||
}
|
||||
// Validate time format and suggest corrections
|
||||
validateTimeFormat(timeString) {
|
||||
const date = new Date(timeString);
|
||||
if (isNaN(date.getTime())) {
|
||||
return {
|
||||
isValid: false,
|
||||
suggestion: 'Please use format: YYYY-MM-DDTHH:MM (e.g., 2025-07-01T14:30)'
|
||||
};
|
||||
}
|
||||
return { isValid: true };
|
||||
}
|
||||
}
|
||||
exports.default = new ScheduleValidationService();
|
||||
//# sourceMappingURL=scheduleValidationService.js.map
|
||||
1
backend-old-20260125/dist/services/scheduleValidationService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/scheduleValidationService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
30
backend-old-20260125/dist/services/unifiedDataService.d.ts
vendored
Normal file
30
backend-old-20260125/dist/services/unifiedDataService.d.ts
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
declare class UnifiedDataService {
|
||||
private pool;
|
||||
constructor();
|
||||
private toCamelCase;
|
||||
getVips(): Promise<any>;
|
||||
getVipById(id: string): Promise<any>;
|
||||
createVip(vipData: any): Promise<any>;
|
||||
updateVip(id: string, vipData: any): Promise<any>;
|
||||
deleteVip(id: string): Promise<any>;
|
||||
getDrivers(): Promise<any>;
|
||||
getDriverById(id: string): Promise<any>;
|
||||
createDriver(driverData: any): Promise<any>;
|
||||
updateDriver(id: string, driverData: any): Promise<any>;
|
||||
deleteDriver(id: string): Promise<any>;
|
||||
getScheduleByVipId(vipId: string): Promise<any>;
|
||||
createScheduleEvent(vipId: string, eventData: any): Promise<any>;
|
||||
updateScheduleEvent(id: string, eventData: any): Promise<any>;
|
||||
deleteScheduleEvent(id: string): Promise<any>;
|
||||
getAllSchedules(): Promise<Record<string, any[]>>;
|
||||
getUserByEmail(email: string): Promise<any>;
|
||||
getUserById(id: string): Promise<any>;
|
||||
createUser(userData: any): Promise<any>;
|
||||
updateUserRole(email: string, role: string): Promise<any>;
|
||||
getUserCount(): Promise<number>;
|
||||
getAdminSettings(): Promise<any>;
|
||||
updateAdminSetting(key: string, value: string): Promise<void>;
|
||||
}
|
||||
declare const _default: UnifiedDataService;
|
||||
export default _default;
|
||||
//# sourceMappingURL=unifiedDataService.d.ts.map
|
||||
1
backend-old-20260125/dist/services/unifiedDataService.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/services/unifiedDataService.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"unifiedDataService.d.ts","sourceRoot":"","sources":["../../src/services/unifiedDataService.ts"],"names":[],"mappings":"AAIA,cAAM,kBAAkB;IACtB,OAAO,CAAC,IAAI,CAAO;;IAOnB,OAAO,CAAC,WAAW;IAab,OAAO;IAwBP,UAAU,CAAC,EAAE,EAAE,MAAM;IAwBrB,SAAS,CAAC,OAAO,EAAE,GAAG;IA2CtB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG;IAkDlC,SAAS,CAAC,EAAE,EAAE,MAAM;IASpB,UAAU;IAOV,aAAa,CAAC,EAAE,EAAE,MAAM;IAQxB,YAAY,CAAC,UAAU,EAAE,GAAG;IAa5B,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG;IAcxC,YAAY,CAAC,EAAE,EAAE,MAAM;IASvB,kBAAkB,CAAC,KAAK,EAAE,MAAM;IAYhC,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;IAajD,mBAAmB,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG;IAe9C,mBAAmB,CAAC,EAAE,EAAE,MAAM;IAQ9B,eAAe;IAuBf,cAAc,CAAC,KAAK,EAAE,MAAM;IAQ5B,WAAW,CAAC,EAAE,EAAE,MAAM;IAQtB,UAAU,CAAC,QAAQ,EAAE,GAAG;IAaxB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAW1C,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC;IAM/B,gBAAgB;IAWhB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM;CAQpD;;AAED,wBAAwC"}
|
||||
264
backend-old-20260125/dist/services/unifiedDataService.js
vendored
Normal file
264
backend-old-20260125/dist/services/unifiedDataService.js
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const database_1 = __importDefault(require("../config/database"));
|
||||
// Simplified, unified data service that replaces the three redundant services
|
||||
class UnifiedDataService {
|
||||
constructor() {
|
||||
this.pool = database_1.default;
|
||||
}
|
||||
// Helper to convert snake_case to camelCase
|
||||
toCamelCase(obj) {
|
||||
if (!obj)
|
||||
return obj;
|
||||
if (Array.isArray(obj))
|
||||
return obj.map(item => this.toCamelCase(item));
|
||||
if (typeof obj !== 'object')
|
||||
return obj;
|
||||
return Object.keys(obj).reduce((result, key) => {
|
||||
const camelKey = key.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
||||
result[camelKey] = this.toCamelCase(obj[key]);
|
||||
return result;
|
||||
}, {});
|
||||
}
|
||||
// VIP Operations
|
||||
async getVips() {
|
||||
const query = `
|
||||
SELECT v.*,
|
||||
COALESCE(
|
||||
JSON_AGG(
|
||||
JSON_BUILD_OBJECT(
|
||||
'flightNumber', f.flight_number,
|
||||
'airline', f.airline,
|
||||
'scheduledArrival', f.scheduled_arrival,
|
||||
'scheduledDeparture', f.scheduled_departure,
|
||||
'status', f.status
|
||||
) ORDER BY f.scheduled_arrival
|
||||
) FILTER (WHERE f.id IS NOT NULL),
|
||||
'[]'
|
||||
) as flights
|
||||
FROM vips v
|
||||
LEFT JOIN flights f ON v.id = f.vip_id
|
||||
GROUP BY v.id
|
||||
ORDER BY v.created_at DESC`;
|
||||
const result = await this.pool.query(query);
|
||||
return this.toCamelCase(result.rows);
|
||||
}
|
||||
async getVipById(id) {
|
||||
const query = `
|
||||
SELECT v.*,
|
||||
COALESCE(
|
||||
JSON_AGG(
|
||||
JSON_BUILD_OBJECT(
|
||||
'flightNumber', f.flight_number,
|
||||
'airline', f.airline,
|
||||
'scheduledArrival', f.scheduled_arrival,
|
||||
'scheduledDeparture', f.scheduled_departure,
|
||||
'status', f.status
|
||||
) ORDER BY f.scheduled_arrival
|
||||
) FILTER (WHERE f.id IS NOT NULL),
|
||||
'[]'
|
||||
) as flights
|
||||
FROM vips v
|
||||
LEFT JOIN flights f ON v.id = f.vip_id
|
||||
WHERE v.id = $1
|
||||
GROUP BY v.id`;
|
||||
const result = await this.pool.query(query, [id]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async createVip(vipData) {
|
||||
const { name, organization, department, transportMode, flights, expectedArrival, needsAirportPickup, needsVenueTransport, notes } = vipData;
|
||||
const client = await this.pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
// Insert VIP
|
||||
const vipQuery = `
|
||||
INSERT INTO vips (name, organization, department, transport_mode, expected_arrival,
|
||||
needs_airport_pickup, needs_venue_transport, notes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING *`;
|
||||
const vipResult = await client.query(vipQuery, [
|
||||
name, organization, department || 'Office of Development', transportMode || 'flight',
|
||||
expectedArrival, needsAirportPickup !== false, needsVenueTransport !== false, notes || ''
|
||||
]);
|
||||
const vip = vipResult.rows[0];
|
||||
// Insert flights if any
|
||||
if (transportMode === 'flight' && flights?.length > 0) {
|
||||
for (const flight of flights) {
|
||||
await client.query(`INSERT INTO flights (vip_id, flight_number, airline, scheduled_arrival, scheduled_departure)
|
||||
VALUES ($1, $2, $3, $4, $5)`, [vip.id, flight.flightNumber, flight.airline, flight.scheduledArrival, flight.scheduledDeparture]);
|
||||
}
|
||||
}
|
||||
await client.query('COMMIT');
|
||||
return this.getVipById(vip.id);
|
||||
}
|
||||
catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
async updateVip(id, vipData) {
|
||||
const { name, organization, department, transportMode, flights, expectedArrival, needsAirportPickup, needsVenueTransport, notes } = vipData;
|
||||
const client = await this.pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
// Update VIP
|
||||
const updateQuery = `
|
||||
UPDATE vips
|
||||
SET name = $2, organization = $3, department = $4, transport_mode = $5,
|
||||
expected_arrival = $6, needs_airport_pickup = $7, needs_venue_transport = $8,
|
||||
notes = $9, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING *`;
|
||||
const result = await client.query(updateQuery, [
|
||||
id, name, organization, department, transportMode,
|
||||
expectedArrival, needsAirportPickup, needsVenueTransport, notes
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
await client.query('ROLLBACK');
|
||||
return null;
|
||||
}
|
||||
// Update flights
|
||||
await client.query('DELETE FROM flights WHERE vip_id = $1', [id]);
|
||||
if (transportMode === 'flight' && flights?.length > 0) {
|
||||
for (const flight of flights) {
|
||||
await client.query(`INSERT INTO flights (vip_id, flight_number, airline, scheduled_arrival, scheduled_departure)
|
||||
VALUES ($1, $2, $3, $4, $5)`, [id, flight.flightNumber, flight.airline, flight.scheduledArrival, flight.scheduledDeparture]);
|
||||
}
|
||||
}
|
||||
await client.query('COMMIT');
|
||||
return this.getVipById(id);
|
||||
}
|
||||
catch (error) {
|
||||
await client.query('ROLLBACK');
|
||||
throw error;
|
||||
}
|
||||
finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
async deleteVip(id) {
|
||||
const result = await this.pool.query('DELETE FROM vips WHERE id = $1 RETURNING *', [id]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
// Driver Operations
|
||||
async getDrivers() {
|
||||
const result = await this.pool.query('SELECT * FROM drivers ORDER BY name ASC');
|
||||
return this.toCamelCase(result.rows);
|
||||
}
|
||||
async getDriverById(id) {
|
||||
const result = await this.pool.query('SELECT * FROM drivers WHERE id = $1', [id]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async createDriver(driverData) {
|
||||
const { name, email, phone, vehicleInfo, status } = driverData;
|
||||
const result = await this.pool.query(`INSERT INTO drivers (name, email, phone, vehicle_info, status)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING *`, [name, email, phone, vehicleInfo, status || 'available']);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async updateDriver(id, driverData) {
|
||||
const { name, email, phone, vehicleInfo, status } = driverData;
|
||||
const result = await this.pool.query(`UPDATE drivers
|
||||
SET name = $2, email = $3, phone = $4, vehicle_info = $5, status = $6, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING *`, [id, name, email, phone, vehicleInfo, status]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async deleteDriver(id) {
|
||||
const result = await this.pool.query('DELETE FROM drivers WHERE id = $1 RETURNING *', [id]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
// Schedule Operations
|
||||
async getScheduleByVipId(vipId) {
|
||||
const result = await this.pool.query(`SELECT se.*, d.name as driver_name
|
||||
FROM schedule_events se
|
||||
LEFT JOIN drivers d ON se.driver_id = d.id
|
||||
WHERE se.vip_id = $1
|
||||
ORDER BY se.event_time ASC`, [vipId]);
|
||||
return this.toCamelCase(result.rows);
|
||||
}
|
||||
async createScheduleEvent(vipId, eventData) {
|
||||
const { driverId, eventTime, eventType, location, notes } = eventData;
|
||||
const result = await this.pool.query(`INSERT INTO schedule_events (vip_id, driver_id, event_time, event_type, location, notes)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING *`, [vipId, driverId, eventTime, eventType, location, notes]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async updateScheduleEvent(id, eventData) {
|
||||
const { driverId, eventTime, eventType, location, notes, status } = eventData;
|
||||
const result = await this.pool.query(`UPDATE schedule_events
|
||||
SET driver_id = $2, event_time = $3, event_type = $4, location = $5,
|
||||
notes = $6, status = $7, updated_at = NOW()
|
||||
WHERE id = $1
|
||||
RETURNING *`, [id, driverId, eventTime, eventType, location, notes, status]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async deleteScheduleEvent(id) {
|
||||
const result = await this.pool.query('DELETE FROM schedule_events WHERE id = $1 RETURNING *', [id]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async getAllSchedules() {
|
||||
const result = await this.pool.query(`SELECT se.*, d.name as driver_name, v.name as vip_name
|
||||
FROM schedule_events se
|
||||
LEFT JOIN drivers d ON se.driver_id = d.id
|
||||
LEFT JOIN vips v ON se.vip_id = v.id
|
||||
ORDER BY se.event_time ASC`);
|
||||
// Group by VIP ID
|
||||
const schedules = {};
|
||||
result.rows.forEach((row) => {
|
||||
const event = this.toCamelCase(row);
|
||||
if (!schedules[event.vipId]) {
|
||||
schedules[event.vipId] = [];
|
||||
}
|
||||
schedules[event.vipId].push(event);
|
||||
});
|
||||
return schedules;
|
||||
}
|
||||
// User Operations (simplified)
|
||||
async getUserByEmail(email) {
|
||||
const result = await this.pool.query('SELECT * FROM users WHERE email = $1', [email]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async getUserById(id) {
|
||||
const result = await this.pool.query('SELECT * FROM users WHERE id = $1', [id]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async createUser(userData) {
|
||||
const { email, name, role, department, googleId } = userData;
|
||||
const result = await this.pool.query(`INSERT INTO users (email, name, role, department, google_id)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
RETURNING *`, [email, name, role || 'coordinator', department || 'Office of Development', googleId]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async updateUserRole(email, role) {
|
||||
const result = await this.pool.query(`UPDATE users SET role = $2, updated_at = NOW()
|
||||
WHERE email = $1
|
||||
RETURNING *`, [email, role]);
|
||||
return this.toCamelCase(result.rows[0]);
|
||||
}
|
||||
async getUserCount() {
|
||||
const result = await this.pool.query('SELECT COUNT(*) FROM users');
|
||||
return parseInt(result.rows[0].count, 10);
|
||||
}
|
||||
// Admin Settings (simplified)
|
||||
async getAdminSettings() {
|
||||
const result = await this.pool.query('SELECT key, value FROM admin_settings');
|
||||
return result.rows.reduce((settings, row) => {
|
||||
settings[row.key] = row.value;
|
||||
return settings;
|
||||
}, {});
|
||||
}
|
||||
async updateAdminSetting(key, value) {
|
||||
await this.pool.query(`INSERT INTO admin_settings (key, value)
|
||||
VALUES ($1, $2)
|
||||
ON CONFLICT (key) DO UPDATE SET value = $2, updated_at = NOW()`, [key, value]);
|
||||
}
|
||||
}
|
||||
exports.default = new UnifiedDataService();
|
||||
//# sourceMappingURL=unifiedDataService.js.map
|
||||
1
backend-old-20260125/dist/services/unifiedDataService.js.map
vendored
Normal file
1
backend-old-20260125/dist/services/unifiedDataService.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
69
backend-old-20260125/dist/types/api.d.ts
vendored
Normal file
69
backend-old-20260125/dist/types/api.d.ts
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
export interface SuccessResponse<T = any> {
|
||||
success: true;
|
||||
data: T;
|
||||
message?: string;
|
||||
timestamp: string;
|
||||
}
|
||||
export interface PaginatedResponse<T = any> {
|
||||
success: true;
|
||||
data: T[];
|
||||
pagination: {
|
||||
page: number;
|
||||
limit: number;
|
||||
total: number;
|
||||
totalPages: number;
|
||||
};
|
||||
timestamp: string;
|
||||
}
|
||||
export interface User {
|
||||
id: string;
|
||||
email: string;
|
||||
name: string;
|
||||
role: 'admin' | 'coordinator' | 'driver';
|
||||
department?: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
export interface VIP {
|
||||
id: string;
|
||||
name: string;
|
||||
email?: string;
|
||||
phone?: string;
|
||||
arrivalMode: 'flight' | 'driving';
|
||||
flightNumber?: string;
|
||||
arrivalTime?: Date;
|
||||
departureTime?: Date;
|
||||
notes?: string;
|
||||
status: 'pending' | 'confirmed' | 'completed' | 'cancelled';
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
export interface Driver {
|
||||
id: string;
|
||||
name: string;
|
||||
email?: string;
|
||||
phone: string;
|
||||
vehicleInfo?: string;
|
||||
status: 'available' | 'assigned' | 'unavailable';
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
export interface ScheduleEvent {
|
||||
id: string;
|
||||
vipId: string;
|
||||
driverId?: string;
|
||||
eventType: 'pickup' | 'dropoff' | 'custom';
|
||||
eventTime: Date;
|
||||
location: string;
|
||||
notes?: string;
|
||||
status: 'scheduled' | 'in_progress' | 'completed' | 'cancelled';
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
export interface AuthRequest extends Request {
|
||||
user?: User;
|
||||
requestId?: string;
|
||||
}
|
||||
export declare const successResponse: <T>(data: T, message?: string) => SuccessResponse<T>;
|
||||
export declare const paginatedResponse: <T>(data: T[], page: number, limit: number, total: number) => PaginatedResponse<T>;
|
||||
//# sourceMappingURL=api.d.ts.map
|
||||
1
backend-old-20260125/dist/types/api.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/types/api.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe,CAAC,CAAC,GAAG,GAAG;IACtC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,CAAC;IACR,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC,GAAG,GAAG;IACxC,OAAO,EAAE,IAAI,CAAC;IACd,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,UAAU,EAAE;QACV,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,OAAO,GAAG,aAAa,GAAG,QAAQ,CAAC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAGD,MAAM,WAAW,GAAG;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,QAAQ,GAAG,SAAS,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,IAAI,CAAC;IACnB,aAAa,CAAC,EAAE,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,CAAC;IAC5D,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAGD,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,aAAa,CAAC;IACjD,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAGD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,QAAQ,GAAG,SAAS,GAAG,QAAQ,CAAC;IAC3C,SAAS,EAAE,IAAI,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,CAAC;IAChE,SAAS,EAAE,IAAI,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAGD,MAAM,WAAW,WAAY,SAAQ,OAAO;IAC1C,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,eAAO,MAAM,eAAe,GAAI,CAAC,EAAE,MAAM,CAAC,EAAE,UAAU,MAAM,KAAG,eAAe,CAAC,CAAC,CAK9E,CAAC;AAEH,eAAO,MAAM,iBAAiB,GAAI,CAAC,EACjC,MAAM,CAAC,EAAE,EACT,MAAM,MAAM,EACZ,OAAO,MAAM,EACb,OAAO,MAAM,KACZ,iBAAiB,CAAC,CAAC,CAUpB,CAAC"}
|
||||
24
backend-old-20260125/dist/types/api.js
vendored
Normal file
24
backend-old-20260125/dist/types/api.js
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.paginatedResponse = exports.successResponse = void 0;
|
||||
// Response helper functions
|
||||
const successResponse = (data, message) => ({
|
||||
success: true,
|
||||
data,
|
||||
message,
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
exports.successResponse = successResponse;
|
||||
const paginatedResponse = (data, page, limit, total) => ({
|
||||
success: true,
|
||||
data,
|
||||
pagination: {
|
||||
page,
|
||||
limit,
|
||||
total,
|
||||
totalPages: Math.ceil(total / limit)
|
||||
},
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
exports.paginatedResponse = paginatedResponse;
|
||||
//# sourceMappingURL=api.js.map
|
||||
1
backend-old-20260125/dist/types/api.js.map
vendored
Normal file
1
backend-old-20260125/dist/types/api.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":";;;AA8EA,4BAA4B;AACrB,MAAM,eAAe,GAAG,CAAI,IAAO,EAAE,OAAgB,EAAsB,EAAE,CAAC,CAAC;IACpF,OAAO,EAAE,IAAI;IACb,IAAI;IACJ,OAAO;IACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;CACpC,CAAC,CAAC;AALU,QAAA,eAAe,mBAKzB;AAEI,MAAM,iBAAiB,GAAG,CAC/B,IAAS,EACT,IAAY,EACZ,KAAa,EACb,KAAa,EACS,EAAE,CAAC,CAAC;IAC1B,OAAO,EAAE,IAAI;IACb,IAAI;IACJ,UAAU,EAAE;QACV,IAAI;QACJ,KAAK;QACL,KAAK;QACL,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;KACrC;IACD,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;CACpC,CAAC,CAAC;AAfU,QAAA,iBAAiB,qBAe3B"}
|
||||
34
backend-old-20260125/dist/types/errors.d.ts
vendored
Normal file
34
backend-old-20260125/dist/types/errors.d.ts
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
export declare class AppError extends Error {
|
||||
readonly statusCode: number;
|
||||
readonly isOperational: boolean;
|
||||
constructor(message: string, statusCode: number, isOperational?: boolean);
|
||||
}
|
||||
export declare class ValidationError extends AppError {
|
||||
constructor(message: string);
|
||||
}
|
||||
export declare class AuthenticationError extends AppError {
|
||||
constructor(message?: string);
|
||||
}
|
||||
export declare class AuthorizationError extends AppError {
|
||||
constructor(message?: string);
|
||||
}
|
||||
export declare class NotFoundError extends AppError {
|
||||
constructor(message: string);
|
||||
}
|
||||
export declare class ConflictError extends AppError {
|
||||
constructor(message: string);
|
||||
}
|
||||
export declare class DatabaseError extends AppError {
|
||||
constructor(message?: string);
|
||||
}
|
||||
export interface ErrorResponse {
|
||||
success: false;
|
||||
error: {
|
||||
message: string;
|
||||
code?: string;
|
||||
details?: any;
|
||||
};
|
||||
timestamp: string;
|
||||
path?: string;
|
||||
}
|
||||
//# sourceMappingURL=errors.d.ts.map
|
||||
1
backend-old-20260125/dist/types/errors.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/types/errors.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/types/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAS,SAAQ,KAAK;IACjC,SAAgB,UAAU,EAAE,MAAM,CAAC;IACnC,SAAgB,aAAa,EAAE,OAAO,CAAC;gBAE3B,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,UAAO;CAOtE;AAED,qBAAa,eAAgB,SAAQ,QAAQ;gBAC/B,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,mBAAoB,SAAQ,QAAQ;gBACnC,OAAO,SAA0B;CAG9C;AAED,qBAAa,kBAAmB,SAAQ,QAAQ;gBAClC,OAAO,SAA6B;CAGjD;AAED,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,aAAc,SAAQ,QAAQ;gBAC7B,OAAO,SAA8B;CAGlD;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,GAAG,CAAC;KACf,CAAC;IACF,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
|
||||
49
backend-old-20260125/dist/types/errors.js
vendored
Normal file
49
backend-old-20260125/dist/types/errors.js
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.DatabaseError = exports.ConflictError = exports.NotFoundError = exports.AuthorizationError = exports.AuthenticationError = exports.ValidationError = exports.AppError = void 0;
|
||||
class AppError extends Error {
|
||||
constructor(message, statusCode, isOperational = true) {
|
||||
super(message);
|
||||
this.statusCode = statusCode;
|
||||
this.isOperational = isOperational;
|
||||
Error.captureStackTrace(this, this.constructor);
|
||||
}
|
||||
}
|
||||
exports.AppError = AppError;
|
||||
class ValidationError extends AppError {
|
||||
constructor(message) {
|
||||
super(message, 400, true);
|
||||
}
|
||||
}
|
||||
exports.ValidationError = ValidationError;
|
||||
class AuthenticationError extends AppError {
|
||||
constructor(message = 'Authentication failed') {
|
||||
super(message, 401, true);
|
||||
}
|
||||
}
|
||||
exports.AuthenticationError = AuthenticationError;
|
||||
class AuthorizationError extends AppError {
|
||||
constructor(message = 'Insufficient permissions') {
|
||||
super(message, 403, true);
|
||||
}
|
||||
}
|
||||
exports.AuthorizationError = AuthorizationError;
|
||||
class NotFoundError extends AppError {
|
||||
constructor(message) {
|
||||
super(message, 404, true);
|
||||
}
|
||||
}
|
||||
exports.NotFoundError = NotFoundError;
|
||||
class ConflictError extends AppError {
|
||||
constructor(message) {
|
||||
super(message, 409, true);
|
||||
}
|
||||
}
|
||||
exports.ConflictError = ConflictError;
|
||||
class DatabaseError extends AppError {
|
||||
constructor(message = 'Database operation failed') {
|
||||
super(message, 500, false);
|
||||
}
|
||||
}
|
||||
exports.DatabaseError = DatabaseError;
|
||||
//# sourceMappingURL=errors.js.map
|
||||
1
backend-old-20260125/dist/types/errors.js.map
vendored
Normal file
1
backend-old-20260125/dist/types/errors.js.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/types/errors.ts"],"names":[],"mappings":";;;AAAA,MAAa,QAAS,SAAQ,KAAK;IAIjC,YAAY,OAAe,EAAE,UAAkB,EAAE,aAAa,GAAG,IAAI;QACnE,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;QAEnC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAClD,CAAC;CACF;AAXD,4BAWC;AAED,MAAa,eAAgB,SAAQ,QAAQ;IAC3C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF;AAJD,0CAIC;AAED,MAAa,mBAAoB,SAAQ,QAAQ;IAC/C,YAAY,OAAO,GAAG,uBAAuB;QAC3C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF;AAJD,kDAIC;AAED,MAAa,kBAAmB,SAAQ,QAAQ;IAC9C,YAAY,OAAO,GAAG,0BAA0B;QAC9C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF;AAJD,gDAIC;AAED,MAAa,aAAc,SAAQ,QAAQ;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,aAAc,SAAQ,QAAQ;IACzC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;CACF;AAJD,sCAIC;AAED,MAAa,aAAc,SAAQ,QAAQ;IACzC,YAAY,OAAO,GAAG,2BAA2B;QAC/C,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;CACF;AAJD,sCAIC"}
|
||||
364
backend-old-20260125/dist/types/schemas.d.ts
vendored
Normal file
364
backend-old-20260125/dist/types/schemas.d.ts
vendored
Normal file
@@ -0,0 +1,364 @@
|
||||
import { z } from 'zod';
|
||||
export declare const vipFlightSchema: z.ZodObject<{
|
||||
flightNumber: z.ZodString;
|
||||
airline: z.ZodOptional<z.ZodString>;
|
||||
scheduledArrival: z.ZodUnion<[z.ZodString, z.ZodDate]>;
|
||||
scheduledDeparture: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
||||
status: z.ZodOptional<z.ZodEnum<["scheduled", "delayed", "cancelled", "arrived"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}>;
|
||||
export declare const createVipSchema: z.ZodEffects<z.ZodObject<{
|
||||
name: z.ZodString;
|
||||
organization: z.ZodOptional<z.ZodString>;
|
||||
department: z.ZodDefault<z.ZodEnum<["Office of Development", "Admin"]>>;
|
||||
transportMode: z.ZodDefault<z.ZodEnum<["flight", "self-driving"]>>;
|
||||
flights: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
||||
flightNumber: z.ZodString;
|
||||
airline: z.ZodOptional<z.ZodString>;
|
||||
scheduledArrival: z.ZodUnion<[z.ZodString, z.ZodDate]>;
|
||||
scheduledDeparture: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
||||
status: z.ZodOptional<z.ZodEnum<["scheduled", "delayed", "cancelled", "arrived"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}>, "many">>;
|
||||
expectedArrival: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
||||
needsAirportPickup: z.ZodDefault<z.ZodBoolean>;
|
||||
needsVenueTransport: z.ZodDefault<z.ZodBoolean>;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name: string;
|
||||
department: "Office of Development" | "Admin";
|
||||
transportMode: "flight" | "self-driving";
|
||||
needsAirportPickup: boolean;
|
||||
needsVenueTransport: boolean;
|
||||
organization?: string | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | Date | undefined;
|
||||
notes?: string | undefined;
|
||||
}, {
|
||||
name: string;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | Date | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}>, {
|
||||
name: string;
|
||||
department: "Office of Development" | "Admin";
|
||||
transportMode: "flight" | "self-driving";
|
||||
needsAirportPickup: boolean;
|
||||
needsVenueTransport: boolean;
|
||||
organization?: string | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | Date | undefined;
|
||||
notes?: string | undefined;
|
||||
}, {
|
||||
name: string;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | Date | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}>;
|
||||
export declare const updateVipSchema: z.ZodObject<{
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
organization: z.ZodOptional<z.ZodString>;
|
||||
department: z.ZodOptional<z.ZodEnum<["Office of Development", "Admin"]>>;
|
||||
transportMode: z.ZodOptional<z.ZodEnum<["flight", "self-driving"]>>;
|
||||
flights: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
||||
flightNumber: z.ZodString;
|
||||
airline: z.ZodOptional<z.ZodString>;
|
||||
scheduledArrival: z.ZodUnion<[z.ZodString, z.ZodDate]>;
|
||||
scheduledDeparture: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
||||
status: z.ZodOptional<z.ZodEnum<["scheduled", "delayed", "cancelled", "arrived"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}, {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}>, "many">>;
|
||||
expectedArrival: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
||||
needsAirportPickup: z.ZodOptional<z.ZodBoolean>;
|
||||
needsVenueTransport: z.ZodOptional<z.ZodBoolean>;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name?: string | undefined;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | Date | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}, {
|
||||
name?: string | undefined;
|
||||
organization?: string | undefined;
|
||||
department?: "Office of Development" | "Admin" | undefined;
|
||||
transportMode?: "flight" | "self-driving" | undefined;
|
||||
flights?: {
|
||||
flightNumber: string;
|
||||
scheduledArrival: string | Date;
|
||||
status?: "scheduled" | "cancelled" | "delayed" | "arrived" | undefined;
|
||||
airline?: string | undefined;
|
||||
scheduledDeparture?: string | Date | undefined;
|
||||
}[] | undefined;
|
||||
expectedArrival?: string | Date | undefined;
|
||||
needsAirportPickup?: boolean | undefined;
|
||||
needsVenueTransport?: boolean | undefined;
|
||||
notes?: string | undefined;
|
||||
}>;
|
||||
export declare const createDriverSchema: z.ZodObject<{
|
||||
name: z.ZodString;
|
||||
email: z.ZodOptional<z.ZodString>;
|
||||
phone: z.ZodString;
|
||||
vehicleInfo: z.ZodOptional<z.ZodString>;
|
||||
status: z.ZodDefault<z.ZodEnum<["available", "assigned", "unavailable"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name: string;
|
||||
phone: string;
|
||||
status: "available" | "assigned" | "unavailable";
|
||||
email?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
}, {
|
||||
name: string;
|
||||
phone: string;
|
||||
email?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
status?: "available" | "assigned" | "unavailable" | undefined;
|
||||
}>;
|
||||
export declare const updateDriverSchema: z.ZodObject<{
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
email: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
||||
phone: z.ZodOptional<z.ZodString>;
|
||||
vehicleInfo: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
||||
status: z.ZodOptional<z.ZodDefault<z.ZodEnum<["available", "assigned", "unavailable"]>>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name?: string | undefined;
|
||||
email?: string | undefined;
|
||||
phone?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
status?: "available" | "assigned" | "unavailable" | undefined;
|
||||
}, {
|
||||
name?: string | undefined;
|
||||
email?: string | undefined;
|
||||
phone?: string | undefined;
|
||||
vehicleInfo?: string | undefined;
|
||||
status?: "available" | "assigned" | "unavailable" | undefined;
|
||||
}>;
|
||||
export declare const createScheduleEventSchema: z.ZodObject<{
|
||||
vipId: z.ZodString;
|
||||
driverId: z.ZodOptional<z.ZodString>;
|
||||
eventType: z.ZodEnum<["pickup", "dropoff", "custom"]>;
|
||||
eventTime: z.ZodUnion<[z.ZodString, z.ZodDate]>;
|
||||
location: z.ZodString;
|
||||
notes: z.ZodOptional<z.ZodString>;
|
||||
status: z.ZodDefault<z.ZodEnum<["scheduled", "in_progress", "completed", "cancelled"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
status: "scheduled" | "in_progress" | "completed" | "cancelled";
|
||||
eventTime: string | Date;
|
||||
eventType: "custom" | "pickup" | "dropoff";
|
||||
location: string;
|
||||
vipId: string;
|
||||
notes?: string | undefined;
|
||||
driverId?: string | undefined;
|
||||
}, {
|
||||
eventTime: string | Date;
|
||||
eventType: "custom" | "pickup" | "dropoff";
|
||||
location: string;
|
||||
vipId: string;
|
||||
notes?: string | undefined;
|
||||
status?: "scheduled" | "in_progress" | "completed" | "cancelled" | undefined;
|
||||
driverId?: string | undefined;
|
||||
}>;
|
||||
export declare const updateScheduleEventSchema: z.ZodObject<{
|
||||
vipId: z.ZodOptional<z.ZodString>;
|
||||
driverId: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
||||
eventType: z.ZodOptional<z.ZodEnum<["pickup", "dropoff", "custom"]>>;
|
||||
eventTime: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodDate]>>;
|
||||
location: z.ZodOptional<z.ZodString>;
|
||||
notes: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
||||
status: z.ZodOptional<z.ZodDefault<z.ZodEnum<["scheduled", "in_progress", "completed", "cancelled"]>>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
notes?: string | undefined;
|
||||
status?: "scheduled" | "in_progress" | "completed" | "cancelled" | undefined;
|
||||
driverId?: string | undefined;
|
||||
eventTime?: string | Date | undefined;
|
||||
eventType?: "custom" | "pickup" | "dropoff" | undefined;
|
||||
location?: string | undefined;
|
||||
vipId?: string | undefined;
|
||||
}, {
|
||||
notes?: string | undefined;
|
||||
status?: "scheduled" | "in_progress" | "completed" | "cancelled" | undefined;
|
||||
driverId?: string | undefined;
|
||||
eventTime?: string | Date | undefined;
|
||||
eventType?: "custom" | "pickup" | "dropoff" | undefined;
|
||||
location?: string | undefined;
|
||||
vipId?: string | undefined;
|
||||
}>;
|
||||
export declare const createUserSchema: z.ZodObject<{
|
||||
email: z.ZodString;
|
||||
name: z.ZodString;
|
||||
role: z.ZodEnum<["admin", "coordinator", "driver"]>;
|
||||
department: z.ZodOptional<z.ZodString>;
|
||||
password: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name: string;
|
||||
email: string;
|
||||
role: "coordinator" | "admin" | "driver";
|
||||
department?: string | undefined;
|
||||
password?: string | undefined;
|
||||
}, {
|
||||
name: string;
|
||||
email: string;
|
||||
role: "coordinator" | "admin" | "driver";
|
||||
department?: string | undefined;
|
||||
password?: string | undefined;
|
||||
}>;
|
||||
export declare const updateUserSchema: z.ZodObject<{
|
||||
email: z.ZodOptional<z.ZodString>;
|
||||
name: z.ZodOptional<z.ZodString>;
|
||||
role: z.ZodOptional<z.ZodEnum<["admin", "coordinator", "driver"]>>;
|
||||
department: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
||||
password: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
name?: string | undefined;
|
||||
department?: string | undefined;
|
||||
email?: string | undefined;
|
||||
role?: "coordinator" | "admin" | "driver" | undefined;
|
||||
password?: string | undefined;
|
||||
}, {
|
||||
name?: string | undefined;
|
||||
department?: string | undefined;
|
||||
email?: string | undefined;
|
||||
role?: "coordinator" | "admin" | "driver" | undefined;
|
||||
password?: string | undefined;
|
||||
}>;
|
||||
export declare const updateAdminSettingsSchema: z.ZodObject<{
|
||||
key: z.ZodString;
|
||||
value: z.ZodString;
|
||||
description: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
value: string;
|
||||
key: string;
|
||||
description?: string | undefined;
|
||||
}, {
|
||||
value: string;
|
||||
key: string;
|
||||
description?: string | undefined;
|
||||
}>;
|
||||
export declare const loginSchema: z.ZodObject<{
|
||||
email: z.ZodString;
|
||||
password: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
email: string;
|
||||
password: string;
|
||||
}, {
|
||||
email: string;
|
||||
password: string;
|
||||
}>;
|
||||
export declare const googleAuthCallbackSchema: z.ZodObject<{
|
||||
code: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
code: string;
|
||||
}, {
|
||||
code: string;
|
||||
}>;
|
||||
export declare const paginationSchema: z.ZodObject<{
|
||||
page: z.ZodDefault<z.ZodEffects<z.ZodString, number, string>>;
|
||||
limit: z.ZodDefault<z.ZodEffects<z.ZodString, number, string>>;
|
||||
sortBy: z.ZodOptional<z.ZodString>;
|
||||
sortOrder: z.ZodDefault<z.ZodEnum<["asc", "desc"]>>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
page: number;
|
||||
limit: number;
|
||||
sortOrder: "asc" | "desc";
|
||||
sortBy?: string | undefined;
|
||||
}, {
|
||||
page?: string | undefined;
|
||||
limit?: string | undefined;
|
||||
sortBy?: string | undefined;
|
||||
sortOrder?: "asc" | "desc" | undefined;
|
||||
}>;
|
||||
export declare const dateRangeSchema: z.ZodObject<{
|
||||
startDate: z.ZodOptional<z.ZodString>;
|
||||
endDate: z.ZodOptional<z.ZodString>;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
startDate?: string | undefined;
|
||||
endDate?: string | undefined;
|
||||
}, {
|
||||
startDate?: string | undefined;
|
||||
endDate?: string | undefined;
|
||||
}>;
|
||||
export declare const idParamSchema: z.ZodObject<{
|
||||
id: z.ZodString;
|
||||
}, "strip", z.ZodTypeAny, {
|
||||
id: string;
|
||||
}, {
|
||||
id: string;
|
||||
}>;
|
||||
//# sourceMappingURL=schemas.d.ts.map
|
||||
1
backend-old-20260125/dist/types/schemas.d.ts.map
vendored
Normal file
1
backend-old-20260125/dist/types/schemas.d.ts.map
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/types/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;EAM1B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuB3B,CAAC;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAU1B,CAAC;AAGH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;EAM7B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;EAA+B,CAAC;AAG/D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;EAQpC,CAAC;AAEH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;EAAsC,CAAC;AAG7E,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;EAM3B,CAAC;AAEH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;EAA6B,CAAC;AAG3D,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAIpC,CAAC;AAGH,eAAO,MAAM,WAAW;;;;;;;;;EAGtB,CAAC;AAEH,eAAO,MAAM,wBAAwB;;;;;;EAEnC,CAAC;AAGH,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;EAK3B,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;EAG1B,CAAC;AAGH,eAAO,MAAM,aAAa;;;;;;EAExB,CAAC"}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user