diff --git a/public/main/admin/statistics/index.php b/public/main/admin/statistics/index.php index 7bef0ffad0f..a1aad38a435 100644 --- a/public/main/admin/statistics/index.php +++ b/public/main/admin/statistics/index.php @@ -785,49 +785,6 @@ } // courses for each course category $content .= Statistics::printStats(get_lang('Courses'), $courses); - - $content .= ' - - - '; - $content .= ' - '; - break; case 'tools': $content .= ''; diff --git a/public/main/inc/lib/statistics.lib.php b/public/main/inc/lib/statistics.lib.php index df472770524..106936329a0 100644 --- a/public/main/inc/lib/statistics.lib.php +++ b/public/main/inc/lib/statistics.lib.php @@ -1950,71 +1950,38 @@ public static function getUnsubscriptionsByDay(string $startDate, string $endDat } /** - * Returns users who have activity in open courses without being officially enrolled. + * Users with activity in this course but not officially enrolled (optionally in a session). */ - public static function getUsersWithActivityButNotRegistered(int $sessionId = 0): array + public static function getNonRegisteredActiveUsersInCourse(int $courseId, int $sessionId = 0): array { $em = Database::getManager(); $qb = $em->createQueryBuilder(); - $qb->select('t.accessUserId AS userId, t.cId AS courseId, MAX(t.accessDate) AS lastAccess') + $qb->select('u.id AS id, u.firstname AS firstname, u.lastname AS lastname, u.email AS email, MAX(t.accessDate) AS lastAccess') ->from(TrackEAccess::class, 't') - ->where('t.accessUserId IS NOT NULL') - ->andWhere('t.cId IS NOT NULL') - ->groupBy('t.accessUserId, t.cId'); + ->join(User::class, 'u', 'WITH', 'u.id = t.accessUserId') + ->leftJoin( + CourseRelUser::class, + 'cu', + 'WITH', + 'cu.user = u AND cu.course = :courseId'.($sessionId > 0 ? ' AND cu.session = :sessionId' : '') + ) + ->where('t.cId = :courseId') + ->andWhere('t.accessUserId IS NOT NULL') + ->andWhere('cu.id IS NULL') + ->groupBy('u.id, u.firstname, u.lastname, u.email') + ->orderBy('lastAccess', 'DESC') + ->setParameter('courseId', $courseId); if ($sessionId > 0) { - $qb->andWhere('t.sessionId = :sessionId') - ->setParameter('sessionId', $sessionId); + $qb->andWhere('t.sessionId = :sessionId')->setParameter('sessionId', $sessionId); } - $results = $qb->getQuery()->getArrayResult(); - - $nonRegistered = []; - - foreach ($results as $row) { - $userId = $row['userId']; - $courseId = $row['courseId']; - - $course = $em->getRepository(Course::class)->find($courseId); - if (!$course) { - continue; - } - - if (!\in_array($course->getVisibility(), [Course::OPEN_PLATFORM, Course::OPEN_WORLD], true)) { - continue; - } - - $isRegistered = $em->createQueryBuilder() - ->select('1') - ->from(CourseRelUser::class, 'cu') - ->where('cu.user = :userId AND cu.course = :courseId') - ->setParameter('userId', $userId) - ->setParameter('courseId', $courseId); - - if ($sessionId > 0) { - $isRegistered->andWhere('cu.session = :sessionId') - ->setParameter('sessionId', $sessionId); - } - - if (empty($isRegistered->getQuery()->getResult())) { - $user = $em->getRepository(User::class)->find($userId); - if (!$user) { - continue; - } - - $nonRegistered[] = [ - 'id' => $user->getId(), - 'firstname' => $user->getFirstname(), - 'lastname' => $user->getLastname(), - 'email' => $user->getEmail(), - 'courseTitle' => $course->getTitle(), - 'courseCode' => $course->getCode(), - 'lastAccess' => $row['lastAccess'] ? (new \DateTime($row['lastAccess']))->format('Y-m-d H:i:s') : '', - ]; - } + $rows = $qb->getQuery()->getArrayResult(); + foreach ($rows as &$r) { + $r['lastAccess'] = !empty($r['lastAccess']) ? (new \DateTime($r['lastAccess']))->format('Y-m-d H:i:s') : ''; } - return $nonRegistered; + return $rows; } } diff --git a/public/main/tracking/courseLog.php b/public/main/tracking/courseLog.php index 1d2920ccc97..3afb0a4e1f9 100644 --- a/public/main/tracking/courseLog.php +++ b/public/main/tracking/courseLog.php @@ -47,6 +47,45 @@ } } +if (!empty($_GET['ajax']) && (int) $_GET['ajax'] === 1 && (($_GET['fragment'] ?? '') === 'non_registered')) { + $nrUsers = Statistics::getNonRegisteredActiveUsersInCourse($courseId, (int) $sessionId); + + $out = ''; + $out .= Display::page_subheader2(get_lang('Users active in this course (not enrolled)')); + $out .= Display::tag('p', get_lang('These users accessed the course without an official subscription.')); + + if (!empty($nrUsers)) { + $table = new HTML_Table(['class' => 'table table-hover table-striped data_table']); + $col = 0; + $table->setHeaderContents(0, $col++, get_lang('Name')); + if ('true' === api_get_setting('show_email_addresses')) { + $table->setHeaderContents(0, $col++, get_lang('E-mail')); + } + $table->setHeaderContents(0, $col++, get_lang('Last access')); + + $row = 1; + foreach ($nrUsers as $u) { + $fullname = Security::remove_XSS(trim(($u['firstname'] ?? '').' '.($u['lastname'] ?? ''))); + $email = Security::remove_XSS($u['email'] ?? ''); + $last = Security::remove_XSS($u['lastAccess'] ?? ''); + + $col = 0; + $table->setCellContents($row, $col++, Display::tag('strong', $fullname)); + if ('true' === api_get_setting('show_email_addresses')) { + $table->setCellContents($row, $col++, $email); + } + $table->setCellContents($row, $col++, $last); + $row++; + } + $out .= $table->toHtml(); + } else { + $out .= Display::tag('p', get_lang('No users found.')); + } + + echo $out; + exit; +} + // Starting the output buffering when we are exporting the information. $export_csv = isset($_GET['export']) && 'csv' === $_GET['export']; @@ -167,6 +206,50 @@ function(index) { "; $htmlHeadXtra[] = $js; +$labelShow = addslashes(get_lang('Show users active (not enrolled)')); +$labelHide = addslashes(get_lang('Hide users active (not enrolled)')); +$ajaxUrl = api_get_self().'?'.http_build_query([ + 'ajax' => 1, + 'fragment' => 'non_registered', + 'cid' => (int) $courseId, + 'sid' => (int) $sessionId, + ]); + +$js_nonreg = ""; +$htmlHeadXtra[] = $js_nonreg; + // Database table definitions. //@todo remove this calls $TABLETRACK_EXERCISES = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES); @@ -267,6 +350,8 @@ function(index) { $users_tracking_per_page = '&users_tracking_per_page='.intval($_GET['users_tracking_per_page']); } +$showNonRegistered = isset($_GET['show_non_registered']) ? (int) $_GET['show_non_registered'] : 0; + $actionsRight .= ' '.Display::getMdiIcon(ActionIcon::EXPORT_CSV, 'ch-tool-icon', null, ICON_SIZE_MEDIUM, get_lang('CSV export')).''; @@ -847,6 +932,14 @@ function(index) { $html .= Display::return_message(get_lang('No users in course'), 'warning', true); } +$labelShowBtn = get_lang('Show users active (not enrolled)'); +$html .= '
'; +$html .= ''; +$html .= '
'; + +$html .= ''; + $groupContent = ''; echo Display::panel($html, $titleSession);