Passed
Push — ofaj ( 0f9380...ade756 )
by
unknown
12:01 queued 12s
created

Event::getAttemptQuestionDuration()   B

Complexity

Conditions 7
Paths 6

Size

Total Lines 24
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

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