Spaces:
Running
Running
| const { v4: uuidv4 } = require('uuid'); | |
| const { getDb } = require('../config/database'); | |
| const { scoreResume } = require('../services/atsService'); | |
| const logger = require('../config/logger'); | |
| const DEFAULT_CONTENT = JSON.stringify({ | |
| contact: { name: '', title: '', email: '', phone: '', location: '', linkedin: '', github: '', website: '' }, | |
| summary: '', experience: [], education: [], skills: [], certifications: [], projects: [], languages: [], awards: [], customSections: [], | |
| }); | |
| const DEFAULT_DESIGN = JSON.stringify({ primaryColor: '#2563EB', fontFamily: 'Inter, sans-serif', fontSize: 11 }); | |
| const DEFAULT_ORDER = JSON.stringify(['contact', 'summary', 'experience', 'education', 'skills']); | |
| async function saveVersion(db, resumeId, snapshot, label) { | |
| const lastVer = await db.get('SELECT version_num FROM resume_versions WHERE resume_id = ? ORDER BY version_num DESC LIMIT 1', resumeId); | |
| const nextNum = lastVer ? lastVer.version_num + 1 : 1; | |
| await db.run('INSERT INTO resume_versions (id, resume_id, version_num, snapshot, label) VALUES (?, ?, ?, ?, ?)', uuidv4(), resumeId, nextNum, JSON.stringify(snapshot), label || null); | |
| } | |
| async function createResume(req, res) { | |
| const { title, templateId, content, design, sectionOrder } = req.body; | |
| const db = await getDb(); | |
| const id = uuidv4(); | |
| // Default to the first modern template if none provided | |
| const finalTemplateId = templateId || 'tmpl_modern_1'; | |
| if (finalTemplateId) { | |
| const tmpl = await db.get('SELECT id FROM templates WHERE id = ?', finalTemplateId); | |
| if (!tmpl) { | |
| if (templateId) return res.status(404).json({ success: false, message: 'Template not found' }); | |
| // If default template isn't found, just proceed with null (user will have to select one) | |
| } | |
| } | |
| await db.run( | |
| `INSERT INTO resumes (id, user_id, template_id, title, content, design, section_order) VALUES (?, ?, ?, ?, ?, ?, ?)`, | |
| id, (req.user ? req.user.id : 'guest_user'), finalTemplateId || null, title || 'Untitled Resume', content ? JSON.stringify(content) : DEFAULT_CONTENT, design ? JSON.stringify(design) : DEFAULT_DESIGN, sectionOrder ? JSON.stringify(sectionOrder) : DEFAULT_ORDER | |
| ); | |
| const resume = await db.get('SELECT * FROM resumes WHERE id = ?', id); | |
| return res.status(201).json({ success: true, resume: parseResume(resume) }); | |
| } | |
| async function listResumes(req, res) { | |
| const db = await getDb(); | |
| const resumes = await db.all('SELECT r.*, t.name AS template_name FROM resumes r LEFT JOIN templates t ON r.template_id = t.id WHERE r.user_id = ? ORDER BY r.updated_at DESC', (req.user ? req.user.id : 'guest_user')); | |
| return res.json({ success: true, resumes: resumes.map(parseResume) }); | |
| } | |
| async function getResume(req, res) { | |
| const db = await getDb(); | |
| const resume = await db.get('SELECT r.*, t.html_content, t.css_content FROM resumes r LEFT JOIN templates t ON r.template_id = t.id WHERE r.id = ? AND (r.user_id = ? OR r.is_public = 1)', req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| if (!resume) return res.status(404).json({ success: false, message: 'Resume not found' }); | |
| return res.json({ success: true, resume: parseResume(resume) }); | |
| } | |
| async function updateResume(req, res) { | |
| const db = await getDb(); | |
| const existing = await db.get('SELECT * FROM resumes WHERE id = ? AND user_id = ?', req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| if (!existing) return res.status(404).json({ success: false, message: 'Resume not found' }); | |
| const { title, templateId, content, design, sectionOrder, isPublic } = req.body; | |
| let atsScore = existing.ats_score; | |
| let atsFeedback = existing.ats_feedback; | |
| await db.run( | |
| `UPDATE resumes SET title = COALESCE(?, title), template_id = COALESCE(?, template_id), content = COALESCE(?, content), design = COALESCE(?, design), section_order = COALESCE(?, section_order), is_public = COALESCE(?, is_public), ats_score = ?, ats_feedback = ?, updated_at = datetime('now') WHERE id = ?`, | |
| title || null, templateId || null, content ? JSON.stringify(content) : null, design ? JSON.stringify(design) : null, sectionOrder ? JSON.stringify(sectionOrder) : null, isPublic !== undefined ? (isPublic ? 1 : 0) : null, atsScore, atsFeedback, req.params.id | |
| ); | |
| const updated = await db.get('SELECT * FROM resumes WHERE id = ?', req.params.id); | |
| return res.json({ success: true, resume: parseResume(updated) }); | |
| } | |
| async function deleteResume(req, res) { | |
| const db = await getDb(); | |
| const result = await db.run('DELETE FROM resumes WHERE id = ? AND user_id = ?', req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| if (result.changes === 0) return res.status(404).json({ success: false, message: 'Resume not found' }); | |
| return res.json({ success: true, message: 'Resume deleted' }); | |
| } | |
| async function getAtsScore(req, res) { | |
| const db = await getDb(); | |
| const resume = await db.get('SELECT * FROM resumes WHERE id = ? AND user_id = ?', req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| if (!resume) return res.status(404).json({ success: false, message: 'Resume not found' }); | |
| const result = await scoreResume(JSON.parse(resume.content), resume.template_id); | |
| await db.run('UPDATE resumes SET ats_score = ?, ats_feedback = ?, updated_at = datetime("now") WHERE id = ?', result.score, JSON.stringify(result.feedback), resume.id); | |
| return res.json({ success: true, ats: result }); | |
| } | |
| async function duplicateResume(req, res) { | |
| const db = await getDb(); | |
| const original = await db.get('SELECT * FROM resumes WHERE id = ? AND user_id = ?', req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| if (!original) return res.status(404).json({ success: false, message: 'Resume not found' }); | |
| const id = uuidv4(); | |
| await db.run( | |
| `INSERT INTO resumes (id, user_id, template_id, title, content, design, section_order) VALUES (?, ?, ?, ?, ?, ?, ?)`, | |
| id, (req.user ? req.user.id : 'guest_user'), original.template_id, `${original.title} (Copy)`, original.content, original.design, original.section_order | |
| ); | |
| const duplicated = await db.get('SELECT * FROM resumes WHERE id = ?', id); | |
| return res.status(201).json({ success: true, resume: parseResume(duplicated) }); | |
| } | |
| async function getVersions(req, res) { | |
| const db = await getDb(); | |
| const versions = await db.all('SELECT id, version_num, label, created_at FROM resume_versions WHERE resume_id = ? ORDER BY version_num DESC', req.params.id); | |
| return res.json({ success: true, versions }); | |
| } | |
| async function restoreVersion(req, res) { | |
| const db = await getDb(); | |
| const version = await db.get('SELECT * FROM resume_versions WHERE id = ? AND resume_id = ?', req.params.versionId, req.params.id); | |
| if (!version) return res.status(404).json({ success: false, message: 'Version not found' }); | |
| await db.run('UPDATE resumes SET content = ?, updated_at = datetime("now") WHERE id = ?', version.snapshot, req.params.id); | |
| const updated = await db.get('SELECT * FROM resumes WHERE id = ?', req.params.id); | |
| return res.json({ success: true, resume: parseResume(updated) }); | |
| } | |
| async function updateDesign(req, res) { | |
| const db = await getDb(); | |
| const { design } = req.body; | |
| await db.run('UPDATE resumes SET design = ?, updated_at = datetime("now") WHERE id = ? AND user_id = ?', JSON.stringify(design), req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| const updated = await db.get('SELECT * FROM resumes WHERE id = ?', req.params.id); | |
| return res.json({ success: true, resume: parseResume(updated) }); | |
| } | |
| async function updateSectionOrder(req, res) { | |
| const db = await getDb(); | |
| const { sectionOrder } = req.body; | |
| await db.run('UPDATE resumes SET section_order = ?, updated_at = datetime("now") WHERE id = ? AND user_id = ?', JSON.stringify(sectionOrder), req.params.id, (req.user ? req.user.id : 'guest_user')); | |
| const updated = await db.get('SELECT * FROM resumes WHERE id = ?', req.params.id); | |
| return res.json({ success: true, resume: parseResume(updated) }); | |
| } | |
| function parseResume(r) { | |
| if (!r) return null; | |
| return { ...r, content: JSON.parse(r.content || '{}'), design: JSON.parse(r.design || '{}'), sectionOrder: JSON.parse(r.section_order || '[]'), atsFeedback: JSON.parse(r.ats_feedback || '[]'), isPublic: Boolean(r.is_public) }; | |
| } | |
| module.exports = { createResume, listResumes, getResume, updateResume, deleteResume, getAtsScore, duplicateResume, getVersions, restoreVersion, updateDesign, updateSectionOrder }; | |