Project import generated by Copybara.
GitOrigin-RevId: 63746295f1a5ab5a619056791995793d65529e62
diff --git a/src/inc/validations.php b/src/inc/validations.php
new file mode 100644
index 0000000..d3c310f
--- /dev/null
+++ b/src/inc/validations.php
@@ -0,0 +1,234 @@
+<?php
+class validations {
+ const DEFAULT_REMINDER_GRACE_PERIOD = 3; // When sending email notifications about pending elements to verify,
+ // only elements effective until the current day minus the grace period
+ // will be checked for validation. (value is given in days)
+
+ const METHOD_SIMPLE = 0;
+ const METHOD_AUTOVALIDATION = 1;
+
+ public static $methodCodename = [
+ 0 => "simple",
+ 1 => "autovalidation"
+ ];
+
+ public static $methodName = [
+ 0 => "Validación por dirección IP",
+ 1 => "Validación automática"
+ ];
+
+ public static $methods = [self::METHOD_SIMPLE, self::METHOD_AUTOVALIDATION];
+ public static $manualMethods = [self::METHOD_SIMPLE];
+
+ public static function reminderGracePeriod() {
+ return $conf["validation"]["gracePeriod"] ?? self::DEFAULT_REMINDER_GRACE_PERIOD;
+ }
+
+ public static function numPending($userId = "ME", $gracePeriod = 0) {
+ global $con;
+
+ if ($userId === "ME") $userId = people::userData("id");
+ $suser = (int)$userId;
+
+ $query = mysqli_query($con, "SELECT COUNT(*) count FROM incidents i INNER JOIN workers w ON i.worker = w.id WHERE w.person = ".$suser." AND ".incidents::$workerPendingWhere." AND ".incidents::$activeWhere.($gracePeriod === false ? "" : " AND (i.day + i.begins) < ".(int)(time() - (int)$gracePeriod*(24*60*60))));
+
+ if (!mysqli_num_rows($query)) return "?";
+
+ $row = mysqli_fetch_assoc($query);
+
+ $count = (int)(isset($row["count"]) ? $row["count"] : 0);
+
+ $query2 = mysqli_query($con, "SELECT COUNT(*) count FROM records r INNER JOIN workers w ON r.worker = w.id WHERE w.person = ".$suser." AND ".registry::$notInvalidatedWhere." AND ".registry::$workerPendingWhere.($gracePeriod === false ? "" : " AND r.day < ".(int)(time() - (int)$gracePeriod*(24*60*60))));
+
+ if (!mysqli_num_rows($query2)) return "?";
+
+ $row2 = mysqli_fetch_assoc($query2);
+
+ return $count + (int)(isset($row2["count"]) ? $row2["count"] : 0);
+ }
+
+ public static function getAllowedMethods() {
+ global $conf;
+
+ $allowedMethods = [];
+ foreach (self::$manualMethods as $method) {
+ if (in_array($method, $conf["validation"]["allowedMethods"])) $allowedMethods[] = $method;
+ }
+
+ return $allowedMethods;
+ }
+
+ private static function string2array($string) {
+ if (!is_string($string) || empty($string)) return [];
+ $explode = explode(",", $string);
+
+ $array = [];
+ foreach ($explode as $el) {
+ $array[] = (int)$el;
+ }
+
+ return $array;
+ }
+
+ private static function createSimpleAttestation($method, $user) {
+ $attestation = [];
+ if (!isset($_SERVER["REMOTE_ADDR"])) return false;
+ $attestation["ipAddress"] = (string)$_SERVER["REMOTE_ADDR"];
+ if ($method === self::METHOD_AUTOVALIDATION) $attestation["user"] = (int)$user;
+ return $attestation;
+ }
+
+ private static function createIncidentAttestation(&$incident, $method, $user) {
+ switch ($method) {
+ case self::METHOD_SIMPLE:
+ case self::METHOD_AUTOVALIDATION:
+ return self::createSimpleAttestation($method, $user);
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ private static function createRecordAttestation(&$record, $method, $user) {
+ switch ($method) {
+ case self::METHOD_SIMPLE:
+ case self::METHOD_AUTOVALIDATION:
+ return self::createSimpleAttestation($method, $user);
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ private static function createValidation($method, $attestation) {
+ $validation = [];
+ $validation["method"] = (int)$method;
+ $validation["timestamp"] = time();
+ $validation["attestation"] = $attestation;
+
+ return $validation;
+ }
+
+ public static function validateIncident($id, $method, $user, $userCheck = true, $stateCheck = true) {
+ global $con;
+
+ if ($user == "ME") $user = people::userData("id");
+ if ($userCheck && !incidents::checkIncidentIsFromPerson($id, "ME", true)) return false;
+
+ $incident = incidents::get($id, true);
+ if ($incident === false || ($stateCheck && $incident["state"] !== incidents::STATE_REGISTERED)) return false;
+
+ $attestation = self::createIncidentAttestation($incident, $method, $user);
+ if ($attestation === false) return false;
+
+ $validation = self::createValidation($method, $attestation);
+
+ $svalidation = db::sanitize(json_encode($validation));
+ $sid = (int)$incident["id"];
+
+ return mysqli_query($con, "UPDATE incidents SET workervalidated = 1, workervalidation = '$svalidation' WHERE id = $sid LIMIT 1");
+ }
+
+ public static function validateRecord($id, $method, $user, $userCheck = true) {
+ global $con;
+
+ if ($user == "ME") $user = people::userData("id");
+ if ($userCheck && !registry::checkRecordIsFromPerson($id, "ME", true)) return false;
+
+ $record = registry::get($id, true);
+ if ($record === false || $record["state"] !== registry::STATE_REGISTERED) return false;
+
+ $attestation = self::createRecordAttestation($record, $method, $user);
+ if ($attestation === false) return false;
+
+ $validation = self::createValidation($method, $attestation);
+
+ $svalidation = db::sanitize(json_encode($validation));
+ $sid = (int)$record["id"];
+
+ return mysqli_query($con, "UPDATE records SET workervalidated = 1, workervalidation = '$svalidation' WHERE id = $sid LIMIT 1");
+ }
+
+ public static function validate($method, $incidents, $records, $user = "ME") {
+ if (!in_array($method, self::getAllowedMethods())) return -1;
+
+ $incidents = self::string2array($incidents);
+ $records = self::string2array($records);
+
+ if ($user == "ME") $user = people::userData("id");
+
+ $flag = false;
+ foreach ($incidents as $incident) {
+ if (!self::validateIncident($incident, $method, $user)) $flag = true;
+ }
+ foreach ($records as $record) {
+ if (!self::validateRecord($record, $method, $user)) $flag = true;
+ }
+
+ return ($flag ? 1 : 0);
+ }
+
+ public static function getPeopleWithPendingValidations($gracePeriod = "DEFAULT") {
+ if ($gracePeriod === "DEFAULT") $gracePeriod = self::reminderGracePeriod();
+
+ $pendingPeople = [];
+
+ $people = people::getAll();
+ foreach ($people as $p) {
+ $numPending = self::numPending((int)$p["id"], $gracePeriod);
+
+ if ($numPending > 0) {
+ $pending = [];
+ $pending["person"] = $p;
+ $pending["numPending"] = $numPending;
+
+ $pendingPeople[] = $pending;
+ }
+ }
+
+ return $pendingPeople;
+ }
+
+ public static function sendPendingValidationsReminder() {
+ global $conf;
+
+ if (!$conf["mail"]["enabled"]) {
+ echo "[error] The mail functionality is not enabled in config.php.\n";
+ return false;
+ }
+
+ if (!$conf["mail"]["capabilities"]["sendPendingValidationsReminder"]) {
+ echo "[error] The pending validation reminders functionality is not inabled in config.php.\n";
+ return false;
+ }
+
+ $pendingPeople = self::getPeopleWithPendingValidations();
+
+ foreach ($pendingPeople as $p) {
+ if (!isset($p["person"]["email"]) || empty($p["person"]["email"])) {
+ echo "[info] ".$p["person"]["id"]." doesn't have an email address defined.\n";
+ continue;
+ }
+
+ $to = [["email" => $p["person"]["email"]]];
+
+ $subject = "[Recordatorio] Tienes validaciones pendientes en el aplicativo de control horario";
+ $body = mail::bodyTemplate("<p>Hola ".security::htmlsafe(($p["person"]["name"]) ?? "").",</p>
+ <p>Este es un mensaje automático para avisarte de que tienes ".(int)$p["numPending"]." incidencias y/o registros pendientes de validar en el aplicativo de control horario.</p>
+ <p>Para validarlos, puedes acceder al aplicativo desde la siguiente dirección:</p>
+ <ul>
+ <li><a href='".security::htmlsafe($conf["fullPath"])."'>".security::htmlsafe($conf["fullPath"])."</a></li>
+ </ul>");
+
+ if (mail::send($to, [], $subject, $body)) {
+ echo "[info] Mail sent to ".$p["person"]["id"]." successfuly.\n";
+ } else {
+ echo "[error] The email couldn't be sent to ".$p["person"]["id"]."\n";
+ }
+ }
+
+ return true;
+ }
+}