Added has_capability call
[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 */
16
17
18// permission definitions
19define('CAP_ALLOW', 1);
20define('CAP_PREVENT', -1);
21define('CAP_PROHIBIT', -1000);
22
23
24// context definitions
25define('CONTEXT_SYSTEM', 10);
26define('CONTEXT_PERSONAL', 20);
27define('CONTEXT_USERID', 30);
28define('CONTEXT_COURSECAT', 40);
29define('CONTEXT_COURSE', 50);
30define('CONTEXT_GROUP', 60);
31define('CONTEXT_MODULE', 70);
32define('CONTEXT_BLOCK', 80);
33
340ea4e8 34$context_cache = array(); // Cache of all used context objects for performance (by level and instance)
35$context_cache_id = array(); // Index to above cache by id
bbbf2d40 36
cee0901c 37
bbbf2d40 38/**
39 * This functions get all the course categories in proper order
0468976c 40 * @param int $context
bbbf2d40 41 * @param int $type
42 * @return array of contextids
43 */
0468976c 44function get_parent_cats($context, $type) {
98882637 45
46 $parents = array();
98882637 47
48 switch($type) {
49
50 case CONTEXT_COURSECAT:
51
52 $cat = get_record('course_categories','id',$context->instanceid);
53 while ($cat->parent) {
54
55 $context = get_context_instance(CONTEXT_COURSECAT, $cat->parent);
56 $parents[] = $context->id;
57 $cat = get_record('course_categories','id',$cat->parent);
58 }
59
60 break;
61
62 case CONTEXT_COURSE:
63
64 $course = get_record('course', 'id', $context->instanceid);
65 $cat = get_record('course_categories','id',$course->category);
66 $catinstance = get_context_instance(CONTEXT_COURSECAT, $course->category);
67 $parents[] = $catinstance->id;
68
69 // what to do with cat 0?
70 while ($cat->parent) {
71 $context = get_context_instance(CONTEXT_COURSECAT, $cat->parent);
72 $parents[] = $context->id;
73 $cat = get_record('course_categories','id',$cat->parent);
74 }
75 break;
76
77 default:
78 break;
79
80 }
81
82 return array_reverse($parents);
bbbf2d40 83}
84
85
cee0901c 86
87/*************************************
88 * Functions for Roles & Capabilites *
89 *************************************/
bbbf2d40 90
91
0468976c 92/**
93 * This function checks for a capability assertion being true. If it isn't
94 * then the page is terminated neatly with a standard error message
95 * @param string $capability - name of the capability
96 * @param object $context - a context object (record from context table)
97 * @param integer $userid - a userid number
98 * @param string $errorstring - an errorstring
99 */
100function require_capability($capability, $context=NULL, $userid=NULL, $errormessage="nopermissions", $stringfile='') {
101 if (!has_capability($capability, $context, $userid)) {
102 $capabilityname = get_capability_string($capability);
103 print_error($errormessage, $stringfile, '', $capabilityname);
104 }
105}
106
107
bbbf2d40 108/**
109 * This function returns whether the current user has the capability of performing a function
110 * For example, we can do has_capability('mod/forum:replypost',$cm) in forum
111 * only one of the 4 (moduleinstance, courseid, site, userid) would be set at 1 time
112 * This is a recursive funciton.
bbbf2d40 113 * @uses $USER
114 * @param string $capability - name of the capability
0468976c 115 * @param object $context - a context object (record from context table)
116 * @param integer $userid - a userid number
bbbf2d40 117 * @return bool
118 */
0468976c 119function has_capability($capability, $context=NULL, $userid=NULL) {
bbbf2d40 120
340ea4e8 121 global $USER, $CONTEXT;
bbbf2d40 122
98882637 123 if ($userid && $userid != $USER->id) { // loading other user's capability
0468976c 124 $capabilities = load_user_capability($capability, $context, $userid);
98882637 125 } else {
10f5c890 126 $capabilities = empty($USER->capabilities) ? NULL : $USER->capabilities;
98882637 127 }
bbbf2d40 128
0468976c 129 if (empty($context)) { // Use default CONTEXT if none specified
340ea4e8 130 if (empty($CONTEXT)) {
131 return false;
132 } else {
133 $context = $CONTEXT;
134 }
0468976c 135 } else { // A context was given to us
136 if (empty($CONTEXT)) {
137 $CONTEXT = $context; // Store FIRST used context in this global as future default
138 }
340ea4e8 139 }
bbbf2d40 140
98882637 141 // Check site
142 $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
143 if (isset($capabilities[$sitecontext->id]['moodle/site:doanything'])) {
144 return ($capabilities[$sitecontext->id]['moodle/site:doanything']);
145 }
146
0468976c 147 switch ($context->level) {
bbbf2d40 148
149 case CONTEXT_COURSECAT:
98882637 150 // Check parent cats.
0468976c 151 $parentcats = get_parent_cats($context, CONTEXT_COURSECAT);
98882637 152 foreach ($parentcats as $parentcat) {
153 if (isset($capabilities[$parentcat]['moodle/site:doanything'])) {
154 return ($capabilities[$parentcat]['moodle/site:doanything']);
cee0901c 155 }
98882637 156 }
bbbf2d40 157 break;
158
159 case CONTEXT_COURSE:
98882637 160 // Check parent cat.
0468976c 161 $parentcats = get_parent_cats($context, CONTEXT_COURSE);
98882637 162
163 foreach ($parentcats as $parentcat) {
164 if (isset($capabilities[$parentcat]['do_anything'])) {
165 return ($capabilities[$parentcat]['do_anything']);
166 }
167 }
bbbf2d40 168 break;
169
170 case CONTEXT_GROUP:
98882637 171 // Find course.
172 $group = get_record('groups','id',$context->instanceid);
bbbf2d40 173 $courseinstance = get_context_instance(CONTEXT_COURSE, $group->courseid);
98882637 174
175 $parentcats = get_parent_cats($courseinstance->id, CONTEXT_COURSE);
176 foreach ($parentcats as $parentcat) {
177 if (isset($capabilities[$parentcat->id]['do_anything'])) {
178 return ($capabilities[$parentcat->id]['do_anything']);
179 }
180 }
181
182 $coursecontext = '';
183 if (isset($capabilities[$courseinstance->id]['do_anything'])) {
184 return ($capabilities[$courseinstance->id]['do_anything']);
185 }
186
bbbf2d40 187 break;
188
189 case CONTEXT_MODULE:
190 // Find course.
191 $cm = get_record('course_modules', 'id', $context->instanceid);
98882637 192 $courseinstance = get_context_instance(CONTEXT_COURSE, $cm->course);
bbbf2d40 193
98882637 194 if ($parentcats = get_parent_cats($courseinstance->id, CONTEXT_COURSE)) {
195 foreach ($parentcats as $parentcat) {
196 if (isset($capabilities[$parentcat]['do_anything'])) {
197 return ($capabilities[$parentcat]['do_anything']);
cee0901c 198 }
98882637 199 }
200 }
201
202 if (isset($capabilities[$courseinstance->id]['do_anything'])) {
203 return ($capabilities[$courseinstance->id]['do_anything']);
cee0901c 204 }
bbbf2d40 205
206 break;
207
208 case CONTEXT_BLOCK:
209 // 1 to 1 to course.
210 // Find course.
211 $block = get_record('block_instance','id',$context->instanceid);
212 $courseinstance = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check
98882637 213
214 $parentcats = get_parent_cats($courseinstance->id, CONTEXT_COURSE);
215 foreach ($parentcats as $parentcat) {
216 if (isset($capabilities[$parentcat]['do_anything'])) {
217 return ($capabilities[$parentcat]['do_anything']);
cee0901c 218 }
219 }
98882637 220
221 if (isset($capabilities[$courseinstance->id]['do_anything'])) {
222 return ($capabilities[$courseinstance->id]['do_anything']);
cee0901c 223 }
bbbf2d40 224 break;
225
226 default:
227 // CONTEXT_SYSTEM: CONTEXT_PERSONAL: CONTEXT_USERID:
228 // Do nothing.
229 break;
98882637 230 }
bbbf2d40 231
98882637 232 // Last: check self.
0468976c 233 if (isset($capabilities[$context->id]['do_anything'])) {
234 return ($capabilities[$context->id]['do_anything']);
98882637 235 }
236
237 // do_anything has not been set, we now look for it the normal way.
0468976c 238 return capability_search($capability, $context, $capabilities);
bbbf2d40 239
240}
241
242
243/**
244 * In a separate function so that we won't have to deal with do_anything.
245 * again. Used by function has_capability.
246 * @param $capability - capability string
0468976c 247 * @param $context - the context object
bbbf2d40 248 * @param $capabilities - either $USER->capability or loaded array
249 * @return permission (int)
250 */
0468976c 251function capability_search($capability, $context, $capabilities) {
bbbf2d40 252 global $USER, $CFG;
0468976c 253
218564ac 254 if ($CFG->debug > 7) {
0468976c 255 notify("Looking for $capability in context $context->id", 'notifytiny');
bbbf2d40 256 }
257
0468976c 258 if (isset($capabilities[$context->id][$capability])) {
259 return ($capabilities[$context->id][$capability]);
bbbf2d40 260 }
261
262 /* Then, we check the cache recursively */
98882637 263 $permission = 0;
264
0468976c 265 switch ($context->level) {
bbbf2d40 266
267 case CONTEXT_SYSTEM: // by now it's a definite an inherit
268 $permission = 0;
269 break;
270
271 case CONTEXT_PERSONAL:
0468976c 272 $parentcontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
273 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 274 break;
275
276 case CONTEXT_USERID:
0468976c 277 $parentcontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
278 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 279 break;
280
281 case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
282 $coursecat = get_record('course_categories','id',$context->instanceid);
0468976c 283 if (!empty($coursecat->parent)) { // return parent value if it exists
284 $parentcontext = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent);
bbbf2d40 285 } else { // else return site value
0468976c 286 $parentcontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
bbbf2d40 287 }
0468976c 288 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 289 break;
290
291 case CONTEXT_COURSE: // 1 to 1 to course cat
292 // find the course cat, and return its value
293 $course = get_record('course','id',$context->instanceid);
0468976c 294 $parentcontext = get_context_instance(CONTEXT_COURSECAT, $course->category);
295 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 296 break;
297
298 case CONTEXT_GROUP: // 1 to 1 to course
299 $group = get_record('groups','id',$context->instanceid);
0468976c 300 $parentcontext = get_context_instance(CONTEXT_COURSE, $group->courseid);
301 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 302 break;
303
304 case CONTEXT_MODULE: // 1 to 1 to course
305 $cm = get_record('course_modules','id',$context->instanceid);
0468976c 306 $parentcontext = get_context_instance(CONTEXT_COURSE, $cm->course);
307 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 308 break;
309
310 case CONTEXT_BLOCK: // 1 to 1 to course
311 $block = get_record('block_instance','id',$context->instanceid);
0468976c 312 $parentcontext = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check
313 $permission = capability_search($capability, $parentcontext, $capabilities);
bbbf2d40 314 break;
315
316 default:
317 error ('This is an unknown context!');
318 return false;
319 }
320
98882637 321 return $permission;
bbbf2d40 322}
323
324
325/**
326 * This function should be called immediately after a login, when $USER is set.
327 * It will build an array of all the capabilities at each level
328 * i.e. site/metacourse/course_category/course/moduleinstance
329 * Note we should only load capabilities if they are explicitly assigned already,
330 * we should not load all module's capability!
331 * @param $userid - the id of the user whose capabilities we want to load
332 * @return array
333 * possible just s simple 2D array with [contextid][capabilityname]
334 * [Capabilities] => [26][forum_post] = 1
335 * [26][forum_start] = -8990
336 * [26][forum_edit] = -1
337 * [273][blah blah] = 1
338 * [273][blah blah blah] = 2
339 */
0468976c 340function load_user_capability($capability='', $context ='', $userid='') {
bbbf2d40 341
98882637 342 global $USER, $CFG;
bbbf2d40 343
344 if (empty($userid)) {
345 $userid = $USER->id;
346 } else {
98882637 347 $otheruserid = $userid;
bbbf2d40 348 }
349
350 if ($capability) {
98882637 351 $capsearch = ' AND rc.capability = '.$capability.' ';
bbbf2d40 352 } else {
98882637 353 $capsearch ='';
bbbf2d40 354 }
355 // First we generate a list of all relevant contexts of the user
356
0468976c 357 if ($context) { // if context is specified
358 $usercontexts = get_parent_contexts($context);
98882637 359 $listofcontexts = '('.implode(',', $usercontexts).')';
360 } else { // else, we load everything
0468976c 361 $userroles = get_records('role_assignments','userid',$userid);
362 $usercontexts = array();
363 foreach ($userroles as $userrole) {
364 $usercontexts[] = $userrole->contextid;
98882637 365 }
0468976c 366 $listofcontexts = '('.implode(',', $usercontexts).')';
bbbf2d40 367 }
0468976c 368
bbbf2d40 369 // Then we use 1 giant SQL to bring out all relevant capabilities.
370 // The first part gets the capabilities of orginal role.
371 // The second part gets the capabilities of overriden roles.
372
98882637 373 $siteinstance = get_context_instance(CONTEXT_SYSTEM, SITEID);
bbbf2d40 374
41811960 375 $SQL = " SELECT rc.capability, c1.id, (c1.level * 100) AS aggregatelevel,
bbbf2d40 376 SUM(rc.permission) AS sum
377 FROM
171948fd 378 {$CFG->prefix}role_assignments AS ra,
379 {$CFG->prefix}role_capabilities AS rc,
380 {$CFG->prefix}context AS c1
bbbf2d40 381 WHERE
171948fd 382 ra.contextid=c1.id AND
383 ra.roleid=rc.roleid AND
bbbf2d40 384 ra.userid=$userid AND
385 c1.id IN $listofcontexts AND
386 rc.contextid=$siteinstance->id
98882637 387 $capsearch
bbbf2d40 388 GROUP BY
41811960 389 rc.capability,aggregatelevel,c1.id
bbbf2d40 390 HAVING
41811960 391 SUM(rc.permission) != 0
bbbf2d40 392 UNION
393
41811960 394 SELECT rc.capability, c1.id, (c1.level * 100 + c2.level) AS aggregatelevel,
bbbf2d40 395 SUM(rc.permission) AS sum
396 FROM
171948fd 397 {$CFG->prefix}role_assignments AS ra,
398 {$CFG->prefix}role_capabilities AS rc,
399 {$CFG->prefix}context AS c1,
400 {$CFG->prefix}context AS c2
bbbf2d40 401 WHERE
171948fd 402 ra.contextid=c1.id AND
403 ra.roleid=rc.roleid AND
404 ra.userid=$userid AND
405 rc.contextid=c2.id AND
bbbf2d40 406 c1.id IN $listofcontexts AND
407 c2.id IN $listofcontexts AND rc.contextid != $siteinstance->id
408 $capsearch
409
410 GROUP BY
41811960 411 rc.capability, aggregatelevel, c1.id
bbbf2d40 412 HAVING
41811960 413 SUM(rc.permission) != 0
bbbf2d40 414 ORDER BY
41811960 415 aggregatelevel ASC
bbbf2d40 416 ";
417
bbbf2d40 418
98882637 419 $capabilities = array(); // Reinitialize.
420 $rs = get_recordset_sql($SQL);
421
bbbf2d40 422 if ($rs && $rs->RecordCount() > 0) {
423 while (!$rs->EOF) {
98882637 424 $array = $rs->fields;
425 $temprecord = new object;
426
427 foreach ($array as $key=>$val) {
428 $temprecord->{$key} = $val;
429 }
bbbf2d40 430 $capabilities[] = $temprecord;
431 $rs->MoveNext();
432 }
433 }
434
435 /* so up to this point we should have somethign like this
41811960 436 * $capabilities[1] ->aggregatelevel = 1000
bbbf2d40 437 ->module = SITEID
438 ->capability = do_anything
439 ->id = 1 (id is the context id)
440 ->sum = 0
441
41811960 442 * $capabilities[2] ->aggregatelevel = 1000
bbbf2d40 443 ->module = SITEID
444 ->capability = post_messages
445 ->id = 1
446 ->sum = -9000
447
41811960 448 * $capabilittes[3] ->aggregatelevel = 3000
bbbf2d40 449 ->module = course
450 ->capability = view_course_activities
451 ->id = 25
452 ->sum = 1
453
41811960 454 * $capabilittes[4] ->aggregatelevel = 3000
bbbf2d40 455 ->module = course
456 ->capability = view_course_activities
457 ->id = 26
458 ->sum = 0 (this is another course)
459
41811960 460 * $capabilities[5] ->aggregatelevel = 3050
bbbf2d40 461 ->module = course
462 ->capability = view_course_activities
463 ->id = 25 (override in course 25)
464 ->sum = -1
465 * ....
466 * now we proceed to write the session array, going from top to bottom
467 * at anypoint, we need to go up and check parent to look for prohibit
468 */
469 // print_object($capabilities);
470
471 /* This is where we write to the actualy capabilities array
472 * what we need to do from here on is
473 * going down the array from lowest level to highest level
474 * 1) recursively check for prohibit,
475 * if any, we write prohibit
476 * else, we write the value
477 * 2) at an override level, we overwrite current level
478 * if it's not set to prohibit already, and if different
479 * ........ that should be it ........
480 */
98882637 481 $usercap = array(); // for other user's capabilities
bbbf2d40 482 foreach ($capabilities as $capability) {
483
0468976c 484 $context = get_context_instance_by_id($capability->id);
485
41811960 486 if (!empty($otheruserid)) { // we are pulling out other user's capabilities, do not write to session
98882637 487
0468976c 488 if (capability_prohibits($capability->capability, $context, $capability->sum, $usercap)) {
98882637 489 $usercap[$capability->id][$capability->capability] = -9000;
490 continue;
491 }
492
493 $usercap[$capability->id][$capability->capability] = $capability->sum;
494
495 } else {
496
0468976c 497 if (capability_prohibits($capability->capability, $context, $capability->sum)) { // if any parent or parent's parent is set to prohibit
98882637 498 $USER->capabilities[$capability->id][$capability->capability] = -9000;
499 continue;
500 }
501
502 // if no parental prohibit set
503 // just write to session, i am not sure this is correct yet
504 // since 3050 shows up after 3000, and 3070 shows up after 3050,
505 // it should be ok just to overwrite like this, provided that there's no
506 // parental prohibits
507 // no point writing 0, since 0 = inherit
508 // we need to write even if it's 0, because it could be an inherit override
509 $USER->capabilities[$capability->id][$capability->capability] = $capability->sum;
510 }
bbbf2d40 511 }
512
513 // now we don't care about the huge array anymore, we can dispose it.
514 unset($capabilities);
515
41811960 516 if (!empty($otheruseid)) {
98882637 517 return $usercap; // return the array
bbbf2d40 518 }
519 // see array in session to see what it looks like
520
521}
522
523
524/**
525 * This is a recursive function that checks whether the capability in this
526 * context, or the parent capabilities are set to prohibit.
527 *
528 * At this point, we can probably just use the values already set in the
529 * session variable, since we are going down the level. Any prohit set in
530 * parents would already reflect in the session.
531 *
532 * @param $capability - capability name
533 * @param $sum - sum of all capabilities values
0468976c 534 * @param $context - the context object
bbbf2d40 535 * @param $array - when loading another user caps, their caps are not stored in session but an array
536 */
0468976c 537function capability_prohibits($capability, $context, $sum='', $array='') {
bbbf2d40 538 global $USER;
0468976c 539
bbbf2d40 540 if ($sum < -8000) {
541 // If this capability is set to prohibit.
542 return true;
543 }
544
545 if (isset($array)) {
0468976c 546 if (isset($array[$context->id][$capability])
547 && $array[$context->id][$capability] < -8000) {
98882637 548 return true;
549 }
bbbf2d40 550 } else {
98882637 551 // Else if set in session.
0468976c 552 if (isset($USER->capabilities[$context->id][$capability])
553 && $USER->capabilities[$context->id][$capability] < -8000) {
98882637 554 return true;
555 }
bbbf2d40 556 }
0468976c 557 switch ($context->level) {
bbbf2d40 558
559 case CONTEXT_SYSTEM:
560 // By now it's a definite an inherit.
561 return 0;
562 break;
563
564 case CONTEXT_PERSONAL:
565 $parent = get_context_instance(CONTEXT_SYSTEM, SITEID);
0468976c 566 return capability_prohibits($capability, $parent);
bbbf2d40 567 break;
568
569 case CONTEXT_USERID:
570 $parent = get_context_instance(CONTEXT_SYSTEM, SITEID);
0468976c 571 return capability_prohibits($capability, $parent);
bbbf2d40 572 break;
573
574 case CONTEXT_COURSECAT:
575 // Coursecat -> coursecat or site.
576 $coursecat = get_record('course_categories','id',$context->instanceid);
41811960 577 if (!empty($coursecat->parent)) {
bbbf2d40 578 // return parent value if exist.
579 $parent = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent);
580 } else {
581 // Return site value.
582 $parent = get_context_instance(CONTEXT_SYSTEM, SITEID);
583 }
0468976c 584 return capability_prohibits($capability, $parent);
bbbf2d40 585 break;
586
587 case CONTEXT_COURSE:
588 // 1 to 1 to course cat.
589 // Find the course cat, and return its value.
590 $course = get_record('course','id',$context->instanceid);
591 $parent = get_context_instance(CONTEXT_COURSECAT, $course->category);
0468976c 592 return capability_prohibits($capability, $parent);
bbbf2d40 593 break;
594
595 case CONTEXT_GROUP:
596 // 1 to 1 to course.
597 $group = get_record('groups','id',$context->instanceid);
598 $parent = get_context_instance(CONTEXT_COURSE, $group->courseid);
0468976c 599 return capability_prohibits($capability, $parent);
bbbf2d40 600 break;
601
602 case CONTEXT_MODULE:
603 // 1 to 1 to course.
604 $cm = get_record('course_modules','id',$context->instanceid);
605 $parent = get_context_instance(CONTEXT_COURSE, $cm->course);
0468976c 606 return capability_prohibits($capability, $parent);
bbbf2d40 607 break;
608
609 case CONTEXT_BLOCK:
610 // 1 to 1 to course.
611 $block = get_record('block_instance','id',$context->instanceid);
612 $parent = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check
0468976c 613 return capability_prohibits($capability, $parent);
bbbf2d40 614 break;
615
616 default:
617 error ('This is an unknown context!');
618 return false;
619 }
620}
621
622
623/**
624 * A print form function. This should either grab all the capabilities from
625 * files or a central table for that particular module instance, then present
626 * them in check boxes. Only relevant capabilities should print for known
627 * context.
628 * @param $mod - module id of the mod
629 */
630function print_capabilities($modid=0) {
631 global $CFG;
632
633 $capabilities = array();
634
635 if ($modid) {
636 // We are in a module specific context.
637
638 // Get the mod's name.
639 // Call the function that grabs the file and parse.
640 $cm = get_record('course_modules', 'id', $modid);
641 $module = get_record('modules', 'id', $cm->module);
642
643 } else {
644 // Print all capabilities.
645 foreach ($capabilities as $capability) {
646 // Prints the check box component.
647 }
648 }
649}
650
651
652/**
1afecc03 653 * Installs the roles system.
654 * This function runs on a fresh install as well as on an upgrade from the old
655 * hard-coded student/teacher/admin etc. roles to the new roles system.
bbbf2d40 656 */
1afecc03 657function moodle_install_roles() {
bbbf2d40 658
1afecc03 659 global $CFG, $db;
660
bbbf2d40 661 // Create a system wide context for assignemnt.
662 $systemcontext = $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
663
1afecc03 664
665 // Create default/legacy roles and capabilities.
666 // (1 legacy capability per legacy role at system level).
bbbf2d40 667 $adminrole = create_role(get_string('administrator'), get_string('administratordescription'), 'moodle/legacy:admin');
98882637 668 if (!assign_capability('moodle/site:doanything', CAP_ALLOW, $adminrole, $systemcontext->id)) {
bbbf2d40 669 error('Could not assign moodle/site:doanything to the admin role');
670 }
671 $coursecreatorrole = create_role(get_string('coursecreators'), get_string('coursecreatorsdescription'), 'moodle/legacy:coursecreator');
98882637 672 $noneditteacherrole = create_role(get_string('noneditingteacher'), get_string('noneditingteacherdescription'), 'moodle/legacy:teacher');
673 $editteacherrole = create_role(get_string('defaultcourseteacher'), get_string('defaultcourseteacherdescription'), 'moodle/legacy:editingteacher');
674 $studentrole = create_role(get_string('defaultcoursestudent'), get_string('defaultcoursestudentdescription'), 'moodle/legacy:student');
bbbf2d40 675 $guestrole = create_role(get_string('guest'), get_string('guestdescription'), 'moodle/legacy:guest');
1afecc03 676
677
678 // Look inside user_admin, user_creator, user_teachers, user_students and
679 // assign above new roles. If a user has both teacher and student role,
680 // only teacher role is assigned. The assignment should be system level.
681 $dbtables = $db->MetaTables('TABLES');
bbbf2d40 682
1afecc03 683
98882637 684 /**
bbbf2d40 685 * Upgrade the admins.
1afecc03 686 * Sort using id ASC, first one is primary admin.
bbbf2d40 687 */
1afecc03 688 if (in_array($CFG->prefix.'user_admins', $dbtables)) {
689 if ($useradmins = get_records_sql('SELECT * from '.$CFG->prefix.'user_admins ORDER BY ID ASC')) {
690 foreach ($useradmins as $admin) {
691 role_assign($adminrole, $admin->userid, 0, $systemcontext->id);
692 }
693 }
694 } else {
695 // This is a fresh install.
bbbf2d40 696 }
1afecc03 697
698
bbbf2d40 699 /**
700 * Upgrade course creators.
701 */
1afecc03 702 if (in_array($CFG->prefix.'user_coursecreators', $dbtables)) {
703 if ($usercoursecreators = get_records('user_coursecreators')) {
704 foreach ($usercoursecreators as $coursecreator) {
705 role_assign($$coursecreatorrole, $coursecreator->userid, 0, $systemcontext->id);
706 }
707 }
bbbf2d40 708 }
709
1afecc03 710
bbbf2d40 711 /**
712 * Upgrade editting teachers and non-editting teachers.
713 */
1afecc03 714 if (in_array($CFG->prefix.'user_teachers', $dbtables)) {
715 if ($userteachers = get_records('user_teachers')) {
716 foreach ($userteachers as $teacher) {
717 $coursecontext = get_context_instance(CONTEXT_COURSE, $teacher->course); // needs cache
718 if ($teacher->editall) { // editting teacher
719 role_assign($editteacherrole, $teacher->userid, 0, $coursecontext->id);
720 } else {
721 role_assign($noneditteacherrole, $teacher->userid, 0, $coursecontext->id);
722 }
723 }
bbbf2d40 724 }
725 }
1afecc03 726
727
bbbf2d40 728 /**
729 * Upgrade students.
730 */
1afecc03 731 if (in_array($CFG->prefix.'user_students', $dbtables)) {
732 if ($userstudents = get_records('user_students')) {
733 foreach ($userstudents as $student) {
734 $coursecontext = get_context_instance(CONTEXT_COURSE, $student->course);
735 role_assign($studentrole, $student->userid, 0, $coursecontext->id);
736 }
737 }
bbbf2d40 738 }
1afecc03 739
740
bbbf2d40 741 /**
742 * Upgrade guest (only 1 entry).
743 */
1afecc03 744 if ($guestuser = get_record('user', 'username', 'guest')) {
745 role_assign($guestrole, $guestuser->id, 0, $systemcontext->id);
746 }
747
748
749 // Should we delete the tables after we are done? Not yet.
bbbf2d40 750}
751
752
753/**
754 * Assign the defaults found in this capabality definition to roles that have
755 * the corresponding legacy capabilities assigned to them.
756 * @param $legacyperms - an array in the format (example):
757 * 'guest' => CAP_PREVENT,
758 * 'student' => CAP_ALLOW,
759 * 'teacher' => CAP_ALLOW,
760 * 'editingteacher' => CAP_ALLOW,
761 * 'coursecreator' => CAP_ALLOW,
762 * 'admin' => CAP_ALLOW
763 * @return boolean - success or failure.
764 */
765function assign_legacy_capabilities($capability, $legacyperms) {
766
767 foreach ($legacyperms as $type => $perm) {
768
769 $systemcontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
770
771 // The legacy capabilities are:
772 // 'moodle/legacy:guest'
773 // 'moodle/legacy:student'
774 // 'moodle/legacy:teacher'
775 // 'moodle/legacy:editingteacher'
776 // 'moodle/legacy:coursecreator'
777 // 'moodle/legacy:admin'
778
779 if (!$roles = get_roles_with_capability('moodle/legacy:'.$type, CAP_ALLOW)) {
780 return false;
781 }
782
783 foreach ($roles as $role) {
784 // Assign a site level capability.
785 if(!assign_capability($capability, $perm, $role->id, $systemcontext->id)) {
786 return false;
787 }
788 }
789 }
790 return true;
791}
792
793
cee0901c 794/**
795 * Checks to see if a capability is a legacy capability.
796 * @param $capabilityname
797 * @return boolean
798 */
bbbf2d40 799function islegacy($capabilityname) {
98882637 800 if (strstr($capabilityname, 'legacy') === false) {
801 return false;
802 } else {
803 return true;
804 }
bbbf2d40 805}
806
cee0901c 807
808
809/**********************************
bbbf2d40 810 * Context Manipulation functions *
811 **********************************/
812
bbbf2d40 813/**
814 * This should be called prolly everytime a user, group, module, course,
815 * coursecat or site is set up maybe?
816 * @param $level
817 * @param $instanceid
818 */
819function create_context($level, $instanceid) {
820 if (!get_record('context','level',$level,'instanceid',$instanceid)) {
821 $context = new object;
822 $context->level = $level;
823 $context->instanceid = $instanceid;
824 return insert_record('context',$context);
825 }
826}
827
828
829/**
830 * Get the context instance as an object. This function will create the
831 * context instance if it does not exist yet.
832 * @param $level
833 * @param $instance
834 */
340ea4e8 835function get_context_instance($level=NULL, $instance=SITEID) {
bbbf2d40 836
0468976c 837 global $CONTEXT, $context_cache, $context_cache_id;
e5605780 838
340ea4e8 839/// If no level is supplied then return the current global context if there is one
840 if (empty($level)) {
841 if (empty($CONTEXT)) {
842 if ($CFG->debug > 7) {
843 notify("Error: get_context_instance() called without a context");
844 }
845 } else {
846 return $CONTEXT;
847 }
e5605780 848 }
849
340ea4e8 850/// Check the cache
851 if (isset($context_cache[$level][$instance])) { // Already cached
852 return $context_cache[$level][$instance];
e5605780 853 }
854
340ea4e8 855/// Get it from the database, or create it
e5605780 856 if (!$context = get_record('context', 'level', $level, 'instanceid', $instance)) {
98882637 857 create_context($level, $instance);
858 $context = get_record('context', 'level', $level, 'instanceid', $instance);
e5605780 859 }
860
340ea4e8 861/// Update the cache
862 $context_cache[$level][$instance] = $context; // Cache it for later
863 $context_cache_id[$context->id] = $context; // Cache it for later
e5605780 864
0468976c 865
bbbf2d40 866 return $context;
867}
868
cee0901c 869
340ea4e8 870/**
871 * Get a context instance as an object, from a given id.
872 * @param $id
873 */
874function get_context_instance_by_id($id) {
875
876 if (isset($context_cache_id[$id])) { // Already cached
877 return $context_cache[$id];
878 }
879
880 if ($context = get_record('context', 'id', $id)) { // Update the cache and return
65f4d137 881 $context_cache[$context->level][$context->instanceid] = $context;
340ea4e8 882 $context_cache_id[$context->id] = $context;
883 return $context;
884 }
885
886 return false;
887}
888
bbbf2d40 889
8737be58 890/**
891 * Get the local override (if any) for a given capability in a role in a context
892 * @param $roleid
0468976c 893 * @param $contextid
894 * @param $capability
8737be58 895 */
896function get_local_override($roleid, $contextid, $capability) {
897 return get_record('role_capabilities', 'roleid', $roleid, 'capability', $capability, 'contextid', $contextid);
898}
899
900
bbbf2d40 901
902/************************************
903 * DB TABLE RELATED FUNCTIONS *
904 ************************************/
905
cee0901c 906/**
bbbf2d40 907 * function that creates a role
908 * @param name - role name
909 * @param description - role description
910 * @param legacy - optional legacy capability
911 * @return id or false
912 */
913function create_role($name, $description, $legacy='') {
98882637 914
915 // check for duplicate role name
916
917 if ($role = get_record('role','name', $name)) {
98882637 918 error('there is already a role with this name!');
919 }
920
921 $role->name = $name;
922 $role->description = $description;
923
924 if ($id = insert_record('role', $role)) {
1afecc03 925 if ($legacy) {
926 $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
927 assign_capability($legacy, CAP_ALLOW, $id, $context->id);
98882637 928 }
929 return $id;
930 } else {
931 return false;
932 }
bbbf2d40 933
934}
935
cee0901c 936
bbbf2d40 937/**
938 * Function to write context specific overrides, or default capabilities.
939 * @param module - string name
940 * @param capability - string name
941 * @param contextid - context id
942 * @param roleid - role id
943 * @param permission - int 1,-1 or -1000
944 */
945function assign_capability($capability, $permission, $roleid, $contextid) {
98882637 946
947 global $USER;
948
949 if (empty($permission) || $permission == 0) { // if permission is not set
950 unassign_capability($capability, $roleid, $contextid);
951 }
bbbf2d40 952
953 $cap = new object;
954 $cap->contextid = $contextid;
955 $cap->roleid = $roleid;
956 $cap->capability = $capability;
957 $cap->permission = $permission;
958 $cap->timemodified = time();
9db12da7 959 $cap->modifierid = empty($USER->id) ? 0 : $USER->id;
bbbf2d40 960
961 return insert_record('role_capabilities', $cap);
962}
963
964
965/**
966 * Unassign a capability from a role.
967 * @param $roleid - the role id
968 * @param $capability - the name of the capability
969 * @return boolean - success or failure
970 */
971function unassign_capability($capability, $roleid, $contextid=NULL) {
98882637 972
973 if (isset($contextid)) {
974 $status = delete_records('role_capabilities', 'capability', $capability,
975 'roleid', $roleid, 'contextid', $contextid);
976 } else {
977 $status = delete_records('role_capabilities', 'capability', $capability,
978 'roleid', $roleid);
979 }
980 return $status;
bbbf2d40 981}
982
983
984/**
985 * Get the roles that have a given capability.
986 * @param $capability - capability name (string)
987 * @param $permission - optional, the permission defined for this capability
988 * either CAP_ALLOW, CAP_PREVENT or CAP_PROHIBIT
989 * @return array or role objects
990 */
991function get_roles_with_capability($capability, $permission=NULL) {
992
993 global $CFG;
994
995 $selectroles = "SELECT r.*
996 FROM {$CFG->prefix}role AS r,
997 {$CFG->prefix}role_capabilities AS rc
998 WHERE rc.capability = '$capability'
999 AND rc.roleid = r.id";
1000
1001 if (isset($permission)) {
1002 $selectroles .= " AND rc.permission = '$permission'";
1003 }
1004 return get_records_sql($selectroles);
1005}
1006
1007
1008/**
1009 * This function makes a role-assignment (user to a role)
1010 * @param $roleid - the role of the id
1011 * @param $userid - userid
1012 * @param $groupid - group id
1013 * @param $contextid - id of the context
1014 * @param $timestart - time this assignment becomes effective
1015 * @param $timeend - time this assignemnt ceases to be effective
1016 * @uses $USER
1017 * @return id - new id of the assigment
1018 */
1019function role_assign($roleid, $userid, $groupid, $contextid, $timestart=0, $timeend=0, $hidden=0) {
aa311411 1020 global $USER, $CFG;
bbbf2d40 1021
218564ac 1022 if ($CFG->debug > 7) {
98882637 1023 notify("Assign roleid $roleid userid $userid contextid $contextid", 'notifytiny');
aa311411 1024 }
bbbf2d40 1025
1026 if (empty($roleid)) {
1027 error ('you need to select a role');
1028 }
1029
1030 if (empty($userid) && empty($groupid)) {
1031 error ('you need to assign this role to a user or a group');
1032 }
1033
1034 if (empty($contextid)) {
1035 error ('you need to assign this role to a context, e.g. a course, or an activity');
1036 }
1037
1038 $ra = new object;
1039 $ra->roleid = $roleid;
1040 $ra->contextid = $contextid;
1041 $ra->userid = $userid;
1042 $ra->hidden = $hidden;
1043 $ra->groupid = $groupid;
1044 $ra->timestart = $timestart;
1045 $ra->timeend = $timeend;
1046 $ra->timemodified = time();
9db12da7 1047 $ra->modifier = empty($USER->id) ? 0 : $USER->id;
bbbf2d40 1048
1049 return insert_record('role_assignments', $ra);
1050
1051}
1052
1053
1054/**
1055 * Deletes a role assignment.
1056 * @param $roleid
1057 * @param $userid
1058 * @param $groupid
1059 * @param $contextid
1060 * @return boolean - success or failure
1061 */
1062function role_unassign($roleid, $userid, $groupid, $contextid) {
98882637 1063 if ($groupid) {
1064 // do nothing yet as this is not implemented
1065 }
1066 else {
1067 return delete_records('role_assignments', 'userid', $userid,
1068 'roleid', $roleid, 'contextid', $contextid);
1069 }
bbbf2d40 1070}
1071
1072
1073/**
1074 * Loads the capability definitions for the component (from file). If no
1075 * capabilities are defined for the component, we simply return an empty array.
1076 * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
1077 * @return array of capabilities
1078 */
1079function load_capability_def($component) {
1080 global $CFG;
1081
1082 if ($component == 'moodle') {
1083 $defpath = $CFG->libdir.'/db/access.php';
1084 $varprefix = 'moodle';
1085 } else {
1086 $defpath = $CFG->dirroot.'/'.$component.'/db/access.php';
1087 $varprefix = str_replace('/', '_', $component);
1088 }
1089 $capabilities = array();
1090
1091 if (file_exists($defpath)) {
1092 require_once($defpath);
1093 $capabilities = ${$varprefix.'_capabilities'};
1094 }
1095 return $capabilities;
1096}
1097
1098
1099/**
1100 * Gets the capabilities that have been cached in the database for this
1101 * component.
1102 * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
1103 * @return array of capabilities
1104 */
1105function get_cached_capabilities($component='moodle') {
1106 if ($component == 'moodle') {
1107 $storedcaps = get_records_select('capabilities',
1108 "name LIKE 'moodle/%:%'");
1109 } else {
1110 $storedcaps = get_records_select('capabilities',
1111 "name LIKE '$component:%'");
1112 }
1113 return $storedcaps;
1114}
1115
1116
1117/**
1118 * Updates the capabilities table with the component capability definitions.
1119 * If no parameters are given, the function updates the core moodle
1120 * capabilities.
1121 *
1122 * Note that the absence of the db/access.php capabilities definition file
1123 * will cause any stored capabilities for the component to be removed from
1124 * the database.
1125 *
1126 * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
1127 * @return boolean
1128 */
1129function update_capabilities($component='moodle') {
1130
1131 $storedcaps = array();
1132 $filecaps = array();
1133
1134 $cachedcaps = get_cached_capabilities($component);
1135 if ($cachedcaps) {
1136 foreach ($cachedcaps as $cachedcap) {
1137 array_push($storedcaps, $cachedcap->name);
1138 }
1139 }
1140
1141 $filecaps = load_capability_def($component);
1142
1143 // Are there new capabilities in the file definition?
1144 $newcaps = array();
1145
1146 foreach ($filecaps as $filecap => $def) {
1147 if (!$storedcaps ||
1148 ($storedcaps && in_array($filecap, $storedcaps) === false)) {
1149 $newcaps[$filecap] = $def;
1150 }
1151 }
1152 // Add new capabilities to the stored definition.
1153 foreach ($newcaps as $capname => $capdef) {
1154 $capability = new object;
1155 $capability->name = $capname;
1156 $capability->captype = $capdef['captype'];
1157 $capability->contextlevel = $capdef['contextlevel'];
1158 $capability->component = $component;
1159
1160 if (!insert_record('capabilities', $capability, false, 'id')) {
1161 return false;
1162 }
1163 // Do we need to assign the new capabilities to roles that have the
1164 // legacy capabilities moodle/legacy:* as well?
1165 if (isset($capdef['legacy']) && is_array($capdef['legacy']) &&
1166 !assign_legacy_capabilities($capname, $capdef['legacy'])) {
1167 error('Could not assign legacy capabilities');
1168 return false;
1169 }
1170 }
1171 // Are there any capabilities that have been removed from the file
1172 // definition that we need to delete from the stored capabilities and
1173 // role assignments?
1174 capabilities_cleanup($component, $filecaps);
1175
1176 return true;
1177}
1178
1179
1180/**
1181 * Deletes cached capabilities that are no longer needed by the component.
1182 * Also unassigns these capabilities from any roles that have them.
1183 * @param $component - examples: 'moodle', 'mod/forum', 'block/quiz_results'
1184 * @param $newcapdef - array of the new capability definitions that will be
1185 * compared with the cached capabilities
1186 * @return int - number of deprecated capabilities that have been removed
1187 */
1188function capabilities_cleanup($component, $newcapdef=NULL) {
1189
1190 $removedcount = 0;
1191
1192 if ($cachedcaps = get_cached_capabilities($component)) {
1193 foreach ($cachedcaps as $cachedcap) {
1194 if (empty($newcapdef) ||
1195 array_key_exists($cachedcap->name, $newcapdef) === false) {
1196
1197 // Remove from capabilities cache.
1198 if (!delete_records('capabilities', 'name', $cachedcap->name)) {
1199 error('Could not delete deprecated capability '.$cachedcap->name);
1200 } else {
1201 $removedcount++;
1202 }
1203 // Delete from roles.
1204 if($roles = get_roles_with_capability($cachedcap->name)) {
1205 foreach($roles as $role) {
1206 if (!unassign_capability($role->id, $cachedcap->name)) {
1207 error('Could not unassign deprecated capability '.
1208 $cachedcap->name.' from role '.$role->name);
1209 }
1210 }
1211 }
1212 } // End if.
1213 }
1214 }
1215 return $removedcount;
1216}
1217
1218
1219
cee0901c 1220/****************
1221 * UI FUNCTIONS *
1222 ****************/
bbbf2d40 1223
1224
1225/**
1226 * prints human readable context identifier.
1227 */
0468976c 1228function print_context_name($context) {
340ea4e8 1229
ec0810ee 1230 $name = '';
1231
340ea4e8 1232 switch ($context->level) {
ec0810ee 1233
bbbf2d40 1234 case CONTEXT_SYSTEM: // by now it's a definite an inherit
ec0810ee 1235 $name = get_string('site');
340ea4e8 1236 break;
bbbf2d40 1237
1238 case CONTEXT_PERSONAL:
ec0810ee 1239 $name = get_string('personal');
340ea4e8 1240 break;
1241
bbbf2d40 1242 case CONTEXT_USERID:
ec0810ee 1243 if ($user = get_record('user', 'id', $context->instanceid)) {
1244 $name = get_string('user').': '.fullname($user);
1245 }
340ea4e8 1246 break;
1247
bbbf2d40 1248 case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
ec0810ee 1249 if ($category = get_record('course_categories', 'id', $context->instanceid)) {
1250 $name = get_string('category').': '.$category->name;
1251 }
340ea4e8 1252 break;
bbbf2d40 1253
1254 case CONTEXT_COURSE: // 1 to 1 to course cat
ec0810ee 1255 if ($course = get_record('course', 'id', $context->instanceid)) {
1256 $name = get_string('course').': '.$course->fullname;
1257 }
340ea4e8 1258 break;
bbbf2d40 1259
1260 case CONTEXT_GROUP: // 1 to 1 to course
ec0810ee 1261 if ($group = get_record('groups', 'id', $context->instanceid)) {
1262 $name = get_string('group').': '.$group->name;
1263 }
340ea4e8 1264 break;
bbbf2d40 1265
1266 case CONTEXT_MODULE: // 1 to 1 to course
98882637 1267 if ($cm = get_record('course_modules','id',$context->instanceid)) {
1268 if ($module = get_record('modules','id',$cm->module)) {
1269 if ($mod = get_record($module->name, 'id', $cm->instance)) {
ec0810ee 1270 $name = get_string('activitymodule').': '.$mod->name;
98882637 1271 }
ec0810ee 1272 }
1273 }
340ea4e8 1274 break;
bbbf2d40 1275
1276 case CONTEXT_BLOCK: // 1 to 1 to course
98882637 1277 if ($blockinstance = get_record('block_instance','id',$context->instanceid)) {
1278 if ($block = get_record('block','id',$blockinstance->blockid)) {
ec0810ee 1279 $name = get_string('blocks').': '.get_string($block->name, 'block_'.$block->name);
1280 }
1281 }
340ea4e8 1282 break;
bbbf2d40 1283
1284 default:
1285 error ('This is an unknown context!');
340ea4e8 1286 return false;
1287
1288 }
1289
1290 return $name;
bbbf2d40 1291}
1292
1293
1294/**
1295 * Extracts the relevant capabilities given a contextid.
1296 * All case based, example an instance of forum context.
1297 * Will fetch all forum related capabilities, while course contexts
1298 * Will fetch all capabilities
0468976c 1299 * @param object context
bbbf2d40 1300 * @return array();
1301 *
1302 * capabilities
1303 * `name` varchar(150) NOT NULL,
1304 * `captype` varchar(50) NOT NULL,
1305 * `contextlevel` int(10) NOT NULL,
1306 * `component` varchar(100) NOT NULL,
1307 */
0468976c 1308function fetch_context_capabilities($context) {
98882637 1309
1310 global $CFG;
bbbf2d40 1311
1312 $sort = 'ORDER BY contextlevel,component,id'; // To group them sensibly for display
98882637 1313
0468976c 1314 switch ($context->level) {
bbbf2d40 1315
98882637 1316 case CONTEXT_SYSTEM: // all
1317 $SQL = "select * from {$CFG->prefix}capabilities";
bbbf2d40 1318 break;
1319
1320 case CONTEXT_PERSONAL:
1321 break;
1322
1323 case CONTEXT_USERID:
1324 break;
1325
1326 case CONTEXT_COURSECAT: // all
98882637 1327 $SQL = "select * from {$CFG->prefix}capabilities";
bbbf2d40 1328 break;
1329
1330 case CONTEXT_COURSE: // all
98882637 1331 $SQL = "select * from {$CFG->prefix}capabilities";
bbbf2d40 1332 break;
1333
1334 case CONTEXT_GROUP: // group caps
1335 break;
1336
1337 case CONTEXT_MODULE: // mod caps
98882637 1338 $cm = get_record('course_modules', 'id', $context->instanceid);
1339 $module = get_record('modules', 'id', $cm->module);
bbbf2d40 1340
98882637 1341 $SQL = "select * from {$CFG->prefix}capabilities where contextlevel = ".CONTEXT_MODULE."
1342 and component = 'mod/$module->name'";
bbbf2d40 1343 break;
1344
1345 case CONTEXT_BLOCK: // block caps
98882637 1346 $cb = get_record('block_instance', 'id', $context->instanceid);
1347 $block = get_record('block', 'id', $cb->blockid);
bbbf2d40 1348
98882637 1349 $SQL = "select * from {$CFG->prefix}capabilities where contextlevel = ".CONTEXT_BLOCK."
1350 and component = 'block/$block->name'";
bbbf2d40 1351 break;
1352
1353 default:
1354 return false;
1355 }
1356
1357 $records = get_records_sql($SQL.' '.$sort);
1358 return $records;
1359
1360}
1361
1362
1363/**
1364 * This function pulls out all the resolved capabilities (overrides and
1365 * defaults) of a role used in capability overrieds in contexts at a given
1366 * context.
0468976c 1367 * @param int $context
bbbf2d40 1368 * @param int $roleid
1369 * @return array
1370 */
0468976c 1371function role_context_capabilities($roleid, $context) {
98882637 1372 global $CFG;
1373
1374 $sitecontext = get_context_instance(CONTEXT_SYSTEM, SITEID);
0468976c 1375 if ($sitecontext->id == $context->id) {
98882637 1376 return array();
1377 }
1378
1379 // first of all, figure out all parental contexts
98882637 1380 $contexts = array_reverse(get_parent_contexts($context));
1381 $contexts = '('.implode(',', $contexts).')';
1382
1383 $SQL = "SELECT rc.* FROM {$CFG->prefix}role_capabilities rc, {$CFG->prefix}context c
1384 where rc.contextid in $contexts
1385 and rc.roleid = $roleid
1386 and rc.contextid = c.id
1387 ORDER BY c.level DESC, rc.capability DESC";
1388
1389 $records = get_records_sql($SQL);
1390
1391 $capabilities = array();
1392
1393 // We are traversing via reverse order.
1394 foreach ($records as $record) {
1395 // If not set yet (i.e. inherit or not set at all), or currently we have a prohibit
1396 if (!isset($capabilities[$record->capability]) || $record->permission<-500) {
1397 $capabilities[$record->capability] = $record->permission;
1398 }
1399 }
1400 return $capabilities;
bbbf2d40 1401}
1402
1403
1404/**
0468976c 1405 * Recursive function which, given a context, find all parent context ids,
bbbf2d40 1406 * and return the array in reverse order, i.e. parent first, then grand
1407 * parent, etc.
1408 * @param object $context
1409 * @return array()
1410 */
bbbf2d40 1411function get_parent_contexts($context) {
1412
0468976c 1413 switch ($context->level) {
bbbf2d40 1414
1415 case CONTEXT_SYSTEM: // no parent
98882637 1416 return null;
bbbf2d40 1417 break;
1418
1419 case CONTEXT_PERSONAL:
1420 $parent = get_context_instance(CONTEXT_SYSTEM, SITEID);
1421 return array($parent->id);
1422 break;
1423
1424 case CONTEXT_USERID:
1425 $parent = get_context_instance(CONTEXT_SYSTEM, SITEID);
1426 return array($parent->id);
1427 break;
1428
1429 case CONTEXT_COURSECAT: // Coursecat -> coursecat or site
1430 $coursecat = get_record('course_categories','id',$context->instanceid);
1431 if ($coursecat->parent) { // return parent value if exist
1432 $parent = get_context_instance(CONTEXT_COURSECAT, $coursecat->parent);
1433 return array_merge(array($parent->id), get_parent_contexts($parent));
1434 } else { // else return site value
1435 $parent = get_context_instance(CONTEXT_SYSTEM, SITEID);
1436 return array($parent->id);
1437 }
1438 break;
1439
1440 case CONTEXT_COURSE: // 1 to 1 to course cat
1441 // find the course cat, and return its value
1442 $course = get_record('course','id',$context->instanceid);
1443 $parent = get_context_instance(CONTEXT_COURSECAT, $course->category);
1444 return array_merge(array($parent->id), get_parent_contexts($parent));
1445 break;
1446
1447 case CONTEXT_GROUP: // 1 to 1 to course
1448 $group = get_record('groups','id',$context->instanceid);
1449 $parent = get_context_instance(CONTEXT_COURSE, $group->courseid);
1450 return array_merge(array($parent->id), get_parent_contexts($parent));
1451 break;
1452
1453 case CONTEXT_MODULE: // 1 to 1 to course
1454 $cm = get_record('course_modules','id',$context->instanceid);
1455 $parent = get_context_instance(CONTEXT_COURSE, $cm->course);
1456 return array_merge(array($parent->id), get_parent_contexts($parent));
1457 break;
1458
1459 case CONTEXT_BLOCK: // 1 to 1 to course
1460 $block = get_record('block_instance','id',$context->instanceid);
1461 $parent = get_context_instance(CONTEXT_COURSE, $block->pageid); // needs check
1462 return array_merge(array($parent->id), get_parent_contexts($parent));
1463 break;
1464
1465 default:
1466 error ('This is an unknown context!');
1467 return false;
1468 }
1469
1470}
1471
1472
1473/**
1474 * This function gets the capability of a role in a given context.
1475 * It is needed when printing override forms.
1476 * @param int $contextid
bbbf2d40 1477 * @param string $capability
1478 * @param array $capabilities - array loaded using role_context_capabilities
1479 * @return int (allow, prevent, prohibit, inherit)
1480 */
bbbf2d40 1481function get_role_context_capability($contextid, $capability, $capabilities) {
98882637 1482 return $capabilities[$contextid][$capability];
bbbf2d40 1483}
1484
1485
cee0901c 1486/**
1487 * Returns the human-readable, translated version of the capability.
1488 * Basically a big switch statement.
1489 * @param $capabilityname - e.g. mod/choice:readresponses
1490 */
ceb83c70 1491function get_capability_string($capabilityname) {
bbbf2d40 1492
cee0901c 1493 // Typical capabilityname is mod/choice:readresponses
ceb83c70 1494
1495 $names = split('/', $capabilityname);
1496 $stringname = $names[1]; // choice:readresponses
1497 $components = split(':', $stringname);
1498 $componentname = $components[0]; // choice
98882637 1499
1500 switch ($names[0]) {
1501 case 'mod':
ceb83c70 1502 $string = get_string($stringname, $componentname);
98882637 1503 break;
1504
1505 case 'block':
ceb83c70 1506 $string = get_string($stringname, 'block_'.$componentname);
98882637 1507 break;
ceb83c70 1508
98882637 1509 case 'moodle':
ceb83c70 1510 $string = get_string($stringname, 'role');
98882637 1511 break;
1512
1513 case 'enrol':
ceb83c70 1514 $string = get_string($stringname, 'enrol_'.$componentname);
1515 break;
98882637 1516
1517 default:
ceb83c70 1518 $string = get_string($stringname);
98882637 1519 break;
98882637 1520
1521 }
ceb83c70 1522 return $string;
bbbf2d40 1523}
1524
1525
cee0901c 1526/**
1527 * This gets the mod/block/course/core etc strings.
1528 * @param $component
1529 * @param $contextlevel
1530 */
bbbf2d40 1531function get_component_string($component, $contextlevel) {
1532
98882637 1533 switch ($contextlevel) {
bbbf2d40 1534
98882637 1535 case CONTEXT_SYSTEM:
ceb83c70 1536 $string = get_string('coresystem');
bbbf2d40 1537 break;
1538
1539 case CONTEXT_PERSONAL:
98882637 1540 $string = get_string('personal');
bbbf2d40 1541 break;
1542
1543 case CONTEXT_USERID:
98882637 1544 $string = get_string('users');
bbbf2d40 1545 break;
1546
1547 case CONTEXT_COURSECAT:
98882637 1548 $string = get_string('categories');
bbbf2d40 1549 break;
1550
1551 case CONTEXT_COURSE:
98882637 1552 $string = get_string('course');
bbbf2d40 1553 break;
1554
1555 case CONTEXT_GROUP:
98882637 1556 $string = get_string('group');
bbbf2d40 1557 break;
1558
1559 case CONTEXT_MODULE:
98882637 1560 $string = get_string('modulename', basename($component));
bbbf2d40 1561 break;
1562
1563 case CONTEXT_BLOCK:
98882637 1564 $string = get_string('blockname', 'block_'.$component.'.php');
bbbf2d40 1565 break;
1566
1567 default:
1568 error ('This is an unknown context!');
1569 return false;
98882637 1570
1571 }
98882637 1572 return $string;
bbbf2d40 1573}
cee0901c 1574
1575
e4dd3222 1576function get_roles_used_in_context($context) {
1577
1578 global $CFG;
1579
1580 return get_records_sql('SELECT distinct r.id, r.name
1581 FROM '.$CFG->prefix.'role_assignments ra,
1582 '.$CFG->prefix.'role r
1583 WHERE r.id = ra.roleid
1584 AND ra.contextid = '.$context->id.'
1585 ORDER BY r.sortorder ASC');
1586}
1587
1588
1589?>