Merge pull request #5217 from christianbeeznest/GH-5097

User: Add deleting users in 2 steps - refs #5097
pull/5223/head
christianbeeznest 2 years ago committed by GitHub
commit e44b52ee0e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 41
      assets/css/app.scss
  2. 1
      public/documentation/changelog.html
  3. 4
      public/documentation/legacy/changelog.html
  4. 4
      public/main/admin/access_url_add_users_to_url.php
  5. 2
      public/main/admin/access_url_check_user_session.php
  6. 10
      public/main/admin/dashboard_add_users_to_user.php
  7. 6
      public/main/admin/user_edit.php
  8. 347
      public/main/admin/user_list.php
  9. 2
      public/main/admin/user_list_consent.php
  10. 2
      public/main/cron/request_removal_reminder.php
  11. 1
      public/main/inc/ajax/exercise.ajax.php
  12. 2
      public/main/inc/lib/SkillModel.php
  13. 3
      public/main/inc/lib/TicketManager.php
  14. 2
      public/main/inc/lib/access_url_edit_users_to_url_functions.lib.php
  15. 6
      public/main/inc/lib/api.lib.php
  16. 9
      public/main/inc/lib/course.lib.php
  17. 2
      public/main/inc/lib/exercise.lib.php
  18. 2
      public/main/inc/lib/groupmanager.lib.php
  19. 6
      public/main/inc/lib/myspace.lib.php
  20. 10
      public/main/inc/lib/online.inc.php
  21. 13
      public/main/inc/lib/sessionmanager.lib.php
  22. 23
      public/main/inc/lib/statistics.lib.php
  23. 4
      public/main/inc/lib/sub_language.class.php
  24. 2
      public/main/inc/lib/tracking.lib.php
  25. 4
      public/main/inc/lib/urlmanager.lib.php
  26. 5
      public/main/inc/lib/usergroup.lib.php
  27. 70
      public/main/inc/lib/usermanager.lib.php
  28. 1
      public/main/inc/lib/zombie/zombie_manager.class.php
  29. 23
      public/main/user/add_users_to_session.php
  30. 4
      public/main/user/resume_session.php
  31. 10
      public/main/user/subscribe_user.php
  32. 3
      public/main/user/user.php
  33. 7
      public/main/user/user_export.php
  34. 2
      src/CoreBundle/Component/Utils/StateIcon.php
  35. 17
      src/CoreBundle/Controller/SecurityController.php
  36. 22
      src/CoreBundle/Entity/User.php
  37. 34
      src/CoreBundle/Migrations/Schema/V200/Version20240306204200.php
  38. 33
      src/CoreBundle/Repository/Node/UserRepository.php

@ -220,6 +220,10 @@
@import "scss/index.scss"; @import "scss/index.scss";
.field > small.p-error {
@apply text-error;
}
// tabs // tabs
.tab-content { .tab-content {
> .tab-pane { > .tab-pane {
@ -385,6 +389,43 @@
cursor: pointer; cursor: pointer;
} }
.users-list {
.nav-tabs {
display: flex;
list-style-type: none;
padding: 0;
border-bottom: 1px solid #ddd;
margin: 0 0 20px;
}
.nav-tabs .nav-item {
margin-bottom: -1px;
}
.nav-tabs .nav-link {
display: block;
padding: 0.5rem 1rem;
margin-right: 0.1rem;
background: #f8f8f8;
border: 1px solid #ddd;
border-radius: 0.25rem 0.25rem 0 0;
text-decoration: none;
color: #555;
}
.nav-tabs .nav-link:hover {
background-color: #e9ecef;
}
.nav-tabs .nav-link.active {
color: #495057;
background-color: #fff;
border-color: #ddd #ddd #fff;
border-bottom-color: transparent;
font-weight: bolder;
}
}
//@import 'primevue-md-light-indigo/theme.css'; //@import 'primevue-md-light-indigo/theme.css';
//@import '~primevue/resources/primevue.min.css'; //@import '~primevue/resources/primevue.min.css';
//@import '~primeflex/primeflex.css'; //@import '~primeflex/primeflex.css';

@ -90,7 +90,6 @@
<li>Blogs: The blogs tool is not available. It might be included again in future versions, but there were too many changes required to include it in v2.0.</li> <li>Blogs: The blogs tool is not available. It might be included again in future versions, but there were too many changes required to include it in v2.0.</li>
<li>Dropbox: The dropbox tool is not available. It might be included again in future versions, but there were too many changes required to include it in v2.0.</li> <li>Dropbox: The dropbox tool is not available. It might be included again in future versions, but there were too many changes required to include it in v2.0.</li>
<li>Global: Sub-folder mode: Chamilo 2 will not support being installed in a sub-folder. Nowadays, defining a subdomain has become very easy and provides higher security and more configuration flexibility, and supporting sub-folders is a complex task.</li> <li>Global: Sub-folder mode: Chamilo 2 will not support being installed in a sub-folder. Nowadays, defining a subdomain has become very easy and provides higher security and more configuration flexibility, and supporting sub-folders is a complex task.</li>
<li>WYSIWYG: New online editor with different implementation as Chamilo 1. Will take time to re-integrate all toolbar options into v2, so advanced features (math formula, easy integration of YT video, etc) temporarily disabled.</li>
</ul> </ul>
<h3>Known issues</h3> <h3>Known issues</h3>

@ -299,7 +299,7 @@
<li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/6cd142ffd650e7fe5aadce7fb56a1318653114cc">6cd142ff</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2555">GH#2555</a>) Privacy: If user sends remove account request, delete the remove legal request</li> <li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/6cd142ffd650e7fe5aadce7fb56a1318653114cc">6cd142ff</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2555">GH#2555</a>) Privacy: If user sends remove account request, delete the remove legal request</li>
<li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/531e4505434e0d8cd718fbc5517f56c30846bb4d">531e4505</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2555">GH#2555</a>) Privacy: Add "erase account" extra fields</li> <li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/531e4505434e0d8cd718fbc5517f56c30846bb4d">531e4505</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2555">GH#2555</a>) Privacy: Add "erase account" extra fields</li>
<li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/ecb18907a7fec22402411aa873382a4bd06cb07d">ecb18907</a>) Internal: Maintenance: Remove use of Course::unserialize() when exporting/importing course bk</li> <li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/ecb18907a7fec22402411aa873382a4bd06cb07d">ecb18907</a>) Internal: Maintenance: Remove use of Course::unserialize() when exporting/importing course bk</li>
<li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/0683b23602b5fd0505e4d96442f573095c299597">0683b236</a>) Internal: Create the main.language.js file even if we're in CLI</li> <li>[2018-08-06] (<a href="https://github.com/chamilo/chamilo-lms/commit/0683b23602b5fd0505e4d96442f573095c299597">0683b236</a>) Internal: Create the main.languageService.js file even if we're in CLI</li>
<li>[2018-08-03] (<a href="https://github.com/chamilo/chamilo-lms/commit/c2b4f937520fe843f757b78bd77e88c10c091527">c2b4f937</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2616">GH#2616</a>) Quiz: Fix empty lines appearing when no question details set to appear</li> <li>[2018-08-03] (<a href="https://github.com/chamilo/chamilo-lms/commit/c2b4f937520fe843f757b78bd77e88c10c091527">c2b4f937</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2616">GH#2616</a>) Quiz: Fix empty lines appearing when no question details set to appear</li>
<li>[2018-08-03] (<a href="https://github.com/chamilo/chamilo-lms/commit/3400f430a5a70bbd49c261affe5288330abf2291">3400f430</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2572">GH#2572</a>) Learnpath: Quiz: Fix issue preventing save buttons for individual questions and end of test when quizzes are included into learning paths on Apple devices</li> <li>[2018-08-03] (<a href="https://github.com/chamilo/chamilo-lms/commit/3400f430a5a70bbd49c261affe5288330abf2291">3400f430</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2572">GH#2572</a>) Learnpath: Quiz: Fix issue preventing save buttons for individual questions and end of test when quizzes are included into learning paths on Apple devices</li>
<li>[2018-08-03] (<a href="https://github.com/chamilo/chamilo-lms/commit/618c56cd90e1f00fac11df9cb0c35dd4c68539da">618c56cd</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2555">GH#2555</a>) Privacy: Add "Delete legal agreement" button</li> <li>[2018-08-03] (<a href="https://github.com/chamilo/chamilo-lms/commit/618c56cd90e1f00fac11df9cb0c35dd4c68539da">618c56cd</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2555">GH#2555</a>) Privacy: Add "Delete legal agreement" button</li>
@ -314,7 +314,7 @@
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/6413516bfd53050deb97eb0425ec5392d4281883">6413516b</a>) Internal: Improve language terms scanning script - re-enable die() call to avoid non-authorized execution</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/6413516bfd53050deb97eb0425ec5392d4281883">6413516b</a>) Internal: Improve language terms scanning script - re-enable die() call to avoid non-authorized execution</li>
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/c1478e829702662c89003967764df4b1691305a1">c1478e82</a>) Internal: Improve language terms scanning script</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/c1478e829702662c89003967764df4b1691305a1">c1478e82</a>) Internal: Improve language terms scanning script</li>
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/992b79c624a8f524a4fb33a139befb0e1c7f10d1">992b79c6</a>) Template: Fix missing get_lang call for LightBlue in skill wheel</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/992b79c624a8f524a4fb33a139befb0e1c7f10d1">992b79c6</a>) Template: Fix missing get_lang call for LightBlue in skill wheel</li>
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/7a6691647c213b1b950b622de685710b2220a4a8">7a669164</a>) Internal: Add error checking before writing web/build/main.language.js</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/7a6691647c213b1b950b622de685710b2220a4a8">7a669164</a>) Internal: Add error checking before writing web/build/main.languageService.js</li>
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/13676a5dcbbe59e51304dd7eb6ba971726965942">13676a5d</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2574">GH#2574</a>) Install: Use "SET SESSION sql_mode" to avoid issues with bin/doctrine.php when we don't have global DB privileges</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/13676a5dcbbe59e51304dd7eb6ba971726965942">13676a5d</a> - <a href="https://github.com/chamilo/chamilo-lms/issues/2574">GH#2574</a>) Install: Use "SET SESSION sql_mode" to avoid issues with bin/doctrine.php when we don't have global DB privileges</li>
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/dd29d0f3126e5d62bd1d3aea646e10766a752766">dd29d0f3</a>) Internal: Remove TEACHER case from get_status_from_code(): TEACHER constant doesn't exist.</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/dd29d0f3126e5d62bd1d3aea646e10766a752766">dd29d0f3</a>) Internal: Remove TEACHER case from get_status_from_code(): TEACHER constant doesn't exist.</li>
<li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/6075671b780dd703ab4e03a6e33771d83f97198f">6075671b</a>) Quiz: Add link to user profile in test results header table</li> <li>[2018-08-02] (<a href="https://github.com/chamilo/chamilo-lms/commit/6075671b780dd703ab4e03a6e33771d83f97198f">6075671b</a>) Quiz: Add link to user profile in test results header table</li>

@ -66,7 +66,7 @@ if ($_POST['form_sent']) {
/* Display GUI */ /* Display GUI */
if (empty($first_letter_user)) { if (empty($first_letter_user)) {
$sql = "SELECT count(*) as nb_users FROM $tbl_user"; $sql = "SELECT count(*) as nb_users FROM $tbl_user WHERE active <> ".USER_SOFT_DELETED;
$result = Database::query($sql); $result = Database::query($sql);
$num_row = Database::fetch_array($result); $num_row = Database::fetch_array($result);
if ($num_row['nb_users'] > 1000) { if ($num_row['nb_users'] > 1000) {
@ -81,7 +81,7 @@ $first_letter_user_lower = Database::escape_string(api_strtolower($first_letter_
$target_name = api_sort_by_first_name() ? 'firstname' : 'lastname'; $target_name = api_sort_by_first_name() ? 'firstname' : 'lastname';
$target_name = 'lastname'; $target_name = 'lastname';
$sql = "SELECT user_id,lastname,firstname,username FROM $tbl_user $sql = "SELECT user_id,lastname,firstname,username FROM $tbl_user
WHERE ".$target_name." LIKE '".$first_letter_user_lower."%' OR ".$target_name." LIKE '".$first_letter_user_lower."%' WHERE active <> ".USER_SOFT_DELETED." AND ".$target_name." LIKE '".$first_letter_user_lower."%' OR ".$target_name." LIKE '".$first_letter_user_lower."%'
ORDER BY ".(count($users) > 0 ? '(user_id IN('.implode(',', $users).')) DESC,' : '').' '.$target_name; ORDER BY ".(count($users) > 0 ? '(user_id IN('.implode(',', $users).')) DESC,' : '').' '.$target_name;
$result = Database::query($sql); $result = Database::query($sql);
$db_users = Database::store_result($result); $db_users = Database::store_result($result);

@ -78,7 +78,7 @@ foreach ($session_list as $session_item) {
ON u.id = su.user_id AND su.relation_type <> ".Session::DRH." ON u.id = su.user_id AND su.relation_type <> ".Session::DRH."
LEFT OUTER JOIN $table_access_url_user uu LEFT OUTER JOIN $table_access_url_user uu
ON (uu.user_id = u.id) ON (uu.user_id = u.id)
WHERE su.session_id = $session_id AND $access_where WHERE su.session_id = $session_id AND $access_where AND u.active <> ".USER_SOFT_DELETED."
$order_clause"; $order_clause";
$result = Database::query($sql); $result = Database::query($sql);

@ -103,7 +103,7 @@ function search_users($needle, $type = 'multiple')
$sql = "SELECT user.id as user_id, username, lastname, firstname $sql = "SELECT user.id as user_id, username, lastname, firstname
FROM $tbl_user user FROM $tbl_user user
LEFT JOIN $tbl_access_url_rel_user au ON (au.user_id = user.id) LEFT JOIN $tbl_access_url_rel_user au ON (au.user_id = user.id)
WHERE WHERE user.active <> ".USER_SOFT_DELETED." AND
".(api_sort_by_first_name() ? 'firstname' : 'lastname')." LIKE '$needle%' AND ".(api_sort_by_first_name() ? 'firstname' : 'lastname')." LIKE '$needle%' AND
status NOT IN(".DRH.', '.SESSIONADMIN.', '.STUDENT_BOSS.") AND status NOT IN(".DRH.', '.SESSIONADMIN.', '.STUDENT_BOSS.") AND
user.id NOT IN ($user_anonymous, $current_user_id, $user_id) user.id NOT IN ($user_anonymous, $current_user_id, $user_id)
@ -114,7 +114,7 @@ function search_users($needle, $type = 'multiple')
} else { } else {
$sql = "SELECT id as user_id, username, lastname, firstname $sql = "SELECT id as user_id, username, lastname, firstname
FROM $tbl_user user FROM $tbl_user user
WHERE WHERE user.active <> ".USER_SOFT_DELETED." AND
".(api_sort_by_first_name() ? 'firstname' : 'lastname')." LIKE '$needle%' AND ".(api_sort_by_first_name() ? 'firstname' : 'lastname')." LIKE '$needle%' AND
status NOT IN(".DRH.', '.SESSIONADMIN.', '.STUDENT_BOSS.") AND status NOT IN(".DRH.', '.SESSIONADMIN.', '.STUDENT_BOSS.") AND
id NOT IN ($user_anonymous, $current_user_id, $user_id) id NOT IN ($user_anonymous, $current_user_id, $user_id)
@ -132,7 +132,7 @@ function search_users($needle, $type = 'multiple')
$sql = 'SELECT user.id as user_id, username, lastname, firstname $sql = 'SELECT user.id as user_id, username, lastname, firstname
FROM '.$tbl_user.' user FROM '.$tbl_user.' user
INNER JOIN '.$tbl_user_rel_access_url.' url_user ON (url_user.user_id=user.id) INNER JOIN '.$tbl_user_rel_access_url.' url_user ON (url_user.user_id=user.id)
WHERE WHERE user.active <> '.USER_SOFT_DELETED.' AND
access_url_id = '.$access_url_id.' AND access_url_id = '.$access_url_id.' AND
( (
username LIKE "'.$needle.'%" OR username LIKE "'.$needle.'%" OR
@ -400,7 +400,7 @@ if (api_is_multiple_url_enabled()) {
FROM $tbl_user user FROM $tbl_user user
LEFT JOIN $tbl_access_url_rel_user au LEFT JOIN $tbl_access_url_rel_user au
ON (au.user_id = user.id) ON (au.user_id = user.id)
WHERE WHERE user.active <> ".USER_SOFT_DELETED." AND
$without_assigned_users $without_assigned_users
user.id NOT IN ($user_anonymous, $current_user_id, $user_id) AND user.id NOT IN ($user_anonymous, $current_user_id, $user_id) AND
status NOT IN(".DRH.', '.SESSIONADMIN.', '.ANONYMOUS.") $search_user AND status NOT IN(".DRH.', '.SESSIONADMIN.', '.ANONYMOUS.") $search_user AND
@ -410,7 +410,7 @@ if (api_is_multiple_url_enabled()) {
} else { } else {
$sql = "SELECT id as user_id, username, lastname, firstname $sql = "SELECT id as user_id, username, lastname, firstname
FROM $tbl_user user FROM $tbl_user user
WHERE WHERE user.active <> -1 AND
$without_assigned_users $without_assigned_users
id NOT IN ($user_anonymous, $current_user_id, $user_id) AND id NOT IN ($user_anonymous, $current_user_id, $user_id) AND
status NOT IN(".DRH.', '.SESSIONADMIN.', '.ANONYMOUS.") status NOT IN(".DRH.', '.SESSIONADMIN.', '.ANONYMOUS.")

@ -435,7 +435,11 @@ if ($form->validate()) {
$expiration_date = $user['expiration_date']; $expiration_date = $user['expiration_date'];
} }
$active = $user_data['platform_admin'] ? 1 : intval($user['active']); if (isset($user['active'])) {
$active = $user_data['platform_admin'] ? USER_ACTIVE : intval($user['active']);
} else {
$active = USER_SOFT_DELETED;
}
//If the user is set to admin the status will be overwrite by COURSEMANAGER = 1 //If the user is set to admin the status will be overwrite by COURSEMANAGER = 1
if (1 == $platform_admin) { if (1 == $platform_admin) {

@ -18,6 +18,8 @@ $urlId = api_get_current_access_url_id();
$currentUserId = api_get_user_id(); $currentUserId = api_get_user_id();
$action = $_REQUEST['action'] ?? ''; $action = $_REQUEST['action'] ?? '';
$view = $_GET['view'] ?? 'all';
$showDeletedUsers = 'deleted' === $view;
// Login as can be used by different roles // Login as can be used by different roles
if (isset($_GET['user_id']) && 'login_as' === $action) { if (isset($_GET['user_id']) && 'login_as' === $action) {
@ -73,37 +75,27 @@ if ($variables) {
Session::write('variables_to_show', $variablesToShow); Session::write('variables_to_show', $variablesToShow);
$htmlHeadXtra[] = '<script> $htmlHeadXtra[] = '<script>
function active_user(element_div) { function active_user(element) {
id_image=$(element_div).attr("id"); var userId = $(element).attr("id").split("_")[1];
image_clicked=$(element_div).attr("src"); var isActive = $(element).hasClass("mdi-check-circle");
image_clicked_info = image_clicked.split("/"); var newStatus = isActive ? 0 : 1;
image_real_clicked = image_clicked_info[image_clicked_info.length-1]; var confirmMessage = isActive ? "'.get_lang('Are you sure you want to lock this user?', '').'" : "'.get_lang('Are you sure you want to unlock this user?', '').'";
var status = 1; if (confirm(confirmMessage)) {
if (image_real_clicked == "accept.png") { $.ajax({
status = 0;
}
user_id=id_image.split("_");
ident="#img_"+user_id[1];
if (confirm("'.get_lang('AreYouSureToEditTheUserStatus', '').'")) {
$.ajax({
contentType: "application/x-www-form-urlencoded", contentType: "application/x-www-form-urlencoded",
beforeSend: function(myObject) { beforeSend: function() {
$(ident).attr("src","'.Display::returnIconPath('loading1.gif').'"); }, //candy eye stuff $(element).attr("class", "mdi mdi-loading mdi-spin ch-tool-icon");
},
type: "GET", type: "GET",
url: "'.api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=active_user", url: "'.api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=active_user",
data: "user_id="+user_id[1]+"&status="+status, data: "user_id=" + userId + "&status=" + newStatus,
success: function(data) { success: function(data) {
if (data == 1) { if (data == 1) {
$(ident).attr("src", "'.Display::returnIconPath('accept.png', ICON_SIZE_TINY).'"); $(element).attr("class", "mdi mdi-check-circle ch-tool-icon");
$(ident).attr("title","'.get_lang('Lock').'"); $(element).attr("title", "'.get_lang('Lock').'");
} } else {
if (data == 0) { $(element).attr("class", "mdi mdi-alert ch-tool-icon");
$(ident).attr("src","'.Display::returnIconPath('error.png').'"); $(element).attr("title", "'.get_lang('Unlock').'");
$(ident).attr("title","'.get_lang('Unlock').'");
}
if (data == -1) {
$(ident).attr("src", "'.Display::returnIconPath('warning.png').'");
$(ident).attr("title","'.get_lang('Action not allowed').'");
} }
} }
}); });
@ -164,14 +156,12 @@ function trimVariables()
} }
/** /**
* Prepares the shared SQL query for the user table. * Prepares a shared SQL query for retrieving user data from the user table.
* See get_user_data() and get_number_of_users(). * This function is utilized by both get_user_data() and get_number_of_users()
* * to construct the base SQL query. It supports filtering for active, inactive,
* @param bool $getCount Whether to count, or get data * and deleted users based on the provided parameters.
*
* @return string SQL query
*/ */
function prepare_user_sql_query($getCount) function prepare_user_sql_query(bool $getCount, bool $showDeletedUsers = false): string
{ {
$sql = ''; $sql = '';
$user_table = Database::get_main_table(TABLE_MAIN_USER); $user_table = Database::get_main_table(TABLE_MAIN_USER);
@ -393,17 +383,23 @@ function prepare_user_sql_query($getCount)
} }
} }
if ($showDeletedUsers) {
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active = '.USER_SOFT_DELETED : ' AND u.active = '.USER_SOFT_DELETED;
} else {
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active <> '.USER_SOFT_DELETED : ' AND u.active <> '.USER_SOFT_DELETED;
}
return $sql; return $sql;
} }
/** /**
* Get the total number of users on the platform. * Retrieves the total number of users from the database. This function can be
* * configured to either include or exclude users marked as deleted based on the
* @see SortableTable#get_total_number_of_items() * provided parameter.
*/ */
function get_number_of_users() function get_number_of_users(bool $showDeletedUsers = false): int
{ {
$sql = prepare_user_sql_query(true); $sql = prepare_user_sql_query(true, $showDeletedUsers);
$res = Database::query($sql); $res = Database::query($sql);
$obj = Database::fetch_object($res); $obj = Database::fetch_object($res);
@ -411,20 +407,13 @@ function get_number_of_users()
} }
/** /**
* Get the users to display on the current page (fill the sortable-table). * Fetches a subset of user data from the database based on provided parameters. This function
* * is used to populate a sortable and paginated table of users, allowing for dynamic data retrieval
* @param int offset of first user to recover * based on user interaction with the table (such as sorting and pagination).
* @param int Number of users to get
* @param int Column to sort on
* @param string Order (ASC,DESC)
*
* @return array Users list
*
* @see SortableTable#get_table_data($from)
*/ */
function get_user_data($from, $number_of_items, $column, $direction) function get_user_data(int $from, int $number_of_items, int $column, string $direction, bool $showDeletedUsers = false): array
{ {
$sql = prepare_user_sql_query(false); $sql = prepare_user_sql_query(false, $showDeletedUsers);
if (!in_array($direction, ['ASC', 'DESC'])) { if (!in_array($direction, ['ASC', 'DESC'])) {
$direction = 'ASC'; $direction = 'ASC';
} }
@ -508,18 +497,68 @@ function user_filter($name, $params, $row)
return '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$row[0].'">'.$name.'</a>'; return '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$row[0].'">'.$name.'</a>';
} }
/**
* Generates action links for each user in the deleted users list. This function creates HTML
* links for editing user profiles, restoring deleted users, and permanently deleting users.
* It is designed to be used in a table that lists users marked as deleted.
*/
function modify_deleted_filter(int $user_id, string $url_params, array $row): string
{
$result = '';
$editProfileUrl = Display::getProfileEditionLink($user_id, true);
$result .= '<a href="'.$editProfileUrl.'">'.
Display::getMdiIcon('pencil', 'ch-tool-icon', null, 22, get_lang('Edit')).'</a>';
$restoreUrl = "user_list.php?$url_params&".
http_build_query([
'action' => 'restore',
'user_id' => $user_id,
'sec_token' => Security::getTokenFromSession(),
'view' => Security::remove_XSS($_GET['view']),
]);
$result .= Display::url(
Display::getMdiIcon('restore', 'ch-tool-icon', null, 22, get_lang('Restore')),
$restoreUrl,
[
'title' => get_lang('Restore'),
'data-title' => addslashes(api_htmlentities(get_lang("Please confirm your choice"))),
'class' => 'delete-swal',
]
);
$deleteUrl = "user_list.php?$url_params&".
http_build_query([
'action' => 'destroy',
'user_id' => $user_id,
'sec_token' => Security::getTokenFromSession(),
'view' => Security::remove_XSS($_GET['view']),
]);
$result .= Display::url(
Display::getMdiIcon('delete-forever', 'ch-tool-icon', null, 22, get_lang('DeletePermanently')),
$deleteUrl,
[
'title' => get_lang('DeletePermanently'),
'data-title' => addslashes(api_htmlentities(get_lang("Please confirm your choice"))),
'class' => 'delete-swal',
]
);
return $result;
}
/** /**
* Build the modify-column of the table. * Build the modify-column of the table.
* *
* @param int The user id * @param int $user_id The user id
* @param string URL params to add to table links * @param string $url_params URL params to add to table links
* @param array Row of elements to alter * @param array $row Row of elements to alter
* *
* @throws Exception * @throws Exception
* *
* @return string Some HTML-code with modify-buttons * @return string Some HTML-code with modify-buttons
*/ */
function modify_filter($user_id, $url_params, $row) function modify_filter($user_id, $url_params, $row): string
{ {
$_admins_list = Session::read('admin_list', []); $_admins_list = Session::read('admin_list', []);
$is_admin = in_array($user_id, $_admins_list); $is_admin = in_array($user_id, $_admins_list);
@ -648,17 +687,6 @@ function modify_filter($user_id, $url_params, $row)
} }
if (api_is_platform_admin()) { if (api_is_platform_admin()) {
/* Temporarily disabled until improved
$result .= ' <a data-title="'.get_lang('Free/Busy calendar').'" href="'.api_get_path(WEB_AJAX_PATH).'agenda.ajax.php?a=get_user_agenda&user_id='.$user_id.'&modal_size=lg" class="agenda_opener ajax">'.
Display::getMdiIcon(
'calendar-text',
'ch-tool-icon',
null,
22,
get_lang('Free/Busy calendar')
).
'</a>';
*/
if ($user_id != $currentUserId && if ($user_id != $currentUserId &&
!$user_is_anonymous && !$user_is_anonymous &&
api_global_admin_can_edit_admin($user_id) api_global_admin_can_edit_admin($user_id)
@ -830,38 +858,33 @@ function modify_filter($user_id, $url_params, $row)
/** /**
* Build the active-column of the table to lock or unlock a certain user * Build the active-column of the table to lock or unlock a certain user
* lock = the user can no longer use this account. * lock = the user can no longer use this account.
*
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
*
* @param int $active the current state of the account
* @param string $params
* @param array $row
*
* @return string Some HTML-code with the lock/unlock button
*/ */
function active_filter($active, $params, $row) function active_filter(int $active, string $params, array $row): string
{ {
$_user = api_get_user_info(); $_user = api_get_user_info();
$action = 'Unlock'; $action = 'Unlock';
$image = StateIcon::WARNING; $image = StateIcon::WARNING;
if ('1' == $active) { if (USER_ACTIVE == $active) {
$action = 'Lock'; $action = 'Lock';
$image = StateIcon::COMPLETE; $image = StateIcon::COMPLETE;
} elseif ('-1' == $active) { } elseif (USER_INACTIVE_AUTOMATIC == $active) {
$action = 'edit'; $action = 'edit';
$image = StateIcon::EXPIRED; $image = StateIcon::EXPIRED;
} elseif (USER_SOFT_DELETED == $active) {
$action = 'soft_deleted';
$image = StateIcon::REJECT;
} }
$result = ''; $result = '';
if ('edit' === $action) { if (in_array($action, ['edit', 'soft_deleted'])) {
$result = Display::getMdiIcon( $result = Display::getMdiIcon(
$image, $image,
'ch-tool-icon', 'ch-tool-icon',
null, null,
ICON_SIZE_TINY, ICON_SIZE_TINY,
get_lang('Account expired') 'edit' === $action ? get_lang('Account expired') : get_lang('Account is removed temporally')
); );
} elseif ($row['0'] != $_user['user_id']) { } elseif ($row['0'] != $_user['user_id']) {
// you cannot lock yourself out otherwise you could disable all the // you cannot lock yourself out otherwise you could disable all the
@ -882,16 +905,8 @@ function active_filter($active, $params, $row)
/** /**
* Instead of displaying the integer of the status, we give a translation for the status. * Instead of displaying the integer of the status, we give a translation for the status.
*
* @param int $status
*
* @return string translation
*
* @version march 2008
*
* @author Patrick Cool <patrick.cool@UGent.be>, Ghent University, Belgium
*/ */
function status_filter($status) function status_filter(int $status): string
{ {
$name = api_get_status_langvars(); $name = api_get_status_langvars();
@ -1006,6 +1021,106 @@ if (!empty($action)) {
} }
} }
break; break;
case 'restore':
$userIds = [];
$isMassDeletion = false;
if (api_is_platform_admin() && !empty($_POST['id']) && is_array($_POST['id'])) {
$userIds = $_POST['id'];
$isMassDeletion = true;
} elseif (!empty($_GET['user_id'])) {
$userIds[] = $_GET['user_id'];
}
$numberOfAffectedUsers = 0;
foreach ($userIds as $userId) {
if ($userId != $currentUserId && UserManager::change_active_state($userId, 1)) {
$numberOfAffectedUsers++;
}
}
if ($isMassDeletion) {
if (count($userIds) == $numberOfAffectedUsers) {
$message = Display::return_message(
get_lang('Selected users restored'),
'confirmation'
);
} else {
$message = Display::return_message(
get_lang('Some of the selected users have not been restored. We recommend you confirm which, by using the advanced search.'),
'error'
);
}
} else {
if ($numberOfAffectedUsers > 0) {
$message = Display::return_message(
get_lang('The user has been restored.'),
'confirmation'
);
} else {
$message = Display::return_message(
get_lang('The user has not been restored. Please confirm the user ID and try again.'),
'error'
);
}
}
Display::addFlash($message);
if (!$isMassDeletion) {
header('Location: '.api_get_self().'?view='.$view);
exit;
}
break;
case 'destroy':
$userIds = [];
$isMassDeletion = false;
if (api_is_platform_admin() && !empty($_POST['id']) && is_array($_POST['id'])) {
$userIds = $_POST['id'];
$isMassDeletion = true;
} elseif (!empty($_GET['user_id'])) {
$userIds[] = $_GET['user_id'];
}
$numberOfAffectedUsers = 0;
foreach ($userIds as $userId) {
if ($userId != $currentUserId && UserManager::delete_user($userId, true)) {
$numberOfAffectedUsers++;
}
}
if ($isMassDeletion) {
if (count($userIds) == $numberOfAffectedUsers) {
$message = Display::return_message(
get_lang('Selected users deleted permanently'),
'confirmation'
);
} else {
$message = Display::return_message(
get_lang('Some of the selected users have not been deleted. We recommend you confirm which, by using the advanced search.'),
'error'
);
}
} else {
if ($numberOfAffectedUsers > 0) {
$message = Display::return_message(
get_lang('The user has been deleted permanently'),
'confirmation'
);
} else {
$message = Display::return_message(
get_lang('The user has not been deleted. Please confirm the user ID and try again.'),
'error'
);
}
}
Display::addFlash($message);
if (!$isMassDeletion) {
header('Location: '.api_get_self().'?view='.$view);
exit;
}
break;
case 'anonymize': case 'anonymize':
$message = UserManager::anonymizeUserWithVerification($_GET['user_id']); $message = UserManager::anonymizeUserWithVerification($_GET['user_id']);
Display::addFlash($message); Display::addFlash($message);
@ -1027,6 +1142,7 @@ $form->addText(
'placeholder' => get_lang('Search users'), 'placeholder' => get_lang('Search users'),
] ]
); );
$form->addElement('hidden', 'view', $view);
$form->addButtonSearch(get_lang('Search')); $form->addButtonSearch(get_lang('Search'));
$searchAdvanced = ' $searchAdvanced = '
@ -1039,7 +1155,7 @@ $searchAdvanced = '
$actionsLeft = ''; $actionsLeft = '';
$actionsCenter = ''; $actionsCenter = '';
$actionsRight = ''; $actionsRight = '';
if (api_is_platform_admin()) { if (api_is_platform_admin() && !$showDeletedUsers) {
$actionsLeft .= '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_add.php">'. $actionsLeft .= '<a href="'.api_get_path(WEB_CODE_PATH).'admin/user_add.php">'.
Display::getMdiIcon('account-plus', 'ch-tool-icon-gradient', null, 32, get_lang('Add a user')).'</a>'; Display::getMdiIcon('account-plus', 'ch-tool-icon-gradient', null, 32, get_lang('Add a user')).'</a>';
} }
@ -1065,6 +1181,7 @@ if (isset($_GET['keyword'])) {
} }
// Create a sortable table with user-data // Create a sortable table with user-data
$parameters['sec_token'] = Security::get_token(); $parameters['sec_token'] = Security::get_token();
$parameters['view'] = $view;
$_admins_list = array_keys(UserManager::get_all_administrators()); $_admins_list = array_keys(UserManager::get_all_administrators());
Session::write('admin_list', $_admins_list); Session::write('admin_list', $_admins_list);
@ -1077,7 +1194,7 @@ $form = new FormValidator(
[], [],
FormValidator::LAYOUT_HORIZONTAL FormValidator::LAYOUT_HORIZONTAL
); );
$form->addElement('hidden', 'view', $view);
$form->addElement('header', get_lang('Advanced search')); $form->addElement('header', get_lang('Advanced search'));
$form->addText('keyword_firstname', get_lang('First name'), false); $form->addText('keyword_firstname', get_lang('First name'), false);
$form->addText('keyword_lastname', get_lang('Last name'), false); $form->addText('keyword_lastname', get_lang('Last name'), false);
@ -1142,8 +1259,8 @@ $form = '<div id="advanced_search_form" style="display:none;">'.$form->returnFor
$table = new SortableTable( $table = new SortableTable(
'users', 'users',
'get_number_of_users', function() use ($showDeletedUsers) { return get_number_of_users($showDeletedUsers); },
'get_user_data', function($from, $number_of_items, $column, $direction) use ($showDeletedUsers) { return get_user_data($from, $number_of_items, $column, $direction, $showDeletedUsers); },
(api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2, (api_is_western_name_order() xor api_sort_by_first_name()) ? 3 : 2,
20, 20,
'ASC' 'ASC'
@ -1173,24 +1290,32 @@ $table->set_column_filter(4, 'user_filter');
$table->set_column_filter(6, 'email_filter'); $table->set_column_filter(6, 'email_filter');
$table->set_column_filter(7, 'status_filter'); $table->set_column_filter(7, 'status_filter');
$table->set_column_filter(8, 'active_filter'); $table->set_column_filter(8, 'active_filter');
$table->set_column_filter(11, 'modify_filter'); $actionsList = [];
if ($showDeletedUsers) {
$table->set_column_filter(11, 'modify_deleted_filter');
$actionsList['restore'] = get_lang('Restore');
if (api_is_platform_admin() &&
!api_get_configuration_value('deny_delete_users')
) {
$actionsList['destroy'] = get_lang('Destroy');
}
} else {
$table->set_column_filter(11, 'modify_filter');
if (api_is_platform_admin() &&
!api_get_configuration_value('deny_delete_users')
) {
$actionsList['delete'] = get_lang('Remove from portal');
}
$actionsList['disable'] = get_lang('Disable');
$actionsList['enable'] = get_lang('Enable');
}
$table->set_form_actions($actionsList);
// Hide email column if login is email, to avoid column with same data // Hide email column if login is email, to avoid column with same data
if ('true' === api_get_setting('login_is_email')) { if ('true' === api_get_setting('login_is_email')) {
$table->setHideColumn(6); $table->setHideColumn(6);
} }
// Only show empty actions bar if delete users has been blocked
$actionsList = [];
if (api_is_platform_admin() &&
!api_get_configuration_value('deny_delete_users')
) {
$actionsList['delete'] = get_lang('Remove from portal');
}
$actionsList['disable'] = get_lang('Disable');
$actionsList['enable'] = get_lang('Enable');
$table->set_form_actions($actionsList);
$table_result = $table->return_table(); $table_result = $table->return_table();
$extra_search_options = ''; $extra_search_options = '';
@ -1259,7 +1384,21 @@ if (0 == $table->get_total_number_of_items()) {
} }
} }
} }
$toolbarActions = Display::toolbarAction('toolbarUser', [$actionsLeft, $actionsCenter.$actionsRight]);
$tabsHtml = '
<div class="users-list">
<ul class="nav nav-tabs">
<li class="nav-item '.($view == 'all' ? 'active' : '').'">
<a class="nav-link '.($view == 'all' ? 'active' : '').'" href="user_list.php?view=all">'.get_lang('All users').'</a>
</li>
<li class="nav-item '.($view == 'deleted' ? 'active' : '').'">
<a class="nav-link '.($view == 'deleted' ? 'active' : '').'" href="user_list.php?view=deleted">'.get_lang('Deleted Users').'</a>
</li>
</ul>
</div>';
$toolbarActions = $tabsHtml;
$toolbarActions .= Display::toolbarAction('toolbarUser', [$actionsLeft, $actionsCenter.$actionsRight]);
$tpl = new Template($tool_name); $tpl = new Template($tool_name);
$tpl->assign('actions', $toolbarActions); $tpl->assign('actions', $toolbarActions);

@ -173,6 +173,8 @@ function prepare_user_sql_query($getCount)
$sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id(); $sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id();
} }
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active <> '.USER_SOFT_DELETED : ' AND u.active <> '.USER_SOFT_DELETED;
return $sql; return $sql;
} }

@ -41,7 +41,7 @@ foreach ($urlList as $url) {
v.value = 1 v.value = 1
) "; ) ";
$sql .= " WHERE 1 = 1 "; $sql .= " WHERE 1 = 1 AND u.active <> ".USER_SOFT_DELETED;
if (api_get_multiple_access_url()) { if (api_get_multiple_access_url()) {
$sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id(); $sql .= " AND url_rel_user.access_url_id = ".api_get_current_access_url_id();

@ -237,6 +237,7 @@ switch ($action) {
GROUP BY exe_user_id GROUP BY exe_user_id
) as aa ) as aa
ON aa.exe_user_id = u.id ON aa.exe_user_id = u.id
WHERE u.active <> ".USER_SOFT_DELETED."
ORDER BY `$sidx` $sord ORDER BY `$sidx` $sord
LIMIT $start, $limit"; LIMIT $start, $limit";

@ -1243,7 +1243,7 @@ class SkillModel extends Model
ON (s.id = su.skill_id) ON (s.id = su.skill_id)
INNER JOIN {$this->table_user} u INNER JOIN {$this->table_user} u
ON u.id = su.user_id, (SELECT @rownum:=0) r ON u.id = su.user_id, (SELECT @rownum:=0) r
WHERE 1=1 $where_condition WHERE 1=1 AND u.active <> ".USER_SOFT_DELETED." $where_condition
GROUP BY username GROUP BY username
ORDER BY skills_acquired desc ORDER BY skills_acquired desc
LIMIT $start , $limit) AS T1, (SELECT @rownum:=0) r"; LIMIT $start , $limit) AS T1, (SELECT @rownum:=0) r";

@ -1281,7 +1281,7 @@ class TicketManager
FROM $table_support_messages message FROM $table_support_messages message
INNER JOIN $table_main_user user INNER JOIN $table_main_user user
ON (message.sys_insert_user_id = user.id) ON (message.sys_insert_user_id = user.id)
WHERE WHERE user.active <> ".USER_SOFT_DELETED." AND
message.ticket_id = '$ticketId' "; message.ticket_id = '$ticketId' ";
$result = Database::query($sql); $result = Database::query($sql);
$ticket['messages'] = []; $ticket['messages'] = [];
@ -1812,6 +1812,7 @@ class TicketManager
} }
} }
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE user.active <> '.USER_SOFT_DELETED : ' AND user.active <> '.USER_SOFT_DELETED;
$sql .= " LIMIT $from,$number_of_items"; $sql .= " LIMIT $from,$number_of_items";
$result = Database::query($sql); $result = Database::query($sql);

@ -39,7 +39,7 @@ class AccessUrlEditUsersToUrl
$order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname, username' : ' ORDER BY lastname, firstname, username'; $order_clause = api_sort_by_first_name() ? ' ORDER BY firstname, lastname, username' : ' ORDER BY lastname, firstname, username';
$sql = 'SELECT u.id as user_id, username, lastname, firstname $sql = 'SELECT u.id as user_id, username, lastname, firstname
FROM '.$tbl_user.' u FROM '.$tbl_user.' u
WHERE WHERE u.active <> '.USER_SOFT_DELETED.' AND
( (
username LIKE "'.$needle.'%" OR username LIKE "'.$needle.'%" OR
firstname LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%" OR

@ -662,6 +662,12 @@ define('SE_DOCTYPE_EXERCISE_QUESTION', 1);
define('XAPIAN_PREFIX_COURSEID', 'C'); define('XAPIAN_PREFIX_COURSEID', 'C');
define('XAPIAN_PREFIX_TOOLID', 'O'); define('XAPIAN_PREFIX_TOOLID', 'O');
// User active field constants
define('USER_ACTIVE', 1);
define('USER_INACTIVE', 0);
define('USER_INACTIVE_AUTOMATIC', -1);
define('USER_SOFT_DELETED', -2);
/** /**
* Returns a path to a certain resource within Chamilo. * Returns a path to a certain resource within Chamilo.
* *

@ -1375,6 +1375,7 @@ class CourseManager
$sqlInjectJoins $sqlInjectJoins
"; ";
$where[] = ' session_course_user.c_id IS NOT NULL '; $where[] = ' session_course_user.c_id IS NOT NULL ';
$where[] = ' user.active <> '.USER_SOFT_DELETED.' ';
// 2 = coach // 2 = coach
// 0 = student // 0 = student
@ -1451,7 +1452,7 @@ class CourseManager
} }
} }
$sql .= " WHERE $sql .= " WHERE user.active <> ".USER_SOFT_DELETED." AND
$filter_by_status_condition $filter_by_status_condition
".implode(' OR ', $where); ".implode(' OR ', $where);
@ -1758,7 +1759,7 @@ class CourseManager
$sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.id) "; $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.id) ";
} }
$sql .= ' WHERE '.implode(' OR ', $where); $sql .= ' WHERE user.active <> '.USER_SOFT_DELETED.' AND '.implode(' OR ', $where);
if ($multiple_access_url) { if ($multiple_access_url) {
$current_access_url_id = api_get_current_access_url_id(); $current_access_url_id = api_get_current_access_url_id();
@ -1880,7 +1881,7 @@ class CourseManager
FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
INNER JOIN $userTable u INNER JOIN $userTable u
ON cu.user_id = u.id ON cu.user_id = u.id
WHERE c_id = $courseId AND cu.status = ".STUDENT; WHERE u.active <> ".USER_SOFT_DELETED." AND c_id = $courseId AND cu.status = ".STUDENT;
if (!$includeInvitedUsers) { if (!$includeInvitedUsers) {
$sql .= " AND u.status != ".INVITEE; $sql .= " AND u.status != ".INVITEE;
@ -1923,7 +1924,7 @@ class CourseManager
$joinSession $joinSession
INNER JOIN $userTable u INNER JOIN $userTable u
ON scu.user_id = u.id ON scu.user_id = u.id
WHERE scu.c_id = $courseId AND scu.status = ".SessionEntity::STUDENT; WHERE u.active <> ".USER_SOFT_DELETED." AND scu.c_id = $courseId AND scu.status = ".SessionEntity::STUDENT;
if (!empty($date_from) && !empty($date_to)) { if (!empty($date_from) && !empty($date_to)) {
$date_from = Database::escape_string($date_from); $date_from = Database::escape_string($date_from);

@ -2094,6 +2094,8 @@ HOTSPOT;
"; ";
} }
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE user.active <> '.USER_SOFT_DELETED : ' AND user.active <> '.USER_SOFT_DELETED;
if (empty($sql)) { if (empty($sql)) {
return false; return false;
} }

@ -1133,7 +1133,7 @@ class GroupManager
ON (gu.group_id = g.iid) ON (gu.group_id = g.iid)
INNER JOIN $user_table u INNER JOIN $user_table u
ON (u.id = gu.user_id) ON (u.id = gu.user_id)
WHERE WHERE u.active <> ".USER_SOFT_DELETED." AND
g.iid = $group_id"; g.iid = $group_id";
if (!empty($column) && !empty($direction)) { if (!empty($column) && !empty($direction)) {

@ -518,7 +518,7 @@ class MySpace
MAX(login_date) as login_date MAX(login_date) as login_date
FROM $tbl_user u, $tbl_session_course_user scu, $tbl_track_login FROM $tbl_user u, $tbl_session_course_user scu, $tbl_track_login
WHERE WHERE
scu.user_id = u.id AND scu.status=".SessionEntity::COURSE_COACH." AND login_user_id=u.id u.active <> ".USER_SOFT_DELETED." AND scu.user_id = u.id AND scu.status=".SessionEntity::COURSE_COACH." AND login_user_id=u.id
GROUP BY user_id "; GROUP BY user_id ";
if (api_is_multiple_url_enabled()) { if (api_is_multiple_url_enabled()) {
@ -1958,7 +1958,7 @@ class MySpace
FROM $tbl_user AS u FROM $tbl_user AS u
INNER JOIN $tbl_session_rel_course_rel_user AS scu INNER JOIN $tbl_session_rel_course_rel_user AS scu
ON u.id = scu.user_id ON u.id = scu.user_id
WHERE scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'"; WHERE u.active <> ".USER_SOFT_DELETED." AND scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
$result_users = Database::query($sql); $result_users = Database::query($sql);
$time_spent = 0; $time_spent = 0;
$progress = 0; $progress = 0;
@ -2138,7 +2138,7 @@ class MySpace
FROM $tbl_user AS u FROM $tbl_user AS u
INNER JOIN $tbl_session_rel_course_rel_user AS scu INNER JOIN $tbl_session_rel_course_rel_user AS scu
ON u.id = scu.user_id ON u.id = scu.user_id
WHERE scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'"; WHERE u.active <> ".USER_SOFT_DELETED." AND scu.session_id = '".$session_id."' AND scu.c_id = '".$courseId."'";
$result_users = Database::query($sql); $result_users = Database::query($sql);
$time_spent = 0; $time_spent = 0;
$progress = 0; $progress = 0;

@ -316,7 +316,7 @@ function who_is_online(
$query = "SELECT DISTINCT login_user_id, login_date $query = "SELECT DISTINCT login_user_id, login_date
FROM ".$track_online_table." e FROM ".$track_online_table." e
INNER JOIN ".$table_user." u ON (u.id = e.login_user_id) INNER JOIN ".$table_user." u ON (u.id = e.login_user_id)
WHERE u.status != ".ANONYMOUS." AND login_date >= '".$current_date."' WHERE u.active <> ".USER_SOFT_DELETED." AND u.status != ".ANONYMOUS." AND login_date >= '".$current_date."'
ORDER BY `$column` $direction ORDER BY `$column` $direction
LIMIT $from, $number_of_items"; LIMIT $from, $number_of_items";
} }
@ -341,7 +341,7 @@ function who_is_online(
FROM ".$track_online_table." track FROM ".$track_online_table." track
INNER JOIN ".$table_user." u INNER JOIN ".$table_user." u
ON (u.id=track.login_user_id) ON (u.id=track.login_user_id)
WHERE u.status != ".ANONYMOUS." AND track.access_url_id = $access_url_id AND WHERE u.active <> ".USER_SOFT_DELETED." AND u.status != ".ANONYMOUS." AND track.access_url_id = $access_url_id AND
login_date >= '".$current_date."' login_date >= '".$current_date."'
ORDER BY `$column` $direction ORDER BY `$column` $direction
LIMIT $from, $number_of_items"; LIMIT $from, $number_of_items";
@ -400,7 +400,7 @@ function who_is_online_count($time_limit = null, $friends = false)
$query = "SELECT count(login_id) as count $query = "SELECT count(login_id) as count
FROM $track_online_table track INNER JOIN $table_user u FROM $track_online_table track INNER JOIN $table_user u
ON (u.id=track.login_user_id) ON (u.id=track.login_user_id)
WHERE u.status != ".ANONYMOUS." AND login_date >= '$current_date' "; WHERE u.active <> ".USER_SOFT_DELETED." AND u.status != ".ANONYMOUS." AND login_date >= '$current_date' ";
} }
if (api_get_multiple_access_url()) { if (api_get_multiple_access_url()) {
@ -421,6 +421,7 @@ function who_is_online_count($time_limit = null, $friends = false)
$query = "SELECT count(login_id) as count FROM $track_online_table track $query = "SELECT count(login_id) as count FROM $track_online_table track
INNER JOIN $table_user u ON (u.id=track.login_user_id) INNER JOIN $table_user u ON (u.id=track.login_user_id)
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
u.status != ".ANONYMOUS." AND u.status != ".ANONYMOUS." AND
track.access_url_id = $access_url_id AND track.access_url_id = $access_url_id AND
login_date >= '$current_date' "; login_date >= '$current_date' ";
@ -488,6 +489,7 @@ function who_is_online_in_this_course($from, $number_of_items, $uid, $time_limit
ON (o.login_user_id = u.id) ON (o.login_user_id = u.id)
$urlJoin $urlJoin
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
u.status <> '".ANONYMOUS."' AND u.status <> '".ANONYMOUS."' AND
o.c_id = $courseId AND o.c_id = $courseId AND
o.login_date >= '$current_date' o.login_date >= '$current_date'
@ -545,6 +547,7 @@ function who_is_online_in_this_course_count(
ON (login_user_id = u.id) ON (login_user_id = u.id)
$urlJoin $urlJoin
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
u.status <> '".ANONYMOUS."' AND u.status <> '".ANONYMOUS."' AND
c_id = $courseId AND c_id = $courseId AND
login_date >= '$current_date' login_date >= '$current_date'
@ -594,6 +597,7 @@ function whoIsOnlineInThisSessionCount($timeLimit, $sessionId)
ON (login_user_id = u.id) ON (login_user_id = u.id)
$urlJoin $urlJoin
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
u.status <> '".ANONYMOUS."' AND u.status <> '".ANONYMOUS."' AND
session_id = $sessionId AND session_id = $sessionId AND
login_date >= '$current_date' login_date >= '$current_date'

@ -447,6 +447,8 @@ class SessionManager
} }
} }
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active <> '.USER_SOFT_DELETED : ' AND u.active <> '.USER_SOFT_DELETED;
$result_rows = Database::query($sql); $result_rows = Database::query($sql);
$row = Database::fetch_array($result_rows); $row = Database::fetch_array($result_rows);
$num = $row['total_rows']; $num = $row['total_rows'];
@ -4368,7 +4370,7 @@ class SessionManager
$sql .= " WHERE (au.access_url_id = $urlId OR au.access_url_id is null )"; $sql .= " WHERE (au.access_url_id = $urlId OR au.access_url_id is null )";
} }
$sql .= ' ORDER BY su.relation_type, '; $sql .= ' AND u.active <> '.USER_SOFT_DELETED.' ORDER BY su.relation_type, ';
$sql .= api_sort_by_first_name() ? ' u.firstname, u.lastname' : ' u.lastname, u.firstname'; $sql .= api_sort_by_first_name() ? ' u.firstname, u.lastname' : ' u.lastname, u.firstname';
$result = Database::query($sql); $result = Database::query($sql);
@ -6164,7 +6166,7 @@ class SessionManager
$sessionConditions = ''; $sessionConditions = '';
$courseConditions = ''; $courseConditions = '';
$userConditions = ''; $userConditions = ' AND u.active <> '.USER_SOFT_DELETED.' ';
if (isset($active)) { if (isset($active)) {
$active = (int) $active; $active = (int) $active;
@ -7946,7 +7948,7 @@ class SessionManager
'getFullname' 'getFullname'
); );
} else { } else {
$sql = "SELECT COUNT(1) FROM $tbl_user WHERE status = 1"; $sql = "SELECT COUNT(1) FROM $tbl_user WHERE active <> ".USER_SOFT_DELETED." AND status = 1";
$rs = Database::query($sql); $rs = Database::query($sql);
$countUsers = (int) Database::result($rs, 0, '0'); $countUsers = (int) Database::result($rs, 0, '0');
@ -7956,7 +7958,7 @@ class SessionManager
$sql = "SELECT id as user_id, lastname, firstname, username $sql = "SELECT id as user_id, lastname, firstname, username
FROM $tbl_user FROM $tbl_user
WHERE status = '1' ". WHERE active <> -1 AND status = '1' ".
$orderClause; $orderClause;
if (api_is_multiple_url_enabled()) { if (api_is_multiple_url_enabled()) {
@ -7968,6 +7970,7 @@ class SessionManager
INNER JOIN $userRelAccessUrlTable url_user INNER JOIN $userRelAccessUrlTable url_user
ON (url_user.user_id = user.id) ON (url_user.user_id = user.id)
WHERE WHERE
user.active <> -1 AND
access_url_id = $accessUrlId AND access_url_id = $accessUrlId AND
status = 1 " status = 1 "
.$orderClause; .$orderClause;
@ -8317,7 +8320,7 @@ class SessionManager
$tbl_session_field_options = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS); $tbl_session_field_options = Database::get_main_table(TABLE_EXTRA_FIELD_OPTIONS);
$tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER); $tblSessionRelUser = Database::get_main_table(TABLE_MAIN_SESSION_USER);
$where = 'WHERE 1 = 1 '; $where = 'WHERE 1 = 1 AND u.active <> -1 ';
if (api_is_session_admin() && if (api_is_session_admin() &&
'false' == api_get_setting('allow_session_admins_to_see_all_sessions') 'false' == api_get_setting('allow_session_admins_to_see_all_sessions')

@ -143,6 +143,7 @@ class Statistics
$sql = "SELECT COUNT(DISTINCT(u.id)) AS number $sql = "SELECT COUNT(DISTINCT(u.id)) AS number
FROM $user_table as u, $access_url_rel_user_table as url FROM $user_table as u, $access_url_rel_user_table as url
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
u.id = url.user_id AND u.id = url.user_id AND
access_url_id = $urlId access_url_id = $urlId
$status_filter $active_filter"; $status_filter $active_filter";
@ -162,7 +163,7 @@ class Statistics
} else { } else {
$sql = "SELECT COUNT(DISTINCT(id)) AS number $sql = "SELECT COUNT(DISTINCT(id)) AS number
FROM $user_table FROM $user_table
WHERE 1 = 1 $status_filter $active_filter"; WHERE 1 = 1 AND active <> ".USER_SOFT_DELETED." AND $status_filter $active_filter";
if (isset($categoryCode)) { if (isset($categoryCode)) {
$categoryCode = Database::escape_string($categoryCode); $categoryCode = Database::escape_string($categoryCode);
$status_filter = isset($status) ? ' AND status = '.intval($status) : ''; $status_filter = isset($status) ? ' AND status = '.intval($status) : '';
@ -232,14 +233,14 @@ class Statistics
if (api_is_multiple_url_enabled()) { if (api_is_multiple_url_enabled()) {
$sql = "SELECT count(default_id) AS total_number_of_items $sql = "SELECT count(default_id) AS total_number_of_items
FROM $track_e_default, $table_user user, $access_url_rel_user_table url FROM $track_e_default, $table_user user, $access_url_rel_user_table url
WHERE WHERE user.active <> ".USER_SOFT_DELETED." AND
default_user_id = user.id AND default_user_id = user.id AND
user.id=url.user_id AND user.id=url.user_id AND
access_url_id = '".$urlId."'"; access_url_id = '".$urlId."'";
} else { } else {
$sql = "SELECT count(default_id) AS total_number_of_items $sql = "SELECT count(default_id) AS total_number_of_items
FROM $track_e_default, $table_user user FROM $track_e_default, $table_user user
WHERE default_user_id = user.id "; WHERE user.active <> ".USER_SOFT_DELETED." AND default_user_id = user.id ";
} }
if (!empty($courseId)) { if (!empty($courseId)) {
@ -309,6 +310,7 @@ class Statistics
$table_user as user, $table_user as user,
$access_url_rel_user_table as url $access_url_rel_user_table as url
WHERE WHERE
user.active <> -1 AND
track_default.default_user_id = user.id AND track_default.default_user_id = user.id AND
url.user_id = user.id AND url.user_id = user.id AND
access_url_id= $urlId "; access_url_id= $urlId ";
@ -323,7 +325,7 @@ class Statistics
user.id as col6, user.id as col6,
default_date as col7 default_date as col7
FROM $track_e_default track_default, $table_user user FROM $track_e_default track_default, $table_user user
WHERE track_default.default_user_id = user.id "; WHERE user.active <> ".USER_SOFT_DELETED." AND track_default.default_user_id = user.id ";
} }
if (!empty($_GET['keyword'])) { if (!empty($_GET['keyword'])) {
@ -864,6 +866,9 @@ class Statistics
$count1 = Database::fetch_object($res); $count1 = Database::fetch_object($res);
$sql = "SELECT COUNT(*) AS n FROM $user_table as u $table ". $sql = "SELECT COUNT(*) AS n FROM $user_table as u $table ".
"WHERE LENGTH(picture_uri) > 0 $url_condition2"; "WHERE LENGTH(picture_uri) > 0 $url_condition2";
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active <> '.USER_SOFT_DELETED : ' AND u.active <> '.USER_SOFT_DELETED;
$res = Database::query($sql); $res = Database::query($sql);
$count2 = Database::fetch_object($res); $count2 = Database::fetch_object($res);
// #users without picture // #users without picture
@ -1043,14 +1048,14 @@ class Statistics
if (api_is_multiple_url_enabled()) { if (api_is_multiple_url_enabled()) {
$sql = "SELECT lastname, firstname, username, COUNT($field) AS count_message $sql = "SELECT lastname, firstname, username, COUNT($field) AS count_message
FROM $access_url_rel_user_table as url, $message_table m FROM $access_url_rel_user_table as url, $message_table m
LEFT JOIN $user_table u ON m.$field = u.id LEFT JOIN $user_table u ON m.$field = u.id AND u.active <> ".USER_SOFT_DELETED."
WHERE url.user_id = m.$field AND access_url_id='".$urlId."' WHERE url.user_id = m.$field AND access_url_id='".$urlId."'
GROUP BY m.$field GROUP BY m.$field
ORDER BY count_message DESC "; ORDER BY count_message DESC ";
} else { } else {
$sql = "SELECT lastname, firstname, username, COUNT($field) AS count_message $sql = "SELECT lastname, firstname, username, COUNT($field) AS count_message
FROM $message_table m FROM $message_table m
LEFT JOIN $user_table u ON m.$field = u.id LEFT JOIN $user_table u ON m.$field = u.id AND u.active <> ".USER_SOFT_DELETED."
GROUP BY m.$field ORDER BY count_message DESC "; GROUP BY m.$field ORDER BY count_message DESC ";
} }
$res = Database::query($sql); $res = Database::query($sql);
@ -1083,7 +1088,7 @@ class Statistics
$sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend $sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend
FROM $access_url_rel_user_table as url, $user_friend_table uf FROM $access_url_rel_user_table as url, $user_friend_table uf
LEFT JOIN $user_table u LEFT JOIN $user_table u
ON (uf.user_id = u.id) ON (uf.user_id = u.id) AND u.active <> ".USER_SOFT_DELETED."
WHERE WHERE
uf.relation_type <> '".UserRelUser::USER_RELATION_TYPE_RRHH."' AND uf.relation_type <> '".UserRelUser::USER_RELATION_TYPE_RRHH."' AND
uf.user_id = url.user_id AND uf.user_id = url.user_id AND
@ -1094,7 +1099,7 @@ class Statistics
$sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend $sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend
FROM $user_friend_table uf FROM $user_friend_table uf
LEFT JOIN $user_table u LEFT JOIN $user_table u
ON (uf.user_id = u.id) ON (uf.user_id = u.id) AND u.active <> ".USER_SOFT_DELETED."
WHERE uf.relation_type <> '".UserRelUser::USER_RELATION_TYPE_RRHH."' WHERE uf.relation_type <> '".UserRelUser::USER_RELATION_TYPE_RRHH."'
GROUP BY uf.user_id GROUP BY uf.user_id
ORDER BY count_friend DESC "; ORDER BY count_friend DESC ";
@ -1467,7 +1472,7 @@ class Statistics
INNER JOIN $tblLogin l INNER JOIN $tblLogin l
ON u.id = l.login_user_id ON u.id = l.login_user_id
$urlJoin $urlJoin
WHERE l.login_date BETWEEN '$startDate' AND '$endDate' WHERE u.active <> ".USER_SOFT_DELETED." AND l.login_date BETWEEN '$startDate' AND '$endDate'
$urlWhere $urlWhere
GROUP BY u.id"; GROUP BY u.id";

@ -273,12 +273,12 @@ class SubLanguageManager
* *
* @return bool * @return bool
*/ */
public static function check_if_language_is_used($language_id) public static function check_if_language_is_used(int $language_id): bool
{ {
$language_info = self::get_all_information_of_language($language_id); $language_info = self::get_all_information_of_language($language_id);
$table = Database::get_main_table(TABLE_MAIN_USER); $table = Database::get_main_table(TABLE_MAIN_USER);
$sql = 'SELECT count(*) AS count FROM '.$table.' $sql = 'SELECT count(*) AS count FROM '.$table.'
WHERE locale ="'.Database::escape_string($language_info['english_name']).'"'; WHERE locale ="'.Database::escape_string($language_info['english_name']).'" AND active <> '.USER_SOFT_DELETED;
$rs = Database::query($sql); $rs = Database::query($sql);
if (Database::num_rows($rs) > 0 && Database::result($rs, '0', 'count') >= 1) { if (Database::num_rows($rs) > 0 && Database::result($rs, '0', 'count') >= 1) {
return true; return true;

@ -6490,7 +6490,7 @@ class Tracking
// Now fill users data // Now fill users data
$sqlUsers = "SELECT id as user_id, username, lastname, firstname $sqlUsers = "SELECT id as user_id, username, lastname, firstname
FROM $tuser FROM $tuser
WHERE id IN (".implode(',', $userIds).")"; WHERE active <> ".USER_SOFT_DELETED." AND id IN (".implode(',', $userIds).")";
$resUsers = Database::query($sqlUsers); $resUsers = Database::query($sqlUsers);
while ($rowUser = Database::fetch_assoc($resUsers)) { while ($rowUser = Database::fetch_assoc($resUsers)) {
$users[$rowUser['user_id']] = $rowUser; $users[$rowUser['user_id']] = $rowUser;

@ -225,11 +225,11 @@ class UrlManager
public static function get_url_rel_user_data($urlId = 0, $order_by = null) public static function get_url_rel_user_data($urlId = 0, $order_by = null)
{ {
$urlId = (int) $urlId; $urlId = (int) $urlId;
$where = ''; $where = ' WHERE u.active <> '.USER_SOFT_DELETED.' ';
$table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $table_url_rel_user = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
$tbl_user = Database::get_main_table(TABLE_MAIN_USER); $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
if (!empty($urlId)) { if (!empty($urlId)) {
$where = "WHERE $table_url_rel_user.access_url_id = ".$urlId; $where = " AND $table_url_rel_user.access_url_id = ".$urlId;
} }
if (empty($order_by)) { if (empty($order_by)) {
$order_clause = api_sort_by_first_name( $order_clause = api_sort_by_first_name(

@ -1763,7 +1763,7 @@ class UserGroupModel extends Model
$sql = "SELECT u.* FROM $this->table_user u $sql = "SELECT u.* FROM $this->table_user u
INNER JOIN $this->usergroup_rel_user_table c INNER JOIN $this->usergroup_rel_user_table c
ON c.user_id = u.id ON c.user_id = u.id
WHERE c.usergroup_id = $id" WHERE u.active <> ".USER_SOFT_DELETED." AND c.usergroup_id = $id"
; ;
if (!empty($orderBy)) { if (!empty($orderBy)) {
$orderBy = Database::escape_string($orderBy); $orderBy = Database::escape_string($orderBy);
@ -2475,6 +2475,7 @@ class UserGroupModel extends Model
INNER JOIN $table_group_rel_user gu INNER JOIN $table_group_rel_user gu
ON (gu.user_id = u.id) ON (gu.user_id = u.id)
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
gu.usergroup_id= $group_id gu.usergroup_id= $group_id
$where_relation_condition $where_relation_condition
ORDER BY relation_type, firstname ORDER BY relation_type, firstname
@ -2519,7 +2520,7 @@ class UserGroupModel extends Model
FROM $tbl_user u FROM $tbl_user u
INNER JOIN $table_group_rel_user gu INNER JOIN $table_group_rel_user gu
ON (gu.user_id = u.id) ON (gu.user_id = u.id)
WHERE gu.usergroup_id= $group_id WHERE u.active <> ".USER_SOFT_DELETED." AND gu.usergroup_id= $group_id
ORDER BY relation_type, firstname"; ORDER BY relation_type, firstname";
$result = Database::query($sql); $result = Database::query($sql);

@ -631,20 +631,15 @@ class UserManager
} }
/** /**
* Delete a user from the platform, and all its belongings. This is a * Deletes a user from the system or marks the user as deleted based on the $destroy flag.
* very dangerous function that should only be accessible by * If $destroy is false, the user is only marked as deleted (e.g., active = -1) but not actually removed from the database.
* super-admins. Other roles should only be able to disable a user, * This allows for the possibility of restoring the user at a later time. If $destroy is true, the user and all their relations
* which removes access to the platform but doesn't delete anything. * are permanently removed from the database.
* *
* @param int The ID of th user to be deleted * Note: When $destroy is false, the user's relations are not removed, allowing for potential restoration. When $destroy is true,
* * the function proceeds to remove all the user's relations, effectively cleaning up all references to the user in the system.
* @throws Exception
*
* @return bool true if user is successfully deleted, false otherwise
* @assert (null) === false
* @assert ('abc') === false
*/ */
public static function delete_user($user_id) public static function delete_user(int $user_id, bool $destroy = false): bool
{ {
$user_id = (int) $user_id; $user_id = (int) $user_id;
@ -656,6 +651,17 @@ class UserManager
return false; return false;
} }
$repository = Container::getUserRepository();
/** @var User $user */
$user = $repository->find($user_id);
$repository->deleteUser($user, $destroy);
if (!$destroy) {
return true;
}
$usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER); $usergroup_rel_user = Database::get_main_table(TABLE_USERGROUP_REL_USER);
$table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER); $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
$table_course = Database::get_main_table(TABLE_MAIN_COURSE); $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
@ -667,12 +673,6 @@ class UserManager
$table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION); $table_work = Database::get_course_table(TABLE_STUDENT_PUBLICATION);
$userInfo = api_get_user_info($user_id); $userInfo = api_get_user_info($user_id);
$repository = Container::getUserRepository();
/** @var User $user */
$user = $repository->find($user_id);
$repository->deleteUser($user);
// Unsubscribe the user from all groups in all his courses // Unsubscribe the user from all groups in all his courses
$sql = "SELECT c.id $sql = "SELECT c.id
@ -752,30 +752,11 @@ class UserManager
$userGroup->delete_user_rel_group($user_id, $group_id); $userGroup->delete_user_rel_group($user_id, $group_id);
} }
} }
// Delete user from friend lists
//SocialManager::remove_user_rel_user($user_id, true);
} }
// Removing survey invitation // Removing survey invitation
SurveyManager::delete_all_survey_invitations_by_user($user_id); SurveyManager::delete_all_survey_invitations_by_user($user_id);
// Delete students works
/*$sql = "DELETE FROM $table_work WHERE user_id = $user_id ";
Database::query($sql);*/
/*$sql = "UPDATE c_item_property SET to_user_id = NULL
WHERE to_user_id = '".$user_id."'";
Database::query($sql);
$sql = "UPDATE c_item_property SET insert_user_id = NULL
WHERE insert_user_id = '".$user_id."'";
Database::query($sql);
$sql = "UPDATE c_item_property SET lastedit_user_id = NULL
WHERE lastedit_user_id = '".$user_id."'";
Database::query($sql);*/
// Skills // Skills
$em = Database::getManager(); $em = Database::getManager();
@ -1047,8 +1028,10 @@ class UserManager
$change_active = 0; $change_active = 0;
$isUserActive = $user->isActive(); $isUserActive = $user->isActive();
if ($isUserActive != $active) { if ($active != USER_SOFT_DELETED) {
$change_active = 1; if ($isUserActive != $active) {
$change_active = 1;
}
} }
$originalUsername = $user->getUsername(); $originalUsername = $user->getUsername();
@ -1082,7 +1065,7 @@ class UserManager
->setPhone($phone) ->setPhone($phone)
->setAddress($address) ->setAddress($address)
->setExpirationDate($expiration_date) ->setExpirationDate($expiration_date)
->setActive((bool) $active) ->setActive($active)
->setHrDeptId((int) $hr_dept_id) ->setHrDeptId((int) $hr_dept_id)
; ;
@ -3911,6 +3894,7 @@ class UserManager
INNER JOIN $table_user u INNER JOIN $table_user u
ON (u.id=admin.user_id)"; ON (u.id=admin.user_id)";
} }
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE u.active <> '.USER_SOFT_DELETED : ' AND u.active <> '.USER_SOFT_DELETED;
$result = Database::query($sql); $result = Database::query($sql);
$return = []; $return = [];
if (Database::num_rows($result) > 0) { if (Database::num_rows($result) > 0) {
@ -5736,7 +5720,7 @@ SQL;
* *
* @return string * @return string
*/ */
public static function deleteUserWithVerification($userId) public static function deleteUserWithVerification($userId, bool $destroy = false)
{ {
$allowDelete = ('true' === api_get_setting('session.allow_delete_user_for_session_admin')); $allowDelete = ('true' === api_get_setting('session.allow_delete_user_for_session_admin'));
$message = Display::return_message(get_lang('You cannot delete this user'), 'error'); $message = Display::return_message(get_lang('You cannot delete this user'), 'error');
@ -5758,7 +5742,7 @@ SQL;
($allowDelete && api_is_session_admin()) ($allowDelete && api_is_session_admin())
) { ) {
if (api_global_admin_can_edit_admin($userId, null, $allowDelete)) { if (api_global_admin_can_edit_admin($userId, null, $allowDelete)) {
if (self::delete_user($userId)) { if (self::delete_user($userId, $destroy)) {
$message = Display::return_message( $message = Display::return_message(
get_lang('The user has been deleted').': '.$userToUpdateInfo['complete_name_with_username'], get_lang('The user has been deleted').': '.$userToUpdateInfo['complete_name_with_username'],
'confirmation' 'confirmation'
@ -6140,7 +6124,7 @@ SQL;
* @assert (-1,0) === false * @assert (-1,0) === false
* @assert (1,1) === true * @assert (1,1) === true
*/ */
private static function change_active_state($user_id, $active) public static function change_active_state($user_id, $active)
{ {
$user_id = (int) $user_id; $user_id = (int) $user_id;
$active = (int) $active; $active = (int) $active;

@ -86,6 +86,7 @@ class ZombieManager
$sql .= ' AND user.active = 1'; $sql .= ' AND user.active = 1';
} }
$sql .= !str_contains($sql, 'WHERE') ? ' WHERE user.active <> '.USER_SOFT_DELETED : ' AND user.active <> '.USER_SOFT_DELETED;
$sql .= " ORDER BY `$column` $direction"; $sql .= " ORDER BY `$column` $direction";
if (!is_null($from) && !is_null($count)) { if (!is_null($from) && !is_null($count)) {
$count = (int) $count; $count = (int) $count;

@ -117,7 +117,7 @@ if ('true' === $allowTutors) {
// search users where username or firstname or lastname begins likes $needle // search users where username or firstname or lastname begins likes $needle
$sql = 'SELECT user.user_id, username, lastname, firstname $sql = 'SELECT user.user_id, username, lastname, firstname
FROM '.$tbl_user.' user FROM '.$tbl_user.' user
WHERE (username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%" WHERE user.active <> '.USER_SOFT_DELETED.' AND (username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%"
OR lastname LIKE "'.$needle.'%") AND user.status<>6 AND user.status<>'.DRH.''. OR lastname LIKE "'.$needle.'%") AND user.status<>6 AND user.status<>'.DRH.''.
$order_clause. $order_clause.
' LIMIT 11'; ' LIMIT 11';
@ -125,7 +125,7 @@ if ('true' === $allowTutors) {
case 'multiple': case 'multiple':
$sql = 'SELECT user.user_id, username, lastname, firstname $sql = 'SELECT user.user_id, username, lastname, firstname
FROM '.$tbl_user.' user FROM '.$tbl_user.' user
WHERE '.(api_sort_by_first_name() ? 'firstname' : 'lastname').' WHERE user.active <> '.USER_SOFT_DELETED.' AND '.(api_sort_by_first_name() ? 'firstname' : 'lastname').'
LIKE "'.$needle.'%" AND LIKE "'.$needle.'%" AND
user.status<>'.DRH.' AND user.status<>'.DRH.' AND
user.status<>6 '.$cond_user_id. user.status<>6 '.$cond_user_id.
@ -136,6 +136,7 @@ if ('true' === $allowTutors) {
FROM '.$tbl_user.' user FROM '.$tbl_user.' user
LEFT OUTER JOIN '.$tbl_session_rel_user.' s ON (s.user_id = user.user_id) LEFT OUTER JOIN '.$tbl_session_rel_user.' s ON (s.user_id = user.user_id)
WHERE WHERE
user.active <> '.USER_SOFT_DELETED.' AND
s.user_id IS NULL AND s.user_id IS NULL AND
user.status <>'.DRH.' AND user.status <>'.DRH.' AND
user.status <> 6 '.$cond_user_id. user.status <> 6 '.$cond_user_id.
@ -154,6 +155,7 @@ if ('true' === $allowTutors) {
INNER JOIN '.$tbl_user_rel_access_url.' url_user INNER JOIN '.$tbl_user_rel_access_url.' url_user
ON (url_user.user_id=user.user_id) ON (url_user.user_id=user.user_id)
WHERE WHERE
user.active <> '.USER_SOFT_DELETED.' AND
access_url_id = '.$access_url_id.' AND access_url_id = '.$access_url_id.' AND
(username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%" OR lastname LIKE "'.$needle.'%") AND (username LIKE "'.$needle.'%" OR firstname LIKE "'.$needle.'%" OR lastname LIKE "'.$needle.'%") AND
user.status<>6 AND user.status<>6 AND
@ -166,7 +168,7 @@ if ('true' === $allowTutors) {
FROM '.$tbl_user.' user FROM '.$tbl_user.' user
INNER JOIN '.$tbl_user_rel_access_url.' url_user INNER JOIN '.$tbl_user_rel_access_url.' url_user
ON (url_user.user_id=user.user_id) ON (url_user.user_id=user.user_id)
WHERE access_url_id = '.$access_url_id.' AND WHERE user.active <> '.USER_SOFT_DELETED.' AND access_url_id = '.$access_url_id.' AND
'.(api_sort_by_first_name() ? 'firstname' : 'lastname').' LIKE "'.$needle.'%" AND user.status<>'.DRH.' AND user.status<>6 '.$cond_user_id. '.(api_sort_by_first_name() ? 'firstname' : 'lastname').' LIKE "'.$needle.'%" AND user.status<>'.DRH.' AND user.status<>6 '.$cond_user_id.
$order_clause; $order_clause;
break; break;
@ -178,6 +180,7 @@ if ('true' === $allowTutors) {
INNER JOIN '.$tbl_user_rel_access_url.' url_user INNER JOIN '.$tbl_user_rel_access_url.' url_user
ON (url_user.user_id=user.user_id) ON (url_user.user_id=user.user_id)
WHERE WHERE
user.active <> '.USER_SOFT_DELETED.' AND
access_url_id = '.$access_url_id.' AND access_url_id = '.$access_url_id.' AND
s.user_id IS null AND s.user_id IS null AND
user.status<>'.DRH.' AND user.status<>'.DRH.' AND
@ -296,7 +299,7 @@ if ('true' === $allowTutors) {
$tbl_session_rel_user.user_id = u.id AND $tbl_session_rel_user.user_id = u.id AND
$tbl_session_rel_user.relation_type = ".Session::STUDENT." AND $tbl_session_rel_user.relation_type = ".Session::STUDENT." AND
$tbl_session_rel_user.session_id = ".intval($id_session)." $tbl_session_rel_user.session_id = ".intval($id_session)."
WHERE u.status <> ".DRH." AND u.status<>6 $order_clause"; WHERE u.active <> ".USER_SOFT_DELETED." AND u.status <> ".DRH." AND u.status<>6 $order_clause";
if (api_is_multiple_url_enabled()) { if (api_is_multiple_url_enabled()) {
$tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
@ -311,7 +314,7 @@ if ('true' === $allowTutors) {
$tbl_session_rel_user.session_id = ".intval($id_session)." $tbl_session_rel_user.session_id = ".intval($id_session)."
INNER JOIN $tbl_user_rel_access_url url_user INNER JOIN $tbl_user_rel_access_url url_user
ON (url_user.user_id=u.user_id) ON (url_user.user_id=u.user_id)
WHERE access_url_id = $access_url_id AND u.status<>".DRH." AND u.status<>6 WHERE u.active <> ".USER_SOFT_DELETED." AND access_url_id = $access_url_id AND u.status<>".DRH." AND u.status<>6
$order_clause"; $order_clause";
} }
} }
@ -382,7 +385,7 @@ if ('true' === $allowTutors) {
ON $tbl_session_rel_user.user_id = u.id AND ON $tbl_session_rel_user.user_id = u.id AND
$tbl_session_rel_user.session_id = '$id_session' AND $tbl_session_rel_user.session_id = '$id_session' AND
$tbl_session_rel_user.relation_type = ".Session::STUDENT." $tbl_session_rel_user.relation_type = ".Session::STUDENT."
$where_filter AND u.status<>".DRH." AND u.status<>6 $where_filter AND u.status<>".DRH." AND u.status<>6 AND u.active <> ".USER_SOFT_DELETED."
$order_clause"; $order_clause";
} else { } else {
$sql = "SELECT u.id as user_id, lastname, firstname, username, session_id $sql = "SELECT u.id as user_id, lastname, firstname, username, session_id
@ -391,7 +394,7 @@ if ('true' === $allowTutors) {
ON $tbl_session_rel_user.user_id = u.id AND ON $tbl_session_rel_user.user_id = u.id AND
$tbl_session_rel_user.session_id = '$id_session' AND $tbl_session_rel_user.session_id = '$id_session' AND
$tbl_session_rel_user.relation_type = ".Session::STUDENT." $tbl_session_rel_user.relation_type = ".Session::STUDENT."
WHERE u.status <> ".DRH." AND u.status<>6 WHERE u.status <> ".DRH." AND u.status<>6 AND u.active <> ".USER_SOFT_DELETED."
$order_clause"; $order_clause";
} }
@ -407,7 +410,7 @@ if ('true' === $allowTutors) {
$tbl_session_rel_user.session_id = '$id_session' AND $tbl_session_rel_user.session_id = '$id_session' AND
$tbl_session_rel_user.relation_type = ".Session::STUDENT." $tbl_session_rel_user.relation_type = ".Session::STUDENT."
INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id) INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id)
WHERE access_url_id = $access_url_id $where_filter AND u.status<>".DRH." AND u.status<>6 WHERE access_url_id = $access_url_id $where_filter AND u.status<>".DRH." AND u.status<>6 AND u.active <> ".USER_SOFT_DELETED."
$order_clause"; $order_clause";
} }
} }
@ -435,7 +438,7 @@ if ('true' === $allowTutors) {
$tbl_session_rel_user.user_id = u.id AND $tbl_session_rel_user.user_id = u.id AND
$tbl_session_rel_user.session_id = '$id_session' AND $tbl_session_rel_user.session_id = '$id_session' AND
$tbl_session_rel_user.relation_type = ".Session::STUDENT." $tbl_session_rel_user.relation_type = ".Session::STUDENT."
WHERE u.status <> ".DRH." AND u.status<>6 $order_clause"; WHERE u.active <> ".USER_SOFT_DELETED." AND u.status <> ".DRH." AND u.status<>6 $order_clause";
if (api_is_multiple_url_enabled()) { if (api_is_multiple_url_enabled()) {
$tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER); $tbl_user_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
@ -449,7 +452,7 @@ if ('true' === $allowTutors) {
$tbl_session_rel_user.session_id = '$id_session' AND $tbl_session_rel_user.session_id = '$id_session' AND
$tbl_session_rel_user.relation_type = ".Session::STUDENT." $tbl_session_rel_user.relation_type = ".Session::STUDENT."
INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id) INNER JOIN $tbl_user_rel_access_url url_user ON (url_user.user_id=u.user_id)
WHERE access_url_id = $access_url_id AND u.status<>".DRH." AND u.status<>6 WHERE u.active <> ".USER_SOFT_DELETED." AND access_url_id = $access_url_id AND u.status<>".DRH." AND u.status<>6
$order_clause"; $order_clause";
} }
} }

@ -230,14 +230,14 @@ if ('true' === $allowTutors) {
INNER JOIN $tbl_session_rel_user su INNER JOIN $tbl_session_rel_user su
ON u.id = su.user_id AND su.relation_type = ".Session::STUDENT." ON u.id = su.user_id AND su.relation_type = ".Session::STUDENT."
LEFT OUTER JOIN $table_access_url_user uu ON (uu.user_id = u.id) LEFT OUTER JOIN $table_access_url_user uu ON (uu.user_id = u.id)
WHERE su.session_id = $id_session AND (access_url_id = $url_id OR access_url_id is null ) WHERE u.active <> ".USER_SOFT_DELETED." AND su.session_id = $id_session AND (access_url_id = $url_id OR access_url_id is null )
$order_clause"; $order_clause";
} else { } else {
$sql = "SELECT u.id as user_id, lastname, firstname, username $sql = "SELECT u.id as user_id, lastname, firstname, username
FROM $tbl_user u FROM $tbl_user u
INNER JOIN $tbl_session_rel_user su INNER JOIN $tbl_session_rel_user su
ON u.id = su.user_id AND su.relation_type = ".Session::STUDENT." ON u.id = su.user_id AND su.relation_type = ".Session::STUDENT."
AND su.session_id = ".$id_session.$order_clause; AND su.session_id = ".$id_session." WHERE u.active <> ".USER_SOFT_DELETED.$order_clause;
} }
$result = Database::query($sql); $result = Database::query($sql);

@ -253,6 +253,7 @@ function get_number_of_users()
c_id = $courseId AND c_id = $courseId AND
session_id = $sessionId session_id = $sessionId
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.user_id IS NULL cu.user_id IS NULL
$teacherRoleFilter AND $teacherRoleFilter AND
(u.official_code <> 'ADMIN' OR u.official_code IS NULL) "; (u.official_code <> 'ADMIN' OR u.official_code IS NULL) ";
@ -270,6 +271,7 @@ function get_number_of_users()
INNER JOIN $tbl_url_rel_user as url_rel_user INNER JOIN $tbl_url_rel_user as url_rel_user
ON (url_rel_user.user_id = u.id) ON (url_rel_user.user_id = u.id)
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.user_id IS NULL AND cu.user_id IS NULL AND
access_url_id = $url_access_id access_url_id = $url_access_id
$teacherRoleFilter AND $teacherRoleFilter AND
@ -283,6 +285,7 @@ function get_number_of_users()
LEFT JOIN $course_user_table cu LEFT JOIN $course_user_table cu
ON u.id = cu.user_id and c_id = $courseId ON u.id = cu.user_id and c_id = $courseId
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.user_id IS NULL cu.user_id IS NULL
$teacherRoleFilter "; $teacherRoleFilter ";
@ -298,6 +301,7 @@ function get_number_of_users()
INNER JOIN $tbl_url_rel_user as url_rel_user INNER JOIN $tbl_url_rel_user as url_rel_user
ON (url_rel_user.user_id = u.id) ON (url_rel_user.user_id = u.id)
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.user_id IS NULL cu.user_id IS NULL
$teacherRoleFilter AND $teacherRoleFilter AND
access_url_id = $url_access_id "; access_url_id = $url_access_id ";
@ -315,6 +319,7 @@ function get_number_of_users()
c_id = $courseId AND c_id = $courseId AND
session_id = $sessionId session_id = $sessionId
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.user_id IS NULL cu.user_id IS NULL
$studentRoleFilter AND $studentRoleFilter AND
(u.official_code <> 'ADMIN' OR u.official_code IS NULL) "; (u.official_code <> 'ADMIN' OR u.official_code IS NULL) ";
@ -333,6 +338,7 @@ function get_number_of_users()
INNER JOIN $tbl_url_rel_user as url_rel_user INNER JOIN $tbl_url_rel_user as url_rel_user
ON (url_rel_user.user_id = u.id) ON (url_rel_user.user_id = u.id)
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.user_id IS NULL cu.user_id IS NULL
$studentRoleFilter AND $studentRoleFilter AND
access_url_id = $url_access_id AND access_url_id = $url_access_id AND
@ -416,7 +422,7 @@ function get_number_of_users()
$users_of_course[] = $course_user['user_id']; $users_of_course[] = $course_user['user_id'];
} }
} }
$sql .= " AND u.status <> ".ANONYMOUS." "; $sql .= " AND u.status <> ".ANONYMOUS." AND u.active <> ".USER_SOFT_DELETED." ";
$res = Database::query($sql); $res = Database::query($sql);
$count_user = 0; $count_user = 0;
@ -704,7 +710,7 @@ function get_user_data($from, $number_of_items, $column, $direction)
} }
} }
$sql .= " AND u.status != ".ANONYMOUS." "; $sql .= " AND u.status != ".ANONYMOUS." AND u.active <> ".USER_SOFT_DELETED." ";
$column = (int) $column; $column = (int) $column;
$direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction; $direction = !in_array(strtolower(trim($direction)), ['asc', 'desc']) ? 'asc' : $direction;
// Sorting and pagination (used by the sortable table) // Sorting and pagination (used by the sortable table)

@ -233,7 +233,7 @@ if (isset($_GET['action'])) {
$sql .= ' , '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au '; $sql .= ' , '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au ';
} }
$sql .= " $sql .= "
WHERE c_id = $courseId WHERE user.active <> ".USER_SOFT_DELETED." AND c_id = $courseId
AND session_course_user.user_id = user.id AND session_course_user.user_id = user.id
AND session_id = $sessionId AND session_id = $sessionId
"; ";
@ -321,6 +321,7 @@ if (isset($_GET['action'])) {
$sql .= ' , '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au '; $sql .= ' , '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au ';
} }
$sql .= " WHERE $sql .= " WHERE
user.active <> ".USER_SOFT_DELETED." AND
c_id = '$courseId' AND c_id = '$courseId' AND
course_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND course_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
course_user.user_id = user.id "; course_user.user_id = user.id ";

@ -77,6 +77,7 @@ if (strlen($course_code) > 0) {
ON (u.id = cu.user_id) ON (u.id = cu.user_id)
$extraUrlJoin $extraUrlJoin
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
cu.c_id = $courseId AND cu.c_id = $courseId AND
cu.relation_type<>".COURSE_RELATION_TYPE_RRHH." cu.relation_type<>".COURSE_RELATION_TYPE_RRHH."
$extraUrlCondition $extraUrlCondition
@ -88,6 +89,7 @@ if (strlen($course_code) > 0) {
ON (u.id = scu.user_id) ON (u.id = scu.user_id)
$extraUrlJoin $extraUrlJoin
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
scu.c_id = $courseSessionId AND scu.c_id = $courseSessionId AND
scu.session_id = $sessionId scu.session_id = $sessionId
$extraUrlCondition $extraUrlCondition
@ -99,6 +101,7 @@ if (strlen($course_code) > 0) {
ON (u.id = su.user_id) ON (u.id = su.user_id)
$extraUrlJoin $extraUrlJoin
WHERE WHERE
u.active <> ".USER_SOFT_DELETED." AND
su.session_id = $sessionId su.session_id = $sessionId
$extraUrlCondition $extraUrlCondition
ORDER BY lastname,firstname"; ORDER BY lastname,firstname";
@ -111,11 +114,11 @@ if (strlen($course_code) > 0) {
$sql .= " FROM $userTable u $sql .= " FROM $userTable u
INNER JOIN $tbl_user_rel_access_url as user_rel_url INNER JOIN $tbl_user_rel_access_url as user_rel_url
ON (u.id = user_rel_url.user_id) ON (u.id = user_rel_url.user_id)
WHERE access_url_id = $access_url_id WHERE u.active <> ".USER_SOFT_DELETED." AND access_url_id = $access_url_id
ORDER BY lastname,firstname"; ORDER BY lastname,firstname";
} }
} else { } else {
$sql .= " FROM $userTable u ORDER BY lastname,firstname"; $sql .= " FROM $userTable u WHERE u.active <> ".USER_SOFT_DELETED." ORDER BY lastname,firstname";
} }
$filename = 'export_users_'.api_get_local_time(); $filename = 'export_users_'.api_get_local_time();
} }

@ -60,4 +60,6 @@ enum StateIcon: string
case ONLINE = 'account-check'; case ONLINE = 'account-check';
// Offline (for a user) // Offline (for a user)
case OFFLINE = 'account-off'; case OFFLINE = 'account-off';
// Soft deleted (for a user)
case REJECT = 'cancel';
} }

@ -21,6 +21,7 @@ use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Serializer\SerializerInterface; use Symfony\Component\Serializer\SerializerInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
class SecurityController extends AbstractController class SecurityController extends AbstractController
{ {
@ -34,7 +35,7 @@ class SecurityController extends AbstractController
) {} ) {}
#[Route('/login_json', name: 'login_json', methods: ['POST'])] #[Route('/login_json', name: 'login_json', methods: ['POST'])]
public function loginJson(Request $request, EntityManager $entityManager, SettingsManager $settingsManager, TokenStorageInterface $tokenStorage): Response public function loginJson(Request $request, EntityManager $entityManager, SettingsManager $settingsManager, TokenStorageInterface $tokenStorage, TranslatorInterface $translator): Response
{ {
if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) { if (!$this->isGranted('IS_AUTHENTICATED_FULLY')) {
return $this->json( return $this->json(
@ -47,6 +48,20 @@ class SecurityController extends AbstractController
/** @var User $user */ /** @var User $user */
$user = $this->getUser(); $user = $this->getUser();
if ($user->getActive() !== 1) {
if ($user->getActive() === 0) {
$message = $translator->trans('Account not activated.');
} else {
$message = $translator->trans('Invalid credentials. Please try again or contact support if you continue to experience issues.');
}
$tokenStorage->setToken(null);
$request->getSession()->invalidate();
return $this->json(['error' => $message], 401);
}
$extraFieldValuesRepository = $this->entityManager->getRepository(ExtraFieldValues::class); $extraFieldValuesRepository = $this->entityManager->getRepository(ExtraFieldValues::class);
$legalTermsRepo = $this->entityManager->getRepository(Legal::class); $legalTermsRepo = $this->entityManager->getRepository(Legal::class);
if ($user->hasRole('ROLE_STUDENT') if ($user->hasRole('ROLE_STUDENT')

@ -93,6 +93,12 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
public const STUDENT = 5; public const STUDENT = 5;
public const ANONYMOUS = 6;*/ public const ANONYMOUS = 6;*/
// User active field constants
public const ACTIVE = 1;
public const INACTIVE = 0;
public const INACTIVE_AUTOMATIC = -1;
public const SOFT_DELETED = -2;
#[Groups(['user_json:read'])] #[Groups(['user_json:read'])]
#[ORM\OneToOne(targetEntity: ResourceNode::class, cascade: ['persist'])] #[ORM\OneToOne(targetEntity: ResourceNode::class, cascade: ['persist'])]
#[ORM\JoinColumn(name: 'resource_node_id', onDelete: 'CASCADE')] #[ORM\JoinColumn(name: 'resource_node_id', onDelete: 'CASCADE')]
@ -635,8 +641,8 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
#[ORM\Column(name: 'expiration_date', type: 'datetime', unique: false, nullable: true)] #[ORM\Column(name: 'expiration_date', type: 'datetime', unique: false, nullable: true)]
protected ?DateTime $expirationDate = null; protected ?DateTime $expirationDate = null;
#[ORM\Column(name: 'active', type: 'boolean')] #[ORM\Column(name: 'active', type: 'integer')]
protected bool $active; protected int $active;
#[ORM\Column(name: 'openid', type: 'string', length: 255, unique: false, nullable: true)] #[ORM\Column(name: 'openid', type: 'string', length: 255, unique: false, nullable: true)]
protected ?string $openid = null; protected ?string $openid = null;
@ -728,7 +734,7 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
$this->authSource = 'platform'; $this->authSource = 'platform';
$this->status = CourseRelUser::STUDENT; $this->status = CourseRelUser::STUDENT;
$this->salt = sha1(uniqid('', true)); $this->salt = sha1(uniqid('', true));
$this->active = true; $this->active = 1;
$this->locked = false; $this->locked = false;
$this->expired = false; $this->expired = false;
$this->courses = new ArrayCollection(); $this->courses = new ArrayCollection();
@ -937,11 +943,7 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
*/ */
public function getIsActive(): bool public function getIsActive(): bool
{ {
if (1 == $this->active) { return $this->active === 1;
return true;
}
return false;
} }
public function isEnabled(): bool public function isEnabled(): bool
@ -1138,7 +1140,7 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
return $this; return $this;
} }
public function getActive(): bool public function getActive(): int
{ {
return $this->active; return $this->active;
} }
@ -1148,7 +1150,7 @@ class User implements UserInterface, EquatableInterface, ResourceInterface, Reso
return $this->getIsActive(); return $this->getIsActive();
} }
public function setActive(bool $active): self public function setActive(int $active): self
{ {
$this->active = $active; $this->active = $active;

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
/* For licensing terms, see /license.txt */
namespace Chamilo\CoreBundle\Migrations\Schema\V200;
use Chamilo\CoreBundle\Migrations\AbstractMigrationChamilo;
use Doctrine\DBAL\Schema\Schema;
class Version20240306204200 extends AbstractMigrationChamilo
{
public function getDescription(): string
{
return 'Modify user.active field from TINYINT to INT';
}
public function up(Schema $schema): void
{
$table = $schema->getTable('user');
if ($table->hasColumn('active')) {
$this->addSql('ALTER TABLE user CHANGE active active INT NOT NULL');
}
}
public function down(Schema $schema): void
{
$table = $schema->getTable('user');
if ($table->hasColumn('active')) {
$this->addSql('ALTER TABLE user CHANGE active active TINYINT(1) NOT NULL');
}
}
}

@ -136,28 +136,33 @@ class UserRepository extends ResourceRepository implements PasswordUpgraderInter
return $rootUser; return $rootUser;
} }
public function deleteUser(User $user): void public function deleteUser(User $user, bool $destroy = false): void
{ {
$em = $this->getEntityManager(); $em = $this->getEntityManager();
$type = $user->getResourceNode()->getResourceType();
$rootUser = $this->getRootUser();
// User children will be set to the root user. if ($destroy) {
$criteria = Criteria::create()->where(Criteria::expr()->eq('resourceType', $type)); $type = $user->getResourceNode()->getResourceType();
$userNodeCreatedList = $user->getResourceNodes()->matching($criteria); $rootUser = $this->getRootUser();
/** @var ResourceNode $userCreated */ $criteria = Criteria::create()->where(Criteria::expr()->eq('resourceType', $type));
foreach ($userNodeCreatedList as $userCreated) { $userNodeCreatedList = $user->getResourceNodes()->matching($criteria);
$userCreated->setCreator($rootUser);
} foreach ($userNodeCreatedList as $userCreated) {
$userCreated->setCreator($rootUser);
}
$em->remove($user->getResourceNode()); $em->remove($user->getResourceNode());
foreach ($user->getGroups() as $group) { foreach ($user->getGroups() as $group) {
$user->removeGroup($group); $user->removeGroup($group);
}
$em->remove($user);
} else {
$user->setActive(User::SOFT_DELETED);
$em->persist($user);
} }
$em->remove($user);
$em->flush(); $em->flush();
} }

Loading…
Cancel
Save