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

Event::saveQuestionAttempt()   F

Complexity

Conditions 25
Paths > 20000

Size

Total Lines 176
Code Lines 106

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 25
eloc 106
nc 57888
nop 13
dl 0
loc 176
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

1
<?php
2
/* See license terms in /license.txt */
3
4
//use Chamilo\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