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