blob: d3c310f13954cb4a06c8f7c88ca2e391c7ffc74a [file] [log] [blame]
Copybara botbe50d492023-11-30 00:16:42 +01001<?php
2class validations {
3 const DEFAULT_REMINDER_GRACE_PERIOD = 3; // When sending email notifications about pending elements to verify,
4 // only elements effective until the current day minus the grace period
5 // will be checked for validation. (value is given in days)
6
7 const METHOD_SIMPLE = 0;
8 const METHOD_AUTOVALIDATION = 1;
9
10 public static $methodCodename = [
11 0 => "simple",
12 1 => "autovalidation"
13 ];
14
15 public static $methodName = [
16 0 => "Validación por dirección IP",
17 1 => "Validación automática"
18 ];
19
20 public static $methods = [self::METHOD_SIMPLE, self::METHOD_AUTOVALIDATION];
21 public static $manualMethods = [self::METHOD_SIMPLE];
22
23 public static function reminderGracePeriod() {
24 return $conf["validation"]["gracePeriod"] ?? self::DEFAULT_REMINDER_GRACE_PERIOD;
25 }
26
27 public static function numPending($userId = "ME", $gracePeriod = 0) {
28 global $con;
29
30 if ($userId === "ME") $userId = people::userData("id");
31 $suser = (int)$userId;
32
33 $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))));
34
35 if (!mysqli_num_rows($query)) return "?";
36
37 $row = mysqli_fetch_assoc($query);
38
39 $count = (int)(isset($row["count"]) ? $row["count"] : 0);
40
41 $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))));
42
43 if (!mysqli_num_rows($query2)) return "?";
44
45 $row2 = mysqli_fetch_assoc($query2);
46
47 return $count + (int)(isset($row2["count"]) ? $row2["count"] : 0);
48 }
49
50 public static function getAllowedMethods() {
51 global $conf;
52
53 $allowedMethods = [];
54 foreach (self::$manualMethods as $method) {
55 if (in_array($method, $conf["validation"]["allowedMethods"])) $allowedMethods[] = $method;
56 }
57
58 return $allowedMethods;
59 }
60
61 private static function string2array($string) {
62 if (!is_string($string) || empty($string)) return [];
63 $explode = explode(",", $string);
64
65 $array = [];
66 foreach ($explode as $el) {
67 $array[] = (int)$el;
68 }
69
70 return $array;
71 }
72
73 private static function createSimpleAttestation($method, $user) {
74 $attestation = [];
75 if (!isset($_SERVER["REMOTE_ADDR"])) return false;
76 $attestation["ipAddress"] = (string)$_SERVER["REMOTE_ADDR"];
77 if ($method === self::METHOD_AUTOVALIDATION) $attestation["user"] = (int)$user;
78 return $attestation;
79 }
80
81 private static function createIncidentAttestation(&$incident, $method, $user) {
82 switch ($method) {
83 case self::METHOD_SIMPLE:
84 case self::METHOD_AUTOVALIDATION:
85 return self::createSimpleAttestation($method, $user);
86 break;
87
88 default:
89 return false;
90 }
91 }
92
93 private static function createRecordAttestation(&$record, $method, $user) {
94 switch ($method) {
95 case self::METHOD_SIMPLE:
96 case self::METHOD_AUTOVALIDATION:
97 return self::createSimpleAttestation($method, $user);
98 break;
99
100 default:
101 return false;
102 }
103 }
104
105 private static function createValidation($method, $attestation) {
106 $validation = [];
107 $validation["method"] = (int)$method;
108 $validation["timestamp"] = time();
109 $validation["attestation"] = $attestation;
110
111 return $validation;
112 }
113
114 public static function validateIncident($id, $method, $user, $userCheck = true, $stateCheck = true) {
115 global $con;
116
117 if ($user == "ME") $user = people::userData("id");
118 if ($userCheck && !incidents::checkIncidentIsFromPerson($id, "ME", true)) return false;
119
120 $incident = incidents::get($id, true);
121 if ($incident === false || ($stateCheck && $incident["state"] !== incidents::STATE_REGISTERED)) return false;
122
123 $attestation = self::createIncidentAttestation($incident, $method, $user);
124 if ($attestation === false) return false;
125
126 $validation = self::createValidation($method, $attestation);
127
128 $svalidation = db::sanitize(json_encode($validation));
129 $sid = (int)$incident["id"];
130
131 return mysqli_query($con, "UPDATE incidents SET workervalidated = 1, workervalidation = '$svalidation' WHERE id = $sid LIMIT 1");
132 }
133
134 public static function validateRecord($id, $method, $user, $userCheck = true) {
135 global $con;
136
137 if ($user == "ME") $user = people::userData("id");
138 if ($userCheck && !registry::checkRecordIsFromPerson($id, "ME", true)) return false;
139
140 $record = registry::get($id, true);
141 if ($record === false || $record["state"] !== registry::STATE_REGISTERED) return false;
142
143 $attestation = self::createRecordAttestation($record, $method, $user);
144 if ($attestation === false) return false;
145
146 $validation = self::createValidation($method, $attestation);
147
148 $svalidation = db::sanitize(json_encode($validation));
149 $sid = (int)$record["id"];
150
151 return mysqli_query($con, "UPDATE records SET workervalidated = 1, workervalidation = '$svalidation' WHERE id = $sid LIMIT 1");
152 }
153
154 public static function validate($method, $incidents, $records, $user = "ME") {
155 if (!in_array($method, self::getAllowedMethods())) return -1;
156
157 $incidents = self::string2array($incidents);
158 $records = self::string2array($records);
159
160 if ($user == "ME") $user = people::userData("id");
161
162 $flag = false;
163 foreach ($incidents as $incident) {
164 if (!self::validateIncident($incident, $method, $user)) $flag = true;
165 }
166 foreach ($records as $record) {
167 if (!self::validateRecord($record, $method, $user)) $flag = true;
168 }
169
170 return ($flag ? 1 : 0);
171 }
172
173 public static function getPeopleWithPendingValidations($gracePeriod = "DEFAULT") {
174 if ($gracePeriod === "DEFAULT") $gracePeriod = self::reminderGracePeriod();
175
176 $pendingPeople = [];
177
178 $people = people::getAll();
179 foreach ($people as $p) {
180 $numPending = self::numPending((int)$p["id"], $gracePeriod);
181
182 if ($numPending > 0) {
183 $pending = [];
184 $pending["person"] = $p;
185 $pending["numPending"] = $numPending;
186
187 $pendingPeople[] = $pending;
188 }
189 }
190
191 return $pendingPeople;
192 }
193
194 public static function sendPendingValidationsReminder() {
195 global $conf;
196
197 if (!$conf["mail"]["enabled"]) {
198 echo "[error] The mail functionality is not enabled in config.php.\n";
199 return false;
200 }
201
202 if (!$conf["mail"]["capabilities"]["sendPendingValidationsReminder"]) {
203 echo "[error] The pending validation reminders functionality is not inabled in config.php.\n";
204 return false;
205 }
206
207 $pendingPeople = self::getPeopleWithPendingValidations();
208
209 foreach ($pendingPeople as $p) {
210 if (!isset($p["person"]["email"]) || empty($p["person"]["email"])) {
211 echo "[info] ".$p["person"]["id"]." doesn't have an email address defined.\n";
212 continue;
213 }
214
215 $to = [["email" => $p["person"]["email"]]];
216
217 $subject = "[Recordatorio] Tienes validaciones pendientes en el aplicativo de control horario";
218 $body = mail::bodyTemplate("<p>Hola ".security::htmlsafe(($p["person"]["name"]) ?? "").",</p>
219 <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>
220 <p>Para validarlos, puedes acceder al aplicativo desde la siguiente dirección:</p>
221 <ul>
222 <li><a href='".security::htmlsafe($conf["fullPath"])."'>".security::htmlsafe($conf["fullPath"])."</a></li>
223 </ul>");
224
225 if (mail::send($to, [], $subject, $body)) {
226 echo "[info] Mail sent to ".$p["person"]["id"]." successfuly.\n";
227 } else {
228 echo "[error] The email couldn't be sent to ".$p["person"]["id"]."\n";
229 }
230 }
231
232 return true;
233 }
234}