Passed
Push — master ( 3ff5ba...819fa7 )
by Julito
31:00 queued 18:32
created

Event::check_if_mail_already_sent()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 13
nc 2
nop 3
dl 0
loc 22
rs 9.8333
c 0
b 0
f 0
1
<?php
2
/* See license terms in /license.txt */
3
4
//use Chamilo\UserBundle\Entity\User;
5
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
6
use ChamiloSession as Session;
7
8
/**
9
 * Class Event
10
 * Functions of this library are used to record informations when some kind
11
 * of event occur. Each event has his own types of informations then each event
12
 * use its own function.
13
 */
14
class Event
15
{
16
    /**
17
     * @author Sebastien Piraux <[email protected]>
18
     * @desc Record information for open event (when homepage is opened)
19
     */
20
    public static function open()
21
    {
22
        global $_configuration;
23
        global $TABLETRACK_OPEN;
24
25
        // @getHostByAddr($_SERVER['REMOTE_ADDR']) : will provide host and country information
26
        // $_SERVER['HTTP_USER_AGENT'] :  will provide browser and os information
27
        // $_SERVER['HTTP_REFERER'] : provide information about refering url
28
        if (isset($_SERVER['HTT_REFERER'])) {
29
            $referer = Database::escape_string($_SERVER['HTTP_REFERER']);
30
        } else {
31
            $referer = '';
32
        }
33
        // record informations only if user comes from another site
34
        //if(!eregi($_configuration['root_web'],$referer))
35
        $pos = strpos($referer, $_configuration['root_web']);
36
        if ($pos === false && $referer != '') {
37
            $ip = api_get_real_ip();
38
            $remhost = @gethostbyaddr($ip);
39
            if ($remhost == $ip) {
40
                $remhost = "Unknown";
41
            } // don't change this
42
            $reallyNow = api_get_utc_datetime();
43
            $params = [
44
                'open_remote_host' => Database::escape_string($remhost),
45
                'open_agent' => $_SERVER['HTTP_USER_AGENT'],
46
                'open_referer' => $referer,
47
                'open_date' => $reallyNow,
48
            ];
49
            Database::insert($TABLETRACK_OPEN, $params);
50
        }
51
52
        return 1;
53
    }
54
55
    /**
56
     * @author Sebastien Piraux <[email protected]> old code
57
     * @author Julio Montoya
58
     *
59
     * @param int $userId
60
     *
61
     * @return bool
62
     * @desc Record information for login event when an user identifies himself with username & password
63
     */
64
    public static function eventLogin($userId)
65
    {
66
        $userInfo = api_get_user_info($userId);
67
        $userId = (int) $userId;
68
69
        if (empty($userInfo)) {
70
            return false;
71
        }
72
73
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
74
        $reallyNow = api_get_utc_datetime();
75
        $userIp = Database::escape_string(api_get_real_ip());
76
77
        $sql = "INSERT INTO $table (login_user_id, user_ip, login_date, logout_date) VALUES
78
                    ($userId,
79
                    '$userIp',
80
                    '$reallyNow',
81
                    '$reallyNow'
82
                )";
83
        Database::query($sql);
84
85
        // Auto subscribe
86
        $user_status = $userInfo['status'] == SESSIONADMIN ? 'sessionadmin' : $userInfo['status'] == COURSEMANAGER ? 'teacher' : $userInfo['status'] == DRH ? 'DRH' : 'student';
87
        $autoSubscribe = api_get_setting($user_status.'_autosubscribe');
88
        if ($autoSubscribe) {
89
            $autoSubscribe = explode('|', $autoSubscribe);
90
            foreach ($autoSubscribe as $code) {
91
                if (CourseManager::course_exists($code)) {
92
                    CourseManager::subscribe_user($userId, $code);
93
                }
94
            }
95
        }
96
97
        return true;
98
    }
99
100
    /**
101
     * @author Sebastien Piraux <[email protected]>
102
     * @desc Record information for access event for courses
103
     */
104
    public static function accessCourse()
105
    {
106
        if (Session::read('login_as')) {
107
            return false;
108
        }
109
110
        $TABLETRACK_ACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
111
        //for "what's new" notification
112
        $TABLETRACK_LASTACCESS = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
113
114
        $id_session = api_get_session_id();
115
        $now = api_get_utc_datetime();
116
        $courseId = api_get_course_int_id();
117
        $userId = api_get_user_id();
118
        $ip = Database::escape_string(api_get_real_ip());
119
120
        if ($userId) {
121
            $userId = $userId;
122
        } else {
123
            $userId = "0"; // no one
124
        }
125
        $sql = "INSERT INTO $TABLETRACK_ACCESS  (user_ip, access_user_id, c_id, access_date, access_session_id) 
126
                VALUES ('$ip', $userId, $courseId, '$now', $id_session)";
127
128
        Database::query($sql);
129
130
        // added for "what's new" notification
131
        $sql = "UPDATE $TABLETRACK_LASTACCESS  SET access_date = '$now'
132
                WHERE 
133
                  access_user_id = $userId AND
134
                  c_id = $courseId AND 
135
                  access_tool IS NULL AND 
136
                  access_session_id = $id_session";
137
        $result = Database::query($sql);
138
139
        if (Database::affected_rows($result) == 0) {
140
            $sql = "INSERT INTO $TABLETRACK_LASTACCESS (access_user_id, c_id, access_date, access_session_id)
141
                    VALUES ($userId, $courseId, '$now', $id_session)";
142
            Database::query($sql);
143
        }
144
145
        return 1;
146
    }
147
148
    /**
149
     * @param string $tool name of the tool
150
     *
151
     * @author Sebastien Piraux <[email protected]>
152
     * @desc Record information for access event for tools
153
     *
154
     *  $tool can take this values :
155
     *  Links, Calendar, Document, Announcements,
156
     *  Group, Video, Works, Users, Exercises, Course Desc
157
     *  ...
158
     *  Values can be added if new modules are created (15char max)
159
     *  I encourage to use $nameTool as $tool when calling this function
160
     *
161
     * Functionality for "what's new" notification is added by Toon Van Hoecke
162
     *
163
     * @return bool
164
     */
165
    public static function event_access_tool($tool)
166
    {
167
        if (Session::read('login_as')) {
168
            return false;
169
        }
170
171
        $tool = Database::escape_string($tool);
172
173
        if (empty($tool)) {
174
            return false;
175
        }
176
177
        $courseInfo = api_get_course_info();
178
        $sessionId = api_get_session_id();
179
        $reallyNow = api_get_utc_datetime();
180
        $userId = api_get_user_id();
181
182
        if (empty($courseInfo)) {
183
            return false;
184
        }
185
        $courseId = $courseInfo['real_id'];
186
187
        $tableAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
188
        //for "what's new" notification
189
        $tableLastAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
190
191
        // record information
192
        // only if user comes from the course $_cid
193
        //if( eregi($_configuration['root_web'].$_cid,$_SERVER['HTTP_REFERER'] ) )
194
        //$pos = strpos($_SERVER['HTTP_REFERER'],$_configuration['root_web'].$_cid);
195
        $coursePath = isset($courseInfo['path']) ? $courseInfo['path'] : null;
196
197
        $pos = isset($_SERVER['HTTP_REFERER']) ? strpos(strtolower($_SERVER['HTTP_REFERER']), strtolower(api_get_path(WEB_COURSE_PATH).$coursePath)) : false;
198
        // added for "what's new" notification
199
        $pos2 = isset($_SERVER['HTTP_REFERER']) ? strpos(strtolower($_SERVER['HTTP_REFERER']), strtolower(api_get_path(WEB_PATH)."index")) : false;
200
201
        // end "what's new" notification
202
        if ($pos !== false || $pos2 !== false) {
203
            $params = [
204
                'access_user_id' => $userId,
205
                'c_id' => $courseId,
206
                'access_tool' => $tool,
207
                'access_date' => $reallyNow,
208
                'access_session_id' => $sessionId,
209
                'user_ip' => Database::escape_string(api_get_real_ip()),
210
            ];
211
            Database::insert($tableAccess, $params);
212
        }
213
214
        // "what's new" notification
215
        $sql = "UPDATE $tableLastAccess
216
                SET access_date = '$reallyNow'
217
                WHERE 
218
                    access_user_id = $userId AND 
219
                    c_id = $courseId AND 
220
                    access_tool = '$tool' AND 
221
                    access_session_id = $sessionId";
222
        $result = Database::query($sql);
223
224
        if (Database::affected_rows($result) == 0) {
225
            $params = [
226
                'access_user_id' => $userId,
227
                'c_id' => $courseId,
228
                'access_tool' => $tool,
229
                'access_date' => $reallyNow,
230
                'access_session_id' => $sessionId,
231
            ];
232
            Database::insert($tableLastAccess, $params);
233
        }
234
235
        return true;
236
    }
237
238
    /**
239
     * Record information for download event (when an user click to d/l a
240
     * document) it will be used in a redirection page.
241
     *
242
     * @param string $documentUrl
243
     *
244
     * @return int
245
     *
246
     * @author Sebastien Piraux <[email protected]>
247
     * @author Evie Embrechts (bug fixed: The user id is put in single quotes)
248
     */
249
    public static function event_download($documentUrl)
250
    {
251
        if (Session::read('login_as')) {
252
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
253
        }
254
255
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
256
        $documentUrl = Database::escape_string($documentUrl);
257
258
        $reallyNow = api_get_utc_datetime();
259
        $userId = api_get_user_id();
260
        $courseId = api_get_course_int_id();
261
        $sessionId = api_get_session_id();
262
263
        $sql = "INSERT INTO $table (
264
                 down_user_id,
265
                 c_id,
266
                 down_doc_path,
267
                 down_date,
268
                 down_session_id
269
                )
270
                VALUES (
271
                 $userId,
272
                 $courseId,
273
                 '$documentUrl',
274
                 '$reallyNow',
275
                 $sessionId
276
                )";
277
        Database::query($sql);
278
279
        return 1;
280
    }
281
282
    /**
283
     * @param int $documentId of document (id in mainDb.document table)
284
     *
285
     * @author Sebastien Piraux <[email protected]>
286
     * @desc Record information for upload event
287
     * used in the works tool to record informations when
288
     * an user upload 1 work
289
     *
290
     * @return int
291
     */
292
    public static function event_upload($documentId)
293
    {
294
        if (Session::read('login_as')) {
295
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
296
        }
297
298
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
299
        $courseId = api_get_course_int_id();
300
        $reallyNow = api_get_utc_datetime();
301
        $userId = api_get_user_id();
302
        $documentId = (int) $documentId;
303
        $sessionId = api_get_session_id();
304
305
        $sql = "INSERT INTO $table
306
                ( upload_user_id,
307
                  c_id,
308
                  upload_cours_id,
309
                  upload_work_id,
310
                  upload_date,
311
                  upload_session_id
312
                )
313
                VALUES (
314
                 $userId,
315
                 $courseId,
316
                 '',
317
                 $documentId,
318
                 '$reallyNow',
319
                 $sessionId
320
                )";
321
        Database::query($sql);
322
323
        return 1;
324
    }
325
326
    /**
327
     * Record information for link event (when an user click on an added link)
328
     * it will be used in a redirection page.
329
     *
330
     * @param int $linkId (id in c_link table)
331
     *
332
     * @return int
333
     *
334
     * @author Sebastien Piraux <[email protected]>
335
     */
336
    public static function event_link($linkId)
337
    {
338
        if (Session::read('login_as')) {
339
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type integer.
Loading history...
340
        }
341
342
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
343
        $reallyNow = api_get_utc_datetime();
344
        $userId = api_get_user_id();
345
        $courseId = api_get_course_int_id();
346
        $linkId = (int) $linkId;
347
        $sessionId = api_get_session_id();
348
        $sql = "INSERT INTO ".$table."
349
                    ( links_user_id,
350
                     c_id,
351
                     links_link_id,
352
                     links_date,
353
                     links_session_id
354
                    ) VALUES (
355
                     $userId,
356
                     $courseId,
357
                     $linkId,
358
                     '$reallyNow',
359
                     $sessionId
360
                    )";
361
        Database::query($sql);
362
363
        return 1;
364
    }
365
366
    /**
367
     * Update the TRACK_E_EXERCICES exercises.
368
     *
369
     * @param   int     exeid id of the attempt
370
     * @param   int     exo_id    exercise id
371
     * @param   mixed   result    score
372
     * @param   int     weighting ( higher score )
373
     * @param   int     duration ( duration of the attempt in seconds )
374
     * @param   int     session_id
375
     * @param   int     learnpath_id (id of the learnpath)
376
     * @param   int     learnpath_item_id (id of the learnpath_item)
377
     *
378
     * @return bool
379
     *
380
     * @author Sebastien Piraux <[email protected]>
381
     * @author Julio Montoya Armas <[email protected]> Reworked 2010
382
     * @desc Record result of user when an exercise was done
383
     */
384
    public static function updateEventExercise(
385
        $exeId,
386
        $exoId,
387
        $score,
388
        $weighting,
389
        $sessionId,
390
        $learnpathId = 0,
391
        $learnpathItemId = 0,
392
        $learnpathItemViewId = 0,
393
        $duration = 0,
394
        $questionsList = [],
395
        $status = '',
396
        $remindList = [],
397
        $endDate = null
398
    ) {
399
        if (empty($exeId)) {
400
            return false;
401
        }
402
403
        /*
404
         * Code commented due BT#8423 do not change the score to 0.
405
         *
406
         * Validation in case of fraud with actived control time
407
        if (!ExerciseLib::exercise_time_control_is_valid($exo_id, $learnpath_id, $learnpath_item_id)) {
408
            $score = 0;
409
        }
410
        */
411
        if (!isset($status) || empty($status)) {
412
            $status = '';
413
        } else {
414
            $status = Database::escape_string($status);
415
        }
416
417
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
418
419
        if (!empty($questionsList)) {
420
            $questionsList = array_map('intval', $questionsList);
421
        }
422
423
        if (!empty($remindList)) {
424
            $remindList = array_map('intval', $remindList);
425
            $remindList = array_filter($remindList);
426
            $remindList = implode(",", $remindList);
427
        } else {
428
            $remindList = '';
429
        }
430
431
        if (empty($endDate)) {
432
            $endDate = api_get_utc_datetime();
433
        }
434
        $exoId = (int) $exoId;
435
        $sessionId = (int) $sessionId;
436
        $learnpathId = (int) $learnpathId;
437
        $learnpathItemId = (int) $learnpathItemId;
438
        $learnpathItemViewId = (int) $learnpathItemViewId;
439
        $duration = (int) $duration;
440
        $exeId = (int) $exeId;
441
        $score = Database::escape_string($score);
442
        $weighting = Database::escape_string($weighting);
443
        $questions = implode(',', $questionsList);
444
        $userIp = Database::escape_string(api_get_real_ip());
445
446
        $sql = "UPDATE $table SET
447
               exe_exo_id = $exoId,
448
               exe_result = '$score',
449
               exe_weighting = '$weighting',
450
               session_id = $sessionId,
451
               orig_lp_id = $learnpathId,
452
               orig_lp_item_id = $learnpathItemId,
453
               orig_lp_item_view_id = $learnpathItemViewId,
454
               exe_duration = $duration,
455
               exe_date = '$endDate',
456
               status = '$status',
457
               questions_to_check = '$remindList',
458
               data_tracking = '$questions',
459
               user_ip = '$userIp'
460
             WHERE exe_id = $exeId";
461
        Database::query($sql);
462
463
        //Deleting control time session track
464
        //ExerciseLib::exercise_time_control_delete($exo_id);
465
        return true;
466
    }
467
468
    /**
469
     * Record an event for this attempt at answering an exercise.
470
     *
471
     * @param    float    Score achieved
472
     * @param    string    Answer given
473
     * @param    int    Question ID
474
     * @param    int Exercise attempt ID a.k.a exe_id (from track_e_exercise)
475
     * @param    int    Position
476
     * @param    int Exercise ID (from c_quiz)
477
     * @param    bool update results?
478
     * @param $fileName string  Filename (for audio answers - using nanogong)
479
     * @param    int User ID The user who's going to get this score. Default value of null means "get from context".
480
     * @param    int Course ID (from the "id" column of course table). Default value of null means "get from context".
481
     * @param    int Session ID (from the session table). Default value of null means "get from context".
482
     * @param    int Learnpath ID (from c_lp table). Default value of null means "get from context".
483
     * @param    int Learnpath item ID (from the c_lp_item table). Default value of null means "get from context".
484
     *
485
     * @return bool Result of the insert query
486
     */
487
    public static function saveQuestionAttempt(
488
        $score,
489
        $answer,
490
        $question_id,
491
        $exe_id,
492
        $position,
493
        $exercise_id = 0,
494
        $updateResults = false,
495
        $fileName = null,
496
        $user_id = null,
497
        $course_id = null,
498
        $session_id = null,
499
        $learnpath_id = null,
500
        $learnpath_item_id = null
501
    ) {
502
        global $debug;
503
        $question_id = Database::escape_string($question_id);
504
        $exe_id = Database::escape_string($exe_id);
505
        $position = Database::escape_string($position);
506
        $now = api_get_utc_datetime();
507
508
        // check user_id or get from context
509
        if (empty($user_id)) {
510
            $user_id = api_get_user_id();
511
            // anonymous
512
            if (empty($user_id)) {
513
                $user_id = api_get_anonymous_id();
514
            }
515
        }
516
        // check course_id or get from context
517
        if (empty($course_id) or intval($course_id) != $course_id) {
518
            $course_id = api_get_course_int_id();
519
        }
520
        // check session_id or get from context
521
        if (empty($session_id)) {
522
            $session_id = api_get_session_id();
523
        }
524
        // check learnpath_id or get from context
525
        if (empty($learnpath_id)) {
526
            global $learnpath_id;
527
        }
528
        // check learnpath_item_id or get from context
529
        if (empty($learnpath_item_id)) {
530
            global $learnpath_item_id;
531
        }
532
533
        $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
534
535
        if ($debug) {
536
            error_log("----- entering saveQuestionAttempt() function ------");
537
            error_log("answer: $answer");
538
            error_log("score: $score");
539
            error_log("question_id : $question_id");
540
            error_log("position: $position");
541
        }
542
543
        //Validation in case of fraud with active control time
544
        if (!ExerciseLib::exercise_time_control_is_valid($exercise_id, $learnpath_id, $learnpath_item_id)) {
545
            if ($debug) {
546
                error_log("exercise_time_control_is_valid is false");
547
            }
548
            $score = 0;
549
            $answer = 0;
550
        }
551
552
        $session_id = api_get_session_id();
553
554
        if (!empty($question_id) && !empty($exe_id) && !empty($user_id)) {
555
            if (is_null($answer)) {
556
                $answer = '';
557
            }
558
559
            if (is_null($score)) {
560
                $score = 0;
561
            }
562
563
            $attempt = [
564
                'user_id' => $user_id,
565
                'question_id' => $question_id,
566
                'answer' => $answer,
567
                'marks' => $score,
568
                'c_id' => $course_id,
569
                'session_id' => $session_id,
570
                'position' => $position,
571
                'tms' => $now,
572
                'filename' => !empty($fileName) ? basename($fileName) : $fileName,
573
                'teacher_comment' => '',
574
            ];
575
576
            // Check if attempt exists.
577
            $sql = "SELECT exe_id FROM $TBL_TRACK_ATTEMPT
578
                    WHERE
579
                        c_id = $course_id AND
580
                        session_id = $session_id AND
581
                        exe_id = $exe_id AND
582
                        user_id = $user_id AND
583
                        question_id = $question_id AND
584
                        position = $position";
585
            $result = Database::query($sql);
586
            if (Database::num_rows($result)) {
587
                if ($debug) {
588
                    error_log("Attempt already exist: exe_id: $exe_id - user_id:$user_id - question_id:$question_id");
589
                }
590
                if ($updateResults == false) {
591
                    //The attempt already exist do not update use  update_event_exercise() instead
592
                    return false;
593
                }
594
            } else {
595
                $attempt['exe_id'] = $exe_id;
596
            }
597
598
            if ($debug) {
599
                error_log("updateResults : $updateResults");
600
                error_log("Saving question attempt: ");
601
                error_log($sql);
602
            }
603
604
            $recording_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
605
606
            if ($updateResults == false) {
607
                $attempt_id = Database::insert($TBL_TRACK_ATTEMPT, $attempt);
608
609
                if ($debug) {
610
                    error_log("Insert attempt with id #$attempt_id");
611
                }
612
613
                if (defined('ENABLED_LIVE_EXERCISE_TRACKING')) {
614
                    if ($debug) {
615
                        error_log("Saving e attempt recording ");
616
                    }
617
                    $attempt_recording = [
618
                        'exe_id' => $attempt_id,
619
                        'question_id' => $question_id,
620
                        'marks' => $score,
621
                        'insert_date' => $now,
622
                        'author' => '',
623
                        'session_id' => $session_id,
624
                    ];
625
                    Database::insert($recording_table, $attempt_recording);
626
                }
627
            } else {
628
                Database::update(
629
                    $TBL_TRACK_ATTEMPT,
630
                    $attempt,
631
                    [
632
                        'exe_id = ? AND question_id = ? AND user_id = ? ' => [
633
                            $exe_id,
634
                            $question_id,
635
                            $user_id,
636
                        ],
637
                    ]
638
                );
639
640
                if (defined('ENABLED_LIVE_EXERCISE_TRACKING')) {
641
                    $attempt_recording = [
642
                        'exe_id' => $exe_id,
643
                        'question_id' => $question_id,
644
                        'marks' => $score,
645
                        'insert_date' => $now,
646
                        'author' => '',
647
                        'session_id' => $session_id,
648
                    ];
649
650
                    Database::update(
651
                        $recording_table,
652
                        $attempt_recording,
653
                        [
654
                            'exe_id = ? AND question_id = ? AND session_id = ? ' => [
655
                                $exe_id,
656
                                $question_id,
657
                                $session_id,
658
                            ],
659
                        ]
660
                    );
661
                }
662
                $attempt_id = $exe_id;
663
            }
664
665
            return $attempt_id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $attempt_id also could return the type integer|string which is incompatible with the documented return type boolean.
Loading history...
666
        } else {
667
            return false;
668
        }
669
    }
670
671
    /**
672
     * Record an hotspot spot for this attempt at answering an hotspot question.
673
     *
674
     * @param int    $exeId
675
     * @param int    $questionId    Question ID
676
     * @param int    $answerId      Answer ID
677
     * @param int    $correct
678
     * @param string $coords        Coordinates of this point (e.g. 123;324)
679
     * @param bool   $updateResults
680
     * @param int    $exerciseId
681
     *
682
     * @return bool Result of the insert query
683
     *
684
     * @uses \Course code and user_id from global scope $_cid and $_user
685
     */
686
    public static function saveExerciseAttemptHotspot(
687
        $exeId,
688
        $questionId,
689
        $answerId,
690
        $correct,
691
        $coords,
692
        $updateResults = false,
693
        $exerciseId = 0
694
    ) {
695
        $debug = false;
696
        global $safe_lp_id, $safe_lp_item_id;
697
698
        if ($updateResults == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
699
            // Validation in case of fraud with activated control time
700
            if (!ExerciseLib::exercise_time_control_is_valid($exerciseId, $safe_lp_id, $safe_lp_item_id)) {
701
                if ($debug) {
702
                    error_log('Attempt is fraud');
703
                }
704
                $correct = 0;
705
            }
706
        }
707
708
        if (empty($exeId)) {
709
            if ($debug) {
710
                error_log('exe id is empty');
711
            }
712
713
            return false;
714
        }
715
716
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
717
        if ($updateResults) {
718
            if ($debug) {
719
                error_log("Insert hotspot results: exeId: $exeId correct: $correct");
720
            }
721
            $params = [
722
                'hotspot_correct' => $correct,
723
                'hotspot_coordinate' => $coords,
724
            ];
725
            Database::update(
726
                $table,
727
                $params,
728
                [
729
                    'hotspot_user_id = ? AND hotspot_exe_id = ? AND hotspot_question_id = ? AND hotspot_answer_id = ? ' => [
730
                        api_get_user_id(),
731
                        $exeId,
732
                        $questionId,
733
                        $answerId,
734
                    ],
735
                ]
736
            );
737
        } else {
738
            if ($debug) {
739
                error_log("Insert hotspot results: exeId: $exeId correct: $correct");
740
            }
741
742
            return Database::insert(
0 ignored issues
show
Bug Best Practice introduced by
The expression return Database::insert(...oordinate' => $coords)) also could return the type integer which is incompatible with the documented return type boolean.
Loading history...
743
                $table,
744
                [
745
                    'hotspot_course_code' => api_get_course_id(),
746
                    'hotspot_user_id' => api_get_user_id(),
747
                    'c_id' => api_get_course_int_id(),
748
                    'hotspot_exe_id' => $exeId,
749
                    'hotspot_question_id' => $questionId,
750
                    'hotspot_answer_id' => $answerId,
751
                    'hotspot_correct' => $correct,
752
                    'hotspot_coordinate' => $coords,
753
                ]
754
            );
755
        }
756
    }
757
758
    /**
759
     * Records information for common (or admin) events (in the track_e_default table).
760
     *
761
     * @author Yannick Warnier <[email protected]>
762
     *
763
     * @param string $event_type       Type of event
764
     * @param string $event_value_type Type of value
765
     * @param mixed  $event_value      Value (string, or array in the case of user info)
766
     * @param string $datetime         Datetime (UTC) (defaults to null)
767
     * @param int    $user_id          User ID (defaults to null)
768
     * @param int    $course_id        Course ID (defaults to null)
769
     * @param int    $sessionId        Session ID
770
     *
771
     * @return bool
772
     * @assert ('','','') === false
773
     */
774
    public static function addEvent(
775
        $event_type,
776
        $event_value_type,
777
        $event_value,
778
        $datetime = null,
779
        $user_id = null,
780
        $course_id = null,
781
        $sessionId = 0
782
    ) {
783
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
784
785
        if (empty($event_type)) {
786
            return false;
787
        }
788
        $event_type = Database::escape_string($event_type);
789
        $event_value_type = Database::escape_string($event_value_type);
790
        if (!empty($course_id)) {
791
            $course_id = (int) $course_id;
792
        } else {
793
            $course_id = api_get_course_int_id();
794
        }
795
        if (!empty($sessionId)) {
796
            $sessionId = (int) $sessionId;
797
        } else {
798
            $sessionId = api_get_session_id();
799
        }
800
801
        //Clean the user_info
802
        if ($event_value_type == LOG_USER_OBJECT) {
803
            if (is_array($event_value)) {
804
                unset($event_value['complete_name']);
805
                unset($event_value['complete_name_with_username']);
806
                unset($event_value['firstName']);
807
                unset($event_value['lastName']);
808
                unset($event_value['avatar_small']);
809
                unset($event_value['avatar']);
810
                unset($event_value['mail']);
811
                unset($event_value['password']);
812
                unset($event_value['last_login']);
813
                unset($event_value['picture_uri']);
814
                $event_value = serialize($event_value);
815
            }
816
        }
817
        // If event is an array then the $event_value_type should finish with
818
        // the suffix _array for example LOG_WORK_DATA = work_data_array
819
        if (is_array($event_value)) {
820
            $event_value = serialize($event_value);
821
        }
822
823
        $event_value = Database::escape_string($event_value);
824
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
825
826
        if (!isset($datetime)) {
827
            $datetime = api_get_utc_datetime();
828
        }
829
830
        $datetime = Database::escape_string($datetime);
831
832
        if (!isset($user_id)) {
833
            $user_id = api_get_user_id();
834
        }
835
836
        $params = [
837
            'default_user_id' => $user_id,
838
            'c_id' => $course_id,
839
            'default_date' => $datetime,
840
            'default_event_type' => $event_type,
841
            'default_value_type' => $event_value_type,
842
            'default_value' => $event_value,
843
            'session_id' => $sessionId,
844
        ];
845
        Database::insert($table, $params);
846
847
        return true;
848
    }
849
850
    /**
851
     * Gets the last attempt of an exercise based in the exe_id.
852
     *
853
     * @param int $exeId
854
     *
855
     * @return mixed
856
     */
857
    public static function getLastAttemptDateOfExercise($exeId)
858
    {
859
        $exeId = (int) $exeId;
860
        $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
861
        $sql = "SELECT max(tms) as last_attempt_date
862
                FROM $track_attempts
863
                WHERE exe_id = $exeId";
864
        $rs_last_attempt = Database::query($sql);
865
        $row_last_attempt = Database::fetch_array($rs_last_attempt);
866
        $date = $row_last_attempt['last_attempt_date']; //Get the date of last attempt
867
868
        return $date;
869
    }
870
871
    /**
872
     * Gets the last attempt of an exercise based in the exe_id.
873
     *
874
     * @param int $exeId
875
     *
876
     * @return mixed
877
     */
878
    public static function getLatestQuestionIdFromAttempt($exeId)
879
    {
880
        $exeId = (int) $exeId;
881
        $track_attempts = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
882
        $sql = "SELECT question_id FROM $track_attempts
883
                WHERE exe_id = $exeId
884
                ORDER BY tms DESC
885
                LIMIT 1";
886
        $result = Database::query($sql);
887
        if (Database::num_rows($result)) {
888
            $row = Database::fetch_array($result);
889
890
            return $row['question_id'];
891
        } else {
892
            return false;
893
        }
894
    }
895
896
    /**
897
     * Gets how many attempts exists by user, exercise, learning path.
898
     *
899
     * @param   int user id
900
     * @param   int exercise id
901
     * @param   int lp id
902
     * @param   int lp item id
903
     * @param   int lp item view id
904
     *
905
     * @return int
906
     */
907
    public static function get_attempt_count(
908
        $user_id,
909
        $exerciseId,
910
        $lp_id,
911
        $lp_item_id,
912
        $lp_item_view_id
913
    ) {
914
        $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
915
        $user_id = (int) $user_id;
916
        $exerciseId = (int) $exerciseId;
917
        $lp_id = (int) $lp_id;
918
        $lp_item_id = (int) $lp_item_id;
919
        $lp_item_view_id = (int) $lp_item_view_id;
920
        $courseId = api_get_course_int_id();
921
        $sessionId = api_get_session_id();
922
923
        $sql = "SELECT count(*) as count
924
                FROM $stat_table
925
                WHERE
926
                    exe_exo_id = $exerciseId AND
927
                    exe_user_id = $user_id AND
928
                    status != 'incomplete' AND
929
                    orig_lp_id = $lp_id AND
930
                    orig_lp_item_id = $lp_item_id AND
931
                    orig_lp_item_view_id = $lp_item_view_id AND
932
                    c_id = $courseId AND
933
                    session_id = $sessionId";
934
935
        $query = Database::query($sql);
936
        if (Database::num_rows($query) > 0) {
937
            $attempt = Database::fetch_array($query, 'ASSOC');
938
939
            return $attempt['count'];
940
        } else {
941
            return 0;
942
        }
943
    }
944
945
    /**
946
     * @param $user_id
947
     * @param $exerciseId
948
     * @param $lp_id
949
     * @param $lp_item_id
950
     *
951
     * @return int
952
     */
953
    public static function get_attempt_count_not_finished(
954
        $user_id,
955
        $exerciseId,
956
        $lp_id,
957
        $lp_item_id
958
    ) {
959
        $stat_table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
960
        $user_id = (int) $user_id;
961
        $exerciseId = (int) $exerciseId;
962
        $lp_id = (int) $lp_id;
963
        $lp_item_id = (int) $lp_item_id;
964
        //$lp_item_view_id = (int) $lp_item_view_id;
965
        $courseId = api_get_course_int_id();
966
        $sessionId = api_get_session_id();
967
968
        $sql = "SELECT count(*) as count
969
                FROM $stat_table
970
                WHERE
971
                    exe_exo_id 			= $exerciseId AND
972
                    exe_user_id 		= $user_id AND
973
                    status 				!= 'incomplete' AND
974
                    orig_lp_id 			= $lp_id AND
975
                    orig_lp_item_id 	= $lp_item_id AND
976
                    c_id = $courseId AND
977
                    session_id = $sessionId";
978
979
        $query = Database::query($sql);
980
        if (Database::num_rows($query) > 0) {
981
            $attempt = Database::fetch_array($query, 'ASSOC');
982
983
            return $attempt['count'];
984
        } else {
985
            return 0;
986
        }
987
    }
988
989
    /**
990
     * @param int   $user_id
991
     * @param int   $lp_id
992
     * @param array $course
993
     * @param int   $session_id
994
     */
995
    public static function delete_student_lp_events(
996
        $user_id,
997
        $lp_id,
998
        $course,
999
        $session_id
1000
    ) {
1001
        $lp_view_table = Database::get_course_table(TABLE_LP_VIEW);
1002
        $lp_item_view_table = Database::get_course_table(TABLE_LP_ITEM_VIEW);
1003
        $lpInteraction = Database::get_course_table(TABLE_LP_IV_INTERACTION);
1004
        $lpObjective = Database::get_course_table(TABLE_LP_IV_OBJECTIVE);
1005
1006
        $course_id = $course['real_id'];
1007
1008
        if (empty($course_id)) {
1009
            $course_id = api_get_course_int_id();
1010
        }
1011
1012
        $track_e_exercises = Database::get_main_table(
1013
            TABLE_STATISTIC_TRACK_E_EXERCISES
1014
        );
1015
        $track_attempts = Database::get_main_table(
1016
            TABLE_STATISTIC_TRACK_E_ATTEMPT
1017
        );
1018
        $recording_table = Database::get_main_table(
1019
            TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING
1020
        );
1021
1022
        $user_id = (int) $user_id;
1023
        $lp_id = (int) $lp_id;
1024
        $session_id = (int) $session_id;
1025
1026
        //Make sure we have the exact lp_view_id
1027
        $sql = "SELECT id FROM $lp_view_table
1028
                WHERE
1029
                    c_id = $course_id AND
1030
                    user_id = $user_id AND
1031
                    lp_id = $lp_id AND
1032
                    session_id = $session_id";
1033
        $result = Database::query($sql);
1034
1035
        if (Database::num_rows($result)) {
1036
            $view = Database::fetch_array($result, 'ASSOC');
1037
            $lp_view_id = $view['id'];
1038
1039
            $sql = "DELETE FROM $lp_item_view_table
1040
                    WHERE c_id = $course_id AND lp_view_id = $lp_view_id";
1041
            Database::query($sql);
1042
1043
            $sql = "DELETE FROM $lpInteraction
1044
                    WHERE c_id = $course_id AND lp_iv_id = $lp_view_id";
1045
            Database::query($sql);
1046
1047
            $sql = "DELETE FROM $lpObjective
1048
                    WHERE c_id = $course_id AND lp_iv_id = $lp_view_id";
1049
            Database::query($sql);
1050
        }
1051
1052
        $sql = "DELETE FROM $lp_view_table
1053
                WHERE
1054
                    c_id = $course_id AND
1055
                    user_id = $user_id AND
1056
                    lp_id= $lp_id AND
1057
                    session_id = $session_id
1058
            ";
1059
        Database::query($sql);
1060
1061
        $sql = "SELECT exe_id FROM $track_e_exercises
1062
                WHERE   
1063
                    exe_user_id = $user_id AND
1064
                    session_id = $session_id AND
1065
                    c_id = $course_id AND
1066
                    orig_lp_id = $lp_id";
1067
        $result = Database::query($sql);
1068
        $exe_list = [];
1069
        while ($row = Database::fetch_array($result, 'ASSOC')) {
1070
            $exe_list[] = $row['exe_id'];
1071
        }
1072
1073
        if (!empty($exe_list) && is_array($exe_list) && count($exe_list) > 0) {
1074
            $exeListString = implode(',', $exe_list);
1075
            $sql = "DELETE FROM $track_e_exercises
1076
                WHERE exe_id IN ($exeListString)";
1077
            Database::query($sql);
1078
1079
            $sql = "DELETE FROM $track_attempts
1080
                WHERE exe_id IN ($exeListString)";
1081
            Database::query($sql);
1082
1083
            $sql = "DELETE FROM $recording_table
1084
                WHERE exe_id IN ($exeListString)";
1085
            Database::query($sql);
1086
        }
1087
1088
        self::addEvent(
1089
            LOG_LP_ATTEMPT_DELETE,
1090
            LOG_LP_ID,
1091
            $lp_id,
1092
            null,
1093
            null,
1094
            $course_id,
1095
            $session_id
1096
        );
1097
    }
1098
1099
    /**
1100
     * Delete all exercise attempts (included in LP or not).
1101
     *
1102
     * @param int user id
1103
     * @param int exercise id
1104
     * @param int $course_id
1105
     * @param int session id
1106
     */
1107
    public static function delete_all_incomplete_attempts(
1108
        $user_id,
1109
        $exercise_id,
1110
        $course_id,
1111
        $session_id = 0
1112
    ) {
1113
        $track_e_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1114
        $user_id = (int) $user_id;
1115
        $exercise_id = (int) $exercise_id;
1116
        $course_id = (int) $course_id;
1117
        $session_id = (int) $session_id;
1118
        if (!empty($user_id) && !empty($exercise_id) && !empty($course_code)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $course_code does not exist. Did you maybe mean $course_id?
Loading history...
1119
            $sql = "DELETE FROM $track_e_exercises
1120
                    WHERE
1121
                        exe_user_id = $user_id AND
1122
                        exe_exo_id = $exercise_id AND
1123
                        c_id = $course_id AND
1124
                        session_id = $session_id AND
1125
                        status = 'incomplete' ";
1126
            Database::query($sql);
1127
            self::addEvent(
1128
                LOG_EXERCISE_RESULT_DELETE,
1129
                LOG_EXERCISE_AND_USER_ID,
1130
                $exercise_id.'-'.$user_id,
1131
                null,
1132
                null,
1133
                $course_id,
1134
                $session_id
1135
            );
1136
        }
1137
    }
1138
1139
    /**
1140
     * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session.
1141
     *
1142
     * @param   int     exercise id
1143
     * @param int $courseId
1144
     * @param   int     session id
1145
     *
1146
     * @return array with the results
1147
     */
1148
    public static function get_all_exercise_results(
1149
        $exercise_id,
1150
        $courseId,
1151
        $session_id = 0,
1152
        $load_question_list = true,
1153
        $user_id = null
1154
    ) {
1155
        $TABLETRACK_EXERCICES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1156
        $TBL_TRACK_ATTEMPT = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1157
        $courseId = (int) $courseId;
1158
        $exercise_id = (int) $exercise_id;
1159
        $session_id = (int) $session_id;
1160
1161
        $user_condition = null;
1162
        if (!empty($user_id)) {
1163
            $user_id = (int) $user_id;
1164
            $user_condition = "AND exe_user_id = $user_id ";
1165
        }
1166
        $sql = "SELECT * FROM $TABLETRACK_EXERCICES
1167
                WHERE
1168
                    status = ''  AND
1169
                    c_id = $courseId AND
1170
                    exe_exo_id = $exercise_id AND
1171
                    session_id = $session_id  AND
1172
                    orig_lp_id =0 AND
1173
                    orig_lp_item_id = 0
1174
                    $user_condition
1175
                ORDER BY exe_id";
1176
        $res = Database::query($sql);
1177
        $list = [];
1178
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1179
            $list[$row['exe_id']] = $row;
1180
            if ($load_question_list) {
1181
                $sql = "SELECT * FROM $TBL_TRACK_ATTEMPT
1182
                        WHERE exe_id = {$row['exe_id']}";
1183
                $res_question = Database::query($sql);
1184
                while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1185
                    $list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q;
1186
                }
1187
            }
1188
        }
1189
1190
        return $list;
1191
    }
1192
1193
    /**
1194
     * Gets all exercise results (NO Exercises in LPs ) from a given exercise id, course, session.
1195
     *
1196
     * @param int $courseId
1197
     * @param   int     session id
1198
     * @param bool $get_count
1199
     *
1200
     * @return array with the results
1201
     */
1202
    public static function get_all_exercise_results_by_course(
1203
        $courseId,
1204
        $session_id = 0,
1205
        $get_count = true
1206
    ) {
1207
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1208
        $courseId = (int) $courseId;
1209
        $session_id = (int) $session_id;
1210
1211
        $select = '*';
1212
        if ($get_count) {
1213
            $select = 'count(*) as count';
1214
        }
1215
        $sql = "SELECT $select FROM $table_track_exercises
1216
                WHERE   status = ''  AND
1217
                        c_id = $courseId AND
1218
                        session_id = $session_id  AND
1219
                        orig_lp_id = 0 AND
1220
                        orig_lp_item_id = 0
1221
                ORDER BY exe_id";
1222
        $res = Database::query($sql);
1223
        if ($get_count) {
1224
            $row = Database::fetch_array($res, 'ASSOC');
1225
1226
            return $row['count'];
1227
        } else {
1228
            $list = [];
1229
            while ($row = Database::fetch_array($res, 'ASSOC')) {
1230
                $list[$row['exe_id']] = $row;
1231
            }
1232
1233
            return $list;
1234
        }
1235
    }
1236
1237
    /**
1238
     * Gets all exercise results (NO Exercises in LPs) from a given exercise id, course, session.
1239
     *
1240
     * @param   int     exercise id
1241
     * @param int $courseId
1242
     * @param   int     session id
1243
     *
1244
     * @return array with the results
1245
     */
1246
    public static function get_all_exercise_results_by_user(
1247
        $user_id,
1248
        $courseId,
1249
        $session_id = 0
1250
    ) {
1251
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1252
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1253
        $courseId = (int) $courseId;
1254
        $session_id = (int) $session_id;
1255
        $user_id = (int) $user_id;
1256
1257
        $sql = "SELECT * FROM $table_track_exercises
1258
                WHERE
1259
                    status = '' AND
1260
                    exe_user_id = $user_id AND
1261
                    c_id = $courseId AND
1262
                    session_id = $session_id AND
1263
                    orig_lp_id = 0 AND
1264
                    orig_lp_item_id = 0
1265
                ORDER by exe_id";
1266
1267
        $res = Database::query($sql);
1268
        $list = [];
1269
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1270
            $list[$row['exe_id']] = $row;
1271
            $sql = "SELECT * FROM $table_track_attempt 
1272
                    WHERE exe_id = {$row['exe_id']}";
1273
            $res_question = Database::query($sql);
1274
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1275
                $list[$row['exe_id']]['question_list'][$row_q['question_id']] = $row_q;
1276
            }
1277
        }
1278
1279
        return $list;
1280
    }
1281
1282
    /**
1283
     * Gets exercise results (NO Exercises in LPs) from a given exercise id, course, session.
1284
     *
1285
     * @param int    $exe_id exercise id
1286
     * @param string $status
1287
     *
1288
     * @return array with the results
1289
     */
1290
    public static function get_exercise_results_by_attempt($exe_id, $status = null)
1291
    {
1292
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1293
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1294
        $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
1295
        $exe_id = (int) $exe_id;
1296
1297
        $status = Database::escape_string($status);
1298
1299
        $sql = "SELECT * FROM $table_track_exercises
1300
                WHERE status = '$status' AND exe_id = $exe_id";
1301
1302
        $res = Database::query($sql);
1303
        $list = [];
1304
        if (Database::num_rows($res)) {
1305
            $row = Database::fetch_array($res, 'ASSOC');
1306
1307
            //Checking if this attempt was revised by a teacher
1308
            $sql_revised = "SELECT exe_id FROM $table_track_attempt_recording
1309
                            WHERE author != '' AND exe_id = $exe_id 
1310
                            LIMIT 1";
1311
            $res_revised = Database::query($sql_revised);
1312
            $row['attempt_revised'] = 0;
1313
            if (Database::num_rows($res_revised) > 0) {
1314
                $row['attempt_revised'] = 1;
1315
            }
1316
            $list[$exe_id] = $row;
1317
            $sql = "SELECT * FROM $table_track_attempt
1318
                    WHERE exe_id = $exe_id 
1319
                    ORDER BY tms ASC";
1320
            $res_question = Database::query($sql);
1321
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1322
                $list[$exe_id]['question_list'][$row_q['question_id']] = $row_q;
1323
            }
1324
        }
1325
1326
        return $list;
1327
    }
1328
1329
    /**
1330
     * Gets exercise results (NO Exercises in LPs) from a given user, exercise id, course, session, lp_id, lp_item_id.
1331
     *
1332
     * @param   int     user id
1333
     * @param   int     exercise id
1334
     * @param   string  course code
1335
     * @param   int     session id
1336
     * @param   int     lp id
1337
     * @param   int     lp item id
1338
     * @param   string order asc or desc
1339
     *
1340
     * @return array with the results
1341
     */
1342
    public static function getExerciseResultsByUser(
1343
        $user_id,
1344
        $exercise_id,
1345
        $courseId,
1346
        $session_id = 0,
1347
        $lp_id = 0,
1348
        $lp_item_id = 0,
1349
        $order = null
1350
    ) {
1351
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1352
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1353
        $table_track_attempt_recording = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
1354
        $courseId = (int) $courseId;
1355
        $exercise_id = (int) $exercise_id;
1356
        $session_id = (int) $session_id;
1357
        $user_id = (int) $user_id;
1358
        $lp_id = (int) $lp_id;
1359
        $lp_item_id = (int) $lp_item_id;
1360
1361
        if (!in_array(strtolower($order), ['asc', 'desc'])) {
1362
            $order = 'asc';
1363
        }
1364
1365
        $sql = "SELECT * FROM $table_track_exercises
1366
                WHERE
1367
                    status 			= '' AND
1368
                    exe_user_id 	= $user_id AND
1369
                    c_id 	        = $courseId AND
1370
                    exe_exo_id 		= $exercise_id AND
1371
                    session_id 		= $session_id AND
1372
                    orig_lp_id 		= $lp_id AND
1373
                    orig_lp_item_id = $lp_item_id
1374
                ORDER by exe_id $order ";
1375
1376
        $res = Database::query($sql);
1377
        $list = [];
1378
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1379
            // Checking if this attempt was revised by a teacher
1380
            $exeId = $row['exe_id'];
1381
            $sql = "SELECT exe_id FROM $table_track_attempt_recording
1382
                    WHERE author != '' AND exe_id = $exeId
1383
                    LIMIT 1";
1384
            $res_revised = Database::query($sql);
1385
            $row['attempt_revised'] = 0;
1386
            if (Database::num_rows($res_revised) > 0) {
1387
                $row['attempt_revised'] = 1;
1388
            }
1389
            $list[$row['exe_id']] = $row;
1390
            $sql = "SELECT * FROM $table_track_attempt
1391
                    WHERE exe_id = $exeId";
1392
            $res_question = Database::query($sql);
1393
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1394
                $list[$row['exe_id']]['question_list'][$row_q['question_id']][] = $row_q;
1395
            }
1396
        }
1397
1398
        return $list;
1399
    }
1400
1401
    /**
1402
     * Count exercise attempts (NO Exercises in LPs ) from a given exercise id, course, session.
1403
     *
1404
     * @param int $user_id
1405
     * @param   int     exercise id
1406
     * @param int $courseId
1407
     * @param   int     session id
1408
     *
1409
     * @return array with the results
1410
     */
1411
    public static function count_exercise_attempts_by_user(
1412
        $user_id,
1413
        $exercise_id,
1414
        $courseId,
1415
        $session_id = 0
1416
    ) {
1417
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1418
        $courseId = (int) $courseId;
1419
        $exercise_id = (int) $exercise_id;
1420
        $session_id = (int) $session_id;
1421
        $user_id = (int) $user_id;
1422
1423
        $sql = "SELECT count(*) as count 
1424
                FROM $table
1425
                WHERE status = ''  AND
1426
                    exe_user_id = $user_id AND
1427
                    c_id = $courseId AND
1428
                    exe_exo_id = $exercise_id AND
1429
                    session_id = $session_id AND
1430
                    orig_lp_id =0 AND
1431
                    orig_lp_item_id = 0
1432
                ORDER BY exe_id";
1433
        $res = Database::query($sql);
1434
        $result = 0;
1435
        if (Database::num_rows($res) > 0) {
1436
            $row = Database::fetch_array($res, 'ASSOC');
1437
            $result = $row['count'];
1438
        }
1439
1440
        return $result;
1441
    }
1442
1443
    /**
1444
     * Gets all exercise BEST results attempts (NO Exercises in LPs)
1445
     * from a given exercise id, course, session per user.
1446
     *
1447
     * @param int $exercise_id
1448
     * @param int $courseId
1449
     * @param int $session_id
1450
     * @param int $userId
1451
     *
1452
     * @return array with the results
1453
     *
1454
     * @todo rename this function
1455
     */
1456
    public static function get_best_exercise_results_by_user(
1457
        $exercise_id,
1458
        $courseId,
1459
        $session_id = 0,
1460
        $userId = 0
1461
    ) {
1462
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1463
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1464
        $courseId = (int) $courseId;
1465
        $exercise_id = (int) $exercise_id;
1466
        $session_id = (int) $session_id;
1467
1468
        $sql = "SELECT * FROM $table_track_exercises
1469
                WHERE
1470
                    status = '' AND
1471
                    c_id = $courseId AND
1472
                    exe_exo_id = $exercise_id AND
1473
                    session_id = $session_id AND
1474
                    orig_lp_id = 0 AND
1475
                    orig_lp_item_id = 0";
1476
1477
        if (!empty($userId)) {
1478
            $userId = (int) $userId;
1479
            $sql .= " AND exe_user_id = $userId ";
1480
        }
1481
        $sql .= " ORDER BY exe_id";
1482
1483
        $res = Database::query($sql);
1484
        $list = [];
1485
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1486
            $list[$row['exe_id']] = $row;
1487
            $exeId = $row['exe_id'];
1488
            $sql = "SELECT * FROM $table_track_attempt 
1489
                    WHERE exe_id = $exeId";
1490
            $res_question = Database::query($sql);
1491
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1492
                $list[$exeId]['question_list'][$row_q['question_id']] = $row_q;
1493
            }
1494
        }
1495
1496
        // Getting the best results of every student
1497
        $best_score_return = [];
1498
        foreach ($list as $student_result) {
1499
            $user_id = $student_result['exe_user_id'];
1500
            $current_best_score[$user_id] = $student_result['exe_result'];
1501
1502
            //echo $current_best_score[$user_id].' - '.$best_score_return[$user_id]['exe_result'].'<br />';
1503
            if (!isset($best_score_return[$user_id]['exe_result'])) {
1504
                $best_score_return[$user_id] = $student_result;
1505
            }
1506
1507
            if ($current_best_score[$user_id] > $best_score_return[$user_id]['exe_result']) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $current_best_score seems to be defined later in this foreach loop on line 1500. Are you sure it is defined here?
Loading history...
1508
                $best_score_return[$user_id] = $student_result;
1509
            }
1510
        }
1511
1512
        return $best_score_return;
1513
    }
1514
1515
    /**
1516
     * @param int $user_id
1517
     * @param int $exercise_id
1518
     * @param int $courseId
1519
     * @param int $session_id
1520
     *
1521
     * @return array
1522
     */
1523
    public static function get_best_attempt_exercise_results_per_user(
1524
        $user_id,
1525
        $exercise_id,
1526
        $courseId,
1527
        $session_id = 0
1528
    ) {
1529
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1530
        $courseId = (int) $courseId;
1531
        $exercise_id = (int) $exercise_id;
1532
        $session_id = (int) $session_id;
1533
        $user_id = (int) $user_id;
1534
1535
        $sql = "SELECT * FROM $table_track_exercises
1536
                WHERE
1537
                    status = ''  AND
1538
                    c_id = $courseId AND
1539
                    exe_exo_id = $exercise_id AND
1540
                    session_id = $session_id  AND
1541
                    exe_user_id = $user_id AND
1542
                    orig_lp_id = 0 AND
1543
                    orig_lp_item_id = 0
1544
                ORDER BY exe_id";
1545
1546
        $res = Database::query($sql);
1547
        $list = [];
1548
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1549
            $list[$row['exe_id']] = $row;
1550
        }
1551
        //Getting the best results of every student
1552
        $best_score_return = [];
1553
        $best_score_return['exe_result'] = 0;
1554
1555
        foreach ($list as $result) {
1556
            $current_best_score = $result;
1557
            if ($current_best_score['exe_result'] > $best_score_return['exe_result']) {
1558
                $best_score_return = $result;
1559
            }
1560
        }
1561
        if (!isset($best_score_return['exe_weighting'])) {
1562
            $best_score_return = [];
1563
        }
1564
1565
        return $best_score_return;
1566
    }
1567
1568
    /**
1569
     * @param int $exercise_id
1570
     * @param int $courseId
1571
     * @param int $session_id
1572
     *
1573
     * @return mixed
1574
     */
1575
    public static function count_exercise_result_not_validated(
1576
        $exercise_id,
1577
        $courseId,
1578
        $session_id = 0
1579
    ) {
1580
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1581
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT_RECORDING);
1582
        $courseId = (int) $courseId;
1583
        $session_id = (int) $session_id;
1584
        $exercise_id = (int) $exercise_id;
1585
1586
        $sql = "SELECT count(e.exe_id) as count
1587
                FROM $table_track_exercises e
1588
                LEFT JOIN $table_track_attempt a
1589
                ON e.exe_id = a.exe_id
1590
                WHERE
1591
                    exe_exo_id = $exercise_id AND
1592
                    c_id = $courseId AND
1593
                    e.session_id = $session_id  AND
1594
                    orig_lp_id = 0 AND
1595
                    marks IS NULL AND
1596
                    status = '' AND
1597
                    orig_lp_item_id = 0
1598
                ORDER BY e.exe_id";
1599
        $res = Database::query($sql);
1600
        $row = Database::fetch_array($res, 'ASSOC');
1601
1602
        return $row['count'];
1603
    }
1604
1605
    /**
1606
     * Gets all exercise BEST results attempts (NO Exercises in LPs)
1607
     * from a given exercise id, course, session per user.
1608
     *
1609
     * @param   int     exercise id
1610
     * @param   int   course id
1611
     * @param   int     session id
1612
     *
1613
     * @return array with the results
1614
     */
1615
    public static function get_count_exercises_attempted_by_course(
1616
        $courseId,
1617
        $session_id = 0
1618
    ) {
1619
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1620
        $courseId = (int) $courseId;
1621
        $session_id = (int) $session_id;
1622
1623
        $sql = "SELECT DISTINCT exe_exo_id, exe_user_id
1624
                FROM $table_track_exercises
1625
                WHERE
1626
                    status = '' AND
1627
                    c_id = $courseId AND
1628
                    session_id = $session_id AND
1629
                    orig_lp_id = 0 AND
1630
                    orig_lp_item_id = 0
1631
                ORDER BY exe_id";
1632
        $res = Database::query($sql);
1633
        $count = 0;
1634
        if (Database::num_rows($res) > 0) {
1635
            $count = Database::num_rows($res);
1636
        }
1637
1638
        return $count;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $count returns the type integer which is incompatible with the documented return type array.
Loading history...
1639
    }
1640
1641
    /**
1642
     * Gets all exercise events from a Learning Path within a Course    nd Session.
1643
     *
1644
     * @param int $exercise_id
1645
     * @param int $courseId
1646
     * @param int $session_id
1647
     *
1648
     * @return array
1649
     */
1650
    public static function get_all_exercise_event_from_lp(
1651
        $exercise_id,
1652
        $courseId,
1653
        $session_id = 0
1654
    ) {
1655
        $table_track_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
1656
        $table_track_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1657
        $courseId = (int) $courseId;
1658
        $exercise_id = (int) $exercise_id;
1659
        $session_id = (int) $session_id;
1660
1661
        $sql = "SELECT * FROM $table_track_exercises
1662
                WHERE
1663
                    status = '' AND
1664
                    c_id = $courseId AND
1665
                    exe_exo_id = $exercise_id AND
1666
                    session_id = $session_id AND
1667
                    orig_lp_id !=0 AND
1668
                    orig_lp_item_id != 0";
1669
1670
        $res = Database::query($sql);
1671
        $list = [];
1672
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1673
            $exeId = $row['exe_id'];
1674
            $list[$exeId] = $row;
1675
            $sql = "SELECT * FROM $table_track_attempt 
1676
                    WHERE exe_id = $exeId";
1677
            $res_question = Database::query($sql);
1678
            while ($row_q = Database::fetch_array($res_question, 'ASSOC')) {
1679
                $list[$exeId]['question_list'][$row_q['question_id']] = $row_q;
1680
            }
1681
        }
1682
1683
        return $list;
1684
    }
1685
1686
    /**
1687
     * Get a list of all the exercises in a given learning path.
1688
     *
1689
     * @param int $lp_id
1690
     * @param int $course_id This parameter is probably deprecated as lp_id now is a global iid
1691
     *
1692
     * @return array
1693
     */
1694
    public static function get_all_exercises_from_lp($lp_id, $course_id)
1695
    {
1696
        $lp_item_table = Database::get_course_table(TABLE_LP_ITEM);
1697
        $course_id = (int) $course_id;
1698
        $lp_id = (int) $lp_id;
1699
        $sql = "SELECT * FROM $lp_item_table
1700
                WHERE
1701
                    c_id = $course_id AND
1702
                    lp_id = $lp_id AND
1703
                    item_type = 'quiz'
1704
                ORDER BY parent_item_id, display_order";
1705
        $res = Database::query($sql);
1706
1707
        $my_exercise_list = [];
1708
        while ($row = Database::fetch_array($res, 'ASSOC')) {
1709
            $my_exercise_list[] = $row;
1710
        }
1711
1712
        return $my_exercise_list;
1713
    }
1714
1715
    /**
1716
     * This function gets the comments of an exercise.
1717
     *
1718
     * @param int $exe_id
1719
     * @param int $question_id
1720
     *
1721
     * @return string the comment
1722
     */
1723
    public static function get_comments($exe_id, $question_id)
1724
    {
1725
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1726
        $exe_id = (int) $exe_id;
1727
        $question_id = (int) $question_id;
1728
        $sql = "SELECT teacher_comment 
1729
                FROM $table
1730
                WHERE
1731
                    exe_id = $exe_id AND
1732
                    question_id = $question_id
1733
                ORDER by question_id";
1734
        $sqlres = Database::query($sql);
1735
        $comm = strval(Database::result($sqlres, 0, 'teacher_comment'));
1736
        $comm = trim($comm);
1737
1738
        return $comm;
1739
    }
1740
1741
    /**
1742
     * @param int $exeId
1743
     *
1744
     * @return array
1745
     */
1746
    public static function getAllExerciseEventByExeId($exeId)
1747
    {
1748
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1749
        $exeId = (int) $exeId;
1750
1751
        $sql = "SELECT * FROM $table
1752
                WHERE exe_id = $exeId
1753
                ORDER BY position";
1754
        $res_question = Database::query($sql);
1755
        $list = [];
1756
        if (Database::num_rows($res_question)) {
1757
            while ($row = Database::fetch_array($res_question, 'ASSOC')) {
1758
                $list[$row['question_id']][] = $row;
1759
            }
1760
        }
1761
1762
        return $list;
1763
    }
1764
1765
    /**
1766
     * @param int $exeId
1767
     * @param int $user_id
1768
     * @param int $courseId
1769
     * @param int $session_id
1770
     * @param int $question_id
1771
     */
1772
    public static function delete_attempt(
1773
        $exeId,
1774
        $user_id,
1775
        $courseId,
1776
        $session_id,
1777
        $question_id
1778
    ) {
1779
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
1780
1781
        $exeId = (int) $exeId;
1782
        $user_id = (int) $user_id;
1783
        $courseId = (int) $courseId;
1784
        $session_id = (int) $session_id;
1785
        $question_id = (int) $question_id;
1786
1787
        $sql = "DELETE FROM $table
1788
                WHERE
1789
                    exe_id = $exeId AND
1790
                    user_id = $user_id AND
1791
                    c_id = $courseId AND
1792
                    session_id = $session_id AND
1793
                    question_id = $question_id ";
1794
        Database::query($sql);
1795
1796
        self::addEvent(
1797
            LOG_QUESTION_RESULT_DELETE,
1798
            LOG_EXERCISE_ATTEMPT_QUESTION_ID,
1799
            $exeId.'-'.$question_id,
1800
            null,
1801
            null,
1802
            $courseId,
1803
            $session_id
1804
        );
1805
    }
1806
1807
    /**
1808
     * @param $exeId
1809
     * @param $user_id
1810
     * @param int $courseId
1811
     * @param $question_id
1812
     * @param int $sessionId
1813
     */
1814
    public static function delete_attempt_hotspot(
1815
        $exeId,
1816
        $user_id,
1817
        $courseId,
1818
        $question_id,
1819
        $sessionId = null
1820
    ) {
1821
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTSPOT);
1822
1823
        $exeId = (int) $exeId;
1824
        $user_id = (int) $user_id;
1825
        $courseId = (int) $courseId;
1826
        $question_id = (int) $question_id;
1827
        if (!isset($sessionId)) {
1828
            $sessionId = api_get_session_id();
1829
        }
1830
1831
        $sql = "DELETE FROM $table
1832
                WHERE   
1833
                    hotspot_exe_id = $exeId AND
1834
                    hotspot_user_id = $user_id AND
1835
                    c_id = $courseId AND
1836
                    hotspot_question_id = $question_id ";
1837
        Database::query($sql);
1838
        self::addEvent(
1839
            LOG_QUESTION_RESULT_DELETE,
1840
            LOG_EXERCISE_ATTEMPT_QUESTION_ID,
1841
            $exeId.'-'.$question_id,
1842
            null,
1843
            null,
1844
            $courseId,
1845
            $sessionId
1846
        );
1847
    }
1848
1849
    /**
1850
     * Registers in track_e_course_access when user logs in for the first time to a course.
1851
     *
1852
     * @param int $courseId  ID of the course
1853
     * @param int $user_id   ID of the user
1854
     * @param int $sessionId ID of the session (if any)
1855
     *
1856
     * @return bool
1857
     */
1858
    public static function eventCourseLogin($courseId, $user_id, $sessionId)
1859
    {
1860
        if (Session::read('login_as')) {
1861
            return false;
1862
        }
1863
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1864
        $loginDate = $logoutDate = api_get_utc_datetime();
1865
1866
        // $counter represents the number of time this record has been refreshed
1867
        $counter = 1;
1868
        $courseId = (int) $courseId;
1869
        $user_id = (int) $user_id;
1870
        $sessionId = (int) $sessionId;
1871
        $ip = Database::escape_string(api_get_real_ip());
1872
1873
        $sql = "INSERT INTO $table(c_id, user_ip, user_id, login_course_date, logout_course_date, counter, session_id)
1874
                VALUES($courseId, '$ip', $user_id, '$loginDate', '$logoutDate', $counter, $sessionId)";
1875
        $courseAccessId = Database::query($sql);
1876
1877
        if ($courseAccessId) {
0 ignored issues
show
introduced by
$courseAccessId is of type Doctrine\DBAL\Driver\Statement, thus it always evaluated to true.
Loading history...
1878
            // Course catalog stats modifications see #4191
1879
            CourseManager::update_course_ranking(
1880
                null,
1881
                null,
1882
                null,
1883
                null,
1884
                true,
1885
                false
1886
            );
1887
1888
            return true;
1889
        }
1890
    }
1891
1892
    /**
1893
     * Updates the user - course - session every X minutes
1894
     * In order to avoid.
1895
     *
1896
     * @param int $courseId
1897
     * @param int $userId
1898
     * @param int $sessionId
1899
     * @param int $minutes
1900
     *
1901
     * @return bool
1902
     */
1903
    public static function eventCourseLoginUpdate(
1904
        $courseId,
1905
        $userId,
1906
        $sessionId,
1907
        $minutes = 5
1908
    ) {
1909
        if (Session::read('login_as')) {
1910
            return false;
1911
        }
1912
1913
        if (empty($courseId) || empty($userId)) {
1914
            return false;
1915
        }
1916
1917
        $courseId = (int) $courseId;
1918
        $userId = (int) $userId;
1919
        $sessionId = (int) $sessionId;
1920
1921
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1922
        $sql = "SELECT course_access_id, logout_course_date 
1923
                FROM $table 
1924
                WHERE 
1925
                    c_id = $courseId AND
1926
                    session_id = $sessionId AND   
1927
                    user_id = $userId                     
1928
                ORDER BY login_course_date DESC
1929
                LIMIT 1";
1930
1931
        $result = Database::query($sql);
1932
1933
        // Save every 5 minutes by default
1934
        $seconds = $minutes * 60;
1935
        $maxSeconds = 3600; // Only update if max diff is one hour
1936
        if (Database::num_rows($result)) {
1937
            $row = Database::fetch_array($result);
1938
            $id = $row['course_access_id'];
1939
            $logout = $row['logout_course_date'];
1940
            $now = time();
1941
            $logout = api_strtotime($logout, 'UTC');
1942
            if ($now - $logout > $seconds &&
1943
                $now - $logout < $maxSeconds
1944
            ) {
1945
                $now = api_get_utc_datetime();
1946
                $sql = "UPDATE $table SET 
1947
                            logout_course_date = '$now', 
1948
                            counter = counter + 1
1949
                        WHERE course_access_id = $id";
1950
                Database::query($sql);
1951
            }
1952
1953
            return true;
1954
        }
1955
1956
        return false;
1957
    }
1958
1959
    /**
1960
     * Register the logout of the course (usually when logging out of the platform)
1961
     * from the track_e_course_access table.
1962
     *
1963
     * @param array $logoutInfo Information stored by local.inc.php
1964
     *                          before new context ['uid'=> x, 'cid'=>y, 'sid'=>z]
1965
     *
1966
     * @return bool
1967
     */
1968
    public static function courseLogout($logoutInfo)
1969
    {
1970
        if (Session::read('login_as')) {
1971
            return false;
1972
        }
1973
1974
        if (empty($logoutInfo['uid']) || empty($logoutInfo['cid'])) {
1975
            return false;
1976
        }
1977
1978
        $sessionLifetime = api_get_configuration_value('session_lifetime');
1979
        /*
1980
         * When $_configuration['session_lifetime'] is larger than ~100 hours
1981
         * (in order to let users take exercises with no problems)
1982
         * the function Tracking::get_time_spent_on_the_course() returns larger values (200h) due the condition:
1983
         * login_course_date > now() - INTERVAL $session_lifetime SECOND
1984
         */
1985
        if (empty($sessionLifetime) || $sessionLifetime > 86400) {
1986
            $sessionLifetime = 3600; // 1 hour
1987
        }
1988
        if (!empty($logoutInfo) && !empty($logoutInfo['cid'])) {
1989
            $tableCourseAccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
1990
            $userId = (int) $logoutInfo['uid'];
1991
            $courseId = (int) $logoutInfo['cid'];
1992
            $sessionId = 0;
1993
            if (!empty($logoutInfo['sid'])) {
1994
                $sessionId = (int) $logoutInfo['sid'];
1995
            }
1996
            $currentDate = api_get_utc_datetime();
1997
            // UTC time
1998
            $diff = time() - $sessionLifetime;
1999
            $time = api_get_utc_datetime($diff);
2000
            $sql = "SELECT course_access_id, logout_course_date
2001
                    FROM $tableCourseAccess
2002
                    WHERE 
2003
                        user_id = $userId AND
2004
                        c_id = $courseId  AND
2005
                        session_id = $sessionId AND
2006
                        login_course_date > '$time'
2007
                    ORDER BY login_course_date DESC 
2008
                    LIMIT 1";
2009
            $result = Database::query($sql);
2010
            $insert = false;
2011
            if (Database::num_rows($result) > 0) {
2012
                $row = Database::fetch_array($result, 'ASSOC');
2013
                $courseAccessId = $row['course_access_id'];
2014
                $sql = "UPDATE $tableCourseAccess SET 
2015
                                logout_course_date = '$currentDate', 
2016
                                counter = counter + 1
2017
                            WHERE course_access_id = $courseAccessId";
2018
                Database::query($sql);
2019
            } else {
2020
                $insert = true;
2021
            }
2022
2023
            if ($insert) {
2024
                $ip = Database::escape_string(api_get_real_ip());
2025
                $sql = "INSERT INTO $tableCourseAccess (c_id, user_ip, user_id, login_course_date, logout_course_date, counter, session_id)
2026
                        VALUES ($courseId, '$ip', $userId, '$currentDate', '$currentDate', 1, $sessionId)";
2027
                Database::query($sql);
2028
            }
2029
2030
            return true;
2031
        }
2032
    }
2033
2034
    /**
2035
     * Register a "fake" time spent on the platform, for example to match the
2036
     * estimated time he took to author an assignment/work, see configuration
2037
     * setting considered_working_time.
2038
     * This assumes there is already some connection of the student to the
2039
     * course, otherwise he wouldn't be able to upload an assignment.
2040
     * This works by creating a new record, copy of the current one, then
2041
     * updating the current one to be just the considered_working_time and
2042
     * end at the same second as the user connected to the course.
2043
     *
2044
     * @param int    $courseId    The course in which to add the time
2045
     * @param int    $userId      The user for whom to add the time
2046
     * @param int    $sessionId   The session in which to add the time (if any)
2047
     * @param string $virtualTime The amount of time to be added,
2048
     *                            in a hh:mm:ss format. If int, we consider it is expressed in hours.
2049
     * @param string $ip          IP address to go on record for this time record
2050
     *
2051
     * @return true on successful insertion, false otherwise
2052
     */
2053
    public static function eventAddVirtualCourseTime(
2054
        $courseId,
2055
        $userId,
2056
        $sessionId,
2057
        $virtualTime = '',
2058
        $ip = ''
2059
    ) {
2060
        $courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2061
        $time = $loginDate = $logoutDate = api_get_utc_datetime();
2062
2063
        $courseId = (int) $courseId;
2064
        $userId = (int) $userId;
2065
        $sessionId = (int) $sessionId;
2066
        $ip = Database::escape_string($ip);
2067
2068
        // Get the current latest course connection register. We need that
2069
        // record to re-use the data and create a new record.
2070
        $sql = "SELECT *
2071
                FROM $courseTrackingTable
2072
                WHERE
2073
                    user_id = $userId AND
2074
                    c_id = $courseId  AND
2075
                    session_id  = $sessionId AND
2076
                    login_course_date > '$time' - INTERVAL 3600 SECOND
2077
                ORDER BY login_course_date DESC 
2078
                LIMIT 0,1";
2079
        $result = Database::query($sql);
2080
2081
        // Ignore if we didn't find any course connection record in the last
2082
        // hour. In this case it wouldn't be right to add a "fake" time record.
2083
        if (Database::num_rows($result) > 0) {
2084
            // Found the latest connection
2085
            $row = Database::fetch_array($result);
2086
            $courseAccessId = $row['course_access_id'];
2087
            $courseAccessLoginDate = $row['login_course_date'];
2088
            $counter = $row['counter'];
2089
            $counter = $counter ? $counter : 0;
2090
            // Insert a new record, copy of the current one (except the logout
2091
            // date that we update to the current time)
2092
            $sql = "INSERT INTO $courseTrackingTable(
2093
                    c_id,
2094
                    user_ip, 
2095
                    user_id, 
2096
                    login_course_date, 
2097
                    logout_course_date, 
2098
                    counter, 
2099
                    session_id
2100
                ) VALUES(
2101
                    $courseId, 
2102
                    '$ip', 
2103
                    $userId, 
2104
                    '$courseAccessLoginDate', 
2105
                    '$logoutDate', 
2106
                    $counter, 
2107
                    $sessionId
2108
                )";
2109
            Database::query($sql);
2110
2111
            $loginDate = ChamiloApi::addOrSubTimeToDateTime(
2112
                $virtualTime,
2113
                $courseAccessLoginDate,
2114
                false
2115
            );
2116
            // We update the course tracking table
2117
            $sql = "UPDATE $courseTrackingTable  
2118
                    SET 
2119
                        login_course_date = '$loginDate',
2120
                        logout_course_date = '$courseAccessLoginDate',
2121
                        counter = 0
2122
                    WHERE 
2123
                        course_access_id = ".intval($courseAccessId)." AND 
2124
                        session_id = ".$sessionId;
2125
            Database::query($sql);
2126
2127
            return true;
2128
        }
2129
2130
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
2131
    }
2132
2133
    /**
2134
     * Removes a "fake" time spent on the platform, for example to match the
2135
     * estimated time he took to author an assignment/work, see configuration
2136
     * setting considered_working_time.
2137
     * This method should be called when something that generated a fake
2138
     * time record is removed. Given the database link is weak (no real
2139
     * relationship kept between the deleted item and this record), this
2140
     * method just looks for the latest record that has the same time as the
2141
     * item's fake time, is in the past and in this course+session. If such a
2142
     * record cannot be found, it doesn't do anything.
2143
     * The IP address is not considered a useful filter here.
2144
     *
2145
     * @param int    $courseId    The course in which to add the time
2146
     * @param int    $userId      The user for whom to add the time
2147
     * @param int    $sessionId   The session in which to add the time (if any)
2148
     * @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.
2149
     *
2150
     * @return true on successful removal, false otherwise
2151
     */
2152
    public static function eventRemoveVirtualCourseTime(
2153
        $courseId,
2154
        $userId,
2155
        $sessionId = 0,
2156
        $virtualTime = ''
2157
    ) {
2158
        if (empty($virtualTime)) {
2159
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
2160
        }
2161
        $courseTrackingTable = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2162
        $time = $loginDate = $logoutDate = api_get_utc_datetime();
2163
2164
        $courseId = (int) $courseId;
2165
        $userId = (int) $userId;
2166
        $sessionId = (int) $sessionId;
2167
        // Change $virtualTime format from hh:mm:ss to hhmmss which is the
2168
        // format returned by SQL for a subtraction of two datetime values
2169
        // @todo make sure this is portable between DBMSes
2170
        if (preg_match('/:/', $virtualTime)) {
2171
            list($h, $m, $s) = preg_split('/:/', $virtualTime);
2172
            $virtualTime = $h * 3600 + $m * 60 + $s;
2173
        } else {
2174
            $virtualTime *= 3600;
2175
        }
2176
2177
        // Get the current latest course connection register. We need that
2178
        // record to re-use the data and create a new record.
2179
        $sql = "SELECT course_access_id
2180
                FROM $courseTrackingTable
2181
                WHERE
2182
                    user_id = $userId AND
2183
                    c_id = $courseId  AND
2184
                    session_id  = $sessionId AND
2185
                    counter = 0 AND
2186
                    (UNIX_TIMESTAMP(logout_course_date) - UNIX_TIMESTAMP(login_course_date)) = '$virtualTime'
2187
                ORDER BY login_course_date DESC LIMIT 0,1";
2188
        $result = Database::query($sql);
2189
2190
        // Ignore if we didn't find any course connection record in the last
2191
        // hour. In this case it wouldn't be right to add a "fake" time record.
2192
        if (Database::num_rows($result) > 0) {
2193
            // Found the latest connection
2194
            $row = Database::fetch_row($result);
2195
            $courseAccessId = $row[0];
2196
            $sql = "DELETE FROM $courseTrackingTable 
2197
                    WHERE course_access_id = $courseAccessId";
2198
            $result = Database::query($sql);
2199
2200
            return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result returns the type Doctrine\DBAL\Driver\Statement which is incompatible with the documented return type true.
Loading history...
2201
        }
2202
2203
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type true.
Loading history...
2204
    }
2205
}
2206