|
1 | 1 | <?php
|
| 2 | +// This file is part of Moodle - http://moodle.org/ |
| 3 | +// |
| 4 | +// Moodle is free software: you can redistribute it and/or modify |
| 5 | +// it under the terms of the GNU General Public License as published by |
| 6 | +// the Free Software Foundation, either version 3 of the License, or |
| 7 | +// (at your option) any later version. |
| 8 | +// |
| 9 | +// Moodle is distributed in the hope that it will be useful, |
| 10 | +// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | +// GNU General Public License for more details. |
| 13 | +// |
| 14 | +// You should have received a copy of the GNU General Public License |
| 15 | +// along with Moodle. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + |
| 17 | +/** |
| 18 | + * Utility class for managing student account lifecycle operations. |
| 19 | + * |
| 20 | + * This class provides functionality for managing student accounts including: |
| 21 | + * - Identifying accounts for cleanup |
| 22 | + * - Processing account disabling and deletion based on configured rules |
| 23 | + * - Handling role-based exclusions |
| 24 | + * |
| 25 | + * @package core_admin |
| 26 | + * @copyright 2024 onwards Catalyst IT {@link http://www.catalyst-eu.net/} |
| 27 | + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later |
| 28 | + * @author Waleed ul hassan <[email protected]> |
| 29 | + */ |
| 30 | + |
2 | 31 | namespace tool_disable_delete_students;
|
3 | 32 |
|
4 | 33 | defined('MOODLE_INTERNAL') || die();
|
5 | 34 |
|
| 35 | +/** |
| 36 | + * Utility class containing static methods for student account management. |
| 37 | + */ |
6 | 38 | class util {
|
7 | 39 | /**
|
8 |
| - * Get roles that should be excluded from cleanup |
9 |
| - * @return array |
| 40 | + * Get the list of roles that should be excluded from the cleanup process. |
| 41 | + * |
| 42 | + * Users with these roles will not be subject to automatic disabling or deletion, |
| 43 | + * even if they also have a student role. |
| 44 | + * |
| 45 | + * @return array Array of role shortnames that are excluded from processing |
10 | 46 | */
|
11 | 47 | public static function get_excluded_roles(): array {
|
12 | 48 | return ['coursecreator', 'editingteacher', 'teacher', 'manager', 'admin'];
|
13 | 49 | }
|
14 | 50 |
|
15 | 51 | /**
|
16 |
| - * Check if user has any excluded roles |
17 |
| - * @param int $userid |
18 |
| - * @return bool |
| 52 | + * Check if a user has any roles that exclude them from cleanup. |
| 53 | + * |
| 54 | + * @param int $userid The ID of the user to check |
| 55 | + * @return bool True if the user has any excluded roles, false otherwise |
19 | 56 | */
|
20 | 57 | public static function has_excluded_roles(int $userid): bool {
|
21 | 58 | global $DB;
|
22 |
| - |
23 |
| - $excluded_roles = self::get_excluded_roles(); |
| 59 | + |
| 60 | + $excludedroles = self::get_excluded_roles(); |
24 | 61 | $roles = get_user_roles(\context_system::instance(), $userid);
|
25 |
| - |
| 62 | + |
26 | 63 | foreach ($roles as $role) {
|
27 |
| - if (in_array($role->shortname, $excluded_roles)) { |
| 64 | + if (in_array($role->shortname, $excludedroles)) { |
28 | 65 | return true;
|
29 | 66 | }
|
30 | 67 | }
|
31 |
| - |
| 68 | + |
32 | 69 | return false;
|
33 | 70 | }
|
34 | 71 |
|
35 | 72 | /**
|
36 |
| - * Process student accounts |
| 73 | + * Process all student accounts for potential disabling or deletion. |
| 74 | + * |
| 75 | + * This method implements the main business logic for account management: |
| 76 | + * - Identifies active student accounts |
| 77 | + * - Checks each account against configured timeframes |
| 78 | + * - Disables accounts that meet the disability criteria |
| 79 | + * - Deletes accounts that meet the deletion criteria |
| 80 | + * - Respects role-based exclusions |
37 | 81 | */
|
38 | 82 | public static function process_student_accounts() {
|
39 | 83 | global $DB, $CFG;
|
40 | 84 |
|
41 |
| - $disable_after_course_end = get_config('tool_disable_delete_students', 'disable_after_course_end'); |
42 |
| - $disable_after_creation = get_config('tool_disable_delete_students', 'disable_after_creation'); |
43 |
| - $delete_after_months = get_config('tool_disable_delete_students', 'delete_after_months'); |
| 85 | + $disableaftercourseend = get_config('tool_disable_delete_students', 'disable_after_course_end'); |
| 86 | + $disableaftercreation = get_config('tool_disable_delete_students', 'disable_after_creation'); |
| 87 | + $deleteaftermonths = get_config('tool_disable_delete_students', 'delete_after_months'); |
44 | 88 |
|
45 |
| - // Get all active student accounts |
| 89 | + // Get all active student accounts. |
46 | 90 | $sql = "SELECT DISTINCT u.*
|
47 | 91 | FROM {user} u
|
48 | 92 | JOIN {role_assignments} ra ON ra.userid = u.id
|
49 | 93 | JOIN {role} r ON r.id = ra.roleid
|
50 | 94 | WHERE u.deleted = 0
|
51 | 95 | AND r.shortname = 'student'";
|
52 |
| - |
| 96 | + |
53 | 97 | $students = $DB->get_records_sql($sql);
|
54 | 98 |
|
55 | 99 | foreach ($students as $student) {
|
56 |
| - // Skip if user has excluded roles |
| 100 | + // Skip if user has excluded roles. |
57 | 101 | if (self::has_excluded_roles($student->id)) {
|
58 | 102 | continue;
|
59 | 103 | }
|
60 | 104 |
|
61 |
| - $should_disable = false; |
62 |
| - $should_delete = false; |
| 105 | + $shoulddisable = false; |
| 106 | + $shoulddelete = false; |
63 | 107 |
|
64 |
| - // Check course end date condition |
65 |
| - $latest_course_end = self::get_latest_course_end_date($student->id); |
66 |
| - if ($latest_course_end) { |
67 |
| - $days_since_course_end = (time() - $latest_course_end) / DAYSECS; |
68 |
| - if ($days_since_course_end > $disable_after_course_end) { |
69 |
| - $should_disable = true; |
| 108 | + // Check course end date condition. |
| 109 | + $latestcourseend = self::get_latest_course_end_date($student->id); |
| 110 | + if ($latestcourseend) { |
| 111 | + $dayssincecourseend = (time() - $latestcourseend) / DAYSECS; |
| 112 | + if ($dayssincecourseend > $disableaftercourseend) { |
| 113 | + $shoulddisable = true; |
70 | 114 | }
|
71 |
| - if ($days_since_course_end > ($delete_after_months * 30)) { |
72 |
| - $should_delete = true; |
| 115 | + if ($dayssincecourseend > ($deleteaftermonths * 30)) { |
| 116 | + $shoulddelete = true; |
73 | 117 | }
|
74 | 118 | }
|
75 | 119 |
|
76 |
| - // Check account creation date condition |
77 |
| - $days_since_creation = (time() - $student->timecreated) / DAYSECS; |
78 |
| - if ($days_since_creation > $disable_after_creation) { |
79 |
| - $should_disable = true; |
| 120 | + // Check account creation date condition. |
| 121 | + $dayssincecreation = (time() - $student->timecreated) / DAYSECS; |
| 122 | + if ($dayssincecreation > $disableaftercreation) { |
| 123 | + $shoulddisable = true; |
80 | 124 | }
|
81 | 125 |
|
82 |
| - if ($should_delete) { |
| 126 | + if ($shoulddelete) { |
83 | 127 | delete_user($student);
|
84 | 128 | mtrace("Deleted user: " . $student->username);
|
85 |
| - } elseif ($should_disable && !$student->suspended) { |
| 129 | + } else if ($shoulddisable && !$student->suspended) { |
86 | 130 | $DB->set_field('user', 'suspended', 1, ['id' => $student->id]);
|
87 | 131 | mtrace("Disabled user: " . $student->username);
|
88 | 132 | }
|
89 | 133 | }
|
90 | 134 | }
|
91 | 135 |
|
92 | 136 | /**
|
93 |
| - * Get the latest course end date for a user |
94 |
| - * @param int $userid |
95 |
| - * @return int|null |
| 137 | + * Get the latest course end date for a specific user. |
| 138 | + * |
| 139 | + * Retrieves the most recent end date among all courses the user is enrolled in. |
| 140 | + * Only considers courses with valid end dates (enddate > 0). |
| 141 | + * |
| 142 | + * @param int $userid The ID of the user to check |
| 143 | + * @return int|null The timestamp of the latest course end date, or null if no valid end dates found |
96 | 144 | */
|
97 | 145 | private static function get_latest_course_end_date(int $userid): ?int {
|
98 | 146 | global $DB;
|
99 |
| - |
| 147 | + |
100 | 148 | $sql = "SELECT MAX(c.enddate) as latest_end
|
101 | 149 | FROM {course} c
|
102 | 150 | JOIN {enrol} e ON e.courseid = c.id
|
103 | 151 | JOIN {user_enrolments} ue ON ue.enrolid = e.id
|
104 | 152 | WHERE ue.userid = :userid AND c.enddate > 0";
|
105 |
| - |
| 153 | + |
106 | 154 | $result = $DB->get_field_sql($sql, ['userid' => $userid]);
|
107 | 155 | return $result ?: null;
|
108 | 156 | }
|
|
0 commit comments