240 lines
7.5 KiB
JavaScript
240 lines
7.5 KiB
JavaScript
// server3.js - Premium Services API
|
|
import express from 'express';
|
|
import cors from 'cors';
|
|
import helmet from 'helmet';
|
|
import dotenv from 'dotenv';
|
|
import { open } from 'sqlite';
|
|
import sqlite3 from 'sqlite3';
|
|
import jwt from 'jsonwebtoken';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
dotenv.config({ path: path.resolve(__dirname, '..', '.env') });
|
|
|
|
const app = express();
|
|
const PORT = process.env.PREMIUM_PORT || 5002;
|
|
|
|
let db;
|
|
const initDB = async () => {
|
|
try {
|
|
db = await open({
|
|
filename: '/home/jcoakley/aptiva-dev1-app/user_profile.db',
|
|
driver: sqlite3.Database
|
|
});
|
|
console.log('Connected to user_profile.db for Premium Services.');
|
|
} catch (error) {
|
|
console.error('Error connecting to premium database:', error);
|
|
}
|
|
};
|
|
initDB();
|
|
|
|
app.use(helmet());
|
|
app.use(express.json());
|
|
|
|
const allowedOrigins = ['https://dev1.aptivaai.com'];
|
|
app.use(cors({ origin: allowedOrigins, credentials: true }));
|
|
|
|
const authenticatePremiumUser = (req, res, next) => {
|
|
const token = req.headers.authorization?.split(' ')[1];
|
|
if (!token) return res.status(401).json({ error: 'Premium authorization required' });
|
|
|
|
try {
|
|
const { userId } = jwt.verify(token, process.env.SECRET_KEY);
|
|
req.userId = userId;
|
|
next();
|
|
} catch (error) {
|
|
return res.status(403).json({ error: 'Invalid or expired token' });
|
|
}
|
|
};
|
|
|
|
// Get latest selected planned path
|
|
app.get('/api/premium/planned-path/latest', authenticatePremiumUser, async (req, res) => {
|
|
try {
|
|
const row = await db.get(
|
|
`SELECT * FROM career_path WHERE user_id = ? ORDER BY start_date DESC LIMIT 1`,
|
|
[req.userId]
|
|
);
|
|
res.json(row || {});
|
|
} catch (error) {
|
|
console.error('Error fetching latest career path:', error);
|
|
res.status(500).json({ error: 'Failed to fetch latest planned path' });
|
|
}
|
|
});
|
|
|
|
// Get all planned paths for the user
|
|
app.get('/api/premium/planned-path/all', authenticatePremiumUser, async (req, res) => {
|
|
try {
|
|
const rows = await db.all(
|
|
`SELECT * FROM career_path WHERE user_id = ? ORDER BY start_date ASC`,
|
|
[req.userId]
|
|
);
|
|
res.json({ careerPath: rows });
|
|
} catch (error) {
|
|
console.error('Error fetching career paths:', error);
|
|
res.status(500).json({ error: 'Failed to fetch planned paths' });
|
|
}
|
|
});
|
|
|
|
// Save a new planned path
|
|
app.post('/api/premium/planned-path', authenticatePremiumUser, async (req, res) => {
|
|
const { job_title, projected_end_date } = req.body;
|
|
|
|
if (!job_title) {
|
|
return res.status(400).json({ error: 'Job title is required' });
|
|
}
|
|
|
|
try {
|
|
await db.run(
|
|
`INSERT INTO career_path (user_id, job_title, status, start_date, projected_end_date)
|
|
VALUES (?, ?, 'Active', DATE('now'), ?)`,
|
|
[req.userId, job_title, projected_end_date || null]
|
|
);
|
|
|
|
res.status(201).json({ message: 'Planned path added successfully' });
|
|
} catch (error) {
|
|
console.error('Error adding planned path:', error);
|
|
res.status(500).json({ error: 'Failed to add planned path' });
|
|
}
|
|
});
|
|
|
|
// Save a new milestone
|
|
app.post('/api/premium/milestones', authenticatePremiumUser, async (req, res) => {
|
|
const { milestone_type, description, date, career_path_id, progress } = req.body;
|
|
|
|
if (!milestone_type || !description || !date) {
|
|
return res.status(400).json({ error: 'Missing required fields' });
|
|
}
|
|
|
|
try {
|
|
await db.run(
|
|
`INSERT INTO milestones (user_id, milestone_type, description, date, career_path_id, progress, created_at)
|
|
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)`,
|
|
[req.userId, milestone_type, description, date, career_path_id, progress || 0]
|
|
);
|
|
res.status(201).json({ message: 'Milestone saved successfully' });
|
|
} catch (error) {
|
|
console.error('Error saving milestone:', error);
|
|
res.status(500).json({ error: 'Failed to save milestone' });
|
|
}
|
|
});
|
|
|
|
// Get all milestones
|
|
app.get('/api/premium/milestones', authenticatePremiumUser, async (req, res) => {
|
|
try {
|
|
const milestones = await db.all(
|
|
`SELECT * FROM milestones WHERE user_id = ? ORDER BY date ASC`,
|
|
[req.userId]
|
|
);
|
|
|
|
const mapped = milestones.map(m => ({
|
|
id: m.id,
|
|
title: m.description,
|
|
date: m.date,
|
|
type: m.milestone_type,
|
|
progress: m.progress || 0,
|
|
career_path_id: m.career_path_id
|
|
}));
|
|
|
|
res.json({ milestones: mapped });
|
|
} catch (error) {
|
|
console.error('Error fetching milestones:', error);
|
|
res.status(500).json({ error: 'Failed to fetch milestones' });
|
|
}
|
|
});
|
|
|
|
/// Update an existing milestone
|
|
app.put('/api/premium/milestones/:id', authenticatePremiumUser, async (req, res) => {
|
|
const { id } = req.params;
|
|
const { milestone_type, description, date, progress } = req.body;
|
|
|
|
if (!milestone_type || !description || !date) {
|
|
return res.status(400).json({ error: 'Missing required fields' });
|
|
}
|
|
|
|
try {
|
|
await db.run(
|
|
`UPDATE milestones SET milestone_type = ?, description = ?, date = ?, progress = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND user_id = ?`,
|
|
[milestone_type, description, date, progress || 0, id, req.userId]
|
|
);
|
|
res.status(200).json({ message: 'Milestone updated successfully' });
|
|
} catch (error) {
|
|
console.error('Error updating milestone:', error);
|
|
res.status(500).json({ error: 'Failed to update milestone' });
|
|
}
|
|
});
|
|
|
|
// Archive current career to history
|
|
app.post('/api/premium/career-history', authenticatePremiumUser, async (req, res) => {
|
|
const { career_path_id, company } = req.body;
|
|
|
|
if (!career_path_id || !company) {
|
|
return res.status(400).json({ error: 'Career path ID and company are required' });
|
|
}
|
|
|
|
try {
|
|
const career = await db.get(`SELECT * FROM career_path WHERE id = ? AND user_id = ?`, [career_path_id, req.userId]);
|
|
|
|
if (!career) {
|
|
return res.status(404).json({ error: 'Career path not found' });
|
|
}
|
|
|
|
await db.run(
|
|
`INSERT INTO career_history (user_id, job_title, company, start_date)
|
|
VALUES (?, ?, ?, DATE('now'))`,
|
|
[req.userId, career.job_title, company]
|
|
);
|
|
|
|
await db.run(`DELETE FROM career_path WHERE id = ?`, [career_path_id]);
|
|
|
|
res.status(201).json({ message: 'Career moved to history successfully' });
|
|
} catch (error) {
|
|
console.error('Error moving career to history:', error);
|
|
res.status(500).json({ error: 'Failed to update career history' });
|
|
}
|
|
});
|
|
|
|
// Retrieve career history
|
|
app.get('/api/premium/career-history', authenticatePremiumUser, async (req, res) => {
|
|
try {
|
|
const history = await db.all(
|
|
`SELECT * FROM career_history WHERE user_id = ? ORDER BY start_date DESC;`,
|
|
[req.userId]
|
|
);
|
|
|
|
res.json({ careerHistory: history });
|
|
} catch (error) {
|
|
console.error('Error fetching career history:', error);
|
|
res.status(500).json({ error: 'Failed to fetch career history' });
|
|
}
|
|
});
|
|
|
|
// ROI Analysis (placeholder logic)
|
|
app.get('/api/premium/roi-analysis', authenticatePremiumUser, async (req, res) => {
|
|
try {
|
|
const userCareer = await db.get(
|
|
`SELECT * FROM career_path WHERE user_id = ? ORDER BY start_date DESC LIMIT 1`,
|
|
[req.userId]
|
|
);
|
|
|
|
if (!userCareer) return res.status(404).json({ error: 'No planned path found for user' });
|
|
|
|
const roi = {
|
|
jobTitle: userCareer.job_title,
|
|
salary: userCareer.salary,
|
|
tuition: 50000,
|
|
netGain: userCareer.salary - 50000
|
|
};
|
|
|
|
res.json(roi);
|
|
} catch (error) {
|
|
console.error('Error calculating ROI:', error);
|
|
res.status(500).json({ error: 'Failed to calculate ROI' });
|
|
}
|
|
});
|
|
|
|
app.listen(PORT, () => {
|
|
console.log(`Premium server running on http://localhost:${PORT}`);
|
|
}); |