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