From 6705a874d9167eb544f16174ee57c206d2c599e8 Mon Sep 17 00:00:00 2001 From: BorjaSanchezBeezNest Date: Thu, 23 Jan 2025 14:53:38 +0100 Subject: [PATCH 1/3] Tracking: Add quarterly report in admin statistics page --- public/main/admin/statistics/index.php | 153 +++- public/main/inc/ajax/statistics.ajax.php | 654 +++++++++++++++++- public/main/inc/lib/api.lib.php | 17 + .../main/inc/lib/internationalization.lib.php | 55 ++ public/main/inc/lib/statistics.lib.php | 180 ++++- public/main/inc/lib/tracking.lib.php | 36 + public/main/inc/lib/usermanager.lib.php | 139 +++- .../block_global_info.class.php | 10 +- 8 files changed, 1185 insertions(+), 59 deletions(-) diff --git a/public/main/admin/statistics/index.php b/public/main/admin/statistics/index.php index 602e99ee84..b5d62d9667 100644 --- a/public/main/admin/statistics/index.php +++ b/public/main/admin/statistics/index.php @@ -352,16 +352,17 @@ $tools = [ 'report=new_user_registrations' => get_lang('New users registrations'), ], get_lang('System') => [ - 'report=activities' => get_lang('ImportantActivities'), - 'report=user_session' => get_lang('PortalUserSessionStats'), + 'report=activities' => get_lang('Important activities'), + 'report=user_session' => get_lang('Portal user session stats'), + 'report=quarterly_report' => get_lang('Quarterly report'), ], get_lang('Social') => [ - 'report=messagereceived' => get_lang('MessagesReceived'), - 'report=messagesent' => get_lang('MessagesSent'), - 'report=friends' => get_lang('CountFriends'), + 'report=messagereceived' => get_lang('Number of messages received'), + 'report=messagesent' => get_lang('Number of messages sent'), + 'report=friends' => get_lang('Contacts count'), ], get_lang('Session') => [ - 'report=session_by_date' => get_lang('SessionsByDate'), + 'report=session_by_date' => get_lang('Sessions by date'), ], ]; @@ -1665,6 +1666,146 @@ switch ($report) { case 'logins_by_date': $content .= Statistics::printLoginsByDate(); break; + case 'quarterly_report': + global $htmlHeadXtra; + $ajaxPath = api_get_path(WEB_AJAX_PATH); + $waitIcon = Display::getMdiIcon('clock-time-four', 'ch-tool-icon-disabled', null, ICON_SIZE_SMALL, false); + $htmlHeadXtra[] .= ''; + $htmlHeadXtra[] .= ''; + $htmlHeadXtra[] .= ''; + $htmlHeadXtra[] .= ''; + $htmlHeadXtra[] .= ''; + $htmlHeadXtra[] .= ''; + if (api_get_current_access_url_id() === 1) { + $htmlHeadXtra[] .= ''; + } + $content .= Display::tag('H4', get_lang('Number of users registered and connected'), ['style' => 'margin-bottom: 25px;']); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlyUsers();', 'class' => 'btn btn-default'] + ); + $content .= Display::div('', ['id' => 'tracking-report-quarterly-users', 'style' => 'margin: 30px;']); + $content .= Display::tag('H4', get_lang('Number of existing and available courses'), ['style' => 'margin-bottom: 25px;']); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlyCourses();', 'class' => 'btn btn-default'] + ); + $content .= Display::div('', ['id' => 'tracking-report-quarterly-courses', 'style' => 'margin: 30px;']); + $content .= Display::tag('H4', get_lang('Hours of training'), ['style' => 'margin-bottom: 25px;']); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlyHoursOfTraining();', 'class' => 'btn btn-default'] + ); + $content .= Display::div( + '', + [ + 'id' => 'tracking-report-quarterly-hours-of-training', + 'style' => 'margin: 30px;', + ] + ); + $content .= Display::tag( + 'H4', + get_lang('Number of certificates generated'), + ['style' => 'margin-bottom: 25px;'] + ); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlyCertificatesGenerated();', 'class' => 'btn btn-default'] + ); + $content .= Display::div( + '', + ['id' => 'tracking-report-quarterly-number-of-certificates-generated', 'style' => 'margin: 30px;'] + ); + $content .= Display::tag( + 'H4', + get_lang('Number of sessions per duration'), + ['style' => 'margin-bottom: 25px;'] + ); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlySessionsByDuration();', 'class' => 'btn btn-default'] + ); + $content .= Display::div( + '', + ['id' => 'tracking-report-quarterly-sessions-by-duration', 'style' => 'margin: 30px;'] + ); + $content .= Display::tag( + 'H4', + get_lang('Number of courses, sessions and subscribed users'), + ['style' => 'margin-bottom: 25px;'] + ); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlyCoursesAndSessions();', 'class' => 'btn btn-default'] + ); + $content .= Display::div( + '', + [ + 'id' => 'tracking-report-quarterly-courses-and-sessions', + 'style' => 'margin: 30px;', + ] + ); + if (api_get_current_access_url_id() === 1) { + $content .= Display::tag( + 'H4', + get_lang('Total disk usage'), + ['style' => 'margin-bottom: 25px;'] + ); + $content .= Display::url( + get_lang('Show'), + 'javascript://', + ['onclick' => 'loadReportQuarterlyTotalDiskUsage();', 'class' => 'btn btn-default'] + ); + $content .= Display::div( + '', + [ + 'id' => 'tracking-report-quarterly-total-disk-usage', + 'style' => 'margin: 30px;', + ] + ); + } + break; } Display::display_header($tool_name); diff --git a/public/main/inc/ajax/statistics.ajax.php b/public/main/inc/ajax/statistics.ajax.php index 83ba57dcf2..7504b8dbdf 100644 --- a/public/main/inc/ajax/statistics.ajax.php +++ b/public/main/inc/ajax/statistics.ajax.php @@ -644,7 +644,7 @@ switch ($action) { $all = []; while ($row = Database::fetch_array($result)) { $categoryData = SessionManager::get_session_category($row['session_category_id']); - $label = get_lang('NoCategory'); + $label = get_lang('Without category'); if ($categoryData) { $label = $categoryData['name']; } @@ -759,4 +759,656 @@ switch ($action) { header('Content-type: application/json'); echo json_encode($list); break; + case 'report_quarterly_users': + $currentQuarterDates = getQuarterDates(); + $pre1QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-3 month') + ->format('Y-m-d') + ); + $pre2QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-6 month') + ->format('Y-m-d') + ); + $pre3QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-9 month') + ->format('Y-m-d') + ); + $pre4QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-12 month') + ->format('Y-m-d') + ); + $pre5QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-15 month') + ->format('Y-m-d') + ); + // Make de headers for the table + $headers = [ + '', + $pre5QuarterDates['quarter_title'], + $pre4QuarterDates['quarter_title'], + $pre3QuarterDates['quarter_title'], + $pre2QuarterDates['quarter_title'], + $pre1QuarterDates['quarter_title'], + get_lang('YoY'), + $currentQuarterDates['quarter_title'].'*', + ]; + // Get the data for the number of user registered row (2) + $countUsersTotal = UserManager::get_number_of_users( + null, + null, + null + ); + $countUsersPre1Quarter = UserManager::get_number_of_users( + null, + null, + null, + null, + $pre1QuarterDates['quarter_end'] + ); + $countUsersPre2Quarter = UserManager::get_number_of_users( + null, + null, + null, + null, + $pre2QuarterDates['quarter_end'] + ); + $countUsersPre3Quarter = UserManager::get_number_of_users( + null, + null, + null, + null, + $pre3QuarterDates['quarter_end'] + ); + $countUsersPre4Quarter = UserManager::get_number_of_users( + null, + null, + null, + null, + $pre4QuarterDates['quarter_end'] + ); + $countUsersPre5Quarter = UserManager::get_number_of_users( + null, + null, + null, + null, + $pre5QuarterDates['quarter_end'] + ); + // Calculate percent for first row + $percentIncrementUsersRegistered = api_calculate_increment_percent( + $countUsersPre1Quarter, + $countUsersPre5Quarter + ); + // Get the data for number of users connected row (3) + $countUsersConnectedCurrentQuarter = count( + Statistics::getLoginsByDate( + $currentQuarterDates['quarter_start'], + $currentQuarterDates['quarter_end'] + ) + ); + $countUsersConnectedPre1Quarter = count( + Statistics::getLoginsByDate( + $pre1QuarterDates['quarter_start'], + $pre1QuarterDates['quarter_end'] + ) + ); + $countUsersConnectedPre2Quarter = count( + Statistics::getLoginsByDate( + $pre2QuarterDates['quarter_start'], + $pre2QuarterDates['quarter_end'] + ) + ); + $countUsersConnectedPre3Quarter = count( + Statistics::getLoginsByDate( + $pre3QuarterDates['quarter_start'], + $pre3QuarterDates['quarter_end'] + ) + ); + $countUsersConnectedPre4Quarter = count( + Statistics::getLoginsByDate( + $pre4QuarterDates['quarter_start'], + $pre4QuarterDates['quarter_end'] + ) + ); + $countUsersConnectedPre5Quarter = count( + Statistics::getLoginsByDate( + $pre5QuarterDates['quarter_start'], + $pre5QuarterDates['quarter_end'] + ) + ); + // Calculate percent for second row + $percentIncrementUsersConnected = api_calculate_increment_percent( + $countUsersConnectedPre1Quarter, + $countUsersConnectedPre5Quarter + ); + //Make de rows with the recollected data + $rows = []; + $rows[] = [ + get_lang('Number of users registered (total)'), + $countUsersPre5Quarter, + $countUsersPre4Quarter, + $countUsersPre3Quarter, + $countUsersPre2Quarter, + $countUsersPre1Quarter, + $percentIncrementUsersRegistered, + $countUsersTotal, + ]; + //todo comprobacion + - + $rows[] = [ + get_lang('Number of users registered (new vs previous quarter)'), + '-', + '+'.($countUsersPre1Quarter - $countUsersPre2Quarter), + '+'.($countUsersPre2Quarter - $countUsersPre3Quarter), + '+'.($countUsersPre3Quarter - $countUsersPre4Quarter), + '+'.($countUsersPre4Quarter - $countUsersPre5Quarter), + '-', + '+'.($countUsersTotal - $countUsersPre1Quarter), + ]; + $rows[] = [ + get_lang('Number of users who connected'), + $countUsersConnectedPre5Quarter, + $countUsersConnectedPre4Quarter, + $countUsersConnectedPre3Quarter, + $countUsersConnectedPre2Quarter, + $countUsersConnectedPre1Quarter, + $percentIncrementUsersConnected, + $countUsersConnectedCurrentQuarter, + ]; + echo Display::table($headers, $rows, []); + echo Display::label(get_lang('*: Current quarter, incomplete data'), 'warning'); + break; + case 'report_quarterly_courses': + $currentQuarterDates = getQuarterDates(); + $pre1QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-3 month') + ->format('Y-m-d') + ); + $pre2QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-6 month') + ->format('Y-m-d') + ); + $pre3QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-9 month') + ->format('Y-m-d') + ); + $pre4QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-12 month') + ->format('Y-m-d') + ); + $pre5QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-15 month') + ->format('Y-m-d') + ); + // Make the headers for the table + $headers = [ + '', + $pre5QuarterDates['quarter_title'], + $pre4QuarterDates['quarter_title'], + $pre3QuarterDates['quarter_title'], + $pre2QuarterDates['quarter_title'], + $pre1QuarterDates['quarter_title'], + get_lang('YoY'), + $currentQuarterDates['quarter_title'].'*', + ]; + // Get the data for the rows + $countCoursesCurrentQuarter = Statistics::countCourses(null, null, null); + $countCoursesPre1Quarter = Statistics::countCourses(null, null, $pre1QuarterDates['quarter_end']); + $countCoursesPre2Quarter = Statistics::countCourses(null, null, $pre2QuarterDates['quarter_end']); + $countCoursesPre3Quarter = Statistics::countCourses(null, null, $pre3QuarterDates['quarter_end']); + $countCoursesPre4Quarter = Statistics::countCourses(null, null, $pre4QuarterDates['quarter_end']); + $countCoursesPre5Quarter = Statistics::countCourses(null, null, $pre5QuarterDates['quarter_end']); + $auxArrayVisibilities = [ + COURSE_VISIBILITY_OPEN_WORLD, + COURSE_VISIBILITY_OPEN_PLATFORM, + COURSE_VISIBILITY_REGISTERED, + ]; + $countCoursesAvailableCurrentQuarter = Statistics::countCoursesByVisibility($auxArrayVisibilities); + $countCoursesAvailablePre1Quarter = Statistics::countCoursesByVisibility( + $auxArrayVisibilities, + null, + $pre1QuarterDates['quarter_end'] + ); + $countCoursesAvailablePre2Quarter = Statistics::countCoursesByVisibility( + $auxArrayVisibilities, + null, + $pre2QuarterDates['quarter_end'] + ); + $countCoursesAvailablePre3Quarter = Statistics::countCoursesByVisibility( + $auxArrayVisibilities, + null, + $pre3QuarterDates['quarter_end'] + ); + $countCoursesAvailablePre4Quarter = Statistics::countCoursesByVisibility( + $auxArrayVisibilities, + null, + $pre4QuarterDates['quarter_end'] + ); + $countCoursesAvailablePre5Quarter = Statistics::countCoursesByVisibility( + $auxArrayVisibilities, + null, + $pre5QuarterDates['quarter_end'] + ); + // Calculate percents for first row + $percentIncrementCourses = api_calculate_increment_percent( + $countCoursesPre1Quarter, + $countCoursesPre5Quarter + ); + // Calculate percents for second row + $percentIncrementUsersRegistered = api_calculate_increment_percent( + $countCoursesAvailablePre1Quarter, + $countCoursesAvailablePre5Quarter + ); + //Make the rows with the recollected data + $rows = []; + $rows[] = [ + get_lang('Number of existing courses (total)'), + $countCoursesPre5Quarter, + $countCoursesPre4Quarter, + $countCoursesPre3Quarter, + $countCoursesPre2Quarter, + $countCoursesPre1Quarter, + $percentIncrementCourses, + $countCoursesCurrentQuarter, + ]; + $rows[] = [ + get_lang('Number of available courses (not closed or hidden, total)'), + $countCoursesAvailablePre5Quarter, + $countCoursesAvailablePre4Quarter, + $countCoursesAvailablePre3Quarter, + $countCoursesAvailablePre2Quarter, + $countCoursesAvailablePre1Quarter, + $percentIncrementUsersRegistered, + $countCoursesAvailableCurrentQuarter, + ]; + echo Display::table($headers, $rows, []); + echo Display::label(get_lang('*: Current quarter, incomplete data'), 'warning'); + break; + case 'report_quarterly_hours_of_training': + $currentQuarterDates = getQuarterDates(); + $pre1QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-3 month') + ->format('Y-m-d') + ); + $pre2QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-6 month') + ->format('Y-m-d') + ); + $pre3QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-9 month') + ->format('Y-m-d') + ); + $pre4QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-12 month') + ->format('Y-m-d') + ); + $pre5QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-15 month') + ->format('Y-m-d') + ); + // Make the headers for the table + $headers = [ + '', + $pre5QuarterDates['quarter_title'], + $pre4QuarterDates['quarter_title'], + $pre3QuarterDates['quarter_title'], + $pre2QuarterDates['quarter_title'], + $pre1QuarterDates['quarter_title'], + get_lang('YoY'), + $currentQuarterDates['quarter_title'].'*', + ]; + // Get data for the row + $timeSpentCoursesCurrentQuarter = Tracking::getTotalTimeSpentInCourses( + $currentQuarterDates['quarter_start'], + $currentQuarterDates['quarter_end'] + ); + $timeSpentCourses1PreQuarter = Tracking::getTotalTimeSpentInCourses( + $pre1QuarterDates['quarter_start'], + $pre1QuarterDates['quarter_end'] + ); + $timeSpentCourses2PreQuarter = Tracking::getTotalTimeSpentInCourses( + $pre2QuarterDates['quarter_start'], + $pre2QuarterDates['quarter_end'] + ); + $timeSpentCourses3PreQuarter = Tracking::getTotalTimeSpentInCourses( + $pre3QuarterDates['quarter_start'], + $pre3QuarterDates['quarter_end'] + ); + $timeSpentCourses4PreQuarter = Tracking::getTotalTimeSpentInCourses( + $pre4QuarterDates['quarter_start'], + $pre4QuarterDates['quarter_end'] + ); + $timeSpentCourses5PreQuarter = Tracking::getTotalTimeSpentInCourses( + $pre5QuarterDates['quarter_start'], + $pre5QuarterDates['quarter_end'] + ); + // Calculate percent for the row + $percentIncrementTimeSpent = api_calculate_increment_percent( + $timeSpentCourses1PreQuarter, + $timeSpentCourses5PreQuarter + ); + //Make the row with the recollected data + $rows = []; + $rows[] = [ + get_lang('Number of hours of training followed (total)'), + $timeSpentCourses5PreQuarter, + $timeSpentCourses4PreQuarter, + $timeSpentCourses3PreQuarter, + $timeSpentCourses2PreQuarter, + $timeSpentCourses1PreQuarter, + $percentIncrementTimeSpent, + $timeSpentCoursesCurrentQuarter, + ]; + echo Display::table($headers, $rows, []); + echo Display::label(get_lang('*: Current quarter, incomplete data'), 'warning'); + break; + case 'report_quarterly_number_of_certificates_generated': + $currentQuarterDates = getQuarterDates(); + $pre1QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-3 month') + ->format('Y-m-d') + ); + $pre2QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-6 month') + ->format('Y-m-d') + ); + $pre3QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-9 month') + ->format('Y-m-d') + ); + $pre4QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-12 month') + ->format('Y-m-d') + ); + $pre5QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-15 month') + ->format('Y-m-d') + ); + // Make the headers for the table + $headers = [ + '', + $pre5QuarterDates['quarter_title'], + $pre4QuarterDates['quarter_title'], + $pre3QuarterDates['quarter_title'], + $pre2QuarterDates['quarter_title'], + $pre1QuarterDates['quarter_title'], + get_lang('YoY'), + $currentQuarterDates['quarter_title'].'*', + ]; + // Get data for the row + $certificateGeneratedCurrentQuarter = Statistics::countCertificatesByQuarter( + null, + $currentQuarterDates['quarter_end'] + ); + $certificateGenerated1PreQuarter = Statistics::countCertificatesByQuarter( + null, + $pre1QuarterDates['quarter_end'] + ); + $certificateGenerated2PreQuarter = Statistics::countCertificatesByQuarter( + null, + $pre2QuarterDates['quarter_end'] + ); + $certificateGenerated3PreQuarter = Statistics::countCertificatesByQuarter( + null, + $pre3QuarterDates['quarter_end'] + ); + $certificateGenerated4PreQuarter = Statistics::countCertificatesByQuarter( + null, + $pre4QuarterDates['quarter_end'] + ); + $certificateGenerated5PreQuarter = Statistics::countCertificatesByQuarter( + null, + $pre5QuarterDates['quarter_end'] + ); + // Calculate percent for the row + $percentIncrementCertificateGenerated = api_calculate_increment_percent( + $certificateGenerated1PreQuarter, + $certificateGenerated5PreQuarter + ); + //Make the row with the recollected data + $rows = []; + $rows[] = [ + get_lang('Number of certificates generated'), + $certificateGenerated5PreQuarter, + $certificateGenerated4PreQuarter, + $certificateGenerated3PreQuarter, + $certificateGenerated2PreQuarter, + $certificateGenerated1PreQuarter, + $percentIncrementCertificateGenerated, + $certificateGeneratedCurrentQuarter, + ]; + echo Display::table($headers, $rows, []); + echo Display::label(get_lang('*: Current quarter, incomplete data'), 'warning'); + break; + case "report_quarterly_sessions_by_duration": + $currentQuarterDates = getQuarterDates(); + $pre1QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-3 month') + ->format('Y-m-d') + ); + $pre2QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-6 month') + ->format('Y-m-d') + ); + $pre3QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-9 month') + ->format('Y-m-d') + ); + $pre4QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-12 month') + ->format('Y-m-d') + ); + $pre5QuarterDates = getQuarterDates( + date_create($currentQuarterDates['quarter_start']) + ->modify('-15 month') + ->format('Y-m-d') + ); + // Make the headers for the table + $headers = [ + get_lang('Sessions per duration (by quarter)'), + $pre5QuarterDates['quarter_title'], + $pre4QuarterDates['quarter_title'], + $pre3QuarterDates['quarter_title'], + $pre2QuarterDates['quarter_title'], + $pre1QuarterDates['quarter_title'], + get_lang('YoY'), + $currentQuarterDates['quarter_title'].'*', + ]; + // Get the data for the rows + $sessionsDurationCurrentQuarter = Statistics::getSessionsByDuration( + $currentQuarterDates['quarter_start'], + $currentQuarterDates['quarter_end'] + ); + $sessionsDuration1PreQuarter = Statistics::getSessionsByDuration( + $pre1QuarterDates['quarter_start'], + $pre1QuarterDates['quarter_end'] + ); + $sessionsDuration2PreQuarter = Statistics::getSessionsByDuration( + $pre2QuarterDates['quarter_start'], + $pre2QuarterDates['quarter_end'] + ); + $sessionsDuration3PreQuarter = Statistics::getSessionsByDuration( + $pre3QuarterDates['quarter_start'], + $pre3QuarterDates['quarter_end'] + ); + $sessionsDuration4PreQuarter = Statistics::getSessionsByDuration( + $pre4QuarterDates['quarter_start'], + $pre4QuarterDates['quarter_end'] + ); + $sessionsDuration5PreQuarter = Statistics::getSessionsByDuration( + $pre5QuarterDates['quarter_start'], + $pre5QuarterDates['quarter_end'] + ); + // Calculate percent for the rows + $percentIncrementSessionDuration0 = api_calculate_increment_percent( + $sessionsDuration1PreQuarter['0'], + $sessionsDuration5PreQuarter['0'] + ); + $percentIncrementSessionDuration5 = api_calculate_increment_percent( + $sessionsDuration1PreQuarter['5'], + $sessionsDuration5PreQuarter['5'] + ); + $percentIncrementSessionDuration10 = api_calculate_increment_percent( + $sessionsDuration1PreQuarter['10'], + $sessionsDuration5PreQuarter['10'] + ); + $percentIncrementSessionDuration15 = api_calculate_increment_percent( + $sessionsDuration1PreQuarter['15'], + $sessionsDuration5PreQuarter['15'] + ); + $percentIncrementSessionDuration30 = api_calculate_increment_percent( + $sessionsDuration1PreQuarter['30'], + $sessionsDuration5PreQuarter['30'] + ); + $percentIncrementSessionDuration60 = api_calculate_increment_percent( + $sessionsDuration1PreQuarter['60'], + $sessionsDuration5PreQuarter['60'] + ); + //Make the rows with the recollected data + $rows = []; + $rows[] = [ + '0-5′', + $sessionsDuration5PreQuarter['0'], + $sessionsDuration4PreQuarter['0'], + $sessionsDuration3PreQuarter['0'], + $sessionsDuration2PreQuarter['0'], + $sessionsDuration1PreQuarter['0'], + $percentIncrementSessionDuration0, + $sessionsDurationCurrentQuarter['0'], + ]; + $rows[] = [ + '6-10′', + $sessionsDuration5PreQuarter['5'], + $sessionsDuration4PreQuarter['5'], + $sessionsDuration3PreQuarter['5'], + $sessionsDuration2PreQuarter['5'], + $sessionsDuration1PreQuarter['5'], + $percentIncrementSessionDuration5, + $sessionsDurationCurrentQuarter['5'], + ]; + $rows[] = [ + '11-15′', + $sessionsDuration5PreQuarter['10'], + $sessionsDuration4PreQuarter['10'], + $sessionsDuration3PreQuarter['10'], + $sessionsDuration2PreQuarter['10'], + $sessionsDuration1PreQuarter['10'], + $percentIncrementSessionDuration10, + $sessionsDurationCurrentQuarter['10'], + ]; + $rows[] = [ + '16-30′', + $sessionsDuration5PreQuarter['15'], + $sessionsDuration4PreQuarter['15'], + $sessionsDuration3PreQuarter['15'], + $sessionsDuration2PreQuarter['15'], + $sessionsDuration1PreQuarter['15'], + $percentIncrementSessionDuration15, + $sessionsDurationCurrentQuarter['15'], + ]; + $rows[] = [ + '31-60′', + $sessionsDuration5PreQuarter['30'], + $sessionsDuration4PreQuarter['30'], + $sessionsDuration3PreQuarter['30'], + $sessionsDuration2PreQuarter['30'], + $sessionsDuration1PreQuarter['30'], + $percentIncrementSessionDuration30, + $sessionsDurationCurrentQuarter['30'], + ]; + $rows[] = [ + '60-∞′', + $sessionsDuration5PreQuarter['60'], + $sessionsDuration4PreQuarter['60'], + $sessionsDuration3PreQuarter['60'], + $sessionsDuration2PreQuarter['60'], + $sessionsDuration1PreQuarter['60'], + $percentIncrementSessionDuration60, + $sessionsDurationCurrentQuarter['60'], + ]; + echo Display::table($headers, $rows, []); + echo Display::label(get_lang('*: Current quarter, incomplete data'), 'warning'); + break; + case "report_quarterly_courses_and_sessions": + // Make the headers for the tables + $headers = [ + [ + get_lang('List of course codes'), + get_lang('Number of subscribed users').'*', + get_lang('Number of users who finished the course (as defined in gradebook)'), + ], + [ + get_lang('List of course codes and sessions'), + get_lang('Number of subscribed users').'*', + get_lang('Number of users who finished the course (as defined in gradebook)'), + ], + ]; + // Get the data fot the first table + $courses = UserManager::countUsersWhoFinishedCourses(); + //Make the rows for first table + $rows = []; + foreach ($courses as $course => $data) { + $course_url = api_get_path(WEB_CODE_PATH).'course_home/course_home.php?cidReq='.$course; + $rows[] = [ + Display::url($course, $course_url, ['target' => SESSION_LINK_TARGET]), + $data['subscribed'], + $data['finished'], + ]; + } + echo Display::table($headers[0], $rows, []); + //Get the data for the second table (with sessions) + $courses = UserManager::countUsersWhoFinishedCoursesInSessions(); + //Make the rows for second table + $rows = []; + foreach ($courses as $course => $data) { + $rows[] = [ + $course, + $data['subscribed'], + $data['finished'], + ]; + } + echo Display::tag('br', '', ['style' => 'margin-top: 25px;']); + echo Display::table($headers[1], $rows, []); + echo Display::tag('br', '', ['style' => 'margin-top: 25px;']); + echo Display::label(get_lang('*: All users, including inactive, are included'), 'warning'); + break; + case "report_quarterly_total_disk_usage": + $accessUrlId = api_get_current_access_url_id(); + if (api_is_windows_os()) { + $message = get_lang('The space used on disk cannot be measured properly on Windows-based systems.'); + } else { + $dir = api_get_path(SYS_PATH); + $du = exec('du -sh '.$dir, $err); + list($size, $none) = explode("\t", $du); + unset($none); + $limit = 0; + if (isset($_configuration[$accessUrlId]['hosting_limit_disk_space'])) { + $limit = $_configuration[$accessUrlId]['hosting_limit_disk_space']; + } + $message = sprintf(get_lang('Total space used by portal %s limit is %s MB'), $size, $limit); + } + echo Display::tag('H5', $message, ['style' => 'margin-bottom: 25px;']); + break; } diff --git a/public/main/inc/lib/api.lib.php b/public/main/inc/lib/api.lib.php index fe31007fc9..926dd88f16 100644 --- a/public/main/inc/lib/api.lib.php +++ b/public/main/inc/lib/api.lib.php @@ -7534,3 +7534,20 @@ function api_get_permission(string $permissionSlug, array $roles): bool return $permissionService->hasPermission($permissionSlug, $roles); } + +/** + * Calculate the percentage of change between two numbers. + * + * @param int $newValue + * @param int $oldValue + * @return string + */ +function api_calculate_increment_percent(int $newValue, int $oldValue): string +{ + if ($oldValue <= 0) { + $result = " - "; + } else { + $result = ' '.round(100 * (($newValue / $oldValue) - 1), 2).' %'; + } + return $result; +} diff --git a/public/main/inc/lib/internationalization.lib.php b/public/main/inc/lib/internationalization.lib.php index 04a822126c..4424f9add0 100644 --- a/public/main/inc/lib/internationalization.lib.php +++ b/public/main/inc/lib/internationalization.lib.php @@ -2013,3 +2013,58 @@ function api_get_human_date_time($date, $showTime = true, $humanForm = false) } } } + +/** + * Return an array with the start and end dates of a quarter (as in 3 months period). + * If no DateTime is not sent, use the current date. + * + * @param string|null $date (optional) The date or null. + * + * @return array E.G.: ['quarter_start' => '2022-10-11', + * 'quarter_end' => '2022-12-31', + * 'quarter_title' => 'Q4 2022'] + */ +function getQuarterDates(string $date = null): array +{ + if (empty($date)) { + $date = api_get_utc_datetime(); + } + if (strlen($date > 10)) { + $date = substr($date, 0, 10); + } + $month = substr($date, 5, 2); + $year = substr($date, 0, 4); + switch ($month) { + case $month >= 1 && $month <= 3: + $start = "$year-01-01"; + $end = "$year-03-31"; + $quarter = 1; + break; + case $month >= 4 && $month <= 6: + $start = "$year-04-01"; + $end = "$year-06-30"; + $quarter = 2; + break; + case $month >= 7 && $month <= 9: + $start = "$year-07-01"; + $end = "$year-09-30"; + $quarter = 3; + break; + case $month >= 10 && $month <= 12: + $start = "$year-10-01"; + $end = "$year-12-31"; + $quarter = 4; + break; + default: + // Should never happen + $start = "$year-01-01"; + $end = "$year-03-31"; + $quarter = 1; + break; + } + return [ + 'quarter_start' => $start, + 'quarter_end' => $end, + 'quarter_title' => sprintf(get_lang('Q%s %s'), $quarter, $year), + ]; +} diff --git a/public/main/inc/lib/statistics.lib.php b/public/main/inc/lib/statistics.lib.php index 4e31d1c097..cbb3b9bca5 100644 --- a/public/main/inc/lib/statistics.lib.php +++ b/public/main/inc/lib/statistics.lib.php @@ -37,42 +37,44 @@ class Statistics /** * Count courses. * - * @param string $categoryCode Code of a course category. - * Default: count all courses. + * @param string|null $categoryCode Code of a course category. + * Default: count all courses. + * @param string|null $dateFrom dateFrom + * @param string|null $dateUntil dateUntil * * @return int Number of courses counted + * @throws \Doctrine\DBAL\Exception */ - public static function countCourses($categoryCode = null) + public static function countCourses(string $categoryCode = null, string $dateFrom = null, string $dateUntil = null): int { - $course_table = Database::get_main_table(TABLE_MAIN_COURSE); - $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY); - $access_url_rel_course_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); + $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); + $accessUrlRelCourseTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $urlId = api_get_current_access_url_id(); - - $categoryJoin = ''; - $categoryCondition = ''; - - if (!empty($categoryCode)) { - //$categoryJoin = " LEFT JOIN $tblCourseCategory course_category ON course.category_id = course_category.id "; - //$categoryCondition = " course_category.code = '".Database::escape_string($categoryCode)."' "; - } - if (api_is_multiple_url_enabled()) { $sql = "SELECT COUNT(*) AS number - FROM ".$course_table." as c, $access_url_rel_course_table as u - $categoryJoin - WHERE u.c_id = c.id AND access_url_id='".$urlId."'"; + FROM ".$courseTable." AS c, $accessUrlRelCourseTable AS u + WHERE u.c_id = c.id AND $accessUrlRelCourseTable='".$urlId."'"; if (isset($categoryCode)) { - $sql .= " AND $categoryCondition"; + $sql .= " AND category_code = '".Database::escape_string($categoryCode)."'"; } } else { $sql = "SELECT COUNT(*) AS number - FROM $course_table $categoryJoin"; + FROM $courseTable AS c + WHERE 1 = 1"; if (isset($categoryCode)) { - $sql .= " WHERE $categoryCondition"; + $sql .= " WHERE c.category_code = '".Database::escape_string($categoryCode)."'"; } } + if (!empty($dateFrom)) { + $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); + $sql .= " AND c.creation_date >= '$dateFrom' "; + } + if (!empty($dateUntil)) { + $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); + $sql .= " AND c.creation_date <= '$dateUntil' "; + } + $res = Database::query($sql); $obj = Database::fetch_object($res); @@ -82,30 +84,52 @@ class Statistics /** * Count courses by visibility. * - * @param int $visibility visibility (0 = closed, 1 = private, 2 = open, 3 = public) all courses + * @param array|null $visibility visibility (0 = closed, 1 = private, 2 = open, 3 = public) all courses + * @param string|null $dateFrom dateFrom + * @param string|null $dateUntil dateUntil * * @return int Number of courses counted + * @throws \Doctrine\DBAL\Exception */ - public static function countCoursesByVisibility($visibility = null) + public static function countCoursesByVisibility( + array $visibility = null, + string $dateFrom = null, + string $dateUntil = null + ): int { - if (!isset($visibility)) { + if (empty($visibility)) { return 0; + } else { + $visibilityString = ''; + $auxArrayVisibility = []; + if (!is_array($visibility)) { + $visibility = [$visibility]; + } + foreach ($visibility as $item) { + $auxArrayVisibility[] = (int) $item; + } + $visibilityString = implode(',', $auxArrayVisibility); } - $course_table = Database::get_main_table(TABLE_MAIN_COURSE); - $access_url_rel_course_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); + $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); + $accessUrlRelCourseTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $urlId = api_get_current_access_url_id(); if (api_is_multiple_url_enabled()) { $sql = "SELECT COUNT(*) AS number - FROM $course_table as c, $access_url_rel_course_table as u - WHERE u.c_id = c.id AND access_url_id='".$urlId."'"; - if (isset($visibility)) { - $sql .= " AND visibility = ".intval($visibility); - } + FROM $courseTable AS c, $accessUrlRelCourseTable AS u + WHERE u.c_id = c.id AND u.access_url_id='".$urlId."'"; } else { - $sql = "SELECT COUNT(*) AS number FROM $course_table "; - if (isset($visibility)) { - $sql .= " WHERE visibility = ".intval($visibility); - } + $sql = "SELECT COUNT(*) AS number + FROM $courseTable AS c + WHERE 1 = 1"; + } + $sql .= " AND visibility IN ($visibilityString) "; + if (!empty($dateFrom)) { + $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); + $sql .= " AND c.creation_date >= '$dateFrom' "; + } + if (!empty($dateUntil)) { + $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); + $sql .= " AND c.creation_date <= '$dateUntil' "; } $res = Database::query($sql); $obj = Database::fetch_object($res); @@ -1516,7 +1540,7 @@ class Statistics * * @return array */ - private static function getLoginsByDate($startDate, $endDate) + public static function getLoginsByDate(string $startDate, string $endDate): array { $startDate = api_get_utc_datetime("$startDate 00:00:00"); $endDate = api_get_utc_datetime("$endDate 23:59:59"); @@ -1665,4 +1689,88 @@ class Statistics return $groupedData; } + + /** + * Return de number of certificates generated. + * This function is resource intensive. + * @throws \Doctrine\DBAL\Exception + * @throws Exception + */ + public static function countCertificatesByQuarter(string $dateFrom = null, string $dateUntil = null): int + { + $tableGradebookCertificate = Database::get_main_table(TABLE_MAIN_GRADEBOOK_CERTIFICATE); + $condition = ""; + if (!empty($dateFrom) && !empty($dateUntil)) { + $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); + $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); + $condition = "WHERE (created_at BETWEEN '$dateFrom' AND '$dateUntil')"; + } elseif (!empty($dateFrom)) { + $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); + $condition = "WHERE created_at >= '$dateFrom'"; + } elseif (!empty($dateUntil)) { + $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); + $condition = "WHERE created_at <= '$dateUntil'"; + } + $sql = " + SELECT count(*) AS count + FROM $tableGradebookCertificate + $condition + "; + $response = Database::query($sql); + $obj = Database::fetch_object($response); + return $obj->count; + } + + /** + * Get the number of logins by dates. + * This function is resource intensive. + * @throws Exception + */ + public static function getSessionsByDuration(string $dateFrom, string $dateUntil): array + { + $results = [ + '0' => 0, + '5' => 0, + '10' => 0, + '15' => 0, + '30' => 0, + '60' => 0, + ]; + if (!empty($dateFrom) && !empty($dateUntil)) { + $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN); + $accessUrlRelUserTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); + $urlId = api_get_current_access_url_id(); + $tableUrl = ''; + $whereUrl = ''; + $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); + $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); + if (api_is_multiple_url_enabled()) { + $tableUrl = ", $accessUrlRelUserTable"; + $whereUrl = " AND login_user_id = user_id AND access_url_id = $urlId"; + } + $sql = "SELECT login_id, TIMESTAMPDIFF(SECOND, login_date, logout_date) AS duration + FROM $table $tableUrl + WHERE login_date >= '$dateFrom' + AND logout_date <= '$dateUntil' + $whereUrl + "; + $res = Database::query($sql); + while ($session = Database::fetch_array($res)) { + if ($session['duration'] > 3600) { + $results['60']++; + } elseif ($session['duration'] > 1800) { + $results['30']++; + } elseif ($session['duration'] > 900) { + $results['15']++; + } elseif ($session['duration'] > 600) { + $results['10']++; + } elseif ($session['duration'] > 300) { + $results['5']++; + } else { + $results['0']++; + } + } + } + return $results; + } } diff --git a/public/main/inc/lib/tracking.lib.php b/public/main/inc/lib/tracking.lib.php index 8373faa687..4c29d97603 100644 --- a/public/main/inc/lib/tracking.lib.php +++ b/public/main/inc/lib/tracking.lib.php @@ -8134,4 +8134,40 @@ class Tracking return $exeDate; } + /** + * Return the total time spent in courses (no the total in platform). + * + * @return int + * @throws \Doctrine\DBAL\Exception + */ + public static function getTotalTimeSpentInCourses( + string $dateFrom = '', + string $dateUntil = '' + ): int { + $tableTrackLogin = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS); + $tableUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); + $tableUrl = null; + $urlCondition = null; + $conditionTime = null; + if (api_is_multiple_url_enabled()) { + $accessUrlId = api_get_current_access_url_id(); + $tableUrl = ", ".$tableUrlRelUser." as url_users"; + $urlCondition = " AND u.user_id = url_users.user_id AND access_url_id = $accessUrlId"; + } + if (!empty($dateFrom) && !empty($dateUntil)) { + $dateFrom = Database::escape_string($dateFrom); + $dateUntil = Database::escape_string($dateUntil); + $conditionTime = " (login_course_date >= '$dateFrom' AND logout_course_date <= '$dateUntil' ) "; + } + $sql = "SELECT SUM(TIMESTAMPDIFF(HOUR, login_course_date, logout_course_date)) diff + FROM $tableTrackLogin u $tableUrl + WHERE $conditionTime $urlCondition"; + $rs = Database::query($sql); + $row = Database::fetch_array($rs, 'ASSOC'); + $diff = $row['diff']; + if ($diff >= 0 and !empty($diff)) { + return $diff; + } + return 0; + } } diff --git a/public/main/inc/lib/usermanager.lib.php b/public/main/inc/lib/usermanager.lib.php index a25621e931..0b126ae8ec 100644 --- a/public/main/inc/lib/usermanager.lib.php +++ b/public/main/inc/lib/usermanager.lib.php @@ -3368,27 +3368,33 @@ class UserManager /** * Get the total count of users. * - * @param int $status Status of users to be counted - * @param int $access_url_id Access URL ID (optional) - * @param int $active + * @param ?int $status Status of users to be counted + * @param ?int $access_url_id Access URL ID (optional) + * @param ?int $active * * @return mixed Number of users or false on error + * @throws \Doctrine\DBAL\Exception */ - public static function get_number_of_users($status = 0, $access_url_id = 1, $active = null) - { - $t_u = Database::get_main_table(TABLE_MAIN_USER); - $t_a = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); + public static function get_number_of_users( + ?int $status = 0, + ?int $access_url_id = 1, + ?int $active = null, + ?string $dateFrom = null, + ?string $dateUntil = null + ): mixed { + $tableUser = Database::get_main_table(TABLE_MAIN_USER); + $tableAccessUrlRelUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); if (api_is_multiple_url_enabled()) { $sql = "SELECT count(u.id) - FROM $t_u u - INNER JOIN $t_a url_user + FROM $tableUser u + INNER JOIN $tableAccessUrlRelUser url_user ON (u.id = url_user.user_id) WHERE url_user.access_url_id = $access_url_id "; } else { $sql = "SELECT count(u.id) - FROM $t_u u + FROM $tableUser u WHERE 1 = 1 "; } @@ -3397,11 +3403,20 @@ class UserManager $sql .= " AND u.status = $status "; } - if (null !== $active) { + if (isset($active)) { $active = (int) $active; $sql .= " AND u.active = $active "; } + if (!empty($dateFrom)) { + $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); + $sql .= " AND u.registration_date >= '$dateFrom' "; + } + if (!empty($dateUntil)) { + $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); + $sql .= " AND u.registration_date <= '$dateUntil' "; + } + $res = Database::query($sql); if (1 === Database::num_rows($res)) { return (int) Database::result($res, 0, 0); @@ -6066,4 +6081,106 @@ SQL; return $url; } + + /** + * Count users in courses and if they have certificate. + * This function is resource intensive. + * + * @return array + * @throws Exception + * @throws \Doctrine\DBAL\Exception + */ + public static function countUsersWhoFinishedCourses() + { + $courses = []; + $currentAccessUrlId = api_get_current_access_url_id(); + $sql = "SELECT course.code, cru.user_id + FROM course_rel_user cru + JOIN course ON cru.c_id = course.id + JOIN access_url_rel_user auru on cru.user_id = auru.user_id + JOIN access_url_rel_course ON course.id = access_url_rel_course.c_id + WHERE access_url_rel_course.access_url_id = $currentAccessUrlId + ORDER BY course.code + "; + $res = Database::query($sql); + if (Database::num_rows($res) > 0) { + while ($row = Database::fetch_array($res)) { + if (!isset($courses[$row['code']])) { + $courses[$row['code']] = [ + 'subscribed' => 0, + 'finished' => 0, + ]; + } + $courses[$row['code']]['subscribed']++; + $entityManager = Database::getManager(); + $repository = $entityManager->getRepository('ChamiloCoreBundle:GradebookCategory'); + //todo check when have more than 1 gradebook + /** @var \Chamilo\CoreBundle\Entity\GradebookCategory $gradebook */ + $gradebook = $repository->findOneBy(['courseCode' => $row['code']]); + if (!empty($gradebook)) { + $finished = 0; + $gb = Category::createCategoryObjectFromEntity($gradebook); + $finished = $gb->is_certificate_available($row['user_id']); + if (!empty($finished)) { + $courses[$row['code']]['finished']++; + } + } + } + } + return $courses; + } + + /** + * Count users in sessions and if they have certificate. + * This function is resource intensive. + * + * @return array + * @throws Exception + * @throws \Doctrine\DBAL\Exception + */ + public static function countUsersWhoFinishedCoursesInSessions() + { + $coursesInSessions = []; + $currentAccessUrlId = api_get_current_access_url_id(); + $sql = "SELECT course.code, srcru.session_id, srcru.user_id, session.title + FROM session_rel_course_rel_user srcru + JOIN course ON srcru.c_id = course.id + JOIN access_url_rel_session aurs on srcru.session_id = aurs.session_id + JOIN session ON srcru.session_id = session.id + WHERE aurs.access_url_id = $currentAccessUrlId + ORDER BY course.code, session.title + "; + $res = Database::query($sql); + if (Database::num_rows($res) > 0) { + while ($row = Database::fetch_array($res)) { + $index = $row['code'].' ('.$row['title'].')'; + if (!isset($coursesInSessions[$index])) { + $coursesInSessions[$index] = [ + 'subscribed' => 0, + 'finished' => 0, + ]; + } + $coursesInSessions[$index]['subscribed']++; + $entityManager = Database::getManager(); + $repository = $entityManager->getRepository('ChamiloCoreBundle:GradebookCategory'); + /** @var \Chamilo\CoreBundle\Entity\GradebookCategory $gradebook */ + $gradebook = $repository->findOneBy( + [ + 'courseCode' => $row['code'], + 'sessionId' => $row['session_id'], + ] + ); + if (!empty($gradebook)) { + $finished = 0; + $gb = Category::createCategoryObjectFromEntity($gradebook); + $finished = $gb->is_certificate_available($row['user_id']); + if (!empty($finished)) { + $coursesInSessions[$index]['finished']++; + } + } + } + } + return $coursesInSessions; + } + } diff --git a/public/plugin/dashboard/block_global_info/block_global_info.class.php b/public/plugin/dashboard/block_global_info/block_global_info.class.php index b66e3408a2..f874722542 100644 --- a/public/plugin/dashboard/block_global_info/block_global_info.class.php +++ b/public/plugin/dashboard/block_global_info/block_global_info.class.php @@ -122,11 +122,11 @@ class BlockGlobalInfo extends Block [get_lang('Number of active users'), ''.Statistics::countUsers(null, null, null, true).''], // Check number of courses [get_lang('Total number of courses'), ''.Statistics::countCourses().''], - [get_lang('Number of public courses'), ''.Statistics::countCoursesByVisibility(COURSE_VISIBILITY_OPEN_WORLD).''], - [get_lang('Number of open courses'), ''.Statistics::countCoursesByVisibility(COURSE_VISIBILITY_OPEN_PLATFORM).''], - [get_lang('Number of private courses'), ''.Statistics::countCoursesByVisibility(COURSE_VISIBILITY_REGISTERED).''], - [get_lang('Number of closed courses'), ''.Statistics::countCoursesByVisibility(COURSE_VISIBILITY_CLOSED).''], - [get_lang('Number of hidden courses'), ''.Statistics::countCoursesByVisibility(COURSE_VISIBILITY_HIDDEN).''], + [get_lang('Number of public courses'), ''.Statistics::countCoursesByVisibility([COURSE_VISIBILITY_OPEN_WORLD]).''], + [get_lang('Number of open courses'), ''.Statistics::countCoursesByVisibility([COURSE_VISIBILITY_OPEN_PLATFORM]).''], + [get_lang('Number of private courses'), ''.Statistics::countCoursesByVisibility([COURSE_VISIBILITY_REGISTERED]).''], + [get_lang('Number of closed courses'), ''.Statistics::countCoursesByVisibility([COURSE_VISIBILITY_CLOSED]).''], + [get_lang('Number of hidden courses'), ''.Statistics::countCoursesByVisibility([COURSE_VISIBILITY_HIDDEN]).''], ]; } } From 29359940175debcdb438bb6443182de2af5e3caf Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Thu, 23 Jan 2025 15:02:26 +0100 Subject: [PATCH 2/3] Internal: Convert deprecated api_is_multiple_url_enabled() to AccessUrlHelper::isMultiple() --- public/main/inc/lib/statistics.lib.php | 37 +++++++++++++------------- public/main/inc/lib/tracking.lib.php | 21 ++++++++------- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/public/main/inc/lib/statistics.lib.php b/public/main/inc/lib/statistics.lib.php index cbb3b9bca5..d7c8589a5c 100644 --- a/public/main/inc/lib/statistics.lib.php +++ b/public/main/inc/lib/statistics.lib.php @@ -5,6 +5,7 @@ use Chamilo\CoreBundle\Component\Utils\ChamiloApi; use Chamilo\CoreBundle\Entity\MessageRelUser; use Chamilo\CoreBundle\Entity\UserRelUser; use Chamilo\CoreBundle\Component\Utils\ActionIcon; +use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper; /** * This class provides some functions for statistics. @@ -50,7 +51,7 @@ class Statistics $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); $accessUrlRelCourseTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT COUNT(*) AS number FROM ".$courseTable." AS c, $accessUrlRelCourseTable AS u WHERE u.c_id = c.id AND $accessUrlRelCourseTable='".$urlId."'"; @@ -113,7 +114,7 @@ class Statistics $courseTable = Database::get_main_table(TABLE_MAIN_COURSE); $accessUrlRelCourseTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT COUNT(*) AS number FROM $courseTable AS c, $accessUrlRelCourseTable AS u WHERE u.c_id = c.id AND u.access_url_id='".$urlId."'"; @@ -173,7 +174,7 @@ class Statistics $where = implode(' AND ', $conditions); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT COUNT(DISTINCT(u.id)) AS number FROM $user_table as u INNER JOIN $access_url_rel_user_table as url ON u.id = url.user_id @@ -227,7 +228,7 @@ class Statistics $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT DISTINCT(t.c_id) FROM $table t , $access_url_rel_course_table a WHERE t.c_id = a.c_id AND @@ -256,7 +257,7 @@ class Statistics $table_user = Database::get_main_table(TABLE_MAIN_USER); $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT count(default_id) AS total_number_of_items FROM $track_e_default, $table_user user, $access_url_rel_user_table url WHERE user.active <> ".USER_SOFT_DELETED." AND @@ -322,7 +323,7 @@ class Statistics $direction = 'DESC'; } - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT default_event_type as col0, default_value_type as col1, @@ -546,7 +547,7 @@ class Statistics $where_url = null; $now = api_get_utc_datetime(); $where_url_last = ' WHERE login_date > DATE_SUB("'.$now.'",INTERVAL 1 %s)'; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $table_url = ", $access_url_rel_user_table"; $where_url = " WHERE login_user_id=user_id AND access_url_id='".$urlId."'"; $where_url_last = ' AND login_date > DATE_SUB("'.$now.'",INTERVAL 1 %s)'; @@ -646,7 +647,7 @@ class Statistics $urlId = api_get_current_access_url_id(); $table_url = ''; $where_url = ''; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $table_url = ", $access_url_rel_user_table"; $where_url = " AND login_user_id=user_id AND access_url_id='".$urlId."'"; } @@ -736,7 +737,7 @@ class Statistics $urlId = api_get_current_access_url_id(); $table_url = ''; $where_url = ''; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $table_url = ", $access_url_rel_user_table"; $where_url = " AND login_user_id=user_id AND access_url_id='".$urlId."'"; } @@ -802,7 +803,7 @@ class Statistics foreach ($tools as $tool) { $tool_names[$tool] = get_lang(ucfirst($tool), ''); } - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT access_tool, count( access_id ) AS number_of_logins FROM $table t , $access_url_rel_course_table a WHERE @@ -851,7 +852,7 @@ class Statistics $table = Database::get_main_table(TABLE_MAIN_COURSE); $access_url_rel_course_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT course_language, count( c.code ) AS number_of_courses FROM $table as c, $access_url_rel_course_table as u WHERE u.c_id = c.id AND access_url_id='".$urlId."' @@ -882,7 +883,7 @@ class Statistics $url_condition = null; $url_condition2 = null; $table = null; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $url_condition = ", $access_url_rel_user_table as url WHERE url.user_id=u.id AND access_url_id='".$urlId."'"; $url_condition2 = " AND url.user_id=u.id AND access_url_id='".$urlId."'"; $table = ", $access_url_rel_user_table as url "; @@ -995,7 +996,7 @@ class Statistics $values = $form->exportValues(); $date_diff = $values['date_diff']; $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT * FROM $table t , $access_url_rel_course_table a WHERE c_id = a.c_id AND @@ -1074,7 +1075,7 @@ class Statistics break; } - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT u.lastname, u.firstname, u.username, COUNT(DISTINCT m.id) AS count_message FROM $messageTable m INNER JOIN $messageRelUserTable mru ON $joinCondition @@ -1119,7 +1120,7 @@ class Statistics $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend FROM $access_url_rel_user_table as url, $user_friend_table uf LEFT JOIN $user_table u @@ -1159,7 +1160,7 @@ class Statistics $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $urlId = api_get_current_access_url_id(); $total = self::countUsers(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $table_url = ", $access_url_rel_user_table"; $where_url = " AND login_user_id=user_id AND access_url_id='".$urlId."'"; } else { @@ -1554,7 +1555,7 @@ class Statistics $urlJoin = ''; $urlWhere = ''; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $urlJoin = "INNER JOIN $tblUrlUser au ON u.id = au.user_id"; @@ -1744,7 +1745,7 @@ class Statistics $whereUrl = ''; $dateFrom = api_get_utc_datetime("$dateFrom 00:00:00"); $dateUntil = api_get_utc_datetime("$dateUntil 23:59:59"); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $tableUrl = ", $accessUrlRelUserTable"; $whereUrl = " AND login_user_id = user_id AND access_url_id = $urlId"; } diff --git a/public/main/inc/lib/tracking.lib.php b/public/main/inc/lib/tracking.lib.php index 4c29d97603..5649073551 100644 --- a/public/main/inc/lib/tracking.lib.php +++ b/public/main/inc/lib/tracking.lib.php @@ -20,6 +20,7 @@ use CpChart\Image as pImage; use ExtraField as ExtraFieldModel; use Chamilo\CoreBundle\Component\Utils\ActionIcon; use Chamilo\CoreBundle\Component\Utils\StateIcon; +use Chamilo\CoreBundle\ServiceHelper\AccessUrlHelper; /** * Class Tracking. @@ -1745,7 +1746,7 @@ class Tracking $url_condition = null; $tbl_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $url_table = null; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $access_url_id = api_get_current_access_url_id(); $url_table = ", $tbl_url_rel_user as url_users"; $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'"; @@ -1827,7 +1828,7 @@ class Tracking $url_table = null; $url_condition = null; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $access_url_id = api_get_current_access_url_id(); $url_table = ", ".$tbl_url_rel_user." as url_users"; $url_condition = " AND u.login_user_id = url_users.user_id AND access_url_id='$access_url_id'"; @@ -3599,7 +3600,7 @@ class Tracking $tbl_session_user = Database::get_main_table(TABLE_MAIN_SESSION_USER); $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION); - $accessUrlEnabled = api_is_multiple_url_enabled(); + $accessUrlEnabled = AccessUrlHelper::isMultiple(); $access_url_id = $accessUrlEnabled ? api_get_current_access_url_id() : -1; $students = []; @@ -3754,7 +3755,7 @@ class Tracking ON (c.id = sc.c_id) WHERE sc.user_id = '.$coach_id.' AND sc.status = '.SessionEntity::COURSE_COACH; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $access_url_id = api_get_current_access_url_id(); if (-1 != $access_url_id) { $sql = 'SELECT DISTINCT c.code @@ -3792,7 +3793,7 @@ class Tracking INNER JOIN $tbl_course as course ON course.id = session_course.c_id"; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE); $access_url_id = api_get_current_access_url_id(); if (-1 != $access_url_id) { @@ -3815,11 +3816,11 @@ class Tracking if (!empty($sessionId)) { $sql .= ' WHERE session_course.session_id='.$sessionId; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql .= ' AND access_url_id = '.$access_url_id; } } else { - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql .= ' WHERE access_url_id = '.$access_url_id; } } @@ -4596,7 +4597,7 @@ class Tracking $session_id = (int) $session_id; $urlId = api_get_current_access_url_id(); - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT c.id, c.code, title FROM $tbl_course_user cu INNER JOIN $tbl_course c @@ -4643,7 +4644,7 @@ class Tracking } // Get the list of sessions where the user is subscribed as student - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $sql = "SELECT DISTINCT c.code, s.id as session_id, s.title FROM $tbl_session_course_user cu INNER JOIN $tbl_access_rel_session a @@ -8149,7 +8150,7 @@ class Tracking $tableUrl = null; $urlCondition = null; $conditionTime = null; - if (api_is_multiple_url_enabled()) { + if (AccessUrlHelper::isMultiple()) { $accessUrlId = api_get_current_access_url_id(); $tableUrl = ", ".$tableUrlRelUser." as url_users"; $urlCondition = " AND u.user_id = url_users.user_id AND access_url_id = $accessUrlId"; From 24ebed69f35318c34c91b3c3ade7dfe801038636 Mon Sep 17 00:00:00 2001 From: Yannick Warnier Date: Thu, 23 Jan 2025 15:28:58 +0100 Subject: [PATCH 3/3] Internal: Extend timeout for composer execution (taking longer than the default 300s timeout in some cases) --- composer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1d4caaf729..1ed2adea4c 100755 --- a/composer.json +++ b/composer.json @@ -181,7 +181,8 @@ "symfony/flex": true, "dealerdirect/phpcodesniffer-composer-installer": true, "symfony/runtime": true - } + }, + "process-timeout": 900 }, "require-dev": { "behat/behat": "^3.10",