Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403]
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 namespace core_user\output; 18 19 use context_course; 20 use core_user; 21 use core_external\external_api; 22 use coding_exception; 23 24 /** 25 * Class to display list of user roles. 26 * 27 * @package core_user 28 * @copyright 2017 Damyon Wiese 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 30 */ 31 class user_roles_editable extends \core\output\inplace_editable { 32 33 /** @var $context */ 34 private $context = null; 35 36 /** @var \stdClass[] $courseroles */ 37 private $courseroles; 38 39 /** @var \stdClass[] $profileroles */ 40 private $profileroles; 41 42 /** @var \stdClass[] $viewableroles */ 43 private $viewableroles; 44 45 /** @var \stdClass[] $assignableroles */ 46 private $assignableroles; 47 48 /** 49 * Constructor. 50 * 51 * @param \stdClass $course The current course 52 * @param \context $context The course context 53 * @param \stdClass $user The current user 54 * @param \stdClass[] $courseroles The list of course roles. 55 * @param \stdClass[] $assignableroles The list of assignable roles in this course. 56 * @param \stdClass[] $profileroles The list of roles that should be visible in a users profile. 57 * @param \stdClass[] $userroles The list of user roles. 58 */ 59 public function __construct($course, $context, $user, $courseroles, $assignableroles, $profileroles, $userroles, $viewableroles = null) { 60 if ($viewableroles === null) { 61 debugging('Constructor for user_roles_editable now needs the result of get_viewable_roles passed as viewableroles'); 62 } 63 64 // Check capabilities to get editable value. 65 $editable = has_capability('moodle/role:assign', $context); 66 67 // Invent an itemid. 68 $itemid = $course->id . ':' . $user->id; 69 70 $getrole = function($role) { 71 return $role->roleid; 72 }; 73 $ids = array_values(array_unique(array_map($getrole, $userroles))); 74 75 $value = json_encode($ids); 76 77 // Remember these for the display value. 78 $this->courseroles = $courseroles; 79 $this->profileroles = $profileroles; 80 $this->viewableroles = array_keys($viewableroles); 81 $this->assignableroles = array_keys($assignableroles); 82 $this->context = $context; 83 84 parent::__construct('core_user', 'user_roles', $itemid, $editable, $value, $value); 85 86 // Removed the roles that were assigned to the user at a different context. 87 $options = $assignableroles; 88 foreach ($userroles as $role) { 89 if (isset($assignableroles[$role->roleid])) { 90 if ($role->contextid != $context->id) { 91 unset($options[$role->roleid]); 92 } 93 } 94 } 95 $this->edithint = get_string('xroleassignments', 'role', fullname($user)); 96 $this->editlabel = get_string('xroleassignments', 'role', fullname($user)); 97 98 $attributes = ['multiple' => true]; 99 $this->set_type_autocomplete($options, $attributes); 100 } 101 102 /** 103 * Export this data so it can be used as the context for a mustache template. 104 * 105 * @param \renderer_base $output 106 * @return array 107 */ 108 public function export_for_template(\renderer_base $output) { 109 $listofroles = []; 110 $roleids = json_decode($this->value); 111 $viewableroleids = array_intersect($roleids, array_merge($this->viewableroles, $this->assignableroles)); 112 113 foreach ($viewableroleids as $id) { 114 // If this is a student, we only show a subset of the roles. 115 if ($this->editable || array_key_exists($id, $this->profileroles)) { 116 $listofroles[] = format_string($this->courseroles[$id]->localname, true, ['context' => $this->context]); 117 } 118 } 119 120 if (!empty($listofroles)) { 121 $this->displayvalue = implode(', ', $listofroles); 122 } else if (!empty($roleids) && empty($viewableroleids)) { 123 $this->displayvalue = get_string('novisibleroles', 'role'); 124 } else { 125 $this->displayvalue = get_string('noroles', 'role'); 126 } 127 return parent::export_for_template($output); 128 } 129 130 /** 131 * Updates the value in database and returns itself, called from inplace_editable callback 132 * 133 * @param int $itemid 134 * @param mixed $newvalue 135 * @return \self 136 */ 137 public static function update($itemid, $newvalue) { 138 global $DB; 139 140 // Check caps. 141 // Do the thing. 142 // Return one of me. 143 // Validate the inputs. 144 list($courseid, $userid) = explode(':', $itemid, 2); 145 146 $courseid = clean_param($courseid, PARAM_INT); 147 $userid = clean_param($userid, PARAM_INT); 148 $roleids = json_decode($newvalue); 149 foreach ($roleids as $index => $roleid) { 150 $roleids[$index] = clean_param($roleid, PARAM_INT); 151 } 152 153 // Check user is enrolled in the course. 154 $context = context_course::instance($courseid); 155 external_api::validate_context($context); 156 157 // Check permissions. 158 require_capability('moodle/role:assign', $context); 159 160 if (!is_enrolled($context, $userid)) { 161 throw new coding_exception('User does not belong to the course'); 162 } 163 164 // Check that all the groups belong to the course. 165 $allroles = role_fix_names(get_all_roles($context), $context, ROLENAME_BOTH); 166 $assignableroles = get_assignable_roles($context, ROLENAME_BOTH, false); 167 $viewableroles = get_viewable_roles($context); 168 $userrolesbyid = get_user_roles($context, $userid, true, 'c.contextlevel DESC, r.sortorder ASC'); 169 $profileroles = get_profile_roles($context); 170 171 // Set an array where the index is the roleid. 172 $userroles = array(); 173 foreach ($userrolesbyid as $id => $role) { 174 $userroles[$role->roleid] = $role; 175 } 176 177 $rolestoprocess = []; 178 foreach ($roleids as $roleid) { 179 if (!isset($assignableroles[$roleid])) { 180 throw new coding_exception('Role cannot be assigned in this course.'); 181 } 182 $rolestoprocess[$roleid] = $roleid; 183 } 184 185 // Process adds. 186 foreach ($rolestoprocess as $roleid) { 187 if (!isset($userroles[$roleid])) { 188 // Add them. 189 $id = role_assign($roleid, $userid, $context); 190 // Keep this variable in sync. 191 $role = new \stdClass(); 192 $role->id = $id; 193 $role->roleid = $roleid; 194 $role->contextid = $context->id; 195 $userroles[$role->roleid] = $role; 196 } 197 } 198 199 // Process removals. 200 foreach ($assignableroles as $roleid => $rolename) { 201 if (isset($userroles[$roleid]) && !isset($rolestoprocess[$roleid])) { 202 // Do not remove the role if we are not in the same context. 203 if ($userroles[$roleid]->contextid != $context->id) { 204 continue; 205 } 206 $ras = $DB->get_records('role_assignments', ['contextid' => $context->id, 'userid' => $userid, 207 'roleid' => $roleid]); 208 $allremoved = true; 209 foreach ($ras as $ra) { 210 if ($ra->component) { 211 if (strpos($ra->component, 'enrol_') !== 0) { 212 continue; 213 } 214 if (!$plugin = enrol_get_plugin(substr($ra->component, 6))) { 215 continue; 216 } 217 if ($plugin->roles_protected()) { 218 $allremoved = false; 219 continue; 220 } 221 } 222 role_unassign($ra->roleid, $ra->userid, $ra->contextid, $ra->component, $ra->itemid); 223 } 224 if ($allremoved) { 225 unset($userroles[$roleid]); 226 } 227 } 228 } 229 230 $course = get_course($courseid); 231 $user = core_user::get_user($userid); 232 return new self($course, $context, $user, $allroles, $assignableroles, $profileroles, $userroles, $viewableroles); 233 } 234 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body