va-tracker-middleware/src/controllers/va/vaAuth/vaLogin.controller.js

182 lines
6.2 KiB
JavaScript

import bcrypt from "bcrypt";
import jwt from "jsonwebtoken";
import { VAModel, LoggedModel, WorkTrackModel } from "../../../models/vaModel.js";
// function to close open work tracks and create logout
async function closePreviousSession(vaId, lastLog) {
try {
const currentTime = new Date();
// Find all open work tracks for this VA and project (where to is not set or totalTime is 0)
const openWorkTracks = await WorkTrackModel.find({
vaId,
logId: lastLog._id,
$or: [
{ to: { $exists: false } },
{ totalTime: 0 },
{ to: null }
]
});
// console.log(`Found ${openWorkTracks.length} open work tracks to close`);
// Close all open work tracks
for (const workTrack of openWorkTracks) {
const fromTime = new Date(workTrack.from);
const totalTimeMs = currentTime - fromTime;
// Update the work track with end time and total time
workTrack.to = currentTime;
workTrack.totalTime = totalTimeMs;
await workTrack.save();
// console.log(`Closed work track ${workTrack._id} with duration: ${totalTimeMs}ms`);
}
// Create a logout log entry
const logoutLog = await LoggedModel.create({
loggedType: "LOGOUT",
vaId,
vaEmail: lastLog.vaEmail, // Use email from previous log
projectId: lastLog.projectId,
time: currentTime // Use same timestamp for consistent logging
});
// console.log(`Created logout log: ${logoutLog._id}`);
return {
closedWorkTracks: openWorkTracks.length,
logoutLogId: logoutLog._id
};
} catch (error) {
console.error("Error closing previous session:", error);
throw error;
}
}
// Login VA
async function va_login_callback(req, res) {
try {
// const payload = req.body ? JSON.parse(req.body) : {};
const payload = req.body || {};
const { userDetails } = payload;
if (!userDetails || !userDetails.email || !userDetails.password) {
return res.status(400).json({ success: false, message: "Please provide email and password" });
}
// Find user by email
const user = await VAModel.findOne({ "userDetails.email": userDetails.email });
if (!user) {
return res.status(404).json({ success: false, message: "Invalid credentials" });
}
// const saltRounds = 10;
// const hashedPassword = await bcrypt.hash(userDetails.password, saltRounds);
// Compare password with stored hash
const isMatch = await bcrypt.compare(
userDetails.password,
user.userDetails.password
);
if (!isMatch) {
return res.status(401).json({ success: false, message: "Invalid password" });
}
// also on main login when user try to login into app then logout project and workModel track then allow login on same timestamp
// Check if VA has any active sessions (LOGIN without LOGOUT)
const activeSessions = await LoggedModel.find({
vaId: user._id
}).sort({ time: -1 });
let closeResult = [];
if (activeSessions.length > 0) {
// Get the latest login to check if there's no corresponding logout
const latestLog = activeSessions[0];
closeResult = await closePreviousSession(user._id, latestLog);
}
// Generate JWT accessToken with 24h expiry
const accessToken = jwt.sign(
{
id: user._id,
email: user.userDetails.email,
name: user.userDetails.firstName,
},
process.env.JWT_SECRET_ACCESS_TOKEN || "DocTrackerSecretKey",
// { expiresIn: "24h" }
);
// Generate JWT refreshToken with 24h expiry
const refreshToken = jwt.sign(
{
id: user._id,
email: user.userDetails.email,
name: user.userDetails.firstName,
},
process.env.JWT_SECRET_REFRESH_TOKEN || "DocTrackerSecretKeyRefreshToken",
// { expiresIn: "30d" }
);
await VAModel.updateOne({ "userDetails.email": userDetails.email }, {
$set: { accessToken, refreshToken }
})
let responseData = [];
if (closeResult) {
responseData = {
success: true,
message: "Login Successfull",
accessToken,
refreshToken,
user: {
id: user._id,
name: user.userDetails.firstName,
email: user.userDetails.email,
},
previousSession: {
closedWorkTracks: closeResult.closedWorkTracks,
logoutLogId: closeResult.logoutLogId
}
}
} else {
responseData = {
success: true,
message: "Login Successfull",
accessToken,
refreshToken,
user: {
id: user._id,
name: user.userDetails.firstName,
email: user.userDetails.email,
}
}
}
// Return accessToken and user info
return res.status(200).json(responseData);
} catch (error) {
console.error("va_register error:", error);
return res.status(500).json({ success: false, message: "Internal Server Error" });
}
}
// Helper function to format session duration
function formatSessionDuration(loginTime) {
const now = new Date();
const login = new Date(loginTime);
const durationMs = now - login;
const hours = Math.floor(durationMs / (1000 * 60 * 60));
const minutes = Math.floor((durationMs % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((durationMs % (1000 * 60)) / 1000);
return `${hours}h ${minutes}m ${seconds}s`;
}
export { va_login_callback };