1687 lines
51 KiB
JavaScript
1687 lines
51 KiB
JavaScript
const db = require("../config/database");
|
|
const hospitalService = require("../services/hospitalService");
|
|
const jwt = require("jsonwebtoken");
|
|
const bcrypt = require("bcrypt");
|
|
const nodemailer = require("nodemailer");
|
|
const path = require("path");
|
|
const sender_mail = process.env.mail;
|
|
const back_url = process.env.BACK_URL;
|
|
const fs = require("fs");
|
|
const tokenService = require('../services/tokenService');
|
|
|
|
const transporter = nodemailer.createTransport({
|
|
host: "smtp.zoho.com", // Zoho SMTP Server
|
|
port: 465, // Use 465 for SSL or 587 for TLS
|
|
secure: true, // Set to true for port 465, false for port 587
|
|
auth: {
|
|
user: "kavya.j@tech4biz.io", // Your Zoho email address
|
|
pass: "8pQfkBw8gbrz", // Your Zoho App Password (not your account password)
|
|
}
|
|
// tls: {
|
|
// minVersion: "TLSv1.2",
|
|
// ciphers: "SSLv3",
|
|
// },
|
|
});
|
|
|
|
|
|
|
|
function generateHospitalCode() {
|
|
const length = 12;
|
|
const characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
let code = "";
|
|
for (let i = 0; i < length; i++) {
|
|
code += characters.charAt(Math.floor(Math.random() * characters.length));
|
|
}
|
|
return code;
|
|
}
|
|
|
|
exports.createHospital = async (req, res) => {
|
|
try {
|
|
const {
|
|
name_hospital,
|
|
subdomain,
|
|
primary_admin_email,
|
|
primary_admin_password,
|
|
primary_color,
|
|
secondary_color,
|
|
logo_url,
|
|
admin_name,
|
|
mobile_number,
|
|
location,
|
|
super_admin_id, // This comes from request body
|
|
} = req.body;
|
|
|
|
// ✅ Step 1: Ensure the logged-in SuperAdmin is the one creating the hospital
|
|
if (req.user.id !== super_admin_id) {
|
|
return res.status(403).json({
|
|
error:
|
|
"Unauthorized: You cannot create a hospital for another SuperAdmin",
|
|
});
|
|
}
|
|
|
|
// check email if already exists
|
|
const spurrinEmailQuery =
|
|
"SELECT email from super_admins WHERE email = ?";
|
|
const spurrinEmailResult = await db.query(spurrinEmailQuery, [primary_admin_email]);
|
|
|
|
if (spurrinEmailResult.length > 0) {
|
|
return res.status(403).json({ error: "Email already exists!" });
|
|
}
|
|
|
|
const hsptUsrEmailQuery =
|
|
"SELECT email from hospital_users WHERE email = ?";
|
|
const hsptUsrEmailResult = await db.query(hsptUsrEmailQuery, [primary_admin_email]);
|
|
|
|
if (hsptUsrEmailResult.length > 0) {
|
|
return res.status(403).json({ error: "Email already exists!" });
|
|
}
|
|
|
|
|
|
// ✅ Step 2: Generate a unique hospital code
|
|
let hospitalCode;
|
|
let isUnique = false;
|
|
|
|
while (!isUnique) {
|
|
hospitalCode = generateHospitalCode();
|
|
const codeExists = await db.query(
|
|
"SELECT COUNT(*) as count FROM hospitals WHERE hospital_code = ?",
|
|
[hospitalCode]
|
|
);
|
|
if (codeExists[0].count === 0) {
|
|
isUnique = true;
|
|
}
|
|
}
|
|
|
|
// ✅ Step 3: Validate if the SuperAdmin exists in the database
|
|
const superAdminQuery =
|
|
"SELECT id, access_token FROM super_admins WHERE id = ?";
|
|
const superAdminResult = await db.query(superAdminQuery, [super_admin_id]);
|
|
|
|
if (superAdminResult.length === 0) {
|
|
return res.status(400).json({ error: "Invalid super_admin_id" });
|
|
}
|
|
|
|
const superAdmin = superAdminResult[0];
|
|
|
|
// ✅ Step 4: Ensure the access token used in the request matches the one stored in the database
|
|
if (superAdmin.access_token !== req.headers.authorization.split(" ")[1]) {
|
|
return res.status(403).json({
|
|
error:
|
|
"Unauthorized: Access token does not match the SuperAdmin's token in the database",
|
|
});
|
|
}
|
|
|
|
// ✅ Step 5: Hash the primary admin's password
|
|
const hashedPassword = await bcrypt.hash(primary_admin_password, 10);
|
|
|
|
// ✅ Step 6: Send an email to notify
|
|
const mailOptions = {
|
|
from: 'kavya.j@tech4biz.io', // Sender's email
|
|
to: primary_admin_email, // Recipient's email
|
|
subject: "Spurrinai Login Credentials", // Email subject
|
|
html: `<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
|
|
<title>Welcome Email</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');
|
|
|
|
* {
|
|
margin: 0;
|
|
padding: 0;
|
|
box-sizing: border-box;
|
|
}
|
|
body {
|
|
font-family: Inter, sans-serif;
|
|
line-height: 1.6;
|
|
background-color: #f5f5f5;
|
|
color: #333;
|
|
}
|
|
.container {
|
|
max-width: 700px;
|
|
margin: 0 auto;
|
|
background: #fff;
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|
}
|
|
.header {
|
|
background-color: #B4EAE4;
|
|
padding: 20px;
|
|
position: relative;
|
|
height: fit-content;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: flex-start;
|
|
height: 250px;
|
|
|
|
}
|
|
.logo {
|
|
font-size: 24px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
.header-image {
|
|
height: 250px;
|
|
width: auto;
|
|
}
|
|
.content {
|
|
padding: 24px;
|
|
}
|
|
.greeting {
|
|
font-size: 24px;
|
|
margin-bottom: 16px;
|
|
color: #333;
|
|
font-weight: bold;
|
|
}
|
|
.welcome-text {
|
|
margin-bottom: 24px;
|
|
line-height: 1.6;
|
|
}
|
|
.credentials-title {
|
|
margin-bottom: 16px;
|
|
font-weight: 500;
|
|
}
|
|
.credentials-grid {
|
|
margin-bottom: 24px;
|
|
}
|
|
.credential-row {
|
|
display: flex;
|
|
border: 1px solid #e0e0e0;
|
|
margin-bottom: -1px;
|
|
}
|
|
.credential-label {
|
|
flex: 0 0 140px;
|
|
padding: 12px;
|
|
background-color: #F1fffe;
|
|
font-weight: 500;
|
|
border-right: 1px solid #e0e0e0;
|
|
}
|
|
.credential-value {
|
|
flex: 1;
|
|
padding: 12px;
|
|
word-break: break-word;
|
|
}
|
|
.security-note {
|
|
font-style: italic;
|
|
color: #666;
|
|
margin: 24px 0;
|
|
}
|
|
.button {
|
|
display: inline-block;
|
|
background: #333;
|
|
color: #fff;
|
|
padding: 12px 24px;
|
|
text-decoration: none;
|
|
border-radius: 4px;
|
|
font-weight: 500;
|
|
}
|
|
@media screen and (min-width:400px) and (max-width: 768px) {
|
|
|
|
.container {
|
|
margin: 20px auto;
|
|
width: 90%;
|
|
}
|
|
|
|
.content {
|
|
padding: 20px;
|
|
}
|
|
.header {
|
|
padding: 15px;
|
|
background-color: #b4eae4;
|
|
padding: 20px;
|
|
position: relative;
|
|
height: fit-content;
|
|
display: flex;
|
|
justify-content: start;
|
|
align-items: start;
|
|
border-radius: 12px 12px 0px 0px;
|
|
flex-direction: column;
|
|
height: 250px;
|
|
}
|
|
.header-image {
|
|
height: 250px;
|
|
width: 100%;
|
|
}
|
|
}
|
|
@media screen and (max-width: 400px) {
|
|
.header {
|
|
padding: 15px;
|
|
background-color: #b4eae4;
|
|
padding: 20px;
|
|
position: relative;
|
|
height: fit-content;
|
|
display: flex;
|
|
justify-content: start;
|
|
align-items: start;
|
|
border-radius: 12px 12px 0px 0px;
|
|
flex-direction: column;
|
|
}
|
|
.header-image {
|
|
height: 250px;
|
|
width: 100%;
|
|
}
|
|
.container {
|
|
margin: 20px auto;
|
|
width: 90%;
|
|
}
|
|
.content {
|
|
padding: 16px;
|
|
}
|
|
.credential-row {
|
|
flex-direction: column;
|
|
margin-bottom: 16px;
|
|
border: none;
|
|
}
|
|
.credential-label {
|
|
flex: none;
|
|
border: 1px solid #e0e0e0;
|
|
border-bottom: none;
|
|
border-radius: 4px 4px 0 0;
|
|
}
|
|
.credential-value {
|
|
flex: none;
|
|
border: 1px solid #e0e0e0;
|
|
border-radius: 0 0 4px 4px;
|
|
background: #fff;
|
|
}
|
|
.greeting {
|
|
font-size: 20px;
|
|
}
|
|
.button {
|
|
display: block;
|
|
text-align: center;
|
|
}
|
|
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<div class="header"
|
|
style="background-image: url(${back_url}'public/images/email-banner.png');"
|
|
>
|
|
<div class="logo">Spurrinai</div>
|
|
<!-- <img src="/SpurrinAI/public/images/email-banner.png" alt="Doctor illustration" class="header-image"> -->
|
|
</div>
|
|
<div class="content">
|
|
<h1 class="greeting">Greetings, ${admin_name},</h1>
|
|
<div class="welcome-text">
|
|
Congratulations! Your hospital, <strong>${name_hospital}</strong>, has been successfully onboarded to
|
|
<strong>Spurrinai</strong>. We are excited to have you on board and look forward to supporting your
|
|
hospital's needs.
|
|
</div>
|
|
<div class="credentials-title">
|
|
Please find your hospital's login credentials below to access the platform:
|
|
</div>
|
|
<div class="credentials-grid">
|
|
<div class="credential-row">
|
|
<div class="credential-label">Hospital Name</div>
|
|
<div class="credential-value">${name_hospital}</div>
|
|
</div>
|
|
<div class="credential-row">
|
|
<div class="credential-label">Domain</div>
|
|
<div class="credential-value">${subdomain}</div>
|
|
</div>
|
|
<div class="credential-row">
|
|
<div class="credential-label">Username</div>
|
|
<div class="credential-value">${primary_admin_email}</div>
|
|
</div>
|
|
<div class="credential-row">
|
|
<div class="credential-label">Temporary Password</div>
|
|
<div class="credential-value">${primary_admin_password}</div>
|
|
</div>
|
|
</div>
|
|
<div class="security-note">
|
|
For your security, we recommend changing your password immediately after logging in.
|
|
</div>
|
|
<a href="https://${subdomain}superadmin" class="button">Log In and Change Password</a>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>`,
|
|
};
|
|
|
|
const insertHospitalQuery = `
|
|
INSERT INTO hospitals (
|
|
name_hospital,
|
|
subdomain,
|
|
primary_admin_email,
|
|
primary_admin_password,
|
|
primary_color,
|
|
secondary_color,
|
|
logo_url,
|
|
status,
|
|
onboarding_status,
|
|
admin_name,
|
|
mobile_number,
|
|
location,
|
|
super_admin_id,
|
|
hospital_code,
|
|
type
|
|
) VALUES (?, ?, ?, ?, ?, ?, ?, 'Active', 'Pending', ?, ?, ?, ?,?,NULL)
|
|
`;
|
|
const hospitalResult = await db.query(insertHospitalQuery, [
|
|
name_hospital,
|
|
subdomain,
|
|
primary_admin_email,
|
|
hashedPassword,
|
|
primary_color,
|
|
secondary_color,
|
|
logo_url,
|
|
admin_name,
|
|
mobile_number,
|
|
location,
|
|
super_admin_id,
|
|
hospitalCode,
|
|
]);
|
|
|
|
// ✅ Step 7: Get the new hospital ID
|
|
const hospitalId = hospitalResult.insertId;
|
|
|
|
// ✅ Step 8: Generate a refresh token for the hospital's primary admin
|
|
// Step 1: Insert the primary admin into the hospital_users table
|
|
const insertUserQuery = `
|
|
INSERT INTO hospital_users (
|
|
hospital_id,
|
|
email,
|
|
hash_password,
|
|
role_id,
|
|
is_default_admin,
|
|
requires_onboarding,
|
|
password_reset_required,
|
|
phone_number,
|
|
status,
|
|
hospital_code,
|
|
name,
|
|
type,
|
|
location
|
|
) VALUES (?, ?, ?, ?, TRUE, TRUE, TRUE, ?, 'Active', ?, ?, NULL,?)
|
|
`;
|
|
|
|
// Assuming 7 is the role ID for Superadmin
|
|
const roleId = 7;
|
|
|
|
const insertResult = await db.query(insertUserQuery, [
|
|
hospitalId,
|
|
primary_admin_email,
|
|
hashedPassword,
|
|
roleId,
|
|
mobile_number,
|
|
hospitalCode,
|
|
admin_name,
|
|
location
|
|
]);
|
|
|
|
console.log("insert result", insertResult);
|
|
// Step 2: Retrieve the inserted user ID
|
|
const insertedUserId = insertResult.insertId;
|
|
|
|
const payload = { id: insertedUserId, email: primary_admin_email, role: roleId };
|
|
const accessToken = tokenService.generateAccessToken(payload);
|
|
const expiryTimestamp = new Date();
|
|
expiryTimestamp.setHours(expiryTimestamp.getHours() + 5); // Add 5 hours
|
|
|
|
// Step 3: Generate the refresh token
|
|
const refreshTokenPayload = {
|
|
id: insertedUserId,
|
|
email: primary_admin_email,
|
|
role: "Superadmin",
|
|
};
|
|
const refreshToken = jwt.sign(
|
|
refreshTokenPayload,
|
|
process.env.JWT_REFRESH_TOKEN_SECRET
|
|
);
|
|
|
|
|
|
// Step 4: Update the refresh token in the database
|
|
const updateRefreshTokenQuery = `UPDATE hospital_users SET refresh_token = ?, access_token = ?, access_token_expiry= ? WHERE id = ?`;
|
|
await db.query(updateRefreshTokenQuery, [refreshToken, accessToken, expiryTimestamp, insertedUserId]);
|
|
|
|
if (!primary_admin_email) {
|
|
return res.status(400).json({ error: "Recipient email is required" });
|
|
}
|
|
|
|
const responseData = {
|
|
message: "Hospital and Primary SuperAdmin created successfully!",
|
|
hospital: {
|
|
id: hospitalId,
|
|
name_hospital,
|
|
subdomain,
|
|
primary_admin_email,
|
|
primary_color,
|
|
secondary_color,
|
|
logo_url,
|
|
admin_name,
|
|
mobile_number,
|
|
location,
|
|
super_admin_id,
|
|
hospitalCode
|
|
},
|
|
refreshToken,
|
|
};
|
|
|
|
// 3. Send email in a separate try-catch
|
|
try {
|
|
const info = await transporter.sendMail(mailOptions);
|
|
responseData.emailInfo = info.response;
|
|
} catch (emailError) {
|
|
console.error("Email sending failed:", emailError.message);
|
|
responseData.emailInfo = "Email sending failed: " + emailError.message;
|
|
}
|
|
|
|
// 4. Send final response
|
|
res.status(201).json(responseData);
|
|
} catch (error) {
|
|
console.error("Error creating hospital and admin:", error.message);
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
};
|
|
|
|
exports.uploadLogo = (req, res) => {
|
|
try {
|
|
const logoUrl = req.file ? req.file.path : null;
|
|
res
|
|
.status(200)
|
|
.json({ message: "Logo uploaded successfully!", logo_url: logoUrl });
|
|
} catch (error) {
|
|
res.status(500).json({ error: error.message });
|
|
}
|
|
};
|
|
|
|
exports.getHospitalList = async (req, res) => {
|
|
try {
|
|
// Ensure we are filtering by the authenticated Spurrinadmin
|
|
const superAdminId = req.user.id; // Extract authenticated Spurrinadmin ID
|
|
const query = "SELECT * FROM hospitals";
|
|
const hospitals = await db.query(query);
|
|
|
|
res.status(200).json({
|
|
message: "Hospital list fetched successfully!",
|
|
data: hospitals,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching hospital list:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.getHospitalById = async (req, res) => {
|
|
try {
|
|
const { id } = req.params; // Extract the hospital ID from route parameters
|
|
// Query the database to fetch the hospital by ID
|
|
const query = "SELECT * FROM hospitals WHERE id = ?";
|
|
const result = await db.query(query, [id]);
|
|
|
|
// Check if the hospital exists
|
|
if (result.length === 0) {
|
|
return res.status(404).json({ error: "Hospital not found" });
|
|
}
|
|
|
|
res.status(200).json({
|
|
message: "Hospital fetched successfully!",
|
|
data: result[0], // Return the first (and only) result
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching hospital by ID:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.updateHospital = async (req, res) => {
|
|
try {
|
|
const { id } = req.params; // Get the hospital ID from the route parameter
|
|
const updateData = req.body; // Get the fields to update from the request body
|
|
|
|
// Fetch the hospital to validate ownership
|
|
const hospitalQuery = "SELECT id hospital_code, super_admin_id FROM hospitals WHERE id = ?";
|
|
const hospitalResult = await db.query(hospitalQuery, [id]);
|
|
|
|
const hospitalQueryUsr = "SELECT id FROM hospital_users WHERE hospital_id = ?";
|
|
const hospitalResultUsr = await db.query(hospitalQueryUsr, [id]);
|
|
// console.log("requested user", req.user);
|
|
if (hospitalResult.length === 0) {
|
|
return res.status(404).json({ error: "Hospital not found" });
|
|
}
|
|
|
|
|
|
console.log('hspt id----', req.user.id)
|
|
console.log('db hspt id', hospitalResultUsr[0])
|
|
if (req.user.id !== hospitalResultUsr[0].id && req.user.id !== hospitalResult[0].super_admin_id) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You can only edit the hospital you have created" });
|
|
}
|
|
|
|
|
|
const validColumns = new Set([
|
|
"name_hospital",
|
|
"primary_admin_password",
|
|
"primary_color",
|
|
"secondary_color",
|
|
"logo_url",
|
|
"status",
|
|
"onboarding_status",
|
|
"admin_name",
|
|
"mobile_number",
|
|
"location",
|
|
"super_admin_id",
|
|
]);
|
|
|
|
// Ensure no extra fields are present
|
|
for (const key of Object.keys(updateData)) {
|
|
if (!validColumns.has(key)) {
|
|
return res.status(400).json({ error: `Invalid field or cannot update: ${key}` });
|
|
}
|
|
}
|
|
|
|
// Build the SQL SET clause dynamically
|
|
const fields = [];
|
|
const values = [];
|
|
for (const [key, value] of Object.entries(updateData)) {
|
|
fields.push(`${key} = ?`);
|
|
values.push(value);
|
|
}
|
|
|
|
values.push(id); // Add the hospital ID to the values array for the WHERE clause
|
|
|
|
// Construct the SQL query
|
|
const query = `UPDATE hospitals SET ${fields.join(", ")} WHERE id = ?`;
|
|
|
|
const result = await db.query(query, values);
|
|
|
|
const queryhspt = `SELECT * FROM hospitals WHERE id = ?`;
|
|
const resulthspt = await db.query(queryhspt, [id]);
|
|
|
|
// Check if any row was updated
|
|
if (result.affectedRows === 0) {
|
|
return res
|
|
.status(404)
|
|
.json({ error: "Hospital not found or no changes made" });
|
|
}
|
|
|
|
res
|
|
.status(200)
|
|
.json({ message: "Hospital updated successfully!", data: resulthspt });
|
|
} catch (error) {
|
|
console.error("Error updating hospital:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
|
|
// exports.updateHospital = async (req, res) => {
|
|
// try {
|
|
// const { id } = req.params; // Get the hospital ID from the route parameter
|
|
// const updateData = req.body; // Get the fields to update from the request body
|
|
|
|
// // Fetch the hospital to validate ownership
|
|
// // const hospitalQuery = "SELECT hospital_code, super_admin_id FROM hospitals WHERE id = ?";
|
|
// // const hospitalResult = await db.query(hospitalQuery, [id]);
|
|
|
|
// // console.log("requested user", req.user);
|
|
// // if (hospitalResult.length === 0) {
|
|
// // return res.status(404).json({ error: "Hospital not found" });
|
|
// // }
|
|
|
|
// // if (req.user.id !== hospitalResult[0].super_admin_id) {
|
|
// // return res
|
|
// // .status(403)
|
|
// // .json({ error: "You can only edit the hospital you have created" });
|
|
// // }
|
|
|
|
// const validColumns = new Set([
|
|
// "name_hospital",
|
|
// "subdomain",
|
|
// "primary_admin_email",
|
|
// "primary_admin_password",
|
|
// "primary_color",
|
|
// "secondary_color",
|
|
// "logo_url",
|
|
// "status",
|
|
// "onboarding_status",
|
|
// "admin_name",
|
|
// "mobile_number",
|
|
// "location",
|
|
// "super_admin_id",
|
|
// "hospital_code",
|
|
// ]);
|
|
|
|
// // Ensure no extra fields are present
|
|
// for (const key of Object.keys(updateData)) {
|
|
// if (!validColumns.has(key)) {
|
|
// return res.status(400).json({ error: `Invalid field: ${key}` });
|
|
// }
|
|
// }
|
|
|
|
// // Build the SQL SET clause dynamically
|
|
// const fields = [];
|
|
// const values = [];
|
|
// for (const [key, value] of Object.entries(updateData)) {
|
|
// fields.push(`${key} = ?`);
|
|
// values.push(value);
|
|
// }
|
|
|
|
// values.push(id); // Add the hospital ID to the values array for the WHERE clause
|
|
|
|
// // Construct the SQL query
|
|
// const query = `UPDATE hospitals SET ${fields.join(", ")} WHERE id = ?`;
|
|
|
|
// const result = await db.query(query, values);
|
|
|
|
// const queryhspt = `SELECT * FROM hospitals WHERE id = ?`;
|
|
// const resulthspt = await db.query(queryhspt, [id]);
|
|
|
|
// // Check if any row was updated
|
|
// if (result.affectedRows === 0) {
|
|
// return res
|
|
// .status(404)
|
|
// .json({ error: "Hospital not found or no changes made" });
|
|
// }
|
|
|
|
// res
|
|
// .status(200)
|
|
// .json({ message: "Hospital updated successfully!", data: resulthspt });
|
|
// } catch (error) {
|
|
// console.error("Error updating hospital:", error.message);
|
|
// res.status(500).json({ error: "Internal server error" });
|
|
// }
|
|
// };
|
|
exports.deleteHospital = async (req, res) => {
|
|
const { id } = req.params;
|
|
console.log("user details ", req.user);
|
|
const hospitalId = id;
|
|
|
|
if (!id) {
|
|
return res.status(400).json({ error: "hospital ID is required" });
|
|
}
|
|
|
|
// Fetch the hospital to validate ownership
|
|
const hospitalQuery = "SELECT hospital_code, super_admin_id FROM hospitals WHERE id = ?";
|
|
const hospitalResult = await db.query(hospitalQuery, [id]);
|
|
|
|
console.log("requested user", req.user);
|
|
if (hospitalResult.length === 0) {
|
|
return res.status(404).json({ error: "Hospital not found" });
|
|
}
|
|
|
|
if (req.user.id !== hospitalResult[0].super_admin_id) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You can only delete the hospital you have created" });
|
|
}
|
|
|
|
// Ensure the authenticated user is either Admin or Superadmin
|
|
if (!["Spurrinadmin", 6].includes(req.user.role)) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You are not authorized to delete hospitals" });
|
|
}
|
|
|
|
|
|
// Check for dependent records
|
|
const [qaCount] = await db.query(
|
|
"SELECT COUNT(*) AS count FROM questions_answers WHERE document_id IN (SELECT id FROM documents WHERE hospital_id = ?)",
|
|
[hospitalId]
|
|
);
|
|
|
|
const [qaPageCount] = await db.query(
|
|
"SELECT COUNT(*) AS count FROM document_pages WHERE document_id IN (SELECT id FROM documents WHERE hospital_id = ?)",
|
|
[hospitalId]
|
|
);
|
|
const [metadataCount] = await db.query(
|
|
"SELECT COUNT(*) AS count FROM document_metadata WHERE document_id IN (SELECT id FROM documents WHERE hospital_id = ?)",
|
|
[hospitalId]
|
|
);
|
|
const [documentsCount] = await db.query(
|
|
"SELECT COUNT(*) AS count FROM documents WHERE hospital_id = ?",
|
|
[hospitalId]
|
|
);
|
|
const [appUsersCount] = await db.query(
|
|
"SELECT COUNT(*) AS count FROM app_users WHERE hospital_code = (SELECT hospital_code FROM hospitals WHERE id = ?)",
|
|
[hospitalId]
|
|
);
|
|
|
|
|
|
console.log('qaCount', qaCount, '\nqaPageCount', qaPageCount, '\nmetadataCount', metadataCount, '\ndocumentsCount', documentsCount, '\nappUsersCount', appUsersCount);
|
|
|
|
// // If any dependent records exist, block deletion
|
|
// if (qaCount.count > 0 || metadataCount.count > 0 || documentsCount.count > 0 || appUsersCount.count > 0 || qaPageCount.count > 0) {
|
|
// return res
|
|
// .status(403)
|
|
// .json({ error: "Can not delete hospital dependent records found" });
|
|
// }
|
|
|
|
|
|
|
|
|
|
try {
|
|
// Unlink (delete) the associated file if it exists
|
|
// Fetch all documents related to the hospital
|
|
const documents = await db.query(
|
|
"SELECT id, file_url FROM documents WHERE hospital_id = ?",
|
|
[id]
|
|
);
|
|
console.log("doc ids ", documents);
|
|
|
|
// Delete document files dynamically
|
|
for (const document of documents) {
|
|
if (document.file_url) {
|
|
const filePath = path.join(
|
|
__dirname,
|
|
"..",
|
|
"uploads",
|
|
document.file_url.replace(/^\/uploads\//, "")
|
|
);
|
|
|
|
try {
|
|
await fs.promises.access(filePath, fs.constants.F_OK);
|
|
await fs.promises.unlink(filePath);
|
|
console.log("File deleted successfully:", filePath);
|
|
} catch (err) {
|
|
console.error(`Error deleting or accessing file ${filePath}: ${err.message}`);
|
|
}
|
|
}
|
|
}
|
|
// Delete document-related records first
|
|
await db.query(
|
|
"DELETE FROM questions_answers WHERE document_id IN (SELECT id FROM documents WHERE hospital_id = ?)",
|
|
[id]
|
|
);
|
|
console.log('Deleted questions_answers successfully');
|
|
|
|
await db.query(
|
|
"DELETE FROM document_metadata WHERE document_id IN (SELECT id FROM documents WHERE hospital_id = ?)",
|
|
[id]
|
|
);
|
|
console.log('Deleted document_metadata successfully');
|
|
|
|
await db.query(
|
|
"DELETE FROM document_pages WHERE document_id IN (SELECT id FROM documents WHERE hospital_id = ?)",
|
|
[id]
|
|
);
|
|
console.log('Deleted document_pages successfully');
|
|
|
|
await db.query("DELETE FROM onboarding_steps WHERE user_id IN (SELECT id from hospital_users WHERE hospital_code = ?)", [
|
|
hospitalResult[0].hospital_code,
|
|
]);
|
|
console.log('Deleted onboarding steps successfully');
|
|
|
|
|
|
// Now delete the documents themselves
|
|
await db.query("DELETE FROM documents WHERE hospital_id = ?", [id]);
|
|
console.log('Deleted documents successfully');
|
|
|
|
// Now delete hospital_users AFTER documents (because of FK uploaded_by)
|
|
await db.query("DELETE FROM hospital_users WHERE hospital_code = ?", [
|
|
hospitalResult[0].hospital_code,
|
|
]);
|
|
console.log('Deleted hospital_users successfully');
|
|
|
|
// Then delete app_users
|
|
await db.query("DELETE FROM app_users WHERE hospital_code = ?", [
|
|
hospitalResult[0].hospital_code,
|
|
]);
|
|
console.log('Deleted app users successfully');
|
|
|
|
// And finally interaction_logs
|
|
await db.query("DELETE FROM interaction_logs WHERE hospital_code = ?", [
|
|
hospitalResult[0].hospital_code,
|
|
]);
|
|
console.log('Deleted interaction logs successfully');
|
|
|
|
} catch (error) {
|
|
console.error("Error deleting dependent records:", error.message);
|
|
return res.status(500).json({ error: "Failed to delete dependent records" });
|
|
}
|
|
|
|
|
|
// Now delete the hospital
|
|
const deleteQuery = "DELETE FROM hospitals WHERE id = ?";
|
|
const result = await db.query(deleteQuery, [id]);
|
|
|
|
if (result.affectedRows === 0) {
|
|
return res.status(404).json({ message: "hospital not found" });
|
|
}
|
|
|
|
res.status(200).json({ message: "Hospital deleted successfully!" });
|
|
};
|
|
|
|
exports.getAllHospitalUsers = async (req, res) => {
|
|
try {
|
|
// Fetch all users from the hospital_users table
|
|
const hospitalUsers = await db.query(`
|
|
SELECT
|
|
u.id,
|
|
u.hospital_id,
|
|
u.email,
|
|
u.role_id,
|
|
r.name AS role_name,
|
|
u.status,
|
|
u.created_at,
|
|
u.updated_at
|
|
FROM
|
|
hospital_users u
|
|
JOIN
|
|
roles r
|
|
ON
|
|
u.role_id = r.id
|
|
`);
|
|
|
|
res.status(200).json({
|
|
message: "Hospital users fetched successfully!",
|
|
data: hospitalUsers,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching hospital users:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
// get colors
|
|
exports.getColorsFromHospital = async (req, res) => {
|
|
try {
|
|
const { id } = req.user; // Get the hospital ID from the route parameter
|
|
|
|
console.log("requested user", req.user);
|
|
// Ensure no extra fields are present
|
|
if (!["Superadmin", 7].includes(req.user.role)) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You are not authorized to access hospital's colors!!" });
|
|
}
|
|
|
|
const queryhspt_users = `SELECT hospital_id FROM hospital_users WHERE id = ?`;
|
|
const resulthspt_users = await db.query(queryhspt_users, [id]);
|
|
|
|
const queryhspt = `SELECT primary_color, secondary_color FROM hospitals WHERE id = ?`;
|
|
const resulthspt = await db.query(queryhspt, [
|
|
resulthspt_users[0].hospital_id,
|
|
]);
|
|
|
|
console.log("resulthspt", resulthspt);
|
|
|
|
if (resulthspt.length === 0) {
|
|
return res.status(404).json({ error: "Hospital not found" });
|
|
}
|
|
// Check if any row was updated
|
|
|
|
res.status(200).json({
|
|
message: "Hospital colors fetched successfully!",
|
|
data: resulthspt,
|
|
});
|
|
} catch (error) {
|
|
console.error("Error fetching hospital:", error.message);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
// change password of super_admins/hospitals only spurrin have access to do so
|
|
exports.changePassword = async (req, res) => {
|
|
try {
|
|
const id = req.user.id; // Get the user ID from the route parameter
|
|
const { new_password } = req.body; // Get the new password from the request body
|
|
const authHeader = req.headers.authorization; // Get the token from the Authorization header
|
|
|
|
// Validate input
|
|
if (!new_password) {
|
|
return res.status(400).json({ error: "New password is required" });
|
|
}
|
|
|
|
// Ensure the token is present
|
|
if (!authHeader || !authHeader.startsWith("Bearer ")) {
|
|
return res.status(401).json({ error: "Authorization token is required" });
|
|
}
|
|
|
|
const token = authHeader.split(" ")[1]; // Extract token from "Bearer <token>"
|
|
let decodedToken;
|
|
try {
|
|
decodedToken = jwt.verify(token, process.env.JWT_ACCESS_TOKEN_SECRET); // Decode the token
|
|
} catch (err) {
|
|
return res.status(401).json({ error: "Invalid or expired token" });
|
|
}
|
|
|
|
// Ensure the decoded token's user ID matches the route parameter
|
|
if (parseInt(id, 10) !== decodedToken.id) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "Token user does not match the requested user" });
|
|
}
|
|
|
|
// Convert ID to integer and validate
|
|
const numericId = parseInt(id, 10);
|
|
if (isNaN(numericId)) {
|
|
return res.status(400).json({ error: "Invalid user ID" });
|
|
}
|
|
|
|
// Fetch the user from the database to ensure they exist
|
|
const userQuery = `
|
|
SELECT id FROM app_users WHERE id = ?
|
|
`;
|
|
const [userResult] = await db.query(userQuery, [numericId]);
|
|
|
|
if (!userResult || userResult.length === 0) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
// Hash the new password
|
|
const hashedNewPassword = await bcrypt.hash(new_password, 10);
|
|
|
|
// Update the password in the database
|
|
const updatePasswordQuery = `
|
|
UPDATE app_users SET hash_password = ? WHERE id = ?
|
|
`;
|
|
await db.query(updatePasswordQuery, [hashedNewPassword, numericId]);
|
|
|
|
res.status(200).json({ message: "Password updated successfully!" });
|
|
} catch (error) {
|
|
console.error("Error updating password:", error.message, error.stack);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
const crypto = require("crypto");
|
|
|
|
function generateRandomPassword(length = 12) {
|
|
return crypto
|
|
.randomBytes(Math.ceil(length / 2))
|
|
.toString("hex")
|
|
.slice(0, length);
|
|
}
|
|
|
|
// Generate and print the password
|
|
const randomPassword = generateRandomPassword();
|
|
console.log("Generated Password:", randomPassword);
|
|
|
|
exports.sendTempPassword = 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, primary_admin_email ,name_hospital,admin_name FROM hospitals WHERE primary_admin_email = ?",
|
|
[email]
|
|
);
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const hsptuser = await db.query(
|
|
"SELECT id, email FROM hospital_users WHERE email = ?",
|
|
[email]
|
|
);
|
|
if (!hsptuser.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const hsptId = user[0].id;
|
|
const hsptUsrId = hsptuser[0].id;
|
|
|
|
const randomPassword = generateRandomPassword();
|
|
const hashedPassword = await bcrypt.hash(randomPassword, 10);
|
|
const expiresAt = new Date(Date.now() + 2 * 60 * 60 * 1000); // OTP expires in 1 hour
|
|
const type = "temp";
|
|
|
|
await db.query(
|
|
"UPDATE hospitals SET temporary_password = ?, expires_at = ?, type = ? WHERE id = ?",
|
|
[randomPassword, expiresAt, type, hsptId]
|
|
);
|
|
|
|
await db.query(
|
|
"UPDATE hospital_users SET temporary_password = ?, expires_at = ?, type = ? WHERE id = ?",
|
|
[randomPassword, expiresAt, type, hsptUsrId]
|
|
);
|
|
|
|
// // // Send OTP via email
|
|
const info = await sendMail(
|
|
email,
|
|
user[0].name_hospital,
|
|
user[0].admin_name,
|
|
randomPassword
|
|
);
|
|
|
|
res.json({ message: "temporary password generated successfully",email_status: info.response });
|
|
} catch (error) {
|
|
console.error("Error sending OTP:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.changeTempPassword = async (req, res) => {
|
|
try {
|
|
const { email, temp_password, new_password } = req.body;
|
|
|
|
// Validate inputs
|
|
if (!email || !temp_password || !new_password) {
|
|
return res.status(400).json({
|
|
error: "Email, Temporary password, and new password are required",
|
|
});
|
|
}
|
|
|
|
const user = await db.query(
|
|
"SELECT id, temporary_password, expires_at, type FROM hospitals WHERE primary_admin_email = ?",
|
|
[email]
|
|
);
|
|
if (!user.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const hsptuser = await db.query(
|
|
"SELECT id, temporary_password, expires_at, type FROM hospital_users WHERE email = ?",
|
|
[email]
|
|
);
|
|
if (!hsptuser.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const isMatch = temp_password === user[0].temporary_password;
|
|
|
|
// check the password match
|
|
if (!isMatch) {
|
|
return res.status(400).json({ error: "Invalid temporary password" });
|
|
}
|
|
|
|
// Check if temporary password is expired
|
|
if (new Date() > new Date(user[0].expires_at)) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "temporary password 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 hospitals SET primary_admin_password = ?, expires_at = ? ,type = NULL, temporary_password = NULL WHERE id = ?",
|
|
[hashedPassword, new Date(Date.now()), user[0].id]
|
|
);
|
|
|
|
await db.query(
|
|
"UPDATE hospital_users SET hash_password = ?, expires_at = ? ,type = NULL, temporary_password = NULL WHERE id = ?",
|
|
[hashedPassword, new Date(Date.now()), hsptuser[0].id]
|
|
);
|
|
|
|
res.json({ message: "Password changed successfully!" });
|
|
} catch (error) {
|
|
console.error("Error resetting password:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
async function sendMail(email, hospital_name, adminName, randomPassword) {
|
|
const mailOptions = {
|
|
from: "kavya.j@tech4biz.io", // Sender's email
|
|
to: email, // Recipient's email
|
|
subject: "Spurrinai temporary password", // 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 - 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</h1>
|
|
</div>
|
|
<div class="email-content">
|
|
<div class="greeting">Hello ${adminName},</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>Your temporary password:</p>
|
|
<div class="code">${randomPassword}</div>
|
|
<p>use same password to generate new password</p>
|
|
</div>
|
|
|
|
<a href="#" class="reset-button">Copy 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);
|
|
return info; // Return the info object for further processing if needed
|
|
} catch (error) {
|
|
console.error(`Error sending email to ${email}:`, error);
|
|
return error
|
|
}
|
|
}
|
|
|
|
exports.updateHospitalName = async (req, res) => {
|
|
|
|
console.log("requested user", req.user);
|
|
|
|
const hospital_user_id = req.user.id;
|
|
const { hospital_name } = req.body;
|
|
// Ensure the authenticated user is either Admin or Superadmin
|
|
if (!["Superadmin", 7].includes(req.user.role)) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You are not authorized to update admins name" });
|
|
}
|
|
|
|
const queryuser = 'SELECT hospital_id FROM hospital_users WHERE id = ?';
|
|
const [rows] = await db.execute(queryuser, [hospital_user_id]);
|
|
console.log(rows[0]?.hospital_id);
|
|
|
|
const query = "UPDATE hospital_name SET name = ? WHERE id = ?";
|
|
const values = [hospital_name, rows[0]?.hospital_id];
|
|
|
|
await db.query(query, values);
|
|
|
|
res.json({ message: "Name changed successfully!" });
|
|
|
|
}
|
|
|
|
// password change for admins and viewers
|
|
exports.sendTemporaryPassword = async (req, res) => {
|
|
try {
|
|
const { email } = req.body;
|
|
|
|
// Validate email input
|
|
if (!email) {
|
|
return res.status(400).json({ error: "Email is required" });
|
|
}
|
|
|
|
|
|
const hsptuser = await db.query(
|
|
"SELECT id,hospital_id, hash_password, name, expires_at, type FROM hospital_users WHERE email = ? AND role_id IN (8, 9)",
|
|
[email]
|
|
);
|
|
|
|
if (!hsptuser.length) {
|
|
return res.status(404).json({ error: "User not found" });
|
|
}
|
|
|
|
const hsptUsrId = hsptuser[0].id;
|
|
const hsptId = hsptuser[0].hospital_id;
|
|
const randomPassword = generateRandomPassword();
|
|
const hashedPassword = await bcrypt.hash(randomPassword, 10);
|
|
const expiresAt = new Date(Date.now() + 2 * 60 * 60 * 1000); // OTP expires in 1 hour
|
|
const type = "temp";
|
|
|
|
await db.query(
|
|
"UPDATE hospital_users SET hash_password = ?, expires_at = ?, type = ? WHERE id = ?",
|
|
[hashedPassword, expiresAt, type, hsptUsrId]
|
|
);
|
|
|
|
const hspt = await db.query(
|
|
"SELECT name_hospital FROM hospitals WHERE id = ?",
|
|
[hsptId]
|
|
);
|
|
// // // Send OTP via email
|
|
const info =await sendMail(
|
|
email,
|
|
hspt[0].name_hospital,
|
|
hsptuser[0].name,
|
|
randomPassword
|
|
);
|
|
|
|
|
|
res.json({ message: "temporary password gerated successfully",email_status: info.response });
|
|
} catch (error) {
|
|
console.error("Error sending OTP:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.changeTempPasswordAdminsViewers = async (req, res) => {
|
|
try {
|
|
const { email, temp_password, new_password } = req.body;
|
|
|
|
console.log("incoming data ", req.body);
|
|
|
|
// Validate inputs
|
|
if (!email || !temp_password || !new_password) {
|
|
return res.status(400).json({
|
|
error: "Email, Temporary password, and new password are required",
|
|
});
|
|
}
|
|
// Ensure the user has the proper role
|
|
const hsptuser = await db.query(
|
|
"SELECT id, temporary_password, expires_at, type FROM hospital_users WHERE email = ? AND role_id IN (8, 9)",
|
|
[email]
|
|
);
|
|
|
|
if (!hsptuser.length) {
|
|
return res.status(404).json({ error: "Email not found" });
|
|
}
|
|
|
|
const isMatch = await bcrypt.compare(
|
|
temp_password,
|
|
hsptuser[0].temporary_password
|
|
);
|
|
|
|
// Check if temporary password matches
|
|
if (!isMatch) {
|
|
return res.status(400).json({ error: "Invalid temporary password" });
|
|
}
|
|
|
|
// Check if temporary password is expired
|
|
if (new Date() > new Date(hsptuser[0].expires_at)) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "temporary password 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 hospital_users SET hash_password = ?, expires_at = ? ,type = NULL, temporary_password = NULL WHERE id = ?",
|
|
[hashedPassword, new Date(Date.now()), hsptuser[0].id]
|
|
);
|
|
|
|
res.json({ message: "Password changed successfully!" });
|
|
} catch (error) {
|
|
console.error("Error resetting password:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
// check app user notification
|
|
exports.checkNewAppUser = async (req, res) => {
|
|
|
|
if (!["Superadmin", "Admin", 7, 8].includes(req.user.role)) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You are not authorized" });
|
|
}
|
|
|
|
try {
|
|
const { hospital_code } = req.body;
|
|
|
|
// Validate inputs
|
|
if (!hospital_code) {
|
|
return res.status(400).json({ error: "hospital code is required" });
|
|
}
|
|
|
|
|
|
// notify hospital only if notification is not checked
|
|
const appUser = await db.query(
|
|
"SELECT * FROM app_users WHERE hospital_code = ? AND checked = 0",
|
|
[hospital_code]
|
|
);
|
|
|
|
|
|
if (!appUser.length) {
|
|
return res.status(404).json({ error: "No new user found" });
|
|
}
|
|
|
|
res.json({ message: "new notification found", appUser });
|
|
} catch (error) {
|
|
console.error("Error checking new notification:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.updateAppUserChecked = async (req, res) => {
|
|
|
|
if (!["Superadmin", "Admin", 7, 8].includes(req.user.role)) {
|
|
return res
|
|
.status(403)
|
|
.json({ error: "You are not authorized" });
|
|
}
|
|
|
|
try {
|
|
const id = req.params.id;
|
|
|
|
if (!id) {
|
|
return res.status(400).json({ error: "User ID is required" });
|
|
}
|
|
|
|
const result = await db.query("UPDATE app_users SET checked = 1 WHERE id = ?", [id]);
|
|
|
|
if (result.affectedRows === 0) {
|
|
return res.status(404).json({ error: "User not found or already checked" });
|
|
}
|
|
|
|
res.json({ message: "User checked status updated successfully", updatedUserId: id });
|
|
} catch (error) {
|
|
console.error("Error updating checked status:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
exports.interactionLogs = async (req, res) => {
|
|
const { hospital_code, app_user_id } = req.body;
|
|
|
|
if (!["Superadmin", 7].includes(req.user.role)) {
|
|
return res.status(403).json({ error: "You are not authorized" });
|
|
}
|
|
|
|
try {
|
|
// Validate inputs
|
|
if (!hospital_code && !app_user_id) {
|
|
return res
|
|
.status(400)
|
|
.json({ error: "hospital code or app user id is required" });
|
|
}
|
|
|
|
let intLogs;
|
|
|
|
// Build dynamic query based on inputs
|
|
let baseQuery = `
|
|
SELECT il.*, au.email, au.username
|
|
FROM interaction_logs il
|
|
LEFT JOIN app_users au ON il.app_user_id = au.id
|
|
WHERE 1=1
|
|
`;
|
|
const params = [];
|
|
|
|
if (hospital_code) {
|
|
baseQuery += ` AND il.hospital_code = ?`;
|
|
params.push(hospital_code);
|
|
}
|
|
|
|
if (app_user_id) {
|
|
baseQuery += ` AND il.app_user_id = ?`;
|
|
params.push(app_user_id);
|
|
}
|
|
|
|
intLogs = await db.query(baseQuery, params);
|
|
|
|
if (!intLogs.length) {
|
|
return res.status(200).json({ error: "No logs found" });
|
|
}
|
|
|
|
res.json({ message: "log data found", intLogs });
|
|
} catch (error) {
|
|
console.error("Error fetching logs:", error);
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
};
|
|
|
|
|
|
exports.updatePublicSignup = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const { enabled } = req.body;
|
|
|
|
|
|
// Validate input
|
|
if (typeof enabled !== 'boolean') {
|
|
return res.status(400).json({
|
|
error: "Invalid input. 'enabled' must be a boolean value"
|
|
});
|
|
}
|
|
|
|
console.log("req user-----", req.user)
|
|
// Check if user has permission
|
|
if (!["Spurrinadmin", "Superadmin", 7, 6].includes(req.user.role)) {
|
|
return res.status(403).json({
|
|
error: "You are not authorized to update public signup settings"
|
|
});
|
|
}
|
|
|
|
|
|
|
|
// If user is Superadmin, verify they own the hospital
|
|
if (req.user.role === "Superadmin") {
|
|
const hospital = await db.query(
|
|
"SELECT id FROM hospitals WHERE id = ?",
|
|
[id]
|
|
);
|
|
|
|
|
|
if (!hospital.length) {
|
|
return res.status(403).json({
|
|
error: "hospital not found"
|
|
});
|
|
}
|
|
|
|
if (id != req.user.hospital_id) {
|
|
return res.status(403).json({
|
|
message: "You can only update public signup settings for your own hospital"
|
|
});
|
|
}
|
|
}
|
|
|
|
const result = await db.query(
|
|
'UPDATE hospitals SET publicSignupEnabled = ? WHERE id = ?',
|
|
[enabled, id]
|
|
);
|
|
|
|
if (result.affectedRows > 0) {
|
|
res.status(200).json({
|
|
status: 'success',
|
|
message: 'Hospital signup settings updated successfully.',
|
|
data: {
|
|
id,
|
|
publicSignupEnabled: enabled
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
res.status(404).json({
|
|
status: 'error',
|
|
message: 'Hospital not found or no changes made.',
|
|
data: null
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("Error updating public signup setting:", error);
|
|
if (error instanceof ValidationError) {
|
|
res.status(400).json({ error: error.message });
|
|
} else {
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|
|
};
|
|
|
|
exports.getPublicSignup = async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
// Check if user has permission
|
|
if (!["Spurrinadmin", "Superadmin", 7, 6].includes(req.user.role)) {
|
|
return res.status(403).json({
|
|
error: "You are not authorized to update public signup settings"
|
|
});
|
|
}
|
|
|
|
|
|
|
|
// If user is Superadmin, verify they own the hospital
|
|
if (req.user.role === "Superadmin") {
|
|
const hospital = await db.query(
|
|
"SELECT id FROM hospitals WHERE id = ?",
|
|
[id]
|
|
);
|
|
|
|
|
|
if (!hospital.length) {
|
|
return res.status(403).json({
|
|
error: "hospital not found"
|
|
});
|
|
}
|
|
|
|
if (id != req.user.hospital_id) {
|
|
return res.status(403).json({
|
|
message: "You can only get public signup settings for your own hospital"
|
|
});
|
|
}
|
|
}
|
|
|
|
const result = await db.query(
|
|
'SELECT publicSignupEnabled from hospitals WHERE id = ?',
|
|
[id]
|
|
);
|
|
|
|
console.log("result----",result)
|
|
|
|
if (result.length > 0) {
|
|
res.status(200).json({
|
|
message: 'data fetched successfully.',
|
|
result
|
|
});
|
|
}
|
|
else {
|
|
res.status(200).json({
|
|
status: 'Not found',
|
|
message: 'Hospital not found or no changes made.',
|
|
});
|
|
}
|
|
|
|
} catch (error) {
|
|
console.error("Error updating public signup setting:", error);
|
|
if (error instanceof ValidationError) {
|
|
res.status(400).json({ error: error.message });
|
|
} else {
|
|
res.status(500).json({ error: "Internal server error" });
|
|
}
|
|
}
|
|
}; |