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

MySpace::export_tracking_course_overview()   F

Complexity

Conditions 16
Paths 0

Size

Total Lines 178
Code Lines 127

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 16
eloc 127
nc 0
nop 0
dl 0
loc 178
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

1
<?php
2
/* For licensing terms, see /license.txt */
3
4
use ChamiloSession as Session;
5
use CpChart\Cache as pCache;
6
use CpChart\Data as pData;
7
use CpChart\Image as pImage;
8
9
/**
10
 * Class MySpace
11
 * @package chamilo.reporting
12
 */
13
class MySpace
14
{
15
    /**
16
     * Get admin actions
17
     * @return string
18
     */
19
    public static function getAdminActions()
20
    {
21
        $actions = [
22
            [
23
                'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=coaches',
24
                'content' => get_lang('DisplayCoaches'),
25
            ],
26
            [
27
                'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=user',
28
                'content' => get_lang('DisplayUserOverview'),
29
            ],
30
            [
31
                'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=session',
32
                'content' => get_lang('DisplaySessionOverview'),
33
            ],
34
            [
35
                'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=course',
36
                'content' => get_lang('DisplayCourseOverview'),
37
            ],
38
            [
39
                'url' => api_get_path(WEB_CODE_PATH).'tracking/question_course_report.php?view=admin',
40
                'content' => get_lang('LPQuestionListResults'),
41
            ],
42
            [
43
                'url' => api_get_path(WEB_CODE_PATH).'tracking/course_session_report.php?view=admin',
44
                'content' => get_lang('LPExerciseResultsBySession'),
45
            ],
46
            [
47
                'url' => api_get_path(WEB_CODE_PATH).'mySpace/admin_view.php?display=accessoverview',
48
                'content' => get_lang('DisplayAccessOverview').' ('.get_lang('Beta').')',
49
            ],
50
            [
51
                'url' => api_get_path(WEB_CODE_PATH).'mySpace/exercise_category_report.php',
52
                'content' => get_lang('ExerciseCategoryAllSessionsReport'),
53
            ],
54
        ];
55
56
        return Display::actions($actions, null);
57
    }
58
59
    /**
60
     * @return string
61
     */
62
    public static function getTopMenu()
63
    {
64
        $menu_items = [];
65
        $menu_items[] = Display::url(
66
            Display::return_icon(
67
                'stats.png',
68
                get_lang('MyStats'),
69
                '',
70
                ICON_SIZE_MEDIUM
71
            ),
72
            api_get_path(WEB_CODE_PATH)."auth/my_progress.php"
73
        );
74
        $menu_items[] = Display::url(
75
            Display::return_icon(
76
                'teacher.png',
77
                get_lang('TeacherInterface'),
78
                [],
79
                32
80
            ),
81
            api_get_path(WEB_CODE_PATH).'mySpace/?view=teacher'
82
        );
83
        $menu_items[] = Display::url(
84
            Display::return_icon(
85
                'star_na.png',
86
                get_lang('AdminInterface'),
87
                [],
88
                32
89
            ),
90
            '#'
91
        );
92
        $menu_items[] = Display::url(
93
            Display::return_icon('quiz.png', get_lang('ExamTracking'), [], 32),
94
            api_get_path(WEB_CODE_PATH).'tracking/exams.php'
95
        );
96
        $menu = '';
97
        foreach ($menu_items as $item) {
98
            $menu .= $item;
99
        }
100
        $menu .= '<br />';
101
102
        return $menu;
103
    }
104
105
    /**
106
     * This function serves exporting data in CSV format.
107
     * @param array $header         The header labels.
108
     * @param array $data           The data array.
109
     * @param string $file_name     The name of the file which contains exported data.
110
     * @return string mixed             Returns a message (string) if an error occurred.
111
     */
112
    public function export_csv($header, $data, $file_name = 'export.csv')
113
    {
114
        $archive_path = api_get_path(SYS_ARCHIVE_PATH);
115
        $archive_url = api_get_path(WEB_CODE_PATH).'course_info/download.php?archive_path=&archive=';
116
        $message = '';
117
        if (!$open = fopen($archive_path.$file_name, 'w+')) {
118
            $message = get_lang('noOpen');
119
        } else {
120
            $info = '';
121
122
            foreach ($header as $value) {
123
                $info .= $value.';';
124
            }
125
            $info .= "\r\n";
126
127
            foreach ($data as $row) {
128
                foreach ($row as $value) {
129
                    $info .= $value.';';
130
                }
131
                $info .= "\r\n";
132
            }
133
134
            fwrite($open, $info);
135
            fclose($open);
136
            @chmod($file_name, api_get_permissions_for_new_files());
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for chmod(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

136
            /** @scrutinizer ignore-unhandled */ @chmod($file_name, api_get_permissions_for_new_files());

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
137
138
            header("Location:".$archive_url.$file_name);
139
            exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
140
        }
141
        return $message;
142
    }
143
144
    /**
145
     * Gets the connections to a course as an array of login and logout time
146
     *
147
     * @param int $userId User id
148
     * @param array $courseInfo
149
     * @param int $sessionId Session id (optional, default = 0)
150
     * @return array Connections
151
     */
152
    public static function get_connections_to_course(
153
        $userId,
154
        $courseInfo,
155
        $sessionId = 0
156
    ) {
157
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
158
159
        // protect data
160
        $userId = (int) $userId;
161
        $courseId = (int) $courseInfo['real_id'];
162
        $sessionId = (int) $sessionId;
163
        $sessionCondition = api_get_session_condition($sessionId);
164
165
        $sql = 'SELECT login_course_date, logout_course_date
166
                FROM ' . $table.'
167
                WHERE
168
                    user_id = '.$userId.' AND
169
                    c_id = '.$courseId.' 
170
                    '.$sessionCondition.'
171
                ORDER BY login_course_date ASC';
172
        $rs = Database::query($sql);
173
        $connections = [];
174
175
        while ($row = Database::fetch_array($rs)) {
176
            $connections[] = [
177
                'login' => $row['login_course_date'],
178
                'logout' => $row['logout_course_date']
179
            ];
180
        }
181
182
        return $connections;
183
    }
184
185
    /**
186
     * @param $user_id
187
     * @param $course_list
188
     * @param int $session_id
189
     * @return array|bool
190
     */
191
    public static function get_connections_from_course_list(
192
        $user_id,
193
        $course_list,
194
        $session_id = 0
195
    ) {
196
        // Database table definitions
197
        $tbl_track_course = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
198
        if (empty($course_list)) {
199
            return false;
200
        }
201
202
        // protect data
203
        $user_id = intval($user_id);
204
        $session_id = intval($session_id);
205
        $new_course_list = [];
206
        foreach ($course_list as $course_item) {
207
            $courseInfo = api_get_course_info($course_item['code']);
208
            $courseId = $courseInfo['real_id'];
209
            $new_course_list[] = '"'.$courseId.'"';
210
        }
211
        $course_list = implode(', ', $new_course_list);
212
213
        if (empty($course_list)) {
214
            return false;
215
        }
216
        $sql = 'SELECT login_course_date, logout_course_date, c_id
217
                FROM ' . $tbl_track_course.'
218
                WHERE
219
                    user_id = '.$user_id.' AND
220
                    c_id IN ('.$course_list.') AND
221
                    session_id = '.$session_id.'
222
                ORDER BY login_course_date ASC';
223
        $rs = Database::query($sql);
224
        $connections = [];
225
226
        while ($row = Database::fetch_array($rs)) {
227
            $timestamp_login_date = api_strtotime($row['login_course_date'], 'UTC');
228
            $timestamp_logout_date = api_strtotime($row['logout_course_date'], 'UTC');
229
            $connections[] = [
230
                'login' => $timestamp_login_date,
231
                'logout' => $timestamp_logout_date,
232
                'c_id' => $row['c_id']
233
            ];
234
        }
235
236
        return $connections;
237
    }
238
239
    /**
240
     * Creates a small table in the last column of the table with the user overview
241
     *
242
     * @param integer $user_id the id of the user
243
     * @param array $url_params additional url parameters
244
     * @param array $row the row information (the other columns)
245
     * @return string html code
246
     */
247
    public static function course_info_tracking_filter($user_id, $url_params, $row)
248
    {
249
        // the table header
250
        $return = '<table class="data_table" style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
251
        // database table definition
252
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
253
254
        // getting all the courses of the user
255
        $sql = "SELECT * FROM $tbl_course_user
256
                WHERE
257
                    user_id = '".intval($user_id)."' AND
258
                    relation_type<>".COURSE_RELATION_TYPE_RRHH." ";
259
        $result = Database::query($sql);
260
        while ($row = Database::fetch_array($result)) {
261
            $courseInfo = api_get_course_info_by_id($row['c_id']);
262
            if (empty($courseInfo)) {
263
                continue;
264
            }
265
266
            $courseCode = $courseInfo['code'];
267
            $courseId = $courseInfo['real_id'];
268
269
            $return .= '<tr>';
270
            // course code
271
            $return .= '    <td width="157px" >'.cut($courseCode, 20, true).'</td>';
272
            // time spent in the course
273
            $return .= '<td><div>'.api_time_to_hms(Tracking::get_time_spent_on_the_course($user_id, $courseId)).'</div></td>';
274
            // student progress in course
275
            $return .= '<td><div>'.round(Tracking::get_avg_student_progress($user_id, $courseCode), 2).'</div></td>';
276
            // student score
277
            $avg_score = Tracking::get_avg_student_score($user_id, $courseCode);
278
            if (is_numeric($avg_score)) {
279
                $avg_score = round($avg_score, 2);
280
            } else {
281
                $avg_score = '-';
282
            }
283
284
            $return .= '    <td><div>'.$avg_score.'</div></td>';
285
            // student tes score
286
            //$return .= '  <td><div style="width:40px">'.round(Tracking::get_avg_student_exercise_score ($user_id, $courseCode),2).'%</div></td>';
287
            // student messages
288
            $return .= '    <td><div>'.Tracking::count_student_messages($user_id, $courseCode).'</div></td>';
289
            // student assignments
290
            $return .= '    <td><div>'.Tracking::count_student_assignments($user_id, $courseCode).'</div></td>';
291
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
292
            $exercises_results = self::exercises_results($user_id, $courseCode);
293
            $return .= '    <td width="105px"><div>'.(is_null($exercises_results['percentage']) ? '' : $exercises_results['score_obtained'].'/'.$exercises_results['score_possible'].' ( '.$exercises_results['percentage'].'% )').'</div></td>';
294
            $return .= '    <td><div>'.$exercises_results['questions_answered'].'</div></td>';
295
            $return .= '    <td><div>'.Tracking::get_last_connection_date_on_the_course($user_id, $courseInfo).'</div></td>';
296
            $return .= '<tr>';
297
        }
298
        $return .= '</table>';
299
        return $return;
300
    }
301
302
    /**
303
     * Display a sortable table that contains an overview off all the
304
     * reporting progress of all users and all courses the user is subscribed to
305
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
306
     * @version Dokeos 1.8.6
307
     * @since October 2008
308
     */
309
    public static function display_tracking_user_overview()
310
    {
311
        self::display_user_overview_export_options();
312
        $t_head = '<table style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
313
        $t_head .= '<tr>';
314
        $t_head .= '<th width="155px" style="border-left:0;border-bottom:0"><span>'.get_lang('Course').'</span></th>';
315
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgTimeSpentInTheCourse'), 6, true).'</span></th>';
316
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgStudentsProgress'), 6, true).'</span></th>';
317
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgCourseScore'), 6, true).'</span></th>';
318
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalNumberOfMessages'), 6, true).'</span></th>';
319
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalNumberOfAssignments'), 6, true).'</span></th>';
320
        $t_head .= '<th width="105px" style="border-bottom:0"><span>'.get_lang('TotalExercisesScoreObtained').'</span></th>';
321
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalExercisesAnswered'), 6, true).'</span></th>';
322
        $t_head .= '<th style="padding:0;border-bottom:0;border-right:0;"><span>'.get_lang('LatestLogin').'</span></th>';
323
        $t_head .= '</tr></table>';
324
        $addparams = ['view' => 'admin', 'display' => 'user'];
325
        $table = new SortableTable(
326
            'tracking_user_overview',
327
            ['MySpace', 'get_number_of_users_tracking_overview'],
328
            ['MySpace', 'get_user_data_tracking_overview'],
329
            0
330
        );
331
        $table->additional_parameters = $addparams;
332
        $table->set_header(
333
            0,
334
            get_lang('OfficialCode'),
335
            true,
336
            ['style' => 'font-size:8pt'],
337
            ['style' => 'font-size:8pt']
338
        );
339
        if (api_is_western_name_order()) {
340
            $table->set_header(
341
                1,
342
                get_lang('FirstName'),
343
                true,
344
                ['style' => 'font-size:8pt'],
345
                ['style' => 'font-size:8pt']
346
            );
347
            $table->set_header(
348
                2,
349
                get_lang('LastName'),
350
                true,
351
                ['style' => 'font-size:8pt'],
352
                ['style' => 'font-size:8pt']
353
            );
354
        } else {
355
            $table->set_header(
356
                1,
357
                get_lang('LastName'),
358
                true,
359
                ['style' => 'font-size:8pt'],
360
                ['style' => 'font-size:8pt']
361
            );
362
            $table->set_header(
363
                2,
364
                get_lang('FirstName'),
365
                true,
366
                ['style' => 'font-size:8pt'],
367
                ['style' => 'font-size:8pt']
368
            );
369
        }
370
        $table->set_header(
371
            3,
372
            get_lang('LoginName'),
373
            true,
374
            ['style' => 'font-size:8pt'],
375
            ['style' => 'font-size:8pt']
376
        );
377
        $table->set_header(
378
            4,
379
            $t_head,
380
            false,
381
            ['style' => 'width:90%;border:0;padding:0;font-size:7.5pt;'],
382
            ['style' => 'width:90%;padding:0;font-size:7.5pt;']
383
        );
384
        $table->set_column_filter(4, ['MySpace', 'course_info_tracking_filter']);
385
        $table->display();
386
    }
387
388
    /**
389
     * @param $export_csv
390
     */
391
    public static function display_tracking_coach_overview($export_csv)
392
    {
393
        if ($export_csv) {
394
            $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
395
        } else {
396
            $is_western_name_order = api_is_western_name_order();
397
        }
398
        $sort_by_first_name = api_sort_by_first_name();
399
        $tracking_column = isset($_GET['tracking_list_coaches_column']) ? $_GET['tracking_list_coaches_column'] : ($is_western_name_order xor $sort_by_first_name) ? 1 : 0;
400
        $tracking_direction = (isset($_GET['tracking_list_coaches_direction']) && in_array(strtoupper($_GET['tracking_list_coaches_direction']), ['ASC', 'DESC', 'ASCENDING', 'DESCENDING', '0', '1'])) ? $_GET['tracking_list_coaches_direction'] : 'DESC';
401
        // Prepare array for column order - when impossible, use some of user names.
402
        if ($is_western_name_order) {
403
            $order = [
404
                0 => 'firstname',
405
                1 => 'lastname',
406
                2 => ($sort_by_first_name ? 'firstname' : 'lastname'),
407
                3 => 'login_date',
408
                4 => ($sort_by_first_name ? 'firstname' : 'lastname'),
409
                5 => ($sort_by_first_name ? 'firstname' : 'lastname'),
410
            ];
411
        } else {
412
            $order = [
413
                0 => 'lastname',
414
                1 => 'firstname',
415
                2 => ($sort_by_first_name ? 'firstname' : 'lastname'),
416
                3 => 'login_date',
417
                4 => ($sort_by_first_name ? 'firstname' : 'lastname'),
418
                5 => ($sort_by_first_name ? 'firstname' : 'lastname'),
419
            ];
420
        }
421
        $table = new SortableTable(
422
            'tracking_list_coaches_myspace',
423
            ['MySpace', 'count_coaches'],
424
            null,
425
            ($is_western_name_order xor $sort_by_first_name) ? 1 : 0
426
        );
427
        $parameters['view'] = 'admin';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$parameters was never initialized. Although not strictly required by PHP, it is generally a good practice to add $parameters = array(); before regardless.
Loading history...
428
        $table->set_additional_parameters($parameters);
429
        if ($is_western_name_order) {
430
            $table->set_header(0, get_lang('FirstName'), true);
431
            $table->set_header(1, get_lang('LastName'), true);
432
        } else {
433
            $table->set_header(0, get_lang('LastName'), true);
434
            $table->set_header(1, get_lang('FirstName'), true);
435
        }
436
        $table->set_header(2, get_lang('TimeSpentOnThePlatform'), false);
437
        $table->set_header(3, get_lang('LastConnexion'), false);
438
        $table->set_header(4, get_lang('NbStudents'), false);
439
        $table->set_header(5, get_lang('CountCours'), false);
440
        $table->set_header(6, get_lang('NumberOfSessions'), false);
441
        $table->set_header(7, get_lang('Sessions'), false);
442
443
        if ($is_western_name_order) {
444
            $csv_header[] = [
0 ignored issues
show
Comprehensibility Best Practice introduced by
$csv_header was never initialized. Although not strictly required by PHP, it is generally a good practice to add $csv_header = array(); before regardless.
Loading history...
445
                get_lang('FirstName'),
446
                get_lang('LastName'),
447
                get_lang('TimeSpentOnThePlatform'),
448
                get_lang('LastConnexion'),
449
                get_lang('NbStudents'),
450
                get_lang('CountCours'),
451
                get_lang('NumberOfSessions')
452
            ];
453
        } else {
454
            $csv_header[] = [
455
                get_lang('LastName'),
456
                get_lang('FirstName'),
457
                get_lang('TimeSpentOnThePlatform'),
458
                get_lang('LastConnexion'),
459
                get_lang('NbStudents'),
460
                get_lang('CountCours'),
461
                get_lang('NumberOfSessions')
462
            ];
463
        }
464
465
        $tbl_track_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
466
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
467
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
468
        $tbl_sessions = Database::get_main_table(TABLE_MAIN_SESSION);
469
470
        $sqlCoachs = "SELECT DISTINCT
471
                        scu.user_id as id_coach,
472
                        u.id as user_id,
473
                        lastname,
474
                        firstname,
475
                        MAX(login_date) as login_date
476
                        FROM $tbl_user u, $tbl_session_course_user scu, $tbl_track_login
477
                        WHERE
478
                            scu.user_id = u.id AND scu.status=2 AND login_user_id=u.id
479
                        GROUP BY user_id ";
480
481
        if (api_is_multiple_url_enabled()) {
482
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
483
            $access_url_id = api_get_current_access_url_id();
484
            if ($access_url_id != -1) {
485
                $sqlCoachs = "SELECT DISTINCT
486
                                    scu.user_id as id_coach,
487
                                    u.id as user_id,
488
                                    lastname,
489
                                    firstname,
490
                                    MAX(login_date) as login_date
491
                                FROM $tbl_user u,
492
                                $tbl_session_course_user scu,
493
                                $tbl_track_login ,
494
                                $tbl_session_rel_access_url session_rel_url
495
                                WHERE
496
                                    scu.user_id = u.id AND
497
                                    scu.status = 2 AND
498
                                    login_user_id = u.id AND
499
                                    access_url_id = $access_url_id AND
500
                                    session_rel_url.session_id = scu.session_id
501
                                GROUP BY u.id";
502
            }
503
        }
504
        if (!empty($order[$tracking_column])) {
505
            $sqlCoachs .= " ORDER BY ".$order[$tracking_column]." ".$tracking_direction;
506
        }
507
508
        $result_coaches = Database::query($sqlCoachs);
509
        $global_coaches = [];
510
        while ($coach = Database::fetch_array($result_coaches)) {
511
            $global_coaches[$coach['user_id']] = $coach;
512
        }
513
514
        $sql_session_coach = "SELECT session.id_coach, u.id as user_id, lastname, firstname, MAX(login_date) as login_date
515
                                FROM $tbl_user u , $tbl_sessions as session, $tbl_track_login
516
                                WHERE id_coach = u.id AND login_user_id = u.id
517
                                GROUP BY u.id
518
                                ORDER BY login_date $tracking_direction";
519
520
        if (api_is_multiple_url_enabled()) {
521
            $tbl_session_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
522
            $access_url_id = api_get_current_access_url_id();
523
            if ($access_url_id != -1) {
524
                $sql_session_coach = "SELECT session.id_coach, u.id as user_id, lastname, firstname, MAX(login_date) as login_date
525
					FROM $tbl_user u , $tbl_sessions as session, $tbl_track_login , $tbl_session_rel_access_url as session_rel_url
526
					WHERE
527
					    id_coach = u.id AND
528
					    login_user_id = u.id  AND
529
					    access_url_id = $access_url_id AND
530
					    session_rel_url.session_id = session.id
531
					GROUP BY  u.id
532
					ORDER BY login_date $tracking_direction";
533
            }
534
        }
535
536
        $result_sessions_coach = Database::query($sql_session_coach);
537
        //$total_no_coaches += Database::num_rows($result_sessions_coach);
538
        while ($coach = Database::fetch_array($result_sessions_coach)) {
539
            $global_coaches[$coach['user_id']] = $coach;
540
        }
541
542
        $all_datas = [];
543
        foreach ($global_coaches as $id_coach => $coaches) {
544
            $time_on_platform = api_time_to_hms(
545
                Tracking::get_time_spent_on_the_platform($coaches['user_id'])
546
            );
547
            $last_connection = Tracking::get_last_connection_date(
548
                $coaches['user_id']
549
            );
550
            $nb_students = count(
551
                Tracking::get_student_followed_by_coach($coaches['user_id'])
552
            );
553
            $nb_courses = count(
554
                Tracking::get_courses_followed_by_coach($coaches['user_id'])
555
            );
556
            $nb_sessions = count(
557
                Tracking::get_sessions_coached_by_user($coaches['user_id'])
558
            );
559
560
            $table_row = [];
561
            if ($is_western_name_order) {
562
                $table_row[] = $coaches['firstname'];
563
                $table_row[] = $coaches['lastname'];
564
            } else {
565
                $table_row[] = $coaches['lastname'];
566
                $table_row[] = $coaches['firstname'];
567
            }
568
            $table_row[] = $time_on_platform;
569
            $table_row[] = $last_connection;
570
            $table_row[] = $nb_students;
571
            $table_row[] = $nb_courses;
572
            $table_row[] = $nb_sessions;
573
            $table_row[] = '<a href="session.php?id_coach='.$coaches['user_id'].'">
574
                '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
575
            </a>';
576
            $all_datas[] = $table_row;
577
578
            if ($is_western_name_order) {
579
                $csv_content[] = [
580
                    api_html_entity_decode($coaches['firstname'], ENT_QUOTES),
581
                    api_html_entity_decode($coaches['lastname'], ENT_QUOTES),
582
                    $time_on_platform,
583
                    $last_connection,
584
                    $nb_students,
585
                    $nb_courses,
586
                    $nb_sessions
587
                ];
588
            } else {
589
                $csv_content[] = [
590
                    api_html_entity_decode($coaches['lastname'], ENT_QUOTES),
591
                    api_html_entity_decode($coaches['firstname'], ENT_QUOTES),
592
                    $time_on_platform,
593
                    $last_connection,
594
                    $nb_students,
595
                    $nb_courses,
596
                    $nb_sessions
597
                ];
598
            }
599
        }
600
601
        if ($tracking_column != 3) {
602
            if ($tracking_direction == 'DESC') {
603
                usort($all_datas, ['MySpace', 'rsort_users']);
604
            } else {
605
                usort($all_datas, ['MySpace', 'sort_users']);
606
            }
607
        }
608
609
        if ($export_csv && $tracking_column != 3) {
610
            usort($csv_content, 'sort_users');
611
        }
612
        if ($export_csv) {
613
            $csv_content = array_merge($csv_header, $csv_content);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $csv_content does not seem to be defined for all execution paths leading up to this point.
Loading history...
614
        }
615
616
        foreach ($all_datas as $row) {
617
            $table -> addRow($row, 'align="right"');
618
        }
619
        $table->display();
620
    }
621
622
    /**
623
     * @return mixed
624
     */
625
    public static function count_coaches()
626
    {
627
        global $total_no_coaches;
628
        return $total_no_coaches;
629
    }
630
631
    public static function sort_users($a, $b)
632
    {
633
        $tracking = Session::read('tracking_column');
634
        return api_strcmp(
635
            trim(api_strtolower($a[$tracking])),
636
            trim(api_strtolower($b[$tracking]))
637
        );
638
    }
639
640
    public static function rsort_users($a, $b)
641
    {
642
        $tracking = Session::read('tracking_column');
643
        return api_strcmp(
644
            trim(api_strtolower($b[$tracking])),
645
            trim(api_strtolower($a[$tracking]))
646
        );
647
    }
648
649
    /**
650
     * Display a sortable table that contains an overview off all the progress of the user in a session
651
     * @author César Perales <[email protected]>, Beeznest Team
652
     */
653
    public static function display_tracking_lp_progress_overview(
654
        $sessionId = '',
655
        $courseId = '',
656
        $date_from,
657
        $date_to
658
    ) {
659
        $course = api_get_course_info_by_id($courseId);
660
        /**
661
         * Column name
662
         * The order is important you need to check the $column variable in the model.ajax.php file
663
         */
664
        $columns = [
665
            get_lang('Username'),
666
            get_lang('FirstName'),
667
            get_lang('LastName'),
668
        ];
669
        //add lessons of course
670
        $lessons = LearnpathList::get_course_lessons($course['code'], $sessionId);
671
672
        //create columns array
673
        foreach ($lessons as $lesson_id => $lesson) {
674
            $columns[] = $lesson['name'];
675
        }
676
677
        $columns[] = get_lang('Total');
678
679
        /**
680
         * Column config
681
         */
682
        $column_model = [
683
            [
684
                'name' => 'username',
685
                'index' => 'username',
686
                'align' => 'left',
687
                'search' => 'true',
688
                'wrap_cell' => "true",
689
            ],
690
            [
691
                'name' => 'firstname',
692
                'index' => 'firstname',
693
                'align' => 'left',
694
                'search' => 'true',
695
            ],
696
            [
697
                'name' => 'lastname',
698
                'index' => 'lastname',
699
                'align' => 'left',
700
                'search' => 'true',
701
            ],
702
        ];
703
704
        // Get dinamic column names
705
        foreach ($lessons as $lesson_id => $lesson) {
706
            $column_model[] = [
707
                'name' => $lesson['id'],
708
                'index' => $lesson['id'],
709
                'align' => 'left',
710
                'search' => 'true',
711
            ];
712
        }
713
714
        $column_model[] = [
715
            'name' => 'total',
716
            'index' => 'total',
717
            'align' => 'left',
718
            'search' => 'true',
719
        ];
720
721
        $action_links = '';
722
        // jqgrid will use this URL to do the selects
723
        $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_session_lp_progress&session_id='.$sessionId.'&course_id='.$courseId.'&date_to='.$date_to.'&date_from='.$date_from;
724
725
        // Table Id
726
        $tableId = 'lpProgress';
727
728
        // Autowidth
729
        $extra_params['autowidth'] = 'true';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$extra_params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $extra_params = array(); before regardless.
Loading history...
730
731
        // height auto
732
        $extra_params['height'] = 'auto';
733
734
        $table = Display::grid_js(
735
            $tableId,
736
            $url,
737
            $columns,
738
            $column_model,
739
            $extra_params,
740
            [],
741
            $action_links,
742
            true
743
        );
744
745
        $return = '<script>$(function() {'.$table.
746
            'jQuery("#'.$tableId.'").jqGrid("navGrid","#'.$tableId.'_pager",{view:false, edit:false, add:false, del:false, search:false, excel:true});
747
                jQuery("#'.$tableId.'").jqGrid("navButtonAdd","#'.$tableId.'_pager",{
748
                       caption:"",
749
                       title:"' . get_lang('ExportExcel').'",
750
                       onClickButton : function () {
751
                           jQuery("#'.$tableId.'").jqGrid("excelExport",{"url":"'.$url.'&export_format=xls"});
752
                       }
753
                });
754
            });</script>';
755
        $return .= Display::grid_html($tableId);
756
        return $return;
757
    }
758
759
    /**
760
     * Display a sortable table that contains an overview off all the progress of the user in a session
761
     * @param   int $sessionId  The session ID
762
     * @param   int $courseId   The course ID
763
     * @param   int $exerciseId The quiz ID
764
     * @param   $date_from
765
     * @param   $date_to
766
     * @return  string  HTML array of results formatted for gridJS
767
     * @author César Perales <[email protected]>, Beeznest Team
768
     */
769
    public static function display_tracking_exercise_progress_overview(
770
        $sessionId = 0,
771
        $courseId = 0,
772
        $exerciseId = 0,
773
        $date_from = null,
774
        $date_to = null
775
    ) {
776
        $date_from = Security::remove_XSS($date_from);
777
        $date_to = Security::remove_XSS($date_to);
778
        /**
779
         * Column names
780
         * The column order is important. Check $column variable in the main/inc/ajax/model.ajax.php file
781
         */
782
        $columns = [
783
            get_lang('Session'),
784
            get_lang('ExerciseId'),
785
            get_lang('ExerciseName'),
786
            get_lang('Username'),
787
            get_lang('LastName'),
788
            get_lang('FirstName'),
789
            get_lang('Time'),
790
            get_lang('QuestionId'),
791
            get_lang('QuestionTitle'),
792
            get_lang('WorkDescription'),
793
            get_lang('Answer'),
794
            get_lang('Correct')
795
        ];
796
797
        /**
798
         * Column config
799
         */
800
        $column_model = [
801
            ['name'=>'session', 'index'=>'session', 'align'=>'left', 'search' => 'true', 'wrap_cell' => "true"],
802
            ['name'=>'exercise_id', 'index'=>'exercise_id', 'align'=>'left', 'search' => 'true'],
803
            ['name'=>'quiz_title', 'index'=>'quiz_title', 'align'=>'left', 'search' => 'true'],
804
            ['name'=>'username', 'index'=>'username', 'align'=>'left', 'search' => 'true'],
805
            ['name'=>'lastname', 'index'=>'lastname', 'align'=>'left', 'search' => 'true'],
806
            ['name'=>'firstname', 'index'=>'firstname', 'align'=>'left', 'search' => 'true'],
807
            ['name'=>'time', 'index'=>'time', 'align'=>'left', 'search' => 'true', 'wrap_cell' => "true"],
808
            ['name'=>'question_id', 'index'=>'question_id', 'align'=>'left', 'search' => 'true'],
809
            ['name'=>'question', 'index'=>'question', 'align'=>'left', 'search' => 'true', 'wrap_cell' => "true"],
810
            ['name'=>'description', 'index'=>'description', 'align'=>'left', 'width' => '550', 'search' => 'true', 'wrap_cell' => "true"],
811
            ['name'=>'answer', 'index'=>'answer', 'align'=>'left', 'search' => 'true', 'wrap_cell' => "true"],
812
            ['name'=>'correct', 'index'=>'correct', 'align'=>'left', 'search' => 'true', 'wrap_cell' => "true"],
813
        ];
814
        //get dynamic column names
815
816
        // jqgrid will use this URL to do the selects
817
        $url = api_get_path(WEB_AJAX_PATH).'model.ajax.php?a=get_exercise_progress&session_id='.$sessionId.'&course_id='.$courseId.'&exercise_id='.$exerciseId.'&date_to='.$date_to.'&date_from='.$date_from;
818
819
        // Autowidth
820
        $extra_params['autowidth'] = 'true';
0 ignored issues
show
Comprehensibility Best Practice introduced by
$extra_params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $extra_params = array(); before regardless.
Loading history...
821
822
        // height auto
823
        $extra_params['height'] = 'auto';
824
825
        $tableId = 'exerciseProgressOverview';
826
        $table = Display::grid_js(
827
            $tableId,
828
            $url,
829
            $columns,
830
            $column_model,
831
            $extra_params,
832
            [],
833
            '',
834
            true
835
        );
836
837
        $return = '<script>$(function() {'.$table.
838
            'jQuery("#'.$tableId.'").jqGrid("navGrid","#'.$tableId.'_pager",{view:false, edit:false, add:false, del:false, search:false, excel:true});
839
                jQuery("#'.$tableId.'").jqGrid("navButtonAdd","#'.$tableId.'_pager",{
840
                       caption:"",
841
                       title:"' . get_lang('ExportExcel').'",
842
                       onClickButton : function () {
843
                           jQuery("#'.$tableId.'").jqGrid("excelExport",{"url":"'.$url.'&export_format=xls"});
844
                       }
845
                });
846
            });</script>';
847
        $return .= Display::grid_html($tableId);
848
849
        return $return;
850
    }
851
852
    /**
853
     * Displays a form with all the additionally defined user fields of the profile
854
     * and give you the opportunity to include these in the CSV export
855
     *
856
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
857
     * @version 1.8.6
858
     * @since November 2008
859
     */
860
    public static function display_user_overview_export_options()
861
    {
862
        $message = '';
863
        $defaults = [];
864
        // include the user manager and formvalidator library
865
        if (isset($_GET['export']) && $_GET['export'] == 'options') {
866
            // get all the defined extra fields
867
            $extrafields = UserManager::get_extra_fields(
868
                0,
869
                50,
870
                5,
871
                'ASC',
872
                false,
873
                1
874
            );
875
876
            // creating the form with all the defined extra fields
877
            $form = new FormValidator(
878
                'exportextrafields',
879
                'post',
880
                api_get_self()."?view=".Security::remove_XSS($_GET['view']).'&display='.Security::remove_XSS($_GET['display']).'&export='.Security::remove_XSS($_GET['export'])
881
            );
882
883
            if (is_array($extrafields) && count($extrafields) > 0) {
884
                foreach ($extrafields as $key => $extra) {
885
                    $form->addElement('checkbox', 'extra_export_field'.$extra[0], '', $extra[3]);
886
                }
887
                $form->addButtonSave(get_lang('Ok'), 'submit');
888
889
                // setting the default values for the form that contains all the extra fields
890
                $exportFields = Session::read('additional_export_fields');
891
                if (is_array($exportFields)) {
892
                    foreach ($exportFields as $key => $value) {
893
                        $defaults['extra_export_field'.$value] = 1;
894
                    }
895
                }
896
                $form->setDefaults($defaults);
897
            } else {
898
                $form->addElement('html', Display::return_message(get_lang('ThereAreNotExtrafieldsAvailable'), 'warning'));
899
            }
900
901
            if ($form->validate()) {
902
                // exporting the form values
903
                $values = $form->exportValues();
904
905
                // re-initialising the session that contains the additional fields that need to be exported
906
                Session::write('additional_export_fields', []);
907
908
                // adding the fields that are checked to the session
909
                $message = '';
910
                $additionalExportFields = [];
911
                foreach ($values as $field_ids => $value) {
912
                    if ($value == 1 && strstr($field_ids, 'extra_export_field')) {
913
                        $additionalExportFields[] = str_replace('extra_export_field', '', $field_ids);
914
                    }
915
                }
916
                Session::write('additional_export_fields', $additionalExportFields);
917
918
                // adding the fields that will be also exported to a message string
919
                $additionalExportFields = Session::read('additional_export_fields');
920
                if (is_array($additionalExportFields)) {
921
                    foreach ($additionalExportFields as $key => $extra_field_export) {
922
                        $message .= '<li>'.$extrafields[$extra_field_export][3].'</li>';
923
                    }
924
                }
925
926
                // Displaying a feedback message
927
                if (!empty($additionalExportFields)) {
928
                    echo Display::return_message(
929
                        get_lang('FollowingFieldsWillAlsoBeExported').': <br /><ul>'.$message.'</ul>',
930
                        'confirm',
931
                        false
932
                    );
933
                } else {
934
                    echo Display::return_message(
935
                        get_lang('NoAdditionalFieldsWillBeExported'),
936
                        'confirm',
937
                        false
938
                    );
939
                }
940
            } else {
941
                $form->display();
942
            }
943
        } else {
944
            $additionalExportFields = Session::read('additional_export_fields');
945
            if (!empty($additionalExportFields)) {
946
                // get all the defined extra fields
947
                $extrafields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
948
949
                foreach ($additionalExportFields as $key => $extra_field_export) {
950
                    $message .= '<li>'.$extrafields[$extra_field_export][3].'</li>';
951
                }
952
953
                echo Display::return_message(
954
                    get_lang('FollowingFieldsWillAlsoBeExported').': <br /><ul>'.$message.'</ul>',
955
                    'normal',
956
                    false
957
                );
958
            }
959
        }
960
    }
961
962
    /**
963
     * Display a sortable table that contains an overview of all the reporting progress of all courses
964
     */
965
    public static function display_tracking_course_overview()
966
    {
967
        $t_head = '<table style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
968
        $t_head .= '<tr>';
969
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgTimeSpentInTheCourse'), 6, true).'</span></th>';
970
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgStudentsProgress'), 6, true).'</span></th>';
971
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgCourseScore'), 6, true).'</span></th>';
972
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalNumberOfMessages'), 6, true).'</span></th>';
973
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalNumberOfAssignments'), 6, true).'</span></th>';
974
        $t_head .= '<th width="105px" style="border-bottom:0"><span>'.get_lang('TotalExercisesScoreObtained').'</span></th>';
975
        $t_head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalExercisesAnswered'), 6, true).'</span></th>';
976
        $t_head .= '<th style="padding:0;border-bottom:0;border-right:0;"><span>'.get_lang('LatestLogin').'</span></th>';
977
        $t_head .= '</tr></table>';
978
        $addparams = ['view' => 'admin', 'display' => 'courseoverview'];
979
        $table = new SortableTable(
980
            'tracking_session_overview',
981
            ['MySpace', 'get_total_number_courses'],
982
            ['MySpace', 'get_course_data_tracking_overview'],
983
            1
984
        );
985
        $table->additional_parameters = $addparams;
986
987
        $table->set_header(0, '', false, null, ['style' => 'display: none']);
988
        $table->set_header(1, get_lang('Course'), true, ['style' => 'font-size:8pt'], ['style' => 'font-size:8pt']);
989
        $table->set_header(2, $t_head, false, ['style' => 'width:90%;border:0;padding:0;font-size:7.5pt;'], ['style' => 'width:90%;padding:0;font-size:7.5pt;']);
990
        $table->set_column_filter(2, ['MySpace', 'course_tracking_filter']);
991
        $table->display();
992
    }
993
994
    /**
995
     * Get the total number of courses
996
     *
997
     * @return integer Total number of courses
998
     */
999
    public static function get_total_number_courses()
1000
    {
1001
        return CourseManager::count_courses(api_get_current_access_url_id());
1002
    }
1003
1004
    /**
1005
     * Get data for the courses
1006
     *
1007
     * @param int $from Inferior limit
1008
     * @param int $numberItems Number of items to select
1009
     * @param string $column Column to order on
1010
     * @param string $direction Order direction
1011
     * @return array Results
1012
     */
1013
    public static function get_course_data_tracking_overview(
1014
        $from,
1015
        $numberItems,
1016
        $column,
1017
        $direction
1018
    ) {
1019
        $courses = CourseManager::get_courses_list(
1020
            $from,
1021
            $numberItems,
1022
            $column,
1023
            $direction,
1024
             -1,
1025
            '',
1026
            api_get_current_access_url_id()
1027
        );
1028
1029
        $list = [];
1030
        foreach ($courses as $course) {
1031
            $list[] = [
1032
                '0' => $course['code'],
1033
                'col0' => $course['code'],
1034
                '1' => $course['title'],
1035
                'col1' => $course['title']
1036
            ];
1037
        }
1038
1039
        return $list;
1040
    }
1041
1042
    /**
1043
     * Fills in course reporting data
1044
     *
1045
     * @param integer course code
1046
     * @param array $url_params additional url parameters
1047
     * @param array $row the row information (the other columns)
1048
     * @return string html code
1049
     */
1050
    public static function course_tracking_filter($course_code, $url_params, $row)
1051
    {
1052
        $course_code = $row[0];
1053
        $courseInfo = api_get_course_info($course_code);
1054
        $courseId = $courseInfo['real_id'];
1055
1056
        // the table header
1057
        $return = '<table class="data_table" style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
1058
1059
        // database table definition
1060
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1061
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1062
1063
        // getting all the courses of the user
1064
        $sql = "SELECT *
1065
                FROM $tbl_user AS u
1066
                INNER JOIN $tbl_course_rel_user AS cu
1067
                ON cu.user_id = u.user_id
1068
                WHERE cu.c_id = '".$courseId."'";
1069
        $result = Database::query($sql);
1070
        $time_spent = 0;
1071
        $progress = 0;
1072
        $nb_progress_lp = 0;
1073
        $score = 0;
1074
        $nb_score_lp = 0;
1075
        $nb_messages = 0;
1076
        $nb_assignments = 0;
1077
        $last_login_date = false;
1078
        $total_score_obtained = 0;
1079
        $total_score_possible = 0;
1080
        $total_questions_answered = 0;
1081
        while ($row = Database::fetch_object($result)) {
1082
            // get time spent in the course and session
1083
            $time_spent += Tracking::get_time_spent_on_the_course(
1084
                $row->user_id,
1085
                $courseInfo['real_id']
1086
            );
1087
            $progress_tmp = Tracking::get_avg_student_progress(
1088
                $row->user_id,
1089
                $course_code,
1090
                [],
1091
                null,
1092
                true
1093
            );
1094
            $progress += $progress_tmp[0];
1095
            $nb_progress_lp += $progress_tmp[1];
1096
            $score_tmp = Tracking::get_avg_student_score(
1097
                $row->user_id,
1098
                $course_code,
1099
                [],
1100
                null,
1101
                true
1102
            );
1103
            if (is_array($score_tmp)) {
1104
                $score += $score_tmp[0];
1105
                $nb_score_lp += $score_tmp[1];
1106
            }
1107
            $nb_messages += Tracking::count_student_messages(
1108
                $row->user_id,
1109
                $course_code
1110
            );
1111
            $nb_assignments += Tracking::count_student_assignments(
1112
                $row->user_id,
1113
                $course_code
1114
            );
1115
            $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
1116
                $row->user_id,
1117
                $courseInfo,
1118
                null,
1119
                false
1120
            );
1121
            if ($last_login_date_tmp != false &&
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
1122
                $last_login_date == false
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1123
            ) { // TODO: To be cleaned
1124
                $last_login_date = $last_login_date_tmp;
1125
            } elseif ($last_login_date_tmp != false &&
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
1126
                $last_login_date != false
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
1127
            ) { // TODO: Repeated previous condition. To be cleaned.
1128
                // Find the max and assign it to first_login_date
1129
                if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
1130
                    $last_login_date = $last_login_date_tmp;
1131
                }
1132
            }
1133
1134
            $exercise_results_tmp = self::exercises_results($row->user_id, $course_code);
1135
            $total_score_obtained += $exercise_results_tmp['score_obtained'];
1136
            $total_score_possible += $exercise_results_tmp['score_possible'];
1137
            $total_questions_answered += $exercise_results_tmp['questions_answered'];
1138
        }
1139
        if ($nb_progress_lp > 0) {
1140
            $avg_progress = round($progress / $nb_progress_lp, 2);
1141
        } else {
1142
            $avg_progress = 0;
1143
        }
1144
        if ($nb_score_lp > 0) {
1145
            $avg_score = round($score / $nb_score_lp, 2);
1146
        } else {
1147
            $avg_score = '-';
1148
        }
1149
        if ($last_login_date) {
1150
            $last_login_date = api_convert_and_format_date(
1151
                $last_login_date,
1152
                DATE_FORMAT_SHORT,
1153
                date_default_timezone_get()
1154
            );
1155
        } else {
1156
            $last_login_date = '-';
1157
        }
1158
        if ($total_score_possible > 0) {
1159
            $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
1160
        } else {
1161
            $total_score_percentage = 0;
1162
        }
1163
        if ($total_score_percentage > 0) {
1164
            $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
1165
        } else {
1166
            $total_score = '-';
1167
        }
1168
        $return .= '<tr>';
1169
        // time spent in the course
1170
        $return .= '    <td style="width:164px;">'.api_time_to_hms($time_spent).'</td>';
1171
        // student progress in course
1172
        $return .= '    <td>'.$avg_progress.'</td>';
1173
        // student score
1174
        $return .= '    <td>'.$avg_score.'</td>';
1175
        // student messages
1176
        $return .= '    <td>'.$nb_messages.'</td>';
1177
        // student assignments
1178
        $return .= '    <td>'.$nb_assignments.'</td>';
1179
        // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
1180
        $return .= '<td width="105px;">'.$total_score.'</td>';
1181
        $return .= '<td>'.$total_questions_answered.'</td>';
1182
        // last connection
1183
        $return .= '    <td>'.$last_login_date.'</td>';
1184
        $return .= '</tr>';
1185
        $return .= '</table>';
1186
        return $return;
1187
    }
1188
1189
    /**
1190
     * This function exports the table that we see in display_tracking_course_overview()
1191
     *
1192
     */
1193
    public static function export_tracking_course_overview()
1194
    {
1195
        // database table definition
1196
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1197
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1198
1199
        // the values of the sortable table
1200
        if ($_GET['tracking_course_overview_page_nr']) {
1201
            $from = $_GET['tracking_course_overview_page_nr'];
1202
        } else {
1203
            $from = 0;
1204
        }
1205
        if ($_GET['tracking_course_overview_column']) {
1206
            $orderby = $_GET['tracking_course_overview_column'];
1207
        } else {
1208
            $orderby = 0;
1209
        }
1210
1211
        if ($_GET['tracking_course_overview_direction']) {
1212
            $direction = $_GET['tracking_course_overview_direction'];
1213
        } else {
1214
            $direction = 'ASC';
1215
        }
1216
1217
        $course_data = self::get_course_data_tracking_overview(
1218
            $from,
1219
            1000,
1220
            $orderby,
1221
            $direction
1222
        );
1223
1224
        $csv_content = [];
1225
1226
        // the first line of the csv file with the column headers
1227
        $csv_row = [];
1228
        $csv_row[] = get_lang('Course');
1229
        $csv_row[] = get_lang('AvgTimeSpentInTheCourse');
1230
        $csv_row[] = get_lang('AvgStudentsProgress');
1231
        $csv_row[] = get_lang('AvgCourseScore');
1232
        $csv_row[] = get_lang('TotalNumberOfMessages');
1233
        $csv_row[] = get_lang('TotalNumberOfAssignments');
1234
        $csv_row[] = get_lang('TotalExercisesScoreObtained');
1235
        $csv_row[] = get_lang('TotalExercisesScorePossible');
1236
        $csv_row[] = get_lang('TotalExercisesAnswered');
1237
        $csv_row[] = get_lang('TotalExercisesScorePercentage');
1238
        $csv_row[] = get_lang('LatestLogin');
1239
        $csv_content[] = $csv_row;
1240
1241
        // the other lines (the data)
1242
        foreach ($course_data as $key => $course) {
1243
            $course_code = $course[0];
1244
            $courseInfo = api_get_course_info($course_code);
1245
            $course_title = $courseInfo['title'];
1246
            $courseId = $courseInfo['real_id'];
1247
1248
            $csv_row = [];
1249
            $csv_row[] = $course_title;
1250
1251
            // getting all the courses of the session
1252
            $sql = "SELECT *
1253
                    FROM $tbl_user AS u
1254
                    INNER JOIN $tbl_course_rel_user AS cu
1255
                    ON cu.user_id = u.user_id
1256
                    WHERE cu.c_id = '".$courseId."'";
1257
            $result = Database::query($sql);
1258
            $time_spent = 0;
1259
            $progress = 0;
1260
            $nb_progress_lp = 0;
1261
            $score = 0;
1262
            $nb_score_lp = 0;
1263
            $nb_messages = 0;
1264
            $nb_assignments = 0;
1265
            $last_login_date = false;
1266
            $total_score_obtained = 0;
1267
            $total_score_possible = 0;
1268
            $total_questions_answered = 0;
1269
            while ($row = Database::fetch_object($result)) {
1270
                // get time spent in the course and session
1271
                $time_spent += Tracking::get_time_spent_on_the_course(
1272
                    $row->user_id,
1273
                    $courseId
1274
                );
1275
                $progress_tmp = Tracking::get_avg_student_progress(
1276
                    $row->user_id,
1277
                    $course_code,
1278
                    [],
1279
                    null,
1280
                    true
1281
                );
1282
                $progress += $progress_tmp[0];
1283
                $nb_progress_lp += $progress_tmp[1];
1284
                $score_tmp = Tracking::get_avg_student_score(
1285
                    $row->user_id,
1286
                    $course_code,
1287
                    [],
1288
                    null,
1289
                    true
1290
                );
1291
                if (is_array($score_tmp)) {
1292
                    $score += $score_tmp[0];
1293
                    $nb_score_lp += $score_tmp[1];
1294
                }
1295
                $nb_messages += Tracking::count_student_messages(
1296
                    $row->user_id,
1297
                    $course_code
1298
                );
1299
                $nb_assignments += Tracking::count_student_assignments(
1300
                    $row->user_id,
1301
                    $course_code
1302
                );
1303
1304
                $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
1305
                    $row->user_id,
1306
                    $courseInfo,
1307
                    null,
1308
                    false
1309
                );
1310
                if ($last_login_date_tmp != false && $last_login_date == false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1311
                    // TODO: To be cleaned.
1312
                    $last_login_date = $last_login_date_tmp;
1313
                } elseif ($last_login_date_tmp != false && $last_login_date == false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1314
                    // TODO: Repeated previous condition. To be cleaned.
1315
                    // Find the max and assign it to first_login_date
1316
                    if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
0 ignored issues
show
Bug introduced by
It seems like $last_login_date_tmp can also be of type true; however, parameter $time of strtotime() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1316
                    if (strtotime(/** @scrutinizer ignore-type */ $last_login_date_tmp) > strtotime($last_login_date)) {
Loading history...
1317
                        $last_login_date = $last_login_date_tmp;
1318
                    }
1319
                }
1320
1321
                $exercise_results_tmp = self::exercises_results($row->user_id, $course_code);
1322
                $total_score_obtained += $exercise_results_tmp['score_obtained'];
1323
                $total_score_possible += $exercise_results_tmp['score_possible'];
1324
                $total_questions_answered += $exercise_results_tmp['questions_answered'];
1325
            }
1326
            if ($nb_progress_lp > 0) {
1327
                $avg_progress = round($progress / $nb_progress_lp, 2);
1328
            } else {
1329
                $avg_progress = 0;
1330
            }
1331
            if ($nb_score_lp > 0) {
1332
                $avg_score = round($score / $nb_score_lp, 2);
1333
            } else {
1334
                $avg_score = '-';
1335
            }
1336
            if ($last_login_date) {
1337
                $last_login_date = api_convert_and_format_date(
1338
                    $last_login_date,
1339
                    DATE_FORMAT_SHORT,
1340
                    date_default_timezone_get()
1341
                );
1342
            } else {
1343
                $last_login_date = '-';
1344
            }
1345
            if ($total_score_possible > 0) {
1346
                $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
1347
            } else {
1348
                $total_score_percentage = 0;
1349
            }
1350
            // time spent in the course
1351
            $csv_row[] = api_time_to_hms($time_spent);
1352
            // student progress in course
1353
            $csv_row[] = $avg_progress;
1354
            // student score
1355
            $csv_row[] = $avg_score;
1356
            // student messages
1357
            $csv_row[] = $nb_messages;
1358
            // student assignments
1359
            $csv_row[] = $nb_assignments;
1360
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
1361
            $csv_row[] = $total_score_obtained;
1362
            $csv_row[] = $total_score_possible;
1363
            $csv_row[] = $total_questions_answered;
1364
            $csv_row[] = $total_score_percentage;
1365
            // last connection
1366
            $csv_row[] = $last_login_date;
1367
            $csv_content[] = $csv_row;
1368
        }
1369
        Export::arrayToCsv($csv_content, 'reporting_course_overview');
1370
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1371
    }
1372
1373
    /**
1374
     * Display a sortable table that contains an overview of all the reporting
1375
     * progress of all sessions and all courses the user is subscribed to
1376
     * @author Guillaume Viguier <[email protected]>
1377
     */
1378
    public static function display_tracking_session_overview()
1379
    {
1380
        $head = '<table style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
1381
        $head .= '<tr>';
1382
        $head .= '<th width="155px" style="border-left:0;border-bottom:0"><span>'.get_lang('Course').'</span></th>';
1383
        $head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgTimeSpentInTheCourse'), 6, true).'</span></th>';
1384
        $head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgStudentsProgress'), 6, true).'</span></th>';
1385
        $head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('AvgCourseScore'), 6, true).'</span></th>';
1386
        $head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalNumberOfMessages'), 6, true).'</span></th>';
1387
        $head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalNumberOfAssignments'), 6, true).'</span></th>';
1388
        $head .= '<th width="105px" style="border-bottom:0"><span>'.get_lang('TotalExercisesScoreObtained').'</span></th>';
1389
        $head .= '<th style="padding:0;border-bottom:0"><span>'.cut(get_lang('TotalExercisesAnswered'), 6, true).'</span></th>';
1390
        $head .= '<th style="padding:0;border-bottom:0;border-right:0;"><span>'.get_lang('LatestLogin').'</span></th>';
1391
        $head .= '</tr></table>';
1392
1393
        $addparams = ['view' => 'admin', 'display' => 'sessionoverview'];
1394
        $table = new SortableTable(
1395
            'tracking_session_overview',
1396
            ['MySpace', 'get_total_number_sessions'],
1397
            ['MySpace', 'get_session_data_tracking_overview'],
1398
            1
1399
        );
1400
        $table->additional_parameters = $addparams;
1401
1402
        $table->set_header(0, '', false, null, ['style' => 'display: none']);
1403
        $table->set_header(
1404
            1,
1405
            get_lang('Session'),
1406
            true,
1407
            ['style' => 'font-size:8pt'],
1408
            ['style' => 'font-size:8pt']
1409
        );
1410
        $table->set_header(
1411
            2,
1412
            $head,
1413
            false,
1414
            ['style' => 'width:90%;border:0;padding:0;font-size:7.5pt;'],
1415
            ['style' => 'width:90%;padding:0;font-size:7.5pt;']
1416
        );
1417
        $table->set_column_filter(2, ['MySpace', 'session_tracking_filter']);
1418
        $table->display();
1419
    }
1420
1421
    /**
1422
     * Get the total number of sessions
1423
     *
1424
     * @return integer Total number of sessions
1425
     */
1426
    public static function get_total_number_sessions()
1427
    {
1428
        return SessionManager::count_sessions(api_get_current_access_url_id());
1429
    }
1430
1431
    /**
1432
     * Get data for the sessions
1433
     *
1434
     * @param int $from Inferior limit
1435
     * @param int $numberItems Number of items to select
1436
     * @param string $column Column to order on
1437
     * @param string $direction Order direction
1438
     * @return array Results
1439
     */
1440
    public static function get_session_data_tracking_overview(
1441
        $from,
1442
        $numberItems,
1443
        $column,
1444
        $direction
1445
    ) {
1446
        $from = (int) $from;
1447
        $numberItems = (int) $numberItems;
1448
        $direction = Database::escape_string($direction);
1449
        $columnName = 'name';
1450
        if ($column === 1) {
1451
            $columnName = 'id';
1452
        }
1453
1454
        $options = [
1455
            'order' => " $columnName $direction",
1456
            'limit' => " $from,$numberItems"
1457
        ];
1458
        $sessions = SessionManager::get_sessions_admin($options);
1459
        $list = [];
1460
        foreach ($sessions as $session) {
1461
            $list[] = [
1462
                '0' => $session['id'],
1463
                'col0' => $session['id'],
1464
                '1' => strip_tags($session['name']),
1465
                'col1' => strip_tags($session['name'])
1466
            ];
1467
        }
1468
1469
        return $list;
1470
    }
1471
1472
    /**
1473
     * Fills in session reporting data
1474
     *
1475
     * @param int $session_id the id of the user
1476
     * @param array $url_params additonal url parameters
1477
     * @param array $row the row information (the other columns)
1478
     * @return string html code
1479
     */
1480
    public static function session_tracking_filter($session_id, $url_params, $row)
1481
    {
1482
        $session_id = $row[0];
1483
        // the table header
1484
        $return = '<table class="data_table" style="width: 100%;border:0;padding:0;border-collapse:collapse;table-layout: fixed">';
1485
1486
        // database table definition
1487
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
1488
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1489
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1490
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1491
1492
        // getting all the courses of the user
1493
        $sql = "SELECT * FROM $tbl_course AS c
1494
                INNER JOIN $tbl_session_rel_course AS sc
1495
                ON sc.c_id = c.id
1496
                WHERE sc.session_id = '".$session_id."'";
1497
        $result = Database::query($sql);
1498
        while ($row = Database::fetch_object($result)) {
1499
            $courseId = $row->c_id;
1500
            $courseInfo = api_get_course_info_by_id($courseId);
1501
            $return .= '<tr>';
1502
            // course code
1503
            $return .= '    <td width="157px" >'.$row->title.'</td>';
1504
            // get the users in the course
1505
            $sql = "SELECT u.user_id
1506
                    FROM $tbl_user AS u
1507
                    INNER JOIN $tbl_session_rel_course_rel_user AS scu
1508
                    ON u.user_id = scu.user_id
1509
                    WHERE scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
1510
            $result_users = Database::query($sql);
1511
            $time_spent = 0;
1512
            $progress = 0;
1513
            $nb_progress_lp = 0;
1514
            $score = 0;
1515
            $nb_score_lp = 0;
1516
            $nb_messages = 0;
1517
            $nb_assignments = 0;
1518
            $last_login_date = false;
1519
            $total_score_obtained = 0;
1520
            $total_score_possible = 0;
1521
            $total_questions_answered = 0;
1522
            while ($row_user = Database::fetch_object($result_users)) {
1523
                // get time spent in the course and session
1524
                $time_spent += Tracking::get_time_spent_on_the_course($row_user->user_id, $courseId, $session_id);
1525
                $progress_tmp = Tracking::get_avg_student_progress($row_user->user_id, $row->code, [], $session_id, true);
1526
                $progress += $progress_tmp[0];
1527
                $nb_progress_lp += $progress_tmp[1];
1528
                $score_tmp = Tracking::get_avg_student_score($row_user->user_id, $row->code, [], $session_id, true);
1529
                if (is_array($score_tmp)) {
1530
                    $score += $score_tmp[0];
1531
                    $nb_score_lp += $score_tmp[1];
1532
                }
1533
                $nb_messages += Tracking::count_student_messages($row_user->user_id, $row->code, $session_id);
1534
                $nb_assignments += Tracking::count_student_assignments($row_user->user_id, $row->code, $session_id);
1535
                $last_login_date_tmp = Tracking::get_last_connection_date_on_the_course(
1536
                    $row_user->user_id,
1537
                    $courseInfo,
1538
                    $session_id,
1539
                    false
1540
                );
1541
                if ($last_login_date_tmp != false && $last_login_date == false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1542
                    // TODO: To be cleaned.
1543
                    $last_login_date = $last_login_date_tmp;
1544
                } elseif ($last_login_date_tmp != false && $last_login_date != false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
1545
                    // TODO: Repeated previous condition! To be cleaned.
1546
                    // Find the max and assign it to first_login_date
1547
                    if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
1548
                        $last_login_date = $last_login_date_tmp;
1549
                    }
1550
                }
1551
1552
                $exercise_results_tmp = self::exercises_results($row_user->user_id, $row->code, $session_id);
1553
                $total_score_obtained += $exercise_results_tmp['score_obtained'];
1554
                $total_score_possible += $exercise_results_tmp['score_possible'];
1555
                $total_questions_answered += $exercise_results_tmp['questions_answered'];
1556
            }
1557
            if ($nb_progress_lp > 0) {
1558
                $avg_progress = round($progress / $nb_progress_lp, 2);
1559
            } else {
1560
                $avg_progress = 0;
1561
            }
1562
            if ($nb_score_lp > 0) {
1563
                $avg_score = round($score / $nb_score_lp, 2);
1564
            } else {
1565
                $avg_score = '-';
1566
            }
1567
            if ($last_login_date) {
1568
                $last_login_date = api_convert_and_format_date(
1569
                    $last_login_date,
1570
                    DATE_FORMAT_SHORT,
1571
                    date_default_timezone_get()
1572
                );
1573
            } else {
1574
                $last_login_date = '-';
1575
            }
1576
            if ($total_score_possible > 0) {
1577
                $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
1578
            } else {
1579
                $total_score_percentage = 0;
1580
            }
1581
            if ($total_score_percentage > 0) {
1582
                $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
1583
            } else {
1584
                $total_score = '-';
1585
            }
1586
            // time spent in the course
1587
            $return .= '    <td><div>'.api_time_to_hms($time_spent).'</div></td>';
1588
            // student progress in course
1589
            $return .= '    <td><div>'.$avg_progress.'</div></td>';
1590
            // student score
1591
            $return .= '    <td><div>'.$avg_score.'</div></td>';
1592
            // student messages
1593
            $return .= '    <td><div>'.$nb_messages.'</div></td>';
1594
            // student assignments
1595
            $return .= '    <td><div>'.$nb_assignments.'</div></td>';
1596
            // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
1597
            $return .= '<td width="105px;">'.$total_score.'</td>';
1598
            $return .= '<td>'.$total_questions_answered.'</td>';
1599
            // last connection
1600
            $return .= '    <td><div>'.$last_login_date.'</div></td>';
1601
            $return .= '<tr>';
1602
        }
1603
        $return .= '</table>';
1604
        return $return;
1605
    }
1606
1607
    /**
1608
     * This function exports the table that we see in display_tracking_session_overview()
1609
     *
1610
     */
1611
    public static function export_tracking_session_overview()
1612
    {
1613
        // database table definition
1614
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
1615
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1616
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1617
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
1618
1619
        // the values of the sortable table
1620
        if ($_GET['tracking_session_overview_page_nr']) {
1621
            $from = $_GET['tracking_session_overview_page_nr'];
1622
        } else {
1623
            $from = 0;
1624
        }
1625
        if ($_GET['tracking_session_overview_column']) {
1626
            $orderby = $_GET['tracking_session_overview_column'];
1627
        } else {
1628
            $orderby = 0;
1629
        }
1630
1631
        if ($_GET['tracking_session_overview_direction']) {
1632
            $direction = $_GET['tracking_session_overview_direction'];
1633
        } else {
1634
            $direction = 'ASC';
1635
        }
1636
1637
        $session_data = self::get_session_data_tracking_overview($from, 1000, $orderby, $direction);
1638
1639
        $csv_content = [];
1640
1641
        // the first line of the csv file with the column headers
1642
        $csv_row = [];
1643
        $csv_row[] = get_lang('Session');
1644
        $csv_row[] = get_lang('Course');
1645
        $csv_row[] = get_lang('AvgTimeSpentInTheCourse');
1646
        $csv_row[] = get_lang('AvgStudentsProgress');
1647
        $csv_row[] = get_lang('AvgCourseScore');
1648
        $csv_row[] = get_lang('TotalNumberOfMessages');
1649
        $csv_row[] = get_lang('TotalNumberOfAssignments');
1650
        $csv_row[] = get_lang('TotalExercisesScoreObtained');
1651
        $csv_row[] = get_lang('TotalExercisesScorePossible');
1652
        $csv_row[] = get_lang('TotalExercisesAnswered');
1653
        $csv_row[] = get_lang('TotalExercisesScorePercentage');
1654
        $csv_row[] = get_lang('LatestLogin');
1655
        $csv_content[] = $csv_row;
1656
1657
        // the other lines (the data)
1658
        foreach ($session_data as $key => $session) {
1659
            $session_id = $session[0];
1660
            $session_title = $session[1];
1661
1662
            // getting all the courses of the session
1663
            $sql = "SELECT * FROM $tbl_course AS c
1664
                    INNER JOIN $tbl_session_rel_course AS sc
1665
                    ON sc.c_id = c.id
1666
                    WHERE sc.session_id = '".$session_id."';";
1667
            $result = Database::query($sql);
1668
            while ($row = Database::fetch_object($result)) {
1669
                $courseId = $row->c_id;
1670
                $courseInfo = api_get_course_info_by_id($courseId);
1671
                $csv_row = [];
1672
                $csv_row[] = $session_title;
1673
                $csv_row[] = $row->title;
1674
                // get the users in the course
1675
                $sql = "SELECT scu.user_id
1676
                        FROM $tbl_user AS u
1677
                        INNER JOIN $tbl_session_rel_course_rel_user AS scu
1678
                        ON u.user_id = scu.user_id
1679
                        WHERE scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
1680
                $result_users = Database::query($sql);
1681
                $time_spent = 0;
1682
                $progress = 0;
1683
                $nb_progress_lp = 0;
1684
                $score = 0;
1685
                $nb_score_lp = 0;
1686
                $nb_messages = 0;
1687
                $nb_assignments = 0;
1688
                $last_login_date = false;
1689
                $total_score_obtained = 0;
1690
                $total_score_possible = 0;
1691
                $total_questions_answered = 0;
1692
                while ($row_user = Database::fetch_object($result_users)) {
1693
                    // get time spent in the course and session
1694
                    $time_spent += Tracking::get_time_spent_on_the_course($row_user->user_id, $courseId, $session_id);
1695
                    $progress_tmp = Tracking::get_avg_student_progress(
1696
                        $row_user->user_id,
1697
                        $row->code,
1698
                        [],
1699
                        $session_id,
1700
                        true
1701
                    );
1702
                    $progress += $progress_tmp[0];
1703
                    $nb_progress_lp += $progress_tmp[1];
1704
                    $score_tmp = Tracking::get_avg_student_score(
1705
                        $row_user->user_id,
1706
                        $row->code,
1707
                        [],
1708
                        $session_id,
1709
                        true
1710
                    );
1711
                    if (is_array($score_tmp)) {
1712
                        $score += $score_tmp[0];
1713
                        $nb_score_lp += $score_tmp[1];
1714
                    }
1715
                    $nb_messages += Tracking::count_student_messages(
1716
                        $row_user->user_id,
1717
                        $row->code,
1718
                        $session_id
1719
                    );
1720
1721
                    $nb_assignments += Tracking::count_student_assignments(
1722
                        $row_user->user_id,
1723
                        $row->code,
1724
                        $session_id
1725
                    );
1726
1727
                    $last_login_date_tmp = Tracking:: get_last_connection_date_on_the_course(
1728
                        $row_user->user_id,
1729
                        $courseInfo,
1730
                        $session_id,
1731
                        false
1732
                    );
1733
                    if ($last_login_date_tmp != false && $last_login_date == false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
1734
                        // TODO: To be cleaned.
1735
                        $last_login_date = $last_login_date_tmp;
1736
                    } elseif ($last_login_date_tmp != false && $last_login_date == false) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $last_login_date_tmp of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
Bug introduced by
It seems like you are loosely comparing $last_login_date of type string|boolean against false; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
1737
                        // TODO: Repeated previous condition. To be cleaned.
1738
                        // Find the max and assign it to first_login_date
1739
                        if (strtotime($last_login_date_tmp) > strtotime($last_login_date)) {
0 ignored issues
show
Bug introduced by
It seems like $last_login_date_tmp can also be of type true; however, parameter $time of strtotime() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

1739
                        if (strtotime(/** @scrutinizer ignore-type */ $last_login_date_tmp) > strtotime($last_login_date)) {
Loading history...
1740
                            $last_login_date = $last_login_date_tmp;
1741
                        }
1742
                    }
1743
1744
                    $exercise_results_tmp = self::exercises_results($row_user->user_id, $row->code, $session_id);
1745
                    $total_score_obtained += $exercise_results_tmp['score_obtained'];
1746
                    $total_score_possible += $exercise_results_tmp['score_possible'];
1747
                    $total_questions_answered += $exercise_results_tmp['questions_answered'];
1748
                }
1749
                if ($nb_progress_lp > 0) {
1750
                    $avg_progress = round($progress / $nb_progress_lp, 2);
1751
                } else {
1752
                    $avg_progress = 0;
1753
                }
1754
                if ($nb_score_lp > 0) {
1755
                    $avg_score = round($score / $nb_score_lp, 2);
1756
                } else {
1757
                    $avg_score = '-';
1758
                }
1759
                if ($last_login_date) {
1760
                    $last_login_date = api_convert_and_format_date(
1761
                        $last_login_date,
1762
                        DATE_FORMAT_SHORT,
1763
                        date_default_timezone_get()
1764
                    );
1765
                } else {
1766
                    $last_login_date = '-';
1767
                }
1768
                if ($total_score_possible > 0) {
1769
                    $total_score_percentage = round($total_score_obtained / $total_score_possible * 100, 2);
1770
                } else {
1771
                    $total_score_percentage = 0;
1772
                }
1773
                if ($total_score_percentage > 0) {
1774
                    $total_score = $total_score_obtained.'/'.$total_score_possible.' ('.$total_score_percentage.' %)';
1775
                } else {
1776
                    $total_score = '-';
1777
                }
1778
                // time spent in the course
1779
                $csv_row[] = api_time_to_hms($time_spent);
1780
                // student progress in course
1781
                $csv_row[] = $avg_progress;
1782
                // student score
1783
                $csv_row[] = $avg_score;
1784
                // student messages
1785
                $csv_row[] = $nb_messages;
1786
                // student assignments
1787
                $csv_row[] = $nb_assignments;
1788
                // student exercises results (obtained score, maximum score, number of exercises answered, score percentage)
1789
                $csv_row[] = $total_score_obtained;
1790
                $csv_row[] = $total_score_possible;
1791
                $csv_row[] = $total_questions_answered;
1792
                $csv_row[] = $total_score_percentage;
1793
                // last connection
1794
                $csv_row[] = $last_login_date;
1795
                $csv_content[] = $csv_row;
1796
            }
1797
        }
1798
        Export::arrayToCsv($csv_content, 'reporting_session_overview');
1799
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1800
    }
1801
1802
    /**
1803
     * Get general information about the exercise performance of the user
1804
     * the total obtained score (all the score on all the questions)
1805
     * the maximum score that could be obtained
1806
     * the number of questions answered
1807
     * the success percentage
1808
     * @param integer $user_id the id of the user
1809
     * @param string $course_code the course code
1810
     * @return array
1811
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1812
     * @version Dokeos 1.8.6
1813
     * @since November 2008
1814
     */
1815
    public static function exercises_results($user_id, $course_code, $session_id = false)
1816
    {
1817
        $courseId = api_get_course_int_id($course_code);
1818
        $sql = 'SELECT exe_result, exe_weighting
1819
                FROM '.Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES)."
1820
                WHERE 
1821
                    c_id = ' . $courseId . ' AND 
1822
                    exe_user_id = '".intval($user_id)."'";
1823
        if ($session_id !== false) {
1824
            $sql .= " AND session_id = '".$session_id."' ";
1825
        }
1826
        $result = Database::query($sql);
1827
        $score_obtained = 0;
1828
        $score_possible = 0;
1829
        $questions_answered = 0;
1830
        while ($row = Database::fetch_array($result)) {
1831
            $score_obtained += $row['exe_result'];
1832
            $score_possible += $row['exe_weighting'];
1833
            $questions_answered++;
1834
        }
1835
1836
        if ($score_possible != 0) {
1837
            $percentage = round(($score_obtained / $score_possible * 100), 2);
1838
        } else {
1839
            $percentage = null;
1840
        }
1841
1842
        return [
1843
            'score_obtained' => $score_obtained,
1844
            'score_possible' => $score_possible,
1845
            'questions_answered' => $questions_answered,
1846
            'percentage' => $percentage
1847
        ];
1848
    }
1849
1850
    /**
1851
     * This function exports the table that we see in display_tracking_user_overview()
1852
     *
1853
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
1854
     * @version Dokeos 1.8.6
1855
     * @since October 2008
1856
     */
1857
    public static function export_tracking_user_overview()
1858
    {
1859
        // database table definitions
1860
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1861
        $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
1862
1863
        // the values of the sortable table
1864
        if ($_GET['tracking_user_overview_page_nr']) {
1865
            $from = $_GET['tracking_user_overview_page_nr'];
1866
        } else {
1867
            $from = 0;
1868
        }
1869
        if ($_GET['tracking_user_overview_column']) {
1870
            $orderby = $_GET['tracking_user_overview_column'];
1871
        } else {
1872
            $orderby = 0;
1873
        }
1874
        if ($is_western_name_order != api_is_western_name_order() && ($orderby == 1 || $orderby == 2)) {
1875
            // Swapping the sorting column if name order for export is different than the common name order.
1876
            $orderby = 3 - $orderby;
1877
        }
1878
        if ($_GET['tracking_user_overview_direction']) {
1879
            $direction = $_GET['tracking_user_overview_direction'];
1880
        } else {
1881
            $direction = 'ASC';
1882
        }
1883
1884
        $user_data = self::get_user_data_tracking_overview(
1885
            $from,
1886
            1000,
1887
            $orderby,
1888
            $direction
1889
        );
1890
1891
        // the first line of the csv file with the column headers
1892
        $csv_row = [];
1893
        $csv_row[] = get_lang('OfficialCode');
1894
        if ($is_western_name_order) {
1895
            $csv_row[] = get_lang('FirstName', '');
1896
            $csv_row[] = get_lang('LastName', '');
1897
        } else {
1898
            $csv_row[] = get_lang('LastName', '');
1899
            $csv_row[] = get_lang('FirstName', '');
1900
        }
1901
        $csv_row[] = get_lang('LoginName');
1902
        $csv_row[] = get_lang('CourseCode');
1903
        // the additional user defined fields (only those that were selected to be exported)
1904
1905
        $fields = UserManager::get_extra_fields(0, 50, 5, 'ASC');
1906
1907
        $additionalExportFields = Session::read('additional_export_fields');
1908
1909
        if (is_array($additionalExportFields)) {
1910
            foreach ($additionalExportFields as $key => $extra_field_export) {
1911
                $csv_row[] = $fields[$extra_field_export][3];
1912
                $field_names_to_be_exported[] = 'extra_'.$fields[$extra_field_export][1];
1913
            }
1914
        }
1915
        $csv_row[] = get_lang('AvgTimeSpentInTheCourse', '');
1916
        $csv_row[] = get_lang('AvgStudentsProgress', '');
1917
        $csv_row[] = get_lang('AvgCourseScore', '');
1918
        $csv_row[] = get_lang('AvgExercisesScore', '');
1919
        $csv_row[] = get_lang('AvgMessages', '');
1920
        $csv_row[] = get_lang('AvgAssignments', '');
1921
        $csv_row[] = get_lang('TotalExercisesScoreObtained', '');
1922
        $csv_row[] = get_lang('TotalExercisesScorePossible', '');
1923
        $csv_row[] = get_lang('TotalExercisesAnswered', '');
1924
        $csv_row[] = get_lang('TotalExercisesScorePercentage', '');
1925
        $csv_row[] = get_lang('FirstLogin', '');
1926
        $csv_row[] = get_lang('LatestLogin', '');
1927
        $csv_content[] = $csv_row;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$csv_content was never initialized. Although not strictly required by PHP, it is generally a good practice to add $csv_content = array(); before regardless.
Loading history...
1928
1929
        // the other lines (the data)
1930
        foreach ($user_data as $key => $user) {
1931
            // getting all the courses of the user
1932
            $sql = "SELECT * FROM $tbl_course_user
1933
                    WHERE user_id = '".intval($user[4])."' AND relation_type<>".COURSE_RELATION_TYPE_RRHH." ";
1934
            $result = Database::query($sql);
1935
            while ($row = Database::fetch_row($result)) {
1936
                $courseInfo = api_get_course_info($row['course_code']);
1937
                $courseId = $courseInfo['real_id'];
1938
1939
                $csv_row = [];
1940
                // user official code
1941
                $csv_row[] = $user[0];
1942
                // user first|last name
1943
                $csv_row[] = $user[1];
1944
                // user last|first name
1945
                $csv_row[] = $user[2];
1946
                // user login name
1947
                $csv_row[] = $user[3];
1948
                // course code
1949
                $csv_row[] = $row[0];
1950
                // the additional defined user fields
1951
                $extra_fields = self::get_user_overview_export_extra_fields($user[4]);
1952
1953
                if (is_array($field_names_to_be_exported)) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $field_names_to_be_exported does not seem to be defined for all execution paths leading up to this point.
Loading history...
1954
                    foreach ($field_names_to_be_exported as $key => $extra_field_export) {
1955
                        $csv_row[] = $extra_fields[$extra_field_export];
1956
                    }
1957
                }
1958
                // time spent in the course
1959
                $csv_row[] = api_time_to_hms(Tracking::get_time_spent_on_the_course($user[4], $courseId));
1960
                // student progress in course
1961
                $csv_row[] = round(Tracking::get_avg_student_progress($user[4], $row[0]), 2);
1962
                // student score
1963
                $csv_row[] = round(Tracking::get_avg_student_score($user[4], $row[0]), 2);
1964
                // student tes score
1965
                $csv_row[] = round(Tracking::get_avg_student_exercise_score($user[4], $row[0]), 2);
1966
                // student messages
1967
                $csv_row[] = Tracking::count_student_messages($user[4], $row[0]);
1968
                // student assignments
1969
                $csv_row[] = Tracking::count_student_assignments($user[4], $row[0]);
1970
                // student exercises results
1971
                $exercises_results = self::exercises_results($user[4], $row[0]);
1972
                $csv_row[] = $exercises_results['score_obtained'];
1973
                $csv_row[] = $exercises_results['score_possible'];
1974
                $csv_row[] = $exercises_results['questions_answered'];
1975
                $csv_row[] = $exercises_results['percentage'];
1976
                // first connection
1977
                $csv_row[] = Tracking::get_first_connection_date_on_the_course($user[4], $courseId);
1978
                // last connection
1979
                $csv_row[] = strip_tags(Tracking::get_last_connection_date_on_the_course($user[4], $courseInfo));
1980
1981
                $csv_content[] = $csv_row;
1982
            }
1983
        }
1984
        Export::arrayToCsv($csv_content, 'reporting_user_overview');
1985
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1986
    }
1987
1988
    /**
1989
     * Get data for courses list in sortable with pagination
1990
     * @return array
1991
     */
1992
    public static function get_course_data($from, $number_of_items, $column, $direction)
1993
    {
1994
        global $courses, $csv_content, $charset, $session_id;
1995
1996
        // definition database tables
1997
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1998
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1999
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2000
2001
        $course_data = [];
2002
        $courses_code = array_keys($courses);
2003
2004
        foreach ($courses_code as &$code) {
2005
            $code = "'$code'";
2006
        }
2007
2008
        // get all courses with limit
2009
        $sql = "SELECT course.code as col1, course.title as col2
2010
                FROM $tbl_course course
2011
                WHERE course.code IN (".implode(',', $courses_code).")";
2012
2013
        if (!in_array($direction, ['ASC', 'DESC'])) {
2014
            $direction = 'ASC';
2015
        }
2016
2017
        $column = intval($column);
2018
        $from = intval($from);
2019
        $number_of_items = intval($number_of_items);
2020
        $sql .= " ORDER BY col$column $direction ";
2021
        $sql .= " LIMIT $from,$number_of_items";
2022
2023
        $res = Database::query($sql);
2024
        while ($row_course = Database::fetch_row($res)) {
2025
            $course_code = $row_course[0];
2026
            $courseInfo = api_get_course_info($course_code);
2027
            $courseId = $courseInfo['real_id'];
2028
            $avg_assignments_in_course = $avg_messages_in_course = $nb_students_in_course = $avg_progress_in_course = $avg_score_in_course = $avg_time_spent_in_course = $avg_score_in_exercise = 0;
2029
2030
            // students directly subscribed to the course
2031
            if (empty($session_id)) {
2032
                $sql = "SELECT user_id
2033
                        FROM $tbl_course_user as course_rel_user
2034
                        WHERE
2035
                            course_rel_user.status='5' AND
2036
                            course_rel_user.c_id = '$courseId'";
2037
            } else {
2038
                $sql = "SELECT user_id FROM $tbl_session_course_user srcu
2039
                        WHERE
2040
                            c_id = '$courseId' AND
2041
                            session_id = '$session_id' AND
2042
                            status<>2";
2043
            }
2044
            $rs = Database::query($sql);
2045
            $users = [];
2046
            while ($row = Database::fetch_array($rs)) {
2047
                $users[] = $row['user_id'];
2048
            }
2049
2050
            if (count($users) > 0) {
2051
                $nb_students_in_course = count($users);
2052
                $avg_assignments_in_course = Tracking::count_student_assignments($users, $course_code, $session_id);
2053
                $avg_messages_in_course = Tracking::count_student_messages($users, $course_code, $session_id);
2054
                $avg_progress_in_course = Tracking::get_avg_student_progress($users, $course_code, [], $session_id);
2055
                $avg_score_in_course = Tracking::get_avg_student_score($users, $course_code, [], $session_id);
2056
                $avg_score_in_exercise = Tracking::get_avg_student_exercise_score($users, $course_code, 0, $session_id);
2057
                $avg_time_spent_in_course = Tracking::get_time_spent_on_the_course(
2058
                    $users,
2059
                    $courseInfo['real_id'],
2060
                    $session_id
2061
                );
2062
2063
                $avg_progress_in_course = round($avg_progress_in_course / $nb_students_in_course, 2);
2064
                if (is_numeric($avg_score_in_course)) {
2065
                    $avg_score_in_course = round($avg_score_in_course / $nb_students_in_course, 2);
2066
                }
2067
                $avg_time_spent_in_course = api_time_to_hms($avg_time_spent_in_course / $nb_students_in_course);
2068
            } else {
2069
                $avg_time_spent_in_course = null;
2070
                $avg_progress_in_course = null;
2071
                $avg_score_in_course = null;
2072
                $avg_score_in_exercise = null;
2073
                $avg_messages_in_course = null;
2074
                $avg_assignments_in_course = null;
2075
            }
2076
            $table_row = [];
2077
            $table_row[] = $row_course[1];
2078
            $table_row[] = $nb_students_in_course;
2079
            $table_row[] = $avg_time_spent_in_course;
2080
            $table_row[] = is_null($avg_progress_in_course) ? '' : $avg_progress_in_course.'%';
2081
            $table_row[] = is_null($avg_score_in_course) ? '' : $avg_score_in_course.'%';
2082
            $table_row[] = is_null($avg_score_in_exercise) ? '' : $avg_score_in_exercise.'%';
2083
            $table_row[] = $avg_messages_in_course;
2084
            $table_row[] = $avg_assignments_in_course;
2085
2086
            //set the "from" value to know if I access the Reporting by the chamilo tab or the course link
2087
            $table_row[] = '<center><a href="../../tracking/courseLog.php?cidReq='.$course_code.'&from=myspace&id_session='.$session_id.'">
2088
                             '.Display::return_icon('2rightarrow.png', get_lang('Details')).'
2089
                             </a>
2090
                            </center>';
2091
            $csv_content[] = [
2092
                api_html_entity_decode($row_course[1], ENT_QUOTES, $charset),
2093
                $nb_students_in_course,
2094
                $avg_time_spent_in_course,
2095
                is_null($avg_progress_in_course) ? null : $avg_progress_in_course.'%',
2096
                is_null($avg_score_in_course) ? null : is_numeric($avg_score_in_course) ? $avg_score_in_course.'%' : $avg_score_in_course,
2097
                is_null($avg_score_in_exercise) ? null : $avg_score_in_exercise.'%',
2098
                $avg_messages_in_course,
2099
                $avg_assignments_in_course,
2100
            ];
2101
            $course_data[] = $table_row;
2102
        }
2103
        return $course_data;
2104
    }
2105
2106
    /**
2107
     * Get the number of users of the platform
2108
     *
2109
     * @return integer
2110
     *
2111
     */
2112
    public static function get_number_of_users_tracking_overview()
2113
    {
2114
        return UserManager::get_number_of_users(0, api_get_current_access_url_id());
0 ignored issues
show
Bug Best Practice introduced by
The expression return UserManager::get_...urrent_access_url_id()) could also return false which is incompatible with the documented return type integer. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
2115
    }
2116
2117
    /**
2118
     * Get all the data for the sortable table of the reporting progress of
2119
     * all users and all the courses the user is subscribed to.
2120
     *
2121
     * @param int $from
2122
     * @param int $numberItems
2123
     * @param int $column
2124
     * @param string $direction
2125
     * @return array
2126
     */
2127
    public static function get_user_data_tracking_overview($from, $numberItems, $column, $direction)
2128
    {
2129
        $isWestern = api_is_western_name_order();
2130
        switch ($column) {
2131
            case '0':
2132
                $column = 'official_code';
2133
                break;
2134
            case '1':
2135
                $column = $isWestern ? 'firstname' : 'lastname';
2136
                break;
2137
            case '2':
2138
                $column = $isWestern ? 'lastname' : 'firstname';
2139
                break;
2140
            case '3':
2141
                $column = 'username';
2142
                break;
2143
            case '4':
2144
                $column = 'username';
2145
                break;
2146
        }
2147
2148
        $order = [
2149
            "$column $direction"
2150
        ];
2151
        $userList = UserManager::get_user_list([], $order, $from, $numberItems);
2152
        $return = [];
2153
        foreach ($userList as $user) {
2154
            $firstPosition = $user['lastname'];
2155
            $secondPosition = $user['firstname'];
2156
            if ($isWestern) {
2157
                $firstPosition = $user['firstname'];
2158
                $secondPosition = $user['lastname'];
2159
            }
2160
            $return[] = [
2161
                '0' => $user['official_code'],
2162
                'col0' => $user['official_code'],
2163
                '1' => $firstPosition,
2164
                'col1' => $firstPosition,
2165
                '2' => $secondPosition,
2166
                'col2' => $secondPosition,
2167
                '3' => $user['username'],
2168
                'col3' => $user['username'],
2169
                '4' => $user['user_id'],
2170
                'col4' => $user['user_id']
2171
            ];
2172
        }
2173
2174
        return $return;
2175
    }
2176
2177
    /**
2178
     * Get all information that the user with user_id = $user_data has
2179
     * entered in the additionally defined profile fields
2180
     * @param integer $user_id the id of the user
2181
     * @return array
2182
     * @author Patrick Cool <[email protected]>, Ghent University, Belgium
2183
     * @version Dokeos 1.8.6
2184
     * @since November 2008
2185
     */
2186
    public static function get_user_overview_export_extra_fields($user_id)
2187
    {
2188
        // include the user manager
2189
        $extra_data = UserManager::get_extra_user_data($user_id, true);
2190
        return $extra_data;
2191
    }
2192
2193
    /**
2194
     * Checks if a username exist in the DB otherwise it create a "double"
2195
     * i.e. if we look into for jmontoya but the user's name already exist we create the user jmontoya2
2196
     * the return array will be array(username=>'jmontoya', sufix='2')
2197
     * @param string firstname
2198
     * @param string lastname
2199
     * @param string username
2200
     * @return array with the username, the sufix
2201
     * @author Julio Montoya Armas
2202
     */
2203
    public static function make_username($firstname, $lastname, $username, $language = null, $encoding = null)
2204
    {
2205
        // if username exist
2206
        if (!UserManager::is_username_available($username) || empty($username)) {
2207
            $i = 0;
2208
            while (1) {
2209
                if ($i == 0) {
2210
                    $sufix = '';
2211
                } else {
2212
                    $sufix = $i;
2213
                }
2214
                $desired_username = UserManager::create_username(
2215
                    $firstname,
2216
                    $lastname,
2217
                    $language,
2218
                    $encoding
2219
                );
2220
                if (UserManager::is_username_available($desired_username.$sufix)) {
0 ignored issues
show
Bug introduced by
Are you sure $desired_username of type false|string can be used in concatenation? ( Ignorable by Annotation )

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

2220
                if (UserManager::is_username_available(/** @scrutinizer ignore-type */ $desired_username.$sufix)) {
Loading history...
2221
                    break;
2222
                } else {
2223
                    $i++;
2224
                }
2225
            }
2226
            $username_array = ['username' => $desired_username, 'sufix' => $sufix];
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sufix does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $desired_username does not seem to be defined for all execution paths leading up to this point.
Loading history...
2227
            return $username_array;
2228
        } else {
2229
            $username_array = ['username' => $username, 'sufix' => ''];
2230
            return $username_array;
2231
        }
2232
    }
2233
2234
    /**
2235
     * Checks if there are repeted users in a given array
2236
     * @param  array $usernames list of the usernames in the uploaded file
2237
     * @param  array $user_array $user_array['username'] and $user_array['sufix']
2238
     * where suffix is the number part in a login i.e -> jmontoya2
2239
     * @return array with the $usernames array and the $user_array array
2240
     * @author Julio Montoya
2241
     */
2242
    public static function check_user_in_array($usernames, $user_array)
2243
    {
2244
        $user_list = array_keys($usernames);
2245
        $username = $user_array['username'].$user_array['sufix'];
2246
2247
        if (in_array($username, $user_list)) {
2248
            $user_array['sufix'] += $usernames[$username];
2249
            $usernames[$username]++;
2250
        } else {
2251
            $usernames[$username] = 1;
2252
        }
2253
        $result_array = [$usernames, $user_array];
2254
        return $result_array;
2255
    }
2256
2257
    /**
2258
     * Checks whether a username has been already subscribed in a session.
2259
     * @param string $username a given username
2260
     * @param array $course_list the array with the course list id
2261
     * @param int $id_session the session id
2262
     * @return int 0 if the user is not subscribed otherwise it returns the user_id of the given username
2263
     * @author Julio Montoya
2264
     */
2265
    public static function user_available_in_session($username, $course_list, $id_session)
2266
    {
2267
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2268
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2269
        $id_session = intval($id_session);
2270
        $username = Database::escape_string($username);
2271
        foreach ($course_list as $courseId) {
2272
            $courseId = intval($courseId);
2273
            $sql = " SELECT u.user_id FROM $tbl_session_rel_course_rel_user rel
2274
                     INNER JOIN $table_user u
2275
                     ON (rel.user_id = u.user_id)
2276
                     WHERE
2277
                        rel.session_id='$id_session' AND
2278
                        u.status='5' AND
2279
                        u.username ='$username' AND
2280
                        rel.c_id='$courseId'";
2281
            $rs = Database::query($sql);
2282
            if (Database::num_rows($rs) > 0) {
2283
                return Database::result($rs, 0, 0);
2284
            } else {
2285
                return 0;
2286
            }
2287
        }
2288
        return 0;
2289
    }
2290
2291
    /**
2292
     * This function checks whether some users in the uploaded file
2293
     * repeated and creates unique usernames if necesary.
2294
     * A case: Within the file there is an user repeted twice (Julio Montoya / Julio Montoya)
2295
     * and the username fields are empty.
2296
     * Then, this function would create unique usernames based on the first and the last name.
2297
     * Two users wiould be created - jmontoya and jmontoya2.
2298
     * Of course, if in the database there is a user with the name jmontoya,
2299
     * the newly created two users registered would be jmontoya2 and jmontoya3.
2300
     * @param $users list of users
2301
     * @return array
2302
     * @author Julio Montoya Armas
2303
     */
2304
    public function check_all_usernames($users, $course_list, $id_session)
2305
    {
2306
        $table_user = Database::get_main_table(TABLE_MAIN_USER);
2307
        $usernames = [];
2308
        $new_users = [];
2309
        foreach ($users as $index => $user) {
2310
            $desired_username = [];
2311
            if (empty($user['UserName'])) {
2312
                $desired_username = self::make_username($user['FirstName'], $user['LastName'], '');
2313
                $pre_username = $desired_username['username'].$desired_username['sufix'];
2314
                $user['UserName'] = $pre_username;
2315
                $user['create'] = '1';
2316
            } else {
2317
                if (UserManager::is_username_available($user['UserName'])) {
2318
                    $desired_username = self::make_username($user['FirstName'], $user['LastName'], $user['UserName']);
2319
                    $user['UserName'] = $desired_username['username'].$desired_username['sufix'];
2320
                    $user['create'] = '1';
2321
                } else {
2322
                    $is_session_avail = self::user_available_in_session($user['UserName'], $course_list, $id_session);
2323
                    if ($is_session_avail == 0) {
2324
                        $user_name = $user['UserName'];
2325
                        $sql_select = "SELECT user_id FROM $table_user WHERE username ='$user_name' ";
2326
                        $rs = Database::query($sql_select);
2327
                        $user['create'] = Database::result($rs, 0, 0);
2328
                        // This should be the ID because the user exists.
2329
                    } else {
2330
                        $user['create'] = $is_session_avail;
2331
                    }
2332
                }
2333
            }
2334
            // Usernames is the current list of users in the file.
2335
            $result_array = self::check_user_in_array($usernames, $desired_username);
2336
            $usernames = $result_array[0];
2337
            $desired_username = $result_array[1];
2338
            $user['UserName'] = $desired_username['username'].$desired_username['sufix'];
2339
            $new_users[] = $user;
2340
        }
2341
        return $new_users;
2342
    }
2343
2344
    /**
2345
     * This functions checks whether there are users that are already
2346
     * registered in the DB by different creator than the current coach.
2347
     * @param array $users
2348
     * @return array
2349
     * @author Julio Montoya Armas
2350
     */
2351
    public function get_user_creator($users)
2352
    {
2353
        $errors = [];
2354
        foreach ($users as $index => $user) {
2355
            // database table definition
2356
            $table_user = Database::get_main_table(TABLE_MAIN_USER);
2357
            $username = Database::escape_string($user['UserName']);
2358
            $sql = "SELECT creator_id FROM $table_user WHERE username='$username' ";
2359
2360
            $rs = Database::query($sql);
2361
            $creator_id = Database::result($rs, 0, 0);
2362
            // check if we are the creators or not
2363
            if ($creator_id != '') {
2364
                if ($creator_id != api_get_user_id()) {
2365
                    $user['error'] = get_lang('UserAlreadyRegisteredByOtherCreator');
2366
                    $errors[] = $user;
2367
                }
2368
            }
2369
        }
2370
2371
        return $errors;
2372
    }
2373
2374
    /**
2375
     * Validates imported data.
2376
     * @param array $users list of users
2377
     */
2378
    public function validate_data($users, $id_session = null)
2379
    {
2380
        $errors = [];
2381
        $new_users = [];
2382
        foreach ($users as $index => $user) {
2383
            // 1. Check whether mandatory fields are set.
2384
            $mandatory_fields = ['LastName', 'FirstName'];
2385
            if (api_get_setting('registration', 'email') == 'true') {
2386
                $mandatory_fields[] = 'Email';
2387
            }
2388
2389
            foreach ($mandatory_fields as $key => $field) {
2390
                if (!isset($user[$field]) || strlen($user[$field]) == 0) {
2391
                    $user['error'] = get_lang($field.'Mandatory');
2392
                    $errors[] = $user;
2393
                }
2394
            }
2395
            // 2. Check whether the username is too long.
2396
            if (UserManager::is_username_too_long($user['UserName'])) {
2397
                $user['error'] = get_lang('UserNameTooLong');
2398
                $errors[] = $user;
2399
            }
2400
2401
            $user['UserName'] = trim($user['UserName']);
2402
2403
            if (empty($user['UserName'])) {
2404
                $user['UserName'] = UserManager::create_username($user['FirstName'], $user['LastName']);
2405
            }
2406
            $new_users[] = $user;
2407
        }
2408
        $results = ['errors' => $errors, 'users' => $new_users];
2409
        return $results;
2410
    }
2411
2412
    /**
2413
     * Adds missing user-information (which isn't required, like password, etc).
2414
     */
2415
    public function complete_missing_data($user)
2416
    {
2417
        // 1. Generate a password if it is necessary.
2418
        if (!isset($user['Password']) || strlen($user['Password']) == 0) {
2419
            $user['Password'] = api_generate_password();
2420
        }
2421
2422
        return $user;
2423
    }
2424
2425
    /**
2426
     * Saves imported data.
2427
     */
2428
    public function save_data($users, $course_list, $id_session)
2429
    {
2430
        $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
2431
        $tbl_session_rel_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2432
        $tbl_session_rel_course_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2433
        $tbl_session_rel_user = Database::get_main_table(TABLE_MAIN_SESSION_USER);
2434
2435
        $id_session = intval($id_session);
2436
        $sendMail = $_POST['sendMail'] ? 1 : 0;
2437
2438
        // Adding users to the platform.
2439
        $new_users = [];
2440
        foreach ($users as $index => $user) {
2441
            $user = self::complete_missing_data($user);
0 ignored issues
show
Bug Best Practice introduced by
The method MySpace::complete_missing_data() 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

2441
            /** @scrutinizer ignore-call */ 
2442
            $user = self::complete_missing_data($user);
Loading history...
2442
            // coach only will registered users
2443
            $default_status = STUDENT;
2444
            if ($user['create'] == COURSEMANAGER) {
2445
                $user['id'] = UserManager:: create_user(
2446
                    $user['FirstName'],
2447
                    $user['LastName'],
2448
                    $default_status,
2449
                    $user['Email'],
2450
                    $user['UserName'],
2451
                    $user['Password'],
2452
                    $user['OfficialCode'],
2453
                    api_get_setting('PlatformLanguage'),
2454
                    $user['PhoneNumber'],
2455
                    ''
2456
                );
2457
                $user['added_at_platform'] = 1;
2458
            } else {
2459
                $user['id'] = $user['create'];
2460
                $user['added_at_platform'] = 0;
2461
            }
2462
            $new_users[] = $user;
2463
        }
2464
        // Update user list.
2465
        $users = $new_users;
2466
2467
        // Inserting users.
2468
        $super_list = [];
2469
        foreach ($course_list as $enreg_course) {
2470
            $nbr_users = 0;
2471
            $new_users = [];
2472
            $enreg_course = Database::escape_string($enreg_course);
2473
            foreach ($users as $index => $user) {
2474
                $userid = intval($user['id']);
2475
                $sql = "INSERT IGNORE INTO $tbl_session_rel_course_rel_user(session_id, c_id, user_id)
2476
                        VALUES('$id_session','$enreg_course','$userid')";
2477
                $course_session = ['course' => $enreg_course, 'added' => 1];
2478
2479
                $result = Database::query($sql);
2480
                if (Database::affected_rows($result)) {
2481
                    $nbr_users++;
2482
                }
2483
                $new_users[] = $user;
2484
            }
2485
            $super_list[] = $new_users;
2486
2487
            //update the nbr_users field
2488
            $sql_select = "SELECT COUNT(user_id) as nbUsers FROM $tbl_session_rel_course_rel_user
2489
                           WHERE session_id='$id_session' AND c_id='$enreg_course'";
2490
            $rs = Database::query($sql_select);
2491
            list($nbr_users) = Database::fetch_array($rs);
2492
            $sql_update = "UPDATE $tbl_session_rel_course SET nbr_users=$nbr_users
2493
                           WHERE session_id='$id_session' AND c_id='$enreg_course'";
2494
            Database::query($sql_update);
2495
2496
            $sql_update = "UPDATE $tbl_session SET nbr_users= '$nbr_users' WHERE id='$id_session'";
2497
            Database::query($sql_update);
2498
        }
2499
2500
        $new_users = [];
2501
        foreach ($users as $index => $user) {
2502
            $userid = $user['id'];
2503
            $sql_insert = "INSERT IGNORE INTO $tbl_session_rel_user(session_id, user_id, registered_at)
2504
                           VALUES ('$id_session','$userid', '".api_get_utc_datetime()."')";
2505
            Database::query($sql_insert);
2506
            $user['added_at_session'] = 1;
2507
            $new_users[] = $user;
2508
        }
2509
2510
        $users = $new_users;
2511
        $registered_users = get_lang('FileImported').'<br /> Import file results : <br />';
2512
        // Sending emails.
2513
        $addedto = '';
2514
        if ($sendMail) {
2515
            $i = 0;
2516
            foreach ($users as $index => $user) {
2517
                $emailsubject = '['.api_get_setting('siteName').'] '.get_lang('YourReg').' '.api_get_setting('siteName');
2518
                $emailbody = get_lang('Dear').' '.
2519
                    api_get_person_name($user['FirstName'], $user['LastName']).",\n\n".
2520
                    get_lang('YouAreReg')." ".api_get_setting('siteName')." ".get_lang('WithTheFollowingSettings')."\n\n".
2521
                    get_lang('Username')." : $user[UserName]\n".
2522
                    get_lang('Pass')." : $user[Password]\n\n".
2523
                    get_lang('Address')." ".api_get_setting('siteName')." ".get_lang('Is')." : ".api_get_path(WEB_PATH)." \n\n".
2524
                    get_lang('Problem')."\n\n".
2525
                    get_lang('SignatureFormula').",\n\n".
2526
                    api_get_person_name(api_get_setting('administratorName'), api_get_setting('administratorSurname'))."\n".
2527
                    get_lang('Manager')." ".api_get_setting('siteName')."\nT. ".
2528
                    api_get_setting('administratorTelephone')."\n".get_lang('Email')." : ".api_get_setting('emailAdministrator');
2529
2530
                api_mail_html(
2531
                    api_get_person_name($user['FirstName'], $user['LastName'], null, PERSON_NAME_EMAIL_ADDRESS),
2532
                    $user['Email'],
2533
                    $emailsubject,
2534
                    $emailbody
2535
                );
2536
                $userInfo = api_get_user_info($user['id']);
2537
2538
                if (($user['added_at_platform'] == 1 && $user['added_at_session'] == 1) || $user['added_at_session'] == 1) {
2539
                    if ($user['added_at_platform'] == 1) {
2540
                        $addedto = get_lang('UserCreatedPlatform');
2541
                    } else {
2542
                        $addedto = '          ';
2543
                    }
2544
2545
                    if ($user['added_at_session'] == 1) {
2546
                        $addedto .= get_lang('UserInSession');
2547
                    }
2548
                } else {
2549
                    $addedto = get_lang('UserNotAdded');
2550
                }
2551
2552
                $registered_users .= UserManager::getUserProfileLink($userInfo)." - ".$addedto.'<br />';
2553
            }
2554
        } else {
2555
            $i = 0;
2556
            foreach ($users as $index => $user) {
2557
                $userInfo = api_get_user_info($user['id']);
2558
                if (($user['added_at_platform'] == 1 && $user['added_at_session'] == 1) || $user['added_at_session'] == 1) {
2559
                    if ($user['added_at_platform'] == 1) {
2560
                        $addedto = get_lang('UserCreatedPlatform');
2561
                    } else {
2562
                        $addedto = '          ';
2563
                    }
2564
2565
                    if ($user['added_at_session'] == 1) {
2566
                        $addedto .= ' '.get_lang('UserInSession');
2567
                    }
2568
                } else {
2569
                    $addedto = get_lang('UserNotAdded');
2570
                }
2571
                $registered_users .= "<a href=\"../user/userInfo.php?uInfo=".$user['id']."\">".
2572
                    api_get_person_name($user['FirstName'], $user['LastName'])."</a> - ".$addedto.'<br />';
2573
            }
2574
        }
2575
        Display::addFlash(Display::return_message($registered_users));
2576
        header('Location: course.php?id_session='.$id_session);
2577
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
2578
    }
2579
2580
    /**
2581
     * Reads CSV-file.
2582
     * @param string $file Path to the CSV-file
2583
     * @return array All userinformation read from the file
2584
     */
2585
    public function parse_csv_data($file)
2586
    {
2587
        $users = Import::csvToArray($file);
2588
        foreach ($users as $index => $user) {
2589
            if (isset($user['Courses'])) {
2590
                $user['Courses'] = explode('|', trim($user['Courses']));
2591
            }
2592
            $users[$index] = $user;
2593
        }
2594
        return $users;
2595
    }
2596
2597
    /**
2598
     * XML-parser: the handler at the beginning of element.
2599
     */
2600
    public function element_start($parser, $data)
2601
    {
2602
        $data = api_utf8_decode($data);
2603
        global $user;
2604
        global $current_tag;
2605
        switch ($data) {
2606
            case 'Contact':
2607
                $user = [];
2608
                break;
2609
            default:
2610
                $current_tag = $data;
2611
        }
2612
    }
2613
2614
    /**
2615
     * XML-parser: the handler at the end of element.
2616
     */
2617
    public function element_end($parser, $data)
2618
    {
2619
        $data = api_utf8_decode($data);
2620
        global $user;
2621
        global $users;
2622
        global $current_value;
2623
        global $purification_option_for_usernames;
2624
        $user[$data] = $current_value;
2625
        switch ($data) {
2626
            case 'Contact':
2627
                $user['UserName'] = UserManager::purify_username($user['UserName'], $purification_option_for_usernames);
2628
                $users[] = $user;
2629
                break;
2630
            default:
2631
                $user[$data] = $current_value;
2632
                break;
2633
        }
2634
    }
2635
2636
    /**
2637
     * XML-parser: the handler for character data.
2638
     */
2639
    public function character_data($parser, $data)
2640
    {
2641
        $data = trim(api_utf8_decode($data));
2642
        global $current_value;
2643
        $current_value = $data;
2644
    }
2645
2646
    /**
2647
     * Reads XML-file.
2648
     * @param string $file Path to the XML-file
2649
     * @return array All userinformation read from the file
2650
     */
2651
    public function parse_xml_data($file)
2652
    {
2653
        global $current_tag;
2654
        global $current_value;
2655
        global $user;
2656
        global $users;
2657
        $users = [];
2658
        $parser = xml_parser_create('UTF-8');
2659
        xml_set_element_handler($parser, ['MySpace', 'element_start'], ['MySpace', 'element_end']);
2660
        xml_set_character_data_handler($parser, "character_data");
2661
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false);
2662
        xml_parse($parser, api_utf8_encode_xml(file_get_contents($file)));
2663
        xml_parser_free($parser);
2664
        return $users;
2665
    }
2666
2667
    public static function displayTrackingAccessOverView($courseId, $sessionId, $studentId)
2668
    {
2669
        $courseId = intval($courseId);
2670
        $sessionId = intval($sessionId);
2671
        $studentId = intval($studentId);
2672
2673
        $em = Database::getManager();
2674
        $sessionRepo = $em->getRepository('ChamiloCoreBundle:Session');
2675
2676
        $courseList = [];
2677
        $sessionList = [];
2678
        $studentList = [];
2679
2680
        if (!empty($courseId)) {
2681
            $course = $em->find('ChamiloCoreBundle:Course', $courseId);
2682
2683
            $courseList[$course->getId()] = $course->getTitle();
2684
        }
2685
2686
        if (!empty($sessionId)) {
2687
            $session = $em->find('ChamiloCoreBundle:Session', $sessionId);
2688
2689
            $sessionList[$session->getId()] = $session->getName();
2690
        }
2691
2692
        if (!empty($studentId)) {
2693
            $student = api_get_user_entity($studentId);
2694
            if ($student) {
2695
                $studentList[$student->getId()] = $student->getCompleteName();
2696
            }
2697
        }
2698
2699
        $form = new FormValidator('access_overview', 'GET');
2700
        $form->addElement(
2701
            'select_ajax',
2702
            'course_id',
2703
            get_lang('SearchCourse'),
2704
            $courseList,
2705
            [
2706
                'url' => api_get_path(WEB_AJAX_PATH).'course.ajax.php?'.http_build_query([
2707
                    'a' => 'search_course_by_session_all',
2708
                    'session_id' => $sessionId
2709
                ])
2710
            ]
2711
        );
2712
        $form->addElement(
2713
            'select_ajax',
2714
            'session_id',
2715
            get_lang('SearchSession'),
2716
            $sessionList,
2717
            [
2718
                'url_function' => "
2719
                    function () {
2720
                        var params = $.param({
2721
                            a: 'search_session_by_course',
2722
                            course_id: $('#course_id').val() || 0
2723
                        });
2724
2725
                        return '" . api_get_path(WEB_AJAX_PATH)."session.ajax.php?' + params;
2726
                    }
2727
                "
2728
            ]
2729
        );
2730
        $form->addSelect(
2731
            'profile',
2732
            get_lang('Profile'),
2733
            [
2734
                '' => get_lang('Select'),
2735
                STUDENT => get_lang('Student'),
2736
                COURSEMANAGER => get_lang('CourseManager'),
2737
                DRH => get_lang('Drh')
2738
            ],
2739
            ['id' => 'profile']
2740
        );
2741
        $form->addElement(
2742
            'select_ajax',
2743
            'student_id',
2744
            get_lang('SearchUsers'),
2745
            $studentList,
2746
            [
2747
                'placeholder' => get_lang('All'),
2748
                'url_function' => "
2749
                    function () {
2750
                        var params = $.param({
2751
                            a: 'search_user_by_course',
2752
                            session_id: $('#session_id').val(),
2753
                            course_id: $('#course_id').val()
2754
                        });
2755
2756
                        return '" . api_get_path(WEB_AJAX_PATH)."course.ajax.php?' + params;
2757
                    }
2758
                "
2759
            ]
2760
        );
2761
        $form->addDateRangePicker(
2762
            'date',
2763
            get_lang('DateRange'),
2764
            true,
2765
            [
2766
                'id' => 'date_range',
2767
                'format' => 'YYYY-MM-DD',
2768
                'timePicker' => 'false',
2769
                'validate_format' => 'Y-m-d'
2770
            ]
2771
        );
2772
        $form->addHidden('display', 'accessoverview');
2773
        $form->addRule('course_id', get_lang('Required'), 'required');
2774
        $form->addRule('profile', get_lang('Required'), 'required');
2775
        $form->addButton('submit', get_lang('Generate'), 'gear', 'primary');
2776
2777
        $table = null;
2778
2779
        if ($form->validate()) {
2780
            $table = new SortableTable(
2781
                'tracking_access_overview',
2782
                ['MySpace', 'getNumberOfTrackAccessOverview'],
2783
                ['MySpace', 'getUserDataAccessTrackingOverview'],
2784
                0
2785
            );
2786
            $table->additional_parameters = $form->exportValues();
2787
2788
            $table->set_header(0, get_lang('LoginDate'), true);
2789
            $table->set_header(1, get_lang('Username'), true);
2790
            if (api_is_western_name_order()) {
2791
                $table->set_header(2, get_lang('FirstName'), true);
2792
                $table->set_header(3, get_lang('LastName'), true);
2793
            } else {
2794
                $table->set_header(2, get_lang('LastName'), true);
2795
                $table->set_header(3, get_lang('FirstName'), true);
2796
            }
2797
            $table->set_header(4, get_lang('Clicks'), false);
2798
            $table->set_header(5, get_lang('IP'), false);
2799
            $table->set_header(6, get_lang('TimeLoggedIn'), false);
2800
        }
2801
2802
        $template = new Template(
2803
            null,
2804
            false,
2805
            false,
2806
            false,
2807
            false,
2808
            false,
2809
            false
2810
        );
2811
        $template->assign('form', $form->returnForm());
2812
        $template->assign('table', $table ? $table->return_table() : null);
2813
2814
        echo $template->fetch(
2815
            $template->get_template('my_space/accessoverview.tpl')
2816
        );
2817
    }
2818
2819
    /**
2820
     * @return int
2821
     */
2822
    public static function getNumberOfTrackAccessOverview()
2823
    {
2824
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2825
        $sql = "SELECT COUNT(course_access_id) count FROM $table";
2826
        $result = Database::query($sql);
2827
        $row = Database::fetch_assoc($result);
2828
2829
        return $row['count'];
2830
    }
2831
2832
    /**
2833
     * @param $from
2834
     * @param $numberItems
2835
     * @param $column
2836
     * @param $orderDirection
2837
     * @return array
2838
     */
2839
    public static function getUserDataAccessTrackingOverview(
2840
        $from,
2841
        $numberItems,
2842
        $column,
2843
        $orderDirection
2844
    ) {
2845
        $user = Database::get_main_table(TABLE_MAIN_USER);
2846
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
2847
        $track_e_login = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
2848
        $track_e_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2849
2850
        global $export_csv;
2851
2852
        if ($export_csv) {
2853
            $is_western_name_order = api_is_western_name_order(PERSON_NAME_DATA_EXPORT);
2854
        } else {
2855
            $is_western_name_order = api_is_western_name_order();
2856
        }
2857
2858
        //TODO add course name
2859
        $sql = "SELECT
2860
                a.login_course_date as col0,
2861
                u.username as col1,
2862
                " . (
2863
                    $is_western_name_order ? "
2864
                        u.firstname AS col2,
2865
                        u.lastname AS col3,
2866
                    " : "
2867
                        u.lastname AS col2,
2868
                        u.firstname AS col3,
2869
                "
2870
        )."
2871
                a.logout_course_date,
2872
                c.title,
2873
                c.code,
2874
                u.user_id
2875
            FROM $track_e_course_access a
2876
            INNER JOIN $user u ON a.user_id = u.user_id
2877
            INNER JOIN $course c ON a.c_id = c.id";
2878
2879
        if (isset($_GET['session_id']) && !empty($_GET['session_id'])) {
2880
            $sessionId = intval($_GET['session_id']);
2881
            $sql .= " WHERE a.session_id = ".$sessionId;
2882
        }
2883
2884
        $sql .= " ORDER BY col$column $orderDirection ";
2885
        $sql .= " LIMIT $from,$numberItems";
2886
        $result = Database::query($sql);
2887
2888
        $data = [];
2889
        while ($user = Database::fetch_assoc($result)) {
2890
            $data[] = $user;
2891
        }
2892
2893
        $return = [];
2894
        //TODO: Dont use numeric index
2895
        foreach ($data as $key => $info) {
2896
            $start_date = $info['col0'];
2897
            $end_date = $info['logout_course_date'];
2898
2899
            $return[$info['user_id']] = [
2900
                $start_date,
2901
                $info['col1'],
2902
                $info['col2'],
2903
                $info['col3'],
2904
                $info['user_id'],
2905
                'ip',
2906
                //TODO is not correct/precise, it counts the time not logged between two loggins
2907
                gmdate("H:i:s", strtotime($end_date) - strtotime($start_date))
2908
            ];
2909
        }
2910
2911
        foreach ($return as $key => $info) {
2912
            $ipResult = Database::select(
2913
                'user_ip',
2914
                $track_e_login,
2915
                ['where' => [
2916
                    '? BETWEEN login_date AND logout_date' => $info[0]
2917
                ]],
2918
                'first'
2919
            );
2920
2921
            $return[$key][5] = $ipResult['user_ip'];
2922
        }
2923
2924
        return $return;
2925
    }
2926
2927
    /**
2928
     * Gets the connections to a course as an array of login and logout time
2929
     *
2930
     * @param   int $user_id
2931
     * @param   array $course_info
2932
     * @param int $sessionId
2933
     * @param string $start_date
2934
     * @param string $end_date
2935
     * @author  Jorge Frisancho Jibaja
2936
     * @author  Julio Montoya <[email protected]> fixing the function
2937
     * @version OCT-22- 2010
2938
     * @return  array
2939
     */
2940
    public static function get_connections_to_course_by_date(
2941
        $user_id,
2942
        $course_info,
2943
        $sessionId,
2944
        $start_date,
2945
        $end_date
2946
    ) {
2947
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2948
        $user_id = intval($user_id);
2949
        $connections = [];
2950
        if (!empty($course_info)) {
2951
            $courseId = intval($course_info['real_id']);
2952
            $end_date = add_day_to($end_date);
2953
            $sessionCondition = api_get_session_condition($sessionId);
2954
            $sql = "SELECT login_course_date, logout_course_date
2955
                    FROM $table
2956
                    WHERE
2957
                        user_id = $user_id AND
2958
                        c_id = $courseId AND
2959
                        login_course_date BETWEEN '$start_date' AND '$end_date' AND
2960
                        logout_course_date BETWEEN '$start_date' AND '$end_date'
2961
                        $sessionCondition
2962
                    ORDER BY login_course_date ASC";
2963
            $rs = Database::query($sql);
2964
2965
            while ($row = Database::fetch_array($rs)) {
2966
                $connections[] = [
2967
                    'login' => $row['login_course_date'],
2968
                    'logout' =>$row['logout_course_date']
2969
                ];
2970
            }
2971
        }
2972
        return $connections;
2973
    }
2974
}
2975
2976
/**
2977
 * @param $user_id
2978
 * @param array $course_info
2979
 * @param int $sessionId
2980
 * @param null $start_date
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $end_date is correct as it would always require null to be passed?
Loading history...
Documentation Bug introduced by
Are you sure the doc-type for parameter $start_date is correct as it would always require null to be passed?
Loading history...
2981
 * @param null $end_date
2982
 * @return array
2983
 */
2984
function get_stats($user_id, $course_info, $sessionId, $start_date = null, $end_date = null)
2985
{
2986
    $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2987
    $result = [];
2988
    if (!empty($course_info)) {
2989
        $stringStartDate = '';
2990
        $stringEndDate = '';
2991
        if ($start_date != null && $end_date != null) {
2992
            $end_date = add_day_to($end_date);
2993
            $stringStartDate = "AND login_course_date BETWEEN '$start_date' AND '$end_date'";
2994
            $stringEndDate = "AND logout_course_date BETWEEN '$start_date' AND '$end_date'";
2995
        }
2996
        $user_id = intval($user_id);
2997
        $courseId = intval($course_info['real_id']);
2998
        $sessionCondition = api_get_session_condition($sessionId);
2999
        $sql = "SELECT
3000
                SEC_TO_TIME(AVG(time_to_sec(timediff(logout_course_date,login_course_date)))) as avrg,
3001
                SEC_TO_TIME(SUM(time_to_sec(timediff(logout_course_date,login_course_date)))) as total,
3002
                count(user_id) as times
3003
                FROM $table
3004
                WHERE
3005
                    user_id = $user_id AND
3006
                    c_id = $courseId $stringStartDate $stringEndDate 
3007
                    $sessionCondition                    
3008
                ORDER BY login_course_date ASC";
3009
3010
        $rs = Database::query($sql);
3011
        if ($row = Database::fetch_array($rs)) {
3012
            $foo_avg = $row['avrg'];
3013
            $foo_total = $row['total'];
3014
            $foo_times = $row['times'];
3015
            $result = [
3016
                'avg' => $foo_avg,
3017
                'total' => $foo_total,
3018
                'times' => $foo_times
3019
            ];
3020
        }
3021
    }
3022
3023
    return $result;
3024
}
3025
3026
function add_day_to($end_date)
3027
{
3028
    $foo_date = strtotime($end_date);
3029
    $foo_date = strtotime(" +1 day", $foo_date);
3030
    $foo_date = date("Y-m-d", $foo_date);
3031
    return $foo_date;
3032
}
3033
3034
/**
3035
 *
3036
 * @param array
3037
 * @author Jorge Frisancho Jibaja
3038
 * @version OCT-22- 2010
3039
 * @return array
3040
 */
3041
function convert_to_array($sql_result)
3042
{
3043
    $result_to_print = '<table>';
3044
    foreach ($sql_result as $key => $data) {
3045
        $result_to_print .= '<tr><td>'.date('d-m-Y (H:i:s)', $data['login']).'</td><td>'.
3046
            api_time_to_hms($data['logout'] - $data['login']).'</tr></td>'."\n";
3047
    }
3048
    $result_to_print .= '</table>';
3049
    $result_to_print = ["result"=>$result_to_print];
3050
    return $result_to_print;
3051
}
3052
3053
3054
/**
3055
 * Converte an array to a table in html
3056
 *
3057
 * @param array $result
3058
 * @author Jorge Frisancho Jibaja
3059
 * @version OCT-22- 2010
3060
 * @return string
3061
 */
3062
function convert_to_string($result)
3063
{
3064
    $html = '<table class="table">';
3065
    if (!empty($result)) {
3066
        foreach ($result as $key => $data) {
3067
            $html .= '<tr><td>';
3068
            $html .= api_get_local_time($data['login']);
3069
            $html .= '</td>';
3070
            $html .= '<td>';
3071
3072
            $html .= api_time_to_hms(api_strtotime($data['logout']) - api_strtotime($data['login']));
3073
            $html .= '</tr></td>';
3074
        }
3075
    }
3076
    $html .= '</table>';
3077
    return $html;
3078
}
3079
3080
3081
/**
3082
 * This function draw the graphic to be displayed on the user view as an image
3083
 *
3084
 * @param array $sql_result
3085
 * @param string $start_date
3086
 * @param string $end_date
3087
 * @param string $type
3088
 * @author Jorge Frisancho Jibaja
3089
 * @version OCT-22- 2010
3090
 * @return string
3091
 */
3092
function grapher($sql_result, $start_date, $end_date, $type = '')
3093
{
3094
    if (empty($start_date)) {
3095
        $start_date = '';
3096
    }
3097
    if (empty($end_date)) {
3098
        $end_date = '';
3099
    }
3100
    if ($type == '') {
3101
        $type = 'day';
3102
    }
3103
    $main_year = $main_month_year = $main_day = [];
3104
3105
    $period = new DatePeriod(
3106
        new DateTime($start_date),
3107
        new DateInterval('P1D'),
3108
        new DateTime($end_date)
3109
    );
3110
3111
    foreach ($period as $date) {
3112
        $main_day[$date->format('d-m-Y')] = 0;
3113
    }
3114
3115
    $period = new DatePeriod(
3116
        new DateTime($start_date),
3117
        new DateInterval('P1M'),
3118
        new DateTime($end_date)
3119
    );
3120
3121
    foreach ($period as $date) {
3122
        $main_month_year[$date->format('m-Y')] = 0;
3123
    }
3124
3125
    $i = 0;
3126
    if (is_array($sql_result) && count($sql_result) > 0) {
3127
        foreach ($sql_result as $key => $data) {
3128
            $login = api_strtotime($data['login']);
3129
            $logout = api_strtotime($data['logout']);
3130
            //creating the main array
3131
            if (isset($main_month_year[date('m-Y', $login)])) {
3132
                $main_month_year[date('m-Y', $login)] += float_format(($logout - $login) / 60, 0);
3133
            }
3134
            if (isset($main_day[date('d-m-Y', $login)])) {
3135
                $main_day[date('d-m-Y', $login)] += float_format(($logout - $login) / 60, 0);
3136
            }
3137
            if ($i > 500) {
3138
                break;
3139
            }
3140
            $i++;
3141
        }
3142
        switch ($type) {
3143
            case 'day':
3144
                $main_date = $main_day;
3145
                break;
3146
            case 'month':
3147
                $main_date = $main_month_year;
3148
                break;
3149
            case 'year':
3150
                $main_date = $main_year;
3151
                break;
3152
        }
3153
3154
        $labels = array_keys($main_date);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $main_date does not seem to be defined for all execution paths leading up to this point.
Loading history...
3155
        if (count($main_date) == 1) {
3156
            $labels = $labels[0];
3157
            $main_date = $main_date[$labels];
3158
        }
3159
3160
        /* Create and populate the pData object */
3161
        $myData = new pData();
3162
        $myData->addPoints($main_date, 'Serie1');
3163
        if (count($main_date) != 1) {
3164
            $myData->addPoints($labels, 'Labels');
3165
            $myData->setSerieDescription('Labels', 'Months');
3166
            $myData->setAbscissa('Labels');
3167
        }
3168
        $myData->setSerieWeight('Serie1', 1);
3169
        $myData->setSerieDescription('Serie1', get_lang('MyResults'));
3170
        $myData->setAxisName(0, get_lang('Minutes'));
3171
        $myData->loadPalette(api_get_path(SYS_CODE_PATH).'palettes/pchart/default.color', true);
3172
3173
        // Cache definition
3174
        $cachePath = api_get_path(SYS_ARCHIVE_PATH);
3175
        $myCache = new pCache(['CacheFolder' => substr($cachePath, 0, strlen($cachePath) - 1)]);
3176
        $chartHash = $myCache->getHash($myData);
3177
3178
        if ($myCache->isInCache($chartHash)) {
3179
            //if we already created the img
3180
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
3181
            $myCache->saveFromCache($chartHash, $imgPath);
3182
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
3183
        } else {
3184
            /* Define width, height and angle */
3185
            $mainWidth = 760;
3186
            $mainHeight = 230;
3187
            $angle = 50;
3188
3189
            /* Create the pChart object */
3190
            $myPicture = new pImage($mainWidth, $mainHeight, $myData);
3191
3192
            /* Turn of Antialiasing */
3193
            $myPicture->Antialias = false;
3194
            /* Draw the background */
3195
            $settings = ["R" => 255, "G" => 255, "B" => 255];
3196
            $myPicture->drawFilledRectangle(0, 0, $mainWidth, $mainHeight, $settings);
3197
3198
            /* Add a border to the picture */
3199
            $myPicture->drawRectangle(
3200
                0,
3201
                0,
3202
                $mainWidth - 1,
3203
                $mainHeight - 1,
3204
                ["R" => 0, "G" => 0, "B" => 0]
3205
            );
3206
3207
            /* Set the default font */
3208
            $myPicture->setFontProperties(
3209
                [
3210
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3211
                    "FontSize" => 10]
3212
            );
3213
            /* Write the chart title */
3214
            $myPicture->drawText(
3215
                $mainWidth / 2,
3216
                30,
3217
                get_lang('TimeSpentInTheCourse'),
3218
                [
3219
                    "FontSize" => 12,
3220
                    "Align" => TEXT_ALIGN_BOTTOMMIDDLE
3221
                ]
3222
            );
3223
3224
            /* Set the default font */
3225
            $myPicture->setFontProperties(
3226
                [
3227
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3228
                    "FontSize" => 8
3229
                ]
3230
            );
3231
3232
            /* Define the chart area */
3233
            $myPicture->setGraphArea(50, 40, $mainWidth - 40, $mainHeight - 80);
3234
3235
            /* Draw the scale */
3236
            $scaleSettings = [
3237
                'XMargin' => 10,
3238
                'YMargin' => 10,
3239
                'Floating' => true,
3240
                'GridR' => 200,
3241
                'GridG' => 200,
3242
                'GridB' => 200,
3243
                'DrawSubTicks' => true,
3244
                'CycleBackground' => true,
3245
                'LabelRotation' => $angle,
3246
                'Mode' => SCALE_MODE_ADDALL_START0,
3247
            ];
3248
            $myPicture->drawScale($scaleSettings);
3249
3250
            /* Turn on Antialiasing */
3251
            $myPicture->Antialias = true;
3252
3253
            /* Enable shadow computing */
3254
            $myPicture->setShadow(
3255
                true,
3256
                [
3257
                    "X" => 1,
3258
                    "Y" => 1,
3259
                    "R" => 0,
3260
                    "G" => 0,
3261
                    "B" => 0,
3262
                    "Alpha" => 10
3263
                ]
3264
            );
3265
3266
            /* Draw the line chart */
3267
            $myPicture->setFontProperties(
3268
                [
3269
                    "FontName" => api_get_path(SYS_FONTS_PATH).'opensans/OpenSans-Regular.ttf',
3270
                    "FontSize" => 10
3271
                ]
3272
            );
3273
            $myPicture->drawSplineChart();
3274
            $myPicture->drawPlotChart(
3275
                [
3276
                    "DisplayValues" => true,
3277
                    "PlotBorder" => true,
3278
                    "BorderSize" => 1,
3279
                    "Surrounding" => -60,
3280
                    "BorderAlpha" => 80
3281
                ]
3282
            );
3283
3284
            /* Do NOT Write the chart legend */
3285
3286
            /* Write and save into cache */
3287
            $myCache->writeToCache($chartHash, $myPicture);
3288
            $imgPath = api_get_path(SYS_ARCHIVE_PATH).$chartHash;
3289
            $myCache->saveFromCache($chartHash, $imgPath);
3290
            $imgPath = api_get_path(WEB_ARCHIVE_PATH).$chartHash;
3291
        }
3292
        $html = '<img src="'.$imgPath.'">';
3293
3294
        return $html;
3295
    } else {
3296
        $foo_img = api_convert_encoding(
3297
            '<div id="messages" class="warning-message">'.get_lang('GraphicNotAvailable').'</div>',
3298
            'UTF-8'
3299
        );
3300
3301
        return $foo_img;
3302
    }
3303
}
3304