Updated project logs function
This commit is contained in:
parent
e55183a2ef
commit
07075bdefb
|
|
@ -1,5 +1,11 @@
|
||||||
import { LoggedModel, ProjectModel } from "../../../models/vaModel.js";
|
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) {
|
async function va_log_callback(req, res) {
|
||||||
try {
|
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) {
|
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
|
let totalSeconds = 0;
|
||||||
const firstLogin = logs.find((l) => l.loggedType === "LOGIN");
|
const sessions = [];
|
||||||
const lastLogout = [...logs].reverse().find((l) => l.loggedType === "LOGOUT");
|
let lastLogin = null; // keep Date object
|
||||||
|
let lastLoginRaw = null; // raw log object for session details
|
||||||
|
|
||||||
if (!firstLogin || !lastLogout) {
|
for (const log of logs) {
|
||||||
return res.json({
|
const t = new Date(log.time);
|
||||||
success: true,
|
|
||||||
message: "Incomplete log data (missing LOGIN or LOGOUT)",
|
if (String(log.loggedType).toUpperCase() === "LOGIN") {
|
||||||
totalWork: "0h 0m",
|
// If there's already an open login (multiple consecutive LOGINS), ignore the new one
|
||||||
firstLogin,
|
if (!lastLogin) {
|
||||||
lastLogout,
|
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
|
// If there's an open LOGIN at the end of the range, close it at toDate (or now if toDate > now)
|
||||||
const diffMs = new Date(lastLogout.time) - new Date(firstLogin.time);
|
if (lastLogin) {
|
||||||
const totalMinutes = Math.floor(diffMs / (1000 * 60));
|
// Use the smaller of toDate and current time as the end point
|
||||||
const hours = Math.floor(totalMinutes / 60);
|
const now = new Date();
|
||||||
const minutes = totalMinutes % 60;
|
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,
|
success: true,
|
||||||
vaId,
|
vaId,
|
||||||
projectId,
|
projectId,
|
||||||
firstLogin: firstLogin.time,
|
from: fromDate,
|
||||||
lastLogout: lastLogout.time,
|
to: toDate,
|
||||||
logs: logs,
|
logs,
|
||||||
totalTimeLogged: `${hours}h ${minutes}m`,
|
sessions,
|
||||||
hoursLogged: hours,
|
totalTimeLogged: formatHMS(totalSeconds),
|
||||||
minutesLogged: minutes,
|
totalSeconds,
|
||||||
|
hoursLogged: Math.floor(totalSeconds / 3600),
|
||||||
|
minutesLogged: Math.floor((totalSeconds % 3600) / 60),
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|
|
||||||
|
|
@ -47,26 +47,59 @@ async function va_profile_update_callback(req, res) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (userDetails.password) {
|
/* ---------------------- PASSWORD UPDATE ---------------------- */
|
||||||
if (!userDetails.cPassword) {
|
if (userDetails.password || userDetails.cPassword || userDetails.oldPassword) {
|
||||||
|
const { oldPassword, password, cPassword } = userDetails;
|
||||||
|
|
||||||
|
if (!oldPassword || !password || !cPassword) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
success: false,
|
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({
|
return res.status(400).json({
|
||||||
success: false,
|
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 saltRounds = 10;
|
||||||
const hashedPassword = await bcrypt.hash(userDetails.password, saltRounds);
|
const hashedPassword = await bcrypt.hash(password, saltRounds);
|
||||||
vaUser.userDetails.password = hashedPassword;
|
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();
|
await vaUser.save();
|
||||||
|
|
||||||
const updatedUser = await VAModel.findById(vaUser._id)
|
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", 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("/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
|
vaRoutes.post("/log/project", authValidator, va_project_log_callback); // VA Logged IN / Logged Out in project
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue