Completed
Push — master ( 27e209...a08afa )
by Julito
186:04 queued 150:53
created

Event::get_all_exercise_event_from_lp()   B

Complexity

Conditions 3
Paths 3

Size

Total Lines 32
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2282
    public function event_send_mail_filter_func(/** @scrutinizer ignore-unused */ &$values)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2283
    {
2284
        return true;
2285
    }
2286
2287
    /**
2288
     * user_registration - send_mail filter
2289
     * @deprecated
2290
     * @param array $values (passing by reference)
2291
     * @return boolean True if everything is OK, false otherwise
2292
     */
2293
    public function user_registration_event_send_mail_filter_func(&$values)
2294
    {
2295
        $res = self::event_send_mail_filter_func($values);
0 ignored issues
show
Bug Best Practice introduced by
The method Event::event_send_mail_filter_func() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2295
        /** @scrutinizer ignore-call */ 
2296
        $res = self::event_send_mail_filter_func($values);
Loading history...
Deprecated Code introduced by
The function Event::event_send_mail_filter_func() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

2295
        $res = /** @scrutinizer ignore-deprecated */ self::event_send_mail_filter_func($values);
Loading history...
2296
        // proper logic for this filter
2297
        return $res;
2298
    }
2299
2300
    /**
2301
     * portal_homepage_edited - send_mail filter
2302
     * @deprecated
2303
     * @param array $values (passing by reference)
2304
     * @return boolean True if everything is OK, false otherwise
2305
     */
2306
    public function portal_homepage_edited_event_send_mail_filter_func(&$values)
2307
    {
2308
        $res = self::event_send_mail_filter_func($values);
0 ignored issues
show
Bug Best Practice introduced by
The method Event::event_send_mail_filter_func() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2308
        /** @scrutinizer ignore-call */ 
2309
        $res = self::event_send_mail_filter_func($values);
Loading history...
Deprecated Code introduced by
The function Event::event_send_mail_filter_func() has been deprecated. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

2308
        $res = /** @scrutinizer ignore-deprecated */ self::event_send_mail_filter_func($values);
Loading history...
2309
        // proper logic for this filter
2310
        return $res;
2311
    }
2312
}
2313