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