2007-08-06 17:55:44 +00:00
< ? php // $Id$
///////////////////////////////////////////////////////////////////////////
// //
// NOTICE OF COPYRIGHT //
// //
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
// http://moodle.org //
// //
2007-10-10 05:25:14 +00:00
// Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com //
2007-08-06 17:55:44 +00:00
// //
// This program is free software; you can redistribute it and/or modify //
// it under the terms of the GNU General Public License as published by //
// the Free Software Foundation; either version 2 of the License, or //
// (at your option) any later version. //
// //
// This program is distributed in the hope that it will be useful, //
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
// GNU General Public License for more details: //
// //
// http://www.gnu.org/copyleft/gpl.html //
// //
///////////////////////////////////////////////////////////////////////////
2007-09-19 07:15:27 +00:00
/**
* Public API vs internals
* -----------------------
*
* General users probably only care about
*
2007-09-19 07:57:10 +00:00
* Context handling
* - get_context_instance ()
* - get_context_instance_by_id ()
* - get_parent_contexts ()
* - get_child_contexts ()
*
* Whether the user can do something ...
2007-09-19 07:15:27 +00:00
* - has_capability ()
2007-09-19 07:24:43 +00:00
* - require_capability ()
2007-09-19 07:57:10 +00:00
* - require_login () ( from moodlelib )
*
* What courses has this user access to ?
2007-09-19 07:15:27 +00:00
* - get_user_courses_bycap ()
2007-09-19 07:57:10 +00:00
*
* What users can do X in this course or context ?
2007-09-19 07:23:30 +00:00
* - get_context_users_bycap ()
2007-09-19 07:57:10 +00:00
* - get_context_users_byrole ()
*
* Enrol / unenrol
2007-09-19 07:25:10 +00:00
* - enrol_into_course ()
* - role_assign () / role_unassign ()
2007-09-19 07:57:10 +00:00
*
2007-09-19 07:15:27 +00:00
*
* Advanced use
2007-09-19 07:57:10 +00:00
* - load_all_capabilities ()
* - reload_all_capabilities ()
2007-09-19 07:15:27 +00:00
* - $ACCESS global
2007-09-20 04:52:54 +00:00
* - has_capability_in_accessdata ()
2007-09-19 07:57:10 +00:00
* - is_siteadmin ()
* - get_user_access_sitewide ()
2007-10-17 09:19:39 +00:00
* - load_subcontext ()
2007-09-19 07:57:10 +00:00
* - get_role_access_bycontext ()
*
* Name conventions
* ----------------
*
* - " ctx " means context
2007-09-19 07:15:27 +00:00
*
* accessdata
* ----------
*
* Access control data is held in the " accessdata " array
* which - for the logged - in user , will be in $USER -> access
*
* For other users can be generated and passed around ( but see
* the $ACCESS global ) .
*
2007-09-20 04:52:54 +00:00
* $accessdata is a multidimensional array , holding
2007-09-19 07:15:27 +00:00
* role assignments ( RAs ), role - capabilities - perm sets
2007-09-19 07:15:50 +00:00
* ( role defs ) and a list of courses we have loaded
2007-09-19 07:15:27 +00:00
* data for .
*
* Things are keyed on " contextpaths " ( the path field of
* the context table ) for fast walking up / down the tree .
*
2007-09-20 04:52:54 +00:00
* $accessdata [ ra ][ $contextpath ] = array ( $roleid )
* [ $contextpath ] = array ( $roleid )
* [ $contextpath ] = array ( $roleid )
2007-09-19 07:15:27 +00:00
*
* Role definitions are stored like this
* ( no cap merge is done - so it ' s compact )
*
2007-09-20 04:52:54 +00:00
* $accessdata [ rdef ][ $contextpath : $roleid ][ mod / forum : viewpost ] = 1
* [ mod / forum : editallpost ] = - 1
* [ mod / forum : startdiscussion ] = - 1000
2007-09-19 07:15:27 +00:00
*
2007-09-20 04:52:54 +00:00
* See how has_capability_in_accessdata () walks up / down the tree .
2007-09-19 07:15:27 +00:00
*
* Normally - specially for the logged - in user , we only load
* rdef and ra down to the course level , but not below . This
* keeps accessdata small and compact . Below - the - course ra / rdef
* are loaded as needed . We keep track of which courses we
* have loaded ra / rdef in
*
2007-09-20 04:52:54 +00:00
* $accessdata [ loaded ] = array ( $contextpath , $contextpath )
2007-09-19 07:15:27 +00:00
*
* Stale accessdata
* ----------------
*
* For the logged - in user , accessdata is long - lived .
*
* On each pageload we load $DIRTYPATHS which lists
* context paths affected by changes . Any check at - or - below
* a dirty context will trigger a transparent reload of accessdata .
*
* Changes at the sytem level will force the reload for everyone .
*
* Default role caps
* -----------------
* The default role assignment is not in the DB , so we
* add it manually to accessdata .
*
* This means that functions that work directly off the
* DB need to ensure that the default role caps
* are dealt with appropriately .
*
*/
2006-08-08 05:13:06 +00:00
2007-02-09 02:24:59 +00:00
require_once $CFG -> dirroot . '/lib/blocklib.php' ;
2006-08-08 05:13:06 +00:00
// permission definitions
2006-09-15 06:07:29 +00:00
define ( 'CAP_INHERIT' , 0 );
2006-08-08 05:13:06 +00:00
define ( 'CAP_ALLOW' , 1 );
define ( 'CAP_PREVENT' , - 1 );
define ( 'CAP_PROHIBIT' , - 1000 );
// context definitions
define ( 'CONTEXT_SYSTEM' , 10 );
define ( 'CONTEXT_PERSONAL' , 20 );
2006-09-15 14:09:16 +00:00
define ( 'CONTEXT_USER' , 30 );
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_COURSECAT' , 40 );
define ( 'CONTEXT_COURSE' , 50 );
define ( 'CONTEXT_GROUP' , 60 );
define ( 'CONTEXT_MODULE' , 70 );
define ( 'CONTEXT_BLOCK' , 80 );
2006-09-18 21:32:49 +00:00
// capability risks - see http://docs.moodle.org/en/Hardening_new_Roles_system
define ( 'RISK_MANAGETRUST' , 0x0001 );
2006-09-19 07:33:22 +00:00
define ( 'RISK_CONFIG' , 0x0002 );
2006-09-18 21:32:49 +00:00
define ( 'RISK_XSS' , 0x0004 );
define ( 'RISK_PERSONAL' , 0x0008 );
define ( 'RISK_SPAM' , 0x0010 );
2007-01-04 13:15:04 +13:00
require_once ( $CFG -> dirroot . '/group/lib.php' );
2006-09-18 21:32:49 +00:00
2006-08-13 15:48:57 +00:00
$context_cache = array (); // Cache of all used context objects for performance (by level and instance)
$context_cache_id = array (); // Index to above cache by id
2006-08-08 05:13:06 +00:00
2007-10-09 12:49:54 +00:00
$DIRTYCONTEXTS = null ; // dirty contexts cache
$ACCESS = array (); // cache of caps for cron user switching and has_capability for other users (==not $USER)
2007-10-17 09:19:39 +00:00
$RDEFS = array (); // role definitions cache - helps a lot with mem usage in cron
2006-09-03 07:56:40 +00:00
2007-03-07 13:45:41 +00:00
function get_role_context_caps ( $roleid , $context ) {
//this is really slow!!!! - do not use above course context level!
$result = array ();
$result [ $context -> id ] = array ();
2006-09-12 06:15:33 +00:00
2007-03-07 13:45:41 +00:00
// first emulate the parent context capabilities merging into context
$searchcontexts = array_reverse ( get_parent_contexts ( $context ));
array_push ( $searchcontexts , $context -> id );
foreach ( $searchcontexts as $cid ) {
if ( $capabilities = get_records_select ( 'role_capabilities' , " roleid = $roleid AND contextid = $cid " )) {
foreach ( $capabilities as $cap ) {
if ( ! array_key_exists ( $cap -> capability , $result [ $context -> id ])) {
$result [ $context -> id ][ $cap -> capability ] = 0 ;
}
$result [ $context -> id ][ $cap -> capability ] += $cap -> permission ;
}
}
}
2006-09-12 06:15:33 +00:00
2007-03-07 13:45:41 +00:00
// now go through the contexts bellow given context
2007-09-19 06:52:34 +00:00
$searchcontexts = array_keys ( get_child_contexts ( $context ));
2007-03-07 13:45:41 +00:00
foreach ( $searchcontexts as $cid ) {
if ( $capabilities = get_records_select ( 'role_capabilities' , " roleid = $roleid AND contextid = $cid " )) {
foreach ( $capabilities as $cap ) {
if ( ! array_key_exists ( $cap -> contextid , $result )) {
$result [ $cap -> contextid ] = array ();
}
$result [ $cap -> contextid ][ $cap -> capability ] = $cap -> permission ;
}
}
2006-09-12 06:15:33 +00:00
}
2007-03-07 13:45:41 +00:00
return $result ;
}
/**
2007-09-19 07:16:29 +00:00
* Gets the accessdata for role " sitewide "
* ( system down to course )
*
2007-09-19 07:02:57 +00:00
* @ return array
2007-03-07 13:45:41 +00:00
*/
2007-09-20 04:52:54 +00:00
function get_role_access ( $roleid , $accessdata = NULL ) {
2007-02-09 02:24:59 +00:00
2007-09-19 07:02:57 +00:00
global $CFG ;
2007-03-07 13:45:41 +00:00
2007-09-19 07:02:57 +00:00
/* Get it in 1 cheap DB query ...
* - relevant role caps at the root and down
* to the course level - but not below
*/
2007-09-20 04:52:54 +00:00
if ( is_null ( $accessdata )) {
$accessdata = array (); // named list
$accessdata [ 'ra' ] = array ();
$accessdata [ 'rdef' ] = array ();
$accessdata [ 'loaded' ] = array ();
2006-09-12 06:15:33 +00:00
}
2007-09-19 07:02:57 +00:00
$base = '/' . SYSCONTEXTID ;
//
// Overrides for the role IN ANY CONTEXTS
// down to COURSE - not below -
//
$sql = " SELECT ctx.path,
rc . capability , rc . permission
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } role_capabilities rc
ON rc . contextid = ctx . id
WHERE rc . roleid = { $roleid }
AND ctx . contextlevel <= " .CONTEXT_COURSE. "
ORDER BY ctx . depth , ctx . path " ;
2007-09-24 19:00:39 +00:00
if ( $rs = get_recordset_sql ( $sql )) {
2007-10-10 12:19:27 +00:00
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
2007-09-19 07:02:57 +00:00
}
2007-10-10 12:19:27 +00:00
unset ( $rd );
2007-09-24 19:00:39 +00:00
rs_close ( $rs );
2007-01-28 20:52:57 +00:00
}
2007-09-19 07:02:57 +00:00
2007-09-20 04:52:54 +00:00
return $accessdata ;
2006-09-12 06:15:33 +00:00
}
2007-09-26 07:12:38 +00:00
/**
* Gets the accessdata for role " sitewide "
* ( system down to course )
*
* @ return array
*/
function get_default_frontpage_role_access ( $roleid , $accessdata = NULL ) {
global $CFG ;
$frontpagecontext = get_context_instance ( CONTEXT_COURSE , SITEID );
$base = '/' . SYSCONTEXTID . '/' . $frontpagecontext -> id ;
//
// Overrides for the role in any contexts related to the course
//
$sql = " SELECT ctx.path,
rc . capability , rc . permission
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } role_capabilities rc
ON rc . contextid = ctx . id
WHERE rc . roleid = { $roleid }
AND ( ctx . id = " .SYSCONTEXTID. " OR ctx . path LIKE '$base/%' )
2007-09-26 07:19:30 +00:00
AND ctx . contextlevel <= " .CONTEXT_COURSE. "
2007-09-26 07:12:38 +00:00
ORDER BY ctx . depth , ctx . path " ;
if ( $rs = get_recordset_sql ( $sql )) {
2007-10-10 12:19:27 +00:00
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
2007-09-26 07:12:38 +00:00
}
2007-10-10 12:19:27 +00:00
unset ( $rd );
2007-09-26 07:12:38 +00:00
rs_close ( $rs );
}
return $accessdata ;
}
2006-09-14 09:39:23 +00:00
/**
* Get the default guest role
* @ return object role
*/
function get_guest_role () {
2007-02-01 10:24:26 +00:00
global $CFG ;
if ( empty ( $CFG -> guestroleid )) {
if ( $roles = get_roles_with_capability ( 'moodle/legacy:guest' , CAP_ALLOW )) {
$guestrole = array_shift ( $roles ); // Pick the first one
set_config ( 'guestroleid' , $guestrole -> id );
return $guestrole ;
} else {
debugging ( 'Can not find any guest role!' );
return false ;
}
2006-09-14 09:39:23 +00:00
} else {
2007-02-01 10:24:26 +00:00
if ( $guestrole = get_record ( 'role' , 'id' , $CFG -> guestroleid )) {
return $guestrole ;
} else {
//somebody is messing with guest roles, remove incorrect setting and try to find a new one
set_config ( 'guestroleid' , '' );
return get_guest_role ();
}
2006-09-14 09:39:23 +00:00
}
}
2007-10-09 12:49:54 +00:00
/**
* This function returns whether the current user has the capability of performing a function
* For example , we can do has_capability ( 'mod/forum:replypost' , $context ) in forum
* @ param string $capability - name of the capability ( or debugcache or clearcache )
* @ param object $context - a context object ( record from context table )
* @ param integer $userid - a userid number , empty if current $USER
* @ param bool $doanything - if false , ignore do anything
* @ return bool
*/
2007-10-05 15:06:38 +00:00
function has_capability ( $capability , $context , $userid = NULL , $doanything = true ) {
global $USER , $ACCESS , $CFG , $DIRTYCONTEXTS ;
2007-09-19 07:02:31 +00:00
2007-10-05 15:06:38 +00:00
// the original $CONTEXT here was hiding serious errors
2007-10-09 12:49:54 +00:00
// for security reasons do not reuse previous context
2007-10-05 15:06:38 +00:00
if ( empty ( $context )) {
debugging ( 'Incorrect context specified' );
return false ;
2007-09-19 07:02:44 +00:00
}
2007-09-19 07:02:31 +00:00
2007-10-09 12:49:54 +00:00
if ( empty ( $userid )) { // we must accept null, 0, '0', '' etc. in $userid
2007-09-19 07:02:31 +00:00
$userid = $USER -> id ;
}
2007-10-09 12:49:54 +00:00
if ( is_null ( $context -> path ) or $context -> depth == 0 ) {
//this should not happen
$contexts = array ( SYSCONTEXTID , $context -> id );
$context -> path = '/' . SYSCONTEXTID . '/' . $context -> id ;
debugging ( 'Context id ' . $context -> id . ' does not have valid path, please use build_context_path()' , DEBUG_DEVELOPER );
2007-09-19 07:02:31 +00:00
} else {
$contexts = explode ( '/' , $context -> path );
array_shift ( $contexts );
}
2007-10-09 12:49:54 +00:00
if ( defined ( 'FULLME' ) && FULLME === 'cron' && ! isset ( $USER -> access )) {
2007-09-19 07:20:24 +00:00
// In cron, some modules setup a 'fake' $USER,
// ensure we load the appropriate accessdata.
2007-10-09 12:49:54 +00:00
if ( isset ( $ACCESS [ $userid ])) {
$DIRTYCONTEXTS = NULL ; //load fresh dirty contexts
} else {
2007-09-19 07:20:24 +00:00
load_user_accessdata ( $userid );
2007-10-09 12:49:54 +00:00
$DIRTYCONTEXTS = array ();
2007-09-19 07:20:24 +00:00
}
$USER -> access = $ACCESS [ $userid ];
2007-10-05 15:06:38 +00:00
2007-10-09 12:49:54 +00:00
} else if ( $USER -> id == $userid && ! isset ( $USER -> access )) {
2007-10-05 15:06:38 +00:00
// caps not loaded yet - better to load them to keep BC with 1.8
2007-10-09 12:49:54 +00:00
// not-logged-in user or $USER object set up manually first time here
2007-10-05 15:06:38 +00:00
load_all_capabilities ();
2007-10-09 12:49:54 +00:00
$ACCESS = array (); // reset the cache for other users too, the dirty contexts are empty now
2007-10-17 09:19:39 +00:00
$RDEFS = array ();
2007-09-19 07:20:24 +00:00
}
2007-10-09 12:49:54 +00:00
// Load dirty contexts list if needed
2007-09-19 07:10:24 +00:00
if ( ! isset ( $DIRTYCONTEXTS )) {
2007-11-16 03:34:05 +00:00
if ( isset ( $USER -> access [ 'time' ])) {
$DIRTYCONTEXTS = get_dirty_contexts ( $USER -> access [ 'time' ]);
}
else {
$DIRTYCONTEXTS = array ();
}
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
// Careful check for staleness...
if ( count ( $DIRTYCONTEXTS ) !== 0 and is_contextpath_dirty ( $contexts , $DIRTYCONTEXTS )) {
2007-09-19 07:11:18 +00:00
// reload all capabilities - preserving loginas, roleswitches, etc
// and then cleanup any marks of dirtyness... at least from our short
// term memory! :-)
2007-10-09 12:49:54 +00:00
$ACCESS = array ();
2007-10-17 09:19:39 +00:00
$RDEFS = array ();
2007-10-09 12:49:54 +00:00
if ( defined ( 'FULLME' ) && FULLME === 'cron' ) {
load_user_accessdata ( $userid );
$USER -> access = $ACCESS [ $userid ];
$DIRTYCONTEXTS = array ();
} else {
reload_all_capabilities ();
}
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
2007-09-19 07:03:34 +00:00
// divulge how many times we are called
//// error_log("has_capability: id:{$context->id} path:{$context->path} userid:$userid cap:$capability");
2007-10-09 12:49:54 +00:00
if ( $USER -> id == $userid ) { // we must accept strings and integers in $userid
2007-09-19 07:02:44 +00:00
//
// For the logged in user, we have $USER->access
// which will have all RAs and caps preloaded for
// course and above contexts.
//
// Contexts below courses && contexts that do not
// hang from courses are loaded into $USER->access
// on demand, and listed in $USER->access[loaded]
//
2007-09-19 07:02:31 +00:00
if ( $context -> contextlevel <= CONTEXT_COURSE ) {
// Course and above are always preloaded
2007-09-20 04:52:54 +00:00
return has_capability_in_accessdata ( $capability , $context , $USER -> access , $doanything );
2007-09-19 07:02:31 +00:00
}
2007-09-19 07:26:02 +00:00
// Load accessdata for below-the-course contexts
2007-09-19 07:15:12 +00:00
if ( ! path_inaccessdata ( $context -> path , $USER -> access )) {
2007-10-18 15:57:15 +00:00
// error_log("loading access for context {$context->path} for $capability at {$context->contextlevel} {$context->id}");
2007-09-19 07:02:44 +00:00
// $bt = debug_backtrace();
// error_log("bt {$bt[0]['file']} {$bt[0]['line']}");
2007-10-17 09:19:39 +00:00
load_subcontext ( $USER -> id , $context , $USER -> access );
2007-09-19 07:02:44 +00:00
}
2007-09-20 04:52:54 +00:00
return has_capability_in_accessdata ( $capability , $context , $USER -> access , $doanything );
2007-09-19 07:02:31 +00:00
}
2007-09-20 04:52:54 +00:00
2007-09-19 07:06:55 +00:00
if ( ! isset ( $ACCESS [ $userid ])) {
load_user_accessdata ( $userid );
}
2007-09-19 07:26:02 +00:00
if ( $context -> contextlevel <= CONTEXT_COURSE ) {
// Course and above are always preloaded
2007-09-20 04:52:54 +00:00
return has_capability_in_accessdata ( $capability , $context , $ACCESS [ $userid ], $doanything );
2007-09-19 07:26:02 +00:00
}
// Load accessdata for below-the-course contexts as needed
2007-10-09 12:49:54 +00:00
if ( ! path_inaccessdata ( $context -> path , $ACCESS [ $userid ])) {
2007-10-18 15:57:15 +00:00
// error_log("loading access for context {$context->path} for $capability at {$context->contextlevel} {$context->id}");
2007-09-19 07:26:02 +00:00
// $bt = debug_backtrace();
// error_log("bt {$bt[0]['file']} {$bt[0]['line']}");
2007-10-17 09:19:39 +00:00
load_subcontext ( $userid , $context , $ACCESS [ $userid ]);
2007-09-19 07:26:02 +00:00
}
2007-09-20 04:52:54 +00:00
return has_capability_in_accessdata ( $capability , $context , $ACCESS [ $userid ], $doanything );
2007-09-19 07:02:31 +00:00
}
2007-10-30 10:50:20 +00:00
/**
* This function returns whether the current user has any of the capabilities in the
* $capabilities array . This is a simple wrapper around has_capability for convinience .
*
* There are probably tricks that could be done to improve the performance here , for example ,
* check the capabilities that are already cached first .
*
* @ param array $capabilities - an array of capability names .
* @ param object $context - a context object ( record from context table )
* @ param integer $userid - a userid number , empty if current $USER
* @ param bool $doanything - if false , ignore do anything
* @ return bool
*/
function has_any_capability ( $capabilities , $context , $userid = NULL , $doanything = true ) {
foreach ( $capabilities as $capability ) {
2007-10-30 20:51:37 +00:00
if ( has_capability ( $capability , $context , $userid , $doanything )) {
2007-10-30 10:50:20 +00:00
return true ;
}
}
return false ;
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:30:09 +00:00
* Uses 1 DB query to answer whether a user is an admin at the sitelevel .
* It depends on DB schema >= 1.7 but does not depend on the new datastructures
* in v1 . 9 ( context . path , or $USER -> access )
*
* Will return true if the userid has any of
* - moodle / site : config
* - moodle / legacy : admin
* - moodle / site : doanything
*
* @ param int $userid
* @ returns bool $isadmin
*/
function is_siteadmin ( $userid ) {
global $CFG ;
2007-09-26 09:40:28 +00:00
$sql = " SELECT SUM(rc.permission)
FROM " . $CFG->prefix . " role_capabilities rc
JOIN " . $CFG->prefix . " context ctx
ON ctx . id = rc . contextid
JOIN " . $CFG->prefix . " role_assignments ra
ON ra . roleid = rc . roleid AND ra . contextid = ctx . id
2007-09-19 07:30:09 +00:00
WHERE ctx . contextlevel = 10
2007-09-26 09:40:28 +00:00
AND ra . userid = { $userid }
2007-09-19 07:30:09 +00:00
AND rc . capability IN ( 'moodle/site:config' , 'moodle/legacy:admin' , 'moodle/site:doanything' )
2007-09-26 09:40:28 +00:00
GROUP BY rc . capability
HAVING SUM ( rc . permission ) > 0 " ;
2007-09-19 07:30:09 +00:00
2007-09-26 09:40:28 +00:00
$isadmin = record_exists_sql ( $sql );
2007-09-19 07:30:09 +00:00
return $isadmin ;
}
2007-09-19 07:02:31 +00:00
function get_course_from_path ( $path ) {
// assume that nothing is more than 1 course deep
if ( preg_match ( '!^(/.+)/\d+$!' , $path , $matches )) {
return $matches [ 1 ];
}
return false ;
}
2007-09-20 04:52:54 +00:00
function path_inaccessdata ( $path , $accessdata ) {
2007-09-19 07:02:44 +00:00
// assume that contexts hang from sys or from a course
// this will only work well with stuff that hangs from a course
2007-09-20 04:52:54 +00:00
if ( in_array ( $path , $accessdata [ 'loaded' ], true )) {
2007-10-18 16:04:54 +00:00
// error_log("found it!");
2007-09-19 07:02:44 +00:00
return true ;
}
$base = '/' . SYSCONTEXTID ;
while ( preg_match ( '!^(/.+)/\d+$!' , $path , $matches )) {
$path = $matches [ 1 ];
if ( $path === $base ) {
return false ;
}
2007-09-20 04:52:54 +00:00
if ( in_array ( $path , $accessdata [ 'loaded' ], true )) {
2007-09-19 07:02:44 +00:00
return true ;
}
}
return false ;
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:15:12 +00:00
* Walk the accessdata array and return true / false .
2007-09-19 07:05:48 +00:00
* Deals with prohibits , roleswitching , aggregating
* capabilities , etc .
*
* The main feature of here is being FAST and with no
* side effects .
*
2007-09-19 07:16:18 +00:00
* Notes :
*
* Switch Roles exits early
* -----------------------
* cap checks within a switchrole need to exit early
* in our bottom up processing so they don ' t " see " that
* there are real RAs that can do all sorts of things .
*
2007-09-19 07:18:23 +00:00
* Switch Role merges with default role
* ------------------------------------
* If you are a teacher in course X , you have at least
* teacher - in - X + defaultloggedinuser - sitewide . So in the
* course you ' ll have techer + defaultloggedinuser .
* We try to mimic that in switchrole .
*
2007-09-19 07:52:06 +00:00
* Local - most role definition and role - assignment wins
* ---------------------------------------------------
* So if the local context has said 'allow' , it wins
* over a high - level context that says 'deny' .
* This is applied when walking rdefs , and RAs .
* Only at the same context the values are SUM () med .
*
* The exception is CAP_PROHIBIT .
*
2007-09-19 07:16:18 +00:00
* " Guest default role " exception
* ------------------------------
*
* See MDL - 7513 and $ignoreguest below for details .
*
* The rule is that
*
* IF we are being asked about moodle / legacy : guest
* OR moodle / course : view
* FOR a real , logged - in user
* AND we reached the top of the path in ra and rdef
* AND that role has moodle / legacy : guest === 1. ..
* THEN we act as if we hadn ' t seen it .
*
*
* To Do :
2007-09-19 07:05:48 +00:00
*
* - Document how it works
* - Rewrite in ASM :- )
*
*/
2007-09-20 04:52:54 +00:00
function has_capability_in_accessdata ( $capability , $context , $accessdata , $doanything ) {
2007-09-19 07:02:31 +00:00
2007-09-19 07:16:18 +00:00
global $CFG ;
2007-09-19 07:02:31 +00:00
$path = $context -> path ;
// build $contexts as a list of "paths" of the current
// contexts and parents with the order top-to-bottom
$contexts = array ( $path );
while ( preg_match ( '!^(/.+)/\d+$!' , $path , $matches )) {
$path = $matches [ 1 ];
array_unshift ( $contexts , $path );
}
2007-09-19 07:16:18 +00:00
$ignoreguest = false ;
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'dr' ])
2007-09-19 07:16:18 +00:00
&& ( $capability == 'moodle/course:view'
|| $capability == 'moodle/legacy:guest' )) {
// At the base, ignore rdefs where moodle/legacy:guest
// is set
2007-09-20 04:52:54 +00:00
$ignoreguest = $accessdata [ 'dr' ];
2007-09-19 07:16:18 +00:00
}
2007-11-20 00:18:31 +00:00
// Coerce it to an int
$CAP_PROHIBIT = ( int ) CAP_PROHIBIT ;
2007-09-19 07:02:57 +00:00
2007-09-19 07:02:31 +00:00
$cc = count ( $contexts );
2007-09-19 07:52:06 +00:00
$can = 0 ;
2007-11-20 00:18:31 +00:00
$capdepth = 0 ;
2007-09-19 07:05:48 +00:00
2007-09-19 07:16:18 +00:00
//
// role-switches loop
//
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'rsw' ])) {
2007-09-19 07:05:48 +00:00
// check for isset() is fast
// empty() is slow...
2007-09-20 04:52:54 +00:00
if ( empty ( $accessdata [ 'rsw' ])) {
unset ( $accessdata [ 'rsw' ]); // keep things fast and unambiguous
2007-09-19 07:05:48 +00:00
break ;
}
// From the bottom up...
for ( $n = $cc - 1 ; $n >= 0 ; $n -- ) {
$ctxp = $contexts [ $n ];
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'rsw' ][ $ctxp ])) {
2007-09-19 07:05:48 +00:00
// Found a switchrole assignment
2007-09-19 07:18:23 +00:00
// check for that role _plus_ the default user role
2007-09-20 04:52:54 +00:00
$ras = array ( $accessdata [ 'rsw' ][ $ctxp ], $CFG -> defaultuserroleid );
2007-09-19 07:18:23 +00:00
for ( $rn = 0 ; $rn < 2 ; $rn ++ ) {
2007-11-20 00:18:31 +00:00
$roleid = ( int ) $ras [ $rn ];
2007-09-19 07:18:23 +00:00
// Walk the path for capabilities
// from the bottom up...
for ( $m = $cc - 1 ; $m >= 0 ; $m -- ) {
$capctxp = $contexts [ $m ];
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'rdef' ][ " { $capctxp } : $roleid " ][ $capability ])) {
2007-11-20 00:18:31 +00:00
$perm = ( int ) $accessdata [ 'rdef' ][ " { $capctxp } : $roleid " ][ $capability ];
2007-09-19 07:52:06 +00:00
// The most local permission (first to set) wins
// the only exception is CAP_PROHIBIT
if ( $can === 0 ) {
$can = $perm ;
2007-11-20 00:18:31 +00:00
} elseif ( $perm === $CAP_PROHIBIT ) {
2007-09-19 07:52:06 +00:00
$can = $perm ;
break ;
2007-09-19 07:18:23 +00:00
}
2007-09-19 07:05:48 +00:00
}
}
}
// As we are dealing with a switchrole,
// we return _here_, do _not_ walk up
// the hierarchy any further
if ( $can < 1 ) {
if ( $doanything ) {
// didn't find it as an explicit cap,
// but maybe the user candoanything in this context...
2007-09-20 04:52:54 +00:00
return has_capability_in_accessdata ( 'moodle/site:doanything' , $context , $accessdata , false );
2007-09-19 07:05:48 +00:00
} else {
return false ;
}
} else {
return true ;
}
}
}
}
2007-09-19 07:16:18 +00:00
//
// Main loop for normal RAs
// From the bottom up...
//
2007-09-19 07:02:31 +00:00
for ( $n = $cc - 1 ; $n >= 0 ; $n -- ) {
$ctxp = $contexts [ $n ];
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'ra' ][ $ctxp ])) {
2007-09-19 07:06:30 +00:00
// Found role assignments on this leaf
2007-09-20 04:52:54 +00:00
$ras = $accessdata [ 'ra' ][ $ctxp ];
2007-11-20 00:18:31 +00:00
$rc = count ( $ras );
$ctxcan = 0 ;
$ctxcapdepth = 0 ;
2007-09-19 07:06:30 +00:00
for ( $rn = 0 ; $rn < $rc ; $rn ++ ) {
2007-11-20 00:18:31 +00:00
$roleid = ( int ) $ras [ $rn ];
2007-09-19 07:52:06 +00:00
$rolecan = 0 ;
2007-11-20 00:18:31 +00:00
$rolecapdepth = 0 ;
2007-09-19 07:06:30 +00:00
// Walk the path for capabilities
// from the bottom up...
for ( $m = $cc - 1 ; $m >= 0 ; $m -- ) {
$capctxp = $contexts [ $m ];
2007-09-19 07:16:18 +00:00
// ignore some guest caps
// at base ra and rdef
if ( $ignoreguest == $roleid
&& $n === 0
&& $m === 0
2007-09-20 04:52:54 +00:00
&& isset ( $accessdata [ 'rdef' ][ " { $capctxp } : $roleid " ][ 'moodle/legacy:guest' ])
&& $accessdata [ 'rdef' ][ " { $capctxp } : $roleid " ][ 'moodle/legacy:guest' ] > 0 ) {
2007-09-19 07:16:18 +00:00
continue ;
}
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'rdef' ][ " { $capctxp } : $roleid " ][ $capability ])) {
2007-11-20 00:18:31 +00:00
$perm = ( int ) $accessdata [ 'rdef' ][ " { $capctxp } : $roleid " ][ $capability ];
2007-09-19 07:52:06 +00:00
// The most local permission (first to set) wins
// the only exception is CAP_PROHIBIT
if ( $rolecan === 0 ) {
2007-11-20 00:18:31 +00:00
$rolecan = $perm ;
$rolecapdepth = $m ;
} elseif ( $perm === $CAP_PROHIBIT ) {
$rolecan = $perm ;
$rolecapdepth = $m ;
2007-09-19 07:52:06 +00:00
break ;
2007-09-19 07:06:30 +00:00
}
2007-09-19 07:02:31 +00:00
}
}
2007-11-20 00:18:31 +00:00
// Rules for RAs at the same context...
// - prohibits always wins
// - permissions at the same ctxlevel & capdepth are added together
// - deeper capdepth wins
if ( $ctxcan === $CAP_PROHIBIT || $rolecan === $CAP_PROHIBIT ) {
$ctxcan = $CAP_PROHIBIT ;
$ctxcapdepth = 0 ;
} elseif ( $ctxcapdepth === $rolecapdepth ) {
$ctxcan += $rolecan ;
} elseif ( $ctxcapdepth < $rolecapdepth ) {
$ctxcan = $rolecan ;
$ctxcapdepth = $rolecapdepth ;
} else { // ctxcaptdepth is deeper
// rolecap ignored
}
2007-09-19 07:52:06 +00:00
}
// The most local RAs with a defined
// permission ($ctxcan) win, except
// for CAP_PROHIBIT
2007-11-20 00:18:31 +00:00
// NOTE: If we want the deepest RDEF to
// win regardless of the depth of the RA,
// change the elseif below to read
// ($can === 0 || $capdepth < $ctxcapdepth) {
if ( $ctxcan === $CAP_PROHIBIT ) {
2007-09-19 07:52:06 +00:00
$can = $ctxcan ;
break ;
2007-11-20 00:18:31 +00:00
} elseif ( $can === 0 ) { // see note above
$can = $ctxcan ;
$capdepth = $ctxcapdepth ;
2007-09-19 07:02:31 +00:00
}
}
}
if ( $can < 1 ) {
if ( $doanything ) {
// didn't find it as an explicit cap,
// but maybe the user candoanything in this context...
2007-09-20 04:52:54 +00:00
return has_capability_in_accessdata ( 'moodle/site:doanything' , $context , $accessdata , false );
2007-09-19 07:02:31 +00:00
} else {
return false ;
}
} else {
return true ;
}
}
2007-09-19 07:03:19 +00:00
2007-09-20 04:52:54 +00:00
function aggregate_roles_from_accessdata ( $context , $accessdata ) {
2007-09-19 07:03:19 +00:00
$path = $context -> path ;
// build $contexts as a list of "paths" of the current
// contexts and parents with the order top-to-bottom
$contexts = array ( $path );
while ( preg_match ( '!^(/.+)/\d+$!' , $path , $matches )) {
$path = $matches [ 1 ];
array_unshift ( $contexts , $path );
}
$cc = count ( $contexts );
$roles = array ();
// From the bottom up...
for ( $n = $cc - 1 ; $n >= 0 ; $n -- ) {
$ctxp = $contexts [ $n ];
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'ra' ][ $ctxp ]) && count ( $accessdata [ 'ra' ][ $ctxp ])) {
2007-09-19 07:06:30 +00:00
// Found assignments on this leaf
2007-09-20 04:52:54 +00:00
$addroles = $accessdata [ 'ra' ][ $ctxp ];
2007-09-19 07:06:30 +00:00
$roles = array_merge ( $roles , $addroles );
2007-09-19 07:03:19 +00:00
}
}
return array_unique ( $roles );
}
2006-08-14 05:55:40 +00:00
/**
2007-09-19 07:24:43 +00:00
* This is an easy to use function , combining has_capability () with require_course_login () .
* And will call those where needed .
*
* It checks for a capability assertion being true . If it isn ' t
* then the page is terminated neatly with a standard error message .
*
* If the user is not logged in , or is using 'guest' access or other special " users,
* it provides a logon prompt .
*
2006-08-14 05:55:40 +00:00
* @ param string $capability - name of the capability
* @ param object $context - a context object ( record from context table )
* @ param integer $userid - a userid number
2006-09-13 06:35:25 +00:00
* @ param bool $doanything - if false , ignore do anything
2006-08-14 05:55:40 +00:00
* @ param string $errorstring - an errorstring
2006-09-13 06:35:25 +00:00
* @ param string $stringfile - which stringfile to get it from
2006-08-14 05:55:40 +00:00
*/
2007-10-09 12:49:54 +00:00
function require_capability ( $capability , $context , $userid = NULL , $doanything = true ,
2006-11-02 08:12:54 +00:00
$errormessage = 'nopermissions' , $stringfile = '' ) {
2006-08-31 07:40:48 +00:00
2006-11-02 08:12:54 +00:00
global $USER , $CFG ;
2006-08-31 07:40:48 +00:00
2007-10-09 12:49:54 +00:00
/* Empty $userid means current user , if the current user is not logged in ,
* then make sure they are ( if needed ) .
* Originally there was a check for loaded permissions - it is not needed here .
* Context is now required parameter , the cached $CONTEXT was only hiding errors .
*/
if ( empty ( $userid )) {
if ( $context -> contextlevel == CONTEXT_COURSE ) {
2006-08-31 07:40:48 +00:00
require_login ( $context -> instanceid );
2006-11-02 08:12:54 +00:00
2007-10-09 12:49:54 +00:00
} else if ( $context -> contextlevel == CONTEXT_MODULE ) {
if ( ! $cm = get_record ( 'course_modules' , 'id' , $context -> instanceid )) {
error ( 'Incorrect module' );
2006-09-24 13:15:13 +00:00
}
2007-10-09 12:49:54 +00:00
if ( ! $course = get_record ( 'course' , 'id' , $cm -> course )) {
error ( 'Incorrect course.' );
}
require_course_login ( $course , true , $cm );
} else if ( $context -> contextlevel == CONTEXT_SYSTEM ) {
2006-11-02 08:12:54 +00:00
if ( ! empty ( $CFG -> forcelogin )) {
require_login ();
}
2006-08-31 07:40:48 +00:00
} else {
require_login ();
}
}
2006-09-20 21:00:45 +00:00
2006-08-31 07:40:48 +00:00
/// OK, if they still don't have the capability then print a nice error message
2006-09-13 06:35:25 +00:00
if ( ! has_capability ( $capability , $context , $userid , $doanything )) {
2006-08-14 05:55:40 +00:00
$capabilityname = get_capability_string ( $capability );
print_error ( $errormessage , $stringfile , '' , $capabilityname );
}
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:03:49 +00:00
* Get an array of courses ( with magic extra bits )
2007-09-19 07:15:12 +00:00
* where the accessdata and in DB enrolments show
2007-09-19 07:04:23 +00:00
* that the cap requested is available .
2007-09-19 07:03:49 +00:00
*
* The main use is for get_my_courses () .
*
* Notes
*
* - $fields is an array of fieldnames to ADD
* so name the fields you really need , which will
* be added and uniq ' d
*
* - the course records have $c -> context which is a fully
* valid context object . Saves you a query per course !
*
2007-09-19 07:18:37 +00:00
* - the course records have $c -> categorypath to make
* category lookups cheap
*
2007-09-19 07:04:23 +00:00
* - current implementation is split in -
*
* - if the user has the cap systemwide , stupidly
* grab * every * course for a capcheck . This eats
* a TON of bandwidth , specially on large sites
* with separate DBs ...
*
* - otherwise , fetch " likely " courses with a wide net
* that should get us _cheaply_ at least the courses we need , and some
* we won ' t - we get courses that ...
* - are in a category where user has the cap
* - or where use has a role - assignment ( any kind )
* - or where the course has an override on for this cap
*
* - walk the courses recordset checking the caps oneach one
* the checks are all in memory and quite fast
* ( though we could implement a specialised variant of the
2007-09-20 04:52:54 +00:00
* has_capability_in_accessdata () code to speed it up )
2007-09-19 07:03:49 +00:00
*
* @ param string $capability - name of the capability
2007-09-20 04:52:54 +00:00
* @ param array $accessdata - accessdata session array
2007-09-19 07:03:49 +00:00
* @ param bool $doanything - if false , ignore do anything
* @ param string $sort - sorting fields - prefix each fieldname with " c. "
* @ param array $fields - additional fields you are interested in ...
* @ param int $limit - set if you want to limit the number of courses
* @ return array $courses - ordered array of course objects - see notes above
*
*/
2007-09-20 04:52:54 +00:00
function get_user_courses_bycap ( $userid , $cap , $accessdata , $doanything , $sort = 'c.sortorder ASC' , $fields = NULL , $limit = 0 ) {
2007-09-19 07:03:49 +00:00
global $CFG ;
2007-09-19 07:04:59 +00:00
// Slim base fields, let callers ask for what they need...
$basefields = array ( 'id' , 'sortorder' , 'shortname' , 'idnumber' );
2007-09-19 07:03:49 +00:00
if ( ! is_null ( $fields )) {
$fields = array_merge ( $basefields , $fields );
$fields = array_unique ( $fields );
} else {
$fields = $basefields ;
}
2007-09-19 07:47:11 +00:00
$coursefields = 'c.' . implode ( ',c.' , $fields );
2007-09-19 07:04:23 +00:00
2007-09-19 07:29:43 +00:00
$sort = trim ( $sort );
if ( $sort !== '' ) {
$sort = " ORDER BY $sort " ;
}
2007-09-19 07:04:23 +00:00
$sysctx = get_context_instance ( CONTEXT_SYSTEM );
2007-09-20 04:52:54 +00:00
if ( has_capability_in_accessdata ( $cap , $sysctx , $accessdata , $doanything )) {
2007-09-19 07:04:23 +00:00
//
// Apparently the user has the cap sitewide, so walk *every* course
// (the cap checks are moderately fast, but this moves massive bandwidth w the db)
// Yuck.
//
$sql = " SELECT $coursefields ,
2007-09-19 07:54:37 +00:00
ctx . id AS ctxid , ctx . path AS ctxpath ,
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel ,
2007-09-19 07:18:37 +00:00
cc . path AS categorypath
2007-09-19 07:04:23 +00:00
FROM { $CFG -> prefix } course c
2007-09-19 07:18:37 +00:00
JOIN { $CFG -> prefix } course_categories cc
ON c . category = cc . id
2007-09-19 07:04:23 +00:00
JOIN { $CFG -> prefix } context ctx
ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
2007-09-19 07:29:43 +00:00
$sort " ;
2007-09-19 07:04:23 +00:00
$rs = get_recordset_sql ( $sql );
} else {
//
// narrow down where we have the caps to a few contexts
// this will be a combination of
// - categories where we have the rights
// - courses where we have an explicit enrolment OR that have an override
//
$sql = " SELECT ctx.*
FROM { $CFG -> prefix } context ctx
WHERE ctx . contextlevel = " .CONTEXT_COURSECAT. "
ORDER BY ctx . depth " ;
$rs = get_recordset_sql ( $sql );
$catpaths = array ();
2007-10-10 12:19:27 +00:00
while ( $catctx = rs_fetch_next_record ( $rs )) {
if ( $catctx -> path != ''
&& has_capability_in_accessdata ( $cap , $catctx , $accessdata , $doanything )) {
$catpaths [] = $catctx -> path ;
2007-09-19 07:04:23 +00:00
}
}
rs_close ( $rs );
$catclause = '' ;
if ( count ( $catpaths )) {
$cc = count ( $catpaths );
for ( $n = 0 ; $n < $cc ; $n ++ ) {
$catpaths [ $n ] = " ctx.path LIKE ' { $catpaths [ $n ] } /%' " ;
}
2007-09-19 07:47:11 +00:00
$catclause = 'OR (' . implode ( ' OR ' , $catpaths ) . ')' ;
2007-09-19 07:04:23 +00:00
}
unset ( $catpaths );
2007-09-19 07:04:37 +00:00
$capany = '' ;
if ( $doanything ) {
$capany = " OR rc.capability='moodle/site:doanything' " ;
}
2007-09-19 07:04:23 +00:00
//
// Note here that we *have* to have the compound clauses
// in the LEFT OUTER JOIN condition for them to return NULL
// appropriately and narrow things down...
//
$sql = " SELECT $coursefields ,
2007-09-19 07:54:37 +00:00
ctx . id AS ctxid , ctx . path AS ctxpath ,
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel ,
2007-09-19 07:18:37 +00:00
cc . path AS categorypath
2007-09-19 07:04:23 +00:00
FROM { $CFG -> prefix } course c
2007-09-19 07:18:37 +00:00
JOIN { $CFG -> prefix } course_categories cc
ON c . category = cc . id
2007-09-19 07:04:23 +00:00
JOIN { $CFG -> prefix } context ctx
ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
LEFT OUTER JOIN { $CFG -> prefix } role_assignments ra
ON ( ra . contextid = ctx . id AND ra . userid = $userid )
LEFT OUTER JOIN { $CFG -> prefix } role_capabilities rc
2007-09-19 07:04:37 +00:00
ON ( rc . contextid = ctx . id AND ( rc . capability = '$cap' $capany ))
2007-09-19 07:04:23 +00:00
WHERE ra . id IS NOT NULL
OR rc . id IS NOT NULL
$catclause
2007-09-19 07:29:43 +00:00
$sort " ;
2007-09-19 07:04:23 +00:00
$rs = get_recordset_sql ( $sql );
}
2007-09-19 07:03:49 +00:00
$courses = array ();
$cc = 0 ; // keep count
2007-10-10 12:19:27 +00:00
while ( $c = rs_fetch_next_record ( $rs )) {
// build the context obj
$c = make_context_subobj ( $c );
if ( has_capability_in_accessdata ( $cap , $c -> context , $accessdata , $doanything )) {
$courses [] = $c ;
if ( $limit > 0 && $cc ++ > $limit ) {
break ;
2007-09-19 07:03:49 +00:00
}
}
}
rs_close ( $rs );
return $courses ;
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:05:21 +00:00
* Draft - use for the course participants list page
*
* Uses 1 DB query ( cheap too - 2 ~ 7 ms ) .
*
* TODO :
* - implement additional where clauses
* - sorting
* - get course participants list to use it !
*
* returns a users array , both sorted _and_ keyed
* on id ( as get_my_courses () does )
*
* as a bonus , every user record comes with its own
* personal context , as our callers need it straight away
* { save 1 dbquery per user ! yay ! }
*
*/
function get_context_users_byrole ( $context , $roleid , $fields = NULL , $where = NULL , $sort = NULL , $limit = 0 ) {
global $CFG ;
// Slim base fields, let callers ask for what they need...
$basefields = array ( 'id' , 'username' );
if ( ! is_null ( $fields )) {
$fields = array_merge ( $basefields , $fields );
$fields = array_unique ( $fields );
} else {
$fields = $basefields ;
}
2007-09-19 07:47:11 +00:00
$userfields = 'u.' . implode ( ',u.' , $fields );
2007-09-19 07:05:21 +00:00
$contexts = substr ( $context -> path , 1 ); // kill leading slash
$contexts = str_replace ( '/' , ',' , $contexts );
$sql = " SELECT $userfields ,
2007-09-19 07:54:37 +00:00
ctx . id AS ctxid , ctx . path AS ctxpath ,
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel
2007-09-19 07:05:21 +00:00
FROM { $CFG -> prefix } user u
JOIN { $CFG -> prefix } context ctx
ON ( u . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_USER. " )
JOIN { $CFG -> prefix } role_assignments ra
ON u . id = ra . userid
WHERE ra . roleid = $roleid
AND ra . contextid IN ( $contexts ) " ;
$rs = get_recordset_sql ( $sql );
2007-09-19 07:07:45 +00:00
$users = array ();
$cc = 0 ; // keep count
2007-10-10 12:19:27 +00:00
while ( $u = rs_fetch_next_record ( $rs )) {
// build the context obj
$u = make_context_subobj ( $u );
2007-09-19 07:08:12 +00:00
2007-10-10 12:19:27 +00:00
$users [] = $u ;
if ( $limit > 0 && $cc ++ > $limit ) {
break ;
2007-09-19 07:07:45 +00:00
}
}
rs_close ( $rs );
return $users ;
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:07:45 +00:00
* Draft - use for the course participants list page
*
* Uses 2 fast DB queries
*
* TODO :
* - automagically exclude roles that can - doanything sitewide ( See callers )
* - perhaps also allow sitewide do - anything via flag
* - implement additional where clauses
* - sorting
* - get course participants list to use it !
*
* returns a users array , both sorted _and_ keyed
* on id ( as get_my_courses () does )
*
* as a bonus , every user record comes with its own
* personal context , as our callers need it straight away
* { save 1 dbquery per user ! yay ! }
*
*/
function get_context_users_bycap ( $context , $capability = 'moodle/course:view' , $fields = NULL , $where = NULL , $sort = NULL , $limit = 0 ) {
global $CFG ;
// Plan
//
// - Get all the *interesting* roles -- those that
// have some rolecap entry in our ctx.path contexts
//
// - Get all RAs for any of those roles in any of our
// interesting contexts, with userid & perm data
// in a nice (per user?) order
//
// - Walk the resultset, computing the permissions
// - actually - this is all a SQL subselect
//
// - Fetch user records against the subselect
//
// Slim base fields, let callers ask for what they need...
$basefields = array ( 'id' , 'username' );
if ( ! is_null ( $fields )) {
$fields = array_merge ( $basefields , $fields );
$fields = array_unique ( $fields );
} else {
$fields = $basefields ;
}
2007-09-19 07:47:11 +00:00
$userfields = 'u.' . implode ( ',u.' , $fields );
2007-09-19 07:07:45 +00:00
$contexts = substr ( $context -> path , 1 ); // kill leading slash
$contexts = str_replace ( '/' , ',' , $contexts );
$roles = array ();
$sql = " SELECT DISTINCT rc.roleid
FROM { $CFG -> prefix } role_capabilities rc
WHERE rc . capability = '$capability'
AND rc . contextid IN ( $contexts ) " ;
$rs = get_recordset_sql ( $sql );
2007-10-10 12:19:27 +00:00
while ( $u = rs_fetch_next_record ( $rs )) {
$roles [] = $u -> roleid ;
2007-09-19 07:07:45 +00:00
}
rs_close ( $rs );
2007-09-19 07:47:11 +00:00
$roles = implode ( ',' , $roles );
2007-09-19 07:07:45 +00:00
//
// User permissions subselect SQL
//
// - the open join condition to
// role_capabilities
//
// - because both rc and ra entries are
// _at or above_ our context, we don't care
// about their depth, we just need to sum them
//
$sql = " SELECT ra.userid, SUM(rc.permission) AS permission
FROM { $CFG -> prefix } role_assignments ra
JOIN { $CFG -> prefix } role_capabilities rc
ON ( ra . roleid = rc . roleid AND rc . contextid IN ( $contexts ))
WHERE ra . contextid IN ( $contexts )
AND ra . roleid IN ( $roles )
GROUP BY ra . userid " ;
// Get users
$sql = " SELECT $userfields ,
2007-09-19 07:54:37 +00:00
ctx . id AS ctxid , ctx . path AS ctxpath ,
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel
2007-09-19 07:07:45 +00:00
FROM { $CFG -> prefix } user u
JOIN { $CFG -> prefix } context ctx
ON ( u . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_USER. " )
JOIN ( $sql ) up
ON u . id = up . userid
WHERE up . permission > 0 AND u . username != 'guest' " ;
$rs = get_recordset_sql ( $sql );
2007-09-19 07:05:21 +00:00
$users = array ();
$cc = 0 ; // keep count
2007-10-10 12:19:27 +00:00
while ( $u = rs_fetch_next_record ( $rs )) {
// build the context obj
$u = make_context_subobj ( $u );
2007-09-19 07:08:12 +00:00
2007-10-10 12:19:27 +00:00
$users [] = $u ;
if ( $limit > 0 && $cc ++ > $limit ) {
break ;
2007-09-19 07:05:21 +00:00
}
}
rs_close ( $rs );
return $users ;
}
2007-09-19 07:02:04 +00:00
/**
2007-09-19 07:02:44 +00:00
* It will return a nested array showing role assignments
2007-09-19 07:02:04 +00:00
* all relevant role capabilities for the user at
* site / metacourse / course_category / course levels
*
* We do _not_ delve deeper than courses because the number of
* overrides at the module / block levels is HUGE .
*
2007-09-19 07:06:30 +00:00
* [ ra ] => [ / path / ] = array ( roleid , roleid )
2007-09-19 07:02:04 +00:00
* [ rdef ] => [ / path /: roleid ][ capability ] = permission
2007-09-19 07:02:44 +00:00
* [ loaded ] => array ( '/path' , '/path' )
2007-09-19 07:02:04 +00:00
*
* @ param $userid integer - the id of the user
*
*/
2007-09-19 07:02:44 +00:00
function get_user_access_sitewide ( $userid ) {
2007-09-19 07:02:04 +00:00
global $CFG ;
// this flag has not been set!
// (not clean install, or upgraded successfully to 1.7 and up)
if ( empty ( $CFG -> rolesactive )) {
return false ;
}
/* Get in 3 cheap DB queries ...
* - role assignments - with role_caps
* - relevant role caps
* - above this user ' s RAs
* - below this user ' s RAs - limited to course level
*/
2007-09-20 04:52:54 +00:00
$accessdata = array (); // named list
$accessdata [ 'ra' ] = array ();
$accessdata [ 'rdef' ] = array ();
$accessdata [ 'loaded' ] = array ();
2007-09-19 07:02:04 +00:00
$sitectx = get_field ( 'context' , 'id' , 'contextlevel' , CONTEXT_SYSTEM );
$base = " / $sitectx " ;
//
// Role assignments - and any rolecaps directly linked
// because it's cheap to read rolecaps here over many
// RAs
//
$sql = " SELECT ctx.path, ra.roleid, rc.capability, rc.permission
FROM { $CFG -> prefix } role_assignments ra
JOIN { $CFG -> prefix } context ctx
ON ra . contextid = ctx . id
LEFT OUTER JOIN { $CFG -> prefix } role_capabilities rc
ON ( rc . roleid = ra . roleid AND rc . contextid = ra . contextid )
WHERE ra . userid = $userid AND ctx . contextlevel <= " .CONTEXT_COURSE. "
ORDER BY ctx . depth , ctx . path " ;
$rs = get_recordset_sql ( $sql );
2007-09-19 07:03:19 +00:00
//
// raparents collects paths & roles we need to walk up
// the parenthood to build the rdef
//
// the array will bulk up a bit with dups
2007-09-19 07:02:04 +00:00
// which we'll later clear up
2007-09-19 07:03:19 +00:00
//
2007-09-19 07:02:04 +00:00
$raparents = array ();
2007-09-19 07:07:59 +00:00
$lastseen = '' ;
2007-10-09 12:49:54 +00:00
if ( $rs ) {
2007-10-10 12:19:27 +00:00
while ( $ra = rs_fetch_next_record ( $rs )) {
// RAs leafs are arrays to support multi
// role assignments...
if ( ! isset ( $accessdata [ 'ra' ][ $ra -> path ])) {
$accessdata [ 'ra' ][ $ra -> path ] = array ();
}
// only add if is not a repeat caused
// by capability join...
// (this check is cheaper than in_array())
if ( $lastseen !== $ra -> path . ':' . $ra -> roleid ) {
$lastseen = $ra -> path . ':' . $ra -> roleid ;
array_push ( $accessdata [ 'ra' ][ $ra -> path ], $ra -> roleid );
$parentids = explode ( '/' , $ra -> path );
array_shift ( $parentids ); // drop empty leading "context"
array_pop ( $parentids ); // drop _this_ context
if ( isset ( $raparents [ $ra -> roleid ])) {
$raparents [ $ra -> roleid ] = array_merge ( $raparents [ $ra -> roleid ],
$parentids );
} else {
$raparents [ $ra -> roleid ] = $parentids ;
2007-09-19 07:07:59 +00:00
}
}
2007-10-10 12:19:27 +00:00
// Always add the roleded
if ( ! empty ( $ra -> capability )) {
$k = " { $ra -> path } : { $ra -> roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $ra -> capability ] = $ra -> permission ;
}
2007-09-19 07:02:04 +00:00
}
2007-10-10 12:19:27 +00:00
unset ( $ra );
2007-10-09 12:49:54 +00:00
rs_close ( $rs );
2007-09-19 07:02:04 +00:00
}
// Walk up the tree to grab all the roledefs
// of interest to our user...
// NOTE: we use a series of IN clauses here - which
// might explode on huge sites with very convoluted nesting of
// categories... - extremely unlikely that the number of categories
// and roletypes is so large that we hit the limits of IN()
$clauses = array ();
foreach ( $raparents as $roleid => $contexts ) {
2007-09-19 07:47:11 +00:00
$contexts = implode ( ',' , array_unique ( $contexts ));
2007-09-19 07:02:04 +00:00
if ( $contexts ==! '' ) {
$clauses [] = " (roleid= $roleid AND contextid IN ( $contexts )) " ;
}
}
2007-09-19 07:47:11 +00:00
$clauses = implode ( " OR " , $clauses );
2007-09-19 07:22:12 +00:00
if ( $clauses !== '' ) {
$sql = " SELECT ctx.path, rc.roleid, rc.capability, rc.permission
FROM { $CFG -> prefix } role_capabilities rc
JOIN { $CFG -> prefix } context ctx
ON rc . contextid = ctx . id
WHERE $clauses
ORDER BY ctx . depth ASC , ctx . path DESC , rc . roleid ASC " ;
2007-09-19 07:02:04 +00:00
2007-09-19 07:22:12 +00:00
$rs = get_recordset_sql ( $sql );
unset ( $clauses );
2007-09-19 07:02:04 +00:00
2007-11-12 16:53:53 +00:00
if ( $rs ) {
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $rd -> roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
unset ( $rd );
rs_close ( $rs );
2007-09-19 07:02:04 +00:00
}
}
//
// Overrides for the role assignments IN SUBCONTEXTS
// (though we still do _not_ go below the course level.
//
// NOTE that the JOIN w sctx is with 3-way triangulation to
// catch overrides to the applicable role in any subcontext, based
// on the path field of the parent.
//
$sql = " SELECT sctx.path, ra.roleid,
ctx . path AS parentpath ,
rco . capability , rco . permission
FROM { $CFG -> prefix } role_assignments ra
JOIN { $CFG -> prefix } context ctx
ON ra . contextid = ctx . id
JOIN { $CFG -> prefix } context sctx
2007-09-19 07:28:31 +00:00
ON ( sctx . path LIKE " . sql_concat('ctx.path', " '/%' " ). " )
2007-09-19 07:02:04 +00:00
JOIN { $CFG -> prefix } role_capabilities rco
ON ( rco . roleid = ra . roleid AND rco . contextid = sctx . id )
WHERE ra . userid = $userid
AND sctx . contextlevel <= " .CONTEXT_COURSE. "
2007-09-19 07:02:44 +00:00
ORDER BY sctx . depth , sctx . path , ra . roleid " ;
2007-09-19 07:54:06 +00:00
$rs = get_recordset_sql ( $sql );
2007-11-12 16:53:53 +00:00
if ( $rs ) {
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $rd -> roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
unset ( $rd );
rs_close ( $rs );
2007-09-19 07:02:04 +00:00
}
2007-09-20 04:52:54 +00:00
return $accessdata ;
2007-09-19 07:02:04 +00:00
}
2007-09-19 07:02:44 +00:00
/**
* It add to the access ctrl array the data
2007-09-19 07:05:32 +00:00
* needed by a user for a given context
2007-09-19 07:02:44 +00:00
*
* @ param $userid integer - the id of the user
* @ param $context context obj - needs path !
2007-09-20 04:52:54 +00:00
* @ param $accessdata array accessdata array
2007-09-19 07:02:44 +00:00
*/
2007-10-17 09:19:39 +00:00
function load_subcontext ( $userid , $context , & $accessdata ) {
2007-09-19 07:02:44 +00:00
global $CFG ;
2007-09-19 07:03:19 +00:00
/* Get the additional RAs and relevant rolecaps
2007-09-19 07:02:44 +00:00
* - role assignments - with role_caps
* - relevant role caps
* - above this user ' s RAs
* - below this user ' s RAs - limited to course level
*/
$base = " / " . SYSCONTEXTID ;
2007-09-19 07:53:49 +00:00
//
// Replace $context with the target context we will
// load. Normally, this will be a course context, but
// may be a different top-level context.
//
// We have 3 cases
2007-09-19 07:02:44 +00:00
//
// - Course
// - BLOCK/PERSON/USER/COURSE(sitecourse) hanging from SYSTEM
// - BLOCK/MODULE/GROUP hanging from a course
//
// For course contexts, we _already_ have the RAs
// but the cost of re-fetching is minimal so we don't care.
//
2007-09-19 07:53:49 +00:00
if ( $context -> contextlevel !== CONTEXT_COURSE
&& $context -> path !== " $base / { $context -> id } " ) {
// Case BLOCK/MODULE/GROUP hanging from a course
2007-09-19 07:02:44 +00:00
// Assumption: the course _must_ be our parent
// If we ever see stuff nested further this needs to
// change to do 1 query over the exploded path to
// find out which one is the course
2007-09-19 07:53:49 +00:00
$targetid = array_pop ( explode ( '/' , get_course_from_path ( $context -> path )));
$context = get_context_instance_by_id ( $targetid );
2007-09-19 07:02:44 +00:00
}
//
2007-09-19 07:53:49 +00:00
// Role assignments in the context and below
2007-09-19 07:02:44 +00:00
//
2007-09-19 07:53:49 +00:00
$sql = " SELECT ctx.path, ra.roleid
2007-09-19 07:02:44 +00:00
FROM { $CFG -> prefix } role_assignments ra
JOIN { $CFG -> prefix } context ctx
ON ra . contextid = ctx . id
WHERE ra . userid = $userid
2007-09-19 07:53:49 +00:00
AND ( ctx . path = '{$context->path}' OR ctx . path LIKE '{$context->path}/%' )
2007-09-19 07:02:44 +00:00
ORDER BY ctx . depth , ctx . path " ;
$rs = get_recordset_sql ( $sql );
2007-09-19 07:53:49 +00:00
//
// Read in the RAs
2007-09-19 07:03:19 +00:00
//
2007-09-19 07:53:49 +00:00
$localroles = array ();
2007-10-10 12:19:27 +00:00
while ( $ra = rs_fetch_next_record ( $rs )) {
if ( ! isset ( $accessdata [ 'ra' ][ $ra -> path ])) {
$accessdata [ 'ra' ][ $ra -> path ] = array ();
2007-09-19 07:02:44 +00:00
}
2007-10-10 12:19:27 +00:00
array_push ( $accessdata [ 'ra' ][ $ra -> path ], $ra -> roleid );
array_push ( $localroles , $ra -> roleid );
2007-09-19 07:02:44 +00:00
}
rs_close ( $rs );
2007-09-19 07:03:19 +00:00
//
2007-09-19 07:53:49 +00:00
// Walk up and down the tree to grab all the roledefs
2007-09-19 07:02:44 +00:00
// of interest to our user...
2007-09-19 07:03:19 +00:00
//
2007-09-19 07:53:49 +00:00
// NOTES
// - we use IN() but the number of roles is very limited.
//
2007-09-20 04:52:54 +00:00
$courseroles = aggregate_roles_from_accessdata ( $context , $accessdata );
2007-09-19 07:53:49 +00:00
// Do we have any interesting "local" roles?
$localroles = array_diff ( $localroles , $courseroles ); // only "new" local roles
$wherelocalroles = '' ;
if ( count ( $localroles )) {
// Role defs for local roles in 'higher' contexts...
$contexts = substr ( $context -> path , 1 ); // kill leading slash
$contexts = str_replace ( '/' , ',' , $contexts );
$localroleids = implode ( ',' , $localroles );
$wherelocalroles = " OR (rc.roleid IN ( { $localroleids } )
AND ctx . id IN ( $contexts )) " ;
2007-09-19 07:02:44 +00:00
}
2007-09-19 07:53:49 +00:00
// We will want overrides for all of them
2007-09-21 04:33:50 +00:00
$whereroles = '' ;
if ( $roleids = implode ( ',' , array_merge ( $courseroles , $localroles ))) {
$whereroles = " rc.roleid IN ( $roleids ) AND " ;
}
2007-09-19 07:53:49 +00:00
$sql = " SELECT ctx.path, rc.roleid, rc.capability, rc.permission
FROM { $CFG -> prefix } role_capabilities rc
JOIN { $CFG -> prefix } context ctx
ON rc . contextid = ctx . id
2007-09-21 04:33:50 +00:00
WHERE ( $whereroles
( ctx . id = { $context -> id } OR ctx . path LIKE '{$context->path}/%' ))
2007-09-19 07:53:49 +00:00
$wherelocalroles
ORDER BY ctx . depth ASC , ctx . path DESC , rc . roleid ASC " ;
2007-10-17 09:19:39 +00:00
$newrdefs = array ();
2007-09-21 04:33:50 +00:00
if ( $rs = get_recordset_sql ( $sql )) {
2007-10-10 12:19:27 +00:00
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $rd -> roleid } " ;
2007-10-17 09:19:39 +00:00
if ( ! array_key_exists ( $k , $newrdefs )) {
$newrdefs [ $k ] = array ();
}
$newrdefs [ $k ][ $rd -> capability ] = $rd -> permission ;
2007-09-19 07:02:44 +00:00
}
2007-09-21 04:33:50 +00:00
rs_close ( $rs );
} else {
debugging ( 'Bad SQL encountered!' );
2007-09-19 07:02:44 +00:00
}
2007-10-17 09:19:39 +00:00
compact_rdefs ( $newrdefs );
foreach ( $newrdefs as $key => $value ) {
$accessdata [ 'rdef' ][ $key ] =& $newrdefs [ $key ];
}
2007-09-19 07:02:44 +00:00
2007-10-18 15:57:15 +00:00
// error_log("loaded {$context->path}");
2007-09-20 04:52:54 +00:00
$accessdata [ 'loaded' ][] = $context -> path ;
2007-09-19 07:02:44 +00:00
}
2006-10-23 15:17:31 +00:00
2007-03-07 13:45:41 +00:00
/**
2007-09-19 07:05:32 +00:00
* It add to the access ctrl array the data
* needed by a role for a given context .
*
* The data is added in the rdef key .
*
* This role - centric function is useful for role_switching
* and to get an overview of what a role gets under a
* given context and below ...
*
* @ param $roleid integer - the id of the user
* @ param $context context obj - needs path !
2007-09-20 04:52:54 +00:00
* @ param $accessdata accessdata array
2007-09-19 07:05:32 +00:00
*
*/
2007-09-20 04:52:54 +00:00
function get_role_access_bycontext ( $roleid , $context , $accessdata = NULL ) {
2007-09-19 07:05:32 +00:00
global $CFG ;
/* Get the relevant rolecaps into rdef
* - relevant role caps
* - at ctx and above
* - below this ctx
*/
2007-09-20 04:52:54 +00:00
if ( is_null ( $accessdata )) {
$accessdata = array (); // named list
$accessdata [ 'ra' ] = array ();
$accessdata [ 'rdef' ] = array ();
$accessdata [ 'loaded' ] = array ();
2007-09-19 07:05:32 +00:00
}
$contexts = substr ( $context -> path , 1 ); // kill leading slash
$contexts = str_replace ( '/' , ',' , $contexts );
//
// Walk up and down the tree to grab all the roledefs
// of interest to our role...
//
// NOTE: we use an IN clauses here - which
// might explode on huge sites with very convoluted nesting of
// categories... - extremely unlikely that the number of nested
// categories is so large that we hit the limits of IN()
//
$sql = " SELECT ctx.path, rc.capability, rc.permission
FROM { $CFG -> prefix } role_capabilities rc
JOIN { $CFG -> prefix } context ctx
ON rc . contextid = ctx . id
WHERE rc . roleid = $roleid AND
( ctx . id IN ( $contexts ) OR
ctx . path LIKE '{$context->path}/%' )
ORDER BY ctx . depth ASC , ctx . path DESC , rc . roleid ASC " ;
$rs = get_recordset_sql ( $sql );
2007-10-10 12:19:27 +00:00
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
2007-09-19 07:05:32 +00:00
}
rs_close ( $rs );
2007-09-20 04:52:54 +00:00
return $accessdata ;
2007-09-19 07:05:32 +00:00
}
2007-10-17 09:19:39 +00:00
/**
2007-09-19 07:06:55 +00:00
* Load accessdata for a user
* into the $ACCESS global
*
* Used by has_capability () - but feel free
* to call it if you are about to run a BIG
* cron run across a bazillion users .
*
*/
function load_user_accessdata ( $userid ) {
global $ACCESS , $CFG ;
2007-09-19 07:05:32 +00:00
2007-09-19 07:16:56 +00:00
$base = '/' . SYSCONTEXTID ;
2007-09-19 07:06:55 +00:00
2007-09-20 04:52:54 +00:00
$accessdata = get_user_access_sitewide ( $userid );
2007-10-12 07:41:30 +00:00
$frontpagecontext = get_context_instance ( CONTEXT_COURSE , SITEID );
2007-09-19 07:16:18 +00:00
//
2007-09-19 07:16:56 +00:00
// provide "default role" & set 'dr'
2007-09-19 07:16:18 +00:00
//
2007-10-05 15:06:38 +00:00
if ( ! empty ( $CFG -> defaultuserroleid )) {
$accessdata = get_role_access ( $CFG -> defaultuserroleid , $accessdata );
if ( ! isset ( $accessdata [ 'ra' ][ $base ])) {
$accessdata [ 'ra' ][ $base ] = array ( $CFG -> defaultuserroleid );
} else {
array_push ( $accessdata [ 'ra' ][ $base ], $CFG -> defaultuserroleid );
}
$accessdata [ 'dr' ] = $CFG -> defaultuserroleid ;
2007-09-19 07:06:55 +00:00
}
2007-09-26 07:12:38 +00:00
//
// provide "default frontpage role"
//
2007-10-03 14:38:55 +00:00
if ( ! empty ( $CFG -> defaultfrontpageroleid )) {
2007-09-26 07:12:38 +00:00
$base = '/' . SYSCONTEXTID . '/' . $frontpagecontext -> id ;
2007-10-03 14:38:55 +00:00
$accessdata = get_default_frontpage_role_access ( $CFG -> defaultfrontpageroleid , $accessdata );
2007-09-26 07:12:38 +00:00
if ( ! isset ( $accessdata [ 'ra' ][ $base ])) {
2007-10-03 14:38:55 +00:00
$accessdata [ 'ra' ][ $base ] = array ( $CFG -> defaultfrontpageroleid );
2007-09-26 07:12:38 +00:00
} else {
2007-10-03 14:38:55 +00:00
array_push ( $accessdata [ 'ra' ][ $base ], $CFG -> defaultfrontpageroleid );
2007-09-26 07:12:38 +00:00
}
}
2007-10-09 12:49:54 +00:00
// for dirty timestamps in cron
$accessdata [ 'time' ] = time ();
2007-10-17 09:19:39 +00:00
$ACCESS [ $userid ] = $accessdata ;
compact_rdefs ( $ACCESS [ $userid ][ 'rdef' ]);
2007-09-19 07:06:55 +00:00
return true ;
}
2007-09-19 07:11:18 +00:00
2007-10-17 09:19:39 +00:00
/**
* Use shared copy of role definistions stored in $RDEFS ;
* @ param array $rdefs array of role definitions in contexts
*/
function compact_rdefs ( & $rdefs ) {
global $RDEFS ;
/*
* This is a basic sharing only , we could also
* use md5 sums of values . The main purpose is to
* reduce mem in cron jobs - many users in $ACCESS array .
*/
foreach ( $rdefs as $key => $value ) {
if ( ! array_key_exists ( $key , $RDEFS )) {
$RDEFS [ $key ] = $rdefs [ $key ];
}
$rdefs [ $key ] =& $RDEFS [ $key ];
}
}
2007-09-19 07:05:32 +00:00
/**
* A convenience function to completely load all the capabilities
2007-11-14 22:04:05 +00:00
* for the current user . This is what gets called from complete_user_login ()
* for example . Call it only _after_ you ' ve setup $USER and called
* check_enrolment_plugins ();
*
2006-10-23 15:17:31 +00:00
*/
function load_all_capabilities () {
2007-10-09 12:49:54 +00:00
global $USER , $CFG , $DIRTYCONTEXTS ;
2006-08-08 05:13:06 +00:00
2007-09-19 07:02:57 +00:00
$base = '/' . SYSCONTEXTID ;
2007-03-07 13:45:41 +00:00
if ( isguestuser ()) {
2007-09-19 07:02:57 +00:00
$guest = get_guest_role ();
// Load the rdefs
$USER -> access = get_role_access ( $guest -> id );
// Put the ghost enrolment in place...
2007-09-19 07:16:04 +00:00
$USER -> access [ 'ra' ][ $base ] = array ( $guest -> id );
2007-03-07 13:45:41 +00:00
2007-09-19 07:16:56 +00:00
2007-03-07 13:45:41 +00:00
} else if ( isloggedin ()) {
2007-09-20 04:52:54 +00:00
$accessdata = get_user_access_sitewide ( $USER -> id );
2007-03-20 07:42:41 +00:00
2007-09-19 07:16:56 +00:00
//
// provide "default role" & set 'dr'
//
2007-10-05 15:06:38 +00:00
if ( ! empty ( $CFG -> defaultuserroleid )) {
$accessdata = get_role_access ( $CFG -> defaultuserroleid , $accessdata );
if ( ! isset ( $accessdata [ 'ra' ][ $base ])) {
$accessdata [ 'ra' ][ $base ] = array ( $CFG -> defaultuserroleid );
} else {
array_push ( $accessdata [ 'ra' ][ $base ], $CFG -> defaultuserroleid );
}
$accessdata [ 'dr' ] = $CFG -> defaultuserroleid ;
2007-03-20 02:57:57 +00:00
}
2007-09-19 07:16:56 +00:00
2007-09-26 07:12:38 +00:00
$frontpagecontext = get_context_instance ( CONTEXT_COURSE , SITEID );
2007-03-16 20:21:27 +00:00
2007-09-26 07:12:38 +00:00
//
// provide "default frontpage role"
//
2007-10-03 14:38:55 +00:00
if ( ! empty ( $CFG -> defaultfrontpageroleid )) {
2007-09-26 07:12:38 +00:00
$base = '/' . SYSCONTEXTID . '/' . $frontpagecontext -> id ;
$accessdata = get_default_frontpage_role_access ( $CFG -> defaultfrontpageroleid , $accessdata );
if ( ! isset ( $accessdata [ 'ra' ][ $base ])) {
$accessdata [ 'ra' ][ $base ] = array ( $CFG -> defaultfrontpageroleid );
} else {
array_push ( $accessdata [ 'ra' ][ $base ], $CFG -> defaultfrontpageroleid );
}
}
$USER -> access = $accessdata ;
2007-10-05 15:06:38 +00:00
} else if ( ! empty ( $CFG -> notloggedinroleid )) {
$USER -> access = get_role_access ( $CFG -> notloggedinroleid );
$USER -> access [ 'ra' ][ $base ] = array ( $CFG -> notloggedinroleid );
2006-10-23 15:17:31 +00:00
}
2007-09-19 07:17:08 +00:00
2007-10-09 12:49:54 +00:00
// Timestamp to read dirty context timestamps later
2007-09-19 07:10:24 +00:00
$USER -> access [ 'time' ] = time ();
2007-10-09 12:49:54 +00:00
$DIRTYCONTEXTS = array ();
2007-09-19 07:17:08 +00:00
// Clear to force a refresh
unset ( $USER -> mycourses );
2006-08-08 05:13:06 +00:00
}
2007-09-19 07:11:18 +00:00
/**
* A convenience function to completely reload all the capabilities
* for the current user when roles have been updated in a relevant
* context -- but PRESERVING switchroles and loginas .
*
* That is - completely transparent to the user .
*
* Note : rewrites $USER -> access completely .
*
*/
function reload_all_capabilities () {
global $USER , $CFG ;
2007-10-18 16:04:54 +00:00
// error_log("reloading");
2007-09-19 07:11:18 +00:00
// copy switchroles
$sw = array ();
if ( isset ( $USER -> access [ 'rsw' ])) {
$sw = $USER -> access [ 'rsw' ];
2007-10-18 16:04:54 +00:00
// error_log(print_r($sw,1));
2007-09-19 07:11:18 +00:00
}
unset ( $USER -> access );
2007-09-19 07:12:33 +00:00
unset ( $USER -> mycourses );
2007-09-19 07:11:18 +00:00
load_all_capabilities ();
foreach ( $sw as $path => $roleid ) {
$context = get_record ( 'context' , 'path' , $path );
role_switch ( $roleid , $context );
}
}
2006-10-23 15:17:31 +00:00
2007-09-19 07:16:29 +00:00
/*
* Adds a temp role to an accessdata array .
*
* Useful for the " temporary guest " access
* we grant to logged - in users .
*
* Note - assumes a course context !
*
*/
2007-09-20 04:52:54 +00:00
function load_temp_role ( $context , $roleid , $accessdata ) {
2007-09-19 07:16:29 +00:00
global $CFG ;
//
// Load rdefs for the role in -
// - this context
// - all the parents
// - and below - IOWs overrides...
//
// turn the path into a list of context ids
$contexts = substr ( $context -> path , 1 ); // kill leading slash
$contexts = str_replace ( '/' , ',' , $contexts );
$sql = " SELECT ctx.path,
rc . capability , rc . permission
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } role_capabilities rc
ON rc . contextid = ctx . id
WHERE ( ctx . id IN ( $contexts )
OR ctx . path LIKE '{$context->path}/%' )
AND rc . roleid = { $roleid }
ORDER BY ctx . depth , ctx . path " ;
$rs = get_recordset_sql ( $sql );
2007-10-10 12:19:27 +00:00
while ( $rd = rs_fetch_next_record ( $rs )) {
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
2007-09-19 07:16:29 +00:00
}
rs_close ( $rs );
//
// Say we loaded everything for the course context
// - which we just did - if the user gets a proper
// RA in this session, this data will need to be reloaded,
// but that is handled by the complete accessdata reload
//
2007-09-20 04:52:54 +00:00
array_push ( $accessdata [ 'loaded' ], $context -> path );
2007-09-19 07:16:29 +00:00
//
// Add the ghost RA
//
2007-09-20 04:52:54 +00:00
if ( isset ( $accessdata [ 'ra' ][ $context -> path ])) {
array_push ( $accessdata [ 'ra' ][ $context -> path ], $roleid );
2007-09-19 07:16:29 +00:00
} else {
2007-09-20 04:52:54 +00:00
$accessdata [ 'ra' ][ $context -> path ] = array ( $roleid );
2007-09-19 07:16:29 +00:00
}
2007-09-20 04:52:54 +00:00
return $accessdata ;
2007-09-19 07:16:29 +00:00
}
2007-03-05 11:27:01 +00:00
/**
2006-09-16 13:54:57 +00:00
* Check all the login enrolment information for the given user object
2006-09-20 21:00:45 +00:00
* by querying the enrolment plugins
2006-09-16 13:54:57 +00:00
*/
function check_enrolment_plugins ( & $user ) {
global $CFG ;
2006-09-25 01:34:21 +00:00
static $inprogress ; // To prevent this function being called more than once in an invocation
2006-09-25 01:42:41 +00:00
if ( ! empty ( $inprogress [ $user -> id ])) {
2006-09-25 01:34:21 +00:00
return ;
}
2006-09-25 01:42:41 +00:00
$inprogress [ $user -> id ] = true ; // Set the flag
2006-09-25 01:34:21 +00:00
2006-09-16 13:54:57 +00:00
require_once ( $CFG -> dirroot . '/enrol/enrol.class.php' );
2006-09-20 21:00:45 +00:00
2006-09-16 13:54:57 +00:00
if ( ! ( $plugins = explode ( ',' , $CFG -> enrol_plugins_enabled ))) {
$plugins = array ( $CFG -> enrol );
}
foreach ( $plugins as $plugin ) {
$enrol = enrolment_factory :: factory ( $plugin );
if ( method_exists ( $enrol , 'setup_enrolments' )) { /// Plugin supports Roles (Moodle 1.7 and later)
$enrol -> setup_enrolments ( $user );
} else { /// Run legacy enrolment methods
if ( method_exists ( $enrol , 'get_student_courses' )) {
$enrol -> get_student_courses ( $user );
}
if ( method_exists ( $enrol , 'get_teacher_courses' )) {
$enrol -> get_teacher_courses ( $user );
}
/// deal with $user->students and $user->teachers stuff
unset ( $user -> student );
unset ( $user -> teacher );
}
unset ( $enrol );
}
2006-09-25 01:34:21 +00:00
2006-09-25 01:42:41 +00:00
unset ( $inprogress [ $user -> id ]); // Unset the flag
2006-09-16 13:54:57 +00:00
}
2006-08-08 05:13:06 +00:00
/**
2006-08-11 02:44:02 +00:00
* Installs the roles system .
* This function runs on a fresh install as well as on an upgrade from the old
* hard - coded student / teacher / admin etc . roles to the new roles system .
2006-08-08 05:13:06 +00:00
*/
2006-08-11 02:44:02 +00:00
function moodle_install_roles () {
2006-08-08 05:13:06 +00:00
2006-08-11 02:44:02 +00:00
global $CFG , $db ;
2006-09-20 21:00:45 +00:00
2006-09-29 05:35:37 +00:00
/// Create a system wide context for assignemnt.
2006-10-25 08:38:14 +00:00
$systemcontext = $context = get_context_instance ( CONTEXT_SYSTEM );
2006-08-08 05:13:06 +00:00
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Create default/legacy roles and capabilities.
/// (1 legacy capability per legacy role at system level).
2006-11-20 14:08:40 +00:00
$adminrole = create_role ( addslashes ( get_string ( 'administrator' )), 'admin' ,
addslashes ( get_string ( 'administratordescription' )), 'moodle/legacy:admin' );
$coursecreatorrole = create_role ( addslashes ( get_string ( 'coursecreators' )), 'coursecreator' ,
addslashes ( get_string ( 'coursecreatorsdescription' )), 'moodle/legacy:coursecreator' );
$editteacherrole = create_role ( addslashes ( get_string ( 'defaultcourseteacher' )), 'editingteacher' ,
addslashes ( get_string ( 'defaultcourseteacherdescription' )), 'moodle/legacy:editingteacher' );
$noneditteacherrole = create_role ( addslashes ( get_string ( 'noneditingteacher' )), 'teacher' ,
addslashes ( get_string ( 'noneditingteacherdescription' )), 'moodle/legacy:teacher' );
$studentrole = create_role ( addslashes ( get_string ( 'defaultcoursestudent' )), 'student' ,
addslashes ( get_string ( 'defaultcoursestudentdescription' )), 'moodle/legacy:student' );
$guestrole = create_role ( addslashes ( get_string ( 'guest' )), 'guest' ,
addslashes ( get_string ( 'guestdescription' )), 'moodle/legacy:guest' );
2007-01-31 21:05:32 +00:00
$userrole = create_role ( addslashes ( get_string ( 'authenticateduser' )), 'user' ,
addslashes ( get_string ( 'authenticateduserdescription' )), 'moodle/legacy:user' );
2007-09-13 13:44:35 +00:00
2006-10-08 11:00:49 +00:00
/// Now is the correct moment to install capabilities - after creation of legacy roles, but before assigning of roles
2006-09-29 05:35:37 +00:00
2006-08-09 13:14:15 +00:00
if ( ! assign_capability ( 'moodle/site:doanything' , CAP_ALLOW , $adminrole , $systemcontext -> id )) {
2006-08-08 05:13:06 +00:00
error ( 'Could not assign moodle/site:doanything to the admin role' );
}
2006-09-27 22:59:37 +00:00
if ( ! update_capabilities ()) {
error ( 'Had trouble upgrading the core capabilities for the Roles System' );
}
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Look inside user_admin, user_creator, user_teachers, user_students and
/// assign above new roles. If a user has both teacher and student role,
/// only teacher role is assigned. The assignment should be system level.
2006-08-11 02:44:02 +00:00
$dbtables = $db -> MetaTables ( 'TABLES' );
2006-09-20 21:00:45 +00:00
2006-09-29 06:19:47 +00:00
/// Set up the progress bar
$usertables = array ( 'user_admins' , 'user_coursecreators' , 'user_teachers' , 'user_students' );
$totalcount = $progresscount = 0 ;
foreach ( $usertables as $usertable ) {
if ( in_array ( $CFG -> prefix . $usertable , $dbtables )) {
$totalcount += count_records ( $usertable );
}
}
2006-09-29 06:41:10 +00:00
print_progress ( 0 , $totalcount , 5 , 1 , 'Processing role assignments' );
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Upgrade the admins.
/// Sort using id ASC, first one is primary admin.
2006-08-11 02:44:02 +00:00
if ( in_array ( $CFG -> prefix . 'user_admins' , $dbtables )) {
2006-09-26 13:31:57 +00:00
if ( $rs = get_recordset_sql ( 'SELECT * from ' . $CFG -> prefix . 'user_admins ORDER BY ID ASC' )) {
2007-01-29 11:24:18 +00:00
while ( $admin = rs_fetch_next_record ( $rs )) {
2006-08-11 02:44:02 +00:00
role_assign ( $adminrole , $admin -> userid , 0 , $systemcontext -> id );
2006-09-29 06:19:47 +00:00
$progresscount ++ ;
2006-09-29 06:41:10 +00:00
print_progress ( $progresscount , $totalcount , 5 , 1 , 'Processing role assignments' );
2006-08-11 02:44:02 +00:00
}
2007-01-29 11:24:18 +00:00
rs_close ( $rs );
2006-08-11 02:44:02 +00:00
}
} else {
// This is a fresh install.
2006-08-08 05:13:06 +00:00
}
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Upgrade course creators.
2006-08-11 02:44:02 +00:00
if ( in_array ( $CFG -> prefix . 'user_coursecreators' , $dbtables )) {
2006-09-26 13:31:57 +00:00
if ( $rs = get_recordset ( 'user_coursecreators' )) {
2007-01-29 11:24:18 +00:00
while ( $coursecreator = rs_fetch_next_record ( $rs )) {
2006-09-03 21:43:37 +00:00
role_assign ( $coursecreatorrole , $coursecreator -> userid , 0 , $systemcontext -> id );
2006-09-29 06:19:47 +00:00
$progresscount ++ ;
2006-09-29 06:41:10 +00:00
print_progress ( $progresscount , $totalcount , 5 , 1 , 'Processing role assignments' );
2006-08-11 02:44:02 +00:00
}
2007-01-29 11:24:18 +00:00
rs_close ( $rs );
2006-08-11 02:44:02 +00:00
}
2006-08-08 05:13:06 +00:00
}
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Upgrade editting teachers and non-editting teachers.
2006-08-11 02:44:02 +00:00
if ( in_array ( $CFG -> prefix . 'user_teachers' , $dbtables )) {
2006-09-26 13:31:57 +00:00
if ( $rs = get_recordset ( 'user_teachers' )) {
2007-01-29 11:24:18 +00:00
while ( $teacher = rs_fetch_next_record ( $rs )) {
2007-09-13 13:44:35 +00:00
2006-11-20 03:55:35 +00:00
// removed code here to ignore site level assignments
// since the contexts are separated now
2007-09-13 13:44:35 +00:00
2006-09-13 09:08:14 +00:00
// populate the user_lastaccess table
2006-09-23 12:51:00 +00:00
$access = new object ();
2006-09-13 09:08:14 +00:00
$access -> timeaccess = $teacher -> timeaccess ;
$access -> userid = $teacher -> userid ;
$access -> courseid = $teacher -> course ;
insert_record ( 'user_lastaccess' , $access );
2006-09-26 13:31:57 +00:00
2006-09-13 09:08:14 +00:00
// assign the default student role
2006-08-11 02:44:02 +00:00
$coursecontext = get_context_instance ( CONTEXT_COURSE , $teacher -> course ); // needs cache
2007-03-07 01:35:47 +00:00
// hidden teacher
if ( $teacher -> authority == 0 ) {
2007-09-13 13:44:35 +00:00
$hiddenteacher = 1 ;
2007-03-07 01:35:47 +00:00
} else {
2007-09-13 13:44:35 +00:00
$hiddenteacher = 0 ;
}
2006-08-11 02:44:02 +00:00
if ( $teacher -> editall ) { // editting teacher
2007-03-07 01:35:47 +00:00
role_assign ( $editteacherrole , $teacher -> userid , 0 , $coursecontext -> id , 0 , 0 , $hiddenteacher );
2006-08-11 02:44:02 +00:00
} else {
2007-03-07 01:35:47 +00:00
role_assign ( $noneditteacherrole , $teacher -> userid , 0 , $coursecontext -> id , 0 , 0 , $hiddenteacher );
2006-08-11 02:44:02 +00:00
}
2006-09-29 06:19:47 +00:00
$progresscount ++ ;
2006-09-29 06:41:10 +00:00
print_progress ( $progresscount , $totalcount , 5 , 1 , 'Processing role assignments' );
2006-08-11 02:44:02 +00:00
}
2007-01-29 11:24:18 +00:00
rs_close ( $rs );
2006-08-08 05:13:06 +00:00
}
}
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Upgrade students.
2006-08-11 02:44:02 +00:00
if ( in_array ( $CFG -> prefix . 'user_students' , $dbtables )) {
2006-09-26 13:31:57 +00:00
if ( $rs = get_recordset ( 'user_students' )) {
2007-01-29 11:24:18 +00:00
while ( $student = rs_fetch_next_record ( $rs )) {
2006-09-26 13:31:57 +00:00
2006-09-13 09:08:14 +00:00
// populate the user_lastaccess table
2006-09-26 13:31:57 +00:00
$access = new object ;
2006-09-13 09:08:14 +00:00
$access -> timeaccess = $student -> timeaccess ;
$access -> userid = $student -> userid ;
$access -> courseid = $student -> course ;
insert_record ( 'user_lastaccess' , $access );
2006-09-26 13:31:57 +00:00
2006-09-13 09:08:14 +00:00
// assign the default student role
2006-08-11 02:44:02 +00:00
$coursecontext = get_context_instance ( CONTEXT_COURSE , $student -> course );
role_assign ( $studentrole , $student -> userid , 0 , $coursecontext -> id );
2006-09-29 06:19:47 +00:00
$progresscount ++ ;
2006-09-29 06:41:10 +00:00
print_progress ( $progresscount , $totalcount , 5 , 1 , 'Processing role assignments' );
2006-08-11 02:44:02 +00:00
}
2007-01-29 11:24:18 +00:00
rs_close ( $rs );
2006-08-11 02:44:02 +00:00
}
2006-08-08 05:13:06 +00:00
}
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Upgrade guest (only 1 entry).
2006-08-11 02:44:02 +00:00
if ( $guestuser = get_record ( 'user' , 'username' , 'guest' )) {
role_assign ( $guestrole , $guestuser -> id , 0 , $systemcontext -> id );
}
2006-09-29 06:41:10 +00:00
print_progress ( $totalcount , $totalcount , 5 , 1 , 'Processing role assignments' );
2006-08-11 02:44:02 +00:00
2006-09-29 05:35:37 +00:00
/// Insert the correct records for legacy roles
2006-08-23 06:36:08 +00:00
allow_assign ( $adminrole , $adminrole );
allow_assign ( $adminrole , $coursecreatorrole );
allow_assign ( $adminrole , $noneditteacherrole );
2006-09-20 21:00:45 +00:00
allow_assign ( $adminrole , $editteacherrole );
2006-08-23 06:36:08 +00:00
allow_assign ( $adminrole , $studentrole );
allow_assign ( $adminrole , $guestrole );
2006-09-20 21:00:45 +00:00
2006-08-23 06:36:08 +00:00
allow_assign ( $coursecreatorrole , $noneditteacherrole );
allow_assign ( $coursecreatorrole , $editteacherrole );
2006-09-20 21:00:45 +00:00
allow_assign ( $coursecreatorrole , $studentrole );
2006-08-23 06:36:08 +00:00
allow_assign ( $coursecreatorrole , $guestrole );
2006-09-20 21:00:45 +00:00
allow_assign ( $editteacherrole , $noneditteacherrole );
allow_assign ( $editteacherrole , $studentrole );
2006-08-23 06:36:08 +00:00
allow_assign ( $editteacherrole , $guestrole );
2006-09-20 21:00:45 +00:00
2006-09-29 05:35:37 +00:00
/// Set up default permissions for overrides
2006-08-23 06:36:08 +00:00
allow_override ( $adminrole , $adminrole );
allow_override ( $adminrole , $coursecreatorrole );
allow_override ( $adminrole , $noneditteacherrole );
2006-09-20 21:00:45 +00:00
allow_override ( $adminrole , $editteacherrole );
2006-08-23 06:36:08 +00:00
allow_override ( $adminrole , $studentrole );
2006-09-20 21:00:45 +00:00
allow_override ( $adminrole , $guestrole );
2007-01-31 21:05:32 +00:00
allow_override ( $adminrole , $userrole );
2006-08-11 02:44:02 +00:00
2006-09-17 06:37:59 +00:00
2006-09-29 05:35:37 +00:00
/// Delete the old user tables when we are done
2007-10-05 15:06:38 +00:00
$tables = array ( 'user_students' , 'user_teachers' , 'user_coursecreators' , 'user_admins' );
foreach ( $tables as $tablename ) {
$table = new XMLDBTable ( $tablename );
if ( table_exists ( $table )) {
drop_table ( $table );
}
}
2006-08-08 05:13:06 +00:00
}
2007-03-03 21:07:07 +00:00
/**
* Returns array of all legacy roles .
*/
function get_legacy_roles () {
return array (
2007-03-03 22:30:35 +00:00
'admin' => 'moodle/legacy:admin' ,
2007-03-03 21:07:07 +00:00
'coursecreator' => 'moodle/legacy:coursecreator' ,
2007-03-03 22:30:35 +00:00
'editingteacher' => 'moodle/legacy:editingteacher' ,
'teacher' => 'moodle/legacy:teacher' ,
'student' => 'moodle/legacy:student' ,
2007-03-05 11:27:01 +00:00
'guest' => 'moodle/legacy:guest' ,
'user' => 'moodle/legacy:user'
2007-03-03 21:07:07 +00:00
);
}
2007-03-06 19:19:19 +00:00
function get_legacy_type ( $roleid ) {
$sitecontext = get_context_instance ( CONTEXT_SYSTEM );
$legacyroles = get_legacy_roles ();
$result = '' ;
foreach ( $legacyroles as $ltype => $lcap ) {
$localoverride = get_local_override ( $roleid , $sitecontext -> id , $lcap );
if ( ! empty ( $localoverride -> permission ) and $localoverride -> permission == CAP_ALLOW ) {
//choose first selected legacy capability - reset the rest
if ( empty ( $result )) {
$result = $ltype ;
} else {
2007-03-07 09:38:21 +00:00
unassign_capability ( $lcap , $roleid );
2007-09-13 13:44:35 +00:00
}
2007-03-06 19:19:19 +00:00
}
}
return $result ;
}
2006-08-08 05:13:06 +00:00
/**
* Assign the defaults found in this capabality definition to roles that have
* the corresponding legacy capabilities assigned to them .
* @ param $legacyperms - an array in the format ( example ) :
* 'guest' => CAP_PREVENT ,
* 'student' => CAP_ALLOW ,
* 'teacher' => CAP_ALLOW ,
* 'editingteacher' => CAP_ALLOW ,
* 'coursecreator' => CAP_ALLOW ,
* 'admin' => CAP_ALLOW
* @ return boolean - success or failure .
*/
function assign_legacy_capabilities ( $capability , $legacyperms ) {
2006-09-20 21:00:45 +00:00
2007-03-03 21:07:07 +00:00
$legacyroles = get_legacy_roles ();
2006-08-08 05:13:06 +00:00
foreach ( $legacyperms as $type => $perm ) {
2006-09-20 21:00:45 +00:00
2006-10-25 08:38:14 +00:00
$systemcontext = get_context_instance ( CONTEXT_SYSTEM );
2006-09-20 21:00:45 +00:00
2007-03-03 21:07:07 +00:00
if ( ! array_key_exists ( $type , $legacyroles )) {
error ( 'Incorrect legacy role definition for type: ' . $type );
}
2006-09-20 21:00:45 +00:00
2007-03-03 21:07:07 +00:00
if ( $roles = get_roles_with_capability ( $legacyroles [ $type ], CAP_ALLOW )) {
2006-09-12 07:07:30 +00:00
foreach ( $roles as $role ) {
// Assign a site level capability.
if ( ! assign_capability ( $capability , $perm , $role -> id , $systemcontext -> id )) {
return false ;
}
2006-08-08 05:13:06 +00:00
}
}
}
return true ;
}
2006-08-14 07:15:03 +00:00
/**
* Checks to see if a capability is a legacy capability .
* @ param $capabilityname
* @ return boolean
*/
2006-08-08 05:13:06 +00:00
function islegacy ( $capabilityname ) {
2007-03-06 22:01:22 +00:00
if ( strpos ( $capabilityname , 'moodle/legacy' ) === 0 ) {
2006-09-20 21:00:45 +00:00
return true ;
2007-03-06 22:01:22 +00:00
} else {
return false ;
2006-08-09 13:14:15 +00:00
}
2006-08-08 05:13:06 +00:00
}
2006-08-14 07:15:03 +00:00
/**********************************
2006-08-08 05:13:06 +00:00
* Context Manipulation functions *
**********************************/
/**
2006-09-23 06:10:48 +00:00
* Create a new context record for use by all roles - related stuff
2007-09-19 07:12:56 +00:00
* assumes that the caller has done the homework .
*
2006-08-08 05:13:06 +00:00
* @ param $level
* @ param $instanceid
2006-09-27 17:50:53 +00:00
*
2007-09-19 07:13:08 +00:00
* @ return object newly created context
2006-08-08 05:13:06 +00:00
*/
2006-09-22 06:19:32 +00:00
function create_context ( $contextlevel , $instanceid ) {
2007-09-19 07:13:08 +00:00
global $CFG ;
2007-09-19 07:12:56 +00:00
if ( $contextlevel == CONTEXT_SYSTEM ) {
return create_system_context ();
}
2007-09-13 13:44:35 +00:00
2007-09-19 07:12:56 +00:00
$context = new object ();
$context -> contextlevel = $contextlevel ;
$context -> instanceid = $instanceid ;
2007-09-19 07:13:08 +00:00
// Define $context->path based on the parent
// context. In other words... Who is your daddy?
2007-09-19 07:13:45 +00:00
$basepath = '/' . SYSCONTEXTID ;
$basedepth = 1 ;
2007-09-19 07:13:08 +00:00
2007-10-05 15:06:38 +00:00
$result = true ;
2007-09-19 07:13:08 +00:00
switch ( $contextlevel ) {
case CONTEXT_COURSECAT :
2007-09-19 07:13:45 +00:00
$sql = " SELECT ctx.path, ctx.depth
2007-09-19 07:13:08 +00:00
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } course_categories cc
ON ( cc . parent = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSECAT. " )
WHERE cc . id = { $instanceid } " ;
2007-09-19 07:13:45 +00:00
if ( $p = get_record_sql ( $sql )) {
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2007-10-05 15:06:38 +00:00
} else if ( $category = get_record ( 'course_categories' , 'id' , $instanceid )) {
if ( empty ( $category -> parent )) {
// ok - this is a top category
} else if ( $parent = get_context_instance ( CONTEXT_COURSECAT , $category -> parent )) {
$basepath = $parent -> path ;
$basedepth = $parent -> depth ;
} else {
// wrong parent category - no big deal, this can be fixed later
$basepath = null ;
$basedepth = 0 ;
}
} else {
// incorrect category id
$result = false ;
2007-09-19 07:13:08 +00:00
}
break ;
case CONTEXT_COURSE :
2007-09-19 07:13:45 +00:00
$sql = " SELECT ctx.path, ctx.depth
2007-09-19 07:13:08 +00:00
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } course c
ON ( c . category = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSECAT. " )
WHERE c . id = { $instanceid } AND c . id != " . SITEID;
2007-09-19 07:13:45 +00:00
if ( $p = get_record_sql ( $sql )) {
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2007-10-05 15:06:38 +00:00
} else if ( $course = get_record ( 'course' , 'id' , $instanceid )) {
if ( $course -> id == SITEID ) {
//ok - no parent category
} else if ( $parent = get_context_instance ( CONTEXT_COURSECAT , $course -> category )) {
$basepath = $parent -> path ;
$basedepth = $parent -> depth ;
} else {
// wrong parent category of course - no big deal, this can be fixed later
$basepath = null ;
$basedepth = 0 ;
}
} else if ( $instanceid == SITEID ) {
// no errors for missing site course during installation
return false ;
} else {
// incorrect course id
$result = false ;
2007-09-19 07:13:08 +00:00
}
break ;
case CONTEXT_MODULE :
2007-09-19 07:13:45 +00:00
$sql = " SELECT ctx.path, ctx.depth
2007-09-19 07:13:08 +00:00
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } course_modules cm
ON ( cm . course = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
WHERE cm . id = { $instanceid } " ;
2007-10-05 15:06:38 +00:00
if ( $p = get_record_sql ( $sql )) {
$basepath = $p -> path ;
$basedepth = $p -> depth ;
} else if ( $cm = get_record ( 'course_modules' , 'id' , $instanceid )) {
if ( $parent = get_context_instance ( CONTEXT_COURSE , $cm -> course )) {
$basepath = $parent -> path ;
$basedepth = $parent -> depth ;
} else {
// course does not exist - modules can not exist without a course
$result = false ;
}
} else {
// cm does not exist
$result = false ;
}
2007-09-19 07:13:08 +00:00
break ;
case CONTEXT_BLOCK :
// Only non-pinned & course-page based
2007-09-19 07:13:45 +00:00
$sql = " SELECT ctx.path, ctx.depth
2007-09-19 07:13:08 +00:00
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } block_instance bi
ON ( bi . pageid = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
WHERE bi . id = { $instanceid } AND bi . pagetype = 'course-view' " ;
2007-09-19 07:13:45 +00:00
if ( $p = get_record_sql ( $sql )) {
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2007-10-05 15:06:38 +00:00
} else if ( $bi = get_record ( 'block_instance' , 'id' , $instanceid )) {
if ( $bi -> pagetype != 'course-view' ) {
// ok - not a course block
} else if ( $parent = get_context_instance ( CONTEXT_COURSE , $bi -> pageid )) {
$basepath = $parent -> path ;
$basedepth = $parent -> depth ;
} else {
// parent course does not exist - course blocks can not exist without a course
$result = false ;
}
} else {
// block does not exist
$result = false ;
2007-09-19 07:13:45 +00:00
}
2007-09-19 07:13:08 +00:00
break ;
case CONTEXT_USER :
// default to basepath
break ;
case CONTEXT_PERSONAL :
// default to basepath
break ;
}
2007-10-05 15:06:38 +00:00
// if grandparents unknown, maybe rebuild_context_path() will solve it later
if ( $basedepth != 0 ) {
$context -> depth = $basedepth + 1 ;
}
if ( $result and $id = insert_record ( 'context' , $context )) {
// can't set the full path till we know the id!
if ( $basedepth != 0 and ! empty ( $basepath )) {
set_field ( 'context' , 'path' , $basepath . '/' . $id , 'id' , $id );
}
return get_context_instance_by_id ( $id );
2007-09-19 07:13:45 +00:00
2006-09-27 17:50:53 +00:00
} else {
2007-09-19 07:12:56 +00:00
debugging ( 'Error: could not insert new context level "' .
s ( $contextlevel ) . '", instance "' .
s ( $instanceid ) . '".' );
2007-10-05 15:06:38 +00:00
return false ;
2006-08-08 05:13:06 +00:00
}
}
2007-03-05 11:27:01 +00:00
/**
2007-01-30 10:10:25 +00:00
* This hacky function is needed because we can not change system context instanceid using normal upgrade routine .
*/
2007-10-05 15:06:38 +00:00
function get_system_context ( $cache = true ) {
static $cached = null ;
if ( $cache and defined ( 'SYSCONTEXTID' )) {
if ( is_null ( $cached )) {
$cached = new object ();
$cached -> id = SYSCONTEXTID ;
$cached -> contextlevel = CONTEXT_SYSTEM ;
$cached -> instanceid = 0 ;
$cached -> path = '/' . SYSCONTEXTID ;
$cached -> depth = 1 ;
}
return $cached ;
}
2007-01-30 10:10:25 +00:00
2007-10-05 15:06:38 +00:00
if ( ! $context = get_record ( 'context' , 'contextlevel' , CONTEXT_SYSTEM )) {
2007-01-30 10:10:25 +00:00
$context = new object ();
$context -> contextlevel = CONTEXT_SYSTEM ;
2007-10-05 15:06:38 +00:00
$context -> instanceid = 0 ;
$context -> depth = 1 ;
$context -> path = NULL ; //not known before insert
if ( ! $context -> id = insert_record ( 'context' , $context )) {
// better something than nothing - let's hope it will work somehow
if ( ! defined ( 'SYSCONTEXTID' )) {
define ( 'SYSCONTEXTID' , 1 );
}
2007-01-30 10:10:25 +00:00
debugging ( 'Can not create system context' );
2007-10-05 15:06:38 +00:00
$context -> id = SYSCONTEXTID ;
$context -> path = '/' . SYSCONTEXTID ;
return $context ;
2007-01-30 10:10:25 +00:00
}
}
2007-10-05 15:06:38 +00:00
if ( ! isset ( $context -> depth ) or $context -> depth != 1 or $context -> instanceid != 0 or $context -> path != '/' . $context -> id ) {
$context -> instanceid = 0 ;
$context -> path = '/' . $context -> id ;
$context -> depth = 1 ;
update_record ( 'context' , $context );
}
if ( ! defined ( 'SYSCONTEXTID' )) {
define ( 'SYSCONTEXTID' , $context -> id );
}
$cached = $context ;
return $cached ;
2007-01-30 10:10:25 +00:00
}
2007-10-09 16:07:15 +00:00
2006-09-23 06:10:48 +00:00
/**
2007-10-09 16:07:15 +00:00
* Remove a context record and any dependent entries ,
* removes context from static context cache too
2006-09-23 06:10:48 +00:00
* @ param $level
* @ param $instanceid
2006-09-27 17:50:53 +00:00
*
2007-09-19 06:50:53 +00:00
* @ return bool properly deleted
2006-09-23 06:10:48 +00:00
*/
function delete_context ( $contextlevel , $instanceid ) {
2007-10-09 16:07:15 +00:00
global $context_cache , $context_cache_id ;
// do not use get_context_instance(), because the related object might not exist,
// or the context does not exist yet and it would be created now
if ( $context = get_record ( 'context' , 'contextlevel' , $contextlevel , 'instanceid' , $instanceid )) {
$result = delete_records ( 'role_assignments' , 'contextid' , $context -> id ) &&
delete_records ( 'role_capabilities' , 'contextid' , $context -> id ) &&
delete_records ( 'context' , 'id' , $context -> id );
// do not mark dirty contexts if parents unknown
if ( ! is_null ( $context -> path ) and $context -> depth > 0 ) {
mark_context_dirty ( $context -> path );
}
// purge static context cache if entry present
unset ( $context_cache [ $contextlevel ][ $instanceid ]);
unset ( $context_cache_id [ $context -> id ]);
return $result ;
} else {
return true ;
2006-09-23 06:10:48 +00:00
}
}
2007-10-05 20:16:51 +00:00
/**
* Precreates all contexts including all parents
* @ param int $contextlevel , empty means all
* @ param bool $buildpaths update paths and depths
2007-10-10 08:33:06 +00:00
* @ param bool $feedback show sql feedback
2007-10-05 20:16:51 +00:00
* @ return void
*/
2007-10-10 08:33:06 +00:00
function create_contexts ( $contextlevel = null , $buildpaths = true , $feedback = false ) {
2007-10-05 20:16:51 +00:00
global $CFG ;
//make sure system context exists
$syscontext = get_system_context ( false );
2007-10-05 20:47:08 +00:00
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_COURSECAT
or $contextlevel == CONTEXT_COURSE
or $contextlevel == CONTEXT_MODULE
or $contextlevel == CONTEXT_BLOCK ) {
2007-10-05 20:16:51 +00:00
$sql = " INSERT INTO { $CFG -> prefix } context (contextlevel, instanceid)
SELECT " .CONTEXT_COURSECAT. " , cc . id
FROM { $CFG -> prefix } course_categories cc
WHERE NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context cx
WHERE cc . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_COURSECAT. " ) " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-10-05 20:16:51 +00:00
}
2007-10-05 20:47:08 +00:00
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_COURSE
or $contextlevel == CONTEXT_MODULE
or $contextlevel == CONTEXT_BLOCK ) {
2007-10-05 20:16:51 +00:00
$sql = " INSERT INTO { $CFG -> prefix } context (contextlevel, instanceid)
SELECT " .CONTEXT_COURSE. " , c . id
FROM { $CFG -> prefix } course c
WHERE NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context cx
WHERE c . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_COURSE. " ) " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-10-05 20:16:51 +00:00
}
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_MODULE ) {
$sql = " INSERT INTO { $CFG -> prefix } context (contextlevel, instanceid)
SELECT " .CONTEXT_MODULE. " , cm . id
FROM { $CFG -> prefix } course_modules cm
WHERE NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context cx
WHERE cm . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_MODULE. " ) " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-10-05 20:16:51 +00:00
}
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_BLOCK ) {
$sql = " INSERT INTO { $CFG -> prefix } context (contextlevel, instanceid)
SELECT " .CONTEXT_BLOCK. " , bi . id
FROM { $CFG -> prefix } block_instance bi
WHERE NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context cx
WHERE bi . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_BLOCK. " ) " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-10-05 20:16:51 +00:00
}
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_USER ) {
$sql = " INSERT INTO { $CFG -> prefix } context (contextlevel, instanceid)
SELECT " .CONTEXT_USER. " , u . id
FROM { $CFG -> prefix } user u
WHERE u . deleted = 0
AND NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context cx
WHERE u . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_USER. " ) " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-10-05 20:16:51 +00:00
}
if ( $buildpaths ) {
2007-10-10 08:33:06 +00:00
build_context_path ( false , $feedback );
2007-10-05 20:16:51 +00:00
}
}
2007-09-19 06:50:53 +00:00
/**
* Remove stale context records
*
* @ return bool
*/
function cleanup_contexts () {
global $CFG ;
2007-12-10 21:35:58 +00:00
$sql = " SELECT c.contextlevel,
2007-09-19 06:50:53 +00:00
c . instanceid AS instanceid
FROM { $CFG -> prefix } context c
2007-12-10 21:35:58 +00:00
LEFT OUTER JOIN { $CFG -> prefix } course_categories t
2007-09-19 06:50:53 +00:00
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " . CONTEXT_COURSECAT . "
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2007-09-19 06:50:53 +00:00
FROM { $CFG -> prefix } context c
2007-12-10 21:35:58 +00:00
LEFT OUTER JOIN { $CFG -> prefix } course t
2007-09-19 06:50:53 +00:00
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " . CONTEXT_COURSE . "
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2007-09-19 06:50:53 +00:00
FROM { $CFG -> prefix } context c
2007-12-10 21:35:58 +00:00
LEFT OUTER JOIN { $CFG -> prefix } course_modules t
2007-09-19 06:50:53 +00:00
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " . CONTEXT_MODULE . "
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2007-09-19 06:50:53 +00:00
FROM { $CFG -> prefix } context c
2007-12-10 21:35:58 +00:00
LEFT OUTER JOIN { $CFG -> prefix } user t
2007-09-19 06:50:53 +00:00
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " . CONTEXT_USER . "
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2007-09-19 06:50:53 +00:00
FROM { $CFG -> prefix } context c
2007-12-10 21:35:58 +00:00
LEFT OUTER JOIN { $CFG -> prefix } block_instance t
2007-09-19 06:50:53 +00:00
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " . CONTEXT_BLOCK . "
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2007-09-19 06:50:53 +00:00
FROM { $CFG -> prefix } context c
2007-12-10 21:35:58 +00:00
LEFT OUTER JOIN { $CFG -> prefix } groups t
2007-09-19 06:50:53 +00:00
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " . CONTEXT_GROUP . "
" ;
2007-10-10 08:43:25 +00:00
if ( $rs = get_recordset_sql ( $sql )) {
2007-10-10 12:19:27 +00:00
begin_sql ();
$tx = true ;
while ( $tx && $ctx = rs_fetch_next_record ( $rs )) {
2007-12-10 21:35:58 +00:00
$tx = $tx && delete_context ( $ctx -> contextlevel , $ctx -> instanceid );
2007-09-19 06:50:53 +00:00
}
rs_close ( $rs );
2007-10-10 12:19:27 +00:00
if ( $tx ) {
commit_sql ();
return true ;
}
rollback_sql ();
return false ;
rs_close ( $rs );
2007-09-19 06:50:53 +00:00
}
return true ;
}
2006-08-08 05:13:06 +00:00
/**
* Get the context instance as an object . This function will create the
* context instance if it does not exist yet .
2007-06-12 11:11:42 +00:00
* @ param integer $level The context level , for example CONTEXT_COURSE , or CONTEXT_MODULE .
* @ param integer $instance The instance id . For $level = CONTEXT_COURSE , this would be $course -> id ,
* for $level = CONTEXT_MODULE , this would be $cm -> id . And so on .
* @ return object The context object .
2006-08-08 05:13:06 +00:00
*/
2007-10-05 15:06:38 +00:00
function get_context_instance ( $contextlevel , $instance = 0 ) {
2006-08-13 13:28:01 +00:00
2007-10-05 15:06:38 +00:00
global $context_cache , $context_cache_id ;
2006-09-27 17:58:17 +00:00
static $allowed_contexts = array ( CONTEXT_SYSTEM , CONTEXT_PERSONAL , CONTEXT_USER , CONTEXT_COURSECAT , CONTEXT_COURSE , CONTEXT_GROUP , CONTEXT_MODULE , CONTEXT_BLOCK );
2006-08-23 01:29:52 +00:00
2007-09-19 07:23:41 +00:00
if ( $contextlevel === 'clearcache' ) {
// TODO: Remove for v2.0
// No longer needed, but we'll catch it to avoid erroring out on custom code.
// This used to be a fix for MDL-9016
// "Restoring into existing course, deleting first
// deletes context and doesn't recreate it"
2007-03-23 07:21:27 +00:00
return false ;
}
2006-10-19 06:16:35 +00:00
2007-10-05 15:06:38 +00:00
/// System context has special cache
2007-01-30 10:10:25 +00:00
if ( $contextlevel == CONTEXT_SYSTEM ) {
2007-10-05 15:06:38 +00:00
return get_system_context ();
2007-01-30 10:10:25 +00:00
}
2006-09-27 17:58:17 +00:00
/// check allowed context levels
if ( ! in_array ( $contextlevel , $allowed_contexts )) {
2006-09-27 18:11:36 +00:00
// fatal error, code must be fixed - probably typo or switched parameters
2006-09-27 17:58:17 +00:00
error ( 'Error: get_context_instance() called with incorrect context level "' . s ( $contextlevel ) . '"' );
}
2006-08-13 15:48:57 +00:00
/// Check the cache
2006-09-22 06:19:32 +00:00
if ( isset ( $context_cache [ $contextlevel ][ $instance ])) { // Already cached
return $context_cache [ $contextlevel ][ $instance ];
2006-08-13 13:28:01 +00:00
}
2006-08-13 15:48:57 +00:00
/// Get it from the database, or create it
2006-09-22 06:19:32 +00:00
if ( ! $context = get_record ( 'context' , 'contextlevel' , $contextlevel , 'instanceid' , $instance )) {
2007-10-05 15:06:38 +00:00
$context = create_context ( $contextlevel , $instance );
2006-08-13 13:28:01 +00:00
}
2006-09-08 19:28:03 +00:00
/// Only add to cache if context isn't empty.
if ( ! empty ( $context )) {
2006-09-22 06:19:32 +00:00
$context_cache [ $contextlevel ][ $instance ] = $context ; // Cache it for later
2006-09-08 19:28:03 +00:00
$context_cache_id [ $context -> id ] = $context ; // Cache it for later
}
2006-08-14 05:55:40 +00:00
2006-08-08 05:13:06 +00:00
return $context ;
}
2006-08-14 07:15:03 +00:00
2006-08-13 15:48:57 +00:00
/**
2007-06-12 11:11:42 +00:00
* Get a context instance as an object , from a given context id .
* @ param $id a context id .
* @ return object The context object .
2006-08-13 15:48:57 +00:00
*/
function get_context_instance_by_id ( $id ) {
2006-08-23 01:29:52 +00:00
global $context_cache , $context_cache_id ;
2007-10-05 15:06:38 +00:00
if ( $id == SYSCONTEXTID ) {
return get_system_context ();
}
2006-08-13 15:48:57 +00:00
if ( isset ( $context_cache_id [ $id ])) { // Already cached
2006-08-22 16:18:11 +00:00
return $context_cache_id [ $id ];
2006-08-13 15:48:57 +00:00
}
if ( $context = get_record ( 'context' , 'id' , $id )) { // Update the cache and return
2006-09-22 06:19:32 +00:00
$context_cache [ $context -> contextlevel ][ $context -> instanceid ] = $context ;
2006-08-13 15:48:57 +00:00
$context_cache_id [ $context -> id ] = $context ;
return $context ;
}
return false ;
}
2006-08-08 05:13:06 +00:00
2006-08-13 09:25:45 +00:00
/**
* Get the local override ( if any ) for a given capability in a role in a context
* @ param $roleid
2006-08-14 05:55:40 +00:00
* @ param $contextid
* @ param $capability
2006-08-13 09:25:45 +00:00
*/
function get_local_override ( $roleid , $contextid , $capability ) {
return get_record ( 'role_capabilities' , 'roleid' , $roleid , 'capability' , $capability , 'contextid' , $contextid );
}
2006-08-08 05:13:06 +00:00
/************************************
* DB TABLE RELATED FUNCTIONS *
************************************/
2006-08-14 07:15:03 +00:00
/**
2006-08-08 05:13:06 +00:00
* function that creates a role
* @ param name - role name
2006-09-18 17:40:22 +00:00
* @ param shortname - role short name
2006-08-08 05:13:06 +00:00
* @ param description - role description
* @ param legacy - optional legacy capability
* @ return id or false
*/
2006-09-23 10:43:24 +00:00
function create_role ( $name , $shortname , $description , $legacy = '' ) {
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
// check for duplicate role name
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
if ( $role = get_record ( 'role' , 'name' , $name )) {
2006-09-20 21:00:45 +00:00
error ( 'there is already a role with this name!' );
2006-08-09 13:14:15 +00:00
}
2006-09-20 21:00:45 +00:00
2006-09-18 17:40:22 +00:00
if ( $role = get_record ( 'role' , 'shortname' , $shortname )) {
2006-09-20 21:00:45 +00:00
error ( 'there is already a role with this shortname!' );
2006-09-18 17:40:22 +00:00
}
2006-09-21 22:34:45 +00:00
$role = new object ();
2006-08-09 13:14:15 +00:00
$role -> name = $name ;
2006-09-18 17:40:22 +00:00
$role -> shortname = $shortname ;
2006-08-09 13:14:15 +00:00
$role -> description = $description ;
2006-09-20 21:00:45 +00:00
2006-09-23 10:43:24 +00:00
//find free sortorder number
$role -> sortorder = count_records ( 'role' );
while ( get_record ( 'role' , 'sortorder' , $role -> sortorder )) {
$role -> sortorder += 1 ;
2006-09-21 22:34:45 +00:00
}
2006-10-25 08:38:14 +00:00
if ( ! $context = get_context_instance ( CONTEXT_SYSTEM )) {
return false ;
}
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
if ( $id = insert_record ( 'role' , $role )) {
2006-09-20 21:00:45 +00:00
if ( $legacy ) {
assign_capability ( $legacy , CAP_ALLOW , $id , $context -> id );
2006-08-09 13:14:15 +00:00
}
2006-09-20 21:00:45 +00:00
2006-09-07 08:57:56 +00:00
/// By default, users with role:manage at site level
/// should be able to assign users to this new role, and override this new role's capabilities
2006-09-20 21:00:45 +00:00
2006-09-07 08:57:56 +00:00
// find all admin roles
2006-09-10 20:29:44 +00:00
if ( $adminroles = get_roles_with_capability ( 'moodle/role:manage' , CAP_ALLOW , $context )) {
// foreach admin role
foreach ( $adminroles as $arole ) {
// write allow_assign and allow_overrid
allow_assign ( $arole -> id , $id );
2006-09-20 21:00:45 +00:00
allow_override ( $arole -> id , $id );
2006-09-10 20:29:44 +00:00
}
2006-09-07 08:57:56 +00:00
}
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
return $id ;
} else {
2006-09-20 21:00:45 +00:00
return false ;
2006-08-09 13:14:15 +00:00
}
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
}
2006-09-23 10:43:24 +00:00
/**
* function that deletes a role and cleanups up after it
* @ param roleid - id of role to delete
* @ return success
*/
function delete_role ( $roleid ) {
2007-08-02 08:28:29 +00:00
global $CFG ;
2006-09-23 10:43:24 +00:00
$success = true ;
2007-07-19 05:19:05 +00:00
// mdl 10149, check if this is the last active admin role
// if we make the admin role not deletable then this part can go
2007-09-13 13:44:35 +00:00
2007-07-19 05:19:05 +00:00
$systemcontext = get_context_instance ( CONTEXT_SYSTEM );
2007-09-13 13:44:35 +00:00
2007-07-19 05:19:05 +00:00
if ( $role = get_record ( 'role' , 'id' , $roleid )) {
if ( record_exists ( 'role_capabilities' , 'contextid' , $systemcontext -> id , 'roleid' , $roleid , 'capability' , 'moodle/site:doanything' )) {
// deleting an admin role
$status = false ;
if ( $adminroles = get_roles_with_capability ( 'moodle/site:doanything' , CAP_ALLOW , $systemcontext )) {
foreach ( $adminroles as $adminrole ) {
if ( $adminrole -> id != $roleid ) {
// some other admin role
if ( record_exists ( 'role_assignments' , 'roleid' , $adminrole -> id , 'contextid' , $systemcontext -> id )) {
2007-09-13 13:44:35 +00:00
// found another admin role with at least 1 user assigned
2007-07-19 05:19:05 +00:00
$status = true ;
break ;
}
}
2007-09-13 13:44:35 +00:00
}
}
2007-07-19 05:19:05 +00:00
if ( $status !== true ) {
2007-09-13 13:44:35 +00:00
error ( 'You can not delete this role because there is no other admin roles with users assigned' );
2007-07-19 05:19:05 +00:00
}
2007-09-13 13:44:35 +00:00
}
2007-07-19 05:19:05 +00:00
}
2006-09-23 10:43:24 +00:00
// first unssign all users
if ( ! role_unassign ( $roleid )) {
debugging ( " Error while unassigning all users from role with ID $roleid ! " );
$success = false ;
}
// cleanup all references to this role, ignore errors
if ( $success ) {
2007-09-13 13:44:35 +00:00
2007-08-02 08:28:29 +00:00
// MDL-10679 find all contexts where this role has an override
2007-09-13 13:44:35 +00:00
$contexts = get_records_sql ( " SELECT contextid, contextid
2007-08-02 08:28:29 +00:00
FROM { $CFG -> prefix } role_capabilities
WHERE roleid = $roleid " );
2007-09-13 13:44:35 +00:00
2006-09-23 10:43:24 +00:00
delete_records ( 'role_capabilities' , 'roleid' , $roleid );
2007-09-13 13:44:35 +00:00
2006-09-23 10:43:24 +00:00
delete_records ( 'role_allow_assign' , 'roleid' , $roleid );
delete_records ( 'role_allow_assign' , 'allowassign' , $roleid );
delete_records ( 'role_allow_override' , 'roleid' , $roleid );
delete_records ( 'role_allow_override' , 'allowoverride' , $roleid );
2007-09-13 13:44:35 +00:00
delete_records ( 'role_names' , 'roleid' , $roleid );
2006-09-23 10:43:24 +00:00
}
// finally delete the role itself
2007-10-18 05:53:14 +00:00
// get this before the name is gone for logging
$rolename = get_field ( 'role' , 'name' , 'id' , $roleid );
2006-09-23 10:43:24 +00:00
if ( $success and ! delete_records ( 'role' , 'id' , $roleid )) {
2006-09-23 12:51:00 +00:00
debugging ( " Could not delete role record with ID $roleid ! " );
2006-09-23 10:43:24 +00:00
$success = false ;
}
2007-10-18 05:53:14 +00:00
if ( $success ) {
add_to_log ( SITEID , 'role' , 'delete' , 'admin/roles/action=delete&roleid=' . $roleid , $rolename , '' , $USER -> id );
}
2006-09-23 10:43:24 +00:00
return $success ;
}
2006-08-08 05:13:06 +00:00
/**
* Function to write context specific overrides , or default capabilities .
* @ param module - string name
* @ param capability - string name
* @ param contextid - context id
* @ param roleid - role id
* @ param permission - int 1 , - 1 or - 1000
2006-10-11 02:18:09 +00:00
* should not be writing if permission is 0
2006-08-08 05:13:06 +00:00
*/
2006-09-12 06:15:33 +00:00
function assign_capability ( $capability , $permission , $roleid , $contextid , $overwrite = false ) {
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
global $USER ;
2006-09-20 21:00:45 +00:00
2006-10-11 02:18:09 +00:00
if ( empty ( $permission ) || $permission == CAP_INHERIT ) { // if permission is not set
2006-09-20 21:00:45 +00:00
unassign_capability ( $capability , $roleid , $contextid );
2006-10-11 02:18:09 +00:00
return true ;
2006-08-09 13:14:15 +00:00
}
2006-09-20 21:00:45 +00:00
2006-09-12 07:07:30 +00:00
$existing = get_record ( 'role_capabilities' , 'contextid' , $contextid , 'roleid' , $roleid , 'capability' , $capability );
2006-09-12 06:15:33 +00:00
if ( $existing and ! $overwrite ) { // We want to keep whatever is there already
return true ;
}
2006-08-08 05:13:06 +00:00
$cap = new object ;
$cap -> contextid = $contextid ;
$cap -> roleid = $roleid ;
$cap -> capability = $capability ;
$cap -> permission = $permission ;
$cap -> timemodified = time ();
2006-08-14 13:42:34 +00:00
$cap -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2006-09-12 06:15:33 +00:00
if ( $existing ) {
$cap -> id = $existing -> id ;
return update_record ( 'role_capabilities' , $cap );
} else {
2007-08-02 08:28:29 +00:00
$c = get_record ( 'context' , 'id' , $contextid );
2006-09-12 06:15:33 +00:00
return insert_record ( 'role_capabilities' , $cap );
}
2006-08-08 05:13:06 +00:00
}
/**
* Unassign a capability from a role .
* @ param $roleid - the role id
* @ param $capability - the name of the capability
* @ return boolean - success or failure
*/
function unassign_capability ( $capability , $roleid , $contextid = NULL ) {
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
if ( isset ( $contextid )) {
2007-08-02 08:28:29 +00:00
// delete from context rel, if this is the last override in this context
2006-08-09 13:14:15 +00:00
$status = delete_records ( 'role_capabilities' , 'capability' , $capability ,
'roleid' , $roleid , 'contextid' , $contextid );
} else {
$status = delete_records ( 'role_capabilities' , 'capability' , $capability ,
'roleid' , $roleid );
}
return $status ;
2006-08-08 05:13:06 +00:00
}
/**
2006-09-20 08:30:49 +00:00
* Get the roles that have a given capability assigned to it . This function
* does not resolve the actual permission of the capability . It just checks
* for assignment only .
2006-08-08 05:13:06 +00:00
* @ param $capability - capability name ( string )
* @ param $permission - optional , the permission defined for this capability
* either CAP_ALLOW , CAP_PREVENT or CAP_PROHIBIT
* @ return array or role objects
*/
2006-09-07 08:57:56 +00:00
function get_roles_with_capability ( $capability , $permission = NULL , $context = '' ) {
2006-08-08 05:13:06 +00:00
global $CFG ;
2006-09-20 21:00:45 +00:00
2006-09-07 08:57:56 +00:00
if ( $context ) {
if ( $contexts = get_parent_contexts ( $context )) {
$listofcontexts = '(' . implode ( ',' , $contexts ) . ')' ;
} else {
2006-10-25 08:38:14 +00:00
$sitecontext = get_context_instance ( CONTEXT_SYSTEM );
2006-09-20 21:00:45 +00:00
$listofcontexts = '(' . $sitecontext -> id . ')' ; // must be site
}
2006-09-07 20:17:46 +00:00
$contextstr = " AND (rc.contextid = ' $context->id ' OR rc.contextid IN $listofcontexts ) " ;
2006-09-07 08:57:56 +00:00
} else {
$contextstr = '' ;
}
2006-09-20 21:00:45 +00:00
$selectroles = " SELECT r.*
2006-09-07 20:17:46 +00:00
FROM { $CFG -> prefix } role r ,
{ $CFG -> prefix } role_capabilities rc
2006-08-08 05:13:06 +00:00
WHERE rc . capability = '$capability'
2006-09-07 08:57:56 +00:00
AND rc . roleid = r . id $contextstr " ;
2006-08-08 05:13:06 +00:00
if ( isset ( $permission )) {
$selectroles .= " AND rc.permission = ' $permission ' " ;
}
return get_records_sql ( $selectroles );
}
/**
2006-08-31 07:40:48 +00:00
* This function makes a role - assignment ( a role for a user or group in a particular context )
2006-08-08 05:13:06 +00:00
* @ param $roleid - the role of the id
* @ param $userid - userid
* @ param $groupid - group id
* @ param $contextid - id of the context
* @ param $timestart - time this assignment becomes effective
* @ param $timeend - time this assignemnt ceases to be effective
* @ uses $USER
* @ return id - new id of the assigment
*/
2007-07-19 03:37:53 +00:00
function role_assign ( $roleid , $userid , $groupid , $contextid , $timestart = 0 , $timeend = 0 , $hidden = 0 , $enrol = 'manual' , $timemodified = '' ) {
2006-08-09 05:37:31 +00:00
global $USER , $CFG ;
2006-08-08 05:13:06 +00:00
2006-08-31 07:40:48 +00:00
/// Do some data validation
2006-08-08 05:13:06 +00:00
if ( empty ( $roleid )) {
2006-09-22 05:17:57 +00:00
debugging ( 'Role ID not provided' );
2006-08-31 07:40:48 +00:00
return false ;
2006-08-08 05:13:06 +00:00
}
if ( empty ( $userid ) && empty ( $groupid )) {
2006-09-22 05:17:57 +00:00
debugging ( 'Either userid or groupid must be provided' );
2006-08-31 07:40:48 +00:00
return false ;
2006-08-08 05:13:06 +00:00
}
2006-09-20 21:00:45 +00:00
2006-09-03 07:56:40 +00:00
if ( $userid && ! record_exists ( 'user' , 'id' , $userid )) {
2006-09-22 05:23:59 +00:00
debugging ( 'User ID ' . intval ( $userid ) . ' does not exist!' );
2006-09-03 07:56:40 +00:00
return false ;
}
2006-08-08 05:13:06 +00:00
2007-01-04 13:15:04 +13:00
if ( $groupid && ! groups_group_exists ( $groupid )) {
2006-09-22 05:23:59 +00:00
debugging ( 'Group ID ' . intval ( $groupid ) . ' does not exist!' );
2006-09-03 08:45:41 +00:00
return false ;
}
2006-09-03 07:56:40 +00:00
if ( ! $context = get_context_instance_by_id ( $contextid )) {
2006-09-22 05:23:59 +00:00
debugging ( 'Context ID ' . intval ( $contextid ) . ' does not exist!' );
2006-08-31 07:40:48 +00:00
return false ;
2006-08-08 05:13:06 +00:00
}
2006-08-31 07:40:48 +00:00
if (( $timestart and $timeend ) and ( $timestart > $timeend )) {
2006-09-22 05:17:57 +00:00
debugging ( 'The end time can not be earlier than the start time' );
2006-08-31 07:40:48 +00:00
return false ;
}
2007-07-19 03:37:53 +00:00
if ( ! $timemodified ) {
2007-09-13 13:44:35 +00:00
$timemodified = time ();
2007-07-19 03:37:53 +00:00
}
2006-09-03 07:56:40 +00:00
2006-08-31 07:40:48 +00:00
/// Check for existing entry
if ( $userid ) {
2006-09-03 07:56:40 +00:00
$ra = get_record ( 'role_assignments' , 'roleid' , $roleid , 'contextid' , $context -> id , 'userid' , $userid );
2006-08-31 07:40:48 +00:00
} else {
2006-09-03 07:56:40 +00:00
$ra = get_record ( 'role_assignments' , 'roleid' , $roleid , 'contextid' , $context -> id , 'groupid' , $groupid );
2006-08-31 07:40:48 +00:00
}
2006-09-01 06:30:01 +00:00
2006-08-31 07:40:48 +00:00
$newra = new object ;
2006-08-08 05:13:06 +00:00
2006-08-31 07:40:48 +00:00
if ( empty ( $ra )) { // Create a new entry
$newra -> roleid = $roleid ;
2006-09-03 07:56:40 +00:00
$newra -> contextid = $context -> id ;
2006-08-31 07:40:48 +00:00
$newra -> userid = $userid ;
$newra -> hidden = $hidden ;
2006-08-31 07:58:53 +00:00
$newra -> enrol = $enrol ;
2007-09-13 13:44:35 +00:00
/// Always round timestart downto 100 secs to help DBs to use their own caching algorithms
2007-03-07 04:56:07 +00:00
/// by repeating queries with the same exact parameters in a 100 secs time window
$newra -> timestart = round ( $timestart , - 2 );
2006-08-31 07:40:48 +00:00
$newra -> timeend = $timeend ;
2007-07-19 03:37:53 +00:00
$newra -> timemodified = $timemodified ;
2006-11-20 17:47:30 +00:00
$newra -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2006-08-31 07:40:48 +00:00
2006-09-01 06:30:01 +00:00
$success = insert_record ( 'role_assignments' , $newra );
2006-08-31 07:40:48 +00:00
} else { // We already have one, just update it
$newra -> id = $ra -> id ;
$newra -> hidden = $hidden ;
2006-08-31 07:58:53 +00:00
$newra -> enrol = $enrol ;
2007-09-13 13:44:35 +00:00
/// Always round timestart downto 100 secs to help DBs to use their own caching algorithms
2007-03-07 04:56:07 +00:00
/// by repeating queries with the same exact parameters in a 100 secs time window
$newra -> timestart = round ( $timestart , - 2 );
2006-08-31 07:40:48 +00:00
$newra -> timeend = $timeend ;
2007-07-19 03:37:53 +00:00
$newra -> timemodified = $timemodified ;
2006-11-20 17:47:30 +00:00
$newra -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2006-08-31 07:40:48 +00:00
2006-09-01 06:30:01 +00:00
$success = update_record ( 'role_assignments' , $newra );
}
2006-09-03 07:56:40 +00:00
if ( $success ) { /// Role was assigned, so do some other things
2007-10-09 12:49:54 +00:00
/// mark context as dirty - modules might use has_capability() in xxx_role_assing()
/// again expensive, but needed
mark_context_dirty ( $context -> path );
2006-09-03 07:56:40 +00:00
if ( ! empty ( $USER -> id ) && $USER -> id == $userid ) {
2007-10-09 12:49:54 +00:00
/// If the user is the current user, then do full reload of capabilities too.
2006-10-23 15:17:31 +00:00
load_all_capabilities ();
2006-09-03 07:56:40 +00:00
}
2007-09-13 13:44:35 +00:00
2006-09-13 08:07:14 +00:00
/// Ask all the modules if anything needs to be done for this user
if ( $mods = get_list_of_plugins ( 'mod' )) {
foreach ( $mods as $mod ) {
include_once ( $CFG -> dirroot . '/mod/' . $mod . '/lib.php' );
$functionname = $mod . '_role_assign' ;
if ( function_exists ( $functionname )) {
2007-03-21 06:07:46 +00:00
$functionname ( $userid , $context , $roleid );
2006-09-13 08:07:14 +00:00
}
}
}
2006-08-31 07:40:48 +00:00
}
2006-09-20 21:00:45 +00:00
2006-09-17 08:42:42 +00:00
/// now handle metacourse role assignments if in course context
2006-09-22 06:19:32 +00:00
if ( $success and $context -> contextlevel == CONTEXT_COURSE ) {
2006-09-17 08:42:42 +00:00
if ( $parents = get_records ( 'course_meta' , 'child_course' , $context -> instanceid )) {
foreach ( $parents as $parent ) {
2006-09-17 22:21:37 +00:00
sync_metacourse ( $parent -> parent_course );
2006-09-17 08:42:42 +00:00
}
}
}
2006-09-03 07:29:06 +00:00
return $success ;
2006-08-08 05:13:06 +00:00
}
/**
2006-09-01 06:10:45 +00:00
* Deletes one or more role assignments . You must specify at least one parameter .
2006-08-08 05:13:06 +00:00
* @ param $roleid
* @ param $userid
* @ param $groupid
* @ param $contextid
2007-03-22 12:27:52 +00:00
* @ param $enrol unassign only if enrolment type matches , NULL means anything
2006-08-08 05:13:06 +00:00
* @ return boolean - success or failure
*/
2007-03-22 12:27:52 +00:00
function role_unassign ( $roleid = 0 , $userid = 0 , $groupid = 0 , $contextid = 0 , $enrol = NULL ) {
2006-09-13 06:35:25 +00:00
global $USER , $CFG ;
2006-09-20 21:00:45 +00:00
2006-09-17 08:42:42 +00:00
$success = true ;
2006-09-13 06:35:25 +00:00
2006-09-01 06:10:45 +00:00
$args = array ( 'roleid' , 'userid' , 'groupid' , 'contextid' );
$select = array ();
foreach ( $args as $arg ) {
if ( $$arg ) {
$select [] = $arg . ' = ' . $$arg ;
}
}
2007-03-22 12:27:52 +00:00
if ( ! empty ( $enrol )) {
$select [] = " enrol=' $enrol ' " ;
}
2006-09-13 06:35:25 +00:00
2006-09-01 06:10:45 +00:00
if ( $select ) {
2006-09-17 08:42:42 +00:00
if ( $ras = get_records_select ( 'role_assignments' , implode ( ' AND ' , $select ))) {
$mods = get_list_of_plugins ( 'mod' );
foreach ( $ras as $ra ) {
2006-09-17 08:53:57 +00:00
/// infinite loop protection when deleting recursively
if ( ! $ra = get_record ( 'role_assignments' , 'id' , $ra -> id )) {
continue ;
}
2006-09-17 08:42:42 +00:00
$success = delete_records ( 'role_assignments' , 'id' , $ra -> id ) and $success ;
2006-09-17 08:53:57 +00:00
2007-10-09 12:49:54 +00:00
if ( ! $context = get_context_instance_by_id ( $ra -> contextid )) {
// strange error, not much to do
continue ;
}
/* mark contexts as dirty here , because we need the refreshed
* caps bellow to delete group membership and user_lastaccess !
* and yes , this is very expensive for bulk operations :- (
*/
mark_context_dirty ( $context -> path );
/// If the user is the current user, then do full reload of capabilities too.
2006-09-17 08:42:42 +00:00
if ( ! empty ( $USER -> id ) && $USER -> id == $ra -> userid ) {
2006-10-23 15:17:31 +00:00
load_all_capabilities ();
2006-09-17 08:42:42 +00:00
}
2006-09-13 08:07:14 +00:00
/// Ask all the modules if anything needs to be done for this user
2006-09-17 08:42:42 +00:00
foreach ( $mods as $mod ) {
include_once ( $CFG -> dirroot . '/mod/' . $mod . '/lib.php' );
$functionname = $mod . '_role_unassign' ;
if ( function_exists ( $functionname )) {
$functionname ( $ra -> userid , $context ); // watch out, $context might be NULL if something goes wrong
}
}
/// now handle metacourse role unassigment and removing from goups if in course context
2007-10-09 12:49:54 +00:00
if ( $context -> contextlevel == CONTEXT_COURSE ) {
2007-08-06 18:45:35 +00:00
2007-09-13 13:44:35 +00:00
// cleanup leftover course groups/subscriptions etc when user has
2007-08-06 18:45:35 +00:00
// no capability to view course
2007-07-27 05:43:05 +00:00
// this may be slow, but this is the proper way of doing it
if ( ! has_capability ( 'moodle/course:view' , $context , $ra -> userid )) {
2007-08-06 18:45:35 +00:00
// remove from groups
2007-08-15 20:21:01 +00:00
if ( $groups = groups_get_all_groups ( $context -> instanceid )) {
2006-09-17 08:42:42 +00:00
foreach ( $groups as $group ) {
delete_records ( 'groups_members' , 'groupid' , $group -> id , 'userid' , $ra -> userid );
}
}
2007-08-06 18:45:35 +00:00
// delete lastaccess records
delete_records ( 'user_lastaccess' , 'userid' , $ra -> userid , 'courseid' , $context -> instanceid );
2006-09-17 08:42:42 +00:00
}
2007-08-06 18:45:35 +00:00
2006-09-17 22:21:37 +00:00
//unassign roles in metacourses if needed
2006-09-17 08:42:42 +00:00
if ( $parents = get_records ( 'course_meta' , 'child_course' , $context -> instanceid )) {
foreach ( $parents as $parent ) {
2006-09-17 22:21:37 +00:00
sync_metacourse ( $parent -> parent_course );
2006-09-13 08:07:14 +00:00
}
}
}
}
2006-09-13 06:35:25 +00:00
}
2006-09-01 06:10:45 +00:00
}
2006-09-17 08:42:42 +00:00
return $success ;
2006-08-08 05:13:06 +00:00
}
2007-03-05 11:27:01 +00:00
/**
2006-09-20 21:00:45 +00:00
* A convenience function to take care of the common case where you
2006-09-17 16:06:25 +00:00
* just want to enrol someone using the default role into a course
*
* @ param object $course
* @ param object $user
* @ param string $enrol - the plugin used to do this enrolment
*/
function enrol_into_course ( $course , $user , $enrol ) {
2007-05-15 03:19:01 +00:00
$timestart = time ();
2007-07-04 02:26:36 +00:00
// remove time part from the timestamp and keep only the date part
$timestart = make_timestamp ( date ( 'Y' , $timestart ), date ( 'm' , $timestart ), date ( 'd' , $timestart ), 0 , 0 , 0 );
2006-09-17 16:06:25 +00:00
if ( $course -> enrolperiod ) {
2007-07-04 02:26:36 +00:00
$timeend = $timestart + $course -> enrolperiod ;
2006-09-17 16:06:25 +00:00
} else {
2007-05-15 03:19:01 +00:00
$timeend = 0 ;
2006-09-17 16:06:25 +00:00
}
if ( $role = get_default_course_role ( $course )) {
2006-09-20 02:19:08 +00:00
$context = get_context_instance ( CONTEXT_COURSE , $course -> id );
2006-09-22 13:16:32 +00:00
if ( ! role_assign ( $role -> id , $user -> id , 0 , $context -> id , $timestart , $timeend , 0 , $enrol )) {
2006-09-17 16:06:25 +00:00
return false ;
}
2006-09-20 21:00:45 +00:00
2007-09-19 07:15:12 +00:00
// force accessdata refresh for users visiting this context...
2007-09-19 07:11:42 +00:00
mark_context_dirty ( $context -> path );
2006-09-17 16:06:25 +00:00
email_welcome_message_to_user ( $course , $user );
2006-09-20 21:00:45 +00:00
2006-09-17 16:06:25 +00:00
add_to_log ( $course -> id , 'course' , 'enrol' , 'view.php?id=' . $course -> id , $user -> id );
return true ;
}
return false ;
}
2006-08-08 05:13:06 +00:00
/**
* Loads the capability definitions for the component ( from file ) . If no
* capabilities are defined for the component , we simply return an empty array .
* @ param $component - examples : 'moodle' , 'mod/forum' , 'block/quiz_results'
* @ return array of capabilities
*/
function load_capability_def ( $component ) {
global $CFG ;
if ( $component == 'moodle' ) {
$defpath = $CFG -> libdir . '/db/access.php' ;
$varprefix = 'moodle' ;
} else {
2006-09-13 03:56:38 +00:00
$compparts = explode ( '/' , $component );
2006-09-20 21:00:45 +00:00
2006-09-13 03:56:38 +00:00
if ( $compparts [ 0 ] == 'block' ) {
// Blocks are an exception. Blocks directory is 'blocks', and not
// 'block'. So we need to jump through hoops.
$defpath = $CFG -> dirroot . '/' . $compparts [ 0 ] .
's/' . $compparts [ 1 ] . '/db/access.php' ;
$varprefix = $compparts [ 0 ] . '_' . $compparts [ 1 ];
2007-07-24 08:51:45 +00:00
2006-12-11 15:47:23 +00:00
} else if ( $compparts [ 0 ] == 'format' ) {
2007-05-24 02:16:31 +00:00
// Similar to the above, course formats are 'format' while they
2006-12-11 15:47:23 +00:00
// are stored in 'course/format'.
$defpath = $CFG -> dirroot . '/course/' . $component . '/db/access.php' ;
$varprefix = $compparts [ 0 ] . '_' . $compparts [ 1 ];
2007-07-24 08:51:45 +00:00
2007-05-24 02:16:31 +00:00
} else if ( $compparts [ 0 ] == 'gradeimport' ) {
2007-07-24 08:51:45 +00:00
$defpath = $CFG -> dirroot . '/grade/import/' . $compparts [ 1 ] . '/db/access.php' ;
$varprefix = $compparts [ 0 ] . '_' . $compparts [ 1 ];
2007-05-24 02:16:31 +00:00
} else if ( $compparts [ 0 ] == 'gradeexport' ) {
2007-07-24 08:51:45 +00:00
$defpath = $CFG -> dirroot . '/grade/export/' . $compparts [ 1 ] . '/db/access.php' ;
$varprefix = $compparts [ 0 ] . '_' . $compparts [ 1 ];
2007-05-24 02:16:31 +00:00
} else if ( $compparts [ 0 ] == 'gradereport' ) {
2007-07-24 08:51:45 +00:00
$defpath = $CFG -> dirroot . '/grade/report/' . $compparts [ 1 ] . '/db/access.php' ;
$varprefix = $compparts [ 0 ] . '_' . $compparts [ 1 ];
2006-09-13 03:56:38 +00:00
} else {
$defpath = $CFG -> dirroot . '/' . $component . '/db/access.php' ;
$varprefix = str_replace ( '/' , '_' , $component );
}
2006-08-08 05:13:06 +00:00
}
$capabilities = array ();
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
if ( file_exists ( $defpath )) {
2006-12-12 17:23:31 +00:00
require ( $defpath );
2006-08-08 05:13:06 +00:00
$capabilities = $ { $varprefix . '_capabilities' };
}
return $capabilities ;
}
/**
* Gets the capabilities that have been cached in the database for this
* component .
* @ param $component - examples : 'moodle' , 'mod/forum' , 'block/quiz_results'
* @ return array of capabilities
*/
function get_cached_capabilities ( $component = 'moodle' ) {
if ( $component == 'moodle' ) {
$storedcaps = get_records_select ( 'capabilities' ,
" name LIKE 'moodle/%:%' " );
} else {
$storedcaps = get_records_select ( 'capabilities' ,
" name LIKE ' $component :%' " );
}
return $storedcaps ;
}
2007-03-03 21:07:07 +00:00
/**
* Returns default capabilities for given legacy role type .
*
* @ param string legacy role name
* @ return array
*/
function get_default_capabilities ( $legacyrole ) {
if ( ! $allcaps = get_records ( 'capabilities' )) {
error ( 'Error: no capabilitites defined!' );
}
$alldefs = array ();
$defaults = array ();
$components = array ();
foreach ( $allcaps as $cap ) {
2007-03-05 11:27:01 +00:00
if ( ! in_array ( $cap -> component , $components )) {
2007-03-03 21:07:07 +00:00
$components [] = $cap -> component ;
$alldefs = array_merge ( $alldefs , load_capability_def ( $cap -> component ));
}
}
foreach ( $alldefs as $name => $def ) {
if ( isset ( $def [ 'legacy' ][ $legacyrole ])) {
$defaults [ $name ] = $def [ 'legacy' ][ $legacyrole ];
}
}
//some exceptions
$defaults [ 'moodle/legacy:' . $legacyrole ] = CAP_ALLOW ;
if ( $legacyrole == 'admin' ) {
$defaults [ 'moodle/site:doanything' ] = CAP_ALLOW ;
}
return $defaults ;
}
2006-08-08 05:13:06 +00:00
2007-03-05 11:27:01 +00:00
/**
* Reset role capabilitites to default according to selected legacy capability .
* If several legacy caps selected , use the first from get_default_capabilities .
* If no legacy selected , removes all capabilities .
*
* @ param int @ roleid
*/
function reset_role_capabilities ( $roleid ) {
$sitecontext = get_context_instance ( CONTEXT_SYSTEM );
$legacyroles = get_legacy_roles ();
$defaultcaps = array ();
foreach ( $legacyroles as $ltype => $lcap ) {
$localoverride = get_local_override ( $roleid , $sitecontext -> id , $lcap );
if ( ! empty ( $localoverride -> permission ) and $localoverride -> permission == CAP_ALLOW ) {
//choose first selected legacy capability
$defaultcaps = get_default_capabilities ( $ltype );
break ;
}
}
delete_records ( 'role_capabilities' , 'roleid' , $roleid );
if ( ! empty ( $defaultcaps )) {
foreach ( $defaultcaps as $cap => $permission ) {
assign_capability ( $cap , $permission , $roleid , $sitecontext -> id );
}
}
}
2006-08-08 05:13:06 +00:00
/**
* Updates the capabilities table with the component capability definitions .
* If no parameters are given , the function updates the core moodle
* capabilities .
*
* Note that the absence of the db / access . php capabilities definition file
* will cause any stored capabilities for the component to be removed from
2006-09-20 21:00:45 +00:00
* the database .
2006-08-08 05:13:06 +00:00
*
* @ param $component - examples : 'moodle' , 'mod/forum' , 'block/quiz_results'
* @ return boolean
*/
function update_capabilities ( $component = 'moodle' ) {
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
$storedcaps = array ();
2006-08-31 08:36:36 +00:00
$filecaps = load_capability_def ( $component );
2006-08-08 05:13:06 +00:00
$cachedcaps = get_cached_capabilities ( $component );
if ( $cachedcaps ) {
foreach ( $cachedcaps as $cachedcap ) {
array_push ( $storedcaps , $cachedcap -> name );
2007-03-14 21:42:38 +00:00
// update risk bitmasks and context levels in existing capabilities if needed
2006-08-31 08:36:36 +00:00
if ( array_key_exists ( $cachedcap -> name , $filecaps )) {
if ( ! array_key_exists ( 'riskbitmask' , $filecaps [ $cachedcap -> name ])) {
2006-08-31 16:01:41 +00:00
$filecaps [ $cachedcap -> name ][ 'riskbitmask' ] = 0 ; // no risk if not specified
2006-08-31 08:36:36 +00:00
}
if ( $cachedcap -> riskbitmask != $filecaps [ $cachedcap -> name ][ 'riskbitmask' ]) {
2007-03-14 21:42:38 +00:00
$updatecap = new object ();
2006-08-31 08:36:36 +00:00
$updatecap -> id = $cachedcap -> id ;
$updatecap -> riskbitmask = $filecaps [ $cachedcap -> name ][ 'riskbitmask' ];
if ( ! update_record ( 'capabilities' , $updatecap )) {
2007-03-14 21:42:38 +00:00
return false ;
}
}
if ( ! array_key_exists ( 'contextlevel' , $filecaps [ $cachedcap -> name ])) {
$filecaps [ $cachedcap -> name ][ 'contextlevel' ] = 0 ; // no context level defined
}
if ( $cachedcap -> contextlevel != $filecaps [ $cachedcap -> name ][ 'contextlevel' ]) {
$updatecap = new object ();
$updatecap -> id = $cachedcap -> id ;
$updatecap -> contextlevel = $filecaps [ $cachedcap -> name ][ 'contextlevel' ];
if ( ! update_record ( 'capabilities' , $updatecap )) {
2006-08-31 08:36:36 +00:00
return false ;
}
}
}
2006-08-08 05:13:06 +00:00
}
}
2006-08-31 08:36:36 +00:00
2006-08-08 05:13:06 +00:00
// Are there new capabilities in the file definition?
$newcaps = array ();
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
foreach ( $filecaps as $filecap => $def ) {
2006-09-20 21:00:45 +00:00
if ( ! $storedcaps ||
2006-08-08 05:13:06 +00:00
( $storedcaps && in_array ( $filecap , $storedcaps ) === false )) {
2006-08-31 16:01:41 +00:00
if ( ! array_key_exists ( 'riskbitmask' , $def )) {
$def [ 'riskbitmask' ] = 0 ; // no risk if not specified
}
2006-08-08 05:13:06 +00:00
$newcaps [ $filecap ] = $def ;
}
}
// Add new capabilities to the stored definition.
foreach ( $newcaps as $capname => $capdef ) {
$capability = new object ;
$capability -> name = $capname ;
$capability -> captype = $capdef [ 'captype' ];
$capability -> contextlevel = $capdef [ 'contextlevel' ];
$capability -> component = $component ;
2006-08-31 08:36:36 +00:00
$capability -> riskbitmask = $capdef [ 'riskbitmask' ];
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
if ( ! insert_record ( 'capabilities' , $capability , false , 'id' )) {
return false ;
}
2006-09-20 21:00:45 +00:00
2007-09-13 13:44:35 +00:00
2007-05-27 04:53:02 +00:00
if ( isset ( $capdef [ 'clonepermissionsfrom' ]) && in_array ( $capdef [ 'clonepermissionsfrom' ], $storedcaps )){
if ( $rolecapabilities = get_records ( 'role_capabilities' , 'capability' , $capdef [ 'clonepermissionsfrom' ])){
foreach ( $rolecapabilities as $rolecapability ){
//assign_capability will update rather than insert if capability exists
2007-09-13 13:44:35 +00:00
if ( ! assign_capability ( $capname , $rolecapability -> permission ,
2007-05-27 04:53:02 +00:00
$rolecapability -> roleid , $rolecapability -> contextid , true )){
notify ( 'Could not clone capabilities for ' . $capname );
2007-09-13 13:44:35 +00:00
}
2007-05-27 04:53:02 +00:00
}
2007-09-13 13:44:35 +00:00
}
2006-08-08 05:13:06 +00:00
// Do we need to assign the new capabilities to roles that have the
// legacy capabilities moodle/legacy:* as well?
2007-05-27 04:53:02 +00:00
// we ignore legacy key if we have cloned permissions
} else if ( isset ( $capdef [ 'legacy' ]) && is_array ( $capdef [ 'legacy' ]) &&
2006-08-08 05:13:06 +00:00
! assign_legacy_capabilities ( $capname , $capdef [ 'legacy' ])) {
2006-09-12 07:07:30 +00:00
notify ( 'Could not assign legacy capabilities for ' . $capname );
2006-08-08 05:13:06 +00:00
}
}
// Are there any capabilities that have been removed from the file
// definition that we need to delete from the stored capabilities and
// role assignments?
capabilities_cleanup ( $component , $filecaps );
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
return true ;
}
/**
* Deletes cached capabilities that are no longer needed by the component .
* Also unassigns these capabilities from any roles that have them .
* @ param $component - examples : 'moodle' , 'mod/forum' , 'block/quiz_results'
* @ param $newcapdef - array of the new capability definitions that will be
* compared with the cached capabilities
* @ return int - number of deprecated capabilities that have been removed
*/
function capabilities_cleanup ( $component , $newcapdef = NULL ) {
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
$removedcount = 0 ;
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
if ( $cachedcaps = get_cached_capabilities ( $component )) {
foreach ( $cachedcaps as $cachedcap ) {
if ( empty ( $newcapdef ) ||
array_key_exists ( $cachedcap -> name , $newcapdef ) === false ) {
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
// Remove from capabilities cache.
if ( ! delete_records ( 'capabilities' , 'name' , $cachedcap -> name )) {
error ( 'Could not delete deprecated capability ' . $cachedcap -> name );
} else {
$removedcount ++ ;
}
// Delete from roles.
if ( $roles = get_roles_with_capability ( $cachedcap -> name )) {
foreach ( $roles as $role ) {
2006-09-08 02:33:02 +00:00
if ( ! unassign_capability ( $cachedcap -> name , $role -> id )) {
2006-08-08 05:13:06 +00:00
error ( 'Could not unassign deprecated capability ' .
$cachedcap -> name . ' from role ' . $role -> name );
}
}
}
} // End if.
}
}
return $removedcount ;
}
2006-08-14 07:15:03 +00:00
/****************
* UI FUNCTIONS *
****************/
2006-08-08 05:13:06 +00:00
/**
* prints human readable context identifier .
*/
2007-05-22 10:09:22 +00:00
function print_context_name ( $context , $withprefix = true , $short = false ) {
2006-08-13 15:48:57 +00:00
2006-08-09 04:51:05 +00:00
$name = '' ;
2006-09-22 06:19:32 +00:00
switch ( $context -> contextlevel ) {
2006-08-09 04:51:05 +00:00
2006-08-08 05:13:06 +00:00
case CONTEXT_SYSTEM : // by now it's a definite an inherit
2007-03-19 04:49:49 +00:00
$name = get_string ( 'coresystem' );
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
case CONTEXT_PERSONAL :
2006-08-09 04:51:05 +00:00
$name = get_string ( 'personal' );
2006-08-13 15:48:57 +00:00
break ;
2006-09-15 14:09:16 +00:00
case CONTEXT_USER :
2006-08-09 04:51:05 +00:00
if ( $user = get_record ( 'user' , 'id' , $context -> instanceid )) {
2007-05-22 10:09:22 +00:00
if ( $withprefix ){
$name = get_string ( 'user' ) . ': ' ;
}
$name .= fullname ( $user );
2006-08-09 04:51:05 +00:00
}
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
case CONTEXT_COURSECAT : // Coursecat -> coursecat or site
2006-08-09 04:51:05 +00:00
if ( $category = get_record ( 'course_categories' , 'id' , $context -> instanceid )) {
2007-05-22 10:09:22 +00:00
if ( $withprefix ){
$name = get_string ( 'category' ) . ': ' ;
}
$name .= format_string ( $category -> name );
2006-08-09 04:51:05 +00:00
}
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
case CONTEXT_COURSE : // 1 to 1 to course cat
2006-08-09 04:51:05 +00:00
if ( $course = get_record ( 'course' , 'id' , $context -> instanceid )) {
2007-05-22 10:09:22 +00:00
if ( $withprefix ){
if ( $context -> instanceid == SITEID ) {
$name = get_string ( 'site' ) . ': ' ;
} else {
$name = get_string ( 'course' ) . ': ' ;
}
2007-03-19 04:49:49 +00:00
}
2007-05-22 10:09:22 +00:00
if ( $short ){
$name .= format_string ( $course -> shortname );
} else {
$name .= format_string ( $course -> fullname );
}
2006-08-09 04:51:05 +00:00
}
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
case CONTEXT_GROUP : // 1 to 1 to course
2007-01-04 13:15:04 +13:00
if ( $name = groups_get_group_name ( $context -> instanceid )) {
2007-05-22 10:09:22 +00:00
if ( $withprefix ){
$name = get_string ( 'group' ) . ': ' . $name ;
2007-09-13 13:44:35 +00:00
}
2006-08-09 04:51:05 +00:00
}
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
case CONTEXT_MODULE : // 1 to 1 to course
2006-08-09 13:14:15 +00:00
if ( $cm = get_record ( 'course_modules' , 'id' , $context -> instanceid )) {
if ( $module = get_record ( 'modules' , 'id' , $cm -> module )) {
if ( $mod = get_record ( $module -> name , 'id' , $cm -> instance )) {
2007-05-22 10:09:22 +00:00
if ( $withprefix ){
$name = get_string ( 'activitymodule' ) . ': ' ;
}
$name .= $mod -> name ;
2006-08-09 13:14:15 +00:00
}
2006-08-09 04:51:05 +00:00
}
}
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
2007-08-22 19:20:20 +00:00
case CONTEXT_BLOCK : // not necessarily 1 to 1 to course
2006-08-09 13:14:15 +00:00
if ( $blockinstance = get_record ( 'block_instance' , 'id' , $context -> instanceid )) {
if ( $block = get_record ( 'block' , 'id' , $blockinstance -> blockid )) {
2006-09-05 06:30:12 +00:00
global $CFG ;
require_once ( " $CFG->dirroot /blocks/moodleblock.class.php " );
require_once ( " $CFG->dirroot /blocks/ $block->name /block_ $block->name .php " );
$blockname = " block_ $block->name " ;
if ( $blockobject = new $blockname ()) {
2007-05-22 10:09:22 +00:00
if ( $withprefix ){
$name = get_string ( 'block' ) . ': ' ;
}
$name .= $blockobject -> title ;
2006-09-05 06:30:12 +00:00
}
2006-08-09 04:51:05 +00:00
}
}
2006-08-13 15:48:57 +00:00
break ;
2006-08-08 05:13:06 +00:00
default :
2007-03-01 16:42:36 +00:00
error ( 'This is an unknown context (' . $context -> contextlevel . ') in print_context_name!' );
2006-08-13 15:48:57 +00:00
return false ;
}
return $name ;
2006-08-08 05:13:06 +00:00
}
/**
2006-09-20 21:00:45 +00:00
* Extracts the relevant capabilities given a contextid .
2006-08-08 05:13:06 +00:00
* All case based , example an instance of forum context .
* Will fetch all forum related capabilities , while course contexts
* Will fetch all capabilities
2006-08-14 05:55:40 +00:00
* @ param object context
2006-08-08 05:13:06 +00:00
* @ return array ();
*
* capabilities
* `name` varchar ( 150 ) NOT NULL ,
* `captype` varchar ( 50 ) NOT NULL ,
* `contextlevel` int ( 10 ) NOT NULL ,
* `component` varchar ( 100 ) NOT NULL ,
*/
2006-08-14 05:55:40 +00:00
function fetch_context_capabilities ( $context ) {
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
global $CFG ;
2006-08-08 05:13:06 +00:00
$sort = 'ORDER BY contextlevel,component,id' ; // To group them sensibly for display
2006-09-20 21:00:45 +00:00
2006-09-22 06:19:32 +00:00
switch ( $context -> contextlevel ) {
2006-08-08 05:13:06 +00:00
2006-08-09 13:14:15 +00:00
case CONTEXT_SYSTEM : // all
$SQL = " select * from { $CFG -> prefix } capabilities " ;
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_PERSONAL :
2006-08-15 08:29:29 +00:00
$SQL = " select * from { $CFG -> prefix } capabilities where contextlevel = " . CONTEXT_PERSONAL ;
2006-08-08 05:13:06 +00:00
break ;
2006-09-20 21:00:45 +00:00
2006-09-15 14:09:16 +00:00
case CONTEXT_USER :
2007-09-13 13:44:35 +00:00
$SQL = " SELECT *
FROM { $CFG -> prefix } capabilities
2006-10-02 08:49:07 +00:00
WHERE contextlevel = " .CONTEXT_USER;
2006-08-08 05:13:06 +00:00
break ;
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
case CONTEXT_COURSECAT : // all
2006-08-09 13:14:15 +00:00
$SQL = " select * from { $CFG -> prefix } capabilities " ;
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_COURSE : // all
2006-08-09 13:14:15 +00:00
$SQL = " select * from { $CFG -> prefix } capabilities " ;
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_GROUP : // group caps
break ;
case CONTEXT_MODULE : // mod caps
2006-08-09 13:14:15 +00:00
$cm = get_record ( 'course_modules' , 'id' , $context -> instanceid );
$module = get_record ( 'modules' , 'id' , $cm -> module );
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
$SQL = " select * from { $CFG -> prefix } capabilities where contextlevel = " . CONTEXT_MODULE . "
and component = 'mod/$module->name' " ;
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_BLOCK : // block caps
2006-08-09 13:14:15 +00:00
$cb = get_record ( 'block_instance' , 'id' , $context -> instanceid );
$block = get_record ( 'block' , 'id' , $cb -> blockid );
2006-09-20 21:00:45 +00:00
2007-11-15 07:46:04 +00:00
$SQL = " select * from { $CFG -> prefix } capabilities where (contextlevel = " . CONTEXT_BLOCK . " AND component = 'moodle')
OR ( component = 'block/$block->name' ) " ;
2006-08-08 05:13:06 +00:00
break ;
default :
return false ;
}
2006-09-22 21:31:19 +00:00
if ( ! $records = get_records_sql ( $SQL . ' ' . $sort )) {
$records = array ();
}
2006-09-30 20:11:44 +00:00
/// the rest of code is a bit hacky, think twice before modifying it :-(
2006-09-12 19:54:33 +00:00
// special sorting of core system capabiltites and enrollments
2006-10-02 08:57:00 +00:00
if ( in_array ( $context -> contextlevel , array ( CONTEXT_SYSTEM , CONTEXT_COURSECAT , CONTEXT_COURSE ))) {
2006-09-12 19:54:33 +00:00
$first = array ();
foreach ( $records as $key => $record ) {
if ( preg_match ( '|^moodle/|' , $record -> name ) and $record -> contextlevel == CONTEXT_SYSTEM ) {
$first [ $key ] = $record ;
unset ( $records [ $key ]);
} else if ( count ( $first )){
break ;
}
}
if ( count ( $first )) {
$records = $first + $records ; // merge the two arrays keeping the keys
}
2006-09-30 20:11:44 +00:00
} else {
$contextindependentcaps = fetch_context_independent_capabilities ();
$records = array_merge ( $contextindependentcaps , $records );
2006-09-12 19:54:33 +00:00
}
2006-09-30 20:11:44 +00:00
2006-08-08 05:13:06 +00:00
return $records ;
2006-09-20 21:00:45 +00:00
2006-08-08 05:13:06 +00:00
}
2006-09-20 08:30:49 +00:00
/**
* Gets the context - independent capabilities that should be overrridable in
* any context .
* @ return array of capability records from the capabilities table .
*/
function fetch_context_independent_capabilities () {
2006-09-20 21:00:45 +00:00
2006-10-08 11:00:49 +00:00
//only CONTEXT_SYSTEM capabilities here or it will break the hack in fetch_context_capabilities()
2006-09-20 08:30:49 +00:00
$contextindependentcaps = array (
'moodle/site:accessallgroups'
);
$records = array ();
2006-09-20 21:00:45 +00:00
2006-09-20 08:30:49 +00:00
foreach ( $contextindependentcaps as $capname ) {
$record = get_record ( 'capabilities' , 'name' , $capname );
array_push ( $records , $record );
}
return $records ;
}
2006-08-08 05:13:06 +00:00
/**
* This function pulls out all the resolved capabilities ( overrides and
2006-09-20 08:30:49 +00:00
* defaults ) of a role used in capability overrides in contexts at a given
2006-08-08 05:13:06 +00:00
* context .
2006-08-15 08:29:29 +00:00
* @ param obj $context
2006-08-08 05:13:06 +00:00
* @ param int $roleid
2006-09-20 09:00:04 +00:00
* @ param bool self - if set to true , resolve till this level , else stop at immediate parent level
2006-08-08 05:13:06 +00:00
* @ return array
*/
2006-08-28 08:42:30 +00:00
function role_context_capabilities ( $roleid , $context , $cap = '' ) {
2006-09-20 09:00:04 +00:00
global $CFG ;
2006-09-20 21:00:45 +00:00
2006-09-20 06:24:55 +00:00
$contexts = get_parent_contexts ( $context );
$contexts [] = $context -> id ;
2006-08-09 13:14:15 +00:00
$contexts = '(' . implode ( ',' , $contexts ) . ')' ;
2006-09-20 21:00:45 +00:00
2006-08-28 08:42:30 +00:00
if ( $cap ) {
2006-09-05 18:06:53 +00:00
$search = " AND rc.capability = ' $cap ' " ;
2006-08-28 08:42:30 +00:00
} else {
2006-09-20 21:00:45 +00:00
$search = '' ;
2006-08-28 08:42:30 +00:00
}
2006-09-20 21:00:45 +00:00
$SQL = " SELECT rc.*
FROM { $CFG -> prefix } role_capabilities rc ,
2006-09-20 09:00:04 +00:00
{ $CFG -> prefix } context c
WHERE rc . contextid in $contexts
AND rc . roleid = $roleid
AND rc . contextid = c . id $search
2006-09-22 06:19:32 +00:00
ORDER BY c . contextlevel DESC ,
2006-09-20 21:00:45 +00:00
rc . capability DESC " ;
2006-09-20 08:30:49 +00:00
2006-08-09 13:14:15 +00:00
$capabilities = array ();
2006-09-20 21:00:45 +00:00
2006-09-05 03:07:56 +00:00
if ( $records = get_records_sql ( $SQL )) {
// We are traversing via reverse order.
foreach ( $records as $record ) {
// If not set yet (i.e. inherit or not set at all), or currently we have a prohibit
if ( ! isset ( $capabilities [ $record -> capability ]) || $record -> permission <- 500 ) {
$capabilities [ $record -> capability ] = $record -> permission ;
2006-09-20 21:00:45 +00:00
}
2006-09-05 03:07:56 +00:00
}
2006-08-09 13:14:15 +00:00
}
return $capabilities ;
2006-08-08 05:13:06 +00:00
}
/**
2006-09-20 21:00:45 +00:00
* Recursive function which , given a context , find all parent context ids ,
2006-08-08 05:13:06 +00:00
* and return the array in reverse order , i . e . parent first , then grand
* parent , etc .
2007-09-19 07:23:30 +00:00
*
2006-08-08 05:13:06 +00:00
* @ param object $context
* @ return array ()
*/
function get_parent_contexts ( $context ) {
2006-09-20 08:30:49 +00:00
2007-09-19 07:23:30 +00:00
if ( $context -> path == '' ) {
return array ();
2007-01-11 06:06:11 +00:00
}
2007-09-19 07:23:30 +00:00
$parentcontexts = substr ( $context -> path , 1 ); // kill leading slash
2007-09-19 07:26:15 +00:00
$parentcontexts = explode ( '/' , $parentcontexts );
2007-09-19 07:23:30 +00:00
array_pop ( $parentcontexts ); // and remove its own id
2006-08-08 05:13:06 +00:00
2007-09-19 07:23:30 +00:00
return array_reverse ( $parentcontexts );
2006-08-08 05:13:06 +00:00
}
2006-09-20 08:30:49 +00:00
2007-02-09 02:24:59 +00:00
/**
* Recursive function which , given a context , find all its children context ids .
2007-09-19 06:52:34 +00:00
*
* When called for a course context , it will return the modules and blocks
* displayed in the course page .
*
* For course category contexts it will return categories and courses . It will
* NOT recurse into courses - if you want to do that , call it on the returned
* courses .
*
2007-09-19 07:25:25 +00:00
* If called on a course context it _will_ populate the cache with the appropriate
* contexts ; - )
2007-09-19 06:52:34 +00:00
*
2007-02-09 02:24:59 +00:00
* @ param object $context .
2007-09-19 06:52:34 +00:00
* @ return array of child records
2007-02-09 02:24:59 +00:00
*/
function get_child_contexts ( $context ) {
2007-09-19 06:52:34 +00:00
global $CFG , $context_cache ;
// We *MUST* populate the context_cache as the callers
// will probably ask for the full record anyway soon after
// soon after calling us ;-)
2007-02-09 02:24:59 +00:00
switch ( $context -> contextlevel ) {
case CONTEXT_BLOCK :
// No children.
return array ();
break ;
case CONTEXT_MODULE :
// No children.
return array ();
break ;
case CONTEXT_GROUP :
// No children.
return array ();
break ;
case CONTEXT_COURSE :
2007-09-19 06:52:34 +00:00
// Find
// - module instances - easy
// - groups
// - blocks assigned to the course-view page explicitly - easy
// - blocks pinned (note! we get all of them here, regardless of vis)
$sql = " SELECT ctx.*
FROM { $CFG -> prefix } context ctx
WHERE ctx . path LIKE '{$context->path}/%'
AND ctx . contextlevel IN ( " .CONTEXT_MODULE. " , " .CONTEXT_BLOCK. " )
UNION
SELECT ctx .*
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } groups g
ON ( ctx . instanceid = g . id AND ctx . contextlevel = " .CONTEXT_GROUP. " )
WHERE g . courseid = { $context -> instanceid }
UNION
SELECT ctx .*
FROM { $CFG -> prefix } context ctx
JOIN { $CFG -> prefix } block_pinned b
ON ( ctx . instanceid = b . blockid AND ctx . contextlevel = " .CONTEXT_BLOCK. " )
WHERE b . pagetype = 'course-view'
" ;
$rs = get_recordset_sql ( $sql );
$records = array ();
2007-10-10 12:19:27 +00:00
while ( $rec = rs_fetch_next_record ( $rs )) {
$records [ $rec -> id ] = $rec ;
$context_cache [ $rec -> contextlevel ][ $rec -> instanceid ] = $rec ;
}
2007-09-19 06:52:34 +00:00
rs_close ( $rs );
return $records ;
2007-02-09 02:24:59 +00:00
break ;
case CONTEXT_COURSECAT :
2007-09-19 06:52:34 +00:00
// Find
// - categories
// - courses
$sql = " SELECT ctx.*
FROM { $CFG -> prefix } context ctx
WHERE ctx . path LIKE '{$context->path}/%'
AND ctx . contextlevel IN ( " .CONTEXT_COURSECAT. " , " .CONTEXT_COURSE. " )
" ;
$rs = get_recordset_sql ( $sql );
$records = array ();
2007-10-10 12:19:27 +00:00
while ( $rec = rs_fetch_next_record ( $rs )) {
$records [ $rec -> id ] = $rec ;
$context_cache [ $rec -> contextlevel ][ $rec -> instanceid ] = $rec ;
2007-02-09 02:24:59 +00:00
}
2007-09-19 06:52:34 +00:00
rs_close ( $rs );
return $records ;
2007-02-09 02:24:59 +00:00
break ;
case CONTEXT_USER :
// No children.
return array ();
break ;
case CONTEXT_PERSONAL :
// No children.
return array ();
break ;
case CONTEXT_SYSTEM :
2007-09-19 06:52:34 +00:00
// Just get all the contexts except for CONTEXT_SYSTEM level
// and hope we don't OOM in the process - don't cache
$sql = 'SELECT c.*' .
2007-12-10 21:35:58 +00:00
'FROM ' . $CFG -> prefix . 'context c ' .
2007-02-09 02:24:59 +00:00
'WHERE contextlevel != ' . CONTEXT_SYSTEM ;
2007-09-19 06:52:34 +00:00
return get_records_sql ( $sql );
2007-02-09 02:24:59 +00:00
break ;
default :
2007-03-01 16:42:36 +00:00
error ( 'This is an unknown context (' . $context -> contextlevel . ') in get_child_contexts!' );
2007-02-09 02:24:59 +00:00
return false ;
}
}
2006-09-20 08:30:49 +00:00
/**
* Gets a string for sql calls , searching for stuff in this context or above
2006-09-14 09:08:07 +00:00
* @ param object $context
* @ return string
*/
function get_related_contexts_string ( $context ) {
if ( $parents = get_parent_contexts ( $context )) {
2006-09-20 21:00:45 +00:00
return ( ' IN (' . $context -> id . ',' . implode ( ',' , $parents ) . ')' );
2006-09-14 09:08:07 +00:00
} else {
return ( ' =' . $context -> id );
}
}
2006-09-20 08:30:49 +00:00
2006-08-14 07:15:03 +00:00
/**
* Returns the human - readable , translated version of the capability .
* Basically a big switch statement .
* @ param $capabilityname - e . g . mod / choice : readresponses
*/
2006-08-13 09:11:45 +00:00
function get_capability_string ( $capabilityname ) {
2006-09-20 21:00:45 +00:00
2006-08-14 07:15:03 +00:00
// Typical capabilityname is mod/choice:readresponses
2006-08-13 09:11:45 +00:00
$names = split ( '/' , $capabilityname );
$stringname = $names [ 1 ]; // choice:readresponses
2006-09-20 21:00:45 +00:00
$components = split ( ':' , $stringname );
2006-08-13 09:11:45 +00:00
$componentname = $components [ 0 ]; // choice
2006-08-09 13:14:15 +00:00
switch ( $names [ 0 ]) {
case 'mod' :
2006-08-13 09:11:45 +00:00
$string = get_string ( $stringname , $componentname );
2006-08-09 13:14:15 +00:00
break ;
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
case 'block' :
2006-08-13 09:11:45 +00:00
$string = get_string ( $stringname , 'block_' . $componentname );
2006-08-09 13:14:15 +00:00
break ;
2006-08-13 09:11:45 +00:00
2006-08-09 13:14:15 +00:00
case 'moodle' :
2006-08-13 09:11:45 +00:00
$string = get_string ( $stringname , 'role' );
2006-08-09 13:14:15 +00:00
break ;
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
case 'enrol' :
2006-08-13 09:11:45 +00:00
$string = get_string ( $stringname , 'enrol_' . $componentname );
2006-09-20 21:00:45 +00:00
break ;
2007-09-13 13:44:35 +00:00
2006-12-11 15:47:23 +00:00
case 'format' :
$string = get_string ( $stringname , 'format_' . $componentname );
break ;
2006-09-20 21:00:45 +00:00
2007-08-26 05:49:59 +00:00
case 'gradeexport' :
$string = get_string ( $stringname , 'gradeexport_' . $componentname );
break ;
case 'gradeimport' :
$string = get_string ( $stringname , 'gradeimport_' . $componentname );
break ;
case 'gradereport' :
$string = get_string ( $stringname , 'gradereport_' . $componentname );
break ;
2006-08-09 13:14:15 +00:00
default :
2006-08-13 09:11:45 +00:00
$string = get_string ( $stringname );
2006-09-20 21:00:45 +00:00
break ;
2006-08-09 13:14:15 +00:00
}
2006-08-13 09:11:45 +00:00
return $string ;
2006-08-08 05:13:06 +00:00
}
2006-08-14 07:15:03 +00:00
/**
* This gets the mod / block / course / core etc strings .
* @ param $component
* @ param $contextlevel
*/
2006-08-08 05:13:06 +00:00
function get_component_string ( $component , $contextlevel ) {
2006-08-09 13:14:15 +00:00
switch ( $contextlevel ) {
2006-08-08 05:13:06 +00:00
2006-08-09 13:14:15 +00:00
case CONTEXT_SYSTEM :
2006-09-12 20:03:08 +00:00
if ( preg_match ( '|^enrol/|' , $component )) {
$langname = str_replace ( '/' , '_' , $component );
$string = get_string ( 'enrolname' , $langname );
2006-09-24 11:32:11 +00:00
} else if ( preg_match ( '|^block/|' , $component )) {
$langname = str_replace ( '/' , '_' , $component );
$string = get_string ( 'blockname' , $langname );
2006-09-12 19:54:33 +00:00
} else {
$string = get_string ( 'coresystem' );
}
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_PERSONAL :
2006-08-09 13:14:15 +00:00
$string = get_string ( 'personal' );
2006-08-08 05:13:06 +00:00
break ;
2006-09-15 14:09:16 +00:00
case CONTEXT_USER :
2006-08-09 13:14:15 +00:00
$string = get_string ( 'users' );
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_COURSECAT :
2006-08-09 13:14:15 +00:00
$string = get_string ( 'categories' );
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_COURSE :
2007-09-13 13:44:35 +00:00
if ( preg_match ( '|^gradeimport/|' , $component )
|| preg_match ( '|^gradeexport/|' , $component )
2007-08-16 08:48:53 +00:00
|| preg_match ( '|^gradereport/|' , $component )) {
2007-09-13 13:44:35 +00:00
$string = get_string ( 'gradebook' , 'admin' );
2007-08-16 08:48:53 +00:00
} else {
$string = get_string ( 'course' );
}
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_GROUP :
2006-08-09 13:14:15 +00:00
$string = get_string ( 'group' );
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_MODULE :
2006-08-09 13:14:15 +00:00
$string = get_string ( 'modulename' , basename ( $component ));
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_BLOCK :
2007-08-13 10:08:15 +00:00
if ( $component == 'moodle' ){
$string = get_string ( 'block' );
} else {
$string = get_string ( 'blockname' , 'block_' . basename ( $component ));
}
2006-08-08 05:13:06 +00:00
break ;
default :
2007-03-01 16:42:36 +00:00
error ( 'This is an unknown context $contextlevel (' . $contextlevel . ') in get_component_string!' );
2006-08-08 05:13:06 +00:00
return false ;
2006-09-20 21:00:45 +00:00
2006-08-09 13:14:15 +00:00
}
return $string ;
2006-08-08 05:13:06 +00:00
}
2006-08-14 07:15:03 +00:00
2006-09-20 08:30:49 +00:00
/**
* Gets the list of roles assigned to this context and up ( parents )
2006-08-23 06:36:08 +00:00
* @ param object $context
2006-11-15 04:28:18 +00:00
* @ param view - set to true when roles are pulled for display only
2007-09-13 13:44:35 +00:00
* this is so that we can filter roles with no visible
2006-11-15 04:28:18 +00:00
* assignment , for example , you might want to " hide " all
* course creators when browsing the course participants
* list .
2006-08-23 06:36:08 +00:00
* @ return array
*/
2006-11-15 04:28:18 +00:00
function get_roles_used_in_context ( $context , $view = false ) {
2006-08-14 08:14:02 +00:00
global $CFG ;
2007-09-13 13:44:35 +00:00
2006-11-15 04:28:18 +00:00
// filter for roles with all hidden assignments
// no need to return when only pulling roles for reviewing
// e.g. participants page.
2007-09-13 13:44:35 +00:00
$hiddensql = ( $view && ! has_capability ( 'moodle/role:viewhiddenassigns' , $context )) ? ' AND ra.hidden = 0 ' : '' ;
2006-09-19 02:47:55 +00:00
$contextlist = get_related_contexts_string ( $context );
2006-09-20 21:00:45 +00:00
2006-09-20 08:30:49 +00:00
$sql = " SELECT DISTINCT r.id,
r . name ,
r . shortname ,
r . sortorder
FROM { $CFG -> prefix } role_assignments ra ,
2006-09-20 21:00:45 +00:00
{ $CFG -> prefix } role r
WHERE r . id = ra . roleid
2006-09-20 08:30:49 +00:00
AND ra . contextid $contextlist
2006-11-15 04:28:18 +00:00
$hiddensql
2006-09-20 08:30:49 +00:00
ORDER BY r . sortorder ASC " ;
2006-09-20 21:00:45 +00:00
2006-09-20 08:30:49 +00:00
return get_records_sql ( $sql );
2006-08-14 08:14:02 +00:00
}
2007-10-09 12:49:54 +00:00
/**
* This function is used to print roles column in user profile page .
2006-08-23 06:36:08 +00:00
* @ param int userid
* @ param int contextid
* @ return string
*/
2006-08-15 08:29:29 +00:00
function get_user_roles_in_context ( $userid , $contextid ){
global $CFG ;
2006-09-20 21:00:45 +00:00
2006-08-15 08:29:29 +00:00
$rolestring = '' ;
$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' ;
if ( $roles = get_records_sql ( $SQL )) {
foreach ( $roles as $userrole ) {
$rolestring .= '<a href="' . $CFG -> wwwroot . '/user/index.php?contextid=' . $userrole -> contextid . '&roleid=' . $userrole -> roleid . '">' . $userrole -> name . '</a>, ' ;
2006-09-20 21:00:45 +00:00
}
2006-08-15 08:29:29 +00:00
}
return rtrim ( $rolestring , ', ' );
}
2006-08-18 08:01:16 +00:00
2006-08-23 06:36:08 +00:00
/**
* Checks if a user can override capabilities of a particular role in this context
* @ param object $context
* @ param int targetroleid - the id of the role you want to override
* @ return boolean
*/
2006-08-18 08:01:16 +00:00
function user_can_override ( $context , $targetroleid ) {
// first check if user has override capability
// if not return false;
if ( ! has_capability ( 'moodle/role:override' , $context )) {
2006-09-20 21:00:45 +00:00
return false ;
2006-08-18 08:01:16 +00:00
}
// pull out all active roles of this user from this context(or above)
2006-08-19 08:12:45 +00:00
if ( $userroles = get_user_roles ( $context )) {
foreach ( $userroles as $userrole ) {
// if any in the role_allow_override table, then it's ok
if ( get_record ( 'role_allow_override' , 'roleid' , $userrole -> roleid , 'allowoverride' , $targetroleid )) {
return true ;
}
2006-08-18 08:01:16 +00:00
}
}
2006-09-20 21:00:45 +00:00
2006-08-18 08:01:16 +00:00
return false ;
2006-09-20 21:00:45 +00:00
2006-08-18 08:01:16 +00:00
}
2006-08-23 06:36:08 +00:00
/**
* Checks if a user can assign users to a particular role in this context
* @ param object $context
* @ param int targetroleid - the id of the role you want to assign users to
* @ return boolean
*/
2006-08-18 08:01:16 +00:00
function user_can_assign ( $context , $targetroleid ) {
2006-09-20 21:00:45 +00:00
2006-08-18 08:01:16 +00:00
// first check if user has override capability
// if not return false;
if ( ! has_capability ( 'moodle/role:assign' , $context )) {
2006-09-20 21:00:45 +00:00
return false ;
2006-08-18 08:01:16 +00:00
}
// pull out all active roles of this user from this context(or above)
2006-08-19 08:12:45 +00:00
if ( $userroles = get_user_roles ( $context )) {
foreach ( $userroles as $userrole ) {
// if any in the role_allow_override table, then it's ok
if ( get_record ( 'role_allow_assign' , 'roleid' , $userrole -> roleid , 'allowassign' , $targetroleid )) {
return true ;
}
2006-08-18 08:01:16 +00:00
}
}
2006-09-20 21:00:45 +00:00
return false ;
2006-08-18 08:01:16 +00:00
}
2006-09-23 12:51:00 +00:00
/** Returns all site roles in correct sort order .
*
*/
function get_all_roles () {
return get_records ( 'role' , '' , '' , 'sortorder ASC' );
}
2006-08-23 06:36:08 +00:00
/**
* gets all the user roles assigned in this context , or higher contexts
* this is mainly used when checking if a user can assign a role , or overriding a role
* i . e . we need to know what this user holds , in order to verify against allow_assign and
* allow_override tables
* @ param object $context
* @ param int $userid
2006-11-16 08:29:25 +00:00
* @ param view - set to true when roles are pulled for display only
2007-09-13 13:44:35 +00:00
* this is so that we can filter roles with no visible
2006-11-16 08:29:25 +00:00
* assignment , for example , you might want to " hide " all
* course creators when browsing the course participants
* list .
2006-08-23 06:36:08 +00:00
* @ return array
*/
2006-11-16 08:29:25 +00:00
function get_user_roles ( $context , $userid = 0 , $checkparentcontexts = true , $order = 'c.contextlevel DESC, r.sortorder ASC' , $view = false ) {
2006-08-18 08:01:16 +00:00
global $USER , $CFG , $db ;
2006-08-19 08:12:45 +00:00
if ( empty ( $userid )) {
if ( empty ( $USER -> id )) {
return array ();
}
$userid = $USER -> id ;
}
2006-11-16 08:29:25 +00:00
// set up hidden sql
2006-11-17 08:57:50 +00:00
$hiddensql = ( $view && ! has_capability ( 'moodle/role:viewhiddenassigns' , $context )) ? ' AND ra.hidden = 0 ' : '' ;
2006-08-19 08:12:45 +00:00
2006-09-16 15:22:55 +00:00
if ( $checkparentcontexts && ( $parents = get_parent_contexts ( $context ))) {
$contexts = ' ra.contextid IN (' . implode ( ',' , $parents ) . ',' . $context -> id . ')' ;
2006-08-19 08:12:45 +00:00
} else {
2006-09-16 15:22:55 +00:00
$contexts = ' ra.contextid = \'' . $context -> id . '\'' ;
2006-08-19 08:12:45 +00:00
}
2006-09-18 17:40:22 +00:00
return get_records_sql ( ' SELECT ra .* , r . name , r . shortname
2006-09-16 15:22:55 +00:00
FROM '.$CFG->prefix.' role_assignments ra ,
2006-09-17 03:33:22 +00:00
'.$CFG->prefix.' role r ,
'.$CFG->prefix.' context c
2006-08-19 08:12:45 +00:00
WHERE ra . userid = ' . $userid .
2006-09-16 15:22:55 +00:00
' AND ra . roleid = r . id
2006-09-17 03:33:22 +00:00
AND ra . contextid = c . id
2006-11-16 08:29:25 +00:00
AND ' . $contexts . $hiddensql .
2006-11-16 05:17:43 +00:00
' ORDER BY ' . $order );
2006-08-18 08:01:16 +00:00
}
2006-08-23 06:36:08 +00:00
/**
2006-09-20 21:00:45 +00:00
* Creates a record in the allow_override table
2006-08-23 06:36:08 +00:00
* @ param int sroleid - source roleid
* @ param int troleid - target roleid
* @ return int - id or false
*/
function allow_override ( $sroleid , $troleid ) {
2006-09-23 12:51:00 +00:00
$record = new object ();
2006-08-23 06:36:08 +00:00
$record -> roleid = $sroleid ;
$record -> allowoverride = $troleid ;
return insert_record ( 'role_allow_override' , $record );
}
/**
2006-09-20 21:00:45 +00:00
* Creates a record in the allow_assign table
2006-08-23 06:36:08 +00:00
* @ param int sroleid - source roleid
* @ param int troleid - target roleid
* @ return int - id or false
*/
function allow_assign ( $sroleid , $troleid ) {
2006-09-17 07:00:47 +00:00
$record = new object ;
2006-08-23 06:36:08 +00:00
$record -> roleid = $sroleid ;
$record -> allowassign = $troleid ;
return insert_record ( 'role_allow_assign' , $record );
}
/**
2006-09-17 07:00:47 +00:00
* Gets a list of roles that this user can assign in this context
2006-08-23 06:36:08 +00:00
* @ param object $context
2007-09-19 07:27:46 +00:00
* @ param string $field
2006-08-23 06:36:08 +00:00
* @ return array
*/
2006-10-03 08:54:46 +00:00
function get_assignable_roles ( $context , $field = " name " ) {
2006-08-23 06:36:08 +00:00
2007-09-19 07:27:46 +00:00
global $CFG ;
2006-09-17 07:00:47 +00:00
2007-09-19 07:27:46 +00:00
// this users RAs
$ras = get_user_roles ( $context );
$roleids = array ();
foreach ( $ras as $ra ) {
$roleids [] = $ra -> roleid ;
}
unset ( $ra );
if ( count ( $roleids ) === 0 ) {
return array ();
}
$roleids = implode ( ',' , $roleids );
// The subselect scopes the DISTINCT down to
// the role ids - a DISTINCT over the whole of
// the role table is much more expensive on some DBs
$sql = " SELECT r.id, r. $field
FROM { $CFG -> prefix } role r
JOIN ( SELECT DISTINCT allowassign as allowedrole
FROM { $CFG -> prefix } role_allow_assign raa
WHERE raa . roleid IN ( $roleids ) ) ar
ON r . id = ar . allowedrole
ORDER BY sortorder ASC " ;
$rs = get_recordset_sql ( $sql );
$roles = array ();
2007-10-10 12:19:27 +00:00
while ( $r = rs_fetch_next_record ( $rs )) {
$roles [ $r -> id ] = $r -> { $field };
2006-08-23 06:36:08 +00:00
}
2007-10-10 12:19:27 +00:00
rs_close ( $rs );
2007-10-03 03:33:57 +00:00
foreach ( $roles as $roleid => $rolename ) {
$roles [ $roleid ] = strip_tags ( format_string ( $rolename , true ));
}
2007-09-19 07:27:46 +00:00
return $roles ;
2006-08-23 06:36:08 +00:00
}
/**
2006-09-17 07:00:47 +00:00
* Gets a list of roles that this user can override in this context
2006-08-23 06:36:08 +00:00
* @ param object $context
* @ return array
*/
2007-03-05 11:27:01 +00:00
function get_overridable_roles ( $context ) {
2006-08-23 06:36:08 +00:00
$options = array ();
2006-09-17 07:00:47 +00:00
2006-09-23 12:51:00 +00:00
if ( $roles = get_all_roles ()) {
2006-09-17 07:00:47 +00:00
foreach ( $roles as $role ) {
if ( user_can_override ( $context , $role -> id )) {
2006-09-23 12:46:53 +00:00
$options [ $role -> id ] = strip_tags ( format_string ( $role -> name , true ));
2006-09-17 07:00:47 +00:00
}
2006-08-23 06:36:08 +00:00
}
2006-09-17 07:00:47 +00:00
}
2006-09-20 21:00:45 +00:00
return $options ;
2006-08-23 06:36:08 +00:00
}
2006-08-28 08:42:30 +00:00
2007-03-05 11:27:01 +00:00
/**
2006-09-17 16:06:25 +00:00
* Returns a role object that is the default role for new enrolments
* in a given course
*
2006-09-20 21:00:45 +00:00
* @ param object $course
2006-09-17 16:06:25 +00:00
* @ return object $role
*/
function get_default_course_role ( $course ) {
global $CFG ;
/// First let's take the default role the course may have
if ( ! empty ( $course -> defaultrole )) {
if ( $role = get_record ( 'role' , 'id' , $course -> defaultrole )) {
return $role ;
}
}
/// Otherwise the site setting should tell us
if ( $CFG -> defaultcourseroleid ) {
if ( $role = get_record ( 'role' , 'id' , $CFG -> defaultcourseroleid )) {
return $role ;
}
}
/// It's unlikely we'll get here, but just in case, try and find a student role
if ( $studentroles = get_roles_with_capability ( 'moodle/legacy:student' , CAP_ALLOW )) {
return array_shift ( $studentroles ); /// Take the first one
}
return NULL ;
}
2006-08-28 08:42:30 +00:00
/**
2007-12-05 17:25:25 +00:00
* This function is supposed to return a list of all the users who have a particular capability in
* a particular context .
*
* However , at the moment it is buggy . For example it does not resolve conflicting capabilities
* properly - that is if a person has 2 roles , one with allow and one with prevent , they
* will incorrectly be included . In pracitce , this very rarely occurrs , so using this function is
* still the best things you can do , and hopefully one day it will be fixed .
*
* Pleaes note if you do not pass in $fields , then this function attempts to get u .*
* which can be rather large .
*
2006-08-28 08:42:30 +00:00
* @ param $context - object
* @ param $capability - string capability
* @ param $fields - fields to be pulled
* @ param $sort - the sort order
2006-09-05 18:55:16 +00:00
* @ param $limitfrom - number of records to skip ( offset )
2006-09-20 21:00:45 +00:00
* @ param $limitnum - number of records to fetch
2007-06-26 16:16:46 +00:00
* @ param $groups - single group or array of groups - only return
* users who are in one of these group ( s ) .
2006-09-15 09:08:48 +00:00
* @ param $exceptions - list of users to exclude
2006-11-16 08:29:25 +00:00
* @ param view - set to true when roles are pulled for display only
2007-09-13 13:44:35 +00:00
* this is so that we can filter roles with no visible
2006-11-16 08:29:25 +00:00
* assignment , for example , you might want to " hide " all
* course creators when browsing the course participants
* list .
2007-09-13 13:44:35 +00:00
* @ param boolean $useviewallgroups if $groups is set the return users who
2007-06-26 16:16:46 +00:00
* have capability both $capability and moodle / site : accessallgroups
* in this context , as well as users who have $capability and who are
* in $groups .
2006-08-28 08:42:30 +00:00
*/
2006-09-20 21:00:45 +00:00
function get_users_by_capability ( $context , $capability , $fields = '' , $sort = '' ,
2007-06-26 16:16:46 +00:00
$limitfrom = '' , $limitnum = '' , $groups = '' , $exceptions = '' , $doanything = true ,
$view = false , $useviewallgroups = false ) {
2006-08-28 08:42:30 +00:00
global $CFG ;
2006-09-20 21:00:45 +00:00
2007-12-06 03:57:05 +00:00
/// Sorting out exceptions
$exceptionsql = $exceptions ? " AND u.id NOT IN ( $exceptions ) " : '' ;
2007-09-27 01:46:41 +00:00
/// check for front page course, and see if default front page role has the required capability
2007-12-06 03:57:05 +00:00
/// if it does, we can just return all users, and we do not need to check further, just return all users
2007-12-05 17:25:25 +00:00
2007-09-27 01:46:41 +00:00
$frontpagectx = get_context_instance ( CONTEXT_COURSE , SITEID );
2007-10-03 14:38:55 +00:00
if ( ! empty ( $CFG -> defaultfrontpageroleid ) && ( $context -> id == $frontpagectx -> id || strstr ( $context -> path , '/' . $frontpagectx -> id . '/' ))) {
2007-12-06 03:57:05 +00:00
2007-09-27 01:46:41 +00:00
$roles = get_roles_with_capability ( $capability , CAP_ALLOW , $context );
2007-12-06 03:57:05 +00:00
// if this condition is satisfied, then everyone is selected, no need to check further
2007-09-27 01:46:41 +00:00
if ( in_array ( $CFG -> defaultfrontpageroleid , array_keys ( $roles ))) {
2007-12-06 03:57:05 +00:00
if ( empty ( $fields )) {
$fields = 'u.*' ;
}
if ( empty ( $sort )) {
$sort = 'u.lastaccess' ;
}
return get_records_sql ( " SELECT $fields FROM { $CFG -> prefix } user u $exceptionsql ORDER BY $sort " , $limitfrom , $limitnum );
2007-09-27 01:46:41 +00:00
}
}
2006-09-16 13:54:57 +00:00
/// Sorting out groups
2006-09-11 08:56:23 +00:00
if ( $groups ) {
if ( is_array ( $groups )) {
2007-06-26 16:16:46 +00:00
$grouptest = 'gm.groupid IN (' . implode ( ',' , $groups ) . ')' ;
2006-09-11 08:56:23 +00:00
} else {
2007-06-26 16:16:46 +00:00
$grouptest = 'gm.groupid = ' . $groups ;
}
$grouptest = 'ra.userid IN (SELECT userid FROM ' .
$CFG -> prefix . 'groups_members gm WHERE ' . $grouptest . ')' ;
2007-09-13 13:44:35 +00:00
2007-06-26 16:16:46 +00:00
if ( $useviewallgroups ) {
$viewallgroupsusers = get_users_by_capability ( $context ,
2007-08-27 03:54:59 +00:00
'moodle/site:accessallgroups' , 'u.id, u.id' , '' , '' , '' , '' , $exceptions );
2007-09-13 13:44:35 +00:00
$groupsql = ' AND (' . $grouptest . ' OR ra.userid IN (' .
2007-06-26 16:16:46 +00:00
implode ( ',' , array_keys ( $viewallgroupsusers )) . '))' ;
2007-09-13 13:44:35 +00:00
} else {
2007-06-26 16:16:46 +00:00
$groupsql = ' AND ' . $grouptest ;
2006-09-11 08:56:23 +00:00
}
} else {
2006-09-20 21:00:45 +00:00
$groupsql = '' ;
2006-09-11 08:56:23 +00:00
}
2006-09-20 21:00:45 +00:00
2006-09-16 13:54:57 +00:00
/// Set up default fields
if ( empty ( $fields )) {
2006-09-16 15:22:55 +00:00
$fields = 'u.*, ul.timeaccess as lastaccess, ra.hidden' ;
2006-09-16 13:54:57 +00:00
}
/// Set up default sort
if ( empty ( $sort )) {
$sort = 'ul.timeaccess' ;
}
2006-09-20 21:00:45 +00:00
$sortby = $sort ? " ORDER BY $sort " : '' ;
2006-11-16 08:29:25 +00:00
/// Set up hidden sql
2006-11-17 08:57:50 +00:00
$hiddensql = ( $view && ! has_capability ( 'moodle/role:viewhiddenassigns' , $context )) ? ' AND ra.hidden = 0 ' : '' ;
2006-09-20 21:00:45 +00:00
2006-09-16 13:54:57 +00:00
/// If context is a course, then construct sql for ul
2006-09-22 06:19:32 +00:00
if ( $context -> contextlevel == CONTEXT_COURSE ) {
2006-09-15 09:08:48 +00:00
$courseid = $context -> instanceid ;
2006-11-16 05:17:43 +00:00
$coursesql1 = " AND ul.courseid = $courseid " ;
2006-09-15 13:51:42 +00:00
} else {
2006-11-16 05:17:43 +00:00
$coursesql1 = '' ;
2006-09-15 09:08:48 +00:00
}
2006-09-16 13:54:57 +00:00
/// Sorting out roles with this capability set
2006-09-22 05:17:57 +00:00
if ( $possibleroles = get_roles_with_capability ( $capability , CAP_ALLOW , $context )) {
2006-09-25 03:00:50 +00:00
if ( ! $doanything ) {
2006-10-25 08:38:14 +00:00
if ( ! $sitecontext = get_context_instance ( CONTEXT_SYSTEM )) {
2006-09-25 03:00:50 +00:00
return false ; // Something is seriously wrong
}
$doanythingroles = get_roles_with_capability ( 'moodle/site:doanything' , CAP_ALLOW , $sitecontext );
2006-09-24 16:14:39 +00:00
}
2006-09-22 05:17:57 +00:00
$validroleids = array ();
2006-09-24 16:14:39 +00:00
foreach ( $possibleroles as $possiblerole ) {
2006-09-25 03:00:50 +00:00
if ( ! $doanything ) {
if ( isset ( $doanythingroles [ $possiblerole -> id ])) { // We don't want these included
continue ;
}
2006-09-24 16:14:39 +00:00
}
2006-09-27 08:01:22 +00:00
if ( $caps = role_context_capabilities ( $possiblerole -> id , $context , $capability )) { // resolved list
if ( isset ( $caps [ $capability ]) && $caps [ $capability ] > 0 ) { // resolved capability > 0
$validroleids [] = $possiblerole -> id ;
}
2006-09-22 05:17:57 +00:00
}
2006-08-28 08:42:30 +00:00
}
2006-09-25 03:00:50 +00:00
if ( empty ( $validroleids )) {
return false ;
}
2006-09-22 05:17:57 +00:00
$roleids = '(' . implode ( ',' , $validroleids ) . ')' ;
} else {
return false ; // No need to continue, since no roles have this capability set
2006-09-20 21:00:45 +00:00
}
2006-09-16 13:54:57 +00:00
/// Construct the main SQL
2006-09-15 09:08:48 +00:00
$select = " SELECT $fields " ;
2006-09-20 21:00:45 +00:00
$from = " FROM { $CFG -> prefix } user u
INNER JOIN { $CFG -> prefix } role_assignments ra ON ra . userid = u . id
2006-09-25 06:09:06 +00:00
INNER JOIN { $CFG -> prefix } role r ON r . id = ra . roleid
2007-06-26 16:16:46 +00:00
LEFT OUTER JOIN { $CFG -> prefix } user_lastaccess ul ON ( ul . userid = u . id $coursesql1 ) " ;
2006-09-20 21:00:45 +00:00
$where = " WHERE ra.contextid " . get_related_contexts_string ( $context ) . "
AND u . deleted = 0
AND ra . roleid in $roleids
2006-09-15 09:08:48 +00:00
$exceptionsql
2006-11-16 08:29:25 +00:00
$groupsql
$hiddensql " ;
2007-09-13 13:44:35 +00:00
2006-09-20 21:00:45 +00:00
return get_records_sql ( $select . $from . $where . $sortby , $limitfrom , $limitnum );
2006-08-28 08:42:30 +00:00
}
2006-09-03 07:56:40 +00:00
2006-09-12 07:37:23 +00:00
/**
* gets all the users assigned this role in this context or higher
2007-09-19 07:09:13 +00:00
* @ param int roleid ( can also be an array of ints ! )
2006-09-12 07:37:23 +00:00
* @ param int contextid
* @ param bool parent if true , get list of users assigned in higher context too
2007-09-19 07:09:13 +00:00
* @ param string fields - fields from user ( u . ) , role assignment ( ra ) or role ( r . )
* @ param string sort - sort from user ( u . ) , role assignment ( ra ) or role ( r . )
* @ param bool gethidden - whether to fetch hidden enrolments too
2006-09-12 07:37:23 +00:00
* @ return array ()
*/
2007-11-22 05:17:26 +00:00
function get_role_users ( $roleid , $context , $parent = false , $fields = '' , $sort = 'u.lastname ASC' , $gethidden = true , $group = '' , $limitfrom = '' , $limitnum = '' ) {
2006-09-12 07:37:23 +00:00
global $CFG ;
2006-09-20 21:00:45 +00:00
2006-10-25 07:20:28 +00:00
if ( empty ( $fields )) {
$fields = 'u.id, u.confirmed, u.username, u.firstname, u.lastname, ' .
'u.maildisplay, u.mailformat, u.maildigest, u.email, u.city, ' .
'u.country, u.picture, u.idnumber, u.department, u.institution, ' .
2007-09-19 07:09:13 +00:00
'u.emailstop, u.lang, u.timezone, r.name as rolename' ;
2006-10-25 07:20:28 +00:00
}
2006-11-17 08:57:50 +00:00
// whether this assignment is hidden
2007-09-19 07:09:13 +00:00
$hiddensql = $gethidden ? '' : ' AND ra.hidden = 0 ' ;
$parentcontexts = '' ;
2006-09-12 07:37:23 +00:00
if ( $parent ) {
2007-09-19 07:09:13 +00:00
$parentcontexts = substr ( $context -> path , 1 ); // kill leading slash
$parentcontexts = str_replace ( '/' , ',' , $parentcontexts );
if ( $parentcontexts !== '' ) {
$parentcontexts = ' OR ra.contextid IN (' . $parentcontexts . ' )' ;
2006-09-12 07:37:23 +00:00
}
2006-09-20 21:00:45 +00:00
}
2007-09-19 07:09:13 +00:00
if ( is_array ( $roleid )) {
2007-09-19 07:47:11 +00:00
$roleselect = ' AND ra.roleid IN (' . implode ( ',' , $roleid ) . ')' ;
2007-12-05 01:13:29 +00:00
} elseif ( ! empty ( $roleid )) { // should not test for int, because it can come in as a string
2007-09-19 07:09:13 +00:00
$roleselect = " AND ra.roleid = $roleid " ;
2006-10-01 08:34:36 +00:00
} else {
$roleselect = '' ;
}
2007-09-13 13:44:35 +00:00
2007-07-09 06:22:56 +00:00
if ( $group ) {
2007-09-19 07:09:13 +00:00
$groupjoin = " JOIN { $CFG -> prefix } groups_members gm
ON gm . userid = u . id " ;
$groupselect = " AND gm.groupid = $group " ;
2007-07-09 06:22:56 +00:00
} else {
2007-09-19 07:09:13 +00:00
$groupjoin = '' ;
$groupselect = '' ;
2007-07-09 06:22:56 +00:00
}
2006-10-01 08:34:36 +00:00
2007-09-19 07:09:13 +00:00
$SQL = " SELECT $fields , ra.roleid
FROM { $CFG -> prefix } role_assignments ra
JOIN { $CFG -> prefix } user u
ON u . id = ra . userid
JOIN { $CFG -> prefix } role r
ON ra . roleid = r . id
$groupjoin
WHERE ( ra . contextid = $context -> id $parentcontexts )
$roleselect
$groupselect
2006-11-17 08:57:50 +00:00
$hiddensql
2006-10-01 07:02:53 +00:00
ORDER BY $sort
" ; // join now so that we can just use fullname() later
2007-11-22 05:17:26 +00:00
return get_records_sql ( $SQL , $limitfrom , $limitnum );
2006-09-12 07:37:23 +00:00
}
2006-09-28 04:42:49 +00:00
/**
* Counts all the users assigned this role in this context or higher
* @ param int roleid
* @ param int contextid
* @ param bool parent if true , get list of users assigned in higher context too
* @ return array ()
*/
function count_role_users ( $roleid , $context , $parent = false ) {
global $CFG ;
if ( $parent ) {
if ( $contexts = get_parent_contexts ( $context )) {
2006-10-01 07:02:53 +00:00
$parentcontexts = ' OR r.contextid IN (' . implode ( ',' , $contexts ) . ')' ;
2006-09-28 04:42:49 +00:00
} else {
$parentcontexts = '' ;
}
} else {
$parentcontexts = '' ;
}
$SQL = " SELECT count(*)
FROM { $CFG -> prefix } role_assignments r
WHERE ( r . contextid = $context -> id $parentcontexts )
AND r . roleid = $roleid " ;
return count_records_sql ( $SQL );
}
2006-09-20 21:00:45 +00:00
/**
2007-05-14 12:11:47 +00:00
* This function gets the list of courses that this user has a particular capability in .
* It is still not very efficient .
* @ param string $capability Capability in question
* @ param int $userid User ID or null for current user
* @ param bool $doanything True if 'doanything' is permitted ( default )
* @ param string $fieldsexceptid Leave blank if you only need 'id' in the course records ;
* otherwise use a comma - separated list of the fields you require , not including id
2007-09-13 13:44:35 +00:00
* @ param string $orderby If set , use a comma - separated list of fields from course
* table with sql modifiers ( DESC ) if needed
2007-05-14 12:11:47 +00:00
* @ return array Array of courses , may have zero entries . Or false if query failed .
*/
function get_user_capability_course ( $capability , $userid = NULL , $doanything = true , $fieldsexceptid = '' , $orderby = '' ) {
// Convert fields list and ordering
$fieldlist = '' ;
if ( $fieldsexceptid ) {
$fields = explode ( ',' , $fieldsexceptid );
foreach ( $fields as $field ) {
$fieldlist .= ',c.' . $field ;
}
2007-09-13 13:44:35 +00:00
}
2007-05-14 12:11:47 +00:00
if ( $orderby ) {
$fields = explode ( ',' , $orderby );
$orderby = '' ;
foreach ( $fields as $field ) {
if ( $orderby ) {
$orderby .= ',' ;
}
$orderby .= 'c.' . $field ;
}
$orderby = 'ORDER BY ' . $orderby ;
}
2007-09-13 13:44:35 +00:00
2007-05-14 12:11:47 +00:00
// Obtain a list of everything relevant about all courses including context.
// Note the result can be used directly as a context (we are going to), the course
// fields are just appended.
global $CFG ;
$rs = get_recordset_sql ( "
SELECT
x .* , c . id AS courseid $fieldlist
FROM
{ $CFG -> prefix } course c
INNER JOIN { $CFG -> prefix } context x ON c . id = x . instanceid AND x . contextlevel = " .CONTEXT_COURSE. "
$orderby
" );
if ( ! $rs ) {
return false ;
2007-09-13 13:44:35 +00:00
}
2007-05-14 12:11:47 +00:00
// Check capability for each course in turn
$courses = array ();
while ( $coursecontext = rs_fetch_next_record ( $rs )) {
if ( has_capability ( $capability , $coursecontext , $userid , $doanything )) {
// We've got the capability. Make the record look like a course record
// and store it
$coursecontext -> id = $coursecontext -> courseid ;
unset ( $coursecontext -> courseid );
unset ( $coursecontext -> contextlevel );
unset ( $coursecontext -> instanceid );
$courses [] = $coursecontext ;
2006-09-19 01:44:33 +00:00
}
}
2007-05-14 12:11:47 +00:00
return $courses ;
2006-09-21 03:21:33 +00:00
}
/** This function finds the roles assigned directly to this context only
* i . e . no parents role
* @ param object $context
* @ return array
*/
function get_roles_on_exact_context ( $context ) {
2006-09-21 22:34:45 +00:00
2006-09-21 03:21:33 +00:00
global $CFG ;
2006-09-21 06:57:14 +00:00
2006-10-20 02:44:22 +00:00
return get_records_sql ( " SELECT r.*
2006-09-21 03:21:33 +00:00
FROM { $CFG -> prefix } role_assignments ra ,
{ $CFG -> prefix } role r
WHERE ra . roleid = r . id
AND ra . contextid = $context -> id " );
2006-09-21 22:34:45 +00:00
2006-09-21 06:57:14 +00:00
}
2007-03-05 11:27:01 +00:00
/**
2006-09-21 09:16:41 +00:00
* Switches the current user to another role for the current session and only
2007-09-19 07:05:32 +00:00
* in the given context .
*
* The caller * must * check
* - that this op is allowed
* - that the requested role can be assigned in this ctx
* ( hint , use get_assignable_roles ())
* - that the requested role is NOT $CFG -> defaultuserroleid
*
2007-09-19 07:06:03 +00:00
* To " unswitch " pass 0 as the roleid .
*
2007-09-19 07:05:32 +00:00
* This function * will * modify $USER -> access - beware
*
2006-09-21 09:16:41 +00:00
* @ param integer $roleid
* @ param object $context
* @ return bool
*/
function role_switch ( $roleid , $context ) {
2007-03-16 20:21:27 +00:00
global $USER , $CFG ;
2006-09-21 09:16:41 +00:00
2007-09-19 07:05:32 +00:00
//
// Plan of action
//
// - Add the ghost RA to $USER->access
// as $USER->access['rsw'][$path] = $roleid
//
// - Make sure $USER->access['rdef'] has the roledefs
// it needs to honour the switcheroo
//
// Roledefs will get loaded "deep" here - down to the last child
// context. Note that
//
2007-09-19 07:15:12 +00:00
// - When visiting subcontexts, our selective accessdata loading
2007-09-19 07:05:32 +00:00
// will still work fine - though those ra/rdefs will be ignored
// appropriately while the switch is in place
//
// - If a switcheroo happens at a category with tons of courses
// (that have many overrides for switched-to role), the session
// will get... quite large. Sometimes you just can't win.
//
// To un-switch just unset($USER->access['rsw'][$path])
//
2006-09-21 09:16:41 +00:00
2007-09-19 07:11:18 +00:00
// Add the switch RA
if ( ! isset ( $USER -> access [ 'rsw' ])) {
$USER -> access [ 'rsw' ] = array ();
}
2007-09-19 07:06:03 +00:00
if ( $roleid == 0 ) {
unset ( $USER -> access [ 'rsw' ][ $context -> path ]);
if ( empty ( $USER -> access [ 'rsw' ])) {
unset ( $USER -> access [ 'rsw' ]);
}
return true ;
}
2007-09-19 07:05:32 +00:00
$USER -> access [ 'rsw' ][ $context -> path ] = $roleid ;
// Load roledefs
$USER -> access = get_role_access_bycontext ( $roleid , $context ,
$USER -> access );
2006-09-21 09:16:41 +00:00
2007-09-19 07:05:32 +00:00
/* DO WE NEED THIS AT ALL ? ? ?
// Add some permissions we are really going
// to always need, even if the role doesn't have them!
2006-09-21 09:16:41 +00:00
$USER -> capabilities [ $context -> id ][ 'moodle/course:view' ] = CAP_ALLOW ;
2007-09-19 07:05:32 +00:00
*/
2006-09-21 09:16:41 +00:00
return true ;
}
2006-09-21 06:57:14 +00:00
// get any role that has an override on exact context
function get_roles_with_override_on_context ( $context ) {
2006-09-21 22:34:45 +00:00
2006-09-21 06:57:14 +00:00
global $CFG ;
2006-09-21 22:34:45 +00:00
2006-10-20 02:44:22 +00:00
return get_records_sql ( " SELECT r.*
2006-09-21 06:57:14 +00:00
FROM { $CFG -> prefix } role_capabilities rc ,
{ $CFG -> prefix } role r
WHERE rc . roleid = r . id
AND rc . contextid = $context -> id " );
}
// get all capabilities for this role on this context (overrids)
function get_capabilities_from_role_on_context ( $role , $context ) {
2006-09-21 22:34:45 +00:00
2006-09-21 06:57:14 +00:00
global $CFG ;
2006-09-21 22:34:45 +00:00
return get_records_sql ( " SELECT *
2006-09-21 06:57:14 +00:00
FROM { $CFG -> prefix } role_capabilities
WHERE contextid = $context -> id
AND roleid = $role -> id " );
2006-09-21 09:09:16 +00:00
}
2006-09-22 01:46:45 +00:00
// find out which roles has assignment on this context
function get_roles_with_assignment_on_context ( $context ) {
2006-09-23 12:51:00 +00:00
2006-09-22 01:46:45 +00:00
global $CFG ;
2006-09-23 12:51:00 +00:00
2006-10-20 02:44:22 +00:00
return get_records_sql ( " SELECT r.*
2006-09-22 01:46:45 +00:00
FROM { $CFG -> prefix } role_assignments ra ,
{ $CFG -> prefix } role r
WHERE ra . roleid = r . id
AND ra . contextid = $context -> id " );
}
2007-03-05 11:27:01 +00:00
/**
* Find all user assignemnt of users for this role , on this context
2006-09-21 09:09:16 +00:00
*/
function get_users_from_role_on_context ( $role , $context ) {
2006-09-21 22:34:45 +00:00
2006-09-21 09:09:16 +00:00
global $CFG ;
2006-09-21 22:34:45 +00:00
2006-09-21 09:09:16 +00:00
return get_records_sql ( " SELECT *
FROM { $CFG -> prefix } role_assignments
WHERE contextid = $context -> id
2006-09-21 22:34:45 +00:00
AND roleid = $role -> id " );
2006-09-21 09:09:16 +00:00
}
2006-09-21 09:16:41 +00:00
2007-03-05 11:27:01 +00:00
/**
2006-10-04 07:07:57 +00:00
* Simple function returning a boolean true if roles exist , otherwise false
*/
function user_has_role_assignment ( $userid , $roleid , $contextid = 0 ) {
if ( $contextid ) {
return record_exists ( 'role_assignments' , 'userid' , $userid , 'roleid' , $roleid , 'contextid' , $contextid );
} else {
return record_exists ( 'role_assignments' , 'userid' , $userid , 'roleid' , $roleid );
}
}
2007-01-12 07:41:33 +00:00
2007-03-22 08:11:30 +00:00
// gets the custom name of the role in course
// TODO: proper documentation
function role_get_name ( $role , $context ) {
2007-09-13 13:44:35 +00:00
2007-03-22 08:11:30 +00:00
if ( $r = get_record ( 'role_names' , 'roleid' , $role -> id , 'contextid' , $context -> id )) {
2007-09-13 13:44:35 +00:00
return format_string ( $r -> text );
2007-03-22 08:11:30 +00:00
} else {
return format_string ( $role -> name );
}
}
2007-08-02 08:28:29 +00:00
2007-08-16 08:48:53 +00:00
/**
* This function helps admin / roles / manage . php etc to detect if a new line should be printed
* when we read in a new capability
* most of the time , if the 2 components are different we should print a new line , ( e . g . course system -> rss client )
* but when we are in grade , all reports / import / export capabilites should be together
* @ param string a - component string a
* @ param string b - component string b
* @ return bool - whether 2 component are in different " sections "
*/
function component_level_changed ( $cap , $comp , $contextlevel ) {
if ( $cap -> component == 'enrol/authorize' && $comp == 'enrol/authorize' ) {
2007-09-13 13:44:35 +00:00
return false ;
2007-08-16 08:48:53 +00:00
}
if ( strstr ( $cap -> component , '/' ) && strstr ( $comp , '/' )) {
$compsa = explode ( '/' , $cap -> component );
$compsb = explode ( '/' , $comp );
2007-09-13 13:44:35 +00:00
2007-08-16 08:48:53 +00:00
// we are in gradebook, still
if (( $compsa [ 0 ] == 'gradeexport' || $compsa [ 0 ] == 'gradeimport' || $compsa [ 0 ] == 'gradereport' ) &&
( $compsb [ 0 ] == 'gradeexport' || $compsb [ 0 ] == 'gradeimport' || $compsb [ 0 ] == 'gradereport' )) {
return false ;
2007-09-13 13:44:35 +00:00
}
2007-08-16 08:48:53 +00:00
}
return ( $cap -> component != $comp || $cap -> contextlevel != $contextlevel );
2007-09-19 07:01:27 +00:00
}
/**
2007-09-19 07:29:07 +00:00
* Populate context . path and context . depth where missing .
2007-10-09 12:49:54 +00:00
* @ param bool $force force a complete rebuild of the path and depth fields .
2007-10-10 08:33:06 +00:00
* @ param bool $feedback display feedback ( during upgrade usually )
2007-10-09 12:49:54 +00:00
* @ return void
2007-09-19 07:01:27 +00:00
*/
2007-10-10 08:33:06 +00:00
function build_context_path ( $force = false , $feedback = false ) {
2007-09-19 07:01:27 +00:00
global $CFG ;
2007-09-19 15:51:04 +00:00
require_once ( $CFG -> libdir . '/ddllib.php' );
2007-09-19 07:01:27 +00:00
// Site
2007-09-19 07:29:07 +00:00
$sitectx = get_record ( 'context' , 'contextlevel' , CONTEXT_SYSTEM );
$base = '/' . $sitectx -> id ;
2007-09-19 07:01:27 +00:00
2007-09-19 07:29:07 +00:00
if ( $force || $sitectx -> path !== $base ) {
set_field ( 'context' , 'path' , $base , 'id' , $sitectx -> id );
set_field ( 'context' , 'depth' , 1 , 'id' , $sitectx -> id );
$sitectx = get_record ( 'context' , 'contextlevel' , CONTEXT_SYSTEM );
}
2007-09-19 07:01:27 +00:00
2007-09-19 07:29:07 +00:00
// Sitecourse
$sitecoursectx = get_record ( 'context' ,
'contextlevel' , CONTEXT_COURSE ,
'instanceid' , SITEID );
if ( $force || $sitecoursectx -> path !== " $base / { $sitecoursectx -> id } " ) {
set_field ( 'context' , 'path' , " $base / { $sitecoursectx -> id } " ,
'id' , $sitecoursectx -> id );
set_field ( 'context' , 'depth' , 2 ,
'id' , $sitecoursectx -> id );
$sitecoursectx = get_record ( 'context' ,
'contextlevel' , CONTEXT_COURSE ,
'instanceid' , SITEID );
}
2007-10-05 15:06:38 +00:00
$ctxemptyclause = " AND (ctx.path IS NULL
2007-09-20 00:16:22 +00:00
OR ctx . depth = 0 ) " ;
2007-10-05 15:06:38 +00:00
$emptyclause = " AND ( { $CFG -> prefix } context.path IS NULL
2007-09-20 01:03:35 +00:00
OR { $CFG -> prefix } context . depth = 0 ) " ;
2007-09-20 00:16:22 +00:00
if ( $force ) {
$ctxemptyclause = $emptyclause = '' ;
}
2007-09-19 15:51:04 +00:00
2007-09-20 07:37:50 +00:00
/* MDL - 11347 :
* - mysql does not allow to use FROM in UPDATE statements
* - using two tables after UPDATE works in mysql , but might give unexpected
* results in pg 8 ( depends on configuration )
* - using table alias in UPDATE does not work in pg < 8.2
*/
if ( $CFG -> dbfamily == 'mysql' ) {
2007-09-21 08:52:43 +00:00
$updatesql = " UPDATE { $CFG -> prefix } context ct, { $CFG -> prefix } context_temp temp
SET ct . path = temp . path ,
ct . depth = temp . depth
WHERE ct . id = temp . id " ;
} else if ( $CFG -> dbfamily == 'oracle' ) {
$updatesql = " UPDATE { $CFG -> prefix } context ct
SET ( ct . path , ct . depth ) =
( SELECT temp . path , temp . depth
2007-12-04 06:25:25 +00:00
FROM { $CFG -> prefix } context_temp temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ct . id )
WHERE EXISTS ( SELECT 'x'
2007-12-04 06:25:25 +00:00
FROM { $CFG -> prefix } context_temp temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ct . id ) " ;
2007-09-20 07:37:50 +00:00
} else {
$updatesql = " UPDATE { $CFG -> prefix } context
2007-09-21 08:52:43 +00:00
SET path = temp . path ,
depth = temp . depth
FROM { $CFG -> prefix } context_temp temp
WHERE temp . id = { $CFG -> prefix } context . id " ;
2007-09-20 01:03:35 +00:00
}
2007-09-20 07:37:50 +00:00
2007-09-21 08:52:43 +00:00
$udelsql = " TRUNCATE TABLE { $CFG -> prefix } context_temp " ;
2007-09-19 15:51:04 +00:00
2007-09-19 07:01:27 +00:00
// Top level categories
$sql = " UPDATE { $CFG -> prefix } context
2007-09-20 07:37:50 +00:00
SET depth = 2 , path = " . sql_concat( " '$base/' " , 'id') . "
WHERE contextlevel = " .CONTEXT_COURSECAT. "
2007-09-19 19:13:49 +00:00
AND EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } course_categories cc
WHERE cc . id = { $CFG -> prefix } context . instanceid
AND cc . depth = 1 )
$emptyclause " ;
2007-09-21 08:52:43 +00:00
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-09-19 07:01:27 +00:00
2007-10-10 08:33:06 +00:00
execute_sql ( $udelsql , $feedback );
2007-09-19 15:51:04 +00:00
2007-09-19 07:01:27 +00:00
// Deeper categories - one query per depthlevel
$maxdepth = get_field_sql ( " SELECT MAX(depth)
FROM { $CFG -> prefix } course_categories " );
for ( $n = 2 ; $n <= $maxdepth ; $n ++ ) {
2007-09-21 08:52:43 +00:00
$sql = " INSERT INTO { $CFG -> prefix } context_temp (id, path, depth)
2007-09-19 15:51:04 +00:00
SELECT ctx . id , " .sql_concat('pctx.path', " '/' " , 'ctx.id'). " , $n + 1
FROM { $CFG -> prefix } context ctx
2007-09-19 19:01:32 +00:00
JOIN { $CFG -> prefix } course_categories c ON ctx . instanceid = c . id
2007-09-19 22:40:58 +00:00
JOIN { $CFG -> prefix } context pctx ON c . parent = pctx . instanceid
2007-09-19 15:51:04 +00:00
WHERE ctx . contextlevel = " .CONTEXT_COURSECAT. "
2007-09-19 19:01:32 +00:00
AND pctx . contextlevel = " .CONTEXT_COURSECAT. "
AND c . depth = $n
2007-09-21 08:52:43 +00:00
AND NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context_temp temp
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-10-26 07:58:23 +00:00
// this is needed after every loop
// MDL-11532
execute_sql ( $updatesql , $feedback );
execute_sql ( $udelsql , $feedback );
2007-09-19 07:01:27 +00:00
}
// Courses -- except sitecourse
2007-09-21 08:52:43 +00:00
$sql = " INSERT INTO { $CFG -> prefix } context_temp (id, path, depth)
2007-09-19 15:51:04 +00:00
SELECT ctx . id , " .sql_concat('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1
FROM { $CFG -> prefix } context ctx
2007-09-19 19:01:32 +00:00
JOIN { $CFG -> prefix } course c ON ctx . instanceid = c . id
JOIN { $CFG -> prefix } context pctx ON c . category = pctx . instanceid
WHERE ctx . contextlevel = " .CONTEXT_COURSE. "
AND c . id != " .SITEID. "
AND pctx . contextlevel = " .CONTEXT_COURSECAT. "
2007-09-21 08:52:43 +00:00
AND NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context_temp temp
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-09-19 15:51:04 +00:00
2007-10-10 08:33:06 +00:00
execute_sql ( $updatesql , $feedback );
execute_sql ( $udelsql , $feedback );
2007-09-19 07:01:27 +00:00
// Module instances
2007-09-21 08:52:43 +00:00
$sql = " INSERT INTO { $CFG -> prefix } context_temp (id, path, depth)
2007-09-19 15:51:04 +00:00
SELECT ctx . id , " .sql_concat('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1
FROM { $CFG -> prefix } context ctx
2007-09-19 19:01:32 +00:00
JOIN { $CFG -> prefix } course_modules cm ON ctx . instanceid = cm . id
JOIN { $CFG -> prefix } context pctx ON cm . course = pctx . instanceid
2007-09-19 15:51:04 +00:00
WHERE ctx . contextlevel = " .CONTEXT_MODULE. "
2007-09-19 19:01:32 +00:00
AND pctx . contextlevel = " .CONTEXT_COURSE. "
2007-09-21 08:52:43 +00:00
AND NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context_temp temp
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-09-19 15:51:04 +00:00
2007-10-10 08:33:06 +00:00
execute_sql ( $updatesql , $feedback );
execute_sql ( $udelsql , $feedback );
2007-09-19 07:01:27 +00:00
2007-09-19 07:56:14 +00:00
// Blocks - non-pinned course-view only
2007-09-21 08:52:43 +00:00
$sql = " INSERT INTO { $CFG -> prefix } context_temp (id, path, depth)
2007-09-19 15:51:04 +00:00
SELECT ctx . id , " .sql_concat('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1
FROM { $CFG -> prefix } context ctx
2007-09-19 19:01:32 +00:00
JOIN { $CFG -> prefix } block_instance bi ON ctx . instanceid = bi . id
JOIN { $CFG -> prefix } context pctx ON bi . pageid = pctx . instanceid
2007-09-19 15:51:04 +00:00
WHERE ctx . contextlevel = " .CONTEXT_BLOCK. "
2007-09-19 19:01:32 +00:00
AND pctx . contextlevel = " .CONTEXT_COURSE. "
AND bi . pagetype = 'course-view'
2007-09-21 08:52:43 +00:00
AND NOT EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } context_temp temp
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-09-19 07:01:27 +00:00
2007-10-10 08:33:06 +00:00
execute_sql ( $updatesql , $feedback );
execute_sql ( $udelsql , $feedback );
2007-09-19 15:51:04 +00:00
2007-09-19 07:56:14 +00:00
// Blocks - others
$sql = " UPDATE { $CFG -> prefix } context
2007-09-19 19:01:32 +00:00
SET depth = 2 , path = " .sql_concat( " '$base/' " , 'id'). "
WHERE contextlevel = " .CONTEXT_BLOCK. "
2007-09-19 19:13:49 +00:00
AND EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } block_instance bi
WHERE bi . id = { $CFG -> prefix } context . instanceid
AND bi . pagetype != 'course-view' )
$emptyclause " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-09-19 07:56:14 +00:00
2007-09-19 07:01:27 +00:00
// User
$sql = " UPDATE { $CFG -> prefix } context
2007-09-19 19:01:32 +00:00
SET depth = 2 , path = " .sql_concat( " '$base/' " , 'id'). "
WHERE contextlevel = " .CONTEXT_USER. "
2007-09-19 19:13:49 +00:00
AND EXISTS ( SELECT 'x'
FROM { $CFG -> prefix } user u
2007-09-20 07:37:50 +00:00
WHERE u . id = { $CFG -> prefix } context . instanceid )
2007-09-19 19:13:49 +00:00
$emptyclause " ;
2007-10-10 08:33:06 +00:00
execute_sql ( $sql , $feedback );
2007-09-19 07:01:27 +00:00
// Personal TODO
2007-09-13 13:44:35 +00:00
2007-09-19 15:51:04 +00:00
//TODO: fix group contexts
2007-10-05 15:06:38 +00:00
// reset static course cache - it might have incorrect cached data
global $context_cache , $context_cache_id ;
$context_cache = array ();
$context_cache_id = array ();
2007-08-16 08:48:53 +00:00
}
2007-09-19 07:13:33 +00:00
/**
* Update the path field of the context and
* all the dependent subcontexts that follow
* the move .
*
* The most important thing here is to be as
* DB efficient as possible . This op can have a
* massive impact in the DB .
*
* @ param obj current context obj
* @ param obj newparent new parent obj
*
*/
function context_moved ( $context , $newparent ) {
global $CFG ;
$frompath = $context -> path ;
$newpath = $newparent -> path . '/' . $context -> id ;
$setdepth = '' ;
2007-09-19 07:14:11 +00:00
if (( $newparent -> depth + 1 ) != $context -> depth ) {
$setdepth = " , depth= depth + ( { $newparent -> depth } - { $context -> depth } ) + 1 " ;
2007-09-19 07:13:33 +00:00
}
$sql = " UPDATE { $CFG -> prefix } context
SET path = '$newpath'
$setdepth
WHERE path = '$frompath' " ;
execute_sql ( $sql , false );
$len = strlen ( $frompath );
$sql = " UPDATE { $CFG -> prefix } context
2007-10-02 22:34:12 +00:00
SET path = " .sql_concat( " '$newpath' " , 'SUBSTR(path, '. $len .' +1)'). "
2007-09-19 07:13:33 +00:00
$setdepth
WHERE path LIKE '{$frompath}/%' " ;
execute_sql ( $sql , false );
mark_context_dirty ( $frompath );
mark_context_dirty ( $newpath );
}
2007-09-19 07:08:12 +00:00
/**
* Turn the ctx * fields in an objectlike record
* into a context subobject . This allows
* us to SELECT from major tables JOINing with
* context at no cost , saving a ton of context
* lookups ...
*/
function make_context_subobj ( $rec ) {
$ctx = new StdClass ;
$ctx -> id = $rec -> ctxid ; unset ( $rec -> ctxid );
$ctx -> path = $rec -> ctxpath ; unset ( $rec -> ctxpath );
$ctx -> depth = $rec -> ctxdepth ; unset ( $rec -> ctxdepth );
2007-09-19 07:54:37 +00:00
$ctx -> contextlevel = $rec -> ctxlevel ; unset ( $rec -> ctxlevel );
2007-09-19 07:08:12 +00:00
$ctx -> instanceid = $rec -> id ;
2007-09-19 07:54:37 +00:00
2007-09-19 07:08:12 +00:00
$rec -> context = $ctx ;
return $rec ;
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:10:09 +00:00
* Fetch recent dirty contexts to know cheaply whether our $USER -> access
* is stale and needs to be reloaded .
*
2007-10-02 08:46:27 +00:00
* Uses cache_flags
2007-10-09 12:49:54 +00:00
* @ param int $time
* @ return array of dirty contexts
2007-09-19 07:10:09 +00:00
*/
2007-09-19 07:10:24 +00:00
function get_dirty_contexts ( $time ) {
2007-10-02 08:46:27 +00:00
return get_cache_flags ( 'accesslib/dirtycontexts' , $time - 2 );
2007-09-19 07:10:09 +00:00
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:10:09 +00:00
* Mark a context as dirty ( with timestamp )
* so as to force reloading of the context .
2007-10-09 12:49:54 +00:00
* @ param string $path context path
2007-09-19 07:10:09 +00:00
*/
function mark_context_dirty ( $path ) {
2007-10-09 12:49:54 +00:00
global $CFG , $DIRTYCONTEXTS ;
2007-09-19 07:22:49 +00:00
// only if it is a non-empty string
if ( is_string ( $path ) && $path !== '' ) {
2007-10-02 08:46:27 +00:00
set_cache_flag ( 'accesslib/dirtycontexts' , $path , 1 , time () + $CFG -> sessiontimeout );
2007-10-09 12:49:54 +00:00
if ( isset ( $DIRTYCONTEXTS )) {
$DIRTYCONTEXTS [ $path ] = 1 ;
}
2007-09-19 07:22:49 +00:00
}
2007-09-19 07:10:09 +00:00
}
2007-10-09 12:49:54 +00:00
/**
2007-09-19 07:10:24 +00:00
* Will walk the contextpath to answer whether
2007-10-09 12:49:54 +00:00
* the contextpath is dirty
2007-09-19 07:10:24 +00:00
*
2007-10-09 12:49:54 +00:00
* @ param array $contexts array of strings
* @ param obj / array dirty contexts from get_dirty_contexts ()
* @ return bool
2007-09-19 07:10:24 +00:00
*/
2007-10-09 12:49:54 +00:00
function is_contextpath_dirty ( $pathcontexts , $dirty ) {
$path = '' ;
foreach ( $pathcontexts as $ctx ) {
$path = $path . '/' . $ctx ;
2007-09-19 07:25:37 +00:00
if ( isset ( $dirty [ $path ])) {
2007-10-09 12:49:54 +00:00
return true ;
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
}
return false ;
2007-09-19 07:10:24 +00:00
}
2007-05-07 08:34:08 +00:00
?>