forked from rohit/spurrin-backend
1827 lines
54 KiB
JavaScript
1827 lines
54 KiB
JavaScript
const bcrypt = require("bcrypt");
|
|
const db = require("../config/database"); // Database connection
|
|
const fs = require("fs");
|
|
const jwt = require("jsonwebtoken");
|
|
const nlp = require("compromise");
|
|
const nodemailer = require("nodemailer");
|
|
const sender_port = process.env.SENDER_PORT;
|
|
const sender_security = process.env.SENDER_SECURITY;
|
|
const path = require('path')
|
|
|
|
const { emitEvent } = require("../services/secondaryWebsocket");
|
|
|
|
console.log('sender port : ', sender_port);
|
|
console.log('sender security : ', sender_security);
|
|
// zoho transporter
|
|
const transporter = nodemailer.createTransport({
|
|
host: "smtp.zoho.com",
|
|
port: 465,
|
|
secure: true,
|
|
auth: {
|
|
user: "kavya.j@tech4biz.io", // Your Zoho email address
|
|
pass: "8pQfkBw8gbrz", // Your Zoho App Password (not your account password)
|
|
}
|
|
});
|
|
|
|
exports.initWebSocket = (io) => {
|
|
io.on("connection", (socket) => {
|
|
console.log("Hospital connected:", socket.id);
|
|
|
|
socket.on("register_hospital", (hospitalCode) => {
|
|
hospitalSockets[hospitalCode] = socket;
|
|
console.log(`Hospital ${hospitalCode} registered.`);
|
|
});
|
|
|
|
socket.on("disconnect", () => {
|
|
const hospitalCode = Object.keys(hospitalSockets).find(
|
|
(key) => hospitalSockets[key] === socket
|
|
);
|
|
if (hospitalCode) delete hospitalSockets[hospitalCode];
|
|
console.log(`Hospital ${hospitalCode} disconnected.`);
|
|
});
|
|
});
|
|
};
|
|
|
|
exports.uploadIdPhoto = async (req, res) => {
|
|
try {
|
|
// Extracting user ID and hospital code
|
|
const userId = parseInt(req.params.id, 10); // User ID from route
|
|
const { hospital_code } = req.user; // Authenticated user's hospital code
|
|
|
|
// Check if user ID is valid
|
|
if (isNaN(userId)) {
|
|
console.error("Invalid User ID:", userId);
|
|
return res.status(400).json({ error: "Invalid user ID" });
|
|
}
|
|
|
|
// Check if a file was uploaded
|
|
if (!req.file) {
|
|
console.error("No file uploaded");
|
|
return res.status(400).json({ error: "No file uploaded" });
|
|
}
|
|
|
|
const photoPath = `/uploads/id_photos/${req.file.filename}`;
|
|
|
|
// Verify app user is part of the same hospital
|
|
|
|
const query = `
|
|
SELECT hospital_code FROM app_users WHERE id = ? AND hospital_code = ?
|
|
`;
|
|
const result = await db.query(query, [userId, hospital_code]);
|
|
|
|
if (result.length === 0) {
|
|
console.error(
|
|
"Authorization failed for user ID:",
|
|
userId,
|
|
"with hospital_code:",
|
|
hospital_code
|
|
);
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You are not authorized to upload ID for this user" });
|
|
}
|
|
|
|
// Update the ID photo path in the database
|
|
await db.query("UPDATE app_users SET id_photo_url = ? WHERE id = ?", [
|
|
photoPath,
|
|
userId,
|
|
]);
|
|
|
|
res.status(200).json({
|
|
message: "ID photo uploaded successfully!",
|
|
id_photo_url: photoPath,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error uploading ID photo:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.updateSettings = async (req, res) => {
|
|
try {
|
|
const userId = req.user.id; // Assuming user is authenticated and userId is available
|
|
const { pin, pin_enabled, remember_me } = req.body;
|
|
|
|
// Validate pin (if provided)
|
|
if (pin && (typeof pin !== 'string' || pin.length !== 4)) {
|
|
return res.status(400).json({ error: 'Invalid PIN format. Must be a 4-digit string.' });
|
|
}
|
|
|
|
// Determine expiry based on remember_me
|
|
let expiresIn = '5h';
|
|
let expiryTimestamp = new Date();
|
|
|
|
if (remember_me) {
|
|
expiresIn = '30d';
|
|
expiryTimestamp.setDate(expiryTimestamp.getDate() + 30);
|
|
} else {
|
|
expiryTimestamp.setHours(expiryTimestamp.getHours() + 5);
|
|
}
|
|
|
|
// Generate new access token
|
|
const payload = { id: userId, role: 'AppUser' };
|
|
const accessToken = jwt.sign(payload, process.env.JWT_ACCESS_TOKEN_SECRET, {
|
|
expiresIn: expiresIn,
|
|
});
|
|
|
|
// Update user settings and access token
|
|
const query = `UPDATE app_users SET pin_number = ?, pin_enabled = ?, remember_me = ?, access_token = ?, access_token_expiry = ? WHERE id = ?`;
|
|
const result=await db.query(query, [pin, pin_enabled, remember_me, accessToken, expiryTimestamp, userId]);
|
|
|
|
if (result.affectedRows > 0) {
|
|
console.log("Table updated successfully.");
|
|
} else {
|
|
console.log("Table not updated. No matching user found.");
|
|
}
|
|
|
|
res.status(200).json({ message: 'Settings updated successfully.', accessToken });
|
|
} catch (error) {
|
|
console.error('Error updating settings:', error);
|
|
res.status(500).json({ error: 'Internal Server Error' });
|
|
}
|
|
};
|
|
|
|
exports.hitlike = async (req, res) => {
|
|
try {
|
|
// Extract user ID and session ID from the request
|
|
const { session_id, id } = req.body;
|
|
const log_id = id;
|
|
const app_user_id = req.user.id;
|
|
// Check if both app_user_id and session_id are provided
|
|
if (!app_user_id || !session_id || !log_id) {
|
|
return res.status(400).json({
|
|
status: 'error',
|
|
message: 'app user id and session id and log id are required',
|
|
});
|
|
}
|
|
|
|
// Query to toggle the is_liked value
|
|
const toggleQuery = `
|
|
UPDATE interaction_logs
|
|
SET is_liked = NOT is_liked
|
|
WHERE app_user_id = ? AND session_id = ? AND id = ?
|
|
`;
|
|
|
|
// Execute the query
|
|
const result = await db.query(toggleQuery, [app_user_id, session_id,log_id]);
|
|
|
|
// Check if any rows were affected
|
|
if (result.affectedRows > 0) {
|
|
return res.status(200).json({
|
|
status: 'success',
|
|
message: 'Like updated successfully',
|
|
data: {
|
|
app_user_id,
|
|
session_id,
|
|
is_liked: result.changedRows > 0 ? 1 : 0, // 1 if changed, 0 if not
|
|
},
|
|
});
|
|
} else {
|
|
return res.status(404).json({
|
|
status: 'error',
|
|
message: 'No matching record found to toggle',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error during like toggle:', error);
|
|
return res.status(500).json({
|
|
status: 'error',
|
|
message: 'Internal server error',
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.hitFlag = async (req, res) => {
|
|
try {
|
|
// Extract user ID and session ID from the request
|
|
const { session_id, logid } = req.body;
|
|
const log_id = logid;
|
|
|
|
const app_user_id = req.user.id;
|
|
// Check if both app_user_id and session_id are provided
|
|
if (!app_user_id || !session_id || !log_id) {
|
|
return res.status(400).json({
|
|
status: 'error',
|
|
message: 'app user id and session id and log id are required',
|
|
});
|
|
}
|
|
|
|
// Query to toggle the is_liked value
|
|
const toggleQuery = `
|
|
UPDATE interaction_logs
|
|
SET is_flagged = NOT is_flagged
|
|
WHERE app_user_id = ? AND session_id = ? AND id = ?
|
|
|
|
`;
|
|
|
|
// Execute the query
|
|
const result = await db.query(toggleQuery, [app_user_id, session_id,log_id]);
|
|
|
|
// Check if any rows were affected
|
|
if (result.affectedRows > 0) {
|
|
return res.status(200).json({
|
|
status: 'success',
|
|
message: 'Updated successfully',
|
|
data: {
|
|
app_user_id,
|
|
session_id
|
|
},
|
|
});
|
|
} else {
|
|
return res.status(404).json({
|
|
status: 'error',
|
|
message: 'No matching record found to toggle',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error during like toggle:', error);
|
|
return res.status(500).json({
|
|
status: 'error',
|
|
message: 'Internal server error',
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.addReportText = async (req, res) => {
|
|
try {
|
|
const { session_id, report_text } = req.body;
|
|
const app_user_id = req.user.id;
|
|
|
|
// Validate input
|
|
if (!app_user_id || !session_id || typeof report_text !== 'string') {
|
|
return res.status(400).json({
|
|
status: 'error',
|
|
message: 'app_user_id, session_id, logid, and report_text are required',
|
|
});
|
|
}
|
|
|
|
// Update query
|
|
const updateQuery = `
|
|
UPDATE interaction_logs
|
|
SET report_text = ?
|
|
WHERE app_user_id = ? AND session_id = ?
|
|
`;
|
|
|
|
// Execute update
|
|
const result = await db.query(updateQuery, [report_text, app_user_id, session_id]);
|
|
|
|
// Handle response
|
|
if (result.affectedRows > 0) {
|
|
return res.status(200).json({
|
|
status: 'success',
|
|
message: 'Session reported successfully. Admin will review your report',
|
|
data: {
|
|
app_user_id,
|
|
session_id,
|
|
report_text
|
|
},
|
|
});
|
|
} else {
|
|
return res.status(404).json({
|
|
status: 'error',
|
|
message: 'No matching record found to update report text',
|
|
});
|
|
}
|
|
} catch (error) {
|
|
console.error('Error updating report text:', error);
|
|
return res.status(500).json({
|
|
status: 'error',
|
|
message: 'Internal server error',
|
|
});
|
|
}
|
|
};
|
|
|
|
exports.updateChecked = async (req,res) =>{
|
|
try {
|
|
const app_user_id = req.params.id;
|
|
if (!["Admin", 8].includes(req.user.role)) {
|
|
return res.status(403).json({ error: "Unauthorized to acknowledge" });
|
|
}
|
|
|
|
const updateQuery = `
|
|
UPDATE app_users
|
|
SET checked = ?
|
|
WHERE id = ?
|
|
`;
|
|
const result = await db.query(updateQuery, [1, app_user_id]);
|
|
if (result.affectedRows > 0) {
|
|
return res.status(200).json({
|
|
status: 'success',
|
|
message: 'Acknowledged successfully',
|
|
|
|
});
|
|
} else {
|
|
return res.status(404).json({
|
|
status: 'error',
|
|
message: 'No matching record found to update checked',
|
|
});
|
|
}
|
|
|
|
|
|
} catch (error) {
|
|
console.error("Error updating checked:", error);
|
|
return res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|
|
|
|
|
|
exports.signup = async (req, res) => {
|
|
try {
|
|
const { pin, pin_status,remember_me, email, password, hospital_code, username } = req.body;
|
|
|
|
if (!email || !password || !hospital_code || !username) {
|
|
return res.status(400).json({
|
|
error: "Email, password, username, and hospital code are required",
|
|
});
|
|
}
|
|
|
|
const pin_enabled = (pin_status === undefined || pin_status === '') ? 0 : pin_status;
|
|
const remember_me_ = (remember_me === undefined || remember_me === '') ? 0 : remember_me;
|
|
|
|
// Check if the hospital_code exists in the `hospitals` table
|
|
const hospitalQuery =
|
|
"SELECT hospital_code FROM hospitals WHERE hospital_code = ?";
|
|
const hospitalResult = await db.query(hospitalQuery, [hospital_code]);
|
|
|
|
if (hospitalResult.length === 0) {
|
|
return res.status(404).json({ error: "Invalid hospital code" });
|
|
}
|
|
|
|
// Check if the email is already in use
|
|
const userQuery = "SELECT id FROM app_users WHERE email = ?";
|
|
const userResult = await db.query(userQuery, [email]);
|
|
|
|
if (userResult.length > 0) {
|
|
return res.status(400).json({ error: "Email already in use" });
|
|
}
|
|
|
|
// Check if a file was uploaded
|
|
if (!req.file) {
|
|
return res.status(400).json({ error: "ID photo url is required" });
|
|
}
|
|
// Hash the password
|
|
const hashPassword = await bcrypt.hash(password, 10);
|
|
|
|
// Insert the new app user into the `app_users` table
|
|
const insertQuery = `
|
|
INSERT INTO app_users (email, hash_password, hospital_code, status, username, pin_number, pin_enabled, remember_me )
|
|
VALUES (?, ?, ?, 'Pending', ?, ?, ?,?)
|
|
`;
|
|
const result = await db.query(insertQuery, [
|
|
email,
|
|
hashPassword,
|
|
hospital_code,
|
|
username,
|
|
pin, // Set pin to null if not provided
|
|
pin_enabled,
|
|
remember_me_
|
|
]);
|
|
|
|
const userId = result.insertId; // Get the new user's ID
|
|
|
|
|
|
|
|
const filePath = `/uploads/id_photos/${req.file.filename}`; // Correct file path
|
|
|
|
// Update the ID photo path in the database
|
|
await db.query(
|
|
"UPDATE app_users SET id_photo_url = ?, upload_status = ? WHERE id = ?",
|
|
[filePath, "1", userId]
|
|
);
|
|
|
|
// ✅ Notify hospitals in the SECONDARY WebSocket instance
|
|
emitEvent("new_user", {
|
|
message: `A new user has been created for hospital ${hospital_code}.`,
|
|
user: { id: userId, username, email, hospital_code: hospital_code },
|
|
});
|
|
|
|
res.status(201).json({
|
|
message: "User signed up and ID photo uploaded successfully!",
|
|
data: {
|
|
id: userId,
|
|
email,
|
|
hospital_code,
|
|
username,
|
|
id_photo_url: filePath,
|
|
pin: pin || null,
|
|
pin_status : pin_status,
|
|
remember_me: remember_me
|
|
},
|
|
});
|
|
|
|
} catch (error) {
|
|
console.error("Error during signup and ID photo upload:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.login = async (req, res) => {
|
|
try {
|
|
const { email, password } = req.body;
|
|
let remember_me;
|
|
|
|
if (!email || !password) {
|
|
return res.status(400).json({ error: "Email and password are required" });
|
|
}
|
|
|
|
console.log("email----",email)
|
|
// Check if the user exists
|
|
const query = "SELECT * FROM app_users WHERE email = ?";
|
|
const result = await db.query(query, [email]);
|
|
|
|
console.log("result---",result)
|
|
if (result.length === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const user = result[0];
|
|
remember_me = user.remember_me
|
|
|
|
console.log("user-data----------------------",user);
|
|
|
|
const hospitalData = await db.query("SELECT * FROM hospitals WHERE hospital_code = ?", [user.hospital_code]);
|
|
// if (hospitalData.publicSignupEnabled) {
|
|
// throw new Error("Hospital not found");
|
|
// }
|
|
|
|
console.log("hospitalData---",hospitalData)
|
|
|
|
let actual_status;
|
|
actual_status = user.status
|
|
if(hospitalData[0].publicSignupEnabled){
|
|
user.status = "Active"
|
|
}
|
|
|
|
if (user.status === "Pending" && !hospitalData[0].publicSignupEnabled) {
|
|
return res.status(404).json({ error: "Your Account is Under Review" });
|
|
|
|
}
|
|
|
|
if (user.status === "Inactive" && !hospitalData[0].publicSignupEnabled) {
|
|
return res.status(404).json({ error: "Contact admin your account is not approved" });
|
|
|
|
}
|
|
|
|
|
|
// Validate the password
|
|
const validPassword = await bcrypt.compare(password, user.hash_password);
|
|
if (!validPassword) {
|
|
return res.status(401).json({ error: "Invalid email or password" });
|
|
}
|
|
|
|
// Determine expiry based on remember_me
|
|
let expiresIn = "5h";
|
|
let expiryTimestamp = new Date();
|
|
let rememberMeValue = remember_me;
|
|
if (rememberMeValue === undefined) rememberMeValue = user.remember_me;
|
|
if (rememberMeValue === true || rememberMeValue === 1 || rememberMeValue === "1" || rememberMeValue === "true") {
|
|
const updateQuery = `
|
|
UPDATE app_users
|
|
SET remember_me = ?
|
|
WHERE id = ?
|
|
`;
|
|
await db.query(updateQuery, [remember_me,user.id]);
|
|
|
|
expiresIn = "30d";
|
|
expiryTimestamp.setDate(expiryTimestamp.getDate() + 30);
|
|
} else {
|
|
expiryTimestamp.setHours(expiryTimestamp.getHours() + 5);
|
|
}
|
|
|
|
// Generate a new access token
|
|
const payload = { id: user.id, email: user.email, role: "AppUser" };
|
|
const accessToken = jwt.sign(payload, process.env.JWT_ACCESS_TOKEN_SECRET, {
|
|
expiresIn: expiresIn,
|
|
});
|
|
|
|
// SQL query to fetch hospital data based on the provided hospital_code
|
|
const query_hospital = `
|
|
SELECT * FROM hospitals WHERE hospital_code = ?;
|
|
`;
|
|
|
|
// Run the query
|
|
const result_hospital = await db.query(query_hospital, [user.hospital_code]);
|
|
|
|
// hospital users
|
|
const queryHospitalUsr = `
|
|
SELECT * FROM hospital_users WHERE hospital_code = ?;
|
|
`;
|
|
|
|
// Run the query
|
|
const resultHospitalUsr = await db.query(queryHospitalUsr, [user.hospital_code]);
|
|
|
|
const hospitalUser = resultHospitalUsr[0];
|
|
if (!hospitalUser) {
|
|
return res.status(404).json({ error: "Hospital user not found" });
|
|
}
|
|
// Update the access token and expiry in the database
|
|
const updateQuery = `
|
|
UPDATE app_users
|
|
SET access_token = ?, access_token_expiry = ?, remember_me = ?
|
|
WHERE id = ?
|
|
`;
|
|
await db.query(updateQuery, [accessToken, expiryTimestamp, (rememberMeValue === true || rememberMeValue === 1 || rememberMeValue === "1" || rememberMeValue === "true") ? 1 : 0, user.id]);
|
|
|
|
|
|
// Send response
|
|
res.status(200).json({
|
|
message: "Login successful",
|
|
user: {
|
|
id: user.id,
|
|
email: user.email,
|
|
pin: user.pin_number,
|
|
pin_enabled: user.pin_enabled,
|
|
hospital_code: user.hospital_code,
|
|
hospital_id : hospitalData[0].id,
|
|
status: user.status,
|
|
actualStatus: actual_status,
|
|
hospital_name: result_hospital[0].name_hospital,
|
|
primary_color: result_hospital[0].primary_color,
|
|
secondary_color: result_hospital[0].secondary_color,
|
|
upload_status: user.upload_status,
|
|
id_photo_url: user.id_photo_url,
|
|
primary_admin_email: result_hospital[0].primary_admin_email,
|
|
mobile_number: result_hospital[0].mobile_number,
|
|
username: user.username,
|
|
logo_url: resultHospitalUsr[0].profile_photo_url,
|
|
query_title: user.query_title,
|
|
remember_me: (rememberMeValue === true || rememberMeValue === 1 || rememberMeValue === "1" || rememberMeValue === "true") ? 1 : 0
|
|
},
|
|
accessToken,
|
|
});
|
|
|
|
|
|
} catch (error) {
|
|
console.error("Error during login:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.checkPin = async (req, res) => {
|
|
try {
|
|
const { email, pin } = req.body;
|
|
|
|
if (!email || !pin) {
|
|
return res.status(400).json({ error: "Email and Pin are required" });
|
|
}
|
|
|
|
// Check if the user exists
|
|
const query = "SELECT * FROM app_users WHERE email = ?";
|
|
const result = await db.query(query, [email]);
|
|
|
|
if (result.length === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const user = result[0];
|
|
|
|
const hospitalData = await db.query("SELECT * FROM hospitals WHERE hospital_code = ?", [user.hospital_code]);
|
|
|
|
|
|
|
|
|
|
if (user.status === "Pending" && !hospitalData[0].publicSignupEnabled) {
|
|
throw new Error("Your Account is Under Review");
|
|
}
|
|
|
|
if (user.status === "Inactive" && !hospitalData[0].publicSignupEnabled) {
|
|
throw new Error("Contact admin your account is not approved");
|
|
}
|
|
// Check PIN if PIN status is enabled
|
|
if (pin !== user.pin_number) {
|
|
return res.status(401).json({
|
|
error: "Invalid PIN",
|
|
requires_pin: true,
|
|
message: "Incorrect PIN. Please try again"
|
|
});
|
|
}
|
|
|
|
// Send response
|
|
res.status(200).json({
|
|
message: "Pin verified successfully",
|
|
});
|
|
} catch (error) {
|
|
console.error("Error during login:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.logout = async (req, res) => {
|
|
try {
|
|
const userId = req.user.id; // Assuming the user is authenticated via middleware
|
|
|
|
// Check if the user exists
|
|
const query = "SELECT * FROM app_users WHERE id = ?";
|
|
const result = await db.query(query, [userId]);
|
|
|
|
if (result.length === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
// Invalidate the access token in the database
|
|
const updateQuery = `
|
|
UPDATE app_users
|
|
SET access_token = NULL, access_token_expiry = NULL
|
|
WHERE id = ?
|
|
`;
|
|
await db.query(updateQuery, [userId]);
|
|
|
|
res.status(200).json({ message: "Logout successful" });
|
|
} catch (error) {
|
|
console.error("Error during logout:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
// controller.js
|
|
exports.getAppUsersByHospitalCode = async (req, res) => {
|
|
try {
|
|
// Extract the hospital_code from the token (req.user object)
|
|
const userId = req.user.id;
|
|
|
|
if (!userId) {
|
|
return res.status(400).json({ error: "User not found for the token" });
|
|
}
|
|
|
|
// Query to fetch hospital users based on the hospital_code
|
|
const query = `
|
|
SELECT id, email, status,hospital_code
|
|
FROM app_users
|
|
WHERE id = ?;
|
|
`;
|
|
const result = await db.query(query, [userId]);
|
|
|
|
if (result.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ error: "No users found for the specified Token" });
|
|
}
|
|
|
|
const hospitalData = await db.query("SELECT * FROM hospitals WHERE hospital_code = ?", [result[0].hospital_code]);
|
|
if(hospitalData[0].publicSignupEnabled){
|
|
result[0].status = 'Active'
|
|
}
|
|
// Send the response with the users data
|
|
res.status(200).json({
|
|
message: "Hospital users fetched successfully",
|
|
user: result[0],
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching hospital users:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.approveUserId = async (req, res) => {
|
|
try {
|
|
const appUserId = req.params.id; // App user ID to approve
|
|
const { role } = req.user; // Authenticated user's details
|
|
const { Action } = req.body;
|
|
|
|
const { hospital_code } = req.user;
|
|
|
|
if (!req.body.Action) {
|
|
return res.status(400).json({ error: "Action is required" });
|
|
}
|
|
|
|
if (!["Superadmin", "Admin", 8].includes(role)) {
|
|
return res.status(403).json({ error: "Unauthorized to approve IDs" });
|
|
}
|
|
|
|
const query = `
|
|
SELECT hospital_code FROM app_users WHERE id = ? AND hospital_code = ?
|
|
`;
|
|
|
|
const result = await db.query(query, [appUserId, hospital_code]);
|
|
|
|
if (result.length === 0) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "User does not belong to your hospital" });
|
|
}
|
|
|
|
// Approve the ID
|
|
if (Action == "Reject") {
|
|
await db.query('UPDATE app_users SET status = "Inactive" WHERE id = ?', [
|
|
appUserId,
|
|
]);
|
|
res.status(200).json({ message: "ID Rejected successfully" });
|
|
} else if (Action == "Approve") {
|
|
await db.query('UPDATE app_users SET status = "Active" WHERE id = ?', [
|
|
appUserId,
|
|
]);
|
|
res.status(200).json({ message: "ID approved successfully" });
|
|
}
|
|
} catch (error) {
|
|
console.error("Error approving ID:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.getAppUsers = async (req, res) => {
|
|
try {
|
|
const { role } = req.user;
|
|
// Ensure the user has the proper role
|
|
if (!["Superadmin", "Admin", 9, 8].includes(role)) {
|
|
return res.status(403).json({ error: "Unauthorized to view app users" });
|
|
}
|
|
|
|
// Query to fetch app users
|
|
const query = `
|
|
SELECT * FROM app_users;
|
|
`;
|
|
|
|
const users = await db.query(query);
|
|
|
|
if (users.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ message: "No app users found for this hospital" });
|
|
}
|
|
|
|
res.status(200).json({
|
|
message: "App users fetched successfully",
|
|
data: users,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching app users:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.getAppUserByHospitalId = async (req, res) => {
|
|
try {
|
|
const { role } = req.user;
|
|
const { id } = req.params; // Extract user ID from request parameters
|
|
// Log authenticated user details
|
|
|
|
// Ensure the user has the proper role
|
|
if (!["Superadmin", "Admin", 8, 9].includes(role)) {
|
|
return res.status(403).json({ error: "Unauthorized to view app users" });
|
|
}
|
|
|
|
// fetching hospital code from hospital id
|
|
const query1 = `SELECT * FROM hospitals WHERE id = ?`;
|
|
const result1 = await db.query(query1, [id]);
|
|
const hospital_code = result1[0].hospital_code;
|
|
console.log("result1----", result1);
|
|
|
|
// Query to fetch the app user by hospital_code
|
|
const query = `SELECT * FROM app_users WHERE hospital_code = ?`;
|
|
const users = await db.query(query, [hospital_code]);
|
|
|
|
if (users.length === 0) {
|
|
return res.status(404).json({ message: "App users not found" });
|
|
}
|
|
|
|
res.status(200).json({
|
|
message: "App user fetched successfully",
|
|
data: users, // Return single user object
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching app user:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.deleteAppUser = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { hospital_code } = req.user;
|
|
|
|
// Check if the user exists
|
|
const appUserquery = "SELECT * FROM app_users WHERE id = ?";
|
|
const users = await db.query(appUserquery, [id]);
|
|
|
|
if (users.length === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ message: "No app users found for this hospital" });
|
|
}
|
|
|
|
// Ensure only Admin or Superadmin can delete users
|
|
if (!["Admin", "Superadmin", 8, 7,"AppUser"].includes(req.user.role)) {
|
|
return res.status(403).json({ error: "Unauthorized to delete users" });
|
|
}
|
|
|
|
// Ensure user belongs to the same hospital
|
|
const query =
|
|
"SELECT hospital_code,id_photo_url FROM app_users WHERE id = ? AND hospital_code = ?";
|
|
|
|
const result = await db.query(query, [id, hospital_code]);
|
|
|
|
if (!result || result.length === 0) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "User does not belong to your hospital" });
|
|
}
|
|
|
|
// Unlink (delete) the associated file if it exists and is not null
|
|
if (result[0].id_photo_url) {
|
|
const filePath = path.join(__dirname, '..','..', 'uploads', result[0].id_photo_url.replace(/^\/uploads\//, ''));
|
|
|
|
fs.access(filePath, fs.constants.F_OK, (err) => {
|
|
if (err) {
|
|
console.error(`File not found: ${filePath}`);
|
|
return;
|
|
}
|
|
|
|
fs.unlink(filePath, (err) => {
|
|
if (err) {
|
|
console.error('Error deleting file:', err.message);
|
|
} else {
|
|
console.log('File deleted successfully:', filePath);
|
|
}
|
|
});
|
|
});
|
|
} else {
|
|
console.log('No file to delete - id_photo_url is null');
|
|
}
|
|
|
|
// delete feedback
|
|
await db.query(
|
|
'DELETE FROM feedback WHERE sender_type = ? AND sender_id = ?',
|
|
['appuser', id] // Fixed: should be 'id' not 'req.user.id'
|
|
);
|
|
|
|
// Delete the user
|
|
const deleteResult = await db.query("DELETE FROM app_users WHERE id = ?", [
|
|
id,
|
|
]);
|
|
|
|
if (deleteResult.affectedRows === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
res.status(200).json({ message: "User deleted successfully" });
|
|
} catch (error) {
|
|
console.error("Error deleting user:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
// query title CRUD
|
|
exports.updateQueryTitle = async (req, res) => {
|
|
const id = req.user.id;
|
|
const { query_title } = req.body;
|
|
|
|
if (!query_title) {
|
|
return res.status(400).json({ error: "query_title is required" });
|
|
}
|
|
|
|
try {
|
|
const result = await db.query(
|
|
"UPDATE app_users SET query_title = ? WHERE id = ?",
|
|
[query_title, id]
|
|
);
|
|
|
|
if (result.affectedRows === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
res.json({ message: "Query title updated successfully" });
|
|
} catch (error) {
|
|
console.error("Error updating query title:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
// Delete query_title for a user by user ID
|
|
|
|
exports.getShortTitle = (req, res) => {
|
|
const { question } = req.body;
|
|
|
|
console.log("Question: ", question);
|
|
if (!question) return res.status(400).json({ error: "No question provided" });
|
|
|
|
let shortTitle = nlp(question).sentences().toTitleCase().out("text");
|
|
|
|
// Remove unnecessary question words
|
|
shortTitle = shortTitle
|
|
.replace(
|
|
/^(What|How|Why|When|Where|Which|Who|Is|Are|Do|Does|Can|Could)\s+/i,
|
|
""
|
|
)
|
|
.trim();
|
|
|
|
if (!shortTitle)
|
|
return res.status(400).json({ error: "Invalid question format" });
|
|
|
|
console.log("short question:", shortTitle);
|
|
|
|
res.json({ query_title: shortTitle });
|
|
};
|
|
|
|
exports.deleteQueryTitle = async (req, res) => {
|
|
const id = req.user.id;
|
|
|
|
try {
|
|
const result = await db.query(
|
|
"UPDATE app_users SET query_title = NULL WHERE id = ?",
|
|
[id]
|
|
);
|
|
|
|
if (result.affectedRows === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
res.json({ message: "Query title deleted successfully" });
|
|
} catch (error) {
|
|
console.error("Error deleting query title:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.sendOtp = async (req, res) => {
|
|
try {
|
|
const { email } = req.body;
|
|
|
|
// Validate email input
|
|
if (!email) {
|
|
return res.status(400).json({ error: "Email is required" });
|
|
}
|
|
|
|
// Check if user exists
|
|
const user = await db.query(
|
|
"SELECT id, username, hospital_code FROM app_users WHERE email = ?",
|
|
[email]
|
|
);
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
console.log("user", user);
|
|
const userId = user[0].id;
|
|
const hospital_code = user[0].hospital_code;
|
|
|
|
// fetch hospital name of app_user
|
|
const hospital = await db.query(
|
|
"SELECT name_hospital FROM hospitals WHERE hospital_code = ?",
|
|
[hospital_code]
|
|
);
|
|
|
|
console.log("hospital result : ", hospital[0].name_hospital);
|
|
// Generate a 6-digit OTP
|
|
const otp = Math.floor(100000 + Math.random() * 900000).toString();
|
|
const expiresAt = new Date(Date.now() + 2 * 60 * 60 * 1000); // OTP expires in 1 hour
|
|
|
|
console.log("otp : ", otp, "expiresAt: ", expiresAt);
|
|
// Store OTP in database
|
|
await db.query(
|
|
"UPDATE app_users SET otp_code = ?, otp_expires_at = ? WHERE id = ?",
|
|
[otp, expiresAt, userId]
|
|
);
|
|
|
|
// // Send OTP via email
|
|
const info = await sendMail(
|
|
email,
|
|
hospital[0].name_hospital,
|
|
user[0].username,
|
|
otp
|
|
);
|
|
|
|
res.json({ message: "OTP sent successfully", email_status: info.response });
|
|
} catch (error) {
|
|
console.error("Error sending OTP:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.changePassword = async (req, res) => {
|
|
try {
|
|
const { email, otp, new_password } = req.body;
|
|
|
|
console.log("email : ", email);
|
|
// Validate inputs
|
|
if (!email || !otp || !new_password) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "Email, OTP, and new password are required" });
|
|
}
|
|
|
|
// Fetch OTP from the database
|
|
const user = await db.query(
|
|
"SELECT id, otp_code, otp_expires_at FROM app_users WHERE email = ?",
|
|
[email]
|
|
);
|
|
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const userData = user[0];
|
|
|
|
// ✅ Check if OTP matches
|
|
if (userData.otp_code !== otp) {
|
|
return res.status(400).json({ error: "Invalid OTP" });
|
|
}
|
|
|
|
// ✅ Check if OTP is expired
|
|
if (new Date() > new Date(userData.otp_expires_at)) {
|
|
return res.status(400).json({ error: "OTP expired. Request a new one." });
|
|
}
|
|
|
|
// ✅ Hash the new password
|
|
const hashedPassword = await bcrypt.hash(new_password, 10);
|
|
|
|
// ✅ Update password in DB & clear OTP
|
|
await db.query(
|
|
"UPDATE app_users SET hash_password = ?, otp_code = NULL, otp_expires_at = NULL WHERE id = ?",
|
|
[hashedPassword, userData.id]
|
|
);
|
|
|
|
res.json({ message: "Password changed successfully!" });
|
|
} catch (error) {
|
|
console.error("Error resetting password:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.sendPinOtp = async (req, res) => {
|
|
try {
|
|
const { email } = req.body;
|
|
|
|
// Validate email input
|
|
if (!email) {
|
|
return res.status(400).json({ error: "Email is required" });
|
|
}
|
|
|
|
// Check if user exists
|
|
const user = await db.query(
|
|
"SELECT id, username, hospital_code FROM app_users WHERE email = ?",
|
|
[email]
|
|
);
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
console.log("user", user);
|
|
const userId = user[0].id;
|
|
const hospital_code = user[0].hospital_code;
|
|
|
|
// fetch hospital name of app_user
|
|
const hospital = await db.query(
|
|
"SELECT name_hospital FROM hospitals WHERE hospital_code = ?",
|
|
[hospital_code]
|
|
);
|
|
|
|
console.log("hospital result : ", hospital[0].name_hospital);
|
|
// Generate a 6-digit OTP
|
|
const otp = Math.floor(100000 + Math.random() * 900000).toString();
|
|
const expiresAt = new Date(Date.now() + 2 * 60 * 60 * 1000); // OTP expires in 1 hour
|
|
|
|
console.log("otp : ", otp, "expiresAt: ", expiresAt);
|
|
// Store OTP in database
|
|
await db.query(
|
|
"UPDATE app_users SET pin_otp = ?, pin_otp_expiry = ? WHERE id = ?",
|
|
[otp, expiresAt, userId]
|
|
);
|
|
|
|
// // Send OTP via email
|
|
const info = await sendMail(
|
|
email,
|
|
hospital[0].name_hospital,
|
|
user[0].username,
|
|
otp
|
|
);
|
|
|
|
res.json({ message: "OTP sent successfully", email_status: info.response });
|
|
} catch (error) {
|
|
console.error("Error sending OTP:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.changePinByOtp = async (req, res) => {
|
|
try {
|
|
const { email, otp, new_pin } = req.body;
|
|
|
|
console.log("email : ", email);
|
|
// Validate inputs
|
|
if (!email || !otp || !new_pin) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "Email, OTP, and new pin are required" });
|
|
}
|
|
|
|
// Fetch OTP from the database
|
|
const user = await db.query(
|
|
"SELECT id, pin_otp, pin_otp_expiry FROM app_users WHERE email = ?",
|
|
[email]
|
|
);
|
|
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const userData = user[0];
|
|
|
|
// ✅ Check if OTP matches
|
|
if (userData.pin_otp !== otp) {
|
|
return res.status(400).json({ error: "Invalid OTP" });
|
|
}
|
|
|
|
// ✅ Check if OTP is expired
|
|
if (new Date() > new Date(userData.otp_expires_at)) {
|
|
return res.status(400).json({ error: "OTP expired. Request a new one." });
|
|
}
|
|
|
|
// ✅ Hash the new password
|
|
|
|
// ✅ Update password in DB & clear OTP
|
|
await db.query(
|
|
"UPDATE app_users SET pin_number = ?, pin_otp = NULL, pin_otp_expiry = NULL WHERE id = ?",
|
|
[new_pin, userData.id]
|
|
);
|
|
|
|
res.json({ message: "Pin changed successfully!" });
|
|
} catch (error) {
|
|
console.error("Error resetting pin:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
|
|
|
|
async function sendMail(email, hospital_name, username, otp) {
|
|
const mailOptions = {
|
|
from: "kavya.j@tech4biz.io", // Sender's email
|
|
to: email, // Recipient's email
|
|
subject: "Spurrinai Login Credentials", // Email subject
|
|
html: `<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Reset Your Password or Pin - Spurrinai Medical Platform</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Syne:wght@400..800&display=swap');
|
|
|
|
body {
|
|
font-family: 'Inter', sans-serif;
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: #ebf3fa;
|
|
color: #333;
|
|
}
|
|
.email-container {
|
|
max-width: 600px;
|
|
margin: 20px auto;
|
|
background: white;
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
|
|
}
|
|
.email-header {
|
|
background: linear-gradient(135deg, #2193b0, #6dd5ed);
|
|
padding: 30px;
|
|
text-align: center;
|
|
color: white;
|
|
}
|
|
.hospital-name {
|
|
display: inline-block;
|
|
background-color: rgba(255, 255, 255, 0.2);
|
|
padding: 5px 15px;
|
|
border-radius: 20px;
|
|
font-size: 14px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.email-header h1 {
|
|
margin: 10px 0 0;
|
|
font-size: 26px;
|
|
font-weight: 500;
|
|
}
|
|
.email-content {
|
|
padding: 40px 30px;
|
|
}
|
|
.greeting {
|
|
font-size: 30px;
|
|
font-weight: 700;
|
|
margin-bottom: 20px;
|
|
color: #303030;
|
|
}
|
|
.greeting-text{
|
|
font-size: 18px;
|
|
font-weight: 400;
|
|
margin-bottom: 20px;
|
|
line-height: 1.7;
|
|
color: #303030;
|
|
}
|
|
.verification-code {
|
|
background-color: #f5f9fc;
|
|
border: 1px solid #e0e9f0;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 25px 0;
|
|
text-align: center;
|
|
}
|
|
.code {
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 32px;
|
|
letter-spacing: 6px;
|
|
color: #2193b0;
|
|
font-weight: bold;
|
|
padding: 10px 0;
|
|
}
|
|
.reset-button {
|
|
display: block;
|
|
background-color: #2193b0;
|
|
color: white;
|
|
text-decoration: none;
|
|
text-align: center;
|
|
padding: 15px 20px;
|
|
border-radius: 5px;
|
|
margin: 30px auto;
|
|
max-width: 250px;
|
|
font-weight: 500;
|
|
transition: background-color 0.3s;
|
|
}
|
|
.reset-button:hover {
|
|
background-color: #1a7b92;
|
|
}
|
|
.expiry-note {
|
|
background-color: #fff8e1;
|
|
border-left: 4px solid #ffc107;
|
|
padding: 12px 15px;
|
|
margin: 25px 0;
|
|
font-size: 14px;
|
|
color: #856404;
|
|
}
|
|
.security-note {
|
|
margin-top: 30px;
|
|
padding-top: 20px;
|
|
border-top: 1px solid #eee;
|
|
font-size: 14px;
|
|
color: #666;
|
|
}
|
|
.email-footer {
|
|
background-color: #f5f9fc;
|
|
padding: 20px;
|
|
text-align: center;
|
|
font-size: 13px;
|
|
color: #888;
|
|
border-top: 1px solid #e0e9f0;
|
|
}
|
|
.support-link {
|
|
color: #2193b0;
|
|
text-decoration: none;
|
|
}
|
|
.device-info {
|
|
margin-top: 20px;
|
|
background-color: #f5f9fc;
|
|
padding: 15px;
|
|
border-radius: 6px;
|
|
font-size: 14px;
|
|
}
|
|
.device-info p {
|
|
margin: 5px 0;
|
|
color: #666;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="email-container">
|
|
<div class="email-header">
|
|
<div class="hospital-name"> ${hospital_name}</div>
|
|
<h1>Reset Your Password or Pin</h1>
|
|
</div>
|
|
<div class="email-content">
|
|
<div class="greeting">Hello ${username},</div>
|
|
|
|
<p class="greeting-text" >We received a request to <strong>reset the password</strong> for your account on the <strong> Spurrinai healthcare platform</strong>. For your security reasons, please verify this action.</p>
|
|
|
|
<div class="verification-code">
|
|
<p>Please enter this verification code:</p>
|
|
<div class="code">${otp}</div>
|
|
<p>on the password reset screen</p>
|
|
</div>
|
|
|
|
<a href="spurrinai://ResetPassword/${otp}" class="reset-button">Reset Password</a>
|
|
|
|
<div class="expiry-note">
|
|
<strong>Note:</strong> This verification code will expire in 2 hours for security reasons.
|
|
</div>
|
|
|
|
|
|
|
|
<div class="security-note">
|
|
<p>If you did not request this password reset, please contact our IT security team immediately at <a href="mailto:info@spurrinai.com" class="support-link">info@spurrinai.com</a> or call our support line at +1 (800) 555-1234.</p>
|
|
</div>
|
|
</div>
|
|
<div class="email-footer">
|
|
<p>© 2025 Spurrinai - Healthcare Data Management Platform</p>
|
|
<p>This is an automated message. Please do not reply to this email.</p>
|
|
<p>Need help? Contact <a href="mailto:support@spurrinai.com" class="support-link">support@spurrinai.com</a></p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>`,
|
|
};
|
|
|
|
try {
|
|
const info = await transporter.sendMail(mailOptions);
|
|
console.log("info: ", info);
|
|
return info;
|
|
} catch (error) {
|
|
console.error(`Error sending email to ${email}:`, error);
|
|
return error;
|
|
}
|
|
}
|
|
|
|
// chat-sessions
|
|
exports.getChatSessionsByAppUserID = async (req, res) => {
|
|
try {
|
|
|
|
console.log("user data", req.user)
|
|
const { role } = req.user;
|
|
// Ensure the user has the proper role
|
|
// if (!['Superadmin', 'Admin', 9, 8].includes(role)) {
|
|
// return res.status(403).json({ error: 'Unauthorized to view chats' });
|
|
// }
|
|
|
|
if (!req.user.id) {
|
|
return res.status(400).json({ error: "user id not found" });
|
|
}
|
|
// Query to fetch app users
|
|
const query = `
|
|
SELECT session_id,
|
|
MIN(session_title) AS session_title,
|
|
MIN(created_at) AS created_at
|
|
FROM interaction_logs
|
|
WHERE app_user_id = ${req.user.id}
|
|
AND session_id IS NOT NULL
|
|
GROUP BY session_id
|
|
ORDER BY session_id DESC;
|
|
`;
|
|
|
|
|
|
const session_ids = await db.query(query);
|
|
|
|
if (session_ids.length === 0) {
|
|
return res.status(404).json({ message: 'No interaction logs found for this app user', data: session_ids });
|
|
}
|
|
|
|
res.status(200).json({
|
|
message: 'Interaction logs fetched successfully',
|
|
data: session_ids,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error fetching interaction logs:', error.message);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
}
|
|
|
|
exports.getChatForEachSession = async (req, res) => {
|
|
try {
|
|
|
|
console.log("user data", req.user)
|
|
const session_id = req.params.session_id;
|
|
|
|
console.log("session_id ", session_id)
|
|
// Ensure the user has the proper role
|
|
// if (!['Superadmin', 'Admin', 9, 8].includes(role)) {
|
|
// return res.status(403).json({ error: 'Unauthorized to view chats' });
|
|
// }
|
|
|
|
if (!req.user.id) {
|
|
return res.status(400).json({ error: "user id not found" });
|
|
}
|
|
// Query to fetch app users
|
|
const query = `
|
|
SELECT * FROM interaction_logs
|
|
WHERE app_user_id = ?
|
|
AND session_id = ?
|
|
AND status = 'Active';
|
|
`;
|
|
|
|
|
|
const values = [req.user.id, session_id];
|
|
|
|
const interaction_logs = await db.query(query, values);
|
|
|
|
if (interaction_logs.length === 0) {
|
|
return res.status(404).json({ message: 'No interaction logs found for this app user or session', data: interaction_logs });
|
|
}
|
|
|
|
res.status(200).json({
|
|
message: 'Interaction logs fetched successfully',
|
|
data: interaction_logs,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error fetching interaction logs:', error.message);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
}
|
|
|
|
exports.deleteChatSessions = async (req, res) => {
|
|
const id = req.user.id;
|
|
const { session_id } = req.body
|
|
|
|
console.log("session_id ", session_id)
|
|
console.log("app_user_id ", id)
|
|
|
|
try {
|
|
const result = await db.query(
|
|
"UPDATE interaction_logs SET session_id = NULL WHERE app_user_id = ? AND session_id = ?",
|
|
[id, session_id]
|
|
);
|
|
|
|
if (result.affectedRows === 0) {
|
|
return res.status(404).json({ error: "No session found" });
|
|
}
|
|
|
|
res.json({ message: "Chat session deleted successfully" });
|
|
} catch (error) {
|
|
console.error("Error deleting query title:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|
|
|
|
exports.clearChatbasedOnSessions = async (req, res) => {
|
|
const id = req.user.id;
|
|
const { session_id } = req.body
|
|
|
|
try {
|
|
const result = await db.query(
|
|
"UPDATE interaction_logs SET status = ? WHERE app_user_id = ? AND session_id = ?",
|
|
['Inactive', id, session_id]
|
|
);
|
|
|
|
if (result.affectedRows === 0) {
|
|
return res.status(404).json({ error: "No chat found" });
|
|
}
|
|
|
|
res.json({ message: "Chat deleted successfully" });
|
|
} catch (error) {
|
|
console.error("Error deleting chat:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|
|
|
|
exports.getChatByTime = async (req, res) => {
|
|
try {
|
|
|
|
console.log("user data", req.user)
|
|
const { lastcreated_at } = req.body;
|
|
|
|
// Ensure the user has the proper role
|
|
// if (!['Superadmin', 'Admin', 9, 8].includes(role)) {
|
|
// return res.status(403).json({ error: 'Unauthorized to view chats' });
|
|
// }
|
|
|
|
if (!req.user.id) {
|
|
return res.status(400).json({ error: "user id not found" });
|
|
}
|
|
// Query to fetch app users
|
|
|
|
let results
|
|
|
|
console.log("last created at", lastcreated_at)
|
|
if (!lastcreated_at) { // Handles null, undefined, empty string, etc.
|
|
|
|
const query = `
|
|
SELECT * FROM interaction_logs
|
|
WHERE app_user_id = ?;
|
|
`;
|
|
|
|
results = await db.query(query, [req.user.id]);
|
|
} else {
|
|
console.log("Executing with last_created_at:", lastcreated_at);
|
|
|
|
const query = `
|
|
SELECT * FROM interaction_logs
|
|
WHERE app_user_id = ?
|
|
AND created_at > ?;
|
|
`;
|
|
|
|
results = await db.query(query, [req.user.id, lastcreated_at]);
|
|
}
|
|
|
|
|
|
if (results.length === 0) {
|
|
return res.status(404).json({ message: 'No interaction logs found for this app user' });
|
|
}
|
|
|
|
res.status(200).json({
|
|
message: 'Interaction logs fetched successfully',
|
|
data: results,
|
|
});
|
|
} catch (error) {
|
|
console.error('Error fetching interaction logs:', error.message);
|
|
res.status(500).json({ error: 'Internal server error' });
|
|
}
|
|
|
|
}
|
|
|
|
exports.checkEmailCode = async (req, res) => {
|
|
try {
|
|
const { email, hospital_code } = req.body;
|
|
|
|
// Check if the email and code are provided
|
|
if (!email || !hospital_code) {
|
|
return res.status(400).json({ error: "Email and code are required" });
|
|
}
|
|
|
|
console.log("received data", email, hospital_code)
|
|
// Check if the email exists in the database
|
|
const useremail = await db.query("SELECT * FROM app_users WHERE email = ?", [email]);
|
|
console.log("user email", useremail)
|
|
if (useremail.length) {
|
|
return res.status(404).json({ error: "Email already in use" });
|
|
}
|
|
|
|
// Check if the code is correct
|
|
const usercode = await db.query("SELECT hospital_code FROM hospital_users WHERE hospital_code = ?", [hospital_code]);
|
|
console.log("user code", usercode)
|
|
|
|
if (!usercode.length) {
|
|
return res.status(404).json({ error: "Please enter valid hospital code" });
|
|
}
|
|
|
|
|
|
// Code is correct, return success response
|
|
res.status(200).json({ message: "Email code is correct" });
|
|
} catch (error) {
|
|
console.error("Error checking email code:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|
|
|
|
// get popular topics
|
|
exports.getPopularTopics = async (req, res) => {
|
|
let popularTopics = [];
|
|
try {
|
|
// Fetch top 4 most viewed questions
|
|
console.log("req.user data : ", req.user)
|
|
const rows = await getMappedPopularQuestionsAnswers(req.user.hospital_code);
|
|
if (!rows) {
|
|
popularTopics = []
|
|
}
|
|
else {
|
|
popularTopics = rows;
|
|
}
|
|
console.log('hospital data : ', rows)
|
|
res.status(200).json({
|
|
success: true,
|
|
data: popularTopics
|
|
});
|
|
} catch (error) {
|
|
console.error('Error fetching popular topics:', error);
|
|
res.status(500).json({
|
|
success: false,
|
|
message: 'Internal server error'
|
|
});
|
|
}
|
|
}
|
|
|
|
const getMappedPopularQuestionsAnswers = async (hospitalCode) => {
|
|
console.log("Hospital code is---", hospitalCode);
|
|
|
|
try {
|
|
const query = `
|
|
WITH question_frequency AS (
|
|
SELECT
|
|
query,
|
|
response,
|
|
COUNT(*) as frequency
|
|
FROM interaction_logs
|
|
WHERE hospital_code = ?
|
|
GROUP BY query, response
|
|
HAVING COUNT(*) > 1
|
|
ORDER BY frequency DESC
|
|
LIMIT 10
|
|
),
|
|
recent_questions AS (
|
|
SELECT
|
|
il.*,
|
|
COALESCE(qf.frequency, 1) as frequency
|
|
FROM interaction_logs il
|
|
LEFT JOIN question_frequency qf
|
|
ON il.query = qf.query
|
|
AND il.response = qf.response
|
|
WHERE il.hospital_code = ?
|
|
ORDER BY
|
|
COALESCE(qf.frequency, 0) DESC,
|
|
il.created_at DESC
|
|
LIMIT 10
|
|
)
|
|
SELECT * FROM recent_questions;
|
|
`;
|
|
|
|
const rows = await db.query(query, [hospitalCode, hospitalCode]);
|
|
|
|
console.log("Fetched questions before filtering:", rows);
|
|
|
|
// If no data found, return message
|
|
if (!rows || rows.length === 0) {
|
|
return { message: "No interactions made in your hospital" };
|
|
}
|
|
|
|
// Skip the row if either condition is true
|
|
const filteredRows = rows.filter(row =>
|
|
!(row.query.toLowerCase().includes("yes") || row.response.includes("Please reply with 'yes'"))
|
|
);
|
|
|
|
// If no data after filtering, return message
|
|
if (filteredRows.length === 0) {
|
|
return { message: "No interactions made in your hospital" };
|
|
}
|
|
|
|
// Return only the top 4 filtered results
|
|
return filteredRows.slice(0, 4);
|
|
|
|
} catch (error) {
|
|
console.error("Error fetching popular topics:", error.message);
|
|
throw new Error("Internal server error");
|
|
}
|
|
};
|
|
|
|
exports.changePin = async (req, res) => {
|
|
try {
|
|
const { current_pin, new_pin } = req.body;
|
|
const userId = req.user.id;
|
|
|
|
if (!current_pin || !new_pin) {
|
|
return res.status(400).json({ error: "Current pin and new pin are required" });
|
|
}
|
|
|
|
// Add PIN length validation
|
|
if (new_pin.length !== 4 || !/^\d+$/.test(new_pin)) {
|
|
return res.status(400).json({ error: "New PIN must be exactly 4 digits" });
|
|
}
|
|
|
|
// Get user's current pin
|
|
const userQuery = "SELECT pin_number FROM app_users WHERE id = ?";
|
|
const user = await db.query(userQuery, [userId]);
|
|
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
// Verify current pin
|
|
if (user[0].pin_number !== current_pin) {
|
|
return res.status(400).json({ error: "Current pin is incorrect" });
|
|
}
|
|
|
|
// Check if new pin is same as current pin
|
|
if (current_pin === new_pin) {
|
|
return res.status(400).json({ error: "New PIN cannot be the same as current PIN" });
|
|
}
|
|
|
|
// Update to new pin
|
|
await db.query(
|
|
"UPDATE app_users SET pin_number = ? WHERE id = ?",
|
|
[new_pin, userId]
|
|
);
|
|
|
|
res.json({ message: "Pin changed successfully" });
|
|
} catch (error) {
|
|
console.error("Error changing pin:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.forgotPin = async (req, res) => {
|
|
try {
|
|
const { email } = req.body;
|
|
|
|
if (!email) {
|
|
return res.status(400).json({ error: "Email is required" });
|
|
}
|
|
|
|
// Get user details
|
|
const userQuery = `
|
|
SELECT au.id, au.username, au.pin_number, au.hospital_code, h.name_hospital
|
|
FROM app_users au
|
|
JOIN hospitals h ON au.hospital_code = h.hospital_code
|
|
WHERE au.email = ?
|
|
`;
|
|
const user = await db.query(userQuery, [email]);
|
|
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const userData = user[0];
|
|
|
|
// Send pin via email
|
|
const mailOptions = {
|
|
from: "kavya.j@tech4biz.io",
|
|
to: email,
|
|
subject: "Your Spurrinai PIN",
|
|
html: `<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Your PIN - Spurrinai Medical Platform</title>
|
|
<style>
|
|
@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=Syne:wght@400..800&display=swap');
|
|
body {
|
|
font-family: 'Inter', sans-serif;
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: #ebf3fa;
|
|
color: #333;
|
|
}
|
|
.email-container {
|
|
max-width: 600px;
|
|
margin: 20px auto;
|
|
background: white;
|
|
border-radius: 10px;
|
|
overflow: hidden;
|
|
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.08);
|
|
}
|
|
.email-header {
|
|
background: linear-gradient(135deg, #2193b0, #6dd5ed);
|
|
padding: 30px;
|
|
text-align: center;
|
|
color: white;
|
|
}
|
|
.hospital-name {
|
|
display: inline-block;
|
|
background-color: rgba(255, 255, 255, 0.2);
|
|
padding: 5px 15px;
|
|
border-radius: 20px;
|
|
font-size: 14px;
|
|
margin-bottom: 10px;
|
|
}
|
|
.email-content {
|
|
padding: 40px 30px;
|
|
}
|
|
.greeting {
|
|
font-size: 30px;
|
|
font-weight: 700;
|
|
margin-bottom: 20px;
|
|
color: #303030;
|
|
}
|
|
.pin-display {
|
|
background-color: #f5f9fc;
|
|
border: 1px solid #e0e9f0;
|
|
border-radius: 8px;
|
|
padding: 20px;
|
|
margin: 25px 0;
|
|
text-align: center;
|
|
}
|
|
.pin {
|
|
font-family: 'Courier New', monospace;
|
|
font-size: 32px;
|
|
letter-spacing: 6px;
|
|
color: #2193b0;
|
|
font-weight: bold;
|
|
padding: 10px 0;
|
|
}
|
|
.security-note {
|
|
margin-top: 30px;
|
|
padding-top: 20px;
|
|
border-top: 1px solid #eee;
|
|
font-size: 14px;
|
|
color: #666;
|
|
}
|
|
.email-footer {
|
|
background-color: #f5f9fc;
|
|
padding: 20px;
|
|
text-align: center;
|
|
font-size: 13px;
|
|
color: #888;
|
|
border-top: 1px solid #e0e9f0;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="email-container">
|
|
<div class="email-header">
|
|
<div class="hospital-name">${userData.name_hospital}</div>
|
|
<h1>Your PIN Information</h1>
|
|
</div>
|
|
<div class="email-content">
|
|
<div class="greeting">Hello ${userData.username},</div>
|
|
|
|
<p>Here is your PIN for the Spurrinai healthcare platform:</p>
|
|
|
|
<div class="pin-display">
|
|
<div class="pin">${userData.pin_number}</div>
|
|
</div>
|
|
|
|
<div class="security-note">
|
|
<p>For security reasons, please do not share this PIN with anyone. If you did not request this information, please contact our support team immediately.</p>
|
|
</div>
|
|
</div>
|
|
<div class="email-footer">
|
|
<p>© 2025 Spurrinai - Healthcare Data Management Platform</p>
|
|
<p>This is an automated message. Please do not reply to this email.</p>
|
|
<p>Need help? Contact <a href="mailto:support@spurrinai.com">support@spurrinai.com</a></p>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>`
|
|
};
|
|
|
|
await transporter.sendMail(mailOptions);
|
|
|
|
res.json({ message: "PIN has been sent to your email" });
|
|
} catch (error) {
|
|
console.error("Error in forgot pin:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}; |