Fixed the ChatGPT screw up during rewrite from user_profile.id and .user_id
This commit is contained in:
parent
d8027d6d17
commit
fc4e9da50b
@ -109,9 +109,10 @@ app.use((req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// =============== USER REGISTRATION (MySQL) ===============
|
// =============== USER REGISTRATION (MySQL) ===============
|
||||||
|
// /api/register
|
||||||
app.post('/api/register', async (req, res) => {
|
app.post('/api/register', async (req, res) => {
|
||||||
const {
|
const {
|
||||||
userId,
|
userId, // random ID from the front end
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
firstname,
|
firstname,
|
||||||
@ -123,62 +124,54 @@ app.post('/api/register', async (req, res) => {
|
|||||||
career_situation
|
career_situation
|
||||||
} = req.body;
|
} = req.body;
|
||||||
|
|
||||||
if (
|
|
||||||
!userId ||
|
|
||||||
!username ||
|
|
||||||
!password ||
|
|
||||||
!firstname ||
|
|
||||||
!lastname ||
|
|
||||||
!email ||
|
|
||||||
!zipcode ||
|
|
||||||
!state ||
|
|
||||||
!area ||
|
|
||||||
!career_situation
|
|
||||||
) {
|
|
||||||
return res.status(400).json({ error: 'All fields including career_situation are required' });
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
const hashedPassword = await bcrypt.hash(password, 10);
|
||||||
|
|
||||||
// 1) Insert into user_profile first
|
// Insert row in user_profile, storing both user_id (random) and letting id auto-increment
|
||||||
const profileQuery = `
|
const profileQuery = `
|
||||||
INSERT INTO user_profile (user_id, firstname, lastname, email, zipcode, state, area, career_situation)
|
INSERT INTO user_profile
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
(user_id, firstname, lastname, email, zipcode, state, area, career_situation)
|
||||||
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
`;
|
||||||
|
pool.query(
|
||||||
|
profileQuery,
|
||||||
|
[userId, firstname, lastname, email, zipcode, state, area, career_situation],
|
||||||
|
(errProfile, resultProfile) => {
|
||||||
|
if (errProfile) {
|
||||||
|
console.error('Error inserting user_profile:', errProfile.message);
|
||||||
|
return res.status(500).json({ error: 'Failed to create user profile' });
|
||||||
|
}
|
||||||
|
|
||||||
|
const newProfileAutoId = resultProfile.insertId; // auto-increment PK
|
||||||
|
|
||||||
|
// Insert into user_auth, referencing the auto-increment PK
|
||||||
|
const authQuery = `
|
||||||
|
INSERT INTO user_auth (user_id, username, hashed_password)
|
||||||
|
VALUES (?, ?, ?)
|
||||||
`;
|
`;
|
||||||
pool.query(
|
pool.query(authQuery, [newProfileAutoId, username, hashedPassword], (errAuth) => {
|
||||||
profileQuery,
|
if (errAuth) {
|
||||||
[userId, firstname, lastname, email, zipcode, state, area, career_situation],
|
console.error('Error inserting user_auth:', errAuth.message);
|
||||||
(err2, results2) => {
|
if (errAuth.code === 'ER_DUP_ENTRY') {
|
||||||
if (err2) {
|
return res.status(400).json({ error: 'Username already exists' });
|
||||||
console.error('Error inserting into user_profile:', err2.message);
|
|
||||||
return res.status(500).json({ error: 'Failed to create user profile' });
|
|
||||||
}
|
}
|
||||||
|
return res.status(500).json({ error: 'Failed to register user' });
|
||||||
// 2) Insert into user_auth
|
|
||||||
const authQuery = `
|
|
||||||
INSERT INTO user_auth (user_id, username, hashed_password)
|
|
||||||
VALUES (?, ?, ?)
|
|
||||||
`;
|
|
||||||
pool.query(authQuery, [userId, username, hashedPassword], (err, results) => {
|
|
||||||
if (err) {
|
|
||||||
console.error('Error inserting into user_auth:', err.message);
|
|
||||||
if (err.code === 'ER_DUP_ENTRY') {
|
|
||||||
return res.status(400).json({ error: 'Username already exists' });
|
|
||||||
}
|
|
||||||
return res.status(500).json({ error: 'Failed to register user' });
|
|
||||||
}
|
|
||||||
return res.status(201).json({ message: 'User registered successfully', userId });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
return res.status(201).json({
|
||||||
|
message: 'User registered successfully',
|
||||||
} catch (error) {
|
dbId: newProfileAutoId, // the auto-increment PK
|
||||||
console.error('Error during registration:', error.message);
|
customId: userId, // the random ID
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error during registration:', err.message);
|
||||||
return res.status(500).json({ error: 'Internal server error' });
|
return res.status(500).json({ error: 'Internal server error' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// =============== SIGN-IN (MySQL) ===============
|
// =============== SIGN-IN (MySQL) ===============
|
||||||
app.post('/api/signin', async (req, res) => {
|
app.post('/api/signin', async (req, res) => {
|
||||||
const { username, password } = req.body;
|
const { username, password } = req.body;
|
||||||
@ -190,6 +183,7 @@ app.post('/api/signin', async (req, res) => {
|
|||||||
SELECT
|
SELECT
|
||||||
user_auth.user_id,
|
user_auth.user_id,
|
||||||
user_auth.hashed_password,
|
user_auth.hashed_password,
|
||||||
|
user_profile.id,
|
||||||
user_profile.zipcode,
|
user_profile.zipcode,
|
||||||
user_profile.is_premium,
|
user_profile.is_premium,
|
||||||
user_profile.is_pro_premium,
|
user_profile.is_pro_premium,
|
||||||
@ -200,7 +194,7 @@ app.post('/api/signin', async (req, res) => {
|
|||||||
user_profile.career_priorities,
|
user_profile.career_priorities,
|
||||||
user_profile.career_list
|
user_profile.career_list
|
||||||
FROM user_auth
|
FROM user_auth
|
||||||
LEFT JOIN user_profile ON user_auth.user_id = user_profile.user_id
|
LEFT JOIN user_profile ON user_auth.user_id = user_profile.id
|
||||||
WHERE user_auth.username = ?
|
WHERE user_auth.username = ?
|
||||||
`;
|
`;
|
||||||
pool.query(query, [username], async (err, results) => {
|
pool.query(query, [username], async (err, results) => {
|
||||||
@ -219,11 +213,11 @@ app.post('/api/signin', async (req, res) => {
|
|||||||
return res.status(401).json({ error: 'Invalid username or password' });
|
return res.status(401).json({ error: 'Invalid username or password' });
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = jwt.sign({ userId: row.user_id }, SECRET_KEY, { expiresIn: '2h' });
|
const token = jwt.sign({ userId: row.id }, SECRET_KEY, { expiresIn: '2h' });
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
message: 'Login successful',
|
message: 'Login successful',
|
||||||
token,
|
token,
|
||||||
userId: row.user_id,
|
userId: row.id,
|
||||||
user: {
|
user: {
|
||||||
user_id: row.user_id,
|
user_id: row.user_id,
|
||||||
firstname: row.firstname,
|
firstname: row.firstname,
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
|
/**************************************************
|
||||||
|
* server2.js - MySQL version
|
||||||
|
**************************************************/
|
||||||
import express from 'express';
|
import express from 'express';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import cors from 'cors';
|
import cors from 'cors';
|
||||||
import helmet from 'helmet'; // Import helmet for HTTP security headers
|
import helmet from 'helmet'; // For HTTP security headers
|
||||||
import dotenv from 'dotenv';
|
import dotenv from 'dotenv';
|
||||||
import xlsx from 'xlsx'; // Keep for CIP->SOC mapping only
|
import xlsx from 'xlsx'; // For CIP->SOC mapping only
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { fileURLToPath } from 'url';
|
import { fileURLToPath } from 'url';
|
||||||
import { open } from 'sqlite';
|
|
||||||
import sqlite3 from 'sqlite3';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import readline from 'readline';
|
import readline from 'readline';
|
||||||
|
|
||||||
|
// ********** NEW: use mysql2/promise for async/await queries **********
|
||||||
|
import mysql from 'mysql2/promise';
|
||||||
|
|
||||||
// --- Basic file init ---
|
// --- Basic file init ---
|
||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = path.dirname(__filename);
|
const __dirname = path.dirname(__filename);
|
||||||
@ -33,41 +37,31 @@ const mappingFilePath = '/home/jcoakley/aptiva-dev1-app/public/CIP_to_ONET_SOC.x
|
|||||||
// Institution data
|
// Institution data
|
||||||
const institutionFilePath = path.resolve(rootPath, 'public/Institution_data.json');
|
const institutionFilePath = path.resolve(rootPath, 'public/Institution_data.json');
|
||||||
|
|
||||||
// Create Express app
|
// ********** CREATE TWO POOLS FOR TWO DATABASES **********
|
||||||
|
// salary_data_db => poolSalary
|
||||||
|
// user_profile_db => poolProfile
|
||||||
|
|
||||||
|
const poolSalary = mysql.createPool({
|
||||||
|
host: process.env.DB_HOST,
|
||||||
|
port: process.env.DB_PORT || 3306,
|
||||||
|
user: process.env.DB_USER,
|
||||||
|
password: process.env.DB_PASSWORD,
|
||||||
|
database: 'salary_data_db',
|
||||||
|
connectionLimit: 10
|
||||||
|
});
|
||||||
|
|
||||||
|
const poolProfile = mysql.createPool({
|
||||||
|
host: process.env.DB_HOST,
|
||||||
|
port: process.env.DB_PORT || 3306,
|
||||||
|
user: process.env.DB_USER,
|
||||||
|
password: process.env.DB_PASSWORD,
|
||||||
|
database: 'user_profile_db',
|
||||||
|
connectionLimit: 10
|
||||||
|
});
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const PORT = process.env.PORT || 5001;
|
const PORT = process.env.PORT || 5001;
|
||||||
|
|
||||||
/**************************************************
|
|
||||||
* DB connections
|
|
||||||
**************************************************/
|
|
||||||
let db;
|
|
||||||
const initDB = async () => {
|
|
||||||
try {
|
|
||||||
db = await open({
|
|
||||||
filename: '/home/jcoakley/aptiva-dev1-app/salary_info.db',
|
|
||||||
driver: sqlite3.Database,
|
|
||||||
});
|
|
||||||
console.log('Connected to SQLite database.');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error connecting to database:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
initDB();
|
|
||||||
|
|
||||||
let userProfileDb;
|
|
||||||
const initUserProfileDb = async () => {
|
|
||||||
try {
|
|
||||||
userProfileDb = await open({
|
|
||||||
filename: '/home/jcoakley/aptiva-dev1-app/user_profile.db',
|
|
||||||
driver: sqlite3.Database
|
|
||||||
});
|
|
||||||
console.log('Connected to user_profile.db.');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error connecting to user_profile.db:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
initUserProfileDb();
|
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Security, CORS, JSON Body
|
* Security, CORS, JSON Body
|
||||||
**************************************************/
|
**************************************************/
|
||||||
@ -141,13 +135,7 @@ if (socToCipMapping.length === 0) {
|
|||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Load single JSON with all states + US
|
* Load single JSON with all states + US
|
||||||
* Replaces old GA-only approach
|
|
||||||
**************************************************/
|
**************************************************/
|
||||||
// const projectionsFilePath = path.resolve(__dirname, '..', 'public', 'occprj.xlsx');
|
|
||||||
// const workbook = xlsx.readFile(projectionsFilePath);
|
|
||||||
// const sheet = workbook.Sheets['GAOccProj 2022-2032'];
|
|
||||||
// const projectionsData = xlsx.utils.sheet_to_json(sheet, { header: 1 });
|
|
||||||
|
|
||||||
const singleProjFile = path.resolve(__dirname, '..', 'public', 'economicproj.json');
|
const singleProjFile = path.resolve(__dirname, '..', 'public', 'economicproj.json');
|
||||||
let allProjections = [];
|
let allProjections = [];
|
||||||
try {
|
try {
|
||||||
@ -205,7 +193,7 @@ app.get('/api/onet/questions', async (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// geocode
|
// Geocode
|
||||||
async function geocodeZipCode(zipCode) {
|
async function geocodeZipCode(zipCode) {
|
||||||
const apiKey = process.env.GOOGLE_MAPS_API_KEY;
|
const apiKey = process.env.GOOGLE_MAPS_API_KEY;
|
||||||
if (!apiKey) {
|
if (!apiKey) {
|
||||||
@ -394,7 +382,7 @@ app.get('/api/schools', (req, res) => {
|
|||||||
// 1) Read `cipCodes` from query (comma-separated string)
|
// 1) Read `cipCodes` from query (comma-separated string)
|
||||||
const { cipCodes } = req.query;
|
const { cipCodes } = req.query;
|
||||||
|
|
||||||
if (!cipCodes ) {
|
if (!cipCodes) {
|
||||||
return res.status(400).json({ error: 'cipCodes (comma-separated) and state are required.' });
|
return res.status(400).json({ error: 'cipCodes (comma-separated) and state are required.' });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -422,8 +410,7 @@ app.get('/api/schools', (req, res) => {
|
|||||||
return cipArray.some((cip) => scip.startsWith(cip));
|
return cipArray.some((cip) => scip.startsWith(cip));
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5) (Optional) Deduplicate if you suspect overlaps among CIP codes.
|
// 5) (Optional) Deduplicate if you suspect overlaps among CIP codes.
|
||||||
// E.g. by a “UNITID” or unique property:
|
|
||||||
const uniqueMap = new Map();
|
const uniqueMap = new Map();
|
||||||
for (const school of filtered) {
|
for (const school of filtered) {
|
||||||
const key = school.UNITID || school.INSTNM; // pick your unique field
|
const key = school.UNITID || school.INSTNM; // pick your unique field
|
||||||
@ -441,7 +428,6 @@ app.get('/api/schools', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// tuition
|
// tuition
|
||||||
app.get('/api/tuition', (req, res) => {
|
app.get('/api/tuition', (req, res) => {
|
||||||
const { cipCodes, state } = req.query;
|
const { cipCodes, state } = req.query;
|
||||||
@ -489,11 +475,9 @@ app.get('/api/tuition', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* SINGLE route for projections from economicproj.json
|
* SINGLE route for projections from economicproj.json
|
||||||
**************************************************/
|
**************************************************/
|
||||||
// Remove old GA Excel approach; unify with single JSON approach
|
|
||||||
app.get('/api/projections/:socCode', (req, res) => {
|
app.get('/api/projections/:socCode', (req, res) => {
|
||||||
const { socCode } = req.params;
|
const { socCode } = req.params;
|
||||||
const { state } = req.query;
|
const { state } = req.query;
|
||||||
@ -548,7 +532,7 @@ app.get('/api/projections/:socCode', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* Salary route
|
* Salary route (uses poolSalary)
|
||||||
**************************************************/
|
**************************************************/
|
||||||
app.get('/api/salary', async (req, res) => {
|
app.get('/api/salary', async (req, res) => {
|
||||||
const { socCode, area } = req.query;
|
const { socCode, area } = req.query;
|
||||||
@ -576,10 +560,17 @@ app.get('/api/salary', async (req, res) => {
|
|||||||
try {
|
try {
|
||||||
let regionalRow = null;
|
let regionalRow = null;
|
||||||
let nationalRow = null;
|
let nationalRow = null;
|
||||||
|
|
||||||
|
// If area is provided, fetch regional
|
||||||
if (area) {
|
if (area) {
|
||||||
regionalRow = await db.get(regionalQuery, [socCode, area]);
|
const [regRows] = await poolSalary.query(regionalQuery, [socCode, area]);
|
||||||
|
regionalRow = regRows.length ? regRows[0] : null;
|
||||||
}
|
}
|
||||||
nationalRow = await db.get(nationalQuery, [socCode]);
|
|
||||||
|
// Always fetch national
|
||||||
|
const [natRows] = await poolSalary.query(nationalQuery, [socCode]);
|
||||||
|
nationalRow = natRows.length ? natRows[0] : null;
|
||||||
|
|
||||||
if (!regionalRow && !nationalRow) {
|
if (!regionalRow && !nationalRow) {
|
||||||
console.log('No salary data found for:', { socCode, area });
|
console.log('No salary data found for:', { socCode, area });
|
||||||
return res.status(404).json({ error: 'No salary data found' });
|
return res.status(404).json({ error: 'No salary data found' });
|
||||||
@ -597,12 +588,12 @@ app.get('/api/salary', async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* job-zones route
|
* job-zones route (uses poolSalary)
|
||||||
**************************************************/
|
**************************************************/
|
||||||
app.post('/api/job-zones', async (req, res) => {
|
app.post('/api/job-zones', async (req, res) => {
|
||||||
const { socCodes } = req.body;
|
const { socCodes } = req.body;
|
||||||
if (!socCodes || !Array.isArray(socCodes) || socCodes.length === 0) {
|
if (!socCodes || !Array.isArray(socCodes) || socCodes.length === 0) {
|
||||||
return res.status(400).json({ error: "SOC Codes are required." });
|
return res.status(400).json({ error: 'SOC Codes are required.' });
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Format them
|
// Format them
|
||||||
@ -614,28 +605,34 @@ app.post('/api/job-zones', async (req, res) => {
|
|||||||
return cleaned.slice(0, 7);
|
return cleaned.slice(0, 7);
|
||||||
});
|
});
|
||||||
const placeholders = formattedSocCodes.map(() => '?').join(',');
|
const placeholders = formattedSocCodes.map(() => '?').join(',');
|
||||||
|
|
||||||
const q = `
|
const q = `
|
||||||
SELECT OCC_CODE, JOB_ZONE,
|
SELECT OCC_CODE, JOB_ZONE,
|
||||||
A_MEDIAN, A_PCT10, A_PCT25, A_PCT75
|
A_MEDIAN, A_PCT10, A_PCT25, A_PCT75
|
||||||
FROM salary_data
|
FROM salary_data
|
||||||
WHERE OCC_CODE IN (${placeholders})
|
WHERE OCC_CODE IN (${placeholders})
|
||||||
`;
|
`;
|
||||||
const rows = await db.all(q, formattedSocCodes);
|
|
||||||
console.log("Salary Data Query Results:", rows);
|
// Use spread operator for the array
|
||||||
|
const [rows] = await poolSalary.query(q, [...formattedSocCodes]);
|
||||||
|
console.log('Salary Data Query Results:', rows);
|
||||||
|
|
||||||
const jobZoneMapping = rows.reduce((acc, row) => {
|
const jobZoneMapping = rows.reduce((acc, row) => {
|
||||||
const isMissing = [row.A_MEDIAN, row.A_PCT10, row.A_PCT25, row.A_PCT75]
|
const isMissing = [row.A_MEDIAN, row.A_PCT10, row.A_PCT25, row.A_PCT75].some(
|
||||||
.some((v) => !v || v === '#' || v === '*');
|
(v) => !v || v === '#' || v === '*'
|
||||||
|
);
|
||||||
acc[row.OCC_CODE] = {
|
acc[row.OCC_CODE] = {
|
||||||
job_zone: row.JOB_ZONE,
|
job_zone: row.JOB_ZONE,
|
||||||
limited_data: isMissing ? 1 : 0
|
limited_data: isMissing ? 1 : 0
|
||||||
};
|
};
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
console.log("Job Zone & Limited Data:", jobZoneMapping);
|
|
||||||
|
console.log('Job Zone & Limited Data:', jobZoneMapping);
|
||||||
res.json(jobZoneMapping);
|
res.json(jobZoneMapping);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching job zones:", error);
|
console.error('Error fetching job zones:', error);
|
||||||
res.status(500).json({ error: "Failed to fetch job zones." });
|
res.status(500).json({ error: 'Failed to fetch job zones.' });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -665,26 +662,10 @@ app.get('/api/skills/:socCode', async (req, res) => {
|
|||||||
|
|
||||||
const data = response.data || {};
|
const data = response.data || {};
|
||||||
|
|
||||||
// 3) O*NET returns:
|
|
||||||
// {
|
|
||||||
// "code": "17-1011.00",
|
|
||||||
// "group": [
|
|
||||||
// {
|
|
||||||
// "title": { "id": "2.A", "name": "Basic Skills" },
|
|
||||||
// "element": [
|
|
||||||
// { "id": "2.A.1.a", "name": "reading work related information" },
|
|
||||||
// ...
|
|
||||||
// ]
|
|
||||||
// },
|
|
||||||
// ...
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Instead of data.characteristic, parse data.group
|
|
||||||
const groups = data.group || [];
|
const groups = data.group || [];
|
||||||
|
|
||||||
// 4) Flatten out the group[].element[] into a single skills array
|
|
||||||
const skills = [];
|
const skills = [];
|
||||||
|
|
||||||
|
// Flatten out the group[].element[] into a single skills array
|
||||||
groups.forEach((groupItem) => {
|
groups.forEach((groupItem) => {
|
||||||
const groupName = groupItem?.title?.name || 'Unknown Group';
|
const groupName = groupItem?.title?.name || 'Unknown Group';
|
||||||
|
|
||||||
@ -702,43 +683,42 @@ app.get('/api/skills/:socCode', async (req, res) => {
|
|||||||
|
|
||||||
res.json({ skills });
|
res.json({ skills });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching O*NET skills:', error.message);
|
console.error('Error fetching O*NET skills:', error.message);
|
||||||
|
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
console.error('O*NET error status:', error.response.status);
|
console.error('O*NET error status:', error.response.status);
|
||||||
console.error('O*NET error data:', error.response.data);
|
console.error('O*NET error data:', error.response.data);
|
||||||
} else if (error.request) {
|
} else if (error.request) {
|
||||||
// The request was made but no response was received
|
console.error('No response received from O*NET.');
|
||||||
console.error('No response received from O*NET. Possibly a network or credentials error.');
|
console.error('Axios error.request:', error.request);
|
||||||
console.error('Axios error.request:', error.request);
|
} else {
|
||||||
} else {
|
console.error('Request setup error:', error.message);
|
||||||
// Something else happened in setting up the request
|
}
|
||||||
console.error('Request setup error:', error.message);
|
|
||||||
|
return res.status(500).json({ error: 'Failed to fetch O*NET skills' });
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.status(500).json({ error: 'Failed to fetch O*NET skills' });
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
* user-profile by ID route
|
* user-profile by ID route (uses poolProfile)
|
||||||
**************************************************/
|
**************************************************/
|
||||||
app.get('/api/user-profile/:id', (req, res) => {
|
app.get('/api/user-profile/:id', async (req, res) => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
if (!id) return res.status(400).json({ error: 'Profile ID is required' });
|
if (!id) return res.status(400).json({ error: 'Profile ID is required' });
|
||||||
|
|
||||||
const query = `SELECT area, zipcode FROM user_profile WHERE id = ?`;
|
const query = `SELECT area, zipcode FROM user_profile WHERE id = ?`;
|
||||||
db.get(query, [id], (err, row) => {
|
|
||||||
if (err) {
|
try {
|
||||||
console.error('Error fetching user profile:', err.message);
|
const [rows] = await poolProfile.query(query, [id]);
|
||||||
return res.status(500).json({ error: 'Failed to fetch user profile' });
|
if (!rows.length) {
|
||||||
}
|
|
||||||
if (!row) {
|
|
||||||
return res.status(404).json({ error: 'Profile not found' });
|
return res.status(404).json({ error: 'Profile not found' });
|
||||||
}
|
}
|
||||||
|
const row = rows[0];
|
||||||
res.json({ area: row.area, zipcode: row.zipcode });
|
res.json({ area: row.area, zipcode: row.zipcode });
|
||||||
});
|
} catch (err) {
|
||||||
|
console.error('Error fetching user profile:', err.message);
|
||||||
|
return res.status(500).json({ error: 'Failed to fetch user profile' });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
/**************************************************
|
/**************************************************
|
||||||
|
@ -48,6 +48,7 @@ function SignUp() {
|
|||||||
const [areas, setAreas] = useState([]);
|
const [areas, setAreas] = useState([]);
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
const [loadingAreas, setLoadingAreas] = useState(false);
|
const [loadingAreas, setLoadingAreas] = useState(false);
|
||||||
|
const [frontendUserId] = useState(() => Math.floor(Math.random() * 1000000000));
|
||||||
|
|
||||||
// new states
|
// new states
|
||||||
const [showCareerSituations, setShowCareerSituations] = useState(false);
|
const [showCareerSituations, setShowCareerSituations] = useState(false);
|
||||||
@ -168,23 +169,30 @@ function SignUp() {
|
|||||||
|
|
||||||
|
|
||||||
const handleSituationConfirm = async () => {
|
const handleSituationConfirm = async () => {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Verify payload clearly:
|
|
||||||
console.log("Payload sent to backend:", {
|
console.log("Payload sent to backend:", {
|
||||||
userId: Math.floor(Math.random() * 1000000000),
|
userId: frontendUserId,
|
||||||
username, password, firstname, lastname, email, zipcode, state, area,
|
username, password, firstname, lastname, email, zipcode, state, area,
|
||||||
career_situation: selectedSituation.id
|
career_situation: selectedSituation.id
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await fetch('/api/register', {
|
const response = await fetch('/api/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
userId: Math.floor(Math.random() * 1000000000),
|
userId: frontendUserId,
|
||||||
username, password, firstname, lastname, email, zipcode, state, area,
|
username,
|
||||||
career_situation: selectedSituation.id
|
password,
|
||||||
}),
|
firstname,
|
||||||
});
|
lastname,
|
||||||
|
email,
|
||||||
|
zipcode,
|
||||||
|
state,
|
||||||
|
area,
|
||||||
|
career_situation: selectedSituation.id
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user