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