Commit | Line | Data |
---|---|---|
bbbf2d40 | 1 | <?php |
cee0901c | 2 | /** |
3 | * Capability session information format | |
bbbf2d40 | 4 | * 2 x 2 array |
5 | * [context][capability] | |
6 | * where context is the context id of the table 'context' | |
7 | * and capability is a string defining the capability | |
8 | * e.g. | |
9 | * | |
10 | * [Capabilities] => [26][mod/forum:viewpost] = 1 | |
11 | * [26][mod/forum:startdiscussion] = -8990 | |
12 | * [26][mod/forum:editallpost] = -1 | |
13 | * [273][moodle:blahblah] = 1 | |
14 | * [273][moodle:blahblahblah] = 2 | |
15 | */ | |
bbbf2d40 | 16 | |
17 | // permission definitions | |
e49e61bf | 18 | define('CAP_INHERIT', 0); |
bbbf2d40 | 19 | define('CAP_ALLOW', 1); |
20 | define('CAP_PREVENT', -1); | |
21 | define('CAP_PROHIBIT', -1000); | |
22 | ||
bbbf2d40 | 23 | // context definitions |
24 | define('CONTEXT_SYSTEM', 10); | |
25 | define('CONTEXT_PERSONAL', 20); | |
4b10f08b | 26 | define('CONTEXT_USER', 30); |
bbbf2d40 | 27 | define('CONTEXT_COURSECAT', 40); |
28 | define('CONTEXT_COURSE', 50); | |
29 | define('CONTEXT_GROUP', 60); | |
30 | define('CONTEXT_MODULE', 70); | |
31 | define('CONTEXT_BLOCK', 80); | |
32 | ||
21b6db6e | 33 | // capability risks - see http://docs.moodle.org/en/Hardening_new_Roles_system |
34 | define('RISK_MANAGETRUST', 0x0001); | |
a6b02b65 | 35 | define('RISK_CONFIG', 0x0002); |
21b6db6e | 36 | define('RISK_XSS', 0x0004); |
37 | define('RISK_PERSONAL', 0x0008); | |
38 | define('RISK_SPAM', 0x0010); | |
39 | ||
f3f7610c | 40 | require_once($CFG->dirroot.'/group/lib.php'); |
21b6db6e | 41 | |
340ea4e8 | 42 | $context_cache = array(); // Cache of all used context objects for performance (by level and instance) |
43 | $context_cache_id = array(); // Index to above cache by id | |
bbbf2d40 | 44 | |
7700027f | 45 | |
e7876c1e | 46 | /** |
47 | * Loads the capabilities for the default guest role to the current user in a specific context | |
48 | * @return object | |
49 | */ | |
8d2b18a8 | 50 | function load_guest_role($context=NULL, $mergewith=NULL) { |
e7876c1e | 51 | global $USER; |
52 | ||
53 | static $guestrole; | |
54 | ||
55 | if (!isloggedin()) { | |
56 | return false; | |
57 | } | |
58 | ||
21c9bace | 59 | if (!$sitecontext = get_context_instance(CONTEXT_SYSTEM)) { |
e7876c1e | 60 | return false; |
61 | } | |
62 | ||
63 | if (empty($context)) { | |
64 | $context = $sitecontext; | |
65 | } | |
66 | ||
67 | if (empty($guestrole)) { | |
8f8ed475 | 68 | if (!$guestrole = get_guest_role()) { |
e7876c1e | 69 | return false; |
70 | } | |
71 | } | |
72 | ||
eef868d1 | 73 | if ($capabilities = get_records_select('role_capabilities', |
e7876c1e | 74 | "roleid = $guestrole->id AND contextid = $sitecontext->id")) { |
75 | foreach ($capabilities as $capability) { | |
8d2b18a8 | 76 | if ($mergewith === NULL) { |
77 | $USER->capabilities[$context->id][$capability->capability] = $capability->permission; | |
78 | } else { | |
79 | $mergewith[$context->id][$capability->capability] = $capability->permission; | |
80 | } | |
e7876c1e | 81 | } |
82 | } | |
83 | ||
8d2b18a8 | 84 | if ($mergewith === NULL) { |
85 | has_capability('clearcache'); | |
86 | return true; | |
87 | } else { | |
88 | return $mergewith; | |
89 | } | |
e7876c1e | 90 | } |
91 | ||
7700027f | 92 | /** |
93 | * Load default not logged in role capabilities when user is not logged in | |
eef868d1 | 94 | * @return bool |
7700027f | 95 | */ |
20aeb4b8 | 96 | function load_notloggedin_role() { |
97 | global $CFG, $USER; | |
98 | ||
21c9bace | 99 | if (!$sitecontext = get_context_instance(CONTEXT_SYSTEM)) { |
7700027f | 100 | return false; |
35a518c5 | 101 | } |
102 | ||
7700027f | 103 | if (empty($CFG->notloggedinroleid)) { // Let's set the default to the guest role |
8f8ed475 | 104 | if ($role = get_guest_role()) { |
7700027f | 105 | set_config('notloggedinroleid', $role->id); |
106 | } else { | |
107 | return false; | |
108 | } | |
109 | } | |
20aeb4b8 | 110 | |
eef868d1 | 111 | if ($capabilities = get_records_select('role_capabilities', |
7700027f | 112 | "roleid = $CFG->notloggedinroleid AND contextid = $sitecontext->id")) { |
113 | foreach ($capabilities as $capability) { | |
eef868d1 | 114 | $USER->capabilities[$sitecontext->id][$capability->capability] = $capability->permission; |
7700027f | 115 | } |
99ad7633 | 116 | has_capability('clearcache'); |
20aeb4b8 | 117 | } |
118 | ||
119 | return true; | |
120 | } | |
cee0901c | 121 | |
8f8ed475 | 122 | /** |
123 | * Load default not logged in role capabilities when user is not logged in | |
eef868d1 | 124 | * @return bool |
8f8ed475 | 125 | */ |
8d2b18a8 | 126 | function load_defaultuser_role($return=false) { |
8f8ed475 | 127 | global $CFG, $USER; |
128 | ||
21c9bace | 129 | if (!$sitecontext = get_context_instance(CONTEXT_SYSTEM)) { |
8f8ed475 | 130 | return false; |
131 | } | |
132 | ||
133 | if (empty($CFG->defaultuserroleid)) { // Let's set the default to the guest role | |
134 | if ($role = get_guest_role()) { | |
135 | set_config('defaultuserroleid', $role->id); | |
136 | } else { | |
137 | return false; | |
138 | } | |
139 | } | |
140 | ||
8d2b18a8 | 141 | if ($return) { |
142 | $defcaps = array(); | |
143 | } | |
144 | ||
eef868d1 | 145 | if ($capabilities = get_records_select('role_capabilities', |
0163b1d0 | 146 | "roleid = $CFG->defaultuserroleid AND contextid = $sitecontext->id AND permission <> 0")) { |
40d86709 | 147 | // Find out if this default role is a guest role, for the hack below |
8d2b18a8 | 148 | |
40d86709 | 149 | $defaultisguestrole=false; |
8f8ed475 | 150 | foreach ($capabilities as $capability) { |
40d86709 | 151 | if($capability->capability=='moodle/legacy:guest') { |
152 | $defaultisguestrole=true; | |
153 | } | |
154 | } | |
155 | foreach ($capabilities as $capability) { | |
156 | // If the default role is a guest role, then don't copy legacy:guest, | |
157 | // otherwise this user could get confused with a REAL guest. Also don't copy | |
158 | // course:view, which is a hack that's necessary because guest roles are | |
159 | // not really handled properly (see MDL-7513) | |
8d2b18a8 | 160 | if($defaultisguestrole && |
40d86709 | 161 | ($capability->capability=='moodle/legacy:guest' || |
162 | $capability->capability=='moodle/course:view')) { | |
163 | continue; | |
164 | } | |
8d2b18a8 | 165 | if ($return) { |
166 | $defcaps[$sitecontext->id][$capability->capability] = $capability->permission; | |
167 | } else { | |
168 | // Don't overwrite capabilities from real role... | |
169 | if (!isset($USER->capabilities[$sitecontext->id][$capability->capability])) { | |
170 | $USER->capabilities[$sitecontext->id][$capability->capability] = $capability->permission; | |
171 | } | |
ca23ffdb | 172 | } |
8f8ed475 | 173 | } |
8f8ed475 | 174 | } |
175 | ||
8d2b18a8 | 176 | if ($return) { |
177 | return $defcaps; | |
178 | } else { | |
179 | has_capability('clearcache'); | |
180 | return true; | |
181 | } | |
8f8ed475 | 182 | } |
183 | ||
184 | ||
185 | /** | |
186 | * Get the default guest role | |
187 | * @return object role | |
188 | */ | |
189 | function get_guest_role() { | |
ebce32b5 | 190 | global $CFG; |
191 | ||
192 | if (empty($CFG->guestroleid)) { | |
193 | if ($roles = get_roles_with_capability('moodle/legacy:guest', CAP_ALLOW)) { | |
194 | $guestrole = array_shift($roles); // Pick the first one | |
195 | set_config('guestroleid', $guestrole->id); | |
196 | return $guestrole; | |
197 | } else { | |
198 | debugging('Can not find any guest role!'); | |
199 | return false; | |
200 | } | |
8f8ed475 | 201 | } else { |
ebce32b5 | 202 | if ($guestrole = get_record('role','id', $CFG->guestroleid)) { |
203 | return $guestrole; | |
204 | } else { | |
205 | //somebody is messing with guest roles, remove incorrect setting and try to find a new one | |
206 | set_config('guestroleid', ''); | |
207 | return get_guest_role(); | |
208 | } | |
8f8ed475 | 209 | } |
210 | } | |
211 | ||
212 | ||
bbbf2d40 | 213 | /** |
214 | * This functions get all the course categories in proper order | |
40a2a15f | 215 | * (!)note this only gets course category contexts, and not the site |
216 | * context | |
d963740d | 217 | * @param object $context |
bbbf2d40 | 218 | * @param int $type |
219 | * @return array of contextids | |
220 | */ | |
0468976c | 221 | function get_parent_cats($context, $type) { |
eef868d1 | 222 | |
98882637 | 223 | $parents = array(); |
eef868d1 | 224 | |
c5ddc3fd | 225 | switch ($type) { |
40a2a15f | 226 | // a category can be the parent of another category |
227 | // there is no limit of depth in this case | |
98882637 | 228 | case CONTEXT_COURSECAT: |
c5ddc3fd | 229 | if (!$cat = get_record('course_categories','id',$context->instanceid)) { |
230 | break; | |
231 | } | |
232 | ||
233 | while (!empty($cat->parent)) { | |
234 | if (!$context = get_context_instance(CONTEXT_COURSECAT, $cat->parent)) { | |
235 | break; | |
236 | } | |
98882637 | 237 | $parents[] = $context->id; |
238 | $cat = get_record('course_categories','id',$cat->parent); | |
239 | } | |
98882637 | 240 | break; |
40a2a15f | 241 | |
242 | // a course always fall into a category, unless it's a site course | |
8ba412da | 243 | // this happens when SITEID == $course->id |
40a2a15f | 244 | // in this case the parent of the course is site context |
98882637 | 245 | case CONTEXT_COURSE: |
c5ddc3fd | 246 | if (!$course = get_record('course', 'id', $context->instanceid)) { |
247 | break; | |
248 | } | |
249 | if (!$catinstance = get_context_instance(CONTEXT_COURSECAT, $course->category)) { | |
250 | break; | |
251 | } | |
252 | ||
98882637 | 253 | $parents[] = $catinstance->id; |
c5ddc3fd | 254 | |
255 | if (!$cat = get_record('course_categories','id',$course->category)) { | |
256 | break; | |
257 | } | |
40a2a15f | 258 | // Yu: Separating site and site course context |
259 | if ($course->id == SITEID) { | |
260 | break; | |
261 | } | |
c5ddc3fd | 262 | |
263 | while (!empty($cat->parent)) { | |
264 | if (!$context = get_context_instance(CONTEXT_COURSECAT, $cat->parent)) { | |
265 | break; | |
266 | } | |
98882637 | 267 | $parents[] = $context->id; |
268 | $cat = get_record('course_categories','id',$cat->parent); | |
269 | } | |
270 | break; | |
eef868d1 | 271 | |
98882637 | 272 | default: |
273 | break; | |
98882637 | 274 | } |
98882637 | 275 | return array_reverse($parents); |
bbbf2d40 | 276 | } |
277 | ||
278 | ||
cee0901c | 279 | |
0468976c | 280 | /** |
281 | * This function checks for a capability assertion being true. If it isn't | |
282 | * then the page is terminated neatly with a standard error message | |
283 | * @param string $capability - name of the capability | |
284 | * @param object $context - a context object (record from context table) | |
285 | * @param integer $userid - a userid number | |
d74067e8 | 286 | * @param bool $doanything - if false, ignore do anything |
0468976c | 287 | * @param string $errorstring - an errorstring |
d74067e8 | 288 | * @param string $stringfile - which stringfile to get it from |
0468976c | 289 | */ |
eef868d1 | 290 | function require_capability($capability, $context=NULL, $userid=NULL, $doanything=true, |
71483894 | 291 | $errormessage='nopermissions', $stringfile='') { |
a9e1c058 | 292 | |
71483894 | 293 | global $USER, $CFG; |
a9e1c058 | 294 | |
71483894 | 295 | /// If the current user is not logged in, then make sure they are (if needed) |
a9e1c058 | 296 | |
6605128e | 297 | if (empty($userid) and empty($USER->capabilities)) { |
aad2ba95 | 298 | if ($context && ($context->contextlevel == CONTEXT_COURSE)) { |
a9e1c058 | 299 | require_login($context->instanceid); |
11ac79ff | 300 | } else if ($context && ($context->contextlevel == CONTEXT_MODULE)) { |
301 | if ($cm = get_record('course_modules','id',$context->instanceid)) { | |
71483894 | 302 | if (!$course = get_record('course', 'id', $cm->course)) { |
303 | error('Incorrect course.'); | |
304 | } | |
305 | require_course_login($course, true, $cm); | |
306 | ||
11ac79ff | 307 | } else { |
308 | require_login(); | |
309 | } | |
71483894 | 310 | } else if ($context && ($context->contextlevel == CONTEXT_SYSTEM)) { |
311 | if (!empty($CFG->forcelogin)) { | |
312 | require_login(); | |
313 | } | |
314 | ||
a9e1c058 | 315 | } else { |
316 | require_login(); | |
317 | } | |
318 | } | |
eef868d1 | 319 | |
a9e1c058 | 320 | /// OK, if they still don't have the capability then print a nice error message |
321 | ||
d74067e8 | 322 | if (!has_capability($capability, $context, $userid, $doanything)) { |
0468976c | 323 | $capabilityname = get_capability_string($capability); |
324 | print_error($errormessage, $stringfile, '', $capabilityname); | |
325 | } | |
326 | } | |
327 | ||
328 | ||
bbbf2d40 | 329 | /** |
330 | * This function returns whether the current user has the capability of performing a function | |
331 | * For example, we can do has_capability('mod/forum:replypost',$cm) in forum | |
332 | * only one of the 4 (moduleinstance, courseid, site, userid) would be set at 1 time | |
333 | * This is a recursive funciton. | |
bbbf2d40 | 334 | * @uses $USER |
caac8977 | 335 | * @param string $capability - name of the capability (or debugcache or clearcache) |
0468976c | 336 | * @param object $context - a context object (record from context table) |
337 | * @param integer $userid - a userid number | |
20aeb4b8 | 338 | * @param bool $doanything - if false, ignore do anything |
bbbf2d40 | 339 | * @return bool |
340 | */ | |
d74067e8 | 341 | function has_capability($capability, $context=NULL, $userid=NULL, $doanything=true) { |
bbbf2d40 | 342 | |
20aeb4b8 | 343 | global $USER, $CONTEXT, $CFG; |
bbbf2d40 | 344 | |
922633bd | 345 | static $capcache = array(); // Cache of capabilities |
346 | ||
caac8977 | 347 | |
348 | /// Cache management | |
349 | ||
350 | if ($capability == 'clearcache') { | |
351 | $capcache = array(); // Clear ALL the capability cache | |
352 | return false; | |
353 | } | |
354 | ||
922633bd | 355 | /// Some sanity checks |
356 | if (debugging()) { | |
357 | if ($capability == 'debugcache') { | |
358 | print_object($capcache); | |
359 | return true; | |
360 | } | |
361 | if (!record_exists('capabilities', 'name', $capability)) { | |
362 | debugging('Capability "'.$capability.'" was not found! This should be fixed in code.'); | |
363 | } | |
364 | if ($doanything != true and $doanything != false) { | |
365 | debugging('Capability parameter "doanything" is wierd ("'.$doanything.'"). This should be fixed in code.'); | |
366 | } | |
367 | if (!is_object($context) && $context !== NULL) { | |
368 | debugging('Incorrect context parameter "'.$context.'" for has_capability(), object expected! This should be fixed in code.'); | |
369 | } | |
a8a7300a | 370 | } |
371 | ||
922633bd | 372 | /// Make sure we know the current context |
373 | if (empty($context)) { // Use default CONTEXT if none specified | |
374 | if (empty($CONTEXT)) { | |
375 | return false; | |
376 | } else { | |
377 | $context = $CONTEXT; | |
378 | } | |
379 | } else { // A context was given to us | |
380 | if (empty($CONTEXT)) { | |
381 | $CONTEXT = $context; // Store FIRST used context in this global as future default | |
382 | } | |
383 | } | |
384 | ||
385 | /// Check and return cache in case we've processed this one before. | |
8d2b18a8 | 386 | $requsteduser = empty($userid) ? $USER->id : $userid; // find out the requested user id, $USER->id might have been changed |
387 | $cachekey = $capability.'_'.$context->id.'_'.intval($requsteduser).'_'.intval($doanything); | |
caac8977 | 388 | |
922633bd | 389 | if (isset($capcache[$cachekey])) { |
390 | return $capcache[$cachekey]; | |
391 | } | |
392 | ||
20aeb4b8 | 393 | |
922633bd | 394 | /// Load up the capabilities list or item as necessary |
8d2b18a8 | 395 | if ($userid) { |
396 | if (empty($USER->id) or ($userid != $USER->id) or empty($USER->capabilities)) { | |
397 | // this is expensive | |
398 | $capabilities = load_user_capability($capability, $context, $userid); | |
399 | ||
400 | static $guestuserid = false; // cached guest user id | |
401 | if (!$guestuserid) { | |
402 | $guestuserid = get_field('user', 'id', 'username', 'guest'); | |
403 | } | |
404 | ||
405 | if ($userid == $guestuserid) { | |
406 | //this might be cached too, but should not needed | |
407 | $capabilities = load_guest_role($context, $capabilities); | |
408 | ||
409 | } else { | |
410 | static $defcaps = false; //cached default user caps - this might help cron | |
411 | if (empty($capcache) or !$defcaps) { //first run or capcache was reset | |
412 | $defcaps = load_defaultuser_role(true); | |
413 | } | |
414 | foreach($defcaps as $contextid=>$caps) {//apply only extra caps defined for default user | |
415 | foreach($caps as $cap=>$permission) { | |
416 | if (!isset($capabilities[$contextid][$cap])) { | |
417 | $capabilities[$contextid][$cap] = $permission; | |
418 | } | |
419 | } | |
420 | } | |
421 | } | |
422 | } else { //$USER->id == $userid and capabilities already present | |
423 | $capabilities = $USER->capabilities; | |
9425b25f | 424 | } |
8d2b18a8 | 425 | |
9425b25f | 426 | } else { // no userid |
8d2b18a8 | 427 | if (empty($USER->capabilities)) { |
428 | if (empty($USER->id)) { | |
429 | //not logged in user first time here | |
430 | load_notloggedin_role(); | |
431 | } else { | |
432 | // 'Simulated' user first time here - load_all_capabilities() not called from login/index.php | |
433 | load_all_capabilities(); // expensive - but we have to do it once anyway | |
434 | } | |
435 | } | |
436 | $capabilities = $USER->capabilities; | |
922633bd | 437 | $userid = $USER->id; |
98882637 | 438 | } |
9425b25f | 439 | |
caac8977 | 440 | /// We act a little differently when switchroles is active |
441 | ||
442 | $switchroleactive = false; // Assume it isn't active in this context | |
443 | ||
bbbf2d40 | 444 | |
922633bd | 445 | /// First deal with the "doanything" capability |
5fe9a11d | 446 | |
20aeb4b8 | 447 | if ($doanything) { |
2d07587b | 448 | |
f4e2d38a | 449 | /// First make sure that we aren't in a "switched role" |
450 | ||
f4e2d38a | 451 | if (!empty($USER->switchrole)) { // Switchrole is active somewhere! |
452 | if (!empty($USER->switchrole[$context->id])) { // Because of current context | |
453 | $switchroleactive = true; | |
454 | } else { // Check parent contexts | |
455 | if ($parentcontextids = get_parent_contexts($context)) { | |
456 | foreach ($parentcontextids as $parentcontextid) { | |
457 | if (!empty($USER->switchrole[$parentcontextid])) { // Yep, switchroles active here | |
458 | $switchroleactive = true; | |
459 | break; | |
460 | } | |
461 | } | |
462 | } | |
463 | } | |
464 | } | |
465 | ||
466 | /// Check the site context for doanything (most common) first | |
467 | ||
468 | if (empty($switchroleactive)) { // Ignore site setting if switchrole is active | |
21c9bace | 469 | $sitecontext = get_context_instance(CONTEXT_SYSTEM); |
2d07587b | 470 | if (isset($capabilities[$sitecontext->id]['moodle/site:doanything'])) { |
922633bd | 471 | $result = (0 < $capabilities[$sitecontext->id]['moodle/site:doanything']); |
472 | $capcache[$cachekey] = $result; | |
473 | return $result; | |
2d07587b | 474 | } |
20aeb4b8 | 475 | } |
40a2a15f | 476 | /// If it's not set at site level, it is possible to be set on other levels |
477 | /// Though this usage is not common and can cause risks | |
aad2ba95 | 478 | switch ($context->contextlevel) { |
eef868d1 | 479 | |
20aeb4b8 | 480 | case CONTEXT_COURSECAT: |
481 | // Check parent cats. | |
482 | $parentcats = get_parent_cats($context, CONTEXT_COURSECAT); | |
483 | foreach ($parentcats as $parentcat) { | |
484 | if (isset($capabilities[$parentcat]['moodle/site:doanything'])) { | |
922633bd | 485 | $result = (0 < $capabilities[$parentcat]['moodle/site:doanything']); |
486 | $capcache[$cachekey] = $result; | |
487 | return $result; | |
20aeb4b8 | 488 | } |
cee0901c | 489 | } |
20aeb4b8 | 490 | break; |
bbbf2d40 | 491 | |
20aeb4b8 | 492 | case CONTEXT_COURSE: |
493 | // Check parent cat. | |
494 | $parentcats = get_parent_cats($context, CONTEXT_COURSE); | |
98882637 | 495 | |
20aeb4b8 | 496 | foreach ($parentcats as $parentcat) { |
497 | if (isset($capabilities[$parentcat]['do_anything'])) { | |
922633bd | 498 | $result = (0 < $capabilities[$parentcat]['do_anything']); |
499 | $capcache[$cachekey] = $result; | |
500 | return $result; | |
20aeb4b8 | 501 | } |
9425b25f | 502 | } |
20aeb4b8 | 503 | break; |
bbbf2d40 | 504 | |
20aeb4b8 | 505 | case CONTEXT_GROUP: |
506 | // Find course. | |
f3f7610c ML |
507 | $courseid = groups_get_course($context->instanceid); |
508 | $courseinstance = get_context_instance(CONTEXT_COURSE, $courseid); | |
9425b25f | 509 | |
20aeb4b8 | 510 | $parentcats = get_parent_cats($courseinstance, CONTEXT_COURSE); |
511 | foreach ($parentcats as $parentcat) { | |
b4a1805a | 512 | if (isset($capabilities[$parentcat]['do_anything'])) { |
513 | $result = (0 < $capabilities[$parentcat]['do_anything']); | |
922633bd | 514 | $capcache[$cachekey] = $result; |
515 | return $result; | |
20aeb4b8 | 516 | } |
9425b25f | 517 | } |
9425b25f | 518 | |
20aeb4b8 | 519 | $coursecontext = ''; |
520 | if (isset($capabilities[$courseinstance->id]['do_anything'])) { | |
922633bd | 521 | $result = (0 < $capabilities[$courseinstance->id]['do_anything']); |
522 | $capcache[$cachekey] = $result; | |
523 | return $result; | |
20aeb4b8 | 524 | } |
9425b25f | 525 | |
20aeb4b8 | 526 | break; |
bbbf2d40 | 527 | |
20aeb4b8 | 528 | case CONTEXT_MODULE: |
529 | // Find course. | |
530 | $cm = get_record('course_modules', 'id', $context->instanceid); | |
531 | $courseinstance = get_context_instance(CONTEXT_COURSE, $cm->course); | |
9425b25f | 532 | |
20aeb4b8 | 533 | if ($parentcats = get_parent_cats($courseinstance, CONTEXT_COURSE)) { |
534 | foreach ($parentcats as $parentcat) { | |
535 | if (isset($capabilities[$parentcat]['do_anything'])) { | |
922633bd | 536 | $result = (0 < $capabilities[$parentcat]['do_anything']); |
537 | $capcache[$cachekey] = $result; | |
538 | return $result; | |
20aeb4b8 | 539 | } |
cee0901c | 540 | } |
9425b25f | 541 | } |
98882637 | 542 | |
20aeb4b8 | 543 | if (isset($capabilities[$courseinstance->id]['do_anything'])) { |
922633bd | 544 | $result = (0 < $capabilities[$courseinstance->id]['do_anything']); |
545 | $capcache[$cachekey] = $result; | |
546 | return $result; | |
20aeb4b8 | 547 | } |
bbbf2d40 | 548 | |
20aeb4b8 | 549 | break; |
bbbf2d40 | 550 | |
20aeb4b8 | 551 | case CONTEXT_BLOCK: |
2d95f702 | 552 | // not necessarily 1 to 1 to course. |
20aeb4b8 | 553 | $block = get_record('block_instance','id',$context->instanceid); |
2d95f702 | 554 | if ($block->pagetype == 'course-view') { |
555 | $courseinstance = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check | |
556 | $parentcats = get_parent_cats($courseinstance, CONTEXT_COURSE); | |
557 | ||
558 | foreach ($parentcats as $parentcat) { | |
559 | if (isset($capabilities[$parentcat]['do_anything'])) { | |
560 | $result = (0 < $capabilities[$parentcat]['do_anything']); | |
561 | $capcache[$cachekey] = $result; | |
562 | return $result; | |
563 | } | |
564 | } | |
565 | ||
566 | if (isset($capabilities[$courseinstance->id]['do_anything'])) { | |
567 | $result = (0 < $capabilities[$courseinstance->id]['do_anything']); | |
568 | $capcache[$cachekey] = $result; | |
569 | return $result; | |
570 | } | |
571 | } else { // if not course-view type of blocks, check site | |
572 | if (isset($capabilities[$sitecontext->id]['do_anything'])) { | |
573 | $result = (0 < $capabilities[$sitecontext->id]['do_anything']); | |
922633bd | 574 | $capcache[$cachekey] = $result; |
575 | return $result; | |
20aeb4b8 | 576 | } |
20aeb4b8 | 577 | } |
578 | break; | |
bbbf2d40 | 579 | |
20aeb4b8 | 580 | default: |
4b10f08b | 581 | // CONTEXT_SYSTEM: CONTEXT_PERSONAL: CONTEXT_USER: |
40a2a15f | 582 | // Do nothing, because the parents are site context |
583 | // which has been checked already | |
20aeb4b8 | 584 | break; |
585 | } | |
bbbf2d40 | 586 | |
20aeb4b8 | 587 | // Last: check self. |
588 | if (isset($capabilities[$context->id]['do_anything'])) { | |
922633bd | 589 | $result = (0 < $capabilities[$context->id]['do_anything']); |
590 | $capcache[$cachekey] = $result; | |
591 | return $result; | |
20aeb4b8 | 592 | } |
98882637 | 593 | } |
caac8977 | 594 | // do_anything has not been set, we now look for it the normal way. |
595 | $result = (0 < capability_search($capability, $context, $capabilities, $switchroleactive)); | |
922633bd | 596 | $capcache[$cachekey] = $result; |
597 | return $result; | |
bbbf2d40 | 598 | |
9425b25f | 599 | } |
bbbf2d40 | 600 | |
601 | ||
602 | /** | |
603 | * In a separate function so that we won't have to deal with do_anything. | |
40a2a15f | 604 | * again. Used by function has_capability(). |
bbbf2d40 | 605 | * @param $capability - capability string |
0468976c | 606 | * @param $context - the context object |
40a2a15f | 607 | * @param $capabilities - either $USER->capability or loaded array (for other users) |
bbbf2d40 | 608 | * @return permission (int) |
609 | */ | |
caac8977 | 610 | function capability_search($capability, $context, $capabilities, $switchroleactive=false) { |
759ac72d | 611 | |
bbbf2d40 | 612 | global $USER, $CFG; |
0468976c | 613 | |
11ac79ff | 614 | if (!isset($context->id)) { |
615 | return 0; | |
616 | } | |
40a2a15f | 617 | // if already set in the array explicitly, no need to look for it in parent |
618 | // context any longer | |
0468976c | 619 | if (isset($capabilities[$context->id][$capability])) { |
620 | return ($capabilities[$context->id][$capability]); | |
bbbf2d40 | 621 | } |
9425b25f | 622 | |
bbbf2d40 | 623 | /* Then, we check the cache recursively */ |
9425b25f | 624 | $permission = 0; |
625 | ||
aad2ba95 | 626 | switch ($context->contextlevel) { |
bbbf2d40 | 627 | |
628 | case CONTEXT_SYSTEM: // by now it's a definite an inherit | |
629 | $permission = 0; | |
630 | break; | |
631 | ||
632 | case CONTEXT_PERSONAL: | |
21c9bace | 633 | $parentcontext = get_context_instance(CONTEXT_SYSTEM); |
a2b6ee75 | 634 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
bbbf2d40 | 635 | break; |
9425b25f | 636 | |
4b10f08b | 637 | case CONTEXT_USER: |
21c9bace | 638 | $parentcontext = get_context_instance(CONTEXT_SYSTEM); |
a2b6ee75 | 639 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
bbbf2d40 | 640 | break; |
9425b25f | 641 | |
bbbf2d40 | 642 | case CONTEXT_COURSECAT: // Coursecat -> coursecat or site |
643 | $coursecat = get_record('course_categories','id',$context->instanceid); | |
0468976c | 644 | if (!empty($coursecat->parent)) { // return parent value if it exists |
645 | $parentcontext = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent); | |
bbbf2d40 | 646 | } else { // else return site value |
21c9bace | 647 | $parentcontext = get_context_instance(CONTEXT_SYSTEM); |
bbbf2d40 | 648 | } |
a2b6ee75 | 649 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
bbbf2d40 | 650 | break; |
651 | ||
652 | case CONTEXT_COURSE: // 1 to 1 to course cat | |
caac8977 | 653 | if (empty($switchroleactive)) { |
654 | // find the course cat, and return its value | |
655 | $course = get_record('course','id',$context->instanceid); | |
656 | if ($course->id == SITEID) { // In 1.8 we've separated site course and system | |
657 | $parentcontext = get_context_instance(CONTEXT_SYSTEM); | |
658 | } else { | |
659 | $parentcontext = get_context_instance(CONTEXT_COURSECAT, $course->category); | |
660 | } | |
a2b6ee75 | 661 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
40a2a15f | 662 | } |
bbbf2d40 | 663 | break; |
664 | ||
665 | case CONTEXT_GROUP: // 1 to 1 to course | |
f3f7610c ML |
666 | $courseid = groups_get_course($context->instanceid); |
667 | $parentcontext = get_context_instance(CONTEXT_COURSE, $courseid); | |
a2b6ee75 | 668 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
bbbf2d40 | 669 | break; |
670 | ||
671 | case CONTEXT_MODULE: // 1 to 1 to course | |
672 | $cm = get_record('course_modules','id',$context->instanceid); | |
0468976c | 673 | $parentcontext = get_context_instance(CONTEXT_COURSE, $cm->course); |
a2b6ee75 | 674 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
bbbf2d40 | 675 | break; |
676 | ||
2d95f702 | 677 | case CONTEXT_BLOCK: // not necessarily 1 to 1 to course |
bbbf2d40 | 678 | $block = get_record('block_instance','id',$context->instanceid); |
2d95f702 | 679 | if ($block->pagetype == 'course-view') { |
680 | $parentcontext = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check | |
681 | } else { | |
682 | $parentcontext = get_context_instance(CONTEXT_SYSTEM); | |
683 | } | |
a2b6ee75 | 684 | $permission = capability_search($capability, $parentcontext, $capabilities, $switchroleactive); |
bbbf2d40 | 685 | break; |
686 | ||
687 | default: | |
688 | error ('This is an unknown context!'); | |
689 | return false; | |
690 | } | |
9425b25f | 691 | |
98882637 | 692 | return $permission; |
bbbf2d40 | 693 | } |
694 | ||
40a2a15f | 695 | /** |
696 | * auxillary function for load_user_capabilities() | |
697 | * checks if context c1 is a parent (or itself) of context c2 | |
698 | * @param int $c1 - context id of context 1 | |
699 | * @param int $c2 - context id of context 2 | |
700 | * @return bool | |
701 | */ | |
9fccc080 | 702 | function is_parent_context($c1, $c2) { |
703 | static $parentsarray; | |
704 | ||
705 | // context can be itself and this is ok | |
706 | if ($c1 == $c2) { | |
707 | return true; | |
708 | } | |
709 | // hit in cache? | |
710 | if (isset($parentsarray[$c1][$c2])) { | |
711 | return $parentsarray[$c1][$c2]; | |
712 | } | |
713 | ||
714 | if (!$co2 = get_record('context', 'id', $c2)) { | |
715 | return false; | |
716 | } | |
717 | ||
718 | if (!$parents = get_parent_contexts($co2)) { | |
719 | return false; | |
720 | } | |
721 | ||
722 | foreach ($parents as $parent) { | |
723 | $parentsarray[$parent][$c2] = true; | |
724 | } | |
725 | ||
726 | if (in_array($c1, $parents)) { | |
727 | return true; | |
728 | } else { // else not a parent, set the cache anyway | |
729 | $parentsarray[$c1][$c2] = false; | |
730 | return false; | |
731 | } | |
732 | } | |
733 | ||
734 | ||
735 | /* | |
736 | * auxillary function for load_user_capabilities() | |
737 | * handler in usort() to sort contexts according to level | |
40a2a15f | 738 | * @param object contexta |
739 | * @param object contextb | |
740 | * @return int | |
9fccc080 | 741 | */ |
742 | function roles_context_cmp($contexta, $contextb) { | |
743 | if ($contexta->contextlevel == $contextb->contextlevel) { | |
744 | return 0; | |
745 | } | |
746 | return ($contexta->contextlevel < $contextb->contextlevel) ? -1 : 1; | |
747 | } | |
748 | ||
bbbf2d40 | 749 | /** |
bbbf2d40 | 750 | * It will build an array of all the capabilities at each level |
751 | * i.e. site/metacourse/course_category/course/moduleinstance | |
752 | * Note we should only load capabilities if they are explicitly assigned already, | |
753 | * we should not load all module's capability! | |
21c9bace | 754 | * |
bbbf2d40 | 755 | * [Capabilities] => [26][forum_post] = 1 |
756 | * [26][forum_start] = -8990 | |
757 | * [26][forum_edit] = -1 | |
758 | * [273][blah blah] = 1 | |
759 | * [273][blah blah blah] = 2 | |
21c9bace | 760 | * |
761 | * @param $capability string - Only get a specific capability (string) | |
762 | * @param $context object - Only get capabilities for a specific context object | |
763 | * @param $userid integer - the id of the user whose capabilities we want to load | |
764 | * @return array of permissions (or nothing if they get assigned to $USER) | |
bbbf2d40 | 765 | */ |
21c9bace | 766 | function load_user_capability($capability='', $context = NULL, $userid='') { |
d140ad3f | 767 | |
98882637 | 768 | global $USER, $CFG; |
55526eee | 769 | |
40a2a15f | 770 | // this flag has not been set! |
771 | // (not clean install, or upgraded successfully to 1.7 and up) | |
2f1a4248 | 772 | if (empty($CFG->rolesactive)) { |
773 | return false; | |
774 | } | |
775 | ||
bbbf2d40 | 776 | if (empty($userid)) { |
dc411d1b | 777 | if (empty($USER->id)) { // We have no user to get capabilities for |
64026e8c | 778 | debugging('User not logged in for load_user_capability!'); |
dc411d1b | 779 | return false; |
780 | } | |
64026e8c | 781 | unset($USER->capabilities); // We don't want possible older capabilites hanging around |
782 | ||
783 | check_enrolment_plugins($USER); // Call "enrol" system to ensure that we have the correct picture | |
8f8ed475 | 784 | |
bbbf2d40 | 785 | $userid = $USER->id; |
dc411d1b | 786 | $otheruserid = false; |
bbbf2d40 | 787 | } else { |
64026e8c | 788 | if (!$user = get_record('user', 'id', $userid)) { |
789 | debugging('Non-existent userid in load_user_capability!'); | |
790 | return false; | |
791 | } | |
792 | ||
793 | check_enrolment_plugins($user); // Ensure that we have the correct picture | |
794 | ||
9425b25f | 795 | $otheruserid = $userid; |
bbbf2d40 | 796 | } |
9425b25f | 797 | |
5f70bcc3 | 798 | |
799 | /// First we generate a list of all relevant contexts of the user | |
800 | ||
801 | $usercontexts = array(); | |
bbbf2d40 | 802 | |
0468976c | 803 | if ($context) { // if context is specified |
eef868d1 | 804 | $usercontexts = get_parent_contexts($context); |
9343a733 | 805 | $usercontexts[] = $context->id; // Add the current context as well |
98882637 | 806 | } else { // else, we load everything |
5f70bcc3 | 807 | if ($userroles = get_records('role_assignments','userid',$userid)) { |
808 | foreach ($userroles as $userrole) { | |
0db6adc9 | 809 | if (!in_array($userrole->contextid, $usercontexts)) { |
810 | $usercontexts[] = $userrole->contextid; | |
811 | } | |
5f70bcc3 | 812 | } |
98882637 | 813 | } |
5f70bcc3 | 814 | } |
815 | ||
816 | /// Set up SQL fragments for searching contexts | |
817 | ||
818 | if ($usercontexts) { | |
0468976c | 819 | $listofcontexts = '('.implode(',', $usercontexts).')'; |
5f70bcc3 | 820 | $searchcontexts1 = "c1.id IN $listofcontexts AND"; |
5f70bcc3 | 821 | } else { |
c76e095f | 822 | $searchcontexts1 = ''; |
bbbf2d40 | 823 | } |
3ca2dea5 | 824 | |
64026e8c | 825 | if ($capability) { |
826 | $capsearch = " AND rc.capability = '$capability' "; | |
827 | } else { | |
eef868d1 | 828 | $capsearch =""; |
64026e8c | 829 | } |
830 | ||
e38f38c3 | 831 | /// Set up SQL fragments for timestart, timeend etc |
832 | $now = time(); | |
85f101fa | 833 | $timesql = "AND ((ra.timestart = 0 OR ra.timestart < $now) AND (ra.timeend = 0 OR ra.timeend > $now))"; |
e38f38c3 | 834 | |
5f70bcc3 | 835 | /// Then we use 1 giant SQL to bring out all relevant capabilities. |
836 | /// The first part gets the capabilities of orginal role. | |
837 | /// The second part gets the capabilities of overriden roles. | |
bbbf2d40 | 838 | |
21c9bace | 839 | $siteinstance = get_context_instance(CONTEXT_SYSTEM); |
9fccc080 | 840 | $capabilities = array(); // Reinitialize. |
841 | ||
842 | // SQL for normal capabilities | |
843 | $SQL1 = "SELECT rc.capability, c1.id as id1, c1.id as id2, (c1.contextlevel * 100) AS aggrlevel, | |
bbbf2d40 | 844 | SUM(rc.permission) AS sum |
845 | FROM | |
eef868d1 | 846 | {$CFG->prefix}role_assignments ra, |
42ac3ecf | 847 | {$CFG->prefix}role_capabilities rc, |
848 | {$CFG->prefix}context c1 | |
bbbf2d40 | 849 | WHERE |
d4649c76 | 850 | ra.contextid=c1.id AND |
851 | ra.roleid=rc.roleid AND | |
bbbf2d40 | 852 | ra.userid=$userid AND |
5f70bcc3 | 853 | $searchcontexts1 |
eef868d1 | 854 | rc.contextid=$siteinstance->id |
98882637 | 855 | $capsearch |
e38f38c3 | 856 | $timesql |
bbbf2d40 | 857 | GROUP BY |
55526eee | 858 | rc.capability, c1.id, c1.contextlevel * 100 |
bbbf2d40 | 859 | HAVING |
9fccc080 | 860 | SUM(rc.permission) != 0 |
0db6adc9 | 861 | |
862 | UNION ALL | |
863 | ||
864 | SELECT rc.capability, c1.id as id1, c2.id as id2, (c1.contextlevel * 100 + c2.contextlevel) AS aggrlevel, | |
865 | SUM(rc.permission) AS sum | |
866 | FROM | |
867 | {$CFG->prefix}role_assignments ra LEFT JOIN | |
868 | {$CFG->prefix}role_capabilities rc on ra.roleid = rc.roleid LEFT JOIN | |
869 | {$CFG->prefix}context c1 on ra.contextid = c1.id LEFT JOIN | |
870 | {$CFG->prefix}context c2 on rc.contextid = c2.id LEFT JOIN | |
871 | {$CFG->prefix}context_rel cr on cr.c1 = c2.id | |
872 | WHERE | |
873 | ra.userid=$userid AND | |
874 | $searchcontexts1 | |
875 | rc.contextid != $siteinstance->id | |
876 | $capsearch | |
877 | $timesql | |
878 | AND cr.c2 = c1.id | |
879 | GROUP BY | |
55526eee | 880 | rc.capability, c1.id, c2.id, c1.contextlevel * 100 + c2.contextlevel |
0db6adc9 | 881 | HAVING |
882 | SUM(rc.permission) != 0 | |
9fccc080 | 883 | ORDER BY |
884 | aggrlevel ASC"; | |
0db6adc9 | 885 | |
9fccc080 | 886 | if (!$rs = get_recordset_sql($SQL1)) { |
887 | error("Query failed in load_user_capability."); | |
888 | } | |
bbbf2d40 | 889 | |
9fccc080 | 890 | if ($rs && $rs->RecordCount() > 0) { |
bcf88cbb | 891 | while ($caprec = rs_fetch_next_record($rs)) { |
892 | $array = (array)$caprec; | |
9fccc080 | 893 | $temprecord = new object; |
894 | ||
895 | foreach ($array as $key=>$val) { | |
896 | if ($key == 'aggrlevel') { | |
897 | $temprecord->contextlevel = $val; | |
898 | } else { | |
899 | $temprecord->{$key} = $val; | |
900 | } | |
901 | } | |
9fccc080 | 902 | $capabilities[] = $temprecord; |
9fccc080 | 903 | } |
bcf88cbb | 904 | rs_close($rs); |
b7e40271 | 905 | } |
bcf88cbb | 906 | |
9fccc080 | 907 | // SQL for overrides |
908 | // this is take out because we have no way of making sure c1 is indeed related to c2 (parent) | |
909 | // if we do not group by sum, it is possible to have multiple records of rc.capability, c1.id, c2.id, tuple having | |
910 | // different values, we can maually sum it when we go through the list | |
0db6adc9 | 911 | |
912 | /* | |
913 | ||
9fccc080 | 914 | $SQL2 = "SELECT rc.capability, c1.id as id1, c2.id as id2, (c1.contextlevel * 100 + c2.contextlevel) AS aggrlevel, |
915 | rc.permission AS sum | |
bbbf2d40 | 916 | FROM |
42ac3ecf | 917 | {$CFG->prefix}role_assignments ra, |
918 | {$CFG->prefix}role_capabilities rc, | |
919 | {$CFG->prefix}context c1, | |
920 | {$CFG->prefix}context c2 | |
bbbf2d40 | 921 | WHERE |
d4649c76 | 922 | ra.contextid=c1.id AND |
eef868d1 | 923 | ra.roleid=rc.roleid AND |
924 | ra.userid=$userid AND | |
925 | rc.contextid=c2.id AND | |
5f70bcc3 | 926 | $searchcontexts1 |
5f70bcc3 | 927 | rc.contextid != $siteinstance->id |
bbbf2d40 | 928 | $capsearch |
e38f38c3 | 929 | $timesql |
eef868d1 | 930 | |
bbbf2d40 | 931 | GROUP BY |
21c9bace | 932 | rc.capability, (c1.contextlevel * 100 + c2.contextlevel), c1.id, c2.id, rc.permission |
bbbf2d40 | 933 | ORDER BY |
75e84883 | 934 | aggrlevel ASC |
0db6adc9 | 935 | ";*/ |
9fccc080 | 936 | |
0db6adc9 | 937 | /* |
9fccc080 | 938 | if (!$rs = get_recordset_sql($SQL2)) { |
75e84883 | 939 | error("Query failed in load_user_capability."); |
940 | } | |
5cf38a57 | 941 | |
bbbf2d40 | 942 | if ($rs && $rs->RecordCount() > 0) { |
bcf88cbb | 943 | while ($caprec = rs_fetch_next_record($rs)) { |
944 | $array = (array)$caprec; | |
75e84883 | 945 | $temprecord = new object; |
eef868d1 | 946 | |
98882637 | 947 | foreach ($array as $key=>$val) { |
75e84883 | 948 | if ($key == 'aggrlevel') { |
aad2ba95 | 949 | $temprecord->contextlevel = $val; |
75e84883 | 950 | } else { |
951 | $temprecord->{$key} = $val; | |
952 | } | |
98882637 | 953 | } |
9fccc080 | 954 | // for overrides, we have to make sure that context2 is a child of context1 |
955 | // otherwise the combination makes no sense | |
0db6adc9 | 956 | //if (is_parent_context($temprecord->id1, $temprecord->id2)) { |
9fccc080 | 957 | $capabilities[] = $temprecord; |
0db6adc9 | 958 | //} // only write if relevant |
bbbf2d40 | 959 | } |
bcf88cbb | 960 | rs_close($rs); |
bbbf2d40 | 961 | } |
0db6adc9 | 962 | |
9fccc080 | 963 | // this step sorts capabilities according to the contextlevel |
964 | // it is very important because the order matters when we | |
965 | // go through each capabilities later. (i.e. higher level contextlevel | |
966 | // will override lower contextlevel settings | |
967 | usort($capabilities, 'roles_context_cmp'); | |
0db6adc9 | 968 | */ |
bbbf2d40 | 969 | /* so up to this point we should have somethign like this |
aad2ba95 | 970 | * $capabilities[1] ->contextlevel = 1000 |
8ba412da | 971 | ->module = 0 // changed from SITEID in 1.8 (??) |
bbbf2d40 | 972 | ->capability = do_anything |
973 | ->id = 1 (id is the context id) | |
974 | ->sum = 0 | |
eef868d1 | 975 | |
aad2ba95 | 976 | * $capabilities[2] ->contextlevel = 1000 |
8ba412da | 977 | ->module = 0 // changed from SITEID in 1.8 (??) |
bbbf2d40 | 978 | ->capability = post_messages |
979 | ->id = 1 | |
980 | ->sum = -9000 | |
981 | ||
aad2ba95 | 982 | * $capabilittes[3] ->contextlevel = 3000 |
bbbf2d40 | 983 | ->module = course |
984 | ->capability = view_course_activities | |
985 | ->id = 25 | |
986 | ->sum = 1 | |
987 | ||
aad2ba95 | 988 | * $capabilittes[4] ->contextlevel = 3000 |
bbbf2d40 | 989 | ->module = course |
990 | ->capability = view_course_activities | |
991 | ->id = 26 | |
992 | ->sum = 0 (this is another course) | |
eef868d1 | 993 | |
aad2ba95 | 994 | * $capabilities[5] ->contextlevel = 3050 |
bbbf2d40 | 995 | ->module = course |
996 | ->capability = view_course_activities | |
997 | ->id = 25 (override in course 25) | |
998 | ->sum = -1 | |
999 | * .... | |
1000 | * now we proceed to write the session array, going from top to bottom | |
1001 | * at anypoint, we need to go up and check parent to look for prohibit | |
1002 | */ | |
1003 | // print_object($capabilities); | |
1004 | ||
1005 | /* This is where we write to the actualy capabilities array | |
1006 | * what we need to do from here on is | |
1007 | * going down the array from lowest level to highest level | |
1008 | * 1) recursively check for prohibit, | |
1009 | * if any, we write prohibit | |
1010 | * else, we write the value | |
1011 | * 2) at an override level, we overwrite current level | |
1012 | * if it's not set to prohibit already, and if different | |
1013 | * ........ that should be it ........ | |
1014 | */ | |
efb58884 | 1015 | |
1016 | // This is the flag used for detecting the current context level. Since we are going through | |
1017 | // the array in ascending order of context level. For normal capabilities, there should only | |
1018 | // be 1 value per (capability, contextlevel, context), because they are already summed. But, | |
1019 | // for overrides, since we are processing them separate, we need to sum the relevcant entries. | |
1020 | // We set this flag when we hit a new level. | |
1021 | // If the flag is already set, we keep adding (summing), otherwise, we just override previous | |
1022 | // settings (from lower level contexts) | |
1023 | $capflags = array(); // (contextid, contextlevel, capability) | |
98882637 | 1024 | $usercap = array(); // for other user's capabilities |
bbbf2d40 | 1025 | foreach ($capabilities as $capability) { |
1026 | ||
9fccc080 | 1027 | if (!$context = get_context_instance_by_id($capability->id2)) { |
7bfa3101 | 1028 | continue; // incorrect stale context |
1029 | } | |
0468976c | 1030 | |
41811960 | 1031 | if (!empty($otheruserid)) { // we are pulling out other user's capabilities, do not write to session |
eef868d1 | 1032 | |
0468976c | 1033 | if (capability_prohibits($capability->capability, $context, $capability->sum, $usercap)) { |
9fccc080 | 1034 | $usercap[$capability->id2][$capability->capability] = CAP_PROHIBIT; |
98882637 | 1035 | continue; |
1036 | } | |
efb58884 | 1037 | if (isset($usercap[$capability->id2][$capability->capability])) { // use isset because it can be sum 0 |
1038 | if (!empty($capflags[$capability->id2][$capability->contextlevel][$capability->capability])) { | |
1039 | $usercap[$capability->id2][$capability->capability] += $capability->sum; | |
1040 | } else { // else we override, and update flag | |
1041 | $usercap[$capability->id2][$capability->capability] = $capability->sum; | |
1042 | $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; | |
1043 | } | |
9fccc080 | 1044 | } else { |
1045 | $usercap[$capability->id2][$capability->capability] = $capability->sum; | |
efb58884 | 1046 | $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; |
9fccc080 | 1047 | } |
eef868d1 | 1048 | |
98882637 | 1049 | } else { |
1050 | ||
0468976c | 1051 | if (capability_prohibits($capability->capability, $context, $capability->sum)) { // if any parent or parent's parent is set to prohibit |
9fccc080 | 1052 | $USER->capabilities[$capability->id2][$capability->capability] = CAP_PROHIBIT; |
98882637 | 1053 | continue; |
1054 | } | |
eef868d1 | 1055 | |
98882637 | 1056 | // if no parental prohibit set |
1057 | // just write to session, i am not sure this is correct yet | |
1058 | // since 3050 shows up after 3000, and 3070 shows up after 3050, | |
1059 | // it should be ok just to overwrite like this, provided that there's no | |
1060 | // parental prohibits | |
98882637 | 1061 | // we need to write even if it's 0, because it could be an inherit override |
efb58884 | 1062 | if (isset($USER->capabilities[$capability->id2][$capability->capability])) { |
1063 | if (!empty($capflags[$capability->id2][$capability->contextlevel][$capability->capability])) { | |
1064 | $USER->capabilities[$capability->id2][$capability->capability] += $capability->sum; | |
1065 | } else { // else we override, and update flag | |
1066 | $USER->capabilities[$capability->id2][$capability->capability] = $capability->sum; | |
1067 | $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; | |
1068 | } | |
9fccc080 | 1069 | } else { |
1070 | $USER->capabilities[$capability->id2][$capability->capability] = $capability->sum; | |
efb58884 | 1071 | $capflags[$capability->id2][$capability->contextlevel][$capability->capability] = true; |
9fccc080 | 1072 | } |
98882637 | 1073 | } |
bbbf2d40 | 1074 | } |
eef868d1 | 1075 | |
bbbf2d40 | 1076 | // now we don't care about the huge array anymore, we can dispose it. |
1077 | unset($capabilities); | |
efb58884 | 1078 | unset($capflags); |
eef868d1 | 1079 | |
dbe7e582 | 1080 | if (!empty($otheruserid)) { |
eef868d1 | 1081 | return $usercap; // return the array |
bbbf2d40 | 1082 | } |
2f1a4248 | 1083 | } |
1084 | ||
1085 | ||
1086 | /* | |
1087 | * A convenience function to completely load all the capabilities | |
1088 | * for the current user. This is what gets called from login, for example. | |
1089 | */ | |
1090 | function load_all_capabilities() { | |
1091 | global $USER; | |
1092 | ||
1093 | if (empty($USER->username)) { | |
1094 | return; | |
1095 | } | |
bbbf2d40 | 1096 | |
8e82745a | 1097 | unset($USER->mycourses); // Reset a cache used by get_my_courses |
1098 | ||
2f1a4248 | 1099 | load_user_capability(); // Load basic capabilities assigned to this user |
1100 | ||
1101 | if ($USER->username == 'guest') { | |
1102 | load_guest_role(); // All non-guest users get this by default | |
1103 | } else { | |
1104 | load_defaultuser_role(); // All non-guest users get this by default | |
1105 | } | |
bbbf2d40 | 1106 | } |
1107 | ||
2f1a4248 | 1108 | |
64026e8c | 1109 | /* |
1110 | * Check all the login enrolment information for the given user object | |
eef868d1 | 1111 | * by querying the enrolment plugins |
64026e8c | 1112 | */ |
1113 | function check_enrolment_plugins(&$user) { | |
1114 | global $CFG; | |
1115 | ||
e4ec4e41 | 1116 | static $inprogress; // To prevent this function being called more than once in an invocation |
1117 | ||
218eb651 | 1118 | if (!empty($inprogress[$user->id])) { |
e4ec4e41 | 1119 | return; |
1120 | } | |
1121 | ||
218eb651 | 1122 | $inprogress[$user->id] = true; // Set the flag |
e4ec4e41 | 1123 | |
64026e8c | 1124 | require_once($CFG->dirroot .'/enrol/enrol.class.php'); |
eef868d1 | 1125 | |
64026e8c | 1126 | if (!($plugins = explode(',', $CFG->enrol_plugins_enabled))) { |
1127 | $plugins = array($CFG->enrol); | |
1128 | } | |
1129 | ||
1130 | foreach ($plugins as $plugin) { | |
1131 | $enrol = enrolment_factory::factory($plugin); | |
1132 | if (method_exists($enrol, 'setup_enrolments')) { /// Plugin supports Roles (Moodle 1.7 and later) | |
1133 | $enrol->setup_enrolments($user); | |
1134 | } else { /// Run legacy enrolment methods | |
1135 | if (method_exists($enrol, 'get_student_courses')) { | |
1136 | $enrol->get_student_courses($user); | |
1137 | } | |
1138 | if (method_exists($enrol, 'get_teacher_courses')) { | |
1139 | $enrol->get_teacher_courses($user); | |
1140 | } | |
1141 | ||
1142 | /// deal with $user->students and $user->teachers stuff | |
1143 | unset($user->student); | |
1144 | unset($user->teacher); | |
1145 | } | |
1146 | unset($enrol); | |
1147 | } | |
e4ec4e41 | 1148 | |
218eb651 | 1149 | unset($inprogress[$user->id]); // Unset the flag |
64026e8c | 1150 | } |
1151 | ||
bbbf2d40 | 1152 | |
1153 | /** | |
1154 | * This is a recursive function that checks whether the capability in this | |
1155 | * context, or the parent capabilities are set to prohibit. | |
1156 | * | |
1157 | * At this point, we can probably just use the values already set in the | |
1158 | * session variable, since we are going down the level. Any prohit set in | |
1159 | * parents would already reflect in the session. | |
1160 | * | |
1161 | * @param $capability - capability name | |
1162 | * @param $sum - sum of all capabilities values | |
0468976c | 1163 | * @param $context - the context object |
bbbf2d40 | 1164 | * @param $array - when loading another user caps, their caps are not stored in session but an array |
1165 | */ | |
0468976c | 1166 | function capability_prohibits($capability, $context, $sum='', $array='') { |
bbbf2d40 | 1167 | global $USER; |
0468976c | 1168 | |
0db6adc9 | 1169 | // caching, mainly to save unnecessary sqls |
1170 | static $prohibits; //[capability][contextid] | |
1171 | if (isset($prohibits[$capability][$context->id])) { | |
1172 | return $prohibits[$capability][$context->id]; | |
1173 | } | |
1174 | ||
2176adf1 | 1175 | if (empty($context->id)) { |
0db6adc9 | 1176 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1177 | return false; |
1178 | } | |
1179 | ||
1180 | if (empty($capability)) { | |
0db6adc9 | 1181 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1182 | return false; |
1183 | } | |
1184 | ||
819e5a70 | 1185 | if ($sum < (CAP_PROHIBIT/2)) { |
bbbf2d40 | 1186 | // If this capability is set to prohibit. |
0db6adc9 | 1187 | $prohibits[$capability][$context->id] = true; |
bbbf2d40 | 1188 | return true; |
1189 | } | |
eef868d1 | 1190 | |
819e5a70 | 1191 | if (!empty($array)) { |
eef868d1 | 1192 | if (isset($array[$context->id][$capability]) |
819e5a70 | 1193 | && $array[$context->id][$capability] < (CAP_PROHIBIT/2)) { |
0db6adc9 | 1194 | $prohibits[$capability][$context->id] = true; |
98882637 | 1195 | return true; |
eef868d1 | 1196 | } |
bbbf2d40 | 1197 | } else { |
98882637 | 1198 | // Else if set in session. |
eef868d1 | 1199 | if (isset($USER->capabilities[$context->id][$capability]) |
819e5a70 | 1200 | && $USER->capabilities[$context->id][$capability] < (CAP_PROHIBIT/2)) { |
0db6adc9 | 1201 | $prohibits[$capability][$context->id] = true; |
98882637 | 1202 | return true; |
1203 | } | |
bbbf2d40 | 1204 | } |
aad2ba95 | 1205 | switch ($context->contextlevel) { |
eef868d1 | 1206 | |
bbbf2d40 | 1207 | case CONTEXT_SYSTEM: |
1208 | // By now it's a definite an inherit. | |
1209 | return 0; | |
1210 | break; | |
1211 | ||
1212 | case CONTEXT_PERSONAL: | |
2176adf1 | 1213 | $parent = get_context_instance(CONTEXT_SYSTEM); |
0db6adc9 | 1214 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1215 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1216 | break; |
1217 | ||
4b10f08b | 1218 | case CONTEXT_USER: |
2176adf1 | 1219 | $parent = get_context_instance(CONTEXT_SYSTEM); |
0db6adc9 | 1220 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1221 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1222 | break; |
1223 | ||
1224 | case CONTEXT_COURSECAT: | |
1225 | // Coursecat -> coursecat or site. | |
2176adf1 | 1226 | if (!$coursecat = get_record('course_categories','id',$context->instanceid)) { |
0db6adc9 | 1227 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1228 | return false; |
40a2a15f | 1229 | } |
41811960 | 1230 | if (!empty($coursecat->parent)) { |
bbbf2d40 | 1231 | // return parent value if exist. |
1232 | $parent = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent); | |
1233 | } else { | |
1234 | // Return site value. | |
2176adf1 | 1235 | $parent = get_context_instance(CONTEXT_SYSTEM); |
bbbf2d40 | 1236 | } |
0db6adc9 | 1237 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1238 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1239 | break; |
1240 | ||
1241 | case CONTEXT_COURSE: | |
1242 | // 1 to 1 to course cat. | |
1243 | // Find the course cat, and return its value. | |
2176adf1 | 1244 | if (!$course = get_record('course','id',$context->instanceid)) { |
0db6adc9 | 1245 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1246 | return false; |
1247 | } | |
40a2a15f | 1248 | // Yu: Separating site and site course context |
1249 | if ($course->id == SITEID) { | |
1250 | $parent = get_context_instance(CONTEXT_SYSTEM); | |
1251 | } else { | |
1252 | $parent = get_context_instance(CONTEXT_COURSECAT, $course->category); | |
1253 | } | |
0db6adc9 | 1254 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1255 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1256 | break; |
1257 | ||
1258 | case CONTEXT_GROUP: | |
1259 | // 1 to 1 to course. | |
f3f7610c | 1260 | if (!$courseid = groups_get_course($context->instanceid)) { |
0db6adc9 | 1261 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1262 | return false; |
1263 | } | |
f3f7610c | 1264 | $parent = get_context_instance(CONTEXT_COURSE, $courseid); |
0db6adc9 | 1265 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1266 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1267 | break; |
1268 | ||
1269 | case CONTEXT_MODULE: | |
1270 | // 1 to 1 to course. | |
2176adf1 | 1271 | if (!$cm = get_record('course_modules','id',$context->instanceid)) { |
0db6adc9 | 1272 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1273 | return false; |
1274 | } | |
bbbf2d40 | 1275 | $parent = get_context_instance(CONTEXT_COURSE, $cm->course); |
0db6adc9 | 1276 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1277 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1278 | break; |
1279 | ||
1280 | case CONTEXT_BLOCK: | |
1281 | // 1 to 1 to course. | |
2176adf1 | 1282 | if (!$block = get_record('block_instance','id',$context->instanceid)) { |
0db6adc9 | 1283 | $prohibits[$capability][$context->id] = false; |
2176adf1 | 1284 | return false; |
1285 | } | |
bbbf2d40 | 1286 | $parent = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check |
0db6adc9 | 1287 | $prohibits[$capability][$context->id] = capability_prohibits($capability, $parent); |
1288 | return $prohibits[$capability][$context->id]; | |
bbbf2d40 | 1289 | break; |
1290 | ||
1291 | default: | |
2176adf1 | 1292 | print_error('unknowncontext'); |
1293 | return false; | |
bbbf2d40 | 1294 | } |
1295 | } | |
1296 | ||
1297 | ||
1298 | /** | |
1299 | * A print form function. This should either grab all the capabilities from | |
1300 | * files or a central table for that particular module instance, then present | |
1301 | * them in check boxes. Only relevant capabilities should print for known | |
1302 | * context. | |
1303 | * @param $mod - module id of the mod | |
1304 | */ | |
1305 | function print_capabilities($modid=0) { | |
1306 | global $CFG; | |
eef868d1 | 1307 | |
bbbf2d40 | 1308 | $capabilities = array(); |
1309 | ||
1310 | if ($modid) { | |
1311 | // We are in a module specific context. | |
1312 | ||
1313 | // Get the mod's name. | |
1314 | // Call the function that grabs the file and parse. | |
1315 | $cm = get_record('course_modules', 'id', $modid); | |
1316 | $module = get_record('modules', 'id', $cm->module); | |
eef868d1 | 1317 | |
bbbf2d40 | 1318 | } else { |
1319 | // Print all capabilities. | |
1320 | foreach ($capabilities as $capability) { | |
1321 | // Prints the check box component. | |
1322 | } | |
1323 | } | |
1324 | } | |
1325 | ||
1326 | ||
1327 | /** | |
1afecc03 | 1328 | * Installs the roles system. |
1329 | * This function runs on a fresh install as well as on an upgrade from the old | |
1330 | * hard-coded student/teacher/admin etc. roles to the new roles system. | |
bbbf2d40 | 1331 | */ |
1afecc03 | 1332 | function moodle_install_roles() { |
bbbf2d40 | 1333 | |
1afecc03 | 1334 | global $CFG, $db; |
eef868d1 | 1335 | |
459c1ff1 | 1336 | /// Create a system wide context for assignemnt. |
21c9bace | 1337 | $systemcontext = $context = get_context_instance(CONTEXT_SYSTEM); |
bbbf2d40 | 1338 | |
1afecc03 | 1339 | |
459c1ff1 | 1340 | /// Create default/legacy roles and capabilities. |
1341 | /// (1 legacy capability per legacy role at system level). | |
1342 | ||
69aaada0 | 1343 | $adminrole = create_role(addslashes(get_string('administrator')), 'admin', |
1344 | addslashes(get_string('administratordescription')), 'moodle/legacy:admin'); | |
1345 | $coursecreatorrole = create_role(addslashes(get_string('coursecreators')), 'coursecreator', | |
1346 | addslashes(get_string('coursecreatorsdescription')), 'moodle/legacy:coursecreator'); | |
1347 | $editteacherrole = create_role(addslashes(get_string('defaultcourseteacher')), 'editingteacher', | |
1348 | addslashes(get_string('defaultcourseteacherdescription')), 'moodle/legacy:editingteacher'); | |
1349 | $noneditteacherrole = create_role(addslashes(get_string('noneditingteacher')), 'teacher', | |
1350 | addslashes(get_string('noneditingteacherdescription')), 'moodle/legacy:teacher'); | |
1351 | $studentrole = create_role(addslashes(get_string('defaultcoursestudent')), 'student', | |
1352 | addslashes(get_string('defaultcoursestudentdescription')), 'moodle/legacy:student'); | |
1353 | $guestrole = create_role(addslashes(get_string('guest')), 'guest', | |
1354 | addslashes(get_string('guestdescription')), 'moodle/legacy:guest'); | |
c785d40a | 1355 | $userrole = create_role(addslashes(get_string('authenticateduser')), 'user', |
1356 | addslashes(get_string('authenticateduserdescription')), 'moodle/legacy:user'); | |
2851ba9b | 1357 | |
17e5635c | 1358 | /// Now is the correct moment to install capabilities - after creation of legacy roles, but before assigning of roles |
459c1ff1 | 1359 | |
98882637 | 1360 | if (!assign_capability('moodle/site:doanything', CAP_ALLOW, $adminrole, $systemcontext->id)) { |
bbbf2d40 | 1361 | error('Could not assign moodle/site:doanything to the admin role'); |
1362 | } | |
250934b8 | 1363 | if (!update_capabilities()) { |
1364 | error('Had trouble upgrading the core capabilities for the Roles System'); | |
1365 | } | |
1afecc03 | 1366 | |
459c1ff1 | 1367 | /// Look inside user_admin, user_creator, user_teachers, user_students and |
1368 | /// assign above new roles. If a user has both teacher and student role, | |
1369 | /// only teacher role is assigned. The assignment should be system level. | |
1370 | ||
1afecc03 | 1371 | $dbtables = $db->MetaTables('TABLES'); |
eef868d1 | 1372 | |
72da5046 | 1373 | /// Set up the progress bar |
1374 | ||
1375 | $usertables = array('user_admins', 'user_coursecreators', 'user_teachers', 'user_students'); | |
1376 | ||
1377 | $totalcount = $progresscount = 0; | |
1378 | foreach ($usertables as $usertable) { | |
1379 | if (in_array($CFG->prefix.$usertable, $dbtables)) { | |
1380 | $totalcount += count_records($usertable); | |
1381 | } | |
1382 | } | |
1383 | ||
aae37b63 | 1384 | print_progress(0, $totalcount, 5, 1, 'Processing role assignments'); |
1afecc03 | 1385 | |
459c1ff1 | 1386 | /// Upgrade the admins. |
1387 | /// Sort using id ASC, first one is primary admin. | |
1388 | ||
1afecc03 | 1389 | if (in_array($CFG->prefix.'user_admins', $dbtables)) { |
f1dcf000 | 1390 | if ($rs = get_recordset_sql('SELECT * from '.$CFG->prefix.'user_admins ORDER BY ID ASC')) { |
0f5dafff | 1391 | while ($admin = rs_fetch_next_record($rs)) { |
1afecc03 | 1392 | role_assign($adminrole, $admin->userid, 0, $systemcontext->id); |
72da5046 | 1393 | $progresscount++; |
aae37b63 | 1394 | print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments'); |
1afecc03 | 1395 | } |
0f5dafff | 1396 | rs_close($rs); |
1afecc03 | 1397 | } |
1398 | } else { | |
1399 | // This is a fresh install. | |
bbbf2d40 | 1400 | } |
1afecc03 | 1401 | |
1402 | ||
459c1ff1 | 1403 | /// Upgrade course creators. |
1afecc03 | 1404 | if (in_array($CFG->prefix.'user_coursecreators', $dbtables)) { |
f1dcf000 | 1405 | if ($rs = get_recordset('user_coursecreators')) { |
0f5dafff | 1406 | while ($coursecreator = rs_fetch_next_record($rs)) { |
56b4d70d | 1407 | role_assign($coursecreatorrole, $coursecreator->userid, 0, $systemcontext->id); |
72da5046 | 1408 | $progresscount++; |
aae37b63 | 1409 | print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments'); |
1afecc03 | 1410 | } |
0f5dafff | 1411 | rs_close($rs); |
1afecc03 | 1412 | } |
bbbf2d40 | 1413 | } |
1414 | ||
1afecc03 | 1415 | |
459c1ff1 | 1416 | /// Upgrade editting teachers and non-editting teachers. |
1afecc03 | 1417 | if (in_array($CFG->prefix.'user_teachers', $dbtables)) { |
f1dcf000 | 1418 | if ($rs = get_recordset('user_teachers')) { |
0f5dafff | 1419 | while ($teacher = rs_fetch_next_record($rs)) { |
d5511451 | 1420 | |
1421 | // removed code here to ignore site level assignments | |
1422 | // since the contexts are separated now | |
1423 | ||
17d6a25e | 1424 | // populate the user_lastaccess table |
ece4945b | 1425 | $access = new object(); |
17d6a25e | 1426 | $access->timeaccess = $teacher->timeaccess; |
1427 | $access->userid = $teacher->userid; | |
1428 | $access->courseid = $teacher->course; | |
1429 | insert_record('user_lastaccess', $access); | |
f1dcf000 | 1430 | |
17d6a25e | 1431 | // assign the default student role |
1afecc03 | 1432 | $coursecontext = get_context_instance(CONTEXT_COURSE, $teacher->course); // needs cache |
1433 | if ($teacher->editall) { // editting teacher | |
1434 | role_assign($editteacherrole, $teacher->userid, 0, $coursecontext->id); | |
1435 | } else { | |
1436 | role_assign($noneditteacherrole, $teacher->userid, 0, $coursecontext->id); | |
1437 | } | |
72da5046 | 1438 | $progresscount++; |
aae37b63 | 1439 | print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments'); |
1afecc03 | 1440 | } |
0f5dafff | 1441 | rs_close($rs); |
bbbf2d40 | 1442 | } |
1443 | } | |
1afecc03 | 1444 | |
1445 | ||
459c1ff1 | 1446 | /// Upgrade students. |
1afecc03 | 1447 | if (in_array($CFG->prefix.'user_students', $dbtables)) { |
f1dcf000 | 1448 | if ($rs = get_recordset('user_students')) { |
0f5dafff | 1449 | while ($student = rs_fetch_next_record($rs)) { |
f1dcf000 | 1450 | |
17d6a25e | 1451 | // populate the user_lastaccess table |
f1dcf000 | 1452 | $access = new object; |
17d6a25e | 1453 | $access->timeaccess = $student->timeaccess; |
1454 | $access->userid = $student->userid; | |
1455 | $access->courseid = $student->course; | |
1456 | insert_record('user_lastaccess', $access); | |
f1dcf000 | 1457 | |
17d6a25e | 1458 | // assign the default student role |
1afecc03 | 1459 | $coursecontext = get_context_instance(CONTEXT_COURSE, $student->course); |
1460 | role_assign($studentrole, $student->userid, 0, $coursecontext->id); | |
72da5046 | 1461 | $progresscount++; |
aae37b63 | 1462 | print_progress($progresscount, $totalcount, 5, 1, 'Processing role assignments'); |
1afecc03 | 1463 | } |
0f5dafff | 1464 | rs_close($rs); |
1afecc03 | 1465 | } |
bbbf2d40 | 1466 | } |
1afecc03 | 1467 | |
1468 | ||
459c1ff1 | 1469 | /// Upgrade guest (only 1 entry). |
1afecc03 | 1470 | if ($guestuser = get_record('user', 'username', 'guest')) { |
1471 | role_assign($guestrole, $guestuser->id, 0, $systemcontext->id); | |
1472 | } | |
aae37b63 | 1473 | print_progress($totalcount, $totalcount, 5, 1, 'Processing role assignments'); |
1afecc03 | 1474 | |
459c1ff1 | 1475 | |
1476 | /// Insert the correct records for legacy roles | |
945f88ca | 1477 | allow_assign($adminrole, $adminrole); |
1478 | allow_assign($adminrole, $coursecreatorrole); | |
1479 | allow_assign($adminrole, $noneditteacherrole); | |
eef868d1 | 1480 | allow_assign($adminrole, $editteacherrole); |
945f88ca | 1481 | allow_assign($adminrole, $studentrole); |
1482 | allow_assign($adminrole, $guestrole); | |
eef868d1 | 1483 | |
945f88ca | 1484 | allow_assign($coursecreatorrole, $noneditteacherrole); |
1485 | allow_assign($coursecreatorrole, $editteacherrole); | |
eef868d1 | 1486 | allow_assign($coursecreatorrole, $studentrole); |
945f88ca | 1487 | allow_assign($coursecreatorrole, $guestrole); |
eef868d1 | 1488 | |
1489 | allow_assign($editteacherrole, $noneditteacherrole); | |
1490 | allow_assign($editteacherrole, $studentrole); | |
945f88ca | 1491 | allow_assign($editteacherrole, $guestrole); |
eef868d1 | 1492 | |
459c1ff1 | 1493 | /// Set up default permissions for overrides |
945f88ca | 1494 | allow_override($adminrole, $adminrole); |
1495 | allow_override($adminrole, $coursecreatorrole); | |
1496 | allow_override($adminrole, $noneditteacherrole); | |
eef868d1 | 1497 | allow_override($adminrole, $editteacherrole); |
945f88ca | 1498 | allow_override($adminrole, $studentrole); |
eef868d1 | 1499 | allow_override($adminrole, $guestrole); |
c785d40a | 1500 | allow_override($adminrole, $userrole); |
1afecc03 | 1501 | |
746a04c5 | 1502 | |
459c1ff1 | 1503 | /// Delete the old user tables when we are done |
1504 | ||
83ea392e | 1505 | drop_table(new XMLDBTable('user_students')); |
1506 | drop_table(new XMLDBTable('user_teachers')); | |
1507 | drop_table(new XMLDBTable('user_coursecreators')); | |
1508 | drop_table(new XMLDBTable('user_admins')); | |
459c1ff1 | 1509 | |
bbbf2d40 | 1510 | } |
1511 | ||
bbbf2d40 | 1512 | /** |
1513 | * Assign the defaults found in this capabality definition to roles that have | |
1514 | * the corresponding legacy capabilities assigned to them. | |
1515 | * @param $legacyperms - an array in the format (example): | |
1516 | * 'guest' => CAP_PREVENT, | |
1517 | * 'student' => CAP_ALLOW, | |
1518 | * 'teacher' => CAP_ALLOW, | |
1519 | * 'editingteacher' => CAP_ALLOW, | |
1520 | * 'coursecreator' => CAP_ALLOW, | |
1521 | * 'admin' => CAP_ALLOW | |
1522 | * @return boolean - success or failure. | |
1523 | */ | |
1524 | function assign_legacy_capabilities($capability, $legacyperms) { | |
eef868d1 | 1525 | |
bbbf2d40 | 1526 | foreach ($legacyperms as $type => $perm) { |
eef868d1 | 1527 | |
21c9bace | 1528 | $systemcontext = get_context_instance(CONTEXT_SYSTEM); |
eef868d1 | 1529 | |
bbbf2d40 | 1530 | // The legacy capabilities are: |
1531 | // 'moodle/legacy:guest' | |
1532 | // 'moodle/legacy:student' | |
1533 | // 'moodle/legacy:teacher' | |
1534 | // 'moodle/legacy:editingteacher' | |
1535 | // 'moodle/legacy:coursecreator' | |
1536 | // 'moodle/legacy:admin' | |
eef868d1 | 1537 | |
2e85fffe | 1538 | if ($roles = get_roles_with_capability('moodle/legacy:'.$type, CAP_ALLOW)) { |
1539 | foreach ($roles as $role) { | |
1540 | // Assign a site level capability. | |
1541 | if (!assign_capability($capability, $perm, $role->id, $systemcontext->id)) { | |
1542 | return false; | |
1543 | } | |
bbbf2d40 | 1544 | } |
1545 | } | |
1546 | } | |
1547 | return true; | |
1548 | } | |
1549 | ||
1550 | ||
cee0901c | 1551 | /** |
1552 | * Checks to see if a capability is a legacy capability. | |
1553 | * @param $capabilityname | |
1554 | * @return boolean | |
1555 | */ | |
bbbf2d40 | 1556 | function islegacy($capabilityname) { |
98882637 | 1557 | if (strstr($capabilityname, 'legacy') === false) { |
eef868d1 | 1558 | return false; |
98882637 | 1559 | } else { |
eef868d1 | 1560 | return true; |
98882637 | 1561 | } |
bbbf2d40 | 1562 | } |
1563 | ||
cee0901c | 1564 | |
1565 | ||
1566 | /********************************** | |
bbbf2d40 | 1567 | * Context Manipulation functions * |
1568 | **********************************/ | |
1569 | ||
bbbf2d40 | 1570 | /** |
9991d157 | 1571 | * Create a new context record for use by all roles-related stuff |
bbbf2d40 | 1572 | * @param $level |
1573 | * @param $instanceid | |
3ca2dea5 | 1574 | * |
1575 | * @return object newly created context (or existing one with a debug warning) | |
bbbf2d40 | 1576 | */ |
aad2ba95 | 1577 | function create_context($contextlevel, $instanceid) { |
3ca2dea5 | 1578 | if (!$context = get_record('context','contextlevel',$contextlevel,'instanceid',$instanceid)) { |
1579 | if (!validate_context($contextlevel, $instanceid)) { | |
1580 | debugging('Error: Invalid context creation request for level "'.s($contextlevel).'", instance "'.s($instanceid).'".'); | |
1581 | return NULL; | |
1582 | } | |
8ba412da | 1583 | if ($contextlevel == CONTEXT_SYSTEM) { |
1584 | return create_system_context(); | |
1585 | ||
1586 | } | |
3ca2dea5 | 1587 | $context = new object(); |
aad2ba95 | 1588 | $context->contextlevel = $contextlevel; |
bbbf2d40 | 1589 | $context->instanceid = $instanceid; |
3ca2dea5 | 1590 | if ($id = insert_record('context',$context)) { |
0db6adc9 | 1591 | // we need to populate context_rel for every new context inserted |
1592 | $c = get_record('context','id',$id); | |
1593 | insert_context_rel ($c); | |
1594 | return $c; | |
3ca2dea5 | 1595 | } else { |
1596 | debugging('Error: could not insert new context level "'.s($contextlevel).'", instance "'.s($instanceid).'".'); | |
1597 | return NULL; | |
1598 | } | |
1599 | } else { | |
1600 | debugging('Warning: Context id "'.s($context->id).'" not created, because it already exists.'); | |
1601 | return $context; | |
bbbf2d40 | 1602 | } |
1603 | } | |
1604 | ||
8ba412da | 1605 | /* |
1606 | * This hacky function is needed because we can not change system context instanceid using normal upgrade routine. | |
1607 | */ | |
1608 | function create_system_context() { | |
1609 | if ($context = get_record('context', 'contextlevel', CONTEXT_SYSTEM, 'instanceid', SITEID)) { | |
1610 | // we are going to change instanceid of system context to 0 now | |
1611 | $context->instanceid = 0; | |
1612 | update_record('context', $context); | |
1613 | //context rel not affected | |
1614 | return $context; | |
1615 | ||
1616 | } else { | |
1617 | $context = new object(); | |
1618 | $context->contextlevel = CONTEXT_SYSTEM; | |
1619 | $context->instanceid = 0; | |
1620 | if ($context->id = insert_record('context',$context)) { | |
1621 | // we need not to populate context_rel for system context | |
1622 | return $context; | |
1623 | } else { | |
1624 | debugging('Can not create system context'); | |
1625 | return NULL; | |
1626 | } | |
1627 | } | |
1628 | } | |
9991d157 | 1629 | /** |
1630 | * Create a new context record for use by all roles-related stuff | |
1631 | * @param $level | |
1632 | * @param $instanceid | |
3ca2dea5 | 1633 | * |
1634 | * @return true if properly deleted | |
9991d157 | 1635 | */ |
1636 | function delete_context($contextlevel, $instanceid) { | |
0db6adc9 | 1637 | if ($context = get_context_instance($contextlevel, $instanceid)) { |
1638 | delete_records('context_rel', 'c2', $context->id); // might not be a parent | |
9991d157 | 1639 | return delete_records('context', 'id', $context->id) && |
1640 | delete_records('role_assignments', 'contextid', $context->id) && | |
0db6adc9 | 1641 | delete_records('role_capabilities', 'contextid', $context->id) && |
1642 | delete_records('context_rel', 'c1', $context->id); | |
9991d157 | 1643 | } |
1644 | return true; | |
1645 | } | |
1646 | ||
3ca2dea5 | 1647 | /** |
1648 | * Validate that object with instanceid really exists in given context level. | |
1649 | * | |
1650 | * return if instanceid object exists | |
1651 | */ | |
1652 | function validate_context($contextlevel, $instanceid) { | |
1653 | switch ($contextlevel) { | |
1654 | ||
1655 | case CONTEXT_SYSTEM: | |
8ba412da | 1656 | return ($instanceid == 0); |
3ca2dea5 | 1657 | |
1658 | case CONTEXT_PERSONAL: | |
1659 | return (boolean)count_records('user', 'id', $instanceid); | |
1660 | ||
1661 | case CONTEXT_USER: | |
1662 | return (boolean)count_records('user', 'id', $instanceid); | |
1663 | ||
1664 | case CONTEXT_COURSECAT: | |
1cd3eba9 | 1665 | if ($instanceid == 0) { |
1666 | return true; // site course category | |
1667 | } | |
3ca2dea5 | 1668 | return (boolean)count_records('course_categories', 'id', $instanceid); |
1669 | ||
1670 | case CONTEXT_COURSE: | |
1671 | return (boolean)count_records('course', 'id', $instanceid); | |
1672 | ||
1673 | case CONTEXT_GROUP: | |
f3f7610c ML |
1674 | //return (boolean)count_records('groups_groups', 'id', $instanceid); //TODO:DONOTCOMMIT: |
1675 | return groups_group_exists($instanceid); | |
3ca2dea5 | 1676 | |
1677 | case CONTEXT_MODULE: | |
1678 | return (boolean)count_records('course_modules', 'id', $instanceid); | |
1679 | ||
1680 | case CONTEXT_BLOCK: | |
1681 | return (boolean)count_records('block_instance', 'id', $instanceid); | |
1682 | ||
1683 | default: | |
1684 | return false; | |
1685 | } | |
1686 | } | |
bbbf2d40 | 1687 | |
1688 | /** | |
1689 | * Get the context instance as an object. This function will create the | |
1690 | * context instance if it does not exist yet. | |
1691 | * @param $level | |
1692 | * @param $instance | |
1693 | */ | |
8ba412da | 1694 | function get_context_instance($contextlevel=NULL, $instance=0) { |
e5605780 | 1695 | |
51195e6f | 1696 | global $context_cache, $context_cache_id, $CONTEXT; |
a36a3a3f | 1697 | static $allowed_contexts = array(CONTEXT_SYSTEM, CONTEXT_PERSONAL, CONTEXT_USER, CONTEXT_COURSECAT, CONTEXT_COURSE, CONTEXT_GROUP, CONTEXT_MODULE, CONTEXT_BLOCK); |
d9a35e12 | 1698 | |
8ba412da | 1699 | // Yu: Separating site and site course context - removed CONTEXT_COURSE override when SITEID |
b7cec865 | 1700 | |
340ea4e8 | 1701 | /// If no level is supplied then return the current global context if there is one |
aad2ba95 | 1702 | if (empty($contextlevel)) { |
340ea4e8 | 1703 | if (empty($CONTEXT)) { |
a36a3a3f | 1704 | //fatal error, code must be fixed |
1705 | error("Error: get_context_instance() called without a context"); | |
340ea4e8 | 1706 | } else { |
1707 | return $CONTEXT; | |
1708 | } | |
e5605780 | 1709 | } |
1710 | ||
8ba412da | 1711 | /// Backwards compatibility with obsoleted (CONTEXT_SYSTEM, SITEID) |
1712 | if ($contextlevel == CONTEXT_SYSTEM) { | |
1713 | $instance = 0; | |
1714 | } | |
1715 | ||
a36a3a3f | 1716 | /// check allowed context levels |
1717 | if (!in_array($contextlevel, $allowed_contexts)) { | |
7bfa3101 | 1718 | // fatal error, code must be fixed - probably typo or switched parameters |
a36a3a3f | 1719 | error('Error: get_context_instance() called with incorrect context level "'.s($contextlevel).'"'); |
1720 | } | |
1721 | ||
340ea4e8 | 1722 | /// Check the cache |
aad2ba95 | 1723 | if (isset($context_cache[$contextlevel][$instance])) { // Already cached |
1724 | return $context_cache[$contextlevel][$instance]; | |
e5605780 | 1725 | } |
1726 | ||
340ea4e8 | 1727 | /// Get it from the database, or create it |
aad2ba95 | 1728 | if (!$context = get_record('context', 'contextlevel', $contextlevel, 'instanceid', $instance)) { |
1729 | create_context($contextlevel, $instance); | |
1730 | $context = get_record('context', 'contextlevel', $contextlevel, 'instanceid', $instance); | |
e5605780 | 1731 | } |
1732 | ||
ccfc5ecc | 1733 | /// Only add to cache if context isn't empty. |
1734 | if (!empty($context)) { | |
aad2ba95 | 1735 | $context_cache[$contextlevel][$instance] = $context; // Cache it for later |
ccfc5ecc | 1736 | $context_cache_id[$context->id] = $context; // Cache it for later |
1737 | } | |
0468976c | 1738 | |
bbbf2d40 | 1739 | return $context; |
1740 | } | |
1741 | ||
cee0901c | 1742 | |
340ea4e8 | 1743 | /** |
1744 | * Get a context instance as an object, from a given id. | |
1745 | * @param $id | |
1746 | */ | |
1747 | function get_context_instance_by_id($id) { | |
1748 | ||
d9a35e12 | 1749 | global $context_cache, $context_cache_id; |
1750 | ||
340ea4e8 | 1751 | if (isset($context_cache_id[$id])) { // Already cached |
75e84883 | 1752 | return $context_cache_id[$id]; |
340ea4e8 | 1753 | } |
1754 | ||
1755 | if ($context = get_record('context', 'id', $id)) { // Update the cache and return | |
aad2ba95 | 1756 | $context_cache[$context->contextlevel][$context->instanceid] = $context; |
340ea4e8 | 1757 | $context_cache_id[$context->id] = $context; |
1758 | return $context; | |
1759 | } | |
1760 | ||
1761 | return false; | |
1762 | } | |
1763 | ||
bbbf2d40 | 1764 | |
8737be58 | 1765 | /** |
1766 | * Get the local override (if any) for a given capability in a role in a context | |
1767 | * @param $roleid | |
0468976c | 1768 | * @param $contextid |
1769 | * @param $capability | |
8737be58 | 1770 | */ |
1771 | function get_local_override($roleid, $contextid, $capability) { | |
1772 | return get_record('role_capabilities', 'roleid', $roleid, 'capability', $capability, 'contextid', $contextid); | |
1773 | } | |
1774 | ||
1775 | ||
bbbf2d40 | 1776 | |
1777 | /************************************ | |
1778 | * DB TABLE RELATED FUNCTIONS * | |
1779 | ************************************/ | |
1780 | ||
cee0901c | 1781 | /** |
bbbf2d40 | 1782 | * function that creates a role |
1783 | * @param name - role name | |
31f26796 | 1784 | * @param shortname - role short name |
bbbf2d40 | 1785 | * @param description - role description |
1786 | * @param legacy - optional legacy capability | |
1787 | * @return id or false | |
1788 | */ | |
8420bee9 | 1789 | function create_role($name, $shortname, $description, $legacy='') { |
eef868d1 | 1790 | |
98882637 | 1791 | // check for duplicate role name |
eef868d1 | 1792 | |
98882637 | 1793 | if ($role = get_record('role','name', $name)) { |
eef868d1 | 1794 | error('there is already a role with this name!'); |
98882637 | 1795 | } |
eef868d1 | 1796 | |
31f26796 | 1797 | if ($role = get_record('role','shortname', $shortname)) { |
eef868d1 | 1798 | error('there is already a role with this shortname!'); |
31f26796 | 1799 | } |
1800 | ||
b5959f30 | 1801 | $role = new object(); |
98882637 | 1802 | $role->name = $name; |
31f26796 | 1803 | $role->shortname = $shortname; |
98882637 | 1804 | $role->description = $description; |
eef868d1 | 1805 | |
8420bee9 | 1806 | //find free sortorder number |
1807 | $role->sortorder = count_records('role'); | |
1808 | while (get_record('role','sortorder', $role->sortorder)) { | |
1809 | $role->sortorder += 1; | |
b5959f30 | 1810 | } |
1811 | ||
21c9bace | 1812 | if (!$context = get_context_instance(CONTEXT_SYSTEM)) { |
1813 | return false; | |
1814 | } | |
eef868d1 | 1815 | |
98882637 | 1816 | if ($id = insert_record('role', $role)) { |
eef868d1 | 1817 | if ($legacy) { |
1818 | assign_capability($legacy, CAP_ALLOW, $id, $context->id); | |
98882637 | 1819 | } |
eef868d1 | 1820 | |
ec7a8b79 | 1821 | /// By default, users with role:manage at site level |
1822 | /// should be able to assign users to this new role, and override this new role's capabilities | |
eef868d1 | 1823 | |
ec7a8b79 | 1824 | // find all admin roles |
e46c0987 | 1825 | if ($adminroles = get_roles_with_capability('moodle/role:manage', CAP_ALLOW, $context)) { |
1826 | // foreach admin role | |
1827 | foreach ($adminroles as $arole) { | |
1828 | // write allow_assign and allow_overrid | |
1829 | allow_assign($arole->id, $id); | |
eef868d1 | 1830 | allow_override($arole->id, $id); |
e46c0987 | 1831 | } |
ec7a8b79 | 1832 | } |
eef868d1 | 1833 | |
98882637 | 1834 | return $id; |
1835 | } else { | |
eef868d1 | 1836 | return false; |
98882637 | 1837 | } |
eef868d1 | 1838 | |
bbbf2d40 | 1839 | } |
1840 | ||
8420bee9 | 1841 | /** |
1842 | * function that deletes a role and cleanups up after it | |
1843 | * @param roleid - id of role to delete | |
1844 | * @return success | |
1845 | */ | |
1846 | function delete_role($roleid) { | |
1847 | $success = true; | |
1848 | ||
1849 | // first unssign all users | |
1850 | if (!role_unassign($roleid)) { | |
1851 | debugging("Error while unassigning all users from role with ID $roleid!"); | |
1852 | $success = false; | |
1853 | } | |
1854 | ||
1855 | // cleanup all references to this role, ignore errors | |
1856 | if ($success) { | |
1857 | delete_records('role_capabilities', 'roleid', $roleid); | |
1858 | delete_records('role_allow_assign', 'roleid', $roleid); | |
1859 | delete_records('role_allow_assign', 'allowassign', $roleid); | |
1860 | delete_records('role_allow_override', 'roleid', $roleid); | |
1861 | delete_records('role_allow_override', 'allowoverride', $roleid); | |
1862 | delete_records('role_names', 'roleid', $roleid); | |
1863 | } | |
1864 | ||
1865 | // finally delete the role itself | |
1866 | if ($success and !delete_records('role', 'id', $roleid)) { | |
ece4945b | 1867 | debugging("Could not delete role record with ID $roleid!"); |
8420bee9 | 1868 | $success = false; |
1869 | } | |
1870 | ||
1871 | return $success; | |
1872 | } | |
1873 | ||
bbbf2d40 | 1874 | /** |
1875 | * Function to write context specific overrides, or default capabilities. | |
1876 | * @param module - string name | |
1877 | * @param capability - string name | |
1878 | * @param contextid - context id | |
1879 | * @param roleid - role id | |
1880 | * @param permission - int 1,-1 or -1000 | |
96986241 | 1881 | * should not be writing if permission is 0 |
bbbf2d40 | 1882 | */ |
e7876c1e | 1883 | function assign_capability($capability, $permission, $roleid, $contextid, $overwrite=false) { |
eef868d1 | 1884 | |
98882637 | 1885 | global $USER; |
eef868d1 | 1886 | |
96986241 | 1887 | if (empty($permission) || $permission == CAP_INHERIT) { // if permission is not set |
eef868d1 | 1888 | unassign_capability($capability, $roleid, $contextid); |
96986241 | 1889 | return true; |
98882637 | 1890 | } |
eef868d1 | 1891 | |
2e85fffe | 1892 | $existing = get_record('role_capabilities', 'contextid', $contextid, 'roleid', $roleid, 'capability', $capability); |
e7876c1e | 1893 | |
1894 | if ($existing and !$overwrite) { // We want to keep whatever is there already | |
1895 | return true; | |
1896 | } | |
1897 | ||
bbbf2d40 | 1898 | $cap = new object; |
1899 | $cap->contextid = $contextid; | |
1900 | $cap->roleid = $roleid; | |
1901 | $cap->capability = $capability; | |
1902 | $cap->permission = $permission; | |
1903 | $cap->timemodified = time(); | |
9db12da7 | 1904 | $cap->modifierid = empty($USER->id) ? 0 : $USER->id; |
e7876c1e | 1905 | |
1906 | if ($existing) { | |
1907 | $cap->id = $existing->id; | |
1908 | return update_record('role_capabilities', $cap); | |
1909 | } else { | |
1910 | return insert_record('role_capabilities', $cap); | |
1911 | } | |
bbbf2d40 | 1912 | } |
1913 | ||
1914 | ||
1915 | /** | |
1916 | * Unassign a capability from a role. | |
1917 | * @param $roleid - the role id | |
1918 | * @param $capability - the name of the capability | |
1919 | * @return boolean - success or failure | |
1920 | */ | |
1921 | function unassign_capability($capability, $roleid, $contextid=NULL) { | |
eef868d1 | 1922 | |
98882637 | 1923 | if (isset($contextid)) { |
1924 | $status = delete_records('role_capabilities', 'capability', $capability, | |
1925 | 'roleid', $roleid, 'contextid', $contextid); | |
1926 | } else { | |
1927 | $status = delete_records('role_capabilities', 'capability', $capability, | |
1928 | 'roleid', $roleid); | |
1929 | } | |
1930 | return $status; | |
bbbf2d40 | 1931 | } |
1932 | ||
1933 | ||
1934 | /** | |
759ac72d | 1935 | * Get the roles that have a given capability assigned to it. This function |
1936 | * does not resolve the actual permission of the capability. It just checks | |
1937 | * for assignment only. | |
bbbf2d40 | 1938 | * @param $capability - capability name (string) |
1939 | * @param $permission - optional, the permission defined for this capability | |
1940 | * either CAP_ALLOW, CAP_PREVENT or CAP_PROHIBIT | |
1941 | * @return array or role objects | |
1942 | */ | |
ec7a8b79 | 1943 | function get_roles_with_capability($capability, $permission=NULL, $context='') { |
1944 | ||
bbbf2d40 | 1945 | global $CFG; |
eef868d1 | 1946 | |
ec7a8b79 | 1947 | if ($context) { |
1948 | if ($contexts = get_parent_contexts($context)) { | |
1949 | $listofcontexts = '('.implode(',', $contexts).')'; | |
1950 | } else { | |
21c9bace | 1951 | $sitecontext = get_context_instance(CONTEXT_SYSTEM); |
eef868d1 | 1952 | $listofcontexts = '('.$sitecontext->id.')'; // must be site |
1953 | } | |
42ac3ecf | 1954 | $contextstr = "AND (rc.contextid = '$context->id' OR rc.contextid IN $listofcontexts)"; |
ec7a8b79 | 1955 | } else { |
1956 | $contextstr = ''; | |
1957 | } | |
eef868d1 | 1958 | |
1959 | $selectroles = "SELECT r.* | |
42ac3ecf | 1960 | FROM {$CFG->prefix}role r, |
1961 | {$CFG->prefix}role_capabilities rc | |
bbbf2d40 | 1962 | WHERE rc.capability = '$capability' |
ec7a8b79 | 1963 | AND rc.roleid = r.id $contextstr"; |
bbbf2d40 | 1964 | |
1965 | if (isset($permission)) { | |
1966 | $selectroles .= " AND rc.permission = '$permission'"; | |
1967 | } | |
1968 | return get_records_sql($selectroles); | |
1969 | } | |
1970 | ||
1971 | ||
1972 | /** | |
a9e1c058 | 1973 | * This function makes a role-assignment (a role for a user or group in a particular context) |
bbbf2d40 | 1974 | * @param $roleid - the role of the id |
1975 | * @param $userid - userid | |
1976 | * @param $groupid - group id | |
1977 | * @param $contextid - id of the context | |
1978 | * @param $timestart - time this assignment becomes effective | |
1979 | * @param $timeend - time this assignemnt ceases to be effective | |
1980 | * @uses $USER | |
1981 | * @return id - new id of the assigment | |
1982 | */ | |
f44152f4 | 1983 | function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $timeend=0, $hidden=0, $enrol='manual') { |
aa311411 | 1984 | global $USER, $CFG; |
bbbf2d40 | 1985 | |
7eb0b60a | 1986 | debugging("Assign roleid $roleid userid $userid contextid $contextid", DEBUG_DEVELOPER); |
bbbf2d40 | 1987 | |
a9e1c058 | 1988 | /// Do some data validation |
1989 | ||
bbbf2d40 | 1990 | if (empty($roleid)) { |
9d829c68 | 1991 | debugging('Role ID not provided'); |
a9e1c058 | 1992 | return false; |
bbbf2d40 | 1993 | } |
1994 | ||
1995 | if (empty($userid) && empty($groupid)) { | |
9d829c68 | 1996 | debugging('Either userid or groupid must be provided'); |
a9e1c058 | 1997 | return false; |
bbbf2d40 | 1998 | } |
eef868d1 | 1999 | |
7700027f | 2000 | if ($userid && !record_exists('user', 'id', $userid)) { |
82396e5b | 2001 | debugging('User ID '.intval($userid).' does not exist!'); |
7700027f | 2002 | return false; |
2003 | } | |
bbbf2d40 | 2004 | |
f3f7610c | 2005 | if ($groupid && !groups_group_exists($groupid)) { |
82396e5b | 2006 | debugging('Group ID '.intval($groupid).' does not exist!'); |
dc411d1b | 2007 | return false; |
2008 | } | |
2009 | ||
7700027f | 2010 | if (!$context = get_context_instance_by_id($contextid)) { |
82396e5b | 2011 | debugging('Context ID '.intval($contextid).' does not exist!'); |
a9e1c058 | 2012 | return false; |
bbbf2d40 | 2013 | } |
2014 | ||
a9e1c058 | 2015 | if (($timestart and $timeend) and ($timestart > $timeend)) { |
9d829c68 | 2016 | debugging('The end time can not be earlier than the start time'); |
a9e1c058 | 2017 | return false; |
2018 | } | |
2019 | ||
7700027f | 2020 | |
a9e1c058 | 2021 | /// Check for existing entry |
2022 | if ($userid) { | |
7700027f | 2023 | $ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $context->id, 'userid', $userid); |
a9e1c058 | 2024 | } else { |
7700027f | 2025 | $ra = get_record('role_assignments', 'roleid', $roleid, 'contextid', $context->id, 'groupid', $groupid); |
a9e1c058 | 2026 | } |
2027 | ||
9ebcb4d2 | 2028 | |
a9e1c058 | 2029 | $newra = new object; |
bbbf2d40 | 2030 | |
a9e1c058 | 2031 | if (empty($ra)) { // Create a new entry |
2032 | $newra->roleid = $roleid; | |
7700027f | 2033 | $newra->contextid = $context->id; |
a9e1c058 | 2034 | $newra->userid = $userid; |
a9e1c058 | 2035 | $newra->hidden = $hidden; |
f44152f4 | 2036 | $newra->enrol = $enrol; |
a9e1c058 | 2037 | $newra->timestart = $timestart; |
2038 | $newra->timeend = $timeend; | |
2039 | $newra->timemodified = time(); | |
115faa2f | 2040 | $newra->modifierid = empty($USER->id) ? 0 : $USER->id; |
a9e1c058 | 2041 | |
9ebcb4d2 | 2042 | $success = insert_record('role_assignments', $newra); |
a9e1c058 | 2043 | |
2044 | } else { // We already have one, just update it | |
2045 | ||
2046 | $newra->id = $ra->id; | |
2047 | $newra->hidden = $hidden; | |
f44152f4 | 2048 | $newra->enrol = $enrol; |
a9e1c058 | 2049 | $newra->timestart = $timestart; |
2050 | $newra->timeend = $timeend; | |
2051 | $newra->timemodified = time(); | |
115faa2f | 2052 | $newra->modifierid = empty($USER->id) ? 0 : $USER->id; |
a9e1c058 | 2053 | |
9ebcb4d2 | 2054 | $success = update_record('role_assignments', $newra); |
2055 | } | |
2056 | ||
7700027f | 2057 | if ($success) { /// Role was assigned, so do some other things |
2058 | ||
2059 | /// If the user is the current user, then reload the capabilities too. | |
2060 | if (!empty($USER->id) && $USER->id == $userid) { | |
2f1a4248 | 2061 | load_all_capabilities(); |
7700027f | 2062 | } |
9b5d7a46 | 2063 | |
0f161e1f | 2064 | /// Ask all the modules if anything needs to be done for this user |
2065 | if ($mods = get_list_of_plugins('mod')) { | |
2066 | foreach ($mods as $mod) { | |
2067 | include_once($CFG->dirroot.'/mod/'.$mod.'/lib.php'); | |
2068 | $functionname = $mod.'_role_assign'; | |
2069 | if (function_exists($functionname)) { | |
2070 | $functionname($userid, $context); | |
2071 | } | |
2072 | } | |
2073 | } | |
2074 | ||
2075 | /// Make sure they have an entry in user_lastaccess for courses they can access | |
2076 | // role_add_lastaccess_entries($userid, $context); | |
a9e1c058 | 2077 | } |
eef868d1 | 2078 | |
4e5f3064 | 2079 | /// now handle metacourse role assignments if in course context |
aad2ba95 | 2080 | if ($success and $context->contextlevel == CONTEXT_COURSE) { |
4e5f3064 | 2081 | if ($parents = get_records('course_meta', 'child_course', $context->instanceid)) { |
2082 | foreach ($parents as $parent) { | |
1aad4310 | 2083 | sync_metacourse($parent->parent_course); |
4e5f3064 | 2084 | } |
2085 | } | |
2086 | } | |
6eb4f823 | 2087 | |
2088 | return $success; | |
bbbf2d40 | 2089 | } |
2090 | ||
2091 | ||
2092 | /** | |
1dc1f037 | 2093 | * Deletes one or more role assignments. You must specify at least one parameter. |
bbbf2d40 | 2094 | * @param $roleid |
2095 | * @param $userid | |
2096 | * @param $groupid | |
2097 | * @param $contextid | |
2098 | * @return boolean - success or failure | |
2099 | */ | |
1dc1f037 | 2100 | function role_unassign($roleid=0, $userid=0, $groupid=0, $contextid=0) { |
d74067e8 | 2101 | |
2102 | global $USER, $CFG; | |
eef868d1 | 2103 | |
4e5f3064 | 2104 | $success = true; |
d74067e8 | 2105 | |
1dc1f037 | 2106 | $args = array('roleid', 'userid', 'groupid', 'contextid'); |
2107 | $select = array(); | |
2108 | foreach ($args as $arg) { | |
2109 | if ($$arg) { | |
2110 | $select[] = $arg.' = '.$$arg; | |
2111 | } | |
2112 | } | |
d74067e8 | 2113 | |
1dc1f037 | 2114 | if ($select) { |
4e5f3064 | 2115 | if ($ras = get_records_select('role_assignments', implode(' AND ', $select))) { |
2116 | $mods = get_list_of_plugins('mod'); | |
2117 | foreach($ras as $ra) { | |
86e2c51d | 2118 | /// infinite loop protection when deleting recursively |
2119 | if (!$ra = get_record('role_assignments', 'id', $ra->id)) { | |
2120 | continue; | |
2121 | } | |
4e5f3064 | 2122 | $success = delete_records('role_assignments', 'id', $ra->id) and $success; |
86e2c51d | 2123 | |
4e5f3064 | 2124 | /// If the user is the current user, then reload the capabilities too. |
2125 | if (!empty($USER->id) && $USER->id == $ra->userid) { | |
2f1a4248 | 2126 | load_all_capabilities(); |
4e5f3064 | 2127 | } |
2128 | $context = get_record('context', 'id', $ra->contextid); | |
0f161e1f | 2129 | |
2130 | /// Ask all the modules if anything needs to be done for this user | |
4e5f3064 | 2131 | foreach ($mods as $mod) { |
2132 | include_once($CFG->dirroot.'/mod/'.$mod.'/lib.php'); | |
2133 | $functionname = $mod.'_role_unassign'; | |
2134 | if (function_exists($functionname)) { | |
2135 | $functionname($ra->userid, $context); // watch out, $context might be NULL if something goes wrong | |
2136 | } | |
2137 | } | |
2138 | ||
2139 | /// now handle metacourse role unassigment and removing from goups if in course context | |
aad2ba95 | 2140 | if (!empty($context) and $context->contextlevel == CONTEXT_COURSE) { |
4e5f3064 | 2141 | //remove from groups when user has no role |
2142 | $roles = get_user_roles($context, $ra->userid, true); | |
2143 | if (empty($roles)) { | |
2144 | if ($groups = get_groups($context->instanceid, $ra->userid)) { | |
2145 | foreach ($groups as $group) { | |
2146 | delete_records('groups_members', 'groupid', $group->id, 'userid', $ra->userid); | |
2147 | } | |
2148 | } | |
2149 | } | |
1aad4310 | 2150 | //unassign roles in metacourses if needed |
4e5f3064 | 2151 | if ($parents = get_records('course_meta', 'child_course', $context->instanceid)) { |
2152 | foreach ($parents as $parent) { | |
1aad4310 | 2153 | sync_metacourse($parent->parent_course); |
0f161e1f | 2154 | } |
2155 | } | |
0f161e1f | 2156 | } |
2157 | } | |
d74067e8 | 2158 | } |
1dc1f037 | 2159 | } |
4e5f3064 | 2160 | |
2161 | return $success; | |
bbbf2d40 | 2162 | } |
2163 | ||
eef868d1 | 2164 | /* |
2165 | * A convenience function to take care of the common case where you | |
b963384f | 2166 | * just want to enrol someone using the default role into a course |
2167 | * | |
2168 | * @param object $course | |
2169 | * @param object $user | |
2170 | * @param string $enrol - the plugin used to do this enrolment | |
2171 | */ | |
2172 | function enrol_into_course($course, $user, $enrol) { | |
2173 | ||
2174 | if ($course->enrolperiod) { | |
2175 | $timestart = time(); | |
2176 | $timeend = time() + $course->enrolperiod; | |
2177 | } else { | |
2178 | $timestart = $timeend = 0; | |
2179 | } | |
2180 | ||
2181 | if ($role = get_default_course_role($course)) { | |
c4381ef5 | 2182 | |
2183 | $context = get_context_instance(CONTEXT_COURSE, $course->id); | |
2184 | ||
e2183037 | 2185 | if (!role_assign($role->id, $user->id, 0, $context->id, $timestart, $timeend, 0, $enrol)) { |
b963384f | 2186 | return false; |
2187 | } | |
eef868d1 | 2188 | |
b963384f | 2189 | email_welcome_message_to_user($course, $user); |
eef868d1 | 2190 | |
b963384f | 2191 | add_to_log($course->id, 'course', 'enrol', 'view.php?id='.$course->id, $user->id); |
2192 | ||
2193 | return true; | |
2194 | } | |
2195 | ||
2196 | return false; | |
2197 | } | |
2198 | ||
0f161e1f | 2199 | /** |
2200 | * Add last access times to user_lastaccess as required | |
2201 | * @param $userid | |
2202 | * @param $context | |
2203 | * @return boolean - success or failure | |
2204 | */ | |
2205 | function role_add_lastaccess_entries($userid, $context) { | |
2206 | ||
2207 | global $USER, $CFG; | |
2208 | ||
aad2ba95 | 2209 | if (empty($context->contextlevel)) { |
0f161e1f | 2210 | return false; |
2211 | } | |
2212 | ||
2213 | $lastaccess = new object; // Reusable object below | |
2214 | $lastaccess->userid = $userid; | |
2215 | $lastaccess->timeaccess = 0; | |
2216 | ||
aad2ba95 | 2217 | switch ($context->contextlevel) { |
0f161e1f | 2218 | |
2219 | case CONTEXT_SYSTEM: // For the whole site | |
2220 | if ($courses = get_record('course')) { | |
2221 | foreach ($courses as $course) { | |
2222 | $lastaccess->courseid = $course->id; | |
2223 | role_set_lastaccess($lastaccess); | |
2224 | } | |
2225 | } | |
2226 | break; | |
2227 | ||
2228 | case CONTEXT_CATEGORY: // For a whole category | |
2229 | if ($courses = get_record('course', 'category', $context->instanceid)) { | |
2230 | foreach ($courses as $course) { | |
2231 | $lastaccess->courseid = $course->id; | |
2232 | role_set_lastaccess($lastaccess); | |
2233 | } | |
2234 | } | |
2235 | if ($categories = get_record('course_categories', 'parent', $context->instanceid)) { | |
2236 | foreach ($categories as $category) { | |
2237 | $subcontext = get_context_instance(CONTEXT_CATEGORY, $category->id); | |
2238 | role_add_lastaccess_entries($userid, $subcontext); | |
2239 | } | |
2240 | } | |
2241 | break; | |
eef868d1 | 2242 | |
0f161e1f | 2243 | |
2244 | case CONTEXT_COURSE: // For a whole course | |
2245 | if ($course = get_record('course', 'id', $context->instanceid)) { | |
2246 | $lastaccess->courseid = $course->id; | |
2247 | role_set_lastaccess($lastaccess); | |
2248 | } | |
2249 | break; | |
2250 | } | |
2251 | } | |
2252 | ||
2253 | /** | |
2254 | * Delete last access times from user_lastaccess as required | |
2255 | * @param $userid | |
2256 | * @param $context | |
2257 | * @return boolean - success or failure | |
2258 | */ | |
2259 | function role_remove_lastaccess_entries($userid, $context) { | |
2260 | ||
2261 | global $USER, $CFG; | |
2262 | ||
2263 | } | |
2264 | ||
bbbf2d40 | 2265 | |
2266 | /** | |
2267 | * Loads the capability definitions for the component (from file). If no | |
2268 | * capabilities are defined for the component, we simply return an empty array. | |
2269 | * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results' | |
2270 | * @return array of capabilities | |
2271 | */ | |
2272 | function load_capability_def($component) { | |
2273 | global $CFG; | |
2274 | ||
2275 | if ($component == 'moodle') { | |
2276 | $defpath = $CFG->libdir.'/db/access.php'; | |
2277 | $varprefix = 'moodle'; | |
2278 | } else { | |
0c4d9f49 | 2279 | $compparts = explode('/', $component); |
eef868d1 | 2280 | |
0c4d9f49 | 2281 | if ($compparts[0] == 'block') { |
2282 | // Blocks are an exception. Blocks directory is 'blocks', and not | |
2283 | // 'block'. So we need to jump through hoops. | |
2284 | $defpath = $CFG->dirroot.'/'.$compparts[0]. | |
2285 | 's/'.$compparts[1].'/db/access.php'; | |
2286 | $varprefix = $compparts[0].'_'.$compparts[1]; | |
ae628043 | 2287 | } else if ($compparts[0] == 'format') { |
2288 | // Similar to the above, course formats are 'format' while they | |
2289 | // are stored in 'course/format'. | |
2290 | $defpath = $CFG->dirroot.'/course/'.$component.'/db/access.php'; | |
2291 | $varprefix = $compparts[0].'_'.$compparts[1]; | |
0c4d9f49 | 2292 | } else { |
2293 | $defpath = $CFG->dirroot.'/'.$component.'/db/access.php'; | |
2294 | $varprefix = str_replace('/', '_', $component); | |
2295 | } | |
bbbf2d40 | 2296 | } |
2297 | $capabilities = array(); | |
eef868d1 | 2298 | |
bbbf2d40 | 2299 | if (file_exists($defpath)) { |
dc268b2f | 2300 | require($defpath); |
bbbf2d40 | 2301 | $capabilities = ${$varprefix.'_capabilities'}; |
2302 | } | |
2303 | return $capabilities; | |
2304 | } | |
2305 | ||
2306 | ||
2307 | /** | |
2308 | * Gets the capabilities that have been cached in the database for this | |
2309 | * component. | |
2310 | * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results' | |
2311 | * @return array of capabilities | |
2312 | */ | |
2313 | function get_cached_capabilities($component='moodle') { | |
2314 | if ($component == 'moodle') { | |
2315 | $storedcaps = get_records_select('capabilities', | |
2316 | "name LIKE 'moodle/%:%'"); | |
2317 | } else { | |
2318 | $storedcaps = get_records_select('capabilities', | |
2319 | "name LIKE '$component:%'"); | |
2320 | } | |
2321 | return $storedcaps; | |
2322 | } | |
2323 | ||
2324 | ||
2325 | /** | |
2326 | * Updates the capabilities table with the component capability definitions. | |
2327 | * If no parameters are given, the function updates the core moodle | |
2328 | * capabilities. | |
2329 | * | |
2330 | * Note that the absence of the db/access.php capabilities definition file | |
2331 | * will cause any stored capabilities for the component to be removed from | |
eef868d1 | 2332 | * the database. |
bbbf2d40 | 2333 | * |
2334 | * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results' | |
2335 | * @return boolean | |
2336 | */ | |
2337 | function update_capabilities($component='moodle') { | |
eef868d1 | 2338 | |
bbbf2d40 | 2339 | $storedcaps = array(); |
be4486da | 2340 | |
2341 | $filecaps = load_capability_def($component); | |
bbbf2d40 | 2342 | $cachedcaps = get_cached_capabilities($component); |
2343 | if ($cachedcaps) { | |
2344 | foreach ($cachedcaps as $cachedcap) { | |
2345 | array_push($storedcaps, $cachedcap->name); | |
17e5635c | 2346 | // update risk bitmasks in existing capabilities if needed |
be4486da | 2347 | if (array_key_exists($cachedcap->name, $filecaps)) { |
2348 | if (!array_key_exists('riskbitmask', $filecaps[$cachedcap->name])) { | |
2b531945 | 2349 | $filecaps[$cachedcap->name]['riskbitmask'] = 0; // no risk if not specified |
be4486da | 2350 | } |
2351 | if ($cachedcap->riskbitmask != $filecaps[$cachedcap->name]['riskbitmask']) { | |
2352 | $updatecap = new object; | |
2353 | $updatecap->id = $cachedcap->id; | |
2354 | $updatecap->riskbitmask = $filecaps[$cachedcap->name]['riskbitmask']; | |
2355 | if (!update_record('capabilities', $updatecap)) { | |
2356 | return false; | |
2357 | } | |
2358 | } | |
2359 | } | |
bbbf2d40 | 2360 | } |
2361 | } | |
be4486da | 2362 | |
bbbf2d40 | 2363 | // Are there new capabilities in the file definition? |
2364 | $newcaps = array(); | |
eef868d1 | 2365 | |
bbbf2d40 | 2366 | foreach ($filecaps as $filecap => $def) { |
eef868d1 | 2367 | if (!$storedcaps || |
bbbf2d40 | 2368 | ($storedcaps && in_array($filecap, $storedcaps) === false)) { |
2b531945 | 2369 | if (!array_key_exists('riskbitmask', $def)) { |
2370 | $def['riskbitmask'] = 0; // no risk if not specified | |
2371 | } | |
bbbf2d40 | 2372 | $newcaps[$filecap] = $def; |
2373 | } | |
2374 | } | |
2375 | // Add new capabilities to the stored definition. | |
2376 | foreach ($newcaps as $capname => $capdef) { | |
2377 | $capability = new object; | |
2378 | $capability->name = $capname; | |
2379 | $capability->captype = $capdef['captype']; | |
2380 | $capability->contextlevel = $capdef['contextlevel']; | |
2381 | $capability->component = $component; | |
be4486da | 2382 | $capability->riskbitmask = $capdef['riskbitmask']; |
eef868d1 | 2383 | |
bbbf2d40 | 2384 | if (!insert_record('capabilities', $capability, false, 'id')) { |
2385 | return false; | |
2386 | } | |
eef868d1 | 2387 | |
bbbf2d40 | 2388 | // Do we need to assign the new capabilities to roles that have the |
2389 | // legacy capabilities moodle/legacy:* as well? | |
2390 | if (isset($capdef['legacy']) && is_array($capdef['legacy']) && | |
2391 | !assign_legacy_capabilities($capname, $capdef['legacy'])) { | |
2e85fffe | 2392 | notify('Could not assign legacy capabilities for '.$capname); |
bbbf2d40 | 2393 | } |
2394 | } | |
2395 | // Are there any capabilities that have been removed from the file | |
2396 | // definition that we need to delete from the stored capabilities and | |
2397 | // role assignments? | |
2398 | capabilities_cleanup($component, $filecaps); | |
eef868d1 | 2399 | |
bbbf2d40 | 2400 | return true; |
2401 | } | |
2402 | ||
2403 | ||
2404 | /** | |
2405 | * Deletes cached capabilities that are no longer needed by the component. | |
2406 | * Also unassigns these capabilities from any roles that have them. | |
2407 | * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results' | |
2408 | * @param $newcapdef - array of the new capability definitions that will be | |
2409 | * compared with the cached capabilities | |
2410 | * @return int - number of deprecated capabilities that have been removed | |
2411 | */ | |
2412 | function capabilities_cleanup($component, $newcapdef=NULL) { | |
eef868d1 | 2413 | |
bbbf2d40 | 2414 | $removedcount = 0; |
eef868d1 | 2415 | |
bbbf2d40 | 2416 | if ($cachedcaps = get_cached_capabilities($component)) { |
2417 | foreach ($cachedcaps as $cachedcap) { | |
2418 | if (empty($newcapdef) || | |
2419 | array_key_exists($cachedcap->name, $newcapdef) === false) { | |
eef868d1 | 2420 | |
bbbf2d40 | 2421 | // Remove from capabilities cache. |
2422 | if (!delete_records('capabilities', 'name', $cachedcap->name)) { | |
2423 | error('Could not delete deprecated capability '.$cachedcap->name); | |
2424 | } else { | |
2425 | $removedcount++; | |
2426 | } | |
2427 | // Delete from roles. | |
2428 | if($roles = get_roles_with_capability($cachedcap->name)) { | |
2429 | foreach($roles as $role) { | |
46943f7b | 2430 | if (!unassign_capability($cachedcap->name, $role->id)) { |
bbbf2d40 | 2431 | error('Could not unassign deprecated capability '. |
2432 | $cachedcap->name.' from role '.$role->name); | |
2433 | } | |
2434 | } | |
2435 | } | |
2436 | } // End if. | |
2437 | } | |
2438 | } | |
2439 | return $removedcount; | |
2440 | } | |
2441 | ||
2442 | ||
2443 | ||
cee0901c | 2444 | /**************** |
2445 | * UI FUNCTIONS * | |
2446 | ****************/ | |
bbbf2d40 | 2447 | |
2448 | ||
2449 | /** | |
2450 | * prints human readable context identifier. | |
2451 | */ | |
0468976c | 2452 | function print_context_name($context) { |
340ea4e8 | 2453 | |
ec0810ee | 2454 | $name = ''; |
aad2ba95 | 2455 | switch ($context->contextlevel) { |
ec0810ee | 2456 | |
bbbf2d40 | 2457 | case CONTEXT_SYSTEM: // by now it's a definite an inherit |
ec0810ee | 2458 | $name = get_string('site'); |
340ea4e8 | 2459 | break; |
bbbf2d40 | 2460 | |
2461 | case CONTEXT_PERSONAL: | |
ec0810ee | 2462 | $name = get_string('personal'); |
340ea4e8 | 2463 | break; |
2464 | ||
4b10f08b | 2465 | case CONTEXT_USER: |
ec0810ee | 2466 | if ($user = get_record('user', 'id', $context->instanceid)) { |
2467 | $name = get_string('user').': '.fullname($user); | |
2468 | } | |
340ea4e8 | 2469 | break; |
2470 | ||
bbbf2d40 | 2471 | case CONTEXT_COURSECAT: // Coursecat -> coursecat or site |
ec0810ee | 2472 | if ($category = get_record('course_categories', 'id', $context->instanceid)) { |
2473 | $name = get_string('category').': '.$category->name; | |
2474 | } | |
340ea4e8 | 2475 | break; |
bbbf2d40 | 2476 | |
2477 | case CONTEXT_COURSE: // 1 to 1 to course cat | |
ec0810ee | 2478 | if ($course = get_record('course', 'id', $context->instanceid)) { |
2479 | $name = get_string('course').': '.$course->fullname; | |
2480 | } | |
340ea4e8 | 2481 | break; |
bbbf2d40 | 2482 | |
2483 | case CONTEXT_GROUP: // 1 to 1 to course | |
f3f7610c ML |
2484 | if ($name = groups_get_group_name($context->instanceid)) { |
2485 | $name = get_string('group').': '. $name; | |
ec0810ee | 2486 | } |
340ea4e8 | 2487 | break; |
bbbf2d40 | 2488 | |
2489 | case CONTEXT_MODULE: // 1 to 1 to course | |
98882637 | 2490 | if ($cm = get_record('course_modules','id',$context->instanceid)) { |
2491 | if ($module = get_record('modules','id',$cm->module)) { | |
2492 | if ($mod = get_record($module->name, 'id', $cm->instance)) { | |
ec0810ee | 2493 | $name = get_string('activitymodule').': '.$mod->name; |
98882637 | 2494 | } |
ec0810ee | 2495 | } |
2496 | } | |
340ea4e8 | 2497 | break; |
bbbf2d40 | 2498 | |
2499 | case CONTEXT_BLOCK: // 1 to 1 to course | |
98882637 | 2500 | if ($blockinstance = get_record('block_instance','id',$context->instanceid)) { |
2501 | if ($block = get_record('block','id',$blockinstance->blockid)) { | |
91be52d7 | 2502 | global $CFG; |
2503 | require_once("$CFG->dirroot/blocks/moodleblock.class.php"); | |
2504 | require_once("$CFG->dirroot/blocks/$block->name/block_$block->name.php"); | |
2505 | $blockname = "block_$block->name"; | |
2506 | if ($blockobject = new $blockname()) { | |
2507 | $name = $blockobject->title.' ('.get_string('block').')'; | |
2508 | } | |
ec0810ee | 2509 | } |
2510 | } | |
340ea4e8 | 2511 | break; |
bbbf2d40 | 2512 | |
2513 | default: | |
2514 | error ('This is an unknown context!'); | |
340ea4e8 | 2515 | return false; |
2516 | ||
2517 | } | |
340ea4e8 | 2518 | return $name; |
bbbf2d40 | 2519 | } |
2520 | ||
2521 | ||
2522 | /** | |
eef868d1 | 2523 | * Extracts the relevant capabilities given a contextid. |
bbbf2d40 | 2524 | * All case based, example an instance of forum context. |
2525 | * Will fetch all forum related capabilities, while course contexts | |
2526 | * Will fetch all capabilities | |
0468976c | 2527 | * @param object context |
bbbf2d40 | 2528 | * @return array(); |
2529 | * | |
2530 | * capabilities | |
2531 | * `name` varchar(150) NOT NULL, | |
2532 | * `captype` varchar(50) NOT NULL, | |
2533 | * `contextlevel` int(10) NOT NULL, | |
2534 | * `component` varchar(100) NOT NULL, | |
2535 | */ | |
0468976c | 2536 | function fetch_context_capabilities($context) { |
eef868d1 | 2537 | |
98882637 | 2538 | global $CFG; |
bbbf2d40 | 2539 | |
2540 | $sort = 'ORDER BY contextlevel,component,id'; // To group them sensibly for display | |
eef868d1 | 2541 | |
aad2ba95 | 2542 | switch ($context->contextlevel) { |
bbbf2d40 | 2543 | |
98882637 | 2544 | case CONTEXT_SYSTEM: // all |
2545 | $SQL = "select * from {$CFG->prefix}capabilities"; | |
bbbf2d40 | 2546 | break; |
2547 | ||
2548 | case CONTEXT_PERSONAL: | |
0a8a95c9 | 2549 | $SQL = "select * from {$CFG->prefix}capabilities where contextlevel = ".CONTEXT_PERSONAL; |
bbbf2d40 | 2550 | break; |
eef868d1 | 2551 | |
4b10f08b | 2552 | case CONTEXT_USER: |
8020a016 | 2553 | $SQL = "SELECT * |
2554 | FROM {$CFG->prefix}capabilities | |
2555 | WHERE contextlevel = ".CONTEXT_USER; | |
bbbf2d40 | 2556 | break; |
eef868d1 | 2557 | |
bbbf2d40 | 2558 | case CONTEXT_COURSECAT: // all |
98882637 | 2559 | $SQL = "select * from {$CFG->prefix}capabilities"; |
bbbf2d40 | 2560 | break; |
2561 | ||
2562 | case CONTEXT_COURSE: // all | |
98882637 | 2563 | $SQL = "select * from {$CFG->prefix}capabilities"; |
bbbf2d40 | 2564 | break; |
2565 | ||
2566 | case CONTEXT_GROUP: // group caps | |
2567 | break; | |
2568 | ||
2569 | case CONTEXT_MODULE: // mod caps | |
98882637 | 2570 | $cm = get_record('course_modules', 'id', $context->instanceid); |
2571 | $module = get_record('modules', 'id', $cm->module); | |
eef868d1 | 2572 | |
98882637 | 2573 | $SQL = "select * from {$CFG->prefix}capabilities where contextlevel = ".CONTEXT_MODULE." |
2574 | and component = 'mod/$module->name'"; | |
bbbf2d40 | 2575 | break; |
2576 | ||
2577 | case CONTEXT_BLOCK: // block caps | |
98882637 | 2578 | $cb = get_record('block_instance', 'id', $context->instanceid); |
2579 | $block = get_record('block', 'id', $cb->blockid); | |
eef868d1 | 2580 | |
98882637 | 2581 | $SQL = "select * from {$CFG->prefix}capabilities where contextlevel = ".CONTEXT_BLOCK." |
2582 | and component = 'block/$block->name'"; | |
bbbf2d40 | 2583 | break; |
2584 | ||
2585 | default: | |
2586 | return false; | |
2587 | } | |
2588 | ||
16e2e2f3 | 2589 | if (!$records = get_records_sql($SQL.' '.$sort)) { |
2590 | $records = array(); | |
2591 | } | |
ba8d8027 | 2592 | |
2593 | /// the rest of code is a bit hacky, think twice before modifying it :-( | |
69eb59f2 | 2594 | |
2595 | // special sorting of core system capabiltites and enrollments | |
e9c82dca | 2596 | if (in_array($context->contextlevel, array(CONTEXT_SYSTEM, CONTEXT_COURSECAT, CONTEXT_COURSE))) { |
69eb59f2 | 2597 | $first = array(); |
2598 | foreach ($records as $key=>$record) { | |
2599 | if (preg_match('|^moodle/|', $record->name) and $record->contextlevel == CONTEXT_SYSTEM) { | |
2600 | $first[$key] = $record; | |
2601 | unset($records[$key]); | |
2602 | } else if (count($first)){ | |
2603 | break; | |
2604 | } | |
2605 | } | |
2606 | if (count($first)) { | |
2607 | $records = $first + $records; // merge the two arrays keeping the keys | |
2608 | } | |
ba8d8027 | 2609 | } else { |
2610 | $contextindependentcaps = fetch_context_independent_capabilities(); | |
2611 | $records = array_merge($contextindependentcaps, $records); | |
69eb59f2 | 2612 | } |
ba8d8027 | 2613 | |
bbbf2d40 | 2614 | return $records; |
eef868d1 | 2615 | |
bbbf2d40 | 2616 | } |
2617 | ||
2618 | ||
759ac72d | 2619 | /** |
2620 | * Gets the context-independent capabilities that should be overrridable in | |
2621 | * any context. | |
2622 | * @return array of capability records from the capabilities table. | |
2623 | */ | |
2624 | function fetch_context_independent_capabilities() { | |
eef868d1 | 2625 | |
17e5635c | 2626 | //only CONTEXT_SYSTEM capabilities here or it will break the hack in fetch_context_capabilities() |
759ac72d | 2627 | $contextindependentcaps = array( |
2628 | 'moodle/site:accessallgroups' | |
2629 | ); | |
2630 | ||
2631 | $records = array(); | |
eef868d1 | 2632 | |
759ac72d | 2633 | foreach ($contextindependentcaps as $capname) { |
2634 | $record = get_record('capabilities', 'name', $capname); | |
2635 | array_push($records, $record); | |
2636 | } | |
2637 | return $records; | |
2638 | } | |
2639 | ||
2640 | ||
bbbf2d40 | 2641 | /** |
2642 | * This function pulls out all the resolved capabilities (overrides and | |
759ac72d | 2643 | * defaults) of a role used in capability overrides in contexts at a given |
bbbf2d40 | 2644 | * context. |
0a8a95c9 | 2645 | * @param obj $context |
bbbf2d40 | 2646 | * @param int $roleid |
dc558690 | 2647 | * @param bool self - if set to true, resolve till this level, else stop at immediate parent level |
bbbf2d40 | 2648 | * @return array |
2649 | */ | |
1648afb2 | 2650 | function role_context_capabilities($roleid, $context, $cap='') { |
dc558690 | 2651 | global $CFG; |
eef868d1 | 2652 | |
8521d83a | 2653 | $contexts = get_parent_contexts($context); |
2654 | $contexts[] = $context->id; | |
98882637 | 2655 | $contexts = '('.implode(',', $contexts).')'; |
eef868d1 | 2656 | |
1648afb2 | 2657 | if ($cap) { |
e4697bf7 | 2658 | $search = " AND rc.capability = '$cap' "; |
1648afb2 | 2659 | } else { |
eef868d1 | 2660 | $search = ''; |
1648afb2 | 2661 | } |
eef868d1 | 2662 | |
2663 | $SQL = "SELECT rc.* | |
2664 | FROM {$CFG->prefix}role_capabilities rc, | |
dc558690 | 2665 | {$CFG->prefix}context c |
2666 | WHERE rc.contextid in $contexts | |
2667 | AND rc.roleid = $roleid | |
2668 | AND rc.contextid = c.id $search | |
aad2ba95 | 2669 | ORDER BY c.contextlevel DESC, |
eef868d1 | 2670 | rc.capability DESC"; |
759ac72d | 2671 | |
98882637 | 2672 | $capabilities = array(); |
eef868d1 | 2673 | |
4729012f | 2674 | if ($records = get_records_sql($SQL)) { |
2675 | // We are traversing via reverse order. | |
2676 | foreach ($records as $record) { | |
2677 | // If not set yet (i.e. inherit or not set at all), or currently we have a prohibit | |
2678 | if (!isset($capabilities[$record->capability]) || $record->permission<-500) { | |
2679 | $capabilities[$record->capability] = $record->permission; | |
eef868d1 | 2680 | } |
4729012f | 2681 | } |
98882637 | 2682 | } |
2683 | return $capabilities; | |
bbbf2d40 | 2684 | } |
2685 | ||
bbbf2d40 | 2686 | /** |
eef868d1 | 2687 | * Recursive function which, given a context, find all parent context ids, |
bbbf2d40 | 2688 | * and return the array in reverse order, i.e. parent first, then grand |
2689 | * parent, etc. | |
2690 | * @param object $context | |
2691 | * @return array() | |
2692 | */ | |
bbbf2d40 | 2693 | function get_parent_contexts($context) { |
759ac72d | 2694 | |
1cd03601 | 2695 | static $pcontexts; // cache |
2696 | if (isset($pcontexts[$context->id])) { | |
2697 | return ($pcontexts[$context->id]); | |
2698 | } | |
2699 | ||
aad2ba95 | 2700 | switch ($context->contextlevel) { |
bbbf2d40 | 2701 | |
2702 | case CONTEXT_SYSTEM: // no parent | |
957861f7 | 2703 | return array(); |
bbbf2d40 | 2704 | break; |
2705 | ||
2706 | case CONTEXT_PERSONAL: | |
21c9bace | 2707 | if (!$parent = get_context_instance(CONTEXT_SYSTEM)) { |
957861f7 | 2708 | return array(); |
2709 | } else { | |
1cd03601 | 2710 | $res = array($parent->id); |
0de75c4c | 2711 | $pcontexts[$context->id] = $res; |
1cd03601 | 2712 | return $res; |
957861f7 | 2713 | } |
bbbf2d40 | 2714 | break; |
eef868d1 | 2715 | |
4b10f08b | 2716 | case CONTEXT_USER: |
21c9bace | 2717 | if (!$parent = get_context_instance(CONTEXT_SYSTEM)) { |
957861f7 | 2718 | return array(); |
2719 | } else { | |
1cd03601 | 2720 | $res = array($parent->id); |
0de75c4c | 2721 | $pcontexts[$context->id] = $res; |
1cd03601 | 2722 | return $res; |
957861f7 | 2723 | } |
bbbf2d40 | 2724 | break; |
eef868d1 | 2725 | |
bbbf2d40 | 2726 | case CONTEXT_COURSECAT: // Coursecat -> coursecat or site |
957861f7 | 2727 | if (!$coursecat = get_record('course_categories','id',$context->instanceid)) { |
2728 | return array(); | |
2729 | } | |
c5ddc3fd | 2730 | if (!empty($coursecat->parent)) { // return parent value if exist |
bbbf2d40 | 2731 | $parent = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent); |
1cd03601 | 2732 | $res = array_merge(array($parent->id), get_parent_contexts($parent)); |
2733 | $pcontexts[$context->id] = $res; | |
2734 | return $res; | |
bbbf2d40 | 2735 | } else { // else return site value |
21c9bace | 2736 | $parent = get_context_instance(CONTEXT_SYSTEM); |
1cd03601 | 2737 | $res = array($parent->id); |
2738 | $pcontexts[$context->id] = $res; | |
2739 | return $res; | |
bbbf2d40 | 2740 | } |
2741 | break; | |
2742 | ||
2743 | case CONTEXT_COURSE: // 1 to 1 to course cat | |
957861f7 | 2744 | if (!$course = get_record('course','id',$context->instanceid)) { |
2745 | return array(); | |
2746 | } | |
1936c10e | 2747 | if ($course->id != SITEID) { |
957861f7 | 2748 | $parent = get_context_instance(CONTEXT_COURSECAT, $course->category); |
1cd03601 | 2749 | $res = array_merge(array($parent->id), get_parent_contexts($parent)); |
2750 | return $res; | |
957861f7 | 2751 | } else { |
40a2a15f | 2752 | // Yu: Separating site and site course context |
2753 | $parent = get_context_instance(CONTEXT_SYSTEM); | |
1cd03601 | 2754 | $res = array($parent->id); |
2755 | $pcontexts[$context->id] = $res; | |
2756 | return $res; | |
957861f7 | 2757 | } |
bbbf2d40 | 2758 | break; |
2759 | ||
2760 | case CONTEXT_GROUP: // 1 to 1 to course | |
f3f7610c | 2761 | if (! $group = groups_get_group($context->instanceid)) { |
957861f7 | 2762 | return array(); |
2763 | } | |
2764 | if ($parent = get_context_instance(CONTEXT_COURSE, $group->courseid)) { | |
1cd03601 | 2765 | $res = array_merge(array($parent->id), get_parent_contexts($parent)); |
2766 | $pcontexts[$context->id] = $res; | |
2767 | return $res; | |
957861f7 | 2768 | } else { |
2769 | return array(); | |
2770 | } | |
bbbf2d40 | 2771 | break; |
2772 | ||
2773 | case CONTEXT_MODULE: // 1 to 1 to course | |
957861f7 | 2774 | if (!$cm = get_record('course_modules','id',$context->instanceid)) { |
2775 | return array(); | |
2776 | } | |
2777 | if ($parent = get_context_instance(CONTEXT_COURSE, $cm->course)) { | |
1cd03601 | 2778 | $res = array_merge(array($parent->id), get_parent_contexts($parent)); |
2779 | $pcontexts[$context->id] = $res; | |
2780 | return $res; | |
957861f7 | 2781 | } else { |
2782 | return array(); | |
2783 | } | |
bbbf2d40 | 2784 | break; |
2785 | ||
2786 | case CONTEXT_BLOCK: // 1 to 1 to course | |
957861f7 | 2787 | if (!$block = get_record('block_instance','id',$context->instanceid)) { |
2788 | return array(); | |
2789 | } | |
2790 | if ($parent = get_context_instance(CONTEXT_COURSE, $block->pageid)) { | |
1cd03601 | 2791 | $res = array_merge(array($parent->id), get_parent_contexts($parent)); |
2792 | $pcontexts[$context->id] = $res; | |
2793 | return $res; | |
957861f7 | 2794 | } else { |
2795 | return array(); | |
2796 | } | |
bbbf2d40 | 2797 | break; |
2798 | ||
2799 | default: | |
957861f7 | 2800 | error('This is an unknown context!'); |
bbbf2d40 | 2801 | return false; |
2802 | } | |
bbbf2d40 | 2803 | } |
2804 | ||
759ac72d | 2805 | |
2806 | /** | |
2807 | * Gets a string for sql calls, searching for stuff in this context or above | |
ea8158c1 | 2808 | * @param object $context |
2809 | * @return string | |
2810 | */ | |
2811 | function get_related_contexts_string($context) { | |
2812 | if ($parents = get_parent_contexts($context)) { | |
eef868d1 | 2813 | return (' IN ('.$context->id.','.implode(',', $parents).')'); |
ea8158c1 | 2814 | } else { |
2815 | return (' ='.$context->id); | |
2816 | } | |
2817 | } | |
759ac72d | 2818 | |
2819 | ||
bbbf2d40 | 2820 | /** |
2821 | * This function gets the capability of a role in a given context. | |
2822 | * It is needed when printing override forms. | |
2823 | * @param int $contextid | |
bbbf2d40 | 2824 | * @param string $capability |
2825 | * @param array $capabilities - array loaded using role_context_capabilities | |
2826 | * @return int (allow, prevent, prohibit, inherit) | |
2827 | */ | |
bbbf2d40 | 2828 | function get_role_context_capability($contextid, $capability, $capabilities) { |
759ac72d | 2829 | if (isset($capabilities[$contextid][$capability])) { |
2830 | return $capabilities[$contextid][$capability]; | |
2831 | } | |
2832 | else { | |
2833 | return false; | |
2834 | } | |
bbbf2d40 | 2835 | } |
2836 | ||
2837 | ||
cee0901c | 2838 | /** |
2839 | * Returns the human-readable, translated version of the capability. | |
2840 | * Basically a big switch statement. | |
2841 | * @param $capabilityname - e.g. mod/choice:readresponses | |
2842 | */ | |
ceb83c70 | 2843 | function get_capability_string($capabilityname) { |
eef868d1 | 2844 | |
cee0901c | 2845 | // Typical capabilityname is mod/choice:readresponses |
ceb83c70 | 2846 | |
2847 | $names = split('/', $capabilityname); | |
2848 | $stringname = $names[1]; // choice:readresponses | |
eef868d1 | 2849 | $components = split(':', $stringname); |
ceb83c70 | 2850 | $componentname = $components[0]; // choice |
98882637 | 2851 | |
2852 | switch ($names[0]) { | |
2853 | case 'mod': | |
ceb83c70 | 2854 | $string = get_string($stringname, $componentname); |
98882637 | 2855 | break; |
eef868d1 | 2856 | |
98882637 | 2857 | case 'block': |
ceb83c70 | 2858 | $string = get_string($stringname, 'block_'.$componentname); |
98882637 | 2859 | break; |
ceb83c70 | 2860 | |
98882637 | 2861 | case 'moodle': |
ceb83c70 | 2862 | $string = get_string($stringname, 'role'); |
98882637 | 2863 | break; |
eef868d1 | 2864 | |
98882637 | 2865 | case 'enrol': |
ceb83c70 | 2866 | $string = get_string($stringname, 'enrol_'.$componentname); |
eef868d1 | 2867 | break; |
ae628043 | 2868 | |
2869 | case 'format': | |
2870 | $string = get_string($stringname, 'format_'.$componentname); | |
2871 | break; | |
eef868d1 | 2872 | |
98882637 | 2873 | default: |
ceb83c70 | 2874 | $string = get_string($stringname); |
eef868d1 | 2875 | break; |
2876 | ||
98882637 | 2877 | } |
ceb83c70 | 2878 | return $string; |
bbbf2d40 | 2879 | } |
2880 | ||
2881 | ||
cee0901c | 2882 | /** |
2883 | * This gets the mod/block/course/core etc strings. | |
2884 | * @param $component | |
2885 | * @param $contextlevel | |
2886 | */ | |
bbbf2d40 | 2887 | function get_component_string($component, $contextlevel) { |
2888 | ||
98882637 | 2889 | switch ($contextlevel) { |
bbbf2d40 | 2890 | |
98882637 | 2891 | case CONTEXT_SYSTEM: |
be382aaf | 2892 | if (preg_match('|^enrol/|', $component)) { |
2893 | $langname = str_replace('/', '_', $component); | |
2894 | $string = get_string('enrolname', $langname); | |
f3652521 | 2895 | } else if (preg_match('|^block/|', $component)) { |
2896 | $langname = str_replace('/', '_', $component); | |
2897 | $string = get_string('blockname', $langname); | |
69eb59f2 | 2898 | } else { |
2899 | $string = get_string('coresystem'); | |
2900 | } | |
bbbf2d40 | 2901 | break; |
2902 | ||
2903 | case CONTEXT_PERSONAL: | |
98882637 | 2904 | $string = get_string('personal'); |
bbbf2d40 | 2905 | break; |
2906 | ||
4b10f08b | 2907 | case CONTEXT_USER: |
98882637 | 2908 | $string = get_string('users'); |
bbbf2d40 | 2909 | break; |
2910 | ||
2911 | case CONTEXT_COURSECAT: | |
98882637 | 2912 | $string = get_string('categories'); |
bbbf2d40 | 2913 | break; |
2914 | ||
2915 | case CONTEXT_COURSE: | |
98882637 | 2916 | $string = get_string('course'); |
bbbf2d40 | 2917 | break; |
2918 | ||
2919 | case CONTEXT_GROUP: | |
98882637 | 2920 | $string = get_string('group'); |
bbbf2d40 | 2921 | break; |
2922 | ||
2923 | case CONTEXT_MODULE: | |
98882637 | 2924 | $string = get_string('modulename', basename($component)); |
bbbf2d40 | 2925 | break; |
2926 | ||
2927 | case CONTEXT_BLOCK: | |
98882637 | 2928 | $string = get_string('blockname', 'block_'.$component.'.php'); |
bbbf2d40 | 2929 | break; |
2930 | ||
2931 | default: | |
2932 | error ('This is an unknown context!'); | |
2933 | return false; | |
eef868d1 | 2934 | |
98882637 | 2935 | } |
98882637 | 2936 | return $string; |
bbbf2d40 | 2937 | } |
cee0901c | 2938 | |
759ac72d | 2939 | /** |
2940 | * Gets the list of roles assigned to this context and up (parents) | |
945f88ca | 2941 | * @param object $context |
3997cb40 | 2942 | * @param view - set to true when roles are pulled for display only |
2943 | * this is so that we can filter roles with no visible | |
2944 | * assignment, for example, you might want to "hide" all | |
2945 | * course creators when browsing the course participants | |
2946 | * list. | |
945f88ca | 2947 | * @return array |
2948 | */ | |
3997cb40 | 2949 | function get_roles_used_in_context($context, $view = false) { |
e4dd3222 | 2950 | |
2951 | global $CFG; | |
3997cb40 | 2952 | |
2953 | // filter for roles with all hidden assignments | |
2954 | // no need to return when only pulling roles for reviewing | |
2955 | // e.g. participants page. | |
d42c64ba | 2956 | $hiddensql = ($view && !has_capability('moodle/role:viewhiddenassigns', $context))? ' AND ra.hidden = 0 ':''; |
2d9965e1 | 2957 | $contextlist = get_related_contexts_string($context); |
eef868d1 | 2958 | |
759ac72d | 2959 | $sql = "SELECT DISTINCT r.id, |
2960 | r.name, | |
2961 | r.shortname, | |
2962 | r.sortorder | |
2963 | FROM {$CFG->prefix}role_assignments ra, | |
eef868d1 | 2964 | {$CFG->prefix}role r |
2965 | WHERE r.id = ra.roleid | |
759ac72d | 2966 | AND ra.contextid $contextlist |
3997cb40 | 2967 | $hiddensql |
759ac72d | 2968 | ORDER BY r.sortorder ASC"; |
eef868d1 | 2969 | |
759ac72d | 2970 | return get_records_sql($sql); |
e4dd3222 | 2971 | } |
2972 | ||
eef868d1 | 2973 | /** this function is used to print roles column in user profile page. |
945f88ca | 2974 | * @param int userid |
2975 | * @param int contextid | |
2976 | * @return string | |
2977 | */ | |
0a8a95c9 | 2978 | function get_user_roles_in_context($userid, $contextid){ |
2979 | global $CFG; | |
eef868d1 | 2980 | |
0a8a95c9 | 2981 | $rolestring = ''; |
2982 | $SQL = 'select * from '.$CFG->prefix.'role_assignments ra, '.$CFG->prefix.'role r where ra.userid='.$userid.' and ra.contextid='.$contextid.' and ra.roleid = r.id'; | |
2983 | if ($roles = get_records_sql($SQL)) { | |
2984 | foreach ($roles as $userrole) { | |
2985 | $rolestring .= '<a href="'.$CFG->wwwroot.'/user/index.php?contextid='.$userrole->contextid.'&roleid='.$userrole->roleid.'">'.$userrole->name.'</a>, '; | |
eef868d1 | 2986 | } |
2987 | ||
0a8a95c9 | 2988 | } |
2989 | return rtrim($rolestring, ', '); | |
2990 | } | |
68c52526 | 2991 | |
2992 | ||
945f88ca | 2993 | /** |
2994 | * Checks if a user can override capabilities of a particular role in this context | |
2995 | * @param object $context | |
2996 | * @param int targetroleid - the id of the role you want to override | |
2997 | * @return boolean | |
2998 | */ | |
68c52526 | 2999 | function user_can_override($context, $targetroleid) { |
3000 | // first check if user has override capability | |
3001 | // if not return false; | |
3002 | if (!has_capability('moodle/role:override', $context)) { | |
eef868d1 | 3003 | return false; |
68c52526 | 3004 | } |
3005 | // pull out all active roles of this user from this context(or above) | |
c0614051 | 3006 | if ($userroles = get_user_roles($context)) { |
3007 | foreach ($userroles as $userrole) { | |
3008 | // if any in the role_allow_override table, then it's ok | |
3009 | if (get_record('role_allow_override', 'roleid', $userrole->roleid, 'allowoverride', $targetroleid)) { | |
3010 | return true; | |
3011 | } | |
68c52526 | 3012 | } |
3013 | } | |
eef868d1 | 3014 | |
68c52526 | 3015 | return false; |
eef868d1 | 3016 | |
68c52526 | 3017 | } |
3018 | ||
945f88ca | 3019 | /** |
3020 | * Checks if a user can assign users to a particular role in this context | |
3021 | * @param object $context | |
3022 | * @param int targetroleid - the id of the role you want to assign users to | |
3023 | * @return boolean | |
3024 | */ | |
68c52526 | 3025 | function user_can_assign($context, $targetroleid) { |
eef868d1 | 3026 | |
68c52526 | 3027 | // first check if user has override capability |
3028 | // if not return false; | |
3029 | if (!has_capability('moodle/role:assign', $context)) { | |
eef868d1 | 3030 | return false; |
68c52526 | 3031 | } |
3032 | // pull out all active roles of this user from this context(or above) | |
c0614051 | 3033 | if ($userroles = get_user_roles($context)) { |
3034 | foreach ($userroles as $userrole) { | |
3035 | // if any in the role_allow_override table, then it's ok | |
3036 | if (get_record('role_allow_assign', 'roleid', $userrole->roleid, 'allowassign', $targetroleid)) { | |
3037 | return true; | |
3038 | } | |
68c52526 | 3039 | } |
3040 | } | |
eef868d1 | 3041 | |
3042 | return false; | |
68c52526 | 3043 | } |
3044 | ||
ece4945b | 3045 | /** Returns all site roles in correct sort order. |
3046 | * | |
3047 | */ | |
3048 | function get_all_roles() { | |
3049 | return get_records('role', '', '', 'sortorder ASC'); | |
3050 | } | |
3051 | ||
945f88ca | 3052 | /** |
3053 | * gets all the user roles assigned in this context, or higher contexts | |
3054 | * this is mainly used when checking if a user can assign a role, or overriding a role | |
3055 | * i.e. we need to know what this user holds, in order to verify against allow_assign and | |
3056 | * allow_override tables | |
3057 | * @param object $context | |
3058 | * @param int $userid | |
b06334e8 | 3059 | * @param view - set to true when roles are pulled for display only |
3060 | * this is so that we can filter roles with no visible | |
3061 | * assignment, for example, you might want to "hide" all | |
3062 | * course creators when browsing the course participants | |
3063 | * list. | |
945f88ca | 3064 | * @return array |
3065 | */ | |
b06334e8 | 3066 | function get_user_roles($context, $userid=0, $checkparentcontexts=true, $order='c.contextlevel DESC, r.sortorder ASC', $view=false) { |
68c52526 | 3067 | |
3068 | global $USER, $CFG, $db; | |
c0614051 | 3069 | |
3070 | if (empty($userid)) { | |
3071 | if (empty($USER->id)) { | |
3072 | return array(); | |
3073 | } | |
3074 | $userid = $USER->id; | |
3075 | } | |
b06334e8 | 3076 | // set up hidden sql |
d42c64ba | 3077 | $hiddensql = ($view && !has_capability('moodle/role:viewhiddenassigns', $context))? ' AND ra.hidden = 0 ':''; |
c0614051 | 3078 | |
5b630667 | 3079 | if ($checkparentcontexts && ($parents = get_parent_contexts($context))) { |
3080 | $contexts = ' ra.contextid IN ('.implode(',' , $parents).','.$context->id.')'; | |
c0614051 | 3081 | } else { |
5b630667 | 3082 | $contexts = ' ra.contextid = \''.$context->id.'\''; |
c0614051 | 3083 | } |
3084 | ||
31f26796 | 3085 | return get_records_sql('SELECT ra.*, r.name, r.shortname |
5b630667 | 3086 | FROM '.$CFG->prefix.'role_assignments ra, |
ec6eb110 | 3087 | '.$CFG->prefix.'role r, |
3088 | '.$CFG->prefix.'context c | |
c0614051 | 3089 | WHERE ra.userid = '.$userid. |
5b630667 | 3090 | ' AND ra.roleid = r.id |
ec6eb110 | 3091 | AND ra.contextid = c.id |
b06334e8 | 3092 | AND '.$contexts . $hiddensql . |
ae9761ec | 3093 | ' ORDER BY '.$order); |
68c52526 | 3094 | } |
3095 | ||
945f88ca | 3096 | /** |
eef868d1 | 3097 | * Creates a record in the allow_override table |
945f88ca | 3098 | * @param int sroleid - source roleid |
3099 | * @param int troleid - target roleid | |
3100 | * @return int - id or false | |
3101 | */ | |
3102 | function allow_override($sroleid, $troleid) { | |
ece4945b | 3103 | $record = new object(); |
945f88ca | 3104 | $record->roleid = $sroleid; |
3105 | $record->allowoverride = $troleid; | |
3106 | return insert_record('role_allow_override', $record); | |
3107 | } | |
3108 | ||
3109 | /** | |
eef868d1 | 3110 | * Creates a record in the allow_assign table |
945f88ca | 3111 | * @param int sroleid - source roleid |
3112 | * @param int troleid - target roleid | |
3113 | * @return int - id or false | |
3114 | */ | |
3115 | function allow_assign($sroleid, $troleid) { | |
ff64aaea | 3116 | $record = new object; |
945f88ca | 3117 | $record->roleid = $sroleid; |
3118 | $record->allowassign = $troleid; | |
3119 | return insert_record('role_allow_assign', $record); | |
3120 | } | |
3121 | ||
3122 | /** | |
ff64aaea | 3123 | * Gets a list of roles that this user can assign in this context |
945f88ca | 3124 | * @param object $context |
3125 | * @return array | |
3126 | */ | |
5e67946d | 3127 | function get_assignable_roles ($context, $field="name") { |
945f88ca | 3128 | |
945f88ca | 3129 | $options = array(); |
ff64aaea | 3130 | |
ece4945b | 3131 | if ($roles = get_all_roles()) { |
ff64aaea | 3132 | foreach ($roles as $role) { |
3133 | if (user_can_assign($context, $role->id)) { | |
5e67946d | 3134 | $options[$role->id] = strip_tags(format_string($role->{$field}, true)); |
ff64aaea | 3135 | } |
945f88ca | 3136 | } |
3137 | } | |
3138 | return $options; | |
3139 | } | |
3140 | ||
3141 | /** | |
ff64aaea | 3142 | * Gets a list of roles that this user can override in this context |
945f88ca | 3143 | * @param object $context |
3144 | * @return array | |
3145 | */ | |
3146 | function get_overridable_roles ($context) { | |
3147 | ||
945f88ca | 3148 | $options = array(); |
ff64aaea | 3149 | |
ece4945b | 3150 | if ($roles = get_all_roles()) { |
ff64aaea | 3151 | foreach ($roles as $role) { |
3152 | if (user_can_override($context, $role->id)) { | |
65b0c132 | 3153 | $options[$role->id] = strip_tags(format_string($role->name, true)); |
ff64aaea | 3154 | } |
945f88ca | 3155 | } |
ff64aaea | 3156 | } |
eef868d1 | 3157 | |
3158 | return $options; | |
945f88ca | 3159 | } |
1648afb2 | 3160 | |
b963384f | 3161 | /* |
3162 | * Returns a role object that is the default role for new enrolments | |
3163 | * in a given course | |
3164 | * | |
eef868d1 | 3165 | * @param object $course |
b963384f | 3166 | * @return object $role |
3167 | */ | |
3168 | function get_default_course_role($course) { | |
3169 | global $CFG; | |
3170 | ||
3171 | /// First let's take the default role the course may have | |
3172 | if (!empty($course->defaultrole)) { | |
3173 | if ($role = get_record('role', 'id', $course->defaultrole)) { | |
3174 | return $role; | |
3175 | } | |
3176 | } | |
3177 | ||
3178 | /// Otherwise the site setting should tell us | |
3179 | if ($CFG->defaultcourseroleid) { | |
3180 | if ($role = get_record('role', 'id', $CFG->defaultcourseroleid)) { | |
3181 | return $role; | |
3182 | } | |
3183 | } | |
3184 | ||
3185 | /// It's unlikely we'll get here, but just in case, try and find a student role | |
3186 | if ($studentroles = get_roles_with_capability('moodle/legacy:student', CAP_ALLOW)) { | |
3187 | return array_shift($studentroles); /// Take the first one | |
3188 | } | |
3189 | ||
3190 | return NULL; | |
3191 | } | |
3192 | ||
1648afb2 | 3193 | |
3194 | /** | |
3195 | * who has this capability in this context | |
3196 | * does not handling user level resolving!!! | |
40a2a15f | 3197 | * (!)pleaes note if $fields is empty this function attempts to get u.* |
3198 | * which can get rather large. | |
1648afb2 | 3199 | * i.e 1 person has 2 roles 1 allow, 1 prevent, this will not work properly |
3200 |