See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]
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 * Privacy class for requesting user data. 19 * 20 * @package core_completion 21 * @copyright 2018 Adrian Greeve <adrian@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 namespace core_completion\privacy; 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 use core_privacy\local\metadata\collection; 30 use core_privacy\local\request\approved_userlist; 31 use core_privacy\local\request\contextlist; 32 use core_privacy\local\request\transform; 33 use core_privacy\local\request\userlist; 34 35 require_once($CFG->dirroot . '/comment/lib.php'); 36 37 /** 38 * Privacy class for requesting user data. 39 * 40 * @package core_completion 41 * @copyright 2018 Adrian Greeve <adrian@moodle.com> 42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 43 */ 44 class provider implements 45 \core_privacy\local\metadata\provider, 46 \core_privacy\local\request\subsystem\plugin_provider, 47 \core_privacy\local\request\shared_userlist_provider 48 { 49 50 /** 51 * Returns meta data about this system. 52 * 53 * @param collection $collection The initialised collection to add items to. 54 * @return collection A listing of user data stored through this system. 55 */ 56 public static function get_metadata(collection $collection) : collection { 57 $collection->add_database_table('course_completions', [ 58 'userid' => 'privacy:metadata:userid', 59 'course' => 'privacy:metadata:course', 60 'timeenrolled' => 'privacy:metadata:timeenrolled', 61 'timestarted' => 'privacy:metadata:timestarted', 62 'timecompleted' => 'privacy:metadata:timecompleted', 63 'reaggregate' => 'privacy:metadata:reaggregate' 64 ], 'privacy:metadata:coursesummary'); 65 $collection->add_database_table('course_modules_completion', [ 66 'userid' => 'privacy:metadata:userid', 67 'coursemoduleid' => 'privacy:metadata:coursemoduleid', 68 'completionstate' => 'privacy:metadata:completionstate', 69 'overrideby' => 'privacy:metadata:overrideby', 70 'timemodified' => 'privacy:metadata:timemodified' 71 ], 'privacy:metadata:coursemodulesummary'); 72 $collection->add_database_table('course_modules_viewed', [ 73 'userid' => 'privacy:metadata:userid', 74 'coursemoduleid' => 'privacy:metadata:coursemoduleid', 75 'timecreated' => 'privacy:metadata:timecreated', 76 ], 'privacy:metadata:coursemodulesummary'); 77 $collection->add_database_table('course_completion_crit_compl', [ 78 'userid' => 'privacy:metadata:userid', 79 'course' => 'privacy:metadata:course', 80 'gradefinal' => 'privacy:metadata:gradefinal', 81 'unenroled' => 'privacy:metadata:unenroled', 82 'timecompleted' => 'privacy:metadata:timecompleted' 83 ], 'privacy:metadata:coursecompletedsummary'); 84 return $collection; 85 } 86 87 /** 88 * Get join sql to retrieve courses the user is in. 89 * 90 * @param int $userid The user ID 91 * @param string $prefix A unique prefix for these joins. 92 * @param string $joinfield A field to join these tables to. Joins to course ID. 93 * @return array The join, where, and params for this join. 94 */ 95 public static function get_course_completion_join_sql(int $userid, string $prefix, string $joinfield) : array { 96 $cccalias = "{$prefix}_ccc"; // Course completion criteria. 97 $cmcalias = "{$prefix}_cmc"; // Course modules completion. 98 $cmvalias = "{$prefix}_cmv"; // Course modules viewed. 99 $ccccalias = "{$prefix}_cccc"; // Course completion criteria completion. 100 101 $join = "JOIN {course_completion_criteria} {$cccalias} ON {$joinfield} = {$cccalias}.course 102 LEFT JOIN {course_modules_completion} {$cmcalias} ON {$cccalias}.moduleinstance = {$cmcalias}.coursemoduleid 103 AND {$cmcalias}.userid = :{$prefix}_moduleuserid 104 LEFT JOIN {course_modules_viewed} {$cmvalias} ON {$cccalias}.moduleinstance = {$cmvalias}.coursemoduleid 105 AND {$cmvalias}.userid = :{$prefix}_moduleuserid2 106 LEFT JOIN {course_completion_crit_compl} {$ccccalias} ON {$ccccalias}.criteriaid = {$cccalias}.id 107 AND {$ccccalias}.userid = :{$prefix}_courseuserid"; 108 $where = "{$cmcalias}.id IS NOT NULL OR {$ccccalias}.id IS NOT NULL OR {$cmvalias}.id IS NOT NULL"; 109 $params = ["{$prefix}_moduleuserid" => $userid, "{$prefix}_moduleuserid2" => $userid, "{$prefix}_courseuserid" => $userid]; 110 return [$join, $where, $params]; 111 } 112 113 /** 114 * Find users' course completion by context and add to the provided userlist. 115 * 116 * @param userlist $userlist The userlist to add to. 117 */ 118 public static function add_course_completion_users_to_userlist(userlist $userlist) { 119 $context = $userlist->get_context(); 120 121 if (!$context instanceof \context_course) { 122 return; 123 } 124 125 $params = ['courseid' => $context->instanceid]; 126 127 $sql = "SELECT cmc.userid 128 FROM {course} c 129 JOIN {course_completion_criteria} ccc ON ccc.course = c.id 130 JOIN {course_modules_completion} cmc ON cmc.coursemoduleid = ccc.moduleinstance 131 WHERE c.id = :courseid"; 132 133 $userlist->add_from_sql('userid', $sql, $params); 134 135 $sql = "SELECT cmv.userid 136 FROM {course} c 137 JOIN {course_completion_criteria} ccc ON ccc.course = c.id 138 JOIN {course_modules_viewed} cmv ON cmv.coursemoduleid = ccc.moduleinstance 139 WHERE c.id = :courseid"; 140 141 $userlist->add_from_sql('userid', $sql, $params); 142 143 $sql = "SELECT ccc_compl.userid 144 FROM {course} c 145 JOIN {course_completion_criteria} ccc ON ccc.course = c.id 146 JOIN {course_completion_crit_compl} ccc_compl ON ccc_compl.criteriaid = ccc.id 147 WHERE c.id = :courseid"; 148 149 $userlist->add_from_sql('userid', $sql, $params); 150 } 151 152 /** 153 * Returns activity completion information about a user. 154 * 155 * @param \stdClass $user The user to return information about. 156 * @param \stdClass $course The course the user is in. 157 * @param \stdClass $cm Course module information. 158 * @return \stdClass Activity completion information. 159 */ 160 public static function get_activity_completion_info(\stdClass $user, \stdClass $course, $cm) : \stdClass { 161 $completioninfo = new \completion_info($course); 162 $completion = $completioninfo->is_enabled($cm); 163 return ($completion != COMPLETION_TRACKING_NONE) ? $completioninfo->get_data($cm, true, $user->id) : new \stdClass(); 164 } 165 166 /** 167 * Returns course completion information for a user. 168 * 169 * @param \stdClass $user The user that we are getting completion information for. 170 * @param \stdClass $course The course we are interested in. 171 * @return \stdClass Course completion information. 172 */ 173 public static function get_course_completion_info(\stdClass $user, \stdClass $course) : array { 174 $completioninfo = new \completion_info($course); 175 $completion = $completioninfo->is_enabled(); 176 177 if ($completion != COMPLETION_ENABLED) { 178 return []; 179 } 180 181 $coursecomplete = $completioninfo->is_course_complete($user->id); 182 183 if ($coursecomplete) { 184 $status = get_string('complete'); 185 } else { 186 $criteriacomplete = $completioninfo->count_course_user_data($user->id); 187 $ccompletion = new \completion_completion(['userid' => $user->id, 'course' => $course->id]); 188 189 if (!$criteriacomplete && !$ccompletion->timestarted) { 190 $status = get_string('notyetstarted', 'completion'); 191 } else { 192 $status = get_string('inprogress', 'completion'); 193 } 194 } 195 196 $completions = $completioninfo->get_completions($user->id); 197 $overall = get_string('nocriteriaset', 'completion'); 198 if (!empty($completions)) { 199 if ($completioninfo->get_aggregation_method() == COMPLETION_AGGREGATION_ALL) { 200 $overall = get_string('criteriarequiredall', 'completion'); 201 } else { 202 $overall = get_string('criteriarequiredany', 'completion'); 203 } 204 } 205 206 $coursecompletiondata = [ 207 'status' => $status, 208 'required' => $overall, 209 ]; 210 211 $coursecompletiondata['criteria'] = array_map(function($completion) use ($completioninfo) { 212 $criteria = $completion->get_criteria(); 213 $aggregation = $completioninfo->get_aggregation_method($criteria->criteriatype); 214 $required = ($aggregation == COMPLETION_AGGREGATION_ALL) ? get_string('all', 'completion') : 215 get_string('any', 'completion'); 216 $data = [ 217 'required' => $required, 218 'completed' => transform::yesno($completion->is_complete()), 219 'timecompleted' => isset($completion->timecompleted) ? transform::datetime($completion->timecompleted) : '' 220 ]; 221 $details = $criteria->get_details($completion); 222 $data = array_merge($data, $details); 223 return $data; 224 }, $completions); 225 return $coursecompletiondata; 226 } 227 228 /** 229 * Delete completion information for users. 230 * 231 * @param \stdClass $user The user. If provided will delete completion information for just this user. Else all users. 232 * @param int $courseid The course id. Provide this if you want course completion and activity completion deleted. 233 * @param int $cmid The course module id. Provide this if you only want activity completion deleted. 234 */ 235 public static function delete_completion(\stdClass $user = null, int $courseid = null, int $cmid = null) { 236 global $DB; 237 238 if (isset($cmid)) { 239 $params = (isset($user)) ? ['userid' => $user->id, 'coursemoduleid' => $cmid] : ['coursemoduleid' => $cmid]; 240 // Only delete the record for course modules completion. 241 $DB->delete_records('course_modules_completion', $params); 242 return; 243 } 244 245 if (isset($courseid)) { 246 247 $usersql = isset($user) ? 'AND cmc.userid = :userid' : ''; 248 $usercmvsql = isset($user) ? 'AND cmv.userid = :userid' : ''; 249 $params = isset($user) ? ['course' => $courseid, 'userid' => $user->id] : ['course' => $courseid]; 250 251 // Find records relating to course modules. 252 $sql = "SELECT cmc.id 253 FROM {course_completion_criteria} ccc 254 JOIN {course_modules_completion} cmc ON ccc.moduleinstance = cmc.coursemoduleid 255 WHERE ccc.course = :course $usersql"; 256 $recordids = $DB->get_records_sql($sql, $params); 257 $ids = array_keys($recordids); 258 if (!empty($ids)) { 259 list($deletesql, $deleteparams) = $DB->get_in_or_equal($ids); 260 $deletesql = 'id ' . $deletesql; 261 $DB->delete_records_select('course_modules_completion', $deletesql, $deleteparams); 262 } 263 // Find records relating to course modules completion viewed. 264 $sql = "SELECT cmv.id 265 FROM {course_completion_criteria} ccc 266 JOIN {course_modules_viewed} cmv ON ccc.moduleinstance = cmv.coursemoduleid 267 WHERE ccc.course = :course $usercmvsql"; 268 $recordids = $DB->get_records_sql($sql, $params); 269 $ids = array_keys($recordids); 270 if (!empty($ids)) { 271 list($deletesql, $deleteparams) = $DB->get_in_or_equal($ids); 272 $deletesql = 'id ' . $deletesql; 273 $DB->delete_records_select('course_modules_viewed', $deletesql, $deleteparams); 274 } 275 276 $DB->delete_records('course_completion_crit_compl', $params); 277 $DB->delete_records('course_completions', $params); 278 } 279 } 280 281 /** 282 * Delete completion information for users within an approved userlist. 283 * 284 * @param approved_userlist $userlist The approved userlist of users to delete completion information for. 285 * @param int $courseid The course id. Provide this if you want course completion and activity completion deleted. 286 * @param int $cmid The course module id. Provide this if you only want activity completion deleted. 287 */ 288 public static function delete_completion_by_approved_userlist(approved_userlist $userlist, int $courseid = null, int $cmid = null) { 289 global $DB; 290 $userids = $userlist->get_userids(); 291 292 if (empty($userids)) { 293 return; 294 } 295 296 list($useridsql, $params) = $DB->get_in_or_equal($userids, SQL_PARAMS_NAMED); 297 298 if (isset($cmid)) { 299 $params['coursemoduleid'] = $cmid; 300 301 // Only delete the record for course modules completion. 302 $sql = "coursemoduleid = :coursemoduleid AND userid {$useridsql}"; 303 $DB->delete_records_select('course_modules_completion', $sql, $params); 304 $DB->delete_records_select('course_modules_viewed', $sql, $params); 305 return; 306 } 307 308 if (isset($courseid)) { 309 $params['course'] = $courseid; 310 311 // Find records relating to course modules. 312 $sql = "SELECT cmc.id 313 FROM {course_completion_criteria} ccc 314 JOIN {course_modules_completion} cmc ON ccc.moduleinstance = cmc.coursemoduleid 315 WHERE ccc.course = :course AND cmc.userid {$useridsql}"; 316 $recordids = $DB->get_records_sql($sql, $params); 317 $ids = array_keys($recordids); 318 if (!empty($ids)) { 319 list($deletesql, $deleteparams) = $DB->get_in_or_equal($ids); 320 $deletesql = 'id ' . $deletesql; 321 $DB->delete_records_select('course_modules_completion', $deletesql, $deleteparams); 322 } 323 324 // Find records relating to course modules. 325 $sql = "SELECT cmv.id 326 FROM {course_completion_criteria} ccc 327 JOIN {course_modules_viewed} cmv ON ccc.moduleinstance = cmv.coursemoduleid 328 WHERE ccc.course = :course AND cmv.userid {$useridsql}"; 329 $recordids = $DB->get_records_sql($sql, $params); 330 $ids = array_keys($recordids); 331 if (!empty($ids)) { 332 list($deletesql, $deleteparams) = $DB->get_in_or_equal($ids); 333 $deletesql = 'id ' . $deletesql; 334 $DB->delete_records_select('course_modules_viewed', $deletesql, $deleteparams); 335 } 336 337 $sql = "course = :course AND userid {$useridsql}"; 338 $DB->delete_records_select('course_completion_crit_compl', $sql, $params); 339 $DB->delete_records_select('course_completions', $sql, $params); 340 } 341 } 342 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body