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

Event::updateEventExercise()   B

Complexity

Conditions 7
Paths 17

Size

Total Lines 82
Code Lines 45

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 45
c 0
b 0
f 0
nc 17
nop 13
dl 0
loc 82
rs 8.2666

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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