Total Complexity | 261 |
Total Lines | 2866 |
Duplicated Lines | 0 % |
Changes | 0 |
Complex classes like Event often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use Event, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class Event |
||
16 | { |
||
17 | /** |
||
18 | * @author Sebastien Piraux <[email protected]> |
||
19 | * @desc Record information for open event (when homepage is opened) |
||
20 | */ |
||
21 | public static function open() |
||
22 | { |
||
23 | global $_configuration; |
||
24 | global $TABLETRACK_OPEN; |
||
25 | |||
26 | // @getHostByAddr($_SERVER['REMOTE_ADDR']) : will provide host and country information |
||
27 | // $_SERVER['HTTP_USER_AGENT'] : will provide browser and os information |
||
28 | // $_SERVER['HTTP_REFERER'] : provide information about refering url |
||
29 | if (isset($_SERVER['HTTP_REFERER'])) { |
||
30 | $referer = Database::escape_string($_SERVER['HTTP_REFERER']); |
||
31 | } else { |
||
32 | $referer = ''; |
||
33 | } |
||
34 | // record informations only if user comes from another site |
||
35 | //if(!eregi($_configuration['root_web'],$referer)) |
||
36 | $pos = strpos($referer, $_configuration['root_web']); |
||
37 | if ($pos === false && $referer != '') { |
||
38 | $ip = api_get_real_ip(); |
||
39 | $remhost = @gethostbyaddr($ip); |
||
40 | if ($remhost == $ip) { |
||
41 | $remhost = "Unknown"; |
||
42 | } // don't change this |
||
43 | $reallyNow = api_get_utc_datetime(); |
||
44 | $params = [ |
||
45 | 'open_remote_host' => Database::escape_string($remhost), |
||
46 | 'open_agent' => $_SERVER['HTTP_USER_AGENT'], |
||
47 | 'open_referer' => $referer, |
||
48 | 'open_date' => $reallyNow, |
||
49 | ]; |
||
50 | Database::insert($TABLETRACK_OPEN, $params); |
||
51 | } |
||
52 | |||
53 | return 1; |
||
54 | } |
||
55 | |||
56 | /** |
||
57 | * @throws Exception |
||
58 | */ |
||
59 | public static function eventLoginAttempt(string $username, bool $success = false) |
||
60 | { |
||
61 | if ((int) api_get_configuration_value('login_max_attempt_before_blocking_account') <= 0) { |
||
62 | return; |
||
63 | } |
||
64 | |||
65 | $attempt = new TrackELoginAttempt(); |
||
66 | $attempt |
||
67 | ->setUsername($username) |
||
68 | ->setLoginDate(api_get_utc_datetime(null, false, true)) |
||
69 | ->setUserIp(api_get_real_ip()) |
||
70 | ->setSuccess($success) |
||
71 | ; |
||
72 | |||
73 | $em = Database::getManager(); |
||
74 | $em->persist($attempt); |
||
75 | $em->flush(); |
||
76 | } |
||
77 | |||
78 | /** |
||
79 | * @author Sebastien Piraux <[email protected]> old code |
||
80 | * @author Julio Montoya |
||
81 | * |
||
82 | * @param int $userId |
||
83 | * |
||
84 | * @return bool |
||
85 | * @desc Record information for login event when an user identifies himself with username & password |
||
86 | */ |
||
87 | public static function eventLogin($userId) |
||
88 | { |
||
89 | $userInfo = api_get_user_info($userId); |
||
90 | $userId = (int) $userId; |
||
91 | |||
92 | if (empty($userInfo)) { |
||
93 | return false; |
||
94 | } |
||
95 | |||
96 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
97 | $reallyNow = api_get_utc_datetime(); |
||
98 | $userIp = Database::escape_string(api_get_real_ip()); |
||
99 | |||
100 | $sql = "INSERT INTO $table (login_user_id, user_ip, login_date, logout_date) VALUES |
||
101 | ($userId, |
||
102 | '$userIp', |
||
103 | '$reallyNow', |
||
104 | '$reallyNow' |
||
105 | )"; |
||
106 | Database::query($sql); |
||
107 | |||
108 | // Auto subscribe |
||
109 | $status = 'student'; |
||
110 | if ($userInfo['status'] == SESSIONADMIN) { |
||
111 | $status = 'sessionadmin'; |
||
112 | } |
||
113 | if ($userInfo['status'] == COURSEMANAGER) { |
||
114 | $status = 'teacher'; |
||
115 | } |
||
116 | if ($userInfo['status'] == DRH) { |
||
117 | $status = 'DRH'; |
||
118 | } |
||
119 | |||
120 | $autoSubscribe = api_get_setting($status.'_autosubscribe'); |
||
121 | if ($autoSubscribe) { |
||
122 | $autoSubscribe = explode('|', $autoSubscribe); |
||
123 | foreach ($autoSubscribe as $code) { |
||
124 | if (CourseManager::course_exists($code)) { |
||
125 | CourseManager::subscribeUser($userId, $code); |
||
126 | } |
||
127 | } |
||
128 | } |
||
129 | |||
130 | return true; |
||
131 | } |
||
132 | |||
133 | /** |
||
134 | * @param int $sessionId |
||
135 | * |
||
136 | * @return bool |
||
137 | */ |
||
138 | public static function isSessionLogNeedToBeSave($sessionId) |
||
139 | { |
||
140 | if (!empty($sessionId)) { |
||
141 | $visibility = api_get_session_visibility($sessionId); |
||
142 | if (!empty($visibility) && $visibility != SESSION_AVAILABLE) { |
||
143 | $extraFieldValue = new ExtraFieldValue('session'); |
||
144 | $value = $extraFieldValue->get_values_by_handler_and_field_variable( |
||
145 | $sessionId, |
||
146 | 'disable_log_after_session_ends' |
||
147 | ); |
||
148 | if (!empty($value) && isset($value['value']) && (int) $value['value'] == 1) { |
||
149 | return false; |
||
150 | } |
||
151 | } |
||
152 | } |
||
153 | |||
154 | return true; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * @author Sebastien Piraux <[email protected]> |
||
159 | * @desc Record information for access event for courses |
||
160 | * |
||
161 | * @return bool |
||
162 | */ |
||
163 | public static function accessCourse() |
||
164 | { |
||
165 | if (Session::read('login_as')) { |
||
166 | return false; |
||
167 | } |
||
168 | |||
169 | $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS); |
||
170 | // For "what's new" notification |
||
171 | $TABLETRACK_LASTACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
172 | |||
173 | $sessionId = api_get_session_id(); |
||
174 | $now = api_get_utc_datetime(); |
||
175 | $courseId = api_get_course_int_id(); |
||
176 | $userId = api_get_user_id(); |
||
177 | $ip = Database::escape_string(api_get_real_ip()); |
||
178 | |||
179 | if (self::isSessionLogNeedToBeSave($sessionId) === false) { |
||
180 | return false; |
||
181 | } |
||
182 | |||
183 | if ($userId) { |
||
184 | $userId = $userId; |
||
185 | } else { |
||
186 | $userId = '0'; // no one |
||
187 | } |
||
188 | $sql = "INSERT INTO $TABLETRACK_ACCESS (user_ip, access_user_id, c_id, access_date, access_session_id) |
||
189 | VALUES ('$ip', $userId, $courseId, '$now', $sessionId)"; |
||
190 | |||
191 | Database::query($sql); |
||
192 | |||
193 | // added for "what's new" notification |
||
194 | $sql = "UPDATE $TABLETRACK_LASTACCESS SET access_date = '$now' |
||
195 | WHERE |
||
196 | access_user_id = $userId AND |
||
197 | c_id = $courseId AND |
||
198 | access_tool IS NULL AND |
||
199 | access_session_id = $sessionId"; |
||
200 | $result = Database::query($sql); |
||
201 | |||
202 | if (Database::affected_rows($result) == 0) { |
||
203 | $sql = "INSERT INTO $TABLETRACK_LASTACCESS (access_user_id, c_id, access_date, access_session_id) |
||
204 | VALUES ($userId, $courseId, '$now', $sessionId)"; |
||
205 | Database::query($sql); |
||
206 | } |
||
207 | |||
208 | return true; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * @param string $tool name of the tool |
||
213 | * |
||
214 | * @author Sebastien Piraux <[email protected]> |
||
215 | * @desc Record information for access event for tools |
||
216 | * |
||
217 | * $tool can take this values : |
||
218 | * Links, Calendar, Document, Announcements, |
||
219 | * Group, Video, Works, Users, Exercises, Course Desc |
||
220 | * ... |
||
221 | * Values can be added if new modules are created (15char max) |
||
222 | * I encourage to use $nameTool as $tool when calling this function |
||
223 | * |
||
224 | * Functionality for "what's new" notification is added by Toon Van Hoecke |
||
225 | * |
||
226 | * @return bool |
||
227 | */ |
||
228 | public static function event_access_tool($tool) |
||
229 | { |
||
230 | if (Session::read('login_as')) { |
||
231 | return false; |
||
232 | } |
||
233 | |||
234 | $tool = Database::escape_string($tool); |
||
235 | |||
236 | if (empty($tool)) { |
||
237 | return false; |
||
238 | } |
||
239 | |||
240 | $courseInfo = api_get_course_info(); |
||
241 | $sessionId = api_get_session_id(); |
||
242 | $reallyNow = api_get_utc_datetime(); |
||
243 | $userId = api_get_user_id(); |
||
244 | |||
245 | if (empty($courseInfo)) { |
||
246 | return false; |
||
247 | } |
||
248 | |||
249 | if (self::isSessionLogNeedToBeSave($sessionId) === false) { |
||
250 | return false; |
||
251 | } |
||
252 | |||
253 | $courseId = $courseInfo['real_id']; |
||
254 | |||
255 | $tableAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS); |
||
256 | //for "what's new" notification |
||
257 | $tableLastAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); |
||
258 | |||
259 | // record information |
||
260 | // only if user comes from the course $_cid |
||
261 | //if( eregi($_configuration['root_web'].$_cid,$_SERVER['HTTP_REFERER'] ) ) |
||
262 | //$pos = strpos($_SERVER['HTTP_REFERER'],$_configuration['root_web'].$_cid); |
||
263 | $coursePath = isset($courseInfo['path']) ? $courseInfo['path'] : null; |
||
264 | |||
265 | $pos = isset($_SERVER['HTTP_REFERER']) ? strpos(strtolower($_SERVER['HTTP_REFERER']), strtolower(api_get_path(WEB_COURSE_PATH).$coursePath)) : false; |
||
266 | // added for "what's new" notification |
||
267 | $pos2 = isset($_SERVER['HTTP_REFERER']) ? strpos(strtolower($_SERVER['HTTP_REFERER']), strtolower(api_get_path(WEB_PATH)."index")) : false; |
||
268 | |||
269 | // end "what's new" notification |
||
270 | if ($pos !== false || $pos2 !== false) { |
||
271 | $params = [ |
||
272 | 'access_user_id' => $userId, |
||
273 | 'c_id' => $courseId, |
||
274 | 'access_tool' => $tool, |
||
275 | 'access_date' => $reallyNow, |
||
276 | 'access_session_id' => $sessionId, |
||
277 | 'user_ip' => Database::escape_string(api_get_real_ip()), |
||
278 | ]; |
||
279 | Database::insert($tableAccess, $params); |
||
280 | } |
||
281 | |||
282 | // "what's new" notification |
||
283 | $sql = "UPDATE $tableLastAccess |
||
284 | SET access_date = '$reallyNow' |
||
285 | WHERE |
||
286 | access_user_id = $userId AND |
||
287 | c_id = $courseId AND |
||
288 | access_tool = '$tool' AND |
||
289 | access_session_id = $sessionId"; |
||
290 | $result = Database::query($sql); |
||
291 | |||
292 | if (Database::affected_rows($result) == 0) { |
||
293 | $params = [ |
||
294 | 'access_user_id' => $userId, |
||
295 | 'c_id' => $courseId, |
||
296 | 'access_tool' => $tool, |
||
297 | 'access_date' => $reallyNow, |
||
298 | 'access_session_id' => $sessionId, |
||
299 | ]; |
||
300 | Database::insert($tableLastAccess, $params); |
||
301 | } |
||
302 | |||
303 | return true; |
||
304 | } |
||
305 | |||
306 | /** |
||
307 | * Record information for download event (when an user click to d/l a |
||
308 | * document) it will be used in a redirection page. |
||
309 | * |
||
310 | * @param string $documentUrl |
||
311 | * |
||
312 | * @return int |
||
313 | * |
||
314 | * @author Sebastien Piraux <[email protected]> |
||
315 | * @author Evie Embrechts (bug fixed: The user id is put in single quotes) |
||
316 | */ |
||
317 | public static function event_download($documentUrl) |
||
318 | { |
||
319 | if (Session::read('login_as')) { |
||
320 | return false; |
||
321 | } |
||
322 | |||
323 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS); |
||
324 | $documentUrl = Database::escape_string($documentUrl); |
||
325 | |||
326 | $reallyNow = api_get_utc_datetime(); |
||
327 | $userId = api_get_user_id(); |
||
328 | $courseId = api_get_course_int_id(); |
||
329 | $sessionId = api_get_session_id(); |
||
330 | |||
331 | return Database::insert( |
||
332 | $table, |
||
333 | [ |
||
334 | 'down_user_id' => $userId, |
||
335 | 'c_id' => $courseId, |
||
336 | 'down_doc_path' => $documentUrl, |
||
337 | 'down_date' => $reallyNow, |
||
338 | 'down_session_id' => $sessionId, |
||
339 | ] |
||
340 | ); |
||
341 | } |
||
342 | |||
343 | /** |
||
344 | * @param int $documentId of document (id in mainDb.document table) |
||
345 | * |
||
346 | * @author Sebastien Piraux <[email protected]> |
||
347 | * @desc Record information for upload event |
||
348 | * used in the works tool to record informations when |
||
349 | * an user upload 1 work |
||
350 | * |
||
351 | * @return int |
||
352 | */ |
||
353 | public static function event_upload($documentId) |
||
354 | { |
||
355 | if (Session::read('login_as')) { |
||
356 | return false; |
||
357 | } |
||
358 | |||
359 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS); |
||
360 | $courseId = api_get_course_int_id(); |
||
361 | $reallyNow = api_get_utc_datetime(); |
||
362 | $userId = api_get_user_id(); |
||
363 | $documentId = (int) $documentId; |
||
364 | $sessionId = api_get_session_id(); |
||
365 | |||
366 | $sql = "INSERT INTO $table |
||
367 | ( upload_user_id, |
||
368 | c_id, |
||
369 | upload_cours_id, |
||
370 | upload_work_id, |
||
371 | upload_date, |
||
372 | upload_session_id |
||
373 | ) |
||
374 | VALUES ( |
||
375 | $userId, |
||
376 | $courseId, |
||
377 | '', |
||
378 | $documentId, |
||
379 | '$reallyNow', |
||
380 | $sessionId |
||
381 | )"; |
||
382 | Database::query($sql); |
||
383 | |||
384 | return 1; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * Record information for link event (when an user click on an added link) |
||
389 | * it will be used in a redirection page. |
||
390 | * |
||
391 | * @param int $linkId (id in c_link table) |
||
392 | * |
||
393 | * @return int |
||
394 | * |
||
395 | * @author Sebastien Piraux <[email protected]> |
||
396 | */ |
||
397 | public static function event_link($linkId) |
||
398 | { |
||
399 | if (Session::read('login_as')) { |
||
400 | return false; |
||
401 | } |
||
402 | |||
403 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS); |
||
404 | $reallyNow = api_get_utc_datetime(); |
||
405 | $userId = api_get_user_id(); |
||
406 | $courseId = api_get_course_int_id(); |
||
407 | $linkId = (int) $linkId; |
||
408 | $sessionId = api_get_session_id(); |
||
409 | $sql = "INSERT INTO ".$table." |
||
410 | ( links_user_id, |
||
411 | c_id, |
||
412 | links_link_id, |
||
413 | links_date, |
||
414 | links_session_id |
||
415 | ) VALUES ( |
||
416 | $userId, |
||
417 | $courseId, |
||
418 | $linkId, |
||
419 | '$reallyNow', |
||
420 | $sessionId |
||
421 | )"; |
||
422 | Database::query($sql); |
||
423 | |||
424 | return 1; |
||
425 | } |
||
426 | |||
427 | /** |
||
428 | * Update the TRACK_E_EXERCICES exercises. |
||
429 | * Record result of user when an exercise was done. |
||
430 | * |
||
431 | * @param int $exeId |
||
432 | * @param int $exoId |
||
433 | * @param mixed $score |
||
434 | * @param int $weighting |
||
435 | * @param int $sessionId |
||
436 | * @param int $learnpathId |
||
437 | * @param int $learnpathItemId |
||
438 | * @param int $learnpathItemViewId |
||
439 | * @param int $duration |
||
440 | * @param array $questionsList |
||
441 | * @param string $status |
||
442 | * @param array $remindList |
||
443 | * @param null $endDate |
||
|
|||
444 | * |
||
445 | * @return bool |
||
446 | * |
||
447 | * @author Sebastien Piraux <[email protected]> |
||
448 | * @author Julio Montoya Armas <[email protected]> Reworked 2010 |
||
449 | */ |
||
450 | public static function updateEventExercise( |
||
451 | $exeId, |
||
452 | $exoId, |
||
453 | $score, |
||
454 | $weighting, |
||
455 | $sessionId, |
||
456 | $learnpathId = 0, |
||
457 | $learnpathItemId = 0, |
||
458 | $learnpathItemViewId = 0, |
||
459 | $duration = 0, |
||
460 | $questionsList = [], |
||
461 | $status = '', |
||
462 | $remindList = [], |
||
463 | $endDate = null |
||
464 | ) { |
||
465 | if (empty($exeId)) { |
||
466 | return false; |
||
467 | } |
||
468 | if (!isset($status) || empty($status)) { |
||
469 | $status = ''; |
||
470 | } else { |
||
471 | $status = Database::escape_string($status); |
||
472 | } |
||
473 | |||
474 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
475 | |||
476 | if (!empty($questionsList)) { |
||
477 | $questionsList = array_map('intval', $questionsList); |
||
478 | } |
||
479 | |||
480 | if (!empty($remindList)) { |
||
481 | $remindList = array_map('intval', $remindList); |
||
482 | $remindList = array_filter($remindList); |
||
483 | $remindList = implode(",", $remindList); |
||
484 | } else { |
||
485 | $remindList = ''; |
||
486 | } |
||
487 | |||
488 | if (empty($endDate)) { |
||
489 | $endDate = api_get_utc_datetime(); |
||
490 | } |
||
491 | $exoId = (int) $exoId; |
||
492 | $sessionId = (int) $sessionId; |
||
493 | $learnpathId = (int) $learnpathId; |
||
494 | $learnpathItemId = (int) $learnpathItemId; |
||
495 | $learnpathItemViewId = (int) $learnpathItemViewId; |
||
496 | $duration = (int) $duration; |
||
497 | $exeId = (int) $exeId; |
||
498 | $score = Database::escape_string($score); |
||
499 | $weighting = Database::escape_string($weighting); |
||
500 | $questions = implode(',', $questionsList); |
||
501 | $userIp = Database::escape_string(api_get_real_ip()); |
||
502 | |||
503 | $sql = "UPDATE $table SET |
||
504 | exe_exo_id = $exoId, |
||
505 | exe_result = '$score', |
||
506 | exe_weighting = '$weighting', |
||
507 | session_id = $sessionId, |
||
508 | orig_lp_id = $learnpathId, |
||
509 | orig_lp_item_id = $learnpathItemId, |
||
510 | orig_lp_item_view_id = $learnpathItemViewId, |
||
511 | exe_duration = $duration, |
||
512 | exe_date = '$endDate', |
||
513 | status = '$status', |
||
514 | questions_to_check = '$remindList', |
||
515 | data_tracking = '$questions', |
||
516 | user_ip = '$userIp' |
||
517 | WHERE exe_id = $exeId"; |
||
518 | Database::query($sql); |
||
519 | |||
520 | //Deleting control time session track |
||
521 | //ExerciseLib::exercise_time_control_delete($exo_id); |
||
522 | return true; |
||
523 | } |
||
524 | |||
525 | /** |
||
526 | * Record an event for this attempt at answering an exercise. |
||
527 | * |
||
528 | * @param float $score Score achieved |
||
529 | * @param string $answer Answer given |
||
530 | * @param int $question_id |
||
531 | * @param int $exe_id Exercise attempt ID a.k.a exe_id (from track_e_exercise) |
||
532 | * @param int $position |
||
533 | * @param int $exercise_id From c_quiz |
||
534 | * @param bool $updateResults |
||
535 | * @param int $duration Time spent in seconds |
||
536 | * @param string $fileName Filename (for audio answers - using nanogong) |
||
537 | * @param int $user_id The user who's going to get this score. |
||
538 | * @param int $course_id Default value of null means "get from context". |
||
539 | * @param int $session_id Default value of null means "get from context". |
||
540 | * @param int $learnpath_id (from c_lp table). Default value of null means "get from context". |
||
541 | * @param int $learnpath_item_id (from the c_lp_item table). Default value of null means "get from context". |
||
542 | * |
||
543 | * @return bool Result of the insert query |
||
544 | */ |
||
545 | public static function saveQuestionAttempt( |
||
546 | $score, |
||
547 | $answer, |
||
548 | $question_id, |
||
549 | $exe_id, |
||
550 | $position, |
||
551 | $exercise_id = 0, |
||
552 | $updateResults = false, |
||
553 | $questionDuration = 0, |
||
554 | $fileName = null, |
||
555 | $user_id = null, |
||
556 | $course_id = null, |
||
557 | $session_id = null, |
||
558 | $learnpath_id = null, |
||
559 | $learnpath_item_id = null |
||
560 | ) { |
||
561 | global $debug; |
||
562 | $questionDuration = (int) $questionDuration; |
||
563 | $question_id = (int) $question_id; |
||
564 | $exe_id = (int) $exe_id; |
||
565 | $position = (int) $position; |
||
566 | $course_id = (int) $course_id; |
||
567 | $now = api_get_utc_datetime(); |
||
568 | $recording = api_get_configuration_value('quiz_answer_extra_recording'); |
||
569 | |||
570 | // check user_id or get from context |
||
571 | if (empty($user_id)) { |
||
572 | $user_id = api_get_user_id(); |
||
573 | // anonymous |
||
574 | if (empty($user_id)) { |
||
575 | $user_id = api_get_anonymous_id(); |
||
576 | } |
||
577 | } |
||
578 | // check course_id or get from context |
||
579 | if (empty($course_id)) { |
||
580 | $course_id = api_get_course_int_id(); |
||
581 | } |
||
582 | // check session_id or get from context |
||
583 | $session_id = (int) $session_id; |
||
584 | if (empty($session_id)) { |
||
585 | $session_id = api_get_session_id(); |
||
586 | } |
||
587 | // check learnpath_id or get from context |
||
588 | if (empty($learnpath_id)) { |
||
589 | global $learnpath_id; |
||
590 | } |
||
591 | // check learnpath_item_id or get from context |
||
592 | if (empty($learnpath_item_id)) { |
||
593 | global $learnpath_item_id; |
||
594 | } |
||
595 | |||
596 | $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
597 | |||
598 | if ($debug) { |
||
599 | error_log("----- entering saveQuestionAttempt() function ------"); |
||
600 | error_log("answer: $answer"); |
||
601 | error_log("score: $score"); |
||
602 | error_log("question_id : $question_id"); |
||
603 | error_log("position: $position"); |
||
604 | } |
||
605 | |||
606 | // Validation in case of fraud with active control time. |
||
607 | if (!ExerciseLib::exercise_time_control_is_valid($exercise_id, $learnpath_id, $learnpath_item_id)) { |
||
608 | if ($debug) { |
||
609 | error_log("exercise_time_control_is_valid is false"); |
||
610 | } |
||
611 | $score = 0; |
||
612 | $answer = 0; |
||
613 | } |
||
614 | |||
615 | if (empty($question_id) || empty($exe_id) || empty($user_id)) { |
||
616 | return false; |
||
617 | } |
||
618 | |||
619 | if (null === $answer) { |
||
620 | $answer = ''; |
||
621 | } |
||
622 | |||
623 | if (null === $score) { |
||
624 | $score = 0; |
||
625 | } |
||
626 | |||
627 | $attempt = [ |
||
628 | 'user_id' => $user_id, |
||
629 | 'question_id' => $question_id, |
||
630 | 'answer' => $answer, |
||
631 | 'marks' => $score, |
||
632 | 'c_id' => $course_id, |
||
633 | 'session_id' => $session_id, |
||
634 | 'position' => $position, |
||
635 | 'tms' => $now, |
||
636 | 'filename' => !empty($fileName) ? basename($fileName) : $fileName, |
||
637 | 'teacher_comment' => '', |
||
638 | ]; |
||
639 | |||
640 | if (api_get_configuration_value('allow_time_per_question')) { |
||
641 | $attempt['seconds_spent'] = $questionDuration; |
||
642 | } |
||
643 | |||
644 | // Check if attempt exists. |
||
645 | $sql = "SELECT exe_id FROM $TBL_TRACK_ATTEMPT |
||
646 | WHERE |
||
647 | c_id = $course_id AND |
||
648 | session_id = $session_id AND |
||
649 | exe_id = $exe_id AND |
||
650 | user_id = $user_id AND |
||
651 | question_id = $question_id AND |
||
652 | position = $position"; |
||
653 | $result = Database::query($sql); |
||
654 | $attemptData = []; |
||
655 | if (Database::num_rows($result)) { |
||
656 | $attemptData = Database::fetch_array($result, 'ASSOC'); |
||
657 | if ($updateResults == false) { |
||
658 | // The attempt already exist do not update use update_event_exercise() instead |
||
659 | return false; |
||
660 | } |
||
661 | } else { |
||
662 | $attempt['exe_id'] = $exe_id; |
||
663 | } |
||
664 | |||
665 | if ($debug) { |
||
666 | error_log("updateResults : $updateResults"); |
||
667 | error_log("Saving question attempt: "); |
||
668 | error_log($sql); |
||
669 | } |
||
670 | |||
671 | $recording_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
||
672 | if ($updateResults == false) { |
||
673 | $attempt_id = Database::insert($TBL_TRACK_ATTEMPT, $attempt); |
||
674 | if ($recording) { |
||
675 | $attempt_recording = [ |
||
676 | 'exe_id' => $exe_id, |
||
677 | 'question_id' => $question_id, |
||
678 | 'answer' => $answer, |
||
679 | 'marks' => $score, |
||
680 | 'insert_date' => $now, |
||
681 | 'session_id' => $session_id, |
||
682 | ]; |
||
683 | Database::insert($recording_table, $attempt_recording); |
||
684 | } |
||
685 | } else { |
||
686 | if (api_get_configuration_value('allow_time_per_question')) { |
||
687 | $attempt['seconds_spent'] = $questionDuration + (int) $attemptData['seconds_spent']; |
||
688 | } |
||
689 | Database::update( |
||
690 | $TBL_TRACK_ATTEMPT, |
||
691 | $attempt, |
||
692 | [ |
||
693 | 'exe_id = ? AND question_id = ? AND user_id = ? ' => [ |
||
694 | $exe_id, |
||
695 | $question_id, |
||
696 | $user_id, |
||
697 | ], |
||
698 | ] |
||
699 | ); |
||
700 | |||
701 | if ($recording) { |
||
702 | $attempt_recording = [ |
||
703 | 'exe_id' => $exe_id, |
||
704 | 'question_id' => $question_id, |
||
705 | 'answer' => $answer, |
||
706 | 'marks' => $score, |
||
707 | 'insert_date' => $now, |
||
708 | 'session_id' => $session_id, |
||
709 | ]; |
||
710 | |||
711 | Database::update( |
||
712 | $recording_table, |
||
713 | $attempt_recording, |
||
714 | [ |
||
715 | 'exe_id = ? AND question_id = ? AND session_id = ? ' => [ |
||
716 | $exe_id, |
||
717 | $question_id, |
||
718 | $session_id, |
||
719 | ], |
||
720 | ] |
||
721 | ); |
||
722 | } |
||
723 | $attempt_id = $exe_id; |
||
724 | } |
||
725 | |||
726 | return $attempt_id; |
||
727 | } |
||
728 | |||
729 | /** |
||
730 | * Record an hotspot spot for this attempt at answering an hotspot question. |
||
731 | * |
||
732 | * @param int $exeId |
||
733 | * @param int $questionId Question ID |
||
734 | * @param int $answerId Answer ID |
||
735 | * @param int $correct |
||
736 | * @param string $coords Coordinates of this point (e.g. 123;324) |
||
737 | * @param bool $updateResults |
||
738 | * @param int $exerciseId |
||
739 | * |
||
740 | * @return bool Result of the insert query |
||
741 | * |
||
742 | * @uses \Course code and user_id from global scope $_cid and $_user |
||
743 | */ |
||
744 | public static function saveExerciseAttemptHotspot( |
||
745 | $exeId, |
||
746 | $questionId, |
||
747 | $answerId, |
||
748 | $correct, |
||
749 | $coords, |
||
750 | $updateResults = false, |
||
751 | $exerciseId = 0, |
||
752 | $lpId = 0, |
||
753 | $lpItemId = 0 |
||
754 | ) { |
||
755 | $debug = false; |
||
756 | |||
757 | if ($updateResults == false) { |
||
758 | // Validation in case of fraud with activated control time |
||
759 | if (!ExerciseLib::exercise_time_control_is_valid($exerciseId, $lpId, $lpItemId)) { |
||
760 | if ($debug) { |
||
761 | error_log('Attempt is fraud'); |
||
762 | } |
||
763 | $correct = 0; |
||
764 | } |
||
765 | } |
||
766 | |||
767 | if (empty($exeId)) { |
||
768 | if ($debug) { |
||
769 | error_log('exe id is empty'); |
||
770 | } |
||
771 | |||
772 | return false; |
||
773 | } |
||
774 | |||
775 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); |
||
776 | if ($updateResults) { |
||
777 | if ($debug) { |
||
778 | error_log("Insert hotspot results: exeId: $exeId correct: $correct"); |
||
779 | } |
||
780 | $params = [ |
||
781 | 'hotspot_correct' => $correct, |
||
782 | 'hotspot_coordinate' => $coords, |
||
783 | ]; |
||
784 | Database::update( |
||
785 | $table, |
||
786 | $params, |
||
787 | [ |
||
788 | 'hotspot_user_id = ? AND hotspot_exe_id = ? AND hotspot_question_id = ? AND hotspot_answer_id = ? ' => [ |
||
789 | api_get_user_id(), |
||
790 | $exeId, |
||
791 | $questionId, |
||
792 | $answerId, |
||
793 | ], |
||
794 | ] |
||
795 | ); |
||
796 | } else { |
||
797 | if ($debug) { |
||
798 | error_log("Insert hotspot results: exeId: $exeId correct: $correct"); |
||
799 | } |
||
800 | |||
801 | return Database::insert( |
||
802 | $table, |
||
803 | [ |
||
804 | 'hotspot_course_code' => api_get_course_id(), |
||
805 | 'hotspot_user_id' => api_get_user_id(), |
||
806 | 'c_id' => api_get_course_int_id(), |
||
807 | 'hotspot_exe_id' => $exeId, |
||
808 | 'hotspot_question_id' => $questionId, |
||
809 | 'hotspot_answer_id' => $answerId, |
||
810 | 'hotspot_correct' => $correct, |
||
811 | 'hotspot_coordinate' => $coords, |
||
812 | ] |
||
813 | ); |
||
814 | } |
||
815 | } |
||
816 | |||
817 | /** |
||
818 | * Records information for common (or admin) events (in the track_e_default table). |
||
819 | * |
||
820 | * @author Yannick Warnier <[email protected]> |
||
821 | * |
||
822 | * @param string $event_type Type of event |
||
823 | * @param string $event_value_type Type of value |
||
824 | * @param mixed $event_value Value (string, or array in the case of user info) |
||
825 | * @param string $datetime Datetime (UTC) (defaults to null) |
||
826 | * @param int $user_id User ID (defaults to null) |
||
827 | * @param int $course_id Course ID (defaults to null) |
||
828 | * @param int $sessionId Session ID |
||
829 | * |
||
830 | * @return bool |
||
831 | * @assert ('','','') === false |
||
832 | */ |
||
833 | public static function addEvent( |
||
834 | $event_type, |
||
835 | $event_value_type, |
||
836 | $event_value, |
||
837 | $datetime = null, |
||
838 | $user_id = null, |
||
839 | $course_id = null, |
||
840 | $sessionId = 0 |
||
841 | ) { |
||
842 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT); |
||
843 | |||
844 | if (empty($event_type)) { |
||
845 | return false; |
||
846 | } |
||
847 | $event_type = Database::escape_string($event_type); |
||
848 | $event_value_type = Database::escape_string($event_value_type); |
||
849 | if (!empty($course_id)) { |
||
850 | $course_id = (int) $course_id; |
||
851 | } else { |
||
852 | $course_id = api_get_course_int_id(); |
||
853 | } |
||
854 | if (!empty($sessionId)) { |
||
855 | $sessionId = (int) $sessionId; |
||
856 | } else { |
||
857 | $sessionId = api_get_session_id(); |
||
858 | } |
||
859 | |||
860 | //Clean the user_info |
||
861 | if ($event_value_type == LOG_USER_OBJECT) { |
||
862 | if (is_array($event_value)) { |
||
863 | unset($event_value['complete_name']); |
||
864 | unset($event_value['complete_name_with_username']); |
||
865 | unset($event_value['firstName']); |
||
866 | unset($event_value['lastName']); |
||
867 | unset($event_value['avatar_small']); |
||
868 | unset($event_value['avatar']); |
||
869 | unset($event_value['mail']); |
||
870 | unset($event_value['password']); |
||
871 | unset($event_value['last_login']); |
||
872 | unset($event_value['picture_uri']); |
||
873 | $event_value = serialize($event_value); |
||
874 | } |
||
875 | } |
||
876 | // If event is an array then the $event_value_type should finish with |
||
877 | // the suffix _array for example LOG_WORK_DATA = work_data_array |
||
878 | if (is_array($event_value)) { |
||
879 | $event_value = serialize($event_value); |
||
880 | } |
||
881 | |||
882 | $event_value = Database::escape_string($event_value); |
||
883 | $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId; |
||
884 | |||
885 | if (!isset($datetime)) { |
||
886 | $datetime = api_get_utc_datetime(); |
||
887 | } |
||
888 | |||
889 | $datetime = Database::escape_string($datetime); |
||
890 | |||
891 | if (!isset($user_id)) { |
||
892 | $user_id = api_get_user_id(); |
||
893 | } |
||
894 | |||
895 | $params = [ |
||
896 | 'default_user_id' => $user_id, |
||
897 | 'c_id' => $course_id, |
||
898 | 'default_date' => $datetime, |
||
899 | 'default_event_type' => $event_type, |
||
900 | 'default_value_type' => $event_value_type, |
||
901 | 'default_value' => $event_value, |
||
902 | 'session_id' => $sessionId, |
||
903 | ]; |
||
904 | Database::insert($table, $params); |
||
905 | |||
906 | return true; |
||
907 | } |
||
908 | |||
909 | public static function findUserSubscriptionToCourse(int $userId, int $courseId, int $sessionId = 0) |
||
910 | { |
||
911 | $tblTrackEDefault = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT); |
||
912 | |||
913 | return Database::select( |
||
914 | '*', |
||
915 | $tblTrackEDefault, |
||
916 | [ |
||
917 | 'where' => [ |
||
918 | 'default_event_type = ? AND ' => LOG_SUBSCRIBE_USER_TO_COURSE, |
||
919 | 'default_value_type = ? AND ' => LOG_USER_OBJECT, |
||
920 | 'default_value LIKE ? AND ' => '%s:2:\\\\"id\\\\";i:'.$userId.'%', |
||
921 | 'c_id = ? AND ' => $courseId, |
||
922 | 'session_id = ?' => $sessionId, |
||
923 | ], |
||
924 | ], |
||
925 | 'first' |
||
926 | ); |
||
927 | } |
||
928 | |||
929 | /** |
||
930 | * Get every email stored in the database. |
||
931 | * |
||
932 | * @deprecated |
||
933 | * |
||
934 | * @return array |
||
935 | * @assert () !== false |
||
936 | */ |
||
937 | public static function get_all_event_types() |
||
938 | { |
||
939 | global $event_config; |
||
940 | |||
941 | $sql = 'SELECT etm.id, event_type_name, activated, language_id, message, subject, dokeos_folder |
||
942 | FROM '.Database::get_main_table(TABLE_EVENT_EMAIL_TEMPLATE).' etm |
||
943 | INNER JOIN '.Database::get_main_table(TABLE_MAIN_LANGUAGE).' l |
||
944 | ON etm.language_id = l.id'; |
||
945 | |||
946 | $events_types = Database::store_result(Database::query($sql), 'ASSOC'); |
||
947 | |||
948 | $to_return = []; |
||
949 | foreach ($events_types as $et) { |
||
950 | $et['nameLangVar'] = $event_config[$et["event_type_name"]]["name_lang_var"]; |
||
951 | $et['descLangVar'] = $event_config[$et["event_type_name"]]["desc_lang_var"]; |
||
952 | $to_return[] = $et; |
||
953 | } |
||
954 | |||
955 | return $to_return; |
||
956 | } |
||
957 | |||
958 | /** |
||
959 | * Get the users related to one event. |
||
960 | * |
||
961 | * @param string $event_name |
||
962 | * |
||
963 | * @return string |
||
964 | */ |
||
965 | public static function get_event_users($event_name) |
||
966 | { |
||
967 | $event_name = Database::escape_string($event_name); |
||
968 | $sql = 'SELECT user.user_id, user.firstname, user.lastname |
||
969 | FROM '.Database::get_main_table(TABLE_MAIN_USER).' user |
||
970 | JOIN '.Database::get_main_table(TABLE_EVENT_TYPE_REL_USER).' relUser |
||
971 | ON relUser.user_id = user.user_id |
||
972 | WHERE user.status <> '.ANONYMOUS.' AND relUser.event_type_name = "'.$event_name.'"'; |
||
973 | $user_list = Database::store_result(Database::query($sql), 'ASSOC'); |
||
974 | |||
975 | return json_encode($user_list); |
||
976 | } |
||
977 | |||
978 | /** |
||
979 | * @param int $user_id |
||
980 | * @param string $event_type |
||
981 | * |
||
982 | * @return array|bool |
||
983 | */ |
||
984 | public static function get_events_by_user_and_type($user_id, $event_type) |
||
985 | { |
||
986 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT); |
||
987 | $user_id = (int) $user_id; |
||
988 | $event_type = Database::escape_string($event_type); |
||
989 | |||
990 | $sql = "SELECT * FROM $table |
||
991 | WHERE default_value_type = 'user_id' AND |
||
992 | default_value = $user_id AND |
||
993 | default_event_type = '$event_type' |
||
994 | ORDER BY default_date "; |
||
995 | $result = Database::query($sql); |
||
996 | if ($result) { |
||
997 | return Database::store_result($result, 'ASSOC'); |
||
998 | } |
||
999 | |||
1000 | return false; |
||
1001 | } |
||
1002 | |||
1003 | /** |
||
1004 | * Save the new message for one event and for one language. |
||
1005 | * |
||
1006 | * @param string $event_name |
||
1007 | * @param array $users |
||
1008 | * @param string $message |
||
1009 | * @param string $subject |
||
1010 | * @param string $event_message_language |
||
1011 | * @param int $activated |
||
1012 | */ |
||
1013 | public static function save_event_type_message( |
||
1014 | $event_name, |
||
1015 | $users, |
||
1016 | $message, |
||
1017 | $subject, |
||
1018 | $event_message_language, |
||
1019 | $activated |
||
1020 | ) { |
||
1021 | $event_name = Database::escape_string($event_name); |
||
1022 | $activated = (int) $activated; |
||
1023 | $event_message_language = Database::escape_string($event_message_language); |
||
1024 | |||
1025 | // Deletes then re-adds the users linked to the event |
||
1026 | $sql = 'DELETE FROM '.Database::get_main_table(TABLE_EVENT_TYPE_REL_USER).' |
||
1027 | WHERE event_type_name = "'.$event_name.'" '; |
||
1028 | Database::query($sql); |
||
1029 | |||
1030 | $eventTable = Database::get_main_table(TABLE_EVENT_TYPE_REL_USER); |
||
1031 | |||
1032 | foreach ($users as $user) { |
||
1033 | $user = (int) $user; |
||
1034 | $sql = "INSERT INTO $eventTable (user_id,event_type_name) |
||
1035 | VALUES($user,'$event_name')"; |
||
1036 | Database::query($sql); |
||
1037 | } |
||
1038 | $language_id = api_get_language_id($event_message_language); |
||
1039 | // check if this template in this language already exists or not |
||
1040 | $eventMailTable = Database::get_main_table(TABLE_EVENT_EMAIL_TEMPLATE); |
||
1041 | $sql = "SELECT COUNT(id) as total |
||
1042 | FROM $eventMailTable |
||
1043 | WHERE event_type_name = '$event_name' AND language_id = $language_id"; |
||
1044 | |||
1045 | $sql = Database::store_result(Database::query($sql), 'ASSOC'); |
||
1046 | |||
1047 | $languageTable = Database::get_main_table(TABLE_MAIN_LANGUAGE); |
||
1048 | $message = Database::escape_string($message); |
||
1049 | $subject = Database::escape_string($subject); |
||
1050 | // if already exists, we update |
||
1051 | if ($sql[0]["total"] > 0) { |
||
1052 | $sql = "UPDATE $eventMailTable |
||
1053 | SET message = '$message', |
||
1054 | subject = '$subject', |
||
1055 | activated = $activated |
||
1056 | WHERE event_type_name = '$event_name' AND language_id = ( |
||
1057 | SELECT id FROM $languageTable |
||
1058 | WHERE dokeos_folder = '$event_message_language' |
||
1059 | )"; |
||
1060 | Database::query($sql); |
||
1061 | } else { // else we create a new record |
||
1062 | // gets the language_-_id |
||
1063 | $lang_id = "(SELECT id FROM $languageTable |
||
1064 | WHERE dokeos_folder = '$event_message_language')"; |
||
1065 | $lang_id = Database::store_result(Database::query($lang_id), 'ASSOC'); |
||
1066 | $lang_id = $lang_id[0]['id']; |
||
1067 | |||
1068 | if (!empty($lang_id[0]["id"])) { |
||
1069 | $sql = "INSERT INTO $eventMailTable (event_type_name, language_id, message, subject, activated) |
||
1070 | VALUES ('$event_name', $lang_id, '$message', '$subject', $activated)"; |
||
1071 | Database::query($sql); |
||
1072 | } |
||
1073 | } |
||
1074 | |||
1075 | // set activated at every save |
||
1076 | $sql = "UPDATE $eventMailTable |
||
1077 | SET activated = $activated |
||
1078 | WHERE event_type_name = '$event_name'"; |
||
1079 | Database::query($sql); |
||
1080 | } |
||
1081 | |||
1082 | /** |
||
1083 | * Gets the last attempt of an exercise based in the exe_id. |
||
1084 | * |
||
1085 | * @param int $exeId |
||
1086 | * |
||
1087 | * @return mixed |
||
1088 | */ |
||
1089 | public static function getLastAttemptDateOfExercise($exeId) |
||
1090 | { |
||
1091 | $exeId = (int) $exeId; |
||
1092 | $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1093 | $sql = "SELECT max(tms) as last_attempt_date |
||
1094 | FROM $track_attempts |
||
1095 | WHERE exe_id = $exeId"; |
||
1096 | $rs_last_attempt = Database::query($sql); |
||
1097 | $row_last_attempt = Database::fetch_array($rs_last_attempt); |
||
1098 | $date = $row_last_attempt['last_attempt_date']; //Get the date of last attempt |
||
1099 | |||
1100 | return $date; |
||
1101 | } |
||
1102 | |||
1103 | /** |
||
1104 | * Gets the last attempt of an exercise based in the exe_id. |
||
1105 | * |
||
1106 | * @param int $exeId |
||
1107 | * |
||
1108 | * @return mixed |
||
1109 | */ |
||
1110 | public static function getLatestQuestionIdFromAttempt($exeId) |
||
1111 | { |
||
1112 | $exeId = (int) $exeId; |
||
1113 | $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1114 | $sql = "SELECT question_id FROM $track_attempts |
||
1115 | WHERE exe_id = $exeId |
||
1116 | ORDER BY tms DESC |
||
1117 | LIMIT 1"; |
||
1118 | $result = Database::query($sql); |
||
1119 | if (Database::num_rows($result)) { |
||
1120 | $row = Database::fetch_array($result); |
||
1121 | |||
1122 | return $row['question_id']; |
||
1123 | } |
||
1124 | |||
1125 | return false; |
||
1126 | } |
||
1127 | |||
1128 | /** |
||
1129 | * Gets how many attempts exists by user, exercise, learning path. |
||
1130 | * |
||
1131 | * @param int user id |
||
1132 | * @param int exercise id |
||
1133 | * @param int lp id |
||
1134 | * @param int lp item id |
||
1135 | * @param int lp item view id |
||
1136 | * |
||
1137 | * @return int |
||
1138 | */ |
||
1139 | public static function get_attempt_count( |
||
1140 | $user_id, |
||
1141 | $exerciseId, |
||
1142 | $lp_id, |
||
1143 | $lp_item_id, |
||
1144 | $lp_item_view_id |
||
1145 | ) { |
||
1146 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1147 | $user_id = (int) $user_id; |
||
1148 | $exerciseId = (int) $exerciseId; |
||
1149 | $lp_id = (int) $lp_id; |
||
1150 | $lp_item_id = (int) $lp_item_id; |
||
1151 | $lp_item_view_id = (int) $lp_item_view_id; |
||
1152 | $courseId = api_get_course_int_id(); |
||
1153 | $sessionId = api_get_session_id(); |
||
1154 | |||
1155 | $sql = "SELECT count(*) as count |
||
1156 | FROM $table |
||
1157 | WHERE |
||
1158 | exe_exo_id = $exerciseId AND |
||
1159 | exe_user_id = $user_id AND |
||
1160 | status != 'incomplete' AND |
||
1161 | orig_lp_id = $lp_id AND |
||
1162 | orig_lp_item_id = $lp_item_id AND |
||
1163 | orig_lp_item_view_id = $lp_item_view_id AND |
||
1164 | c_id = $courseId AND |
||
1165 | session_id = $sessionId"; |
||
1166 | |||
1167 | $result = Database::query($sql); |
||
1168 | if (Database::num_rows($result) > 0) { |
||
1169 | $attempt = Database::fetch_array($result, 'ASSOC'); |
||
1170 | |||
1171 | return (int) $attempt['count']; |
||
1172 | } |
||
1173 | |||
1174 | return 0; |
||
1175 | } |
||
1176 | |||
1177 | public static function getAttemptPosition( |
||
1178 | $exeId, |
||
1179 | $user_id, |
||
1180 | $exerciseId, |
||
1181 | $lp_id, |
||
1182 | $lp_item_id, |
||
1183 | $lp_item_view_id |
||
1184 | ) { |
||
1185 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1186 | $user_id = (int) $user_id; |
||
1187 | $exerciseId = (int) $exerciseId; |
||
1188 | $lp_id = (int) $lp_id; |
||
1189 | $lp_item_id = (int) $lp_item_id; |
||
1190 | $lp_item_view_id = (int) $lp_item_view_id; |
||
1191 | $courseId = api_get_course_int_id(); |
||
1192 | $sessionId = api_get_session_id(); |
||
1193 | |||
1194 | $sql = "SELECT exe_id |
||
1195 | FROM $table |
||
1196 | WHERE |
||
1197 | exe_exo_id = $exerciseId AND |
||
1198 | exe_user_id = $user_id AND |
||
1199 | status = '' AND |
||
1200 | orig_lp_id = $lp_id AND |
||
1201 | orig_lp_item_id = $lp_item_id AND |
||
1202 | orig_lp_item_view_id = $lp_item_view_id AND |
||
1203 | c_id = $courseId AND |
||
1204 | session_id = $sessionId |
||
1205 | ORDER by exe_id |
||
1206 | "; |
||
1207 | |||
1208 | $result = Database::query($sql); |
||
1209 | if (Database::num_rows($result) > 0) { |
||
1210 | $position = 1; |
||
1211 | while ($row = Database::fetch_array($result, 'ASSOC')) { |
||
1212 | if ($row['exe_id'] === $exeId) { |
||
1213 | break; |
||
1214 | } |
||
1215 | $position++; |
||
1216 | } |
||
1217 | |||
1218 | return $position; |
||
1219 | } |
||
1220 | |||
1221 | return 0; |
||
1222 | } |
||
1223 | |||
1224 | /** |
||
1225 | * @param $user_id |
||
1226 | * @param $exerciseId |
||
1227 | * @param $lp_id |
||
1228 | * @param $lp_item_id |
||
1229 | * |
||
1230 | * @return int |
||
1231 | */ |
||
1232 | public static function get_attempt_count_not_finished( |
||
1233 | $user_id, |
||
1234 | $exerciseId, |
||
1235 | $lp_id, |
||
1236 | $lp_item_id |
||
1237 | ) { |
||
1238 | $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1239 | $user_id = (int) $user_id; |
||
1240 | $exerciseId = (int) $exerciseId; |
||
1241 | $lp_id = (int) $lp_id; |
||
1242 | $lp_item_id = (int) $lp_item_id; |
||
1243 | //$lp_item_view_id = (int) $lp_item_view_id; |
||
1244 | $courseId = api_get_course_int_id(); |
||
1245 | $sessionId = api_get_session_id(); |
||
1246 | |||
1247 | $sql = "SELECT count(*) as count |
||
1248 | FROM $stat_table |
||
1249 | WHERE |
||
1250 | exe_exo_id = $exerciseId AND |
||
1251 | exe_user_id = $user_id AND |
||
1252 | status != 'incomplete' AND |
||
1253 | orig_lp_id = $lp_id AND |
||
1254 | orig_lp_item_id = $lp_item_id AND |
||
1255 | c_id = $courseId AND |
||
1256 | session_id = $sessionId"; |
||
1257 | |||
1258 | $query = Database::query($sql); |
||
1259 | if (Database::num_rows($query) > 0) { |
||
1260 | $attempt = Database::fetch_array($query, 'ASSOC'); |
||
1261 | |||
1262 | return (int) $attempt['count']; |
||
1263 | } |
||
1264 | |||
1265 | return 0; |
||
1266 | } |
||
1267 | |||
1268 | /** |
||
1269 | * @param int $user_id |
||
1270 | * @param int $lp_id |
||
1271 | * @param array $course |
||
1272 | * @param int $session_id |
||
1273 | * @param bool $disconnectExerciseResultsFromLp (Replace orig_lp_* variables to null) |
||
1274 | * |
||
1275 | * @return bool |
||
1276 | */ |
||
1277 | public static function delete_student_lp_events( |
||
1278 | $user_id, |
||
1279 | $lp_id, |
||
1280 | $course, |
||
1281 | $session_id, |
||
1282 | $disconnectExerciseResultsFromLp = false |
||
1283 | ) { |
||
1284 | $lp_view_table = Database::get_course_table(TABLE_LP_VIEW); |
||
1285 | $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW); |
||
1286 | $lpInteraction = Database::get_course_table(TABLE_LP_IV_INTERACTION); |
||
1287 | $lpObjective = Database::get_course_table(TABLE_LP_IV_OBJECTIVE); |
||
1288 | |||
1289 | if (empty($course) || empty($user_id)) { |
||
1290 | return false; |
||
1291 | } |
||
1292 | |||
1293 | $course_id = $course['real_id']; |
||
1294 | $user_id = (int) $user_id; |
||
1295 | $lp_id = (int) $lp_id; |
||
1296 | $session_id = (int) $session_id; |
||
1297 | |||
1298 | if (empty($course_id)) { |
||
1299 | $course_id = api_get_course_int_id(); |
||
1300 | } |
||
1301 | |||
1302 | $track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1303 | $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1304 | $recording_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
||
1305 | |||
1306 | // Make sure we have the exact lp_view_id |
||
1307 | $sql = "SELECT id FROM $lp_view_table |
||
1308 | WHERE |
||
1309 | c_id = $course_id AND |
||
1310 | user_id = $user_id AND |
||
1311 | lp_id = $lp_id AND |
||
1312 | session_id = $session_id"; |
||
1313 | $result = Database::query($sql); |
||
1314 | |||
1315 | if (Database::num_rows($result)) { |
||
1316 | $view = Database::fetch_array($result, 'ASSOC'); |
||
1317 | $lp_view_id = $view['id']; |
||
1318 | |||
1319 | $sql = "DELETE FROM $lp_item_view_table |
||
1320 | WHERE c_id = $course_id AND lp_view_id = $lp_view_id"; |
||
1321 | Database::query($sql); |
||
1322 | |||
1323 | $sql = "DELETE FROM $lpInteraction |
||
1324 | WHERE c_id = $course_id AND lp_iv_id = $lp_view_id"; |
||
1325 | Database::query($sql); |
||
1326 | |||
1327 | $sql = "DELETE FROM $lpObjective |
||
1328 | WHERE c_id = $course_id AND lp_iv_id = $lp_view_id"; |
||
1329 | Database::query($sql); |
||
1330 | } |
||
1331 | |||
1332 | if (api_get_configuration_value('lp_minimum_time')) { |
||
1333 | $sql = "DELETE FROM track_e_access_complete |
||
1334 | WHERE |
||
1335 | tool = 'learnpath' AND |
||
1336 | c_id = $course_id AND |
||
1337 | tool_id = $lp_id AND |
||
1338 | user_id = $user_id AND |
||
1339 | session_id = $session_id |
||
1340 | "; |
||
1341 | Database::query($sql); |
||
1342 | } |
||
1343 | |||
1344 | $sql = "SELECT exe_id FROM $track_e_exercises |
||
1345 | WHERE |
||
1346 | exe_user_id = $user_id AND |
||
1347 | session_id = $session_id AND |
||
1348 | c_id = $course_id AND |
||
1349 | orig_lp_id = $lp_id"; |
||
1350 | $result = Database::query($sql); |
||
1351 | $exeList = []; |
||
1352 | while ($row = Database::fetch_array($result, 'ASSOC')) { |
||
1353 | $exeList[] = $row['exe_id']; |
||
1354 | } |
||
1355 | |||
1356 | if (!empty($exeList) && count($exeList) > 0) { |
||
1357 | $exeListString = implode(',', $exeList); |
||
1358 | if ($disconnectExerciseResultsFromLp) { |
||
1359 | $sql = "UPDATE $track_e_exercises |
||
1360 | SET orig_lp_id = null, |
||
1361 | orig_lp_item_id = null, |
||
1362 | orig_lp_item_view_id = null |
||
1363 | WHERE exe_id IN ($exeListString)"; |
||
1364 | Database::query($sql); |
||
1365 | } else { |
||
1366 | $sql = "DELETE FROM $track_e_exercises |
||
1367 | WHERE exe_id IN ($exeListString)"; |
||
1368 | Database::query($sql); |
||
1369 | |||
1370 | $sql = "DELETE FROM $track_attempts |
||
1371 | WHERE exe_id IN ($exeListString)"; |
||
1372 | Database::query($sql); |
||
1373 | |||
1374 | $sql = "DELETE FROM $recording_table |
||
1375 | WHERE exe_id IN ($exeListString)"; |
||
1376 | Database::query($sql); |
||
1377 | } |
||
1378 | } |
||
1379 | |||
1380 | $sql = "DELETE FROM $lp_view_table |
||
1381 | WHERE |
||
1382 | c_id = $course_id AND |
||
1383 | user_id = $user_id AND |
||
1384 | lp_id= $lp_id AND |
||
1385 | session_id = $session_id |
||
1386 | "; |
||
1387 | Database::query($sql); |
||
1388 | |||
1389 | self::addEvent( |
||
1390 | LOG_LP_ATTEMPT_DELETE, |
||
1391 | LOG_LP_ID, |
||
1392 | $lp_id, |
||
1393 | null, |
||
1394 | null, |
||
1395 | $course_id, |
||
1396 | $session_id |
||
1397 | ); |
||
1398 | |||
1399 | return true; |
||
1400 | } |
||
1401 | |||
1402 | /** |
||
1403 | * Delete all exercise attempts (included in LP or not). |
||
1404 | * |
||
1405 | * @param int user id |
||
1406 | * @param int exercise id |
||
1407 | * @param int $course_id |
||
1408 | * @param int session id |
||
1409 | */ |
||
1410 | public static function delete_all_incomplete_attempts( |
||
1411 | $user_id, |
||
1412 | $exercise_id, |
||
1413 | $course_id, |
||
1414 | $session_id = 0 |
||
1415 | ) { |
||
1416 | $user_id = (int) $user_id; |
||
1417 | $exercise_id = (int) $exercise_id; |
||
1418 | $course_id = (int) $course_id; |
||
1419 | $session_id = (int) $session_id; |
||
1420 | |||
1421 | if (!empty($user_id) && !empty($exercise_id) && !empty($course_id)) { |
||
1422 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1423 | $sql = "DELETE FROM $table |
||
1424 | WHERE |
||
1425 | exe_user_id = $user_id AND |
||
1426 | exe_exo_id = $exercise_id AND |
||
1427 | c_id = $course_id AND |
||
1428 | session_id = $session_id AND |
||
1429 | status = 'incomplete' "; |
||
1430 | Database::query($sql); |
||
1431 | self::addEvent( |
||
1432 | LOG_EXERCISE_RESULT_DELETE_INCOMPLETE, |
||
1433 | LOG_EXERCISE_AND_USER_ID, |
||
1434 | $exercise_id.'-'.$user_id, |
||
1435 | null, |
||
1436 | null, |
||
1437 | $course_id, |
||
1438 | $session_id |
||
1439 | ); |
||
1440 | } |
||
1441 | } |
||
1442 | |||
1443 | /** |
||
1444 | * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session. |
||
1445 | * |
||
1446 | * @param int $exercise_id |
||
1447 | * @param int $courseId |
||
1448 | * @param int $session_id |
||
1449 | * |
||
1450 | * @return array with the results |
||
1451 | */ |
||
1452 | public static function get_all_exercise_results( |
||
1453 | $exercise_id, |
||
1454 | $courseId, |
||
1455 | $session_id = 0, |
||
1456 | $load_question_list = true, |
||
1457 | $user_id = null, |
||
1458 | $groupId = 0, |
||
1459 | $skipLpResults = true |
||
1460 | ) { |
||
1461 | $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1462 | $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1463 | $courseId = (int) $courseId; |
||
1464 | $exercise_id = (int) $exercise_id; |
||
1465 | $session_id = (int) $session_id; |
||
1466 | $user_id = (int) $user_id; |
||
1467 | $groupId = (int) $groupId; |
||
1468 | |||
1469 | $user_condition = null; |
||
1470 | if (!empty($user_id)) { |
||
1471 | $user_condition = "AND exe_user_id = $user_id "; |
||
1472 | } |
||
1473 | |||
1474 | $courseInfo = api_get_course_info_by_id($courseId); |
||
1475 | if (empty($courseInfo)) { |
||
1476 | return []; |
||
1477 | } |
||
1478 | |||
1479 | $groupCondition = ''; |
||
1480 | if (!empty($groupId)) { |
||
1481 | $users = GroupManager::get_users($groupId, null, null, null, false, $courseId); |
||
1482 | // Check users added. |
||
1483 | if (!empty($users)) { |
||
1484 | $usersToString = implode("', '", $users); |
||
1485 | $groupCondition = " AND exe_user_id IN ('$usersToString') "; |
||
1486 | } else { |
||
1487 | // No users found in the group, then return an empty array. |
||
1488 | return []; |
||
1489 | } |
||
1490 | } |
||
1491 | |||
1492 | $skipLpQuery = ""; |
||
1493 | if ($skipLpResults) { |
||
1494 | $skipLpQuery = " AND orig_lp_id = 0 AND orig_lp_item_id = 0 "; |
||
1495 | } |
||
1496 | |||
1497 | $sql = "SELECT * FROM $TABLETRACK_EXERCICES |
||
1498 | WHERE |
||
1499 | status = '' AND |
||
1500 | c_id = $courseId AND |
||
1501 | exe_exo_id = $exercise_id AND |
||
1502 | session_id = $session_id |
||
1503 | $skipLpQuery |
||
1504 | $user_condition |
||
1505 | $groupCondition |
||
1506 | ORDER BY exe_id"; |
||
1507 | $res = Database::query($sql); |
||
1508 | $list = []; |
||
1509 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1510 | $list[$row['exe_id']] = $row; |
||
1511 | if ($load_question_list) { |
||
1512 | $sql = "SELECT * FROM $TBL_TRACK_ATTEMPT |
||
1513 | WHERE exe_id = {$row['exe_id']}"; |
||
1514 | $res_question = Database::query($sql); |
||
1515 | while ($row_q = Database::fetch_array($res_question, 'ASSOC')) { |
||
1516 | $list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q; |
||
1517 | } |
||
1518 | } |
||
1519 | } |
||
1520 | |||
1521 | return $list; |
||
1522 | } |
||
1523 | |||
1524 | /** |
||
1525 | * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session. |
||
1526 | * |
||
1527 | * @param int $courseId |
||
1528 | * @param int $session_id |
||
1529 | * @param bool $get_count |
||
1530 | * |
||
1531 | * @return array with the results |
||
1532 | */ |
||
1533 | public static function get_all_exercise_results_by_course( |
||
1534 | $courseId, |
||
1535 | $session_id = 0, |
||
1536 | $get_count = true |
||
1537 | ) { |
||
1538 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1539 | $courseId = (int) $courseId; |
||
1540 | $session_id = (int) $session_id; |
||
1541 | |||
1542 | $select = '*'; |
||
1543 | if ($get_count) { |
||
1544 | $select = 'count(*) as count'; |
||
1545 | } |
||
1546 | $sql = "SELECT $select FROM $table_track_exercises |
||
1547 | WHERE status = '' AND |
||
1548 | c_id = $courseId AND |
||
1549 | session_id = $session_id AND |
||
1550 | orig_lp_id = 0 AND |
||
1551 | orig_lp_item_id = 0 |
||
1552 | ORDER BY exe_id"; |
||
1553 | $res = Database::query($sql); |
||
1554 | if ($get_count) { |
||
1555 | $row = Database::fetch_array($res, 'ASSOC'); |
||
1556 | |||
1557 | return $row['count']; |
||
1558 | } else { |
||
1559 | $list = []; |
||
1560 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1561 | $list[$row['exe_id']] = $row; |
||
1562 | } |
||
1563 | |||
1564 | return $list; |
||
1565 | } |
||
1566 | } |
||
1567 | |||
1568 | /** |
||
1569 | * Gets all exercise results (NO Exercises in LPs) from a given exercise id, course, session. |
||
1570 | * |
||
1571 | * @param int $user_id |
||
1572 | * @param int $courseId |
||
1573 | * @param int $session_id |
||
1574 | * |
||
1575 | * @return array with the results |
||
1576 | */ |
||
1577 | public static function get_all_exercise_results_by_user( |
||
1578 | $user_id, |
||
1579 | $courseId, |
||
1580 | $session_id = 0 |
||
1581 | ) { |
||
1582 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1583 | $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1584 | $courseId = (int) $courseId; |
||
1585 | $session_id = (int) $session_id; |
||
1586 | $user_id = (int) $user_id; |
||
1587 | |||
1588 | $sql = "SELECT * FROM $table_track_exercises |
||
1589 | WHERE |
||
1590 | status = '' AND |
||
1591 | exe_user_id = $user_id AND |
||
1592 | c_id = $courseId AND |
||
1593 | session_id = $session_id AND |
||
1594 | orig_lp_id = 0 AND |
||
1595 | orig_lp_item_id = 0 |
||
1596 | ORDER by exe_id"; |
||
1597 | |||
1598 | $res = Database::query($sql); |
||
1599 | $list = []; |
||
1600 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1601 | $list[$row['exe_id']] = $row; |
||
1602 | $sql = "SELECT * FROM $table_track_attempt |
||
1603 | WHERE exe_id = {$row['exe_id']}"; |
||
1604 | $res_question = Database::query($sql); |
||
1605 | while ($row_q = Database::fetch_array($res_question, 'ASSOC')) { |
||
1606 | $list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q; |
||
1607 | } |
||
1608 | } |
||
1609 | |||
1610 | return $list; |
||
1611 | } |
||
1612 | |||
1613 | /** |
||
1614 | * Gets exercise results (NO Exercises in LPs) from a given exercise id, course, session. |
||
1615 | * |
||
1616 | * @param int $exe_id attempt id |
||
1617 | * @param string $status |
||
1618 | * |
||
1619 | * @return array with the results |
||
1620 | */ |
||
1621 | public static function get_exercise_results_by_attempt($exe_id, $status = null) |
||
1622 | { |
||
1623 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1624 | $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1625 | $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
||
1626 | $exe_id = (int) $exe_id; |
||
1627 | |||
1628 | $status = Database::escape_string($status); |
||
1629 | |||
1630 | $sql = "SELECT * FROM $table_track_exercises |
||
1631 | WHERE status = '$status' AND exe_id = $exe_id"; |
||
1632 | |||
1633 | $res = Database::query($sql); |
||
1634 | $list = []; |
||
1635 | if (Database::num_rows($res)) { |
||
1636 | $row = Database::fetch_array($res, 'ASSOC'); |
||
1637 | |||
1638 | //Checking if this attempt was revised by a teacher |
||
1639 | $sql_revised = "SELECT exe_id FROM $table_track_attempt_recording |
||
1640 | WHERE author != '' AND exe_id = $exe_id |
||
1641 | LIMIT 1"; |
||
1642 | $res_revised = Database::query($sql_revised); |
||
1643 | $row['attempt_revised'] = 0; |
||
1644 | if (Database::num_rows($res_revised) > 0) { |
||
1645 | $row['attempt_revised'] = 1; |
||
1646 | } |
||
1647 | $list[$exe_id] = $row; |
||
1648 | $sql = "SELECT * FROM $table_track_attempt |
||
1649 | WHERE exe_id = $exe_id |
||
1650 | ORDER BY tms ASC"; |
||
1651 | $res_question = Database::query($sql); |
||
1652 | while ($row_q = Database::fetch_array($res_question, 'ASSOC')) { |
||
1653 | $list[$exe_id]['question_list'][$row_q['question_id']] = $row_q; |
||
1654 | } |
||
1655 | } |
||
1656 | |||
1657 | return $list; |
||
1658 | } |
||
1659 | |||
1660 | /** |
||
1661 | * Gets exercise results (NO Exercises in LPs) from a given user, exercise id, course, session, lp_id, lp_item_id. |
||
1662 | * |
||
1663 | * @param int user id |
||
1664 | * @param int exercise id |
||
1665 | * @param int course id |
||
1666 | * @param int session id |
||
1667 | * @param int lp id |
||
1668 | * @param int lp item id |
||
1669 | * @param string order asc or desc |
||
1670 | * |
||
1671 | * @return array with the results |
||
1672 | */ |
||
1673 | public static function getExerciseResultsByUser( |
||
1674 | $user_id, |
||
1675 | $exercise_id, |
||
1676 | $courseId, |
||
1677 | $session_id = 0, |
||
1678 | $lp_id = 0, |
||
1679 | $lp_item_id = 0, |
||
1680 | $order = null |
||
1681 | ) { |
||
1682 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1683 | $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1684 | $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
||
1685 | $courseId = (int) $courseId; |
||
1686 | $exercise_id = (int) $exercise_id; |
||
1687 | $session_id = (int) $session_id; |
||
1688 | $user_id = (int) $user_id; |
||
1689 | $lp_id = (int) $lp_id; |
||
1690 | $lp_item_id = (int) $lp_item_id; |
||
1691 | |||
1692 | if (!in_array(strtolower($order), ['asc', 'desc'])) { |
||
1693 | $order = 'asc'; |
||
1694 | } |
||
1695 | |||
1696 | $sql = "SELECT * FROM $table_track_exercises |
||
1697 | WHERE |
||
1698 | status = '' AND |
||
1699 | exe_user_id = $user_id AND |
||
1700 | c_id = $courseId AND |
||
1701 | exe_exo_id = $exercise_id AND |
||
1702 | session_id = $session_id AND |
||
1703 | orig_lp_id = $lp_id AND |
||
1704 | orig_lp_item_id = $lp_item_id |
||
1705 | ORDER by exe_id $order "; |
||
1706 | |||
1707 | $res = Database::query($sql); |
||
1708 | $list = []; |
||
1709 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1710 | // Checking if this attempt was revised by a teacher |
||
1711 | $exeId = $row['exe_id']; |
||
1712 | $sql = "SELECT exe_id FROM $table_track_attempt_recording |
||
1713 | WHERE author != '' AND exe_id = $exeId |
||
1714 | LIMIT 1"; |
||
1715 | $res_revised = Database::query($sql); |
||
1716 | $row['attempt_revised'] = 0; |
||
1717 | if (Database::num_rows($res_revised) > 0) { |
||
1718 | $row['attempt_revised'] = 1; |
||
1719 | } |
||
1720 | $row['total_percentage'] = 0; |
||
1721 | if (!empty($row['exe_weighting'])) { |
||
1722 | $row['total_percentage'] = ($row['exe_result'] / $row['exe_weighting']) * 100; |
||
1723 | } |
||
1724 | |||
1725 | $list[$row['exe_id']] = $row; |
||
1726 | $sql = "SELECT * FROM $table_track_attempt |
||
1727 | WHERE exe_id = $exeId"; |
||
1728 | $res_question = Database::query($sql); |
||
1729 | while ($row_q = Database::fetch_array($res_question, 'ASSOC')) { |
||
1730 | $list[$row['exe_id']]['question_list'][$row_q['question_id']][] = $row_q; |
||
1731 | } |
||
1732 | } |
||
1733 | |||
1734 | return $list; |
||
1735 | } |
||
1736 | |||
1737 | /** |
||
1738 | * Count exercise attempts (NO Exercises in LPs ) from a given exercise id, course, session. |
||
1739 | * |
||
1740 | * @param int $user_id |
||
1741 | * @param int $exercise_id |
||
1742 | * @param int $courseId |
||
1743 | * @param int $session_id |
||
1744 | * |
||
1745 | * @return array with the results |
||
1746 | */ |
||
1747 | public static function count_exercise_attempts_by_user( |
||
1748 | $user_id, |
||
1749 | $exercise_id, |
||
1750 | $courseId, |
||
1751 | $session_id = 0, |
||
1752 | $skipLpResults = true |
||
1753 | ) { |
||
1754 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1755 | $courseId = (int) $courseId; |
||
1756 | $exercise_id = (int) $exercise_id; |
||
1757 | $session_id = (int) $session_id; |
||
1758 | $user_id = (int) $user_id; |
||
1759 | |||
1760 | $skipLpQuery = ""; |
||
1761 | if ($skipLpResults) { |
||
1762 | $skipLpQuery = " AND orig_lp_id = 0 AND orig_lp_item_id = 0 "; |
||
1763 | } |
||
1764 | |||
1765 | $sql = "SELECT count(*) as count |
||
1766 | FROM $table |
||
1767 | WHERE status = '' AND |
||
1768 | exe_user_id = $user_id AND |
||
1769 | c_id = $courseId AND |
||
1770 | exe_exo_id = $exercise_id AND |
||
1771 | session_id = $session_id |
||
1772 | $skipLpQuery |
||
1773 | ORDER BY exe_id"; |
||
1774 | $res = Database::query($sql); |
||
1775 | $result = 0; |
||
1776 | if (Database::num_rows($res) > 0) { |
||
1777 | $row = Database::fetch_array($res, 'ASSOC'); |
||
1778 | $result = $row['count']; |
||
1779 | } |
||
1780 | |||
1781 | return $result; |
||
1782 | } |
||
1783 | |||
1784 | /** |
||
1785 | * Gets all exercise BEST results attempts (NO Exercises in LPs) |
||
1786 | * from a given exercise id, course, session per user. |
||
1787 | * |
||
1788 | * @param int $exercise_id |
||
1789 | * @param int $courseId |
||
1790 | * @param int $session_id |
||
1791 | * @param int $userId |
||
1792 | * |
||
1793 | * @return array with the results |
||
1794 | * |
||
1795 | * @todo rename this function |
||
1796 | */ |
||
1797 | public static function get_best_exercise_results_by_user( |
||
1798 | $exercise_id, |
||
1799 | $courseId, |
||
1800 | $session_id = 0, |
||
1801 | $userId = 0, |
||
1802 | $skipLpResults = true |
||
1803 | ) { |
||
1804 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1805 | $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1806 | $courseId = (int) $courseId; |
||
1807 | $exercise_id = (int) $exercise_id; |
||
1808 | $session_id = (int) $session_id; |
||
1809 | |||
1810 | $skipLpQuery = ""; |
||
1811 | if ($skipLpResults) { |
||
1812 | $skipLpQuery = " AND orig_lp_id = 0 AND orig_lp_item_id = 0 "; |
||
1813 | } |
||
1814 | |||
1815 | $sql = "SELECT * FROM $table_track_exercises |
||
1816 | WHERE |
||
1817 | status = '' AND |
||
1818 | c_id = $courseId AND |
||
1819 | exe_exo_id = $exercise_id AND |
||
1820 | session_id = $session_id |
||
1821 | $skipLpQuery"; |
||
1822 | |||
1823 | if (!empty($userId)) { |
||
1824 | $userId = (int) $userId; |
||
1825 | $sql .= " AND exe_user_id = $userId "; |
||
1826 | } |
||
1827 | $sql .= ' ORDER BY exe_id'; |
||
1828 | |||
1829 | $res = Database::query($sql); |
||
1830 | $list = []; |
||
1831 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1832 | $list[$row['exe_id']] = $row; |
||
1833 | $exeId = $row['exe_id']; |
||
1834 | $sql = "SELECT * FROM $table_track_attempt |
||
1835 | WHERE exe_id = $exeId"; |
||
1836 | $res_question = Database::query($sql); |
||
1837 | while ($row_q = Database::fetch_array($res_question, 'ASSOC')) { |
||
1838 | $list[$exeId]['question_list'][$row_q['question_id']] = $row_q; |
||
1839 | } |
||
1840 | } |
||
1841 | |||
1842 | // Getting the best results of every student |
||
1843 | $best_score_return = []; |
||
1844 | foreach ($list as $student_result) { |
||
1845 | $user_id = $student_result['exe_user_id']; |
||
1846 | $current_best_score[$user_id] = $student_result['exe_result']; |
||
1847 | if (!isset($best_score_return[$user_id]['exe_result'])) { |
||
1848 | $best_score_return[$user_id] = $student_result; |
||
1849 | } |
||
1850 | |||
1851 | if ($current_best_score[$user_id] > $best_score_return[$user_id]['exe_result']) { |
||
1852 | $best_score_return[$user_id] = $student_result; |
||
1853 | } |
||
1854 | } |
||
1855 | |||
1856 | return $best_score_return; |
||
1857 | } |
||
1858 | |||
1859 | /** |
||
1860 | * Get the last best result from all attempts in exercises per user (out of learning paths). |
||
1861 | * |
||
1862 | * @param int $user_id |
||
1863 | * @param int $exercise_id |
||
1864 | * @param int $courseId |
||
1865 | * @param int $session_id |
||
1866 | * @param bool $skipLpResults |
||
1867 | * |
||
1868 | * @return array |
||
1869 | */ |
||
1870 | public static function get_best_attempt_exercise_results_per_user( |
||
1871 | $user_id, |
||
1872 | $exercise_id, |
||
1873 | $courseId, |
||
1874 | $session_id = 0, |
||
1875 | $skipLpResults = true |
||
1876 | ) { |
||
1877 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1878 | $courseId = (int) $courseId; |
||
1879 | $exercise_id = (int) $exercise_id; |
||
1880 | $session_id = (int) $session_id; |
||
1881 | $user_id = (int) $user_id; |
||
1882 | |||
1883 | $sql = "SELECT * FROM $table |
||
1884 | WHERE |
||
1885 | status = '' AND |
||
1886 | c_id = $courseId AND |
||
1887 | exe_exo_id = $exercise_id AND |
||
1888 | session_id = $session_id AND |
||
1889 | exe_user_id = $user_id |
||
1890 | "; |
||
1891 | |||
1892 | if ($skipLpResults) { |
||
1893 | $sql .= ' AND |
||
1894 | orig_lp_id = 0 AND |
||
1895 | orig_lp_item_id = 0 '; |
||
1896 | } |
||
1897 | |||
1898 | $sql .= ' ORDER BY exe_id '; |
||
1899 | |||
1900 | $res = Database::query($sql); |
||
1901 | $list = []; |
||
1902 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1903 | $list[$row['exe_id']] = $row; |
||
1904 | } |
||
1905 | // Getting the best results of every student. |
||
1906 | $best_score_return = []; |
||
1907 | $best_score_return['exe_result'] = 0; |
||
1908 | |||
1909 | foreach ($list as $result) { |
||
1910 | $current_best_score = $result; |
||
1911 | if ($current_best_score['exe_result'] > $best_score_return['exe_result']) { |
||
1912 | $best_score_return = $result; |
||
1913 | } |
||
1914 | } |
||
1915 | if (!isset($best_score_return['exe_weighting'])) { |
||
1916 | $best_score_return = []; |
||
1917 | } |
||
1918 | |||
1919 | return $best_score_return; |
||
1920 | } |
||
1921 | |||
1922 | /** |
||
1923 | * @param int $exercise_id |
||
1924 | * @param int $courseId |
||
1925 | * @param int $session_id |
||
1926 | * |
||
1927 | * @return mixed |
||
1928 | */ |
||
1929 | public static function count_exercise_result_not_validated( |
||
1930 | $exercise_id, |
||
1931 | $courseId, |
||
1932 | $session_id = 0 |
||
1933 | ) { |
||
1934 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1935 | $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING); |
||
1936 | $courseId = (int) $courseId; |
||
1937 | $session_id = (int) $session_id; |
||
1938 | $exercise_id = (int) $exercise_id; |
||
1939 | |||
1940 | $sql = "SELECT count(e.exe_id) as count |
||
1941 | FROM $table_track_exercises e |
||
1942 | LEFT JOIN $table_track_attempt a |
||
1943 | ON e.exe_id = a.exe_id |
||
1944 | WHERE |
||
1945 | exe_exo_id = $exercise_id AND |
||
1946 | c_id = $courseId AND |
||
1947 | e.session_id = $session_id AND |
||
1948 | orig_lp_id = 0 AND |
||
1949 | marks IS NULL AND |
||
1950 | status = '' AND |
||
1951 | orig_lp_item_id = 0 |
||
1952 | ORDER BY e.exe_id"; |
||
1953 | $res = Database::query($sql); |
||
1954 | $row = Database::fetch_array($res, 'ASSOC'); |
||
1955 | |||
1956 | return $row['count']; |
||
1957 | } |
||
1958 | |||
1959 | /** |
||
1960 | * Gets all exercise events from a Learning Path within a Course nd Session. |
||
1961 | * |
||
1962 | * @param int $exercise_id |
||
1963 | * @param int $courseId |
||
1964 | * @param int $session_id |
||
1965 | * |
||
1966 | * @return array |
||
1967 | */ |
||
1968 | public static function get_all_exercise_event_from_lp( |
||
1969 | $exercise_id, |
||
1970 | $courseId, |
||
1971 | $session_id = 0 |
||
1972 | ) { |
||
1973 | $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); |
||
1974 | $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
1975 | $courseId = (int) $courseId; |
||
1976 | $exercise_id = (int) $exercise_id; |
||
1977 | $session_id = (int) $session_id; |
||
1978 | |||
1979 | $sql = "SELECT * FROM $table_track_exercises |
||
1980 | WHERE |
||
1981 | status = '' AND |
||
1982 | c_id = $courseId AND |
||
1983 | exe_exo_id = $exercise_id AND |
||
1984 | session_id = $session_id AND |
||
1985 | orig_lp_id !=0 AND |
||
1986 | orig_lp_item_id != 0"; |
||
1987 | |||
1988 | $res = Database::query($sql); |
||
1989 | $list = []; |
||
1990 | while ($row = Database::fetch_array($res, 'ASSOC')) { |
||
1991 | $exeId = $row['exe_id']; |
||
1992 | $list[$exeId] = $row; |
||
1993 | $sql = "SELECT * FROM $table_track_attempt |
||
1994 | WHERE exe_id = $exeId"; |
||
1995 | $res_question = Database::query($sql); |
||
1996 | while ($row_q = Database::fetch_array($res_question, 'ASSOC')) { |
||
1997 | $list[$exeId]['question_list'][$row_q['question_id']] = $row_q; |
||
1998 | } |
||
1999 | } |
||
2000 | |||
2001 | return $list; |
||
2002 | } |
||
2003 | |||
2004 | /** |
||
2005 | * Get a list of all the exercises in a given learning path. |
||
2006 | * |
||
2007 | * @param int $lp_id |
||
2008 | * @param int $course_id This parameter is probably deprecated as lp_id now is a global iid |
||
2009 | * |
||
2010 | * @return array |
||
2011 | */ |
||
2012 | public static function get_all_exercises_from_lp($lp_id, $course_id) |
||
2031 | } |
||
2032 | |||
2033 | /** |
||
2034 | * This function gets the comments of an exercise. |
||
2035 | * |
||
2036 | * @param int $exe_id |
||
2037 | * @param int $question_id |
||
2038 | * |
||
2039 | * @return string the comment |
||
2040 | */ |
||
2041 | public static function get_comments($exe_id, $question_id) |
||
2042 | { |
||
2043 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
2044 | $exe_id = (int) $exe_id; |
||
2045 | $question_id = (int) $question_id; |
||
2046 | $sql = "SELECT teacher_comment |
||
2047 | FROM $table |
||
2048 | WHERE |
||
2049 | exe_id = $exe_id AND |
||
2050 | question_id = $question_id |
||
2051 | ORDER by question_id"; |
||
2052 | $sqlres = Database::query($sql); |
||
2053 | $comm = strval(Database::result($sqlres, 0, 'teacher_comment')); |
||
2054 | $comm = trim($comm); |
||
2055 | |||
2056 | return $comm; |
||
2057 | } |
||
2058 | |||
2059 | /** |
||
2060 | * Get all the track_e_attempt records for a given |
||
2061 | * track_e_exercises.exe_id (pk). |
||
2062 | * |
||
2063 | * @param int $exeId The exe_id from an exercise attempt record |
||
2064 | * |
||
2065 | * @return array The complete records from track_e_attempt that match the given exe_id |
||
2066 | */ |
||
2067 | public static function getAllExerciseEventByExeId($exeId) |
||
2068 | { |
||
2069 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
2070 | $exeId = (int) $exeId; |
||
2071 | |||
2072 | $sql = "SELECT * FROM $table |
||
2073 | WHERE exe_id = $exeId |
||
2074 | ORDER BY position"; |
||
2075 | $res_question = Database::query($sql); |
||
2076 | $list = []; |
||
2077 | if (Database::num_rows($res_question)) { |
||
2078 | while ($row = Database::fetch_array($res_question, 'ASSOC')) { |
||
2079 | $list[$row['question_id']][] = $row; |
||
2080 | } |
||
2081 | } |
||
2082 | |||
2083 | return $list; |
||
2084 | } |
||
2085 | |||
2086 | public static function getQuestionAttemptByExeIdAndQuestion($exeId, $questionId) |
||
2087 | { |
||
2088 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT); |
||
2089 | $exeId = (int) $exeId; |
||
2090 | $questionId = (int) $questionId; |
||
2091 | |||
2092 | $sql = "SELECT * FROM $table |
||
2093 | WHERE |
||
2094 | exe_id = $exeId AND |
||
2095 | question_id = $questionId |
||
2096 | ORDER BY position"; |
||
2097 | $result = Database::query($sql); |
||
2098 | $attempt = []; |
||
2099 | if (Database::num_rows($result)) { |
||
2100 | $attempt = Database::fetch_array($result, 'ASSOC'); |
||
2101 | } |
||
2102 | |||
2103 | return $attempt; |
||
2104 | } |
||
2105 | |||
2106 | /** |
||
2107 | * Delete one record from the track_e_attempt table (recorded quiz answer) |
||
2108 | * and register the deletion event (LOG_QUESTION_RESULT_DELETE) in |
||
2109 | * track_e_default. |
||
2110 | * |
||
2111 | * @param int $exeId The track_e_exercises.exe_id (primary key) |
||
2112 | * @param int $user_id The user who answered (already contained in exe_id) |
||
2113 | * @param int $courseId The course in which it happened (already contained in exe_id) |
||
2114 | * @param int $session_id The session in which it happened (already contained in exe_id) |
||
2115 | * @param int $question_id The c_quiz_question.iid |
||
2116 | */ |
||
2117 | public static function delete_attempt( |
||
2149 | ); |
||
2150 | } |
||
2151 | |||
2152 | /** |
||
2153 | * Delete one record from the track_e_hotspot table based on a given |
||
2154 | * track_e_exercises.exe_id. |
||
2155 | * |
||
2156 | * @param $exeId |
||
2157 | * @param $user_id |
||
2158 | * @param int $courseId |
||
2159 | * @param $question_id |
||
2160 | * @param int $sessionId |
||
2161 | */ |
||
2162 | public static function delete_attempt_hotspot( |
||
2163 | $exeId, |
||
2164 | $user_id, |
||
2165 | $courseId, |
||
2166 | $question_id, |
||
2167 | $sessionId = null |
||
2168 | ) { |
||
2169 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT); |
||
2170 | |||
2171 | $exeId = (int) $exeId; |
||
2172 | $user_id = (int) $user_id; |
||
2173 | $courseId = (int) $courseId; |
||
2174 | $question_id = (int) $question_id; |
||
2175 | if (!isset($sessionId)) { |
||
2176 | $sessionId = api_get_session_id(); |
||
2177 | } |
||
2178 | |||
2179 | $sql = "DELETE FROM $table |
||
2180 | WHERE |
||
2181 | hotspot_exe_id = $exeId AND |
||
2182 | hotspot_user_id = $user_id AND |
||
2183 | c_id = $courseId AND |
||
2184 | hotspot_question_id = $question_id "; |
||
2185 | Database::query($sql); |
||
2186 | self::addEvent( |
||
2187 | LOG_QUESTION_RESULT_DELETE, |
||
2188 | LOG_EXERCISE_ATTEMPT_QUESTION_ID, |
||
2189 | $exeId.'-'.$question_id, |
||
2190 | null, |
||
2191 | null, |
||
2192 | $courseId, |
||
2193 | $sessionId |
||
2194 | ); |
||
2195 | } |
||
2196 | |||
2197 | /** |
||
2198 | * Registers in track_e_course_access when user logs in for the first time to a course. |
||
2199 | * |
||
2200 | * @param int $courseId ID of the course |
||
2201 | * @param int $user_id ID of the user |
||
2202 | * @param int $sessionId ID of the session (if any) |
||
2203 | * |
||
2204 | * @return bool |
||
2205 | */ |
||
2206 | public static function eventCourseLogin($courseId, $user_id, $sessionId) |
||
2207 | { |
||
2208 | if (Session::read('login_as')) { |
||
2209 | return false; |
||
2210 | } |
||
2211 | |||
2212 | $sessionId = (int) $sessionId; |
||
2213 | if (self::isSessionLogNeedToBeSave($sessionId) === false) { |
||
2214 | return false; |
||
2215 | } |
||
2216 | |||
2217 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2218 | $loginDate = $logoutDate = api_get_utc_datetime(); |
||
2219 | |||
2220 | // $counter represents the number of time this record has been refreshed |
||
2221 | $counter = 1; |
||
2222 | $courseId = (int) $courseId; |
||
2223 | $user_id = (int) $user_id; |
||
2224 | $ip = Database::escape_string(api_get_real_ip()); |
||
2225 | |||
2226 | $sql = "INSERT INTO $table(c_id, user_ip, user_id, login_course_date, logout_course_date, counter, session_id) |
||
2227 | VALUES($courseId, '$ip', $user_id, '$loginDate', '$logoutDate', $counter, $sessionId)"; |
||
2228 | $courseAccessId = Database::query($sql); |
||
2229 | |||
2230 | if ($courseAccessId) { |
||
2231 | // Course catalog stats modifications see #4191 |
||
2232 | CourseManager::update_course_ranking( |
||
2233 | null, |
||
2234 | null, |
||
2235 | null, |
||
2236 | null, |
||
2237 | true, |
||
2238 | false |
||
2239 | ); |
||
2240 | |||
2241 | return true; |
||
2242 | } |
||
2243 | } |
||
2244 | |||
2245 | /** |
||
2246 | * Updates the user - course - session every X minutes |
||
2247 | * In order to avoid. |
||
2248 | * |
||
2249 | * @param int $courseId |
||
2250 | * @param int $userId |
||
2251 | * @param int $sessionId |
||
2252 | * @param int $minutes |
||
2253 | * |
||
2254 | * @return bool |
||
2255 | */ |
||
2256 | public static function eventCourseLoginUpdate( |
||
2257 | $courseId, |
||
2258 | $userId, |
||
2259 | $sessionId, |
||
2260 | $minutes = 5 |
||
2261 | ) { |
||
2262 | if (Session::read('login_as')) { |
||
2263 | return false; |
||
2264 | } |
||
2265 | |||
2266 | if (empty($courseId) || empty($userId)) { |
||
2267 | return false; |
||
2268 | } |
||
2269 | |||
2270 | $sessionId = (int) $sessionId; |
||
2271 | |||
2272 | if (self::isSessionLogNeedToBeSave($sessionId) === false) { |
||
2273 | return false; |
||
2274 | } |
||
2275 | |||
2276 | $courseId = (int) $courseId; |
||
2277 | $userId = (int) $userId; |
||
2278 | |||
2279 | $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2280 | $sql = "SELECT course_access_id, logout_course_date |
||
2281 | FROM $table |
||
2282 | WHERE |
||
2283 | c_id = $courseId AND |
||
2284 | session_id = $sessionId AND |
||
2285 | user_id = $userId |
||
2286 | ORDER BY login_course_date DESC |
||
2287 | LIMIT 1"; |
||
2288 | |||
2289 | $result = Database::query($sql); |
||
2290 | |||
2291 | // Save every 5 minutes by default |
||
2292 | $seconds = $minutes * 60; |
||
2293 | $maxSeconds = 3600; // Only update if max diff is one hour |
||
2294 | if (Database::num_rows($result)) { |
||
2295 | $row = Database::fetch_array($result); |
||
2296 | $id = $row['course_access_id']; |
||
2297 | $logout = $row['logout_course_date']; |
||
2298 | $now = time(); |
||
2299 | $logout = api_strtotime($logout, 'UTC'); |
||
2300 | if ($now - $logout > $seconds && |
||
2301 | $now - $logout < $maxSeconds |
||
2302 | ) { |
||
2303 | $now = api_get_utc_datetime(); |
||
2304 | $sql = "UPDATE $table SET |
||
2305 | logout_course_date = '$now', |
||
2306 | counter = counter + 1 |
||
2307 | WHERE course_access_id = $id"; |
||
2308 | Database::query($sql); |
||
2309 | } |
||
2310 | |||
2311 | return true; |
||
2312 | } |
||
2313 | |||
2314 | return false; |
||
2315 | } |
||
2316 | |||
2317 | /** |
||
2318 | * Register the logout of the course (usually when logging out of the platform) |
||
2319 | * from the track_e_course_access table. |
||
2320 | * |
||
2321 | * @param array $logoutInfo Information stored by local.inc.php |
||
2322 | * before new context ['uid'=> x, 'cid'=>y, 'sid'=>z] |
||
2323 | * |
||
2324 | * @return bool |
||
2325 | */ |
||
2326 | public static function courseLogout($logoutInfo) |
||
2327 | { |
||
2328 | if (Session::read('login_as')) { |
||
2329 | return false; |
||
2330 | } |
||
2331 | |||
2332 | if (empty($logoutInfo['uid']) || empty($logoutInfo['cid'])) { |
||
2333 | return false; |
||
2334 | } |
||
2335 | |||
2336 | $sessionLifetime = api_get_configuration_value('session_lifetime'); |
||
2337 | /* |
||
2338 | * When $_configuration['session_lifetime'] is larger than ~100 hours |
||
2339 | * (in order to let users take exercises with no problems) |
||
2340 | * the function Tracking::get_time_spent_on_the_course() returns larger values (200h) due the condition: |
||
2341 | * login_course_date > now() - INTERVAL $session_lifetime SECOND |
||
2342 | */ |
||
2343 | if (empty($sessionLifetime) || $sessionLifetime > 86400) { |
||
2344 | $sessionLifetime = 3600; // 1 hour |
||
2345 | } |
||
2346 | if (!empty($logoutInfo) && !empty($logoutInfo['cid'])) { |
||
2347 | $sessionId = 0; |
||
2348 | if (!empty($logoutInfo['sid'])) { |
||
2349 | $sessionId = (int) $logoutInfo['sid']; |
||
2350 | } |
||
2351 | |||
2352 | if (self::isSessionLogNeedToBeSave($sessionId) === false) { |
||
2353 | return false; |
||
2354 | } |
||
2355 | |||
2356 | $tableCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2357 | $userId = (int) $logoutInfo['uid']; |
||
2358 | $courseId = (int) $logoutInfo['cid']; |
||
2359 | |||
2360 | $currentDate = api_get_utc_datetime(); |
||
2361 | // UTC time |
||
2362 | $diff = time() - $sessionLifetime; |
||
2363 | $time = api_get_utc_datetime($diff); |
||
2364 | $sql = "SELECT course_access_id, logout_course_date |
||
2365 | FROM $tableCourseAccess |
||
2366 | WHERE |
||
2367 | user_id = $userId AND |
||
2368 | c_id = $courseId AND |
||
2369 | session_id = $sessionId AND |
||
2370 | login_course_date > '$time' |
||
2371 | ORDER BY login_course_date DESC |
||
2372 | LIMIT 1"; |
||
2373 | $result = Database::query($sql); |
||
2374 | $insert = false; |
||
2375 | if (Database::num_rows($result) > 0) { |
||
2376 | $row = Database::fetch_array($result, 'ASSOC'); |
||
2377 | $courseAccessId = $row['course_access_id']; |
||
2378 | $sql = "UPDATE $tableCourseAccess SET |
||
2379 | logout_course_date = '$currentDate', |
||
2380 | counter = counter + 1 |
||
2381 | WHERE course_access_id = $courseAccessId"; |
||
2382 | Database::query($sql); |
||
2383 | } else { |
||
2384 | $insert = true; |
||
2385 | } |
||
2386 | |||
2387 | if ($insert) { |
||
2388 | $ip = Database::escape_string(api_get_real_ip()); |
||
2389 | $sql = "INSERT INTO $tableCourseAccess (c_id, user_ip, user_id, login_course_date, logout_course_date, counter, session_id) |
||
2390 | VALUES ($courseId, '$ip', $userId, '$currentDate', '$currentDate', 1, $sessionId)"; |
||
2391 | Database::query($sql); |
||
2392 | } |
||
2393 | |||
2394 | return true; |
||
2395 | } |
||
2396 | } |
||
2397 | |||
2398 | /** |
||
2399 | * Register a "fake" time spent on the platform, for example to match the |
||
2400 | * estimated time he took to author an assignment/work, see configuration |
||
2401 | * setting considered_working_time. |
||
2402 | * This assumes there is already some connection of the student to the |
||
2403 | * course, otherwise he wouldn't be able to upload an assignment. |
||
2404 | * This works by creating a new record, copy of the current one, then |
||
2405 | * updating the current one to be just the considered_working_time and |
||
2406 | * end at the same second as the user connected to the course. |
||
2407 | * |
||
2408 | * @param int $courseId The course in which to add the time |
||
2409 | * @param int $userId The user for whom to add the time |
||
2410 | * @param int $sessionId The session in which to add the time (if any) |
||
2411 | * @param string $virtualTime The amount of time to be added, |
||
2412 | * in a hh:mm:ss format. If int, we consider it is expressed in hours. |
||
2413 | * @param int $workId Student publication id result |
||
2414 | * |
||
2415 | * @return true on successful insertion, false otherwise |
||
2416 | */ |
||
2417 | public static function eventAddVirtualCourseTime( |
||
2418 | $courseId, |
||
2419 | $userId, |
||
2420 | $sessionId, |
||
2421 | $virtualTime, |
||
2422 | $workId |
||
2423 | ) { |
||
2424 | if (empty($virtualTime)) { |
||
2425 | return false; |
||
2426 | } |
||
2427 | |||
2428 | $courseId = (int) $courseId; |
||
2429 | $userId = (int) $userId; |
||
2430 | $sessionId = (int) $sessionId; |
||
2431 | |||
2432 | $logoutDate = api_get_utc_datetime(); |
||
2433 | $loginDate = ChamiloApi::addOrSubTimeToDateTime( |
||
2434 | $virtualTime, |
||
2435 | $logoutDate, |
||
2436 | false |
||
2437 | ); |
||
2438 | |||
2439 | $ip = api_get_real_ip(); |
||
2440 | $params = [ |
||
2441 | 'login_course_date' => $loginDate, |
||
2442 | 'logout_course_date' => $logoutDate, |
||
2443 | 'session_id' => $sessionId, |
||
2444 | 'user_id' => $userId, |
||
2445 | 'counter' => 0, |
||
2446 | 'c_id' => $courseId, |
||
2447 | 'user_ip' => $ip, |
||
2448 | ]; |
||
2449 | $courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2450 | Database::insert($courseTrackingTable, $params); |
||
2451 | |||
2452 | // Time should also be added to the track_e_login table so as to |
||
2453 | // affect total time on the platform |
||
2454 | $params = [ |
||
2455 | 'login_user_id' => $userId, |
||
2456 | 'login_date' => $loginDate, |
||
2457 | 'user_ip' => $ip, |
||
2458 | 'logout_date' => $logoutDate, |
||
2459 | ]; |
||
2460 | $platformTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
2461 | Database::insert($platformTrackingTable, $params); |
||
2462 | |||
2463 | if (Tracking::minimumTimeAvailable($sessionId, $courseId)) { |
||
2464 | $workId = (int) $workId; |
||
2465 | $uniqueId = time(); |
||
2466 | $logInfo = [ |
||
2467 | 'c_id' => $courseId, |
||
2468 | 'session_id' => $sessionId, |
||
2469 | 'tool' => TOOL_STUDENTPUBLICATION, |
||
2470 | 'date_reg' => $loginDate, |
||
2471 | 'action' => 'add_work_start_'.$workId, |
||
2472 | 'action_details' => $virtualTime, |
||
2473 | 'user_id' => $userId, |
||
2474 | 'current_id' => $uniqueId, |
||
2475 | ]; |
||
2476 | self::registerLog($logInfo); |
||
2477 | |||
2478 | $logInfo = [ |
||
2479 | 'c_id' => $courseId, |
||
2480 | 'session_id' => $sessionId, |
||
2481 | 'tool' => TOOL_STUDENTPUBLICATION, |
||
2482 | 'date_reg' => $logoutDate, |
||
2483 | 'action' => 'add_work_end_'.$workId, |
||
2484 | 'action_details' => $virtualTime, |
||
2485 | 'user_id' => $userId, |
||
2486 | 'current_id' => $uniqueId, |
||
2487 | ]; |
||
2488 | self::registerLog($logInfo); |
||
2489 | } |
||
2490 | |||
2491 | return true; |
||
2492 | } |
||
2493 | |||
2494 | /** |
||
2495 | * Removes a "fake" time spent on the platform, for example to match the |
||
2496 | * estimated time he took to author an assignment/work, see configuration |
||
2497 | * setting considered_working_time. |
||
2498 | * This method should be called when something that generated a fake |
||
2499 | * time record is removed. Given the database link is weak (no real |
||
2500 | * relationship kept between the deleted item and this record), this |
||
2501 | * method just looks for the latest record that has the same time as the |
||
2502 | * item's fake time, is in the past and in this course+session. If such a |
||
2503 | * record cannot be found, it doesn't do anything. |
||
2504 | * The IP address is not considered a useful filter here. |
||
2505 | * |
||
2506 | * @param int $courseId The course in which to add the time |
||
2507 | * @param int $userId The user for whom to add the time |
||
2508 | * @param int $sessionId The session in which to add the time (if any) |
||
2509 | * @param string $virtualTime The amount of time to be added, in a hh:mm:ss format. If int, we consider it is expressed in hours. |
||
2510 | * |
||
2511 | * @return true on successful removal, false otherwise |
||
2512 | */ |
||
2513 | public static function eventRemoveVirtualCourseTime( |
||
2514 | $courseId, |
||
2515 | $userId, |
||
2516 | $sessionId, |
||
2517 | $virtualTime, |
||
2518 | $workId |
||
2519 | ) { |
||
2520 | if (empty($virtualTime)) { |
||
2521 | return false; |
||
2522 | } |
||
2523 | |||
2524 | $courseId = (int) $courseId; |
||
2525 | $userId = (int) $userId; |
||
2526 | $sessionId = (int) $sessionId; |
||
2527 | $originalVirtualTime = Database::escape_string($virtualTime); |
||
2528 | $workId = (int) $workId; |
||
2529 | |||
2530 | $courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); |
||
2531 | $platformTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); |
||
2532 | |||
2533 | // Change $virtualTime format from hh:mm:ss to hhmmss which is the |
||
2534 | // format returned by SQL for a subtraction of two datetime values |
||
2535 | // @todo make sure this is portable between DBMSes |
||
2536 | if (preg_match('/:/', $virtualTime)) { |
||
2537 | [$h, $m, $s] = preg_split('/:/', $virtualTime); |
||
2538 | $virtualTime = $h * 3600 + $m * 60 + $s; |
||
2539 | } else { |
||
2540 | $virtualTime *= 3600; |
||
2541 | } |
||
2542 | |||
2543 | // Get the current latest course connection register. We need that |
||
2544 | // record to re-use the data and create a new record. |
||
2545 | $sql = "SELECT course_access_id |
||
2546 | FROM $courseTrackingTable |
||
2547 | WHERE |
||
2548 | user_id = $userId AND |
||
2549 | c_id = $courseId AND |
||
2550 | session_id = $sessionId AND |
||
2551 | counter = 0 AND |
||
2552 | (UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) = '$virtualTime' |
||
2553 | ORDER BY login_course_date DESC LIMIT 0,1"; |
||
2554 | $result = Database::query($sql); |
||
2555 | |||
2556 | // Ignore if we didn't find any course connection record in the last |
||
2557 | // hour. In this case it wouldn't be right to add a "fake" time record. |
||
2558 | if (Database::num_rows($result) > 0) { |
||
2559 | // Found the latest connection |
||
2560 | $row = Database::fetch_row($result); |
||
2561 | $courseAccessId = $row[0]; |
||
2562 | $sql = "DELETE FROM $courseTrackingTable |
||
2563 | WHERE course_access_id = $courseAccessId"; |
||
2564 | Database::query($sql); |
||
2565 | } |
||
2566 | $sql = "SELECT login_id |
||
2567 | FROM $platformTrackingTable |
||
2568 | WHERE |
||
2569 | login_user_id = $userId AND |
||
2570 | (UNIX_TIMESTAMP(logout_date) - UNIX_TIMESTAMP(login_date)) = '$virtualTime' |
||
2571 | ORDER BY login_date DESC LIMIT 0,1"; |
||
2572 | $result = Database::query($sql); |
||
2573 | if (Database::num_rows($result) > 0) { |
||
2574 | // Found the latest connection |
||
2575 | $row = Database::fetch_row($result); |
||
2576 | $loginAccessId = $row[0]; |
||
2577 | $sql = "DELETE FROM $platformTrackingTable |
||
2578 | WHERE login_id = $loginAccessId"; |
||
2579 | Database::query($sql); |
||
2580 | } |
||
2581 | |||
2582 | if (Tracking::minimumTimeAvailable($sessionId, $courseId)) { |
||
2583 | $sql = "SELECT id FROM track_e_access_complete |
||
2584 | WHERE |
||
2585 | tool = '".TOOL_STUDENTPUBLICATION."' AND |
||
2586 | c_id = $courseId AND |
||
2587 | session_id = $sessionId AND |
||
2588 | user_id = $userId AND |
||
2589 | action_details = '$originalVirtualTime' AND |
||
2590 | action = 'add_work_start_$workId' "; |
||
2591 | $result = Database::query($sql); |
||
2592 | $result = Database::fetch_array($result); |
||
2593 | if ($result) { |
||
2594 | $sql = 'DELETE FROM track_e_access_complete WHERE id = '.$result['id']; |
||
2595 | Database::query($sql); |
||
2596 | } |
||
2597 | |||
2598 | $sql = "SELECT id FROM track_e_access_complete |
||
2599 | WHERE |
||
2600 | tool = '".TOOL_STUDENTPUBLICATION."' AND |
||
2601 | c_id = $courseId AND |
||
2602 | session_id = $sessionId AND |
||
2603 | user_id = $userId AND |
||
2604 | action_details = '$originalVirtualTime' AND |
||
2605 | action = 'add_work_end_$workId' "; |
||
2606 | $result = Database::query($sql); |
||
2607 | $result = Database::fetch_array($result); |
||
2608 | if ($result) { |
||
2609 | $sql = 'DELETE FROM track_e_access_complete WHERE id = '.$result['id']; |
||
2610 | Database::query($sql); |
||
2611 | } |
||
2612 | } |
||
2613 | |||
2614 | return false; |
||
2615 | } |
||
2616 | |||
2617 | /** |
||
2618 | * For the sake of cohesion, this function is a switch. |
||
2619 | * It's called by EventsDispatcher and fires the right function |
||
2620 | * with the right require_once. |
||
2621 | * |
||
2622 | * @deprecated |
||
2623 | * |
||
2624 | * @param string $event_name |
||
2625 | * @param array $params |
||
2626 | */ |
||
2627 | public static function event_send_mail($event_name, $params) |
||
2628 | { |
||
2629 | EventsMail::send_mail($event_name, $params); |
||
2630 | } |
||
2631 | |||
2632 | /** |
||
2633 | * Filter EventEmailTemplate Filters see the main/inc/conf/events.conf.dist.php. |
||
2634 | */ |
||
2635 | |||
2636 | /** |
||
2637 | * Basic template event message filter (to be used by other filters as default). |
||
2638 | * |
||
2639 | * @deprecated |
||
2640 | * |
||
2641 | * @param array $values (passing by reference) * |
||
2642 | * |
||
2643 | * @return bool True if everything is OK, false otherwise |
||
2644 | */ |
||
2645 | public function event_send_mail_filter_func(&$values) |
||
2646 | { |
||
2647 | return true; |
||
2648 | } |
||
2649 | |||
2650 | /** |
||
2651 | * user_registration - send_mail filter. |
||
2652 | * |
||
2653 | * @deprecated |
||
2654 | * |
||
2655 | * @param array $values (passing by reference) |
||
2656 | * |
||
2657 | * @return bool True if everything is OK, false otherwise |
||
2658 | */ |
||
2659 | public function user_registration_event_send_mail_filter_func(&$values) |
||
2660 | { |
||
2661 | $res = self::event_send_mail_filter_func($values); |
||
2662 | // proper logic for this filter |
||
2663 | return $res; |
||
2664 | } |
||
2665 | |||
2666 | /** |
||
2667 | * portal_homepage_edited - send_mail filter. |
||
2668 | * |
||
2669 | * @deprecated |
||
2670 | * |
||
2671 | * @param array $values (passing by reference) |
||
2672 | * |
||
2673 | * @return bool True if everything is OK, false otherwise |
||
2674 | */ |
||
2675 | public function portal_homepage_edited_event_send_mail_filter_func(&$values) |
||
2676 | { |
||
2677 | $res = self::event_send_mail_filter_func($values); |
||
2678 | // proper logic for this filter |
||
2679 | return $res; |
||
2680 | } |
||
2681 | |||
2682 | /** |
||
2683 | * Register the logout of the course (usually when logging out of the platform) |
||
2684 | * from the track_e_access_complete table. |
||
2685 | * |
||
2686 | * @param array $logInfo Information stored by local.inc.php |
||
2687 | * |
||
2688 | * @return bool |
||
2689 | */ |
||
2690 | public static function registerLog($logInfo) |
||
2691 | { |
||
2692 | $sessionId = api_get_session_id(); |
||
2693 | $courseId = api_get_course_int_id(); |
||
2694 | |||
2695 | if (isset($logInfo['c_id']) && !empty($logInfo['c_id'])) { |
||
2696 | $courseId = $logInfo['c_id']; |
||
2697 | } |
||
2698 | |||
2699 | if (isset($logInfo['session_id']) && !empty($logInfo['session_id'])) { |
||
2700 | $sessionId = $logInfo['session_id']; |
||
2701 | } |
||
2702 | |||
2703 | if (!Tracking::minimumTimeAvailable($sessionId, $courseId)) { |
||
2704 | return false; |
||
2705 | } |
||
2706 | |||
2707 | if (self::isSessionLogNeedToBeSave($sessionId) === false) { |
||
2708 | return false; |
||
2709 | } |
||
2710 | |||
2711 | $loginAs = (int) Session::read('login_as') === true; |
||
2712 | |||
2713 | $logInfo['user_id'] = isset($logInfo['user_id']) ? $logInfo['user_id'] : api_get_user_id(); |
||
2714 | $logInfo['date_reg'] = isset($logInfo['date_reg']) ? $logInfo['date_reg'] : api_get_utc_datetime(); |
||
2715 | $logInfo['tool'] = !empty($logInfo['tool']) ? $logInfo['tool'] : ''; |
||
2716 | $logInfo['tool_id'] = !empty($logInfo['tool_id']) ? (int) $logInfo['tool_id'] : 0; |
||
2717 | $logInfo['tool_id_detail'] = !empty($logInfo['tool_id_detail']) ? (int) $logInfo['tool_id_detail'] : 0; |
||
2718 | $logInfo['action'] = !empty($logInfo['action']) ? $logInfo['action'] : ''; |
||
2719 | $logInfo['action_details'] = !empty($logInfo['action_details']) ? $logInfo['action_details'] : ''; |
||
2720 | $logInfo['ip_user'] = api_get_real_ip(); |
||
2721 | $logInfo['user_agent'] = $_SERVER['HTTP_USER_AGENT']; |
||
2722 | $logInfo['session_id'] = $sessionId; |
||
2723 | $logInfo['c_id'] = $courseId; |
||
2724 | $logInfo['ch_sid'] = session_id(); |
||
2725 | $logInfo['login_as'] = $loginAs; |
||
2726 | $logInfo['info'] = !empty($logInfo['info']) ? $logInfo['info'] : ''; |
||
2727 | $logInfo['url'] = $_SERVER['REQUEST_URI']; |
||
2728 | $logInfo['current_id'] = isset($logInfo['current_id']) ? $logInfo['current_id'] : Session::read('last_id', 0); |
||
2729 | |||
2730 | $id = Database::insert('track_e_access_complete', $logInfo); |
||
2731 | if ($id && empty($logInfo['current_id'])) { |
||
2732 | Session::write('last_id', $id); |
||
2733 | } |
||
2734 | |||
2735 | return true; |
||
2736 | } |
||
2737 | |||
2738 | public static function getAttemptQuestionDuration($exeId, $questionId) |
||
2762 | } |
||
2763 | |||
2764 | public static function logSubscribedUserInCourse(int $subscribedId, int $courseId) |
||
2765 | { |
||
2766 | $dateTime = api_get_utc_datetime(); |
||
2767 | $registrantId = api_get_user_id(); |
||
2768 | |||
2769 | self::addEvent( |
||
2770 | LOG_SUBSCRIBE_USER_TO_COURSE, |
||
2771 | LOG_COURSE_CODE, |
||
2772 | api_get_course_entity($courseId)->getCode(), |
||
2773 | $dateTime, |
||
2774 | $registrantId, |
||
2775 | $courseId |
||
2776 | ); |
||
2777 | |||
2778 | self::addEvent( |
||
2779 | LOG_SUBSCRIBE_USER_TO_COURSE, |
||
2780 | LOG_USER_OBJECT, |
||
2781 | api_get_user_info($subscribedId), |
||
2785 | ); |
||
2786 | } |
||
2787 | |||
2788 | public static function logUserSubscribedInCourseSession(int $subscribedId, int $courseId, int $sessionId) |
||
2789 | { |
||
2790 | $dateTime = api_get_utc_datetime(); |
||
2791 | $registrantId = api_get_user_id(); |
||
2792 | |||
2793 | self::addEvent( |
||
2794 | LOG_SESSION_ADD_USER_COURSE, |
||
2795 | LOG_USER_ID, |
||
2796 | $subscribedId, |
||
2797 | $dateTime, |
||
2798 | $registrantId, |
||
2799 | $courseId, |
||
2800 | $sessionId |
||
2801 | ); |
||
2802 | self::addEvent( |
||
2803 | LOG_SUBSCRIBE_USER_TO_COURSE, |
||
2804 | LOG_COURSE_CODE, |
||
2805 | api_get_course_entity($courseId)->getCode(), |
||
2806 | $dateTime, |
||
2807 | $registrantId, |
||
2819 | ); |
||
2820 | } |
||
2821 | |||
2822 | /** |
||
2823 | * Retrieves audit items from the track_e_default table. |
||
2824 | * |
||
2825 | * This function fetches audit data based on various optional criteria and |
||
2826 | * formats the result to remove the "default_" prefix from each field. |
||
2827 | */ |
||
2828 | public static function getAuditItems( |
||
2883 |