fcsc_ipi_backend/app/controllers/establishment_user.controller.js
2026-01-21 13:09:42 +05:30

370 lines
11 KiB
JavaScript

const db = require("../models");
const bcrypt = require("bcryptjs");
const EstablishmentUser = db.EstablishmentUser;
const Establishment = db.Establishment;
const crypto = require("crypto");
const { sendEmailService } = require("../services/email.service");
const { sanitizeForLog } = require("../utils/sanitize");
const logger = require("../services/logger");
const User = db.user;
function formatName(name) {
return name
.replace(/([A-Z])/g, ' $1')
.replace(/\b\w/g, char => char.toUpperCase())
.trim();
}
// Create User
exports.createUser = async (req, res) => {
try {
let { establishment_id, name, email, password, gender } = req.body;
establishment_id = Number(establishment_id);
if (!Number.isInteger(establishment_id) || establishment_id <= 0) {
return res.status(400).json({
status: "error",
message: "Invalid establishment_id"
});
}
const establishment = await Establishment.findByPk(establishment_id);
if (!establishment) {
return res.status(404).json({
status: "error",
message: "Establishment not found"
});
}
if (typeof email !== "string" || email.trim().length === 0) {
return res.status(400).json({
status: "error",
message: "Email is required"
});
}
email = email.trim().toLowerCase();
const existingUser = await EstablishmentUser.findOne({
where: { email, is_active: true }
});
const checkEmailInAdminUser = await User.findOne({ where: { email, is_active: true } });
if (existingUser) {
return res.status(409).json({
status: "error",
message: "Email already exists"
});
}
if (checkEmailInAdminUser) {
logger.info(`Email already exists in Admin Users: ${email}`);
return res.status(409).send({
status: "failed",
message: "This email address is already registered in the admin users."
});
}
if (typeof password !== "string" || password.length < 6) {
return res.status(400).json({
status: "error",
message: "Password must be at least 6 characters long"
});
}
name = typeof name === "string" ? name.trim() : null;
if (gender) {
gender = gender.toString().toLowerCase();
if (!["male", "female", "other"].includes(gender)) {
return res.status(400).json({
status: "error",
message: "Invalid gender"
});
}
gender = gender.charAt(0).toUpperCase() + gender.slice(1);
}
// Store plain password for email before hashing
const plainPasswordForEmail = password;
const hashedPassword = await bcrypt.hash(password, 10);
const user = await EstablishmentUser.create({
establishment_id,
name,
email,
password: hashedPassword,
gender,
created_by: req.user.id
});
// Prepare sanitized data for email notification
const emailContactName = name;
const emailUsername = email;
const emailPortalUrl = process.env.FE_BASE_URL;
const emailSupportEmail = process.env.SUPPORT_EMAIL;
const emailSupportPhone = process.env.SUPPORT_PHONE;
const emailData = {
contact_name: formatName(emailContactName),
portal_url: emailPortalUrl,
username: emailUsername,
password: plainPasswordForEmail,
support_email: emailSupportEmail,
support_phone: emailSupportPhone,
logo_url: `${process.env.APP_BASE_URL}/assets/FCSCLogo.png`
};
await sendEmailService(emailUsername, "establishment_user_creation_to_user", emailData);
logger.info(`Establishment user creation email triggered for: ${sanitizeForLog(email)}`);
// Prepare secure response - only non-sensitive data
const responseUserName = user.name;
const responseUserId = user.id;
return res.status(201).json({
status: "success",
message: "Establishment User created successfully.",
});
} catch (error) {
logger.error(error.message);
logger.error(`Stack trace: ${error.stack}`);
return res.status(500).json({ status: "error", message: "Internal server error" });
}
};
// Get all users
exports.getAllUsers = async (req, res) => {
try {
let users;
if (typeof req.query.establishment_id !== 'undefined') {
const establishmentId = parseInt(req.query.establishment_id, 10);
if (Number.isNaN(establishmentId)) {
return res.status(400).json({
status: "failed",
message: "Invalid establishment_id"
});
}
users = await EstablishmentUser.findAll({ where:{ establishment_id : establishmentId} });
}else{
users = await EstablishmentUser.findAll();
}
return res.status(200).send({'status':"success",'message':"Fetched successfully",'data': users });
} catch (err) {
logger.error(err.message);
logger.error(`Stack trace: ${err.stack}`);
return res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};
// Get user by id
exports.getUserById = async (req, res) => {
try {
const user = await EstablishmentUser.findByPk(req.params.id);
if (!user) res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
return res.status(200).send({'status':"success",'message':"Fetched successfully",'data': user });
} catch (err) {
logger.error(err.message);
logger.error(`Stack trace: ${err.stack}`);
return res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};
// Update user
exports.updateUser = async (req, res) => {
try {
const { name, email, is_active, password } = req.body;
const data = {};
// Allow updates only if fields are provided
if (name !== undefined && name !== null) data.name = name;
if (email !== undefined && email !== null) data.email = email;
if (is_active !== undefined && is_active !== null) data.is_active = is_active;
if (password && password.trim() !== "") data.password = await bcrypt.hash(password, 10);
data.updated_by = req.body.updated_by || req.user.id;
data.updated_at = req.body.updated_at || new Date();
const [updated] = await EstablishmentUser.update(data, {
where: { id: req.params.id },
});
if (!updated) return res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
return res.status(200).send({'status':"success",'message':"Record updated successfully",'data': "" });
} catch (err) {
logger.error(err.message);
logger.error(`Stack trace: ${err.stack}`);
return res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};
// Change Establishment User Password
exports.changeUserPassword = async (req, res) => {
try {
const { old_password, new_password, confirm_password } = req.body;
const userId = req.params.id;
// Validate inputs
if (!old_password || !new_password || !confirm_password) {
return res.status(400).send({
status: "failed",
message: "All password fields are required"
});
}
if (new_password !== confirm_password) {
return res.status(400).send({
status: "failed",
message: "New password and confirm password do not match"
});
}
// Find user
const user = await EstablishmentUser.findByPk(userId);
if (!user) {
return res.status(404).send({
status: "failed",
message: "User not found"
});
}
// Verify old password
const isMatch = await bcrypt.compare(old_password, user.password);
if (!isMatch) {
return res.status(401).send({
status: "failed",
message: "Old password is incorrect"
});
}
// Hash and update new password
const hashedPassword = await bcrypt.hash(new_password, 10);
await EstablishmentUser.update(
{ password: hashedPassword, updated_by: req.user.id, updated_at: new Date() },
{ where: { id: userId } }
);
return res.status(200).send({
status: "success",
message: "Password updated successfully"
});
} catch (err) {
logger.error(err.message);
logger.error(`Stack trace: ${err.stack}`);
return res.status(500).send({
status: "failed",
message: "An unexpected error occurred"
});
}
};
// Delete user
exports.deleteUser = async (req, res) => {
try {
const deleted = await EstablishmentUser.destroy({ where: { id: req.params.id } });
if (!deleted) return res.status(404).send({'status':"failed",'message':"Record not found",'data': "" });
return res.status(200).send({'status':"success",'message':"Record deleted successfully",'data': "" });
} catch (err) {
logger.error(err.message);
logger.error(`Stack trace: ${err.stack}`);
return res.status(500).send({'status':"failed",'message': "Internal server error" });
}
};
// Trigger user creation email
exports.triggerEstablishmentUsersWelcomeEmail = async (req, res) => {
try {
let { establishment_id } = req.body;
establishment_id = Number(establishment_id);
if (!Number.isInteger(establishment_id) || establishment_id <= 0) {
return res.status(400).json({
status: "error",
message: "Invalid establishment_id",
});
}
const establishment = await Establishment.findByPk(establishment_id);
if (!establishment) {
return res.status(404).json({
status: "error",
message: "Establishment not found",
});
}
const users = await EstablishmentUser.findAll({
where: {
establishment_id,
is_active: true,
},
});
count = 0;
for (const user of users) {
// Only for users who never logged in
if (user.last_login === null) {
count = count + 1;
// ✅ Generate random 8 character password
const password = crypto.randomBytes(4).toString("hex"); // 8 chars
const hashedPassword = await bcrypt.hash(password, 10);
// ✅ Update password
await EstablishmentUser.update(
{ password: hashedPassword },
{ where: { id: user.id } }
);
// ✅ Send email
await sendEmailService(
user.email,
"establishment_user_creation_to_user",
{
contact_name: formatName(user.name),
portal_url: process.env.FE_BASE_URL,
username: user.email,
password: password,
support_email: process.env.SUPPORT_EMAIL,
support_phone: process.env.SUPPORT_PHONE,
logo_url: `${process.env.APP_BASE_URL}/assets/FCSCLogo.png`
}
);
}
}
if(count != 0)
{
return res.status(200).json({status: "success",message: "Email sent successfully.",});
}else{
return res.status(404).json({status: "failed",message: "Users have already logged in",});
}
} catch (error) {
console.error(error);
logger.error(error.message);
logger.error(`Stack trace: ${error.stack}`);
return res.status(500).json({ status: "error", message: "Internal server error" });
}
};