Updated project logs function
This commit is contained in:
parent
e55183a2ef
commit
07075bdefb
|
|
@ -1,5 +1,11 @@
|
|||
import { LoggedModel, ProjectModel } from "../../../models/vaModel.js";
|
||||
|
||||
function formatHMS(totalSeconds) {
|
||||
const hrs = Math.floor(totalSeconds / 3600);
|
||||
const mins = Math.floor((totalSeconds % 3600) / 60);
|
||||
const secs = Math.floor(totalSeconds % 60);
|
||||
return `${hrs}h ${mins}m ${secs}s`;
|
||||
}
|
||||
|
||||
async function va_log_callback(req, res) {
|
||||
try {
|
||||
|
|
@ -35,42 +41,86 @@ async function va_log_callback(req, res) {
|
|||
};
|
||||
|
||||
|
||||
const logs = await LoggedModel.find(query).sort({ time: 1 });
|
||||
const logs = await LoggedModel.find(query).sort({ time: 1 }).lean();
|
||||
|
||||
if (!logs.length) {
|
||||
return res.json({ success: true, message: "No logs found", totalWork: "0h 0m" });
|
||||
return res.json({ success: true, message: "No logs found", totalWork: "0h 0m 0s", totalSeconds: 0, sessions: [] });
|
||||
}
|
||||
|
||||
// Find first LOGIN and last LOGOUT
|
||||
const firstLogin = logs.find((l) => l.loggedType === "LOGIN");
|
||||
const lastLogout = [...logs].reverse().find((l) => l.loggedType === "LOGOUT");
|
||||
let totalSeconds = 0;
|
||||
const sessions = [];
|
||||
let lastLogin = null; // keep Date object
|
||||
let lastLoginRaw = null; // raw log object for session details
|
||||
|
||||
if (!firstLogin || !lastLogout) {
|
||||
return res.json({
|
||||
success: true,
|
||||
message: "Incomplete log data (missing LOGIN or LOGOUT)",
|
||||
totalWork: "0h 0m",
|
||||
firstLogin,
|
||||
lastLogout,
|
||||
for (const log of logs) {
|
||||
const t = new Date(log.time);
|
||||
|
||||
if (String(log.loggedType).toUpperCase() === "LOGIN") {
|
||||
// If there's already an open login (multiple consecutive LOGINS), ignore the new one
|
||||
if (!lastLogin) {
|
||||
lastLogin = t;
|
||||
lastLoginRaw = log;
|
||||
} else {
|
||||
// consecutive LOGIN without LOGOUT — ignore this login (or you may choose to update lastLogin to this newer time)
|
||||
// we'll ignore to favor the first login until a logout arrives
|
||||
}
|
||||
} else if (String(log.loggedType).toUpperCase() === "LOGOUT") {
|
||||
if (lastLogin) {
|
||||
// valid pair: lastLogin -> this logout
|
||||
const diffSec = Math.floor((t - lastLogin) / 1000);
|
||||
if (diffSec > 0) {
|
||||
totalSeconds += diffSec;
|
||||
sessions.push({
|
||||
loginId: lastLoginRaw?._id || null,
|
||||
logoutId: log._id,
|
||||
from: lastLogin,
|
||||
to: t,
|
||||
durationSeconds: diffSec,
|
||||
durationFormatted: formatHMS(diffSec)
|
||||
});
|
||||
}
|
||||
// reset for next pair
|
||||
lastLogin = null;
|
||||
lastLoginRaw = null;
|
||||
} else {
|
||||
// LOGOUT with no preceding LOGIN in range — ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate duration
|
||||
const diffMs = new Date(lastLogout.time) - new Date(firstLogin.time);
|
||||
const totalMinutes = Math.floor(diffMs / (1000 * 60));
|
||||
const hours = Math.floor(totalMinutes / 60);
|
||||
const minutes = totalMinutes % 60;
|
||||
// If there's an open LOGIN at the end of the range, close it at toDate (or now if toDate > now)
|
||||
if (lastLogin) {
|
||||
// Use the smaller of toDate and current time as the end point
|
||||
const now = new Date();
|
||||
const endPoint = toDate > now ? now : toDate;
|
||||
|
||||
res.json({
|
||||
const diffSec = Math.floor((endPoint - lastLogin) / 1000);
|
||||
if (diffSec > 0) {
|
||||
totalSeconds += diffSec;
|
||||
sessions.push({
|
||||
loginId: lastLoginRaw?._id || null,
|
||||
logoutId: null,
|
||||
from: lastLogin,
|
||||
to: endPoint,
|
||||
durationSeconds: diffSec,
|
||||
durationFormatted: formatHMS(diffSec),
|
||||
note: "Open session closed at range end"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return res.json({
|
||||
success: true,
|
||||
vaId,
|
||||
projectId,
|
||||
firstLogin: firstLogin.time,
|
||||
lastLogout: lastLogout.time,
|
||||
logs: logs,
|
||||
totalTimeLogged: `${hours}h ${minutes}m`,
|
||||
hoursLogged: hours,
|
||||
minutesLogged: minutes,
|
||||
from: fromDate,
|
||||
to: toDate,
|
||||
logs,
|
||||
sessions,
|
||||
totalTimeLogged: formatHMS(totalSeconds),
|
||||
totalSeconds,
|
||||
hoursLogged: Math.floor(totalSeconds / 3600),
|
||||
minutesLogged: Math.floor((totalSeconds % 3600) / 60),
|
||||
});
|
||||
|
||||
} catch (err) {
|
||||
|
|
|
|||
|
|
@ -47,26 +47,59 @@ async function va_profile_update_callback(req, res) {
|
|||
}
|
||||
});
|
||||
|
||||
if (userDetails.password) {
|
||||
if (!userDetails.cPassword) {
|
||||
/* ---------------------- PASSWORD UPDATE ---------------------- */
|
||||
if (userDetails.password || userDetails.cPassword || userDetails.oldPassword) {
|
||||
const { oldPassword, password, cPassword } = userDetails;
|
||||
|
||||
if (!oldPassword || !password || !cPassword) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "Please confirm your new password",
|
||||
message: "Please provide oldPassword, password, and cPassword to update password",
|
||||
});
|
||||
}
|
||||
|
||||
if (userDetails.password !== userDetails.cPassword) {
|
||||
if (password !== cPassword) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "Passwords do not match",
|
||||
message: "New passwords do not match",
|
||||
});
|
||||
}
|
||||
|
||||
// Verify old password
|
||||
const isMatch = await bcrypt.compare(oldPassword, vaUser.userDetails.password);
|
||||
if (!isMatch) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: "Old password is incorrect",
|
||||
});
|
||||
}
|
||||
|
||||
// Hash and update new password
|
||||
const saltRounds = 10;
|
||||
const hashedPassword = await bcrypt.hash(userDetails.password, saltRounds);
|
||||
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||
vaUser.userDetails.password = hashedPassword;
|
||||
}
|
||||
|
||||
// if (userDetails.password) {
|
||||
// if (!userDetails.cPassword) {
|
||||
// return res.status(400).json({
|
||||
// success: false,
|
||||
// message: "Please confirm your new password",
|
||||
// });
|
||||
// }
|
||||
|
||||
// if (userDetails.password !== userDetails.cPassword) {
|
||||
// return res.status(400).json({
|
||||
// success: false,
|
||||
// message: "Passwords do not match",
|
||||
// });
|
||||
// }
|
||||
|
||||
// const saltRounds = 10;
|
||||
// const hashedPassword = await bcrypt.hash(userDetails.password, saltRounds);
|
||||
// vaUser.userDetails.password = hashedPassword;
|
||||
// }
|
||||
|
||||
await vaUser.save();
|
||||
|
||||
const updatedUser = await VAModel.findById(vaUser._id)
|
||||
|
|
|
|||
|
|
@ -37,7 +37,13 @@ vaRoutes.get("/search", va_filter_search);
|
|||
vaRoutes.get("/clients/:clientID", va_clients_callback); // VA Clients Callback for getting all clients or specific client by ID
|
||||
vaRoutes.get("/clients/:clientId/projects/:projectId", va_clients_projects_callback); // VA Clients Projects Callback
|
||||
|
||||
vaRoutes.get("/project/:projectId", va_projects_callback);
|
||||
|
||||
|
||||
|
||||
// Getting Project List assigned to VA should be ACTIVE and add total logged hours added by VA
|
||||
vaRoutes.get("/list/project/:projectId", va_projects_callback);
|
||||
// GET Windows Tab Logged Data for VA IN Between Login and LOGOUT
|
||||
vaRoutes.get("/report/project/:projectId", va_projects_callback);
|
||||
|
||||
|
||||
vaRoutes.post("/log/project", authValidator, va_project_log_callback); // VA Logged IN / Logged Out in project
|
||||
|
|
|
|||
Loading…
Reference in New Issue