workwatch
Version:
A Linux terminal program for honest worktime tracking and billing.
153 lines (143 loc) • 5.41 kB
JavaScript
/**
* This file is part of the WorkWatch, a Linux terminal program for honest
* worktime tracking and billing.
*
* Copyright (C) 2020-2025 by Artur Rutkowski
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* WorkWatch is beeing developped and maintained by Artur (locust) Rutkwoski
* <locust@mailbox.org>
*/
/**
* This is a file containing utility functions. Mainly, they are converting
* and validating values. In future versions the validating part will be
* moved to the separate section.
*/
const timeData = require("./utils/time-data.js");
module.exports = {
// Time strings are converted to number of minutes for easier counting and compare.
timeToMinutesNumber(timeString = "00:00") {
return (Number(timeString.split(":")[0]) * 60) + Number(timeString.split(":")[1]);
},
// Oposite direction conversion for clear data storage.
minutesNumberToTime(minutesNumber = 0) {
let hours = Math.floor(minutesNumber / 60);
let minutes = minutesNumber % 60;
return `${(hours < 10)? "0" + hours : hours}:${(minutes < 10)? "0" + minutes : minutes}`;
},
// Time string is very restricted value so validation is neccesarry.
verifyTimeValue(value) {
if (typeof value !== "string") {
const error = new Error("The time value has to be a string.");
error.code = "ERR_FILE_COMMON_WRONG_TIME_VALUE_TYPE";
throw error;
}
if (!/^[0-9]{2}:[0-9]{2}$/.test(value)) {
const error = new Error("Invalid format of the time value.");
error.code = "ERR_FILE_COMMON_INVALID_TIME_FORMAT";
throw error;
}
let [hoursValue, minutesValue] = value.split(":");
if (
!Number.isInteger(Number(hoursValue))
|| (Number(hoursValue) < 0 || Number(hoursValue) > 23)
) {
const error = new Error("The time value contains wrong amount of hours.");
error.code = "ERR_FILE_COMMON_INVALID_HOURS_AMOUNT";
throw error;
}
if (
!Number.isInteger(Number(minutesValue))
|| (Number(minutesValue) < 0 || Number(minutesValue) > 59)
) {
const error = new Error("The time value contains wrong amount of minutes.");
error.code = "ERR_FILE_COMMON_INVALID_MINUTES_AMOUNT";
throw error;
}
return true;
},
// The same as near time strings but for date which is used in worklog.
verifyDateValue(value) {
if (typeof value !== "string") {
const error = new Error("The date value has to be a string.");
error.code = "ERR_FILE_COMMON_WRONG_DATE_VALUE_TYPE";
throw error;
}
if (!/^[0-9]{4}-[0-9]{2}-[0-9]{2}$/.test(value)) {
const error = new Error("Invalid format of the date value.");
error.code = "ERR_FILE_COMMON_INVALID_DATE_FORMAT";
throw error;
}
let [yearValue, monthValue, dayValue] = value.split("-");
if (
!Number.isInteger(Number(monthValue))
|| (Number(monthValue) < 1 || Number(monthValue) > 12)
) {
const error = new Error("The date value contains wrong amount of months.");
error.code = "ERR_FILE_COMMON_INVALID_MONTHS_AMOUNT";
throw error;
}
if (
!Number.isInteger(Number(dayValue))
|| (Number(dayValue) < 1 || Number(dayValue) > 31)
) {
const error = new Error("The date value contains wrong amount of days.");
error.code = "ERR_FILE_COMMON_INVALID_DAYS_AMOUNT";
throw error;
}
try {
// Beside date parts' values, the entire date has to be checked.
let dateValue = (new Date(value)).toISOString().replace(/T.*/, "");
if (value !== dateValue) {
const error = new Error("The date value has wrong month or day range.");
error.code = "ERR_FILE_COMMON_WRONG_RANGE";
throw error;
}
return true;
} catch (err) {
throw err;
}
},
// Time ranges are used in measurements and they has to be verified.
timeRangesToMinutesNumber(hoursRange) {
let minutes = 0;
hoursRange.forEach(range => {
let [fromMinutes, toMinutes] = [
this.timeToMinutesNumber(range.from),
this.timeToMinutesNumber(range.to)
];
minutes += toMinutes - fromMinutes;
});
return minutes;
},
// Validates filename for data files always beeing JSON format.
verifyFilenameValue(filename) {
return (
typeof filename === "string"
&& /^[a-zA-z0-9_\.-]+$/.test(filename)
&& filename.substring(filename.length - 5) !== ".json"
)? true : false;
},
// Gets current time in hh:mm format.
// This is a wrapper for older code to be modified in future versions.
getCorrectTime() {
return timeData.correctTimeShort();
},
// Gets current date in yyyy-mm-dd format.
// This is a wrapper for older code to be modified in future versions.
getCorrectDate() {
return timeData.correctDate;
}
};