2009-05-19 07:50:54 +00:00
< ? php
2009-11-01 11:31:16 +00:00
// This file is part of Moodle - http://moodle.org/
//
2009-05-19 07:50:54 +00:00
// Moodle 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 3 of the License, or
// (at your option) any later version.
//
// Moodle 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.
2009-11-01 11:31:16 +00:00
//
2009-05-19 07:50:54 +00:00
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
2007-08-06 17:55:44 +00:00
2007-09-19 07:15:27 +00:00
/**
2009-05-19 07:50:54 +00:00
* This file contains functions for managing user access
*
2009-05-22 02:03:55 +00:00
* < b > Public API vs internals </ b >
2008-05-24 18:35:48 +00:00
*
2007-09-19 07:15:27 +00:00
* 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 ()
2008-05-24 18:35:48 +00:00
*
2007-09-19 07:57:10 +00:00
* Whether the user can do something ...
2007-09-19 07:15:27 +00:00
* - has_capability ()
2008-12-08 07:28:19 +00:00
* - has_any_capability ()
* - has_all_capabilities ()
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
*
2008-04-29 06:53:19 +00:00
* What users can do X in this context ?
* - get_users_by_capability ()
*
2007-09-19 07:57:10 +00:00
* Enrol / unenrol
2007-09-19 07:25:10 +00:00
* - enrol_into_course ()
* - role_assign () / role_unassign ()
2008-05-24 18:35:48 +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-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 ()
*
2009-05-22 02:03:55 +00:00
* < b > Name conventions </ b >
2008-05-24 18:35:48 +00:00
*
2009-05-22 02:03:55 +00:00
* " ctx " means context
2007-09-19 07:15:27 +00:00
*
2009-05-22 02:03:55 +00:00
* < b > accessdata </ b >
2007-09-19 07:15:27 +00:00
*
* Access control data is held in the " accessdata " array
* which - for the logged - in user , will be in $USER -> access
2008-05-24 18:35:48 +00:00
*
2009-03-23 03:54:50 +00:00
* For other users can be generated and passed around ( but may also be cached
* against userid in $ACCESSLIB_PRIVATE -> accessdatabyuser .
2007-09-19 07:15:27 +00:00
*
2007-09-20 04:52:54 +00:00
* $accessdata is a multidimensional array , holding
2008-05-24 18:35:48 +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 .
*
2008-05-24 18:35:48 +00:00
* Things are keyed on " contextpaths " ( the path field of
2007-09-19 07:15:27 +00:00
* the context table ) for fast walking up / down the tree .
2009-05-22 02:03:55 +00:00
* < code >
2007-09-20 04:52:54 +00:00
* $accessdata [ ra ][ $contextpath ] = array ( $roleid )
* [ $contextpath ] = array ( $roleid )
2008-05-24 18:35:48 +00:00
* [ $contextpath ] = array ( $roleid )
2009-11-01 11:31:16 +00:00
* </ code >
2007-09-19 07:15:27 +00:00
*
* Role definitions are stored like this
* ( no cap merge is done - so it ' s compact )
*
2009-05-22 02:03:55 +00:00
* < code >
2007-09-20 04:52:54 +00:00
* $accessdata [ rdef ][ $contextpath : $roleid ][ mod / forum : viewpost ] = 1
* [ mod / forum : editallpost ] = - 1
* [ mod / forum : startdiscussion ] = - 1000
2009-05-22 02:03:55 +00:00
* </ code >
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
2008-05-24 18:35:48 +00:00
* have loaded ra / rdef in
2009-05-22 02:03:55 +00:00
* < code >
2008-05-24 18:35:48 +00:00
* $accessdata [ loaded ] = array ( $contextpath , $contextpath )
2009-05-22 02:03:55 +00:00
* </ code >
2007-09-19 07:15:27 +00:00
*
2009-05-22 02:03:55 +00:00
* < b > Stale accessdata </ b >
2007-09-19 07:15:27 +00:00
*
* For the logged - in user , accessdata is long - lived .
*
2009-03-23 03:54:50 +00:00
* On each pageload we load $ACCESSLIB_PRIVATE -> dirtycontexts which lists
2007-09-19 07:15:27 +00:00
* context paths affected by changes . Any check at - or - below
* a dirty context will trigger a transparent reload of accessdata .
2008-05-24 18:35:48 +00:00
*
2007-09-19 07:15:27 +00:00
* Changes at the sytem level will force the reload for everyone .
*
2009-05-22 02:03:55 +00:00
* < b > Default role caps </ b >
2008-05-24 18:35:48 +00:00
* The default role assignment is not in the DB , so we
* add it manually to accessdata .
2007-09-19 07:15:27 +00:00
*
* This means that functions that work directly off the
* DB need to ensure that the default role caps
2008-05-24 18:35:48 +00:00
* are dealt with appropriately .
2007-09-19 07:15:27 +00:00
*
2009-05-19 07:50:54 +00:00
* @ package moodlecore
* @ copyright 1999 onwards Martin Dougiamas http :// dougiamas . com
* @ license http :// www . gnu . org / copyleft / gpl . html GNU GPL v3 or later
2007-09-19 07:15:27 +00:00
*/
2006-08-08 05:13:06 +00:00
2009-05-22 02:03:55 +00:00
/** permission definitions */
2006-09-15 06:07:29 +00:00
define ( 'CAP_INHERIT' , 0 );
2009-05-22 02:03:55 +00:00
/** permission definitions */
2006-08-08 05:13:06 +00:00
define ( 'CAP_ALLOW' , 1 );
2009-05-22 02:03:55 +00:00
/** permission definitions */
2006-08-08 05:13:06 +00:00
define ( 'CAP_PREVENT' , - 1 );
2009-05-22 02:03:55 +00:00
/** permission definitions */
2006-08-08 05:13:06 +00:00
define ( 'CAP_PROHIBIT' , - 1000 );
2009-05-22 02:03:55 +00:00
/** context definitions */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_SYSTEM' , 10 );
2009-05-22 02:03:55 +00:00
/** context definitions */
2006-09-15 14:09:16 +00:00
define ( 'CONTEXT_USER' , 30 );
2009-05-22 02:03:55 +00:00
/** context definitions */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_COURSECAT' , 40 );
2009-05-22 02:03:55 +00:00
/** context definitions */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_COURSE' , 50 );
2009-05-22 02:03:55 +00:00
/** context definitions */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_MODULE' , 70 );
2009-05-22 02:03:55 +00:00
/** context definitions */
2006-08-08 05:13:06 +00:00
define ( 'CONTEXT_BLOCK' , 80 );
2009-05-22 02:03:55 +00:00
/** capability risks - see {@link http://docs.moodle.org/en/Development:Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_MANAGETRUST' , 0x0001 );
2009-05-22 02:03:55 +00:00
/** capability risks - see {@link http://docs.moodle.org/en/Development:Hardening_new_Roles_system} */
2006-09-19 07:33:22 +00:00
define ( 'RISK_CONFIG' , 0x0002 );
2009-05-22 02:03:55 +00:00
/** capability risks - see {@link http://docs.moodle.org/en/Development:Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_XSS' , 0x0004 );
2009-05-22 02:03:55 +00:00
/** capability risks - see {@link http://docs.moodle.org/en/Development:Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_PERSONAL' , 0x0008 );
2009-05-22 02:03:55 +00:00
/** capability risks - see {@link http://docs.moodle.org/en/Development:Hardening_new_Roles_system} */
2006-09-18 21:32:49 +00:00
define ( 'RISK_SPAM' , 0x0010 );
2009-05-22 02:03:55 +00:00
/** capability risks - see {@link http://docs.moodle.org/en/Development:Hardening_new_Roles_system} */
2008-07-23 16:10:06 +00:00
define ( 'RISK_DATALOSS' , 0x0020 );
2006-09-18 21:32:49 +00:00
2009-05-22 02:03:55 +00:00
/** rolename displays - the name as defined in the role definition */
define ( 'ROLENAME_ORIGINAL' , 0 );
/** rolename displays - the name as defined by a role alias */
define ( 'ROLENAME_ALIAS' , 1 );
/** rolename displays - Both, like this: Role alias (Original)*/
define ( 'ROLENAME_BOTH' , 2 );
/** rolename displays - the name as defined in the role definition and the shortname in brackets*/
define ( 'ROLENAME_ORIGINALANDSHORT' , 3 );
/** rolename displays - the name as defined by a role alias, in raw form suitable for editing*/
define ( 'ROLENAME_ALIAS_RAW' , 4 );
/** size limit for context cache */
2009-11-01 11:31:16 +00:00
if ( ! defined ( 'MAX_CONTEXT_CACHE_SIZE' )) {
2009-04-06 09:48:39 +00:00
define ( 'MAX_CONTEXT_CACHE_SIZE' , 5000 );
}
2009-05-22 02:03:55 +00:00
/**
2009-11-01 11:31:16 +00:00
* Although this looks like a global variable , it isn ' t really .
2009-05-22 02:03:55 +00:00
*
2009-11-01 11:31:16 +00:00
* It is just a private implementation detail to accesslib that MUST NOT be used elsewhere .
* It is used to cache various bits of data between function calls for performance reasons .
2009-05-22 02:03:55 +00:00
* Sadly , a PHP global variale is the only way to impleemnt this , withough rewriting everything
* as methods of a class , instead of functions .
*
* @ global stdClass $ACCESSLIB_PRIVATE
* @ name $ACCESSLIB_PRIVATE
*/
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE = new stdClass ;
$ACCESSLIB_PRIVATE -> contexts = array (); // Cache of context objects by level and instance
$ACCESSLIB_PRIVATE -> contextsbyid = array (); // Cache of context objects by id
2010-03-31 07:41:31 +00:00
$ACCESSLIB_PRIVATE -> systemcontext = NULL ; // Used in get_system_context
$ACCESSLIB_PRIVATE -> dirtycontexts = NULL ; // Dirty contexts cache
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> accessdatabyuser = array (); // Holds the $accessdata structure for users other than $USER
$ACCESSLIB_PRIVATE -> roledefinitions = array (); // role definitions cache - helps a lot with mem usage in cron
$ACCESSLIB_PRIVATE -> croncache = array (); // Used in get_role_access
$ACCESSLIB_PRIVATE -> preloadedcourses = array (); // Used in preload_course_contexts.
2010-03-31 07:41:31 +00:00
$ACCESSLIB_PRIVATE -> capabilities = NULL ; // detailed information about the capabilities
2006-08-08 05:13:06 +00:00
2009-03-23 03:54:50 +00:00
/**
2009-05-19 07:50:54 +00:00
* Clears accesslib ' s private caches . ONLY BE USED BY UNIT TESTS
2009-11-01 11:31:16 +00:00
*
2009-03-23 03:54:50 +00:00
* This method should ONLY BE USED BY UNIT TESTS . It clears all of
* accesslib ' s private caches . You need to do this before setting up test data ,
* and also at the end fo the tests .
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
* @ global object
2009-03-23 03:54:50 +00:00
*/
function accesslib_clear_all_caches_for_unit_testing () {
global $UNITTEST , $USER , $ACCESSLIB_PRIVATE ;
if ( empty ( $UNITTEST -> running )) {
throw new coding_exception ( 'You must not call clear_all_caches outside of unit tests.' );
}
$ACCESSLIB_PRIVATE -> contexts = array ();
$ACCESSLIB_PRIVATE -> contextsbyid = array ();
2010-03-31 07:41:31 +00:00
$ACCESSLIB_PRIVATE -> systemcontext = NULL ;
$ACCESSLIB_PRIVATE -> dirtycontexts = NULL ;
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> accessdatabyuser = array ();
$ACCESSLIB_PRIVATE -> roledefinitions = array ();
$ACCESSLIB_PRIVATE -> croncache = array ();
$ACCESSLIB_PRIVATE -> preloadedcourses = array ();
2010-03-31 07:41:31 +00:00
$ACCESSLIB_PRIVATE -> capabilities = NULL ;
2009-03-23 03:54:50 +00:00
unset ( $USER -> access );
}
/**
* Private function . Add a context object to accesslib ' s caches .
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $context
2009-03-23 03:54:50 +00:00
*/
function cache_context ( $context ) {
global $ACCESSLIB_PRIVATE ;
2009-04-06 09:48:39 +00:00
// If there are too many items in the cache already, remove items until
// there is space
while ( count ( $ACCESSLIB_PRIVATE -> contextsbyid ) >= MAX_CONTEXT_CACHE_SIZE ) {
2009-05-23 20:08:48 +00:00
$first = reset ( $ACCESSLIB_PRIVATE -> contextsbyid );
unset ( $ACCESSLIB_PRIVATE -> contextsbyid [ $first -> id ]);
2009-04-06 09:48:39 +00:00
unset ( $ACCESSLIB_PRIVATE -> contexts [ $first -> contextlevel ][ $first -> instanceid ]);
}
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> contexts [ $context -> contextlevel ][ $context -> instanceid ] = $context ;
$ACCESSLIB_PRIVATE -> contextsbyid [ $context -> id ] = $context ;
}
2006-09-03 07:56:40 +00:00
2009-05-19 07:50:54 +00:00
/**
* This is really slow !!! do not use above course context level
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid
* @ param object $context
* @ return array
*/
2007-03-07 13:45:41 +00:00
function get_role_context_caps ( $roleid , $context ) {
2008-05-15 21:40:00 +00:00
global $DB ;
2007-03-07 13:45:41 +00:00
//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 ) {
2008-05-15 21:40:00 +00:00
if ( $capabilities = $DB -> get_records ( 'role_capabilities' , array ( 'roleid' => $roleid , 'contextid' => $cid ))) {
2007-03-07 13:45:41 +00:00
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 ) {
2008-05-15 21:40:00 +00:00
if ( $capabilities = $DB -> get_records ( 'role_capabilities' , array ( 'roleid' => $roleid , 'contextid' => $cid ))) {
2007-03-07 13:45:41 +00:00
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 ;
}
/**
2009-05-19 07:50:54 +00:00
* Gets the accessdata for role " sitewide " ( system down to course )
2007-09-19 07:16:29 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid
2010-03-31 07:41:31 +00:00
* @ param array $accessdata defaults to NULL
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
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
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
//
// Overrides for the role IN ANY CONTEXTS
// down to COURSE - not below -
//
$sql = " SELECT ctx.path,
rc . capability , rc . permission
2008-05-15 21:40:00 +00:00
FROM { context } ctx
JOIN { role_capabilities } rc
ON rc . contextid = ctx . id
WHERE rc . roleid = ?
AND ctx . contextlevel <= " .CONTEXT_COURSE. "
ORDER BY ctx . depth , ctx . path " ;
$params = array ( $roleid );
2008-02-05 10:41:05 +00:00
2009-01-03 14:28:02 +00:00
// we need extra caching in CLI scripts and cron
if ( CLI_SCRIPT ) {
2009-03-23 03:54:50 +00:00
global $ACCESSLIB_PRIVATE ;
2008-02-05 10:41:05 +00:00
2009-03-23 03:54:50 +00:00
if ( ! isset ( $ACCESSLIB_PRIVATE -> croncache [ $roleid ])) {
$ACCESSLIB_PRIVATE -> croncache [ $roleid ] = array ();
2008-05-15 21:40:00 +00:00
if ( $rs = $DB -> get_recordset_sql ( $sql , $params )) {
foreach ( $rs as $rd ) {
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> croncache [ $roleid ][] = $rd ;
2008-02-05 10:41:05 +00:00
}
2008-05-15 21:40:00 +00:00
$rs -> close ();
2008-02-05 10:41:05 +00:00
}
}
2009-03-23 03:54:50 +00:00
foreach ( $ACCESSLIB_PRIVATE -> croncache [ $roleid ] as $rd ) {
2007-10-10 12:19:27 +00:00
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
2007-09-19 07:02:57 +00:00
}
2008-05-24 18:35:48 +00:00
2008-02-05 10:41:05 +00:00
} else {
2008-05-15 21:40:00 +00:00
if ( $rs = $DB -> get_recordset_sql ( $sql , $params )) {
foreach ( $rs as $rd ) {
2008-02-05 10:41:05 +00:00
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
unset ( $rd );
2008-05-15 21:40:00 +00:00
$rs -> close ();
2008-02-05 10:41:05 +00:00
}
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
/**
2009-05-19 07:50:54 +00:00
* Gets the accessdata for role " sitewide " ( system down to course )
2007-09-26 07:12:38 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid
2010-03-31 07:41:31 +00:00
* @ param array $accessdata defaults to NULL
2007-09-26 07:12:38 +00:00
* @ return array
*/
function get_default_frontpage_role_access ( $roleid , $accessdata = NULL ) {
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2008-05-24 18:35:48 +00:00
2007-09-26 07:12:38 +00:00
$frontpagecontext = get_context_instance ( CONTEXT_COURSE , SITEID );
$base = '/' . SYSCONTEXTID . '/' . $frontpagecontext -> id ;
2008-05-24 18:35:48 +00:00
2007-09-26 07:12:38 +00:00
//
// Overrides for the role in any contexts related to the course
//
$sql = " SELECT ctx.path,
rc . capability , rc . permission
2008-05-15 21:40:00 +00:00
FROM { context } ctx
JOIN { role_capabilities } rc
ON rc . contextid = ctx . id
WHERE rc . roleid = ?
AND ( ctx . id = " .SYSCONTEXTID. " OR ctx . path LIKE ? )
AND ctx . contextlevel <= " .CONTEXT_COURSE. "
ORDER BY ctx . depth , ctx . path " ;
$params = array ( $roleid , " $base /% " );
2008-05-24 18:35:48 +00:00
2008-05-15 21:40:00 +00:00
if ( $rs = $DB -> get_recordset_sql ( $sql , $params )) {
foreach ( $rs as $rd ) {
2007-10-10 12:19:27 +00:00
$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 );
2008-05-15 21:40:00 +00:00
$rs -> close ();
2007-09-26 07:12:38 +00:00
}
return $accessdata ;
}
2006-09-14 09:39:23 +00:00
/**
* Get the default guest role
2009-11-01 11:31:16 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2006-09-14 09:39:23 +00:00
* @ return object role
*/
function get_guest_role () {
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-02-01 10:24:26 +00:00
if ( empty ( $CFG -> guestroleid )) {
2010-03-31 07:41:31 +00:00
if ( $roles = $DB -> get_records ( 'role' , array ( 'archetype' => 'guest' ))) {
2007-02-01 10:24:26 +00:00
$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 {
2008-05-15 21:40:00 +00:00
if ( $guestrole = $DB -> get_record ( 'role' , array ( 'id' => $CFG -> guestroleid ))) {
2007-02-01 10:24:26 +00:00
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
/**
2009-07-21 06:24:44 +00:00
* Check whether a user has a paritcular capability in a given context .
2009-05-19 07:50:54 +00:00
*
2009-07-21 06:24:44 +00:00
* For example ::
* $context = get_context_instance ( CONTEXT_MODULE , $cm -> id );
* has_capability ( 'mod/forum:replypost' , $context )
2009-05-19 07:50:54 +00:00
*
2009-07-21 06:24:44 +00:00
* By default checks the capabilties of the current user , but you can pass a
2010-03-31 07:41:31 +00:00
* different userid . By default will return true for admin users , but you can override that with the fourth argument .
*
* Guest and not - logged - in users can never get any dangerous capability - that is any write capability
* or capabilities with XSS , config or data loss risks .
2009-11-01 11:31:16 +00:00
*
2009-07-21 06:24:44 +00:00
* @ param string $capability the name of the capability to check . For example mod / forum : view
* @ param object $context the context to check the capability in . You normally get this with { @ link get_context_instance } .
2010-03-31 07:41:31 +00:00
* @ param integer | object $user A user id or object . By default ( NULL ) checks the permissions of the current user .
* @ param boolean $doanything If false , ignores effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ return boolean true if the user has this capability . Otherwise false .
2007-10-09 12:49:54 +00:00
*/
2010-03-31 07:41:31 +00:00
function has_capability ( $capability , $context , $user = NULL , $doanything = true ) {
2009-03-23 03:54:50 +00:00
global $USER , $CFG , $DB , $SCRIPT , $ACCESSLIB_PRIVATE ;
2009-01-15 22:09:57 +00:00
2009-06-24 09:17:56 +00:00
if ( during_initial_install ()) {
2009-01-15 22:09:57 +00:00
if ( $SCRIPT === " / $CFG->admin /index.php " or $SCRIPT === " / $CFG->admin /cliupgrade.php " ) {
// we are in an installer - roles can not work yet
return true ;
} else {
return false ;
}
}
2007-09-19 07:02:31 +00:00
2010-03-31 07:41:31 +00:00
if ( strpos ( $capability , 'moodle/legacy:' ) === 0 ) {
throw new coding_exception ( 'Legacy capabilities can not be used any more!' );
}
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
}
2010-03-31 07:41:31 +00:00
if ( ! is_bool ( $doanything )) {
throw new coding_exception ( 'Capability parameter "doanything" is wierd ("' . $doanything . '"). This has to be fixed in code.' );
}
2007-09-19 07:02:31 +00:00
2010-03-31 07:41:31 +00:00
// make sure there is a real user specified
if ( $user === NULL ) {
$userid = ! empty ( $USER -> id ) ? $USER -> id : 0 ;
} else {
$userid = ! empty ( $user -> id ) ? $user -> id : $user ;
2008-01-08 15:04:00 +00:00
}
2010-03-31 07:41:31 +00:00
// capability must exist
if ( ! $capinfo = get_capability_info ( $capability )) {
debugging ( 'Capability "' . $capability . '" was not found! This should be fixed in code.' );
return false ;
}
// make sure the guest account and not-logged-in users never get any risky caps no matter what the actual settings are.
if (( $capinfo -> captype === 'write' ) or (( int ) $capinfo -> riskbitmask & ( RISK_XSS | RISK_CONFIG | RISK_DATALOSS ))) {
if ( isguestuser ( $userid ) or $userid == 0 ) {
return false ;
2009-06-29 05:00:45 +00:00
}
2007-09-19 07:02:31 +00:00
}
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 );
}
2009-01-03 14:28:02 +00:00
if ( CLI_SCRIPT && ! 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.
2009-03-23 03:54:50 +00:00
if ( isset ( $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ])) {
$ACCESSLIB_PRIVATE -> dirtycontexts = NULL ; //load fresh dirty contexts
2007-10-09 12:49:54 +00:00
} else {
2007-09-19 07:20:24 +00:00
load_user_accessdata ( $userid );
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> dirtycontexts = array ();
2007-09-19 07:20:24 +00:00
}
2009-03-23 03:54:50 +00:00
$USER -> access = $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ];
2007-10-05 15:06:38 +00:00
2009-10-27 09:31:46 +00:00
} else if ( isset ( $USER -> id ) && ( $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 ();
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> accessdatabyuser = array (); // reset the cache for other users too, the dirty contexts are empty now
$ACCESSLIB_PRIVATE -> roledefinitions = array ();
2007-09-19 07:20:24 +00:00
}
2007-10-09 12:49:54 +00:00
// Load dirty contexts list if needed
2009-03-23 03:54:50 +00:00
if ( ! isset ( $ACCESSLIB_PRIVATE -> dirtycontexts )) {
2007-11-16 03:34:05 +00:00
if ( isset ( $USER -> access [ 'time' ])) {
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> dirtycontexts = get_dirty_contexts ( $USER -> access [ 'time' ]);
2007-11-16 03:34:05 +00:00
}
else {
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> dirtycontexts = array ();
2007-11-16 03:34:05 +00:00
}
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
// Careful check for staleness...
2009-03-23 03:54:50 +00:00
if ( count ( $ACCESSLIB_PRIVATE -> dirtycontexts ) !== 0 and is_contextpath_dirty ( $contexts , $ACCESSLIB_PRIVATE -> 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! :-)
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> accessdatabyuser = array ();
$ACCESSLIB_PRIVATE -> roledefinitions = array ();
2007-10-09 12:49:54 +00:00
2009-01-03 14:28:02 +00:00
if ( CLI_SCRIPT ) {
2007-10-09 12:49:54 +00:00
load_user_accessdata ( $userid );
2009-03-23 03:54:50 +00:00
$USER -> access = $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ];
$ACCESSLIB_PRIVATE -> dirtycontexts = array ();
2007-10-09 12:49:54 +00:00
} else {
reload_all_capabilities ();
}
2007-09-19 07:10:24 +00:00
}
2007-10-09 12:49:54 +00:00
2010-03-31 07:41:31 +00:00
// Find out if user is admin - it is not possible to override the doanything in any way
// and it is not possible to switch to admin role either.
if ( $doanything ) {
if ( is_siteadmin ( $userid )) {
return true ;
}
}
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");
2009-10-27 09:31:46 +00:00
if ( isset ( $USER -> id ) && ( $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
2010-03-31 07:41:31 +00:00
return has_capability_in_accessdata ( $capability , $context , $USER -> access );
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
}
2010-03-31 07:41:31 +00:00
return has_capability_in_accessdata ( $capability , $context , $USER -> access );
2007-09-19 07:02:31 +00:00
}
2007-09-20 04:52:54 +00:00
2009-03-23 03:54:50 +00:00
if ( ! isset ( $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ])) {
2007-09-19 07:06:55 +00:00
load_user_accessdata ( $userid );
}
2010-03-31 07:41:31 +00:00
2007-09-19 07:26:02 +00:00
if ( $context -> contextlevel <= CONTEXT_COURSE ) {
// Course and above are always preloaded
2010-03-31 07:41:31 +00:00
return has_capability_in_accessdata ( $capability , $context , $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ]);
2007-09-19 07:26:02 +00:00
}
// Load accessdata for below-the-course contexts as needed
2009-03-23 03:54:50 +00:00
if ( ! path_inaccessdata ( $context -> path , $ACCESSLIB_PRIVATE -> accessdatabyuser [ $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']}");
2009-03-23 03:54:50 +00:00
load_subcontext ( $userid , $context , $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ]);
2007-09-19 07:26:02 +00:00
}
2010-03-31 07:41:31 +00:00
return has_capability_in_accessdata ( $capability , $context , $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ]);
2007-09-19 07:02:31 +00:00
}
2007-10-30 10:50:20 +00:00
/**
2009-07-21 06:24:44 +00:00
* Check if the user has any one of several capabilities from a list .
2009-05-19 07:50:54 +00:00
*
2009-07-21 06:24:44 +00:00
* This is just a utility method that calls has_capability in a loop . Try to put
* the capabilities that most users are likely to have first in the list for best
* performance .
2007-10-30 10:50:20 +00:00
*
* There are probably tricks that could be done to improve the performance here , for example ,
* check the capabilities that are already cached first .
*
2009-05-19 07:50:54 +00:00
* @ see has_capability ()
2009-07-21 06:24:44 +00:00
* @ param array $capabilities an array of capability names .
* @ param object $context the context to check the capability in . You normally get this with { @ link get_context_instance } .
2010-03-31 07:41:31 +00:00
* @ param integer $userid A user id . By default ( NULL ) checks the permissions of the current user .
* @ param boolean $doanything If false , ignore effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ return boolean true if the user has any of these capabilities . Otherwise false .
2007-10-30 10:50:20 +00:00
*/
function has_any_capability ( $capabilities , $context , $userid = NULL , $doanything = true ) {
2009-07-21 06:24:44 +00:00
if ( ! is_array ( $capabilities )) {
debugging ( 'Incorrect $capabilities parameter in has_any_capabilities() call - must be an array' );
return false ;
}
2007-10-30 10:50:20 +00:00
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 ;
}
2008-12-08 07:28:19 +00:00
/**
2009-07-21 06:24:44 +00:00
* Check if the user has all the capabilities in a list .
2009-05-19 07:50:54 +00:00
*
2009-07-21 06:24:44 +00:00
* This is just a utility method that calls has_capability in a loop . Try to put
* the capabilities that fewest users are likely to have first in the list for best
* performance .
2008-12-08 07:28:19 +00:00
*
* There are probably tricks that could be done to improve the performance here , for example ,
* check the capabilities that are already cached first .
*
2009-05-19 07:50:54 +00:00
* @ see has_capability ()
2009-07-21 06:24:44 +00:00
* @ param array $capabilities an array of capability names .
* @ param object $context the context to check the capability in . You normally get this with { @ link get_context_instance } .
2010-03-31 07:41:31 +00:00
* @ param integer $userid A user id . By default ( NULL ) checks the permissions of the current user .
* @ param boolean $doanything If false , ignore effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ return boolean true if the user has all of these capabilities . Otherwise false .
2008-12-08 07:28:19 +00:00
*/
function has_all_capabilities ( $capabilities , $context , $userid = NULL , $doanything = true ) {
2008-12-09 16:25:38 +00:00
if ( ! is_array ( $capabilities )) {
debugging ( 'Incorrect $capabilities parameter in has_all_capabilities() call - must be an array' );
return false ;
}
2008-12-08 07:28:19 +00:00
foreach ( $capabilities as $capability ) {
if ( ! has_capability ( $capability , $context , $userid , $doanything )) {
return false ;
}
}
return true ;
}
2007-10-09 12:49:54 +00:00
/**
2010-03-31 07:41:31 +00:00
* Check if the user is an admin at the site level .
2009-05-19 07:50:54 +00:00
*
2010-03-31 07:41:31 +00:00
* Please note that use of proper capabilities is always encouraged ,
* this function is supposed to be used from core or for temporary hacks .
2007-09-19 07:30:09 +00:00
*
2010-03-31 07:41:31 +00:00
* @ param int | object $user_or_id user id or user object
* @ returns bool true if user is one of the administrators , false otherwise
2007-09-19 07:30:09 +00:00
*/
2010-03-31 07:41:31 +00:00
function is_siteadmin ( $user_or_id = NULL ) {
global $CFG , $USER ;
2007-09-19 07:30:09 +00:00
2010-03-31 07:41:31 +00:00
if ( $user_or_id === NULL ) {
$user_or_id = $USER ;
}
2008-10-30 10:49:15 +00:00
2010-03-31 07:41:31 +00:00
if ( empty ( $user_or_id )) {
return false ;
}
if ( ! empty ( $user_or_id -> id )) {
// we support
$userid = $user_or_id -> id ;
} else {
$userid = $user_or_id ;
}
2008-10-30 10:49:15 +00:00
2010-03-31 07:41:31 +00:00
$siteadmins = explode ( ',' , $CFG -> siteadmins );
return in_array ( $userid , $siteadmins );
2008-10-30 10:49:15 +00:00
}
2008-11-18 07:10:00 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns true if user has at least one role assign
* of 'coursemanager' role ( is potentially listed in some course descriptions ) .
* @ param $userid
* @ return unknown_type
2008-11-18 07:10:00 +00:00
*/
2010-03-31 07:41:31 +00:00
function has_coursemanager_role ( $userid ) {
2008-11-18 07:10:00 +00:00
global $DB ;
2010-03-31 07:41:31 +00:00
if ( empty ( $CFG -> coursemanager )) {
return false ;
}
$sql = " SELECT 1
FROM { role_assignments }
WHERE userid = : userid AND roleid IN ( $CFG -> coursemanager ) " ;
return $DB -> record_exists ( $sql , array ( 'userid' => $userid ));
2008-11-18 07:10:00 +00:00
}
2009-05-19 07:50:54 +00:00
/**
* @ param string $path
* @ return string
*/
2010-03-31 07:41:31 +00:00
function get_course_from_path ( $path ) {
2007-09-19 07:02:31 +00:00
// assume that nothing is more than 1 course deep
if ( preg_match ( '!^(/.+)/\d+$!' , $path , $matches )) {
return $matches [ 1 ];
}
return false ;
}
2009-05-19 07:50:54 +00:00
/**
* @ param string $path
* @ param array $accessdata
* @ return bool
*/
2007-09-20 04:52:54 +00:00
function path_inaccessdata ( $path , $accessdata ) {
2010-03-31 07:41:31 +00:00
if ( empty ( $accessdata [ 'loaded' ])) {
return false ;
}
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
/**
2010-03-07 09:28:54 +00:00
* Does the user have a capability to do something ?
2009-05-19 07:50: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
2008-05-24 18:35:48 +00:00
* side effects .
2007-09-19 07:05:48 +00:00
*
2007-09-19 07:16:18 +00:00
* Notes :
*
* Switch Roles exits early
2010-03-07 09:28:54 +00:00
* ------------------------
2007-09-19 07:16:18 +00:00
* 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 .
*
2010-03-07 09:28:54 +00:00
* Permission evaluation
* ---------------------
* Originaly there was an extremely complicated way
* to determine the user access that dealt with
* " locality " or role assignemnts and role overrides .
* Now we simply evaluate access for each roel separately
* and then verify if user has at least one role with allow
* and at the same time no role with prohibit .
*
2009-05-19 07:50:54 +00:00
* @ param string $capability
* @ param object $context
* @ param array $accessdata
* @ return bool
2007-09-19 07:05:48 +00:00
*/
2010-03-31 07:41:31 +00:00
function has_capability_in_accessdata ( $capability , $context , array $accessdata ) {
2007-09-19 07:16:18 +00:00
global $CFG ;
2010-03-07 09:28:54 +00:00
if ( empty ( $context -> id )) {
throw new coding_exception ( 'Invalid context specified' );
2007-09-19 07:02:31 +00:00
}
2007-09-19 07:16:18 +00:00
2010-03-07 09:28:54 +00:00
// Build $paths as a list of current + all parent "paths" with order bottom-to-top
$contextids = explode ( '/' , trim ( $context -> path , '/' ));
$paths = array ( $context -> path );
while ( $contextids ) {
array_pop ( $contextids );
$paths [] = '/' . implode ( '/' , $contextids );
2007-09-19 07:16:18 +00:00
}
2010-03-07 09:28:54 +00:00
unset ( $contextids );
2007-09-19 07:16:18 +00:00
2010-03-07 09:28:54 +00:00
$roles = array ();
$switchedrole = false ;
2007-09-19 07:05:48 +00:00
2010-03-07 09:28:54 +00:00
// Find out if role switched
if ( ! empty ( $accessdata [ 'rsw' ])) {
2007-09-19 07:05:48 +00:00
// From the bottom up...
2010-03-07 09:28:54 +00:00
foreach ( $paths as $path ) {
2010-03-24 13:10:10 +00:00
if ( isset ( $accessdata [ 'rsw' ][ $path ])) {
2010-03-07 09:28:54 +00:00
// Found a switchrole assignment - check for that role _plus_ the default user role
2010-03-31 07:41:31 +00:00
$roles = array ( $accessdata [ 'rsw' ][ $path ] => NULL , $CFG -> defaultuserroleid => NULL );
2010-03-07 09:28:54 +00:00
$switchedrole = true ;
break ;
2007-09-19 07:05:48 +00:00
}
}
}
2010-03-07 09:28:54 +00:00
if ( ! $switchedrole ) {
// get all users roles in this context and above
foreach ( $paths as $path ) {
if ( isset ( $accessdata [ 'ra' ][ $path ])) {
foreach ( $accessdata [ 'ra' ][ $path ] as $roleid ) {
2010-03-31 07:41:31 +00:00
$roles [ $roleid ] = NULL ;
2007-09-19 07:02:31 +00:00
}
2010-03-07 09:28:54 +00:00
}
}
2007-09-19 07:02:31 +00:00
}
2010-03-07 09:28:54 +00:00
// Now find out what access is given to each role, going bottom-->up direction
foreach ( $roles as $roleid => $ignored ) {
foreach ( $paths as $path ) {
if ( isset ( $accessdata [ 'rdef' ][ " { $path } : $roleid " ][ $capability ])) {
$perm = ( int ) $accessdata [ 'rdef' ][ " { $path } : $roleid " ][ $capability ];
if ( $perm === CAP_PROHIBIT or is_null ( $roles [ $roleid ])) {
$roles [ $roleid ] = $perm ;
}
}
2007-09-19 07:02:31 +00:00
}
2010-03-07 09:28:54 +00:00
}
// any CAP_PROHIBIT found means no permission for the user
if ( array_search ( CAP_PROHIBIT , $roles ) !== false ) {
return false ;
2007-09-19 07:02:31 +00:00
}
2010-03-07 09:28:54 +00:00
// at least one CAP_ALLOW means the user has a permission
return ( array_search ( CAP_ALLOW , $roles ) !== false );
2007-09-19 07:02:31 +00:00
}
2007-09-19 07:03:19 +00:00
2009-05-19 07:50:54 +00:00
/**
* @ param object $context
* @ param array $accessdata
* @ return array
*/
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
/**
2009-07-21 06:24:44 +00:00
* A convenience function that tests has_capability , and displays an error if
* the user does not have that capability .
2009-07-04 14:22:11 +00:00
*
2009-07-21 06:24:44 +00:00
* NOTE before Moodle 2.0 , this function attempted to make an appropriate
* require_login call before checking the capability . This is no longer the case .
* You must call require_login ( or one of its variants ) if you want to check the
* user is logged in , before you call this function .
2007-09-19 07:24:43 +00:00
*
2009-05-19 07:50:54 +00:00
* @ see has_capability ()
*
2009-07-21 06:24:44 +00:00
* @ param string $capability the name of the capability to check . For example mod / forum : view
* @ param object $context the context to check the capability in . You normally get this with { @ link get_context_instance } .
2010-03-31 07:41:31 +00:00
* @ param integer $userid A user id . By default ( NULL ) checks the permissions of the current user .
* @ param bool $doanything If false , ignore effect of admin role assignment
2009-07-21 06:24:44 +00:00
* @ param string $errorstring The error string to to user . Defaults to 'nopermissions' .
* @ param string $stringfile The language file to load the error string from . Defaults to 'error' .
* @ return void terminates with an error if the user does not have the given capability .
2006-08-14 05:55:40 +00:00
*/
2009-07-21 06:24:44 +00:00
function require_capability ( $capability , $context , $userid = NULL , $doanything = true ,
$errormessage = 'nopermissions' , $stringfile = '' ) {
2006-09-13 06:35:25 +00:00
if ( ! has_capability ( $capability , $context , $userid , $doanything )) {
2009-09-14 23:52:08 +00:00
throw new required_capability_exception ( $context , $capability , $errormessage , $stringfile );
2006-08-14 05:55:40 +00:00
}
}
2007-10-09 12:49:54 +00:00
/**
2009-05-19 07:50:54 +00:00
* Get an array of courses where cap requested is available
*
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
2008-05-24 18:35:48 +00:00
* a TON of bandwidth , specially on large sites
2007-09-19 07:04:23 +00:00
* 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
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
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
2010-03-31 07:41:31 +00:00
* @ param bool $doanything_ignored - admin roles are completely ignored here
2007-09-19 07:03:49 +00:00
* @ 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
*/
2010-03-31 07:41:31 +00:00
function get_user_courses_bycap ( $userid , $cap , $accessdata , $doanything_ignored , $sort = 'c.sortorder ASC' , $fields = NULL , $limit = 0 ) {
2007-09-19 07:03:49 +00:00
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-09-19 07:03:49 +00:00
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 ;
}
2009-05-11 00:04:18 +00:00
// If any of the fields is '*', leave it alone, discarding the rest
// to avoid ambiguous columns under some silly DBs. See MDL-18746 :-D
if ( in_array ( '*' , $fields )) {
$fields = array ( '*' );
}
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 );
2010-03-31 07:41:31 +00:00
if ( has_capability_in_accessdata ( $cap , $sysctx , $accessdata )) {
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
2008-05-15 21:40:00 +00:00
FROM { course } c
JOIN { course_categories } cc
ON c . category = cc . id
2008-05-24 18:35:48 +00:00
JOIN { context } ctx
2008-05-15 21:40:00 +00:00
ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
$sort " ;
$rs = $DB -> get_recordset_sql ( $sql );
2007-09-19 07:04:23 +00:00
} else {
//
// narrow down where we have the caps to a few contexts
// this will be a combination of
2008-08-28 18:08:06 +00:00
// - courses where user has an explicit enrolment
// - courses that have an override (any status) on that capability
// - categories where user has the rights (granted status) on that capability
2008-05-24 18:35:48 +00:00
//
2007-09-19 07:04:23 +00:00
$sql = " SELECT ctx.*
2008-05-15 21:40:00 +00:00
FROM { context } ctx
WHERE ctx . contextlevel = " .CONTEXT_COURSECAT. "
ORDER BY ctx . depth " ;
$rs = $DB -> get_recordset_sql ( $sql );
2007-09-19 07:04:23 +00:00
$catpaths = array ();
2008-05-15 21:40:00 +00:00
foreach ( $rs as $catctx ) {
2008-05-24 18:35:48 +00:00
if ( $catctx -> path != ''
2010-03-31 07:41:31 +00:00
&& has_capability_in_accessdata ( $cap , $catctx , $accessdata )) {
2007-10-10 12:19:27 +00:00
$catpaths [] = $catctx -> path ;
2007-09-19 07:04:23 +00:00
}
}
2008-05-15 21:40:00 +00:00
$rs -> close ();
2007-09-19 07:04:23 +00:00
$catclause = '' ;
2008-05-24 18:35:48 +00:00
$params = array ();
2007-09-19 07:04:23 +00:00
if ( count ( $catpaths )) {
$cc = count ( $catpaths );
for ( $n = 0 ; $n < $cc ; $n ++ ) {
2008-08-28 18:08:06 +00:00
$catpaths [ $n ] = " ctx.path LIKE ' { $catpaths [ $n ] } /%' " ;
2007-09-19 07:04:23 +00:00
}
2008-08-28 18:08:06 +00:00
$catclause = 'WHERE (' . implode ( ' OR ' , $catpaths ) . ')' ;
2007-09-19 07:04:23 +00:00
}
unset ( $catpaths );
2007-09-19 07:04:37 +00:00
2008-08-28 18:08:06 +00:00
/// UNION 3 queries:
/// - user role assignments in courses
/// - user capability (override - any status) in courses
/// - user right (granted status) in categories (optionally executed)
/// Enclosing the 3-UNION into an inline_view to avoid column names conflict and making the ORDER BY cross-db
/// and to allow selection of TEXT columns in the query (MSSQL and Oracle limitation). MDL-16209
$sql = "
2010-03-31 07:41:31 +00:00
SELECT $coursefields , ctxid , ctxpath , ctxdepth , ctxlevel , ctxinstance , categorypath
2008-08-28 18:08:06 +00:00
FROM (
SELECT c . id ,
ctx . id AS ctxid , ctx . path AS ctxpath ,
2010-03-31 07:41:31 +00:00
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel , ctx . instanceid AS ctxinstance ,
2008-08-28 18:08:06 +00:00
cc . path AS categorypath
2009-03-23 05:19:53 +00:00
FROM { course } c
JOIN { course_categories } cc
2008-08-28 18:08:06 +00:00
ON c . category = cc . id
2009-03-23 05:19:53 +00:00
JOIN { context } ctx
2008-08-28 18:08:06 +00:00
ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
2009-03-23 05:19:53 +00:00
JOIN { role_assignments } ra
2008-08-28 18:08:06 +00:00
ON ( ra . contextid = ctx . id AND ra . userid =: userid )
UNION
SELECT c . id ,
ctx . id AS ctxid , ctx . path AS ctxpath ,
2010-03-31 07:41:31 +00:00
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel , ctx . instanceid AS ctxinstance ,
2008-08-28 18:08:06 +00:00
cc . path AS categorypath
2009-03-23 05:19:53 +00:00
FROM { course } c
JOIN { course_categories } cc
2008-08-28 18:08:06 +00:00
ON c . category = cc . id
2009-03-23 05:19:53 +00:00
JOIN { context } ctx
2008-08-28 18:08:06 +00:00
ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
2009-03-23 05:19:53 +00:00
JOIN { role_capabilities } rc
2010-03-31 07:41:31 +00:00
ON ( rc . contextid = ctx . id AND ( rc . capability =: cap )) " ;
2008-08-28 18:08:06 +00:00
if ( ! empty ( $catclause )) { /// If we have found the right in categories, add child courses here too
$sql .= "
UNION
SELECT c . id ,
ctx . id AS ctxid , ctx . path AS ctxpath ,
2010-03-31 07:41:31 +00:00
ctx . depth AS ctxdepth , ctx . contextlevel AS ctxlevel , ctx . instanceid AS ctxinstance ,
2008-08-28 18:08:06 +00:00
cc . path AS categorypath
2009-03-23 05:19:53 +00:00
FROM { course } c
JOIN { course_categories } cc
2008-08-28 18:08:06 +00:00
ON c . category = cc . id
2009-03-23 05:19:53 +00:00
JOIN { context } ctx
2008-08-28 18:08:06 +00:00
ON ( c . id = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
$catclause " ;
}
/// Close the inline_view and join with courses table to get requested $coursefields
$sql .= "
) inline_view
2009-03-23 05:19:53 +00:00
INNER JOIN { course } c
2008-08-28 18:08:06 +00:00
ON inline_view . id = c . id " ;
/// To keep cross-db we need to strip any prefix in the ORDER BY clause for queries using UNION
$sql .= "
" . preg_replace('/[a-z]+ \ ./i', '', $sort ); /// Add ORDER BY clause
2008-05-24 18:35:48 +00:00
$params [ 'userid' ] = $userid ;
$params [ 'cap' ] = $cap ;
2008-05-15 21:40:00 +00:00
$rs = $DB -> get_recordset_sql ( $sql , $params );
2007-09-19 07:04:23 +00:00
}
2008-08-28 18:08:06 +00:00
/// Confirm rights (granted capability) for each course returned
2007-09-19 07:03:49 +00:00
$courses = array ();
$cc = 0 ; // keep count
2008-05-15 21:40:00 +00:00
if ( $rs ) {
foreach ( $rs as $c ) {
// build the context obj
2010-03-31 07:41:31 +00:00
context_instance_preload ( $c );
$context = get_context_instance ( CONTEXT_COURSE , $c -> id );
2008-05-15 21:40:00 +00:00
2010-03-31 07:41:31 +00:00
if ( has_capability_in_accessdata ( $cap , $context , $accessdata )) {
2009-10-08 04:52:33 +00:00
if ( $limit > 0 && $cc >= $limit ) {
2008-05-15 21:40:00 +00:00
break ;
}
2009-11-01 11:31:16 +00:00
2009-10-08 04:52:33 +00:00
$courses [] = $c ;
$cc ++ ;
2007-09-19 07:03:49 +00:00
}
}
2008-05-15 21:40:00 +00:00
$rs -> close ();
2007-09-19 07:03:49 +00:00
}
2008-05-24 18:35:48 +00:00
2007-09-19 07:03:49 +00:00
return $courses ;
}
2007-09-19 07:05:21 +00:00
2007-09-19 07:02:04 +00:00
/**
2009-05-19 07:50:54 +00:00
* 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 .
*
2009-06-16 15:34:55 +00:00
* [ ra ] => [ / path / ][] = 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
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
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
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-09-19 07:02:04 +00:00
/* Get in 3 cheap DB queries ...
2009-06-16 15:34:55 +00:00
* - role assignments
2007-09-19 07:02:04 +00:00
* - relevant role caps
2009-06-16 15:34:55 +00:00
* - above and within this user ' s RAs
2007-09-19 07:02:04 +00:00
* - 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
//
2009-06-16 15:34:55 +00:00
// Role assignments
2007-09-19 07:02:04 +00:00
//
2009-06-16 15:34:55 +00:00
$sql = " SELECT ctx.path, ra.roleid
2008-05-15 21:40:00 +00:00
FROM { role_assignments } ra
2009-06-16 15:34:55 +00:00
JOIN { context } ctx ON ctx . id = ra . contextid
WHERE ra . userid = ? AND ctx . contextlevel <= " .CONTEXT_COURSE;
2008-05-15 21:40:00 +00:00
$params = array ( $userid );
$rs = $DB -> get_recordset_sql ( $sql , $params );
2009-06-16 15:34:55 +00:00
2007-09-19 07:03:19 +00:00
//
// raparents collects paths & roles we need to walk up
// the parenthood to build the rdef
//
2007-09-19 07:02:04 +00:00
$raparents = array ();
2007-10-09 12:49:54 +00:00
if ( $rs ) {
2008-05-15 21:40:00 +00:00
foreach ( $rs as $ra ) {
2007-10-10 12:19:27 +00:00
// RAs leafs are arrays to support multi
// role assignments...
if ( ! isset ( $accessdata [ 'ra' ][ $ra -> path ])) {
$accessdata [ 'ra' ][ $ra -> path ] = array ();
}
2009-06-16 15:34:55 +00:00
array_push ( $accessdata [ 'ra' ][ $ra -> path ], $ra -> roleid );
// Concatenate as string the whole path (all related context)
// for this role. This is damn faster than using array_merge()
// Will unique them later
if ( isset ( $raparents [ $ra -> roleid ])) {
$raparents [ $ra -> roleid ] .= $ra -> path ;
} else {
$raparents [ $ra -> roleid ] = $ra -> path ;
2007-10-10 12:19:27 +00:00
}
2007-09-19 07:02:04 +00:00
}
2007-10-10 12:19:27 +00:00
unset ( $ra );
2008-05-15 21:40:00 +00:00
$rs -> close ();
2007-09-19 07:02:04 +00:00
}
// Walk up the tree to grab all the roledefs
// of interest to our user...
2009-06-16 15:34:55 +00:00
//
2007-09-19 07:02:04 +00:00
// 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()
2009-06-16 15:34:55 +00:00
$clauses = '' ;
2008-05-15 21:40:00 +00:00
$cparams = array ();
2009-06-16 15:34:55 +00:00
foreach ( $raparents as $roleid => $strcontexts ) {
$contexts = implode ( ',' , array_unique ( explode ( '/' , trim ( $strcontexts , '/' ))));
2007-09-19 07:02:04 +00:00
if ( $contexts ==! '' ) {
2009-06-16 15:34:55 +00:00
if ( $clauses ) {
$clauses .= ' OR ' ;
}
$clauses .= " (roleid=? AND contextid IN ( $contexts )) " ;
2008-05-15 21:40:00 +00:00
$cparams [] = $roleid ;
2007-09-19 07:02:04 +00:00
}
}
2009-06-16 15:34:55 +00:00
2007-09-19 07:22:12 +00:00
if ( $clauses !== '' ) {
$sql = " SELECT ctx.path, rc.roleid, rc.capability, rc.permission
2008-05-15 21:40:00 +00:00
FROM { role_capabilities } rc
JOIN { context } ctx
2007-09-19 07:22:12 +00:00
ON rc . contextid = ctx . id
2009-06-16 15:34:55 +00:00
WHERE $clauses " ;
2007-09-19 07:22:12 +00:00
unset ( $clauses );
2009-06-16 15:34:55 +00:00
$rs = $DB -> get_recordset_sql ( $sql , $cparams );
2007-09-19 07:02:04 +00:00
2007-11-12 16:53:53 +00:00
if ( $rs ) {
2008-05-15 21:40:00 +00:00
foreach ( $rs as $rd ) {
2007-11-12 16:53:53 +00:00
$k = " { $rd -> path } : { $rd -> roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
unset ( $rd );
2008-05-15 21:40:00 +00:00
$rs -> close ();
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
2008-05-15 21:40:00 +00:00
FROM { role_assignments } ra
JOIN { context } ctx
ON ra . contextid = ctx . id
JOIN { context } sctx
2008-05-24 18:35:48 +00:00
ON ( sctx . path LIKE " . $DB->sql_concat ('ctx.path', " '/%' " ). " )
2008-05-15 21:40:00 +00:00
JOIN { role_capabilities } rco
ON ( rco . roleid = ra . roleid AND rco . contextid = sctx . id )
WHERE ra . userid = ?
2009-03-20 12:10:47 +00:00
AND ctx . contextlevel <= " .CONTEXT_COURSECAT. "
AND sctx . contextlevel <= " .CONTEXT_COURSE. "
2008-05-15 21:40:00 +00:00
ORDER BY sctx . depth , sctx . path , ra . roleid " ;
$params = array ( $userid );
$rs = $DB -> get_recordset_sql ( $sql , $params );
2007-11-12 16:53:53 +00:00
if ( $rs ) {
2008-05-15 21:40:00 +00:00
foreach ( $rs as $rd ) {
2007-11-12 16:53:53 +00:00
$k = " { $rd -> path } : { $rd -> roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
unset ( $rd );
2008-05-15 21:40:00 +00:00
$rs -> close ();
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
/**
2009-05-19 07:50:54 +00:00
* Add to the access ctrl array the data needed by a user for a given context
2007-09-19 07:02:44 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param integer $userid the id of the user
* @ param object $context needs path !
* @ param array $accessdata 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
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
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.
//
2008-05-24 18:35:48 +00:00
if ( $context -> contextlevel !== CONTEXT_COURSE
2007-09-19 07:53:49 +00:00
&& $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
2008-05-23 10:36:28 +00:00
$courses = explode ( '/' , get_course_from_path ( $context -> path ));
$targetid = array_pop ( $courses );
2007-09-19 07:53:49 +00:00
$context = get_context_instance_by_id ( $targetid );
2008-05-24 18:35:48 +00:00
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
2008-05-15 21:40:00 +00:00
FROM { role_assignments } ra
JOIN { context } ctx
ON ra . contextid = ctx . id
WHERE ra . userid = ?
AND ( ctx . path = ? OR ctx . path LIKE ? )
2008-08-18 22:46:40 +00:00
ORDER BY ctx . depth , ctx . path , ra . roleid " ;
2008-05-15 21:40:00 +00:00
$params = array ( $userid , $context -> path , $context -> path . " /% " );
$rs = $DB -> get_recordset_sql ( $sql , $params );
2007-09-19 07:02:44 +00:00
2008-05-24 18:35:48 +00:00
//
2008-08-18 22:46:40 +00:00
// Read in the RAs, preventing duplicates
2007-09-19 07:03:19 +00:00
//
2008-05-15 21:40:00 +00:00
if ( $rs ) {
$localroles = array ();
2008-08-18 22:46:40 +00:00
$lastseen = '' ;
2008-05-15 21:40:00 +00:00
foreach ( $rs as $ra ) {
if ( ! isset ( $accessdata [ 'ra' ][ $ra -> path ])) {
$accessdata [ 'ra' ][ $ra -> path ] = array ();
}
2008-08-18 22:46:40 +00:00
// 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 );
array_push ( $localroles , $ra -> roleid );
}
2007-09-19 07:02:44 +00:00
}
2008-05-15 21:40:00 +00:00
$rs -> close ();
2007-09-19 07:02:44 +00:00
}
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 );
2008-05-24 18:35:48 +00:00
$wherelocalroles = " OR (rc.roleid IN ( { $localroleids } )
2007-09-19 07:53:49 +00:00
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
2008-05-15 21:40:00 +00:00
FROM { role_capabilities } rc
JOIN { context } ctx
ON rc . contextid = ctx . id
WHERE ( $whereroles
( ctx . id = ? OR ctx . path LIKE ? ))
$wherelocalroles
ORDER BY ctx . depth ASC , ctx . path DESC , rc . roleid ASC " ;
$params = array ( $context -> id , $context -> path . " /% " );
2007-09-19 07:53:49 +00:00
2007-10-17 09:19:39 +00:00
$newrdefs = array ();
2008-05-15 21:40:00 +00:00
if ( $rs = $DB -> get_recordset_sql ( $sql , $params )) {
foreach ( $rs as $rd ) {
2007-10-10 12:19:27 +00:00
$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
}
2008-05-15 21:40:00 +00:00
$rs -> close ();
2007-09-21 04:33:50 +00:00
} 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
/**
2009-05-19 07:50:54 +00:00
* Add to the access ctrl array the data needed by a role for a given context .
2007-09-19 07:05:32 +00:00
*
* 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 ...
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param integer $roleid the id of the user
* @ param object $context needs path !
2010-03-31 07:41:31 +00:00
* @ param array $accessdata accessdata array NULL by default
2009-05-19 07:50:54 +00:00
* @ return 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
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-09-19 07:05:32 +00:00
/* 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
}
2008-05-24 18:35:48 +00:00
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
2008-05-15 21:40:00 +00:00
FROM { role_capabilities } rc
JOIN { context } ctx
ON rc . contextid = ctx . id
WHERE rc . roleid = ? AND
2008-05-24 18:35:48 +00:00
( ctx . id IN ( $contexts ) OR
2008-05-15 21:40:00 +00:00
ctx . path LIKE ? )
ORDER BY ctx . depth ASC , ctx . path DESC , rc . roleid ASC " ;
$params = array ( $roleid , $context -> path . " /% " );
if ( $rs = $DB -> get_recordset_sql ( $sql , $params )) {
foreach ( $rs as $rd ) {
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
$rs -> close ();
2007-09-19 07:05:32 +00:00
}
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
/**
2009-05-19 07:50:54 +00:00
* Load accessdata for a user into the $ACCESSLIB_PRIVATE -> accessdatabyuser global
2007-09-19 07:06:55 +00:00
*
* Used by has_capability () - but feel free
2008-05-24 18:35:48 +00:00
* to call it if you are about to run a BIG
2007-09-19 07:06:55 +00:00
* cron run across a bazillion users .
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $userid
* @ return array returns ACCESSLIB_PRIVATE -> accessdatabyuser [ userid ]
2008-05-24 18:35:48 +00:00
*/
2007-09-19 07:06:55 +00:00
function load_user_accessdata ( $userid ) {
2009-03-23 03:54:50 +00:00
global $CFG , $ACCESSLIB_PRIVATE ;
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 );
2008-05-24 18:35:48 +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 ();
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ] = $accessdata ;
compact_rdefs ( $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ][ 'rdef' ]);
2007-10-17 09:19:39 +00:00
2009-03-23 03:54:50 +00:00
return $ACCESSLIB_PRIVATE -> accessdatabyuser [ $userid ];
2007-09-19 07:06:55 +00:00
}
2007-09-19 07:11:18 +00:00
2007-10-17 09:19:39 +00:00
/**
2009-05-19 07:50:54 +00:00
* Use shared copy of role definistions stored in ACCESSLIB_PRIVATE -> roledefinitions ;
2009-05-22 02:03:55 +00:00
*
* @ global object
2007-10-17 09:19:39 +00:00
* @ param array $rdefs array of role definitions in contexts
*/
function compact_rdefs ( & $rdefs ) {
2009-03-23 03:54:50 +00:00
global $ACCESSLIB_PRIVATE ;
2007-10-17 09:19:39 +00:00
/*
* This is a basic sharing only , we could also
* use md5 sums of values . The main purpose is to
2009-03-23 03:54:50 +00:00
* reduce mem in cron jobs - many users in $ACCESSLIB_PRIVATE -> accessdatabyuser array .
2007-10-17 09:19:39 +00:00
*/
foreach ( $rdefs as $key => $value ) {
2009-03-23 03:54:50 +00:00
if ( ! array_key_exists ( $key , $ACCESSLIB_PRIVATE -> roledefinitions )) {
$ACCESSLIB_PRIVATE -> roledefinitions [ $key ] = $rdefs [ $key ];
2007-10-17 09:19:39 +00:00
}
2009-03-23 03:54:50 +00:00
$rdefs [ $key ] =& $ACCESSLIB_PRIVATE -> roledefinitions [ $key ];
2007-10-17 09:19:39 +00:00
}
}
2007-09-19 07:05:32 +00:00
/**
2009-05-19 07:50:54 +00:00
* A convenience function to completely load all the capabilities
* 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 ();
* @ see check_enrolment_plugins ()
2009-11-01 11:31:16 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
* @ global object
2006-10-23 15:17:31 +00:00
*/
function load_all_capabilities () {
2009-03-23 03:54:50 +00:00
global $USER , $CFG , $ACCESSLIB_PRIVATE ;
2006-08-08 05:13:06 +00:00
2009-01-15 22:09:57 +00:00
// roles not installed yet - we are in the middle of installation
2009-06-24 09:17:56 +00:00
if ( during_initial_install ()) {
2009-01-12 16:52:53 +00:00
return ;
}
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 );
}
2008-05-24 18:35:48 +00:00
}
2007-09-26 07:12:38 +00:00
$USER -> access = $accessdata ;
2008-05-24 18:35:48 +00:00
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 ();
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> 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
/**
2008-05-24 18:35:48 +00:00
* A convenience function to completely reload all the capabilities
2007-09-19 07:11:18 +00:00
* for the current user when roles have been updated in a relevant
2008-05-24 18:35:48 +00:00
* context -- but PRESERVING switchroles and loginas .
2007-09-19 07:11:18 +00:00
*
* That is - completely transparent to the user .
2008-05-24 18:35:48 +00:00
*
2007-09-19 07:11:18 +00:00
* Note : rewrites $USER -> access completely .
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2007-09-19 07:11:18 +00:00
*/
function reload_all_capabilities () {
2008-05-15 21:40:00 +00:00
global $USER , $DB ;
2007-09-19 07:11:18 +00:00
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 );
2008-05-24 18:35:48 +00:00
2007-09-19 07:11:18 +00:00
load_all_capabilities ();
foreach ( $sw as $path => $roleid ) {
2008-05-15 21:40:00 +00:00
$context = $DB -> get_record ( 'context' , array ( 'path' => $path ));
2007-09-19 07:11:18 +00:00
role_switch ( $roleid , $context );
}
}
2006-10-23 15:17:31 +00:00
2008-05-15 21:40:00 +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 !
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $content
* @ param int $roleid
* @ param array $accessdata
* @ return array Returns access data
2007-09-19 07:16:29 +00:00
*/
2007-09-20 04:52:54 +00:00
function load_temp_role ( $context , $roleid , $accessdata ) {
2007-09-19 07:16:29 +00:00
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-09-19 07:16:29 +00:00
//
// Load rdefs for the role in -
// - this context
// - all the parents
// - and below - IOWs overrides...
//
2008-05-24 18:35:48 +00:00
2007-09-19 07:16:29 +00:00
// turn the path into a list of context ids
$contexts = substr ( $context -> path , 1 ); // kill leading slash
$contexts = str_replace ( '/' , ',' , $contexts );
2008-05-15 21:40:00 +00:00
$sql = " SELECT ctx.path, rc.capability, rc.permission
FROM { context } ctx
JOIN { role_capabilities } rc
ON rc . contextid = ctx . id
WHERE ( ctx . id IN ( $contexts )
OR ctx . path LIKE ? )
AND rc . roleid = ?
ORDER BY ctx . depth , ctx . path " ;
2008-05-24 18:35:48 +00:00
$params = array ( $context -> path . " /% " , $roleid );
if ( $rs = $DB -> get_recordset_sql ( $sql , $params )) {
2008-05-15 21:40:00 +00:00
foreach ( $rs as $rd ) {
$k = " { $rd -> path } : { $roleid } " ;
$accessdata [ 'rdef' ][ $k ][ $rd -> capability ] = $rd -> permission ;
}
2008-09-09 02:23:47 +00:00
$rs -> close ();
2008-05-15 21:40:00 +00:00
}
2007-09-19 07:16:29 +00:00
//
// 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
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $user
2009-01-02 20:32:05 +00:00
* @ return void
2006-09-16 13:54:57 +00:00
*/
function check_enrolment_plugins ( & $user ) {
global $CFG ;
2009-01-02 20:32:05 +00:00
if ( empty ( $user -> id ) or isguestuser ( $user )) {
// shortcut - there is no enrolment work for guests and not-logged-in users
return ;
}
2009-01-17 23:16:20 +00:00
static $inprogress = array (); // To prevent this function being called more than once in an invocation
2006-09-25 01:34:21 +00:00
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
}
2007-03-03 21:07:07 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns array of all role archetypes .
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ return array
2007-03-03 21:07:07 +00:00
*/
2010-03-31 07:41:31 +00:00
function get_role_archetypes () {
2007-03-03 21:07:07 +00:00
return array (
2010-03-31 07:41:31 +00:00
'manager' => 'manager' ,
'coursecreator' => 'coursecreator' ,
'editingteacher' => 'editingteacher' ,
'teacher' => 'teacher' ,
'student' => 'student' ,
'guest' => 'guest' ,
'user' => 'user' ,
'frontpage' => 'frontpage'
2007-03-03 21:07:07 +00:00
);
}
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 .
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ param string $capability
* @ param array $legacyperms an array in the format ( example ) :
2006-08-08 05:13:06 +00:00
* 'guest' => CAP_PREVENT ,
* 'student' => CAP_ALLOW ,
* 'teacher' => CAP_ALLOW ,
* 'editingteacher' => CAP_ALLOW ,
* 'coursecreator' => CAP_ALLOW ,
2010-03-31 07:41:31 +00:00
* 'manager' => CAP_ALLOW
2009-05-19 07:50:54 +00:00
* @ return boolean success or failure .
2006-08-08 05:13:06 +00:00
*/
function assign_legacy_capabilities ( $capability , $legacyperms ) {
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
$archetypes = get_role_archetypes ();
2007-03-03 21:07:07 +00:00
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 );
2010-03-31 07:41:31 +00:00
if ( $type === 'admin' ) {
debugging ( 'Legacy type admin in access.php was renamed to manager, please update the code.' );
$type = 'manager' ;
}
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( ! array_key_exists ( $type , $archetypes )) {
2008-05-15 03:07:21 +00:00
print_error ( 'invalidlegacy' , '' , '' , $type );
2007-03-03 21:07:07 +00:00
}
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( $roles = get_archetype_roles ( $type )) {
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 ;
}
2008-11-05 08:17:30 +00:00
/**
* @ param object $capability a capbility - a row from the capabilitites table .
* @ return boolean whether this capability is safe - that is , wether people with the
* safeoverrides capability should be allowed to change it .
*/
function is_safe_capability ( $capability ) {
2008-11-18 08:08:18 +00:00
return ! (( RISK_DATALOSS | RISK_MANAGETRUST | RISK_CONFIG | RISK_XSS | RISK_PERSONAL ) & $capability -> riskbitmask );
2008-11-05 08:17:30 +00:00
}
2006-08-14 07:15:03 +00:00
/**********************************
2006-08-08 05:13:06 +00:00
* Context Manipulation functions *
**********************************/
/**
2009-05-19 07:50:54 +00:00
* Create a new context record for use by all roles - related stuff
*
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 .
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $contextlevel
* @ param int $instanceid
2010-03-31 07:41:31 +00:00
* @ param int $strictness
2007-09-19 07:13:08 +00:00
* @ return object newly created context
2006-08-08 05:13:06 +00:00
*/
2010-03-31 07:41:31 +00:00
function create_context ( $contextlevel , $instanceid , $strictness = IGNORE_MISSING ) {
2007-09-19 07:13:08 +00:00
2008-05-24 18:35:48 +00:00
global $CFG , $DB ;
2007-09-19 07:13:08 +00:00
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 ;
2010-03-31 07:41:31 +00:00
$error_message = NULL ;
2007-10-05 15:06:38 +00:00
2007-09-19 07:13:08 +00:00
switch ( $contextlevel ) {
case CONTEXT_COURSECAT :
2008-05-24 18:35:48 +00:00
$sql = " SELECT ctx.path, ctx.depth
FROM { context } ctx
JOIN { course_categories } cc
ON ( cc . parent = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSECAT. " )
WHERE cc . id = ? " ;
$params = array ( $instanceid );
if ( $p = $DB -> get_record_sql ( $sql , $params )) {
2007-09-19 07:13:45 +00:00
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2010-03-31 07:41:31 +00:00
} else if ( $category = $DB -> get_record ( 'course_categories' , array ( 'id' => $instanceid ), '*' , $strictness )) {
2007-10-05 15:06:38 +00:00
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
2010-03-31 07:41:31 +00:00
$basepath = NULL ;
2007-10-05 15:06:38 +00:00
$basedepth = 0 ;
}
} else {
// incorrect category id
2008-09-06 13:17:15 +00:00
$error_message = " incorrect course category id ( $instanceid ) " ;
2007-10-05 15:06:38 +00:00
$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
2008-05-24 18:35:48 +00:00
FROM { context } ctx
JOIN { course } c
ON ( c . category = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSECAT. " )
WHERE c . id = ? AND c . id != " . SITEID;
$params = array ( $instanceid );
if ( $p = $DB -> get_record_sql ( $sql , $params )) {
2007-09-19 07:13:45 +00:00
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2010-03-31 07:41:31 +00:00
} else if ( $course = $DB -> get_record ( 'course' , array ( 'id' => $instanceid ), '*' , $strictness )) {
2007-10-05 15:06:38 +00:00
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
2010-03-31 07:41:31 +00:00
$basepath = NULL ;
2007-10-05 15:06:38 +00:00
$basedepth = 0 ;
}
} else if ( $instanceid == SITEID ) {
// no errors for missing site course during installation
return false ;
} else {
// incorrect course id
2008-09-06 13:17:15 +00:00
$error_message = " incorrect course id ( $instanceid ) " ;
2007-10-05 15:06:38 +00:00
$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
2008-05-24 18:35:48 +00:00
FROM { context } ctx
JOIN { course_modules } cm
ON ( cm . course = ctx . instanceid AND ctx . contextlevel = " .CONTEXT_COURSE. " )
WHERE cm . id = ? " ;
$params = array ( $instanceid );
if ( $p = $DB -> get_record_sql ( $sql , $params )) {
2007-10-05 15:06:38 +00:00
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2010-03-31 07:41:31 +00:00
} else if ( $cm = $DB -> get_record ( 'course_modules' , array ( 'id' => $instanceid ), '*' , $strictness )) {
if ( $parent = get_context_instance ( CONTEXT_COURSE , $cm -> course , $strictness )) {
2007-10-05 15:06:38 +00:00
$basepath = $parent -> path ;
$basedepth = $parent -> depth ;
} else {
// course does not exist - modules can not exist without a course
2008-09-06 13:17:15 +00:00
$error_message = " course does not exist ( $cm->course ) - modules can not exist without a course " ;
2007-10-05 15:06:38 +00:00
$result = false ;
}
} else {
// cm does not exist
2008-09-06 13:19:26 +00:00
$error_message = " cm with id $instanceid does not exist " ;
2007-10-05 15:06:38 +00:00
$result = false ;
}
2007-09-19 07:13:08 +00:00
break ;
case CONTEXT_BLOCK :
2007-09-19 07:13:45 +00:00
$sql = " SELECT ctx.path, ctx.depth
2009-05-07 08:55:10 +00:00
FROM { context } ctx
2009-07-10 05:58:59 +00:00
JOIN { block_instances } bi ON ( bi . parentcontextid = ctx . id )
2009-07-13 08:37:34 +00:00
WHERE bi . id = ? " ;
2009-05-07 08:55:10 +00:00
$params = array ( $instanceid , CONTEXT_COURSE );
2010-03-31 07:41:31 +00:00
if ( $p = $DB -> get_record_sql ( $sql , $params , '*' , $strictness )) {
2007-09-19 07:13:45 +00:00
$basepath = $p -> path ;
$basedepth = $p -> depth ;
2007-10-05 15:06:38 +00:00
} else {
// block does not exist
2009-05-07 08:55:10 +00:00
$error_message = 'block or parent context does not exist' ;
2007-10-05 15:06:38 +00:00
$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 ;
}
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 ;
}
2010-03-31 07:41:31 +00:00
if ( ! $result ) {
2007-09-19 07:12:56 +00:00
debugging ( 'Error: could not insert new context level "' .
s ( $contextlevel ) . '", instance "' .
2008-09-06 13:17:15 +00:00
s ( $instanceid ) . '". ' . $error_message );
2007-10-05 15:06:38 +00:00
return false ;
2006-08-08 05:13:06 +00:00
}
2010-03-31 07:41:31 +00:00
$id = $DB -> insert_record ( 'context' , $context );
// can't set the full path till we know the id!
if ( $basedepth != 0 and ! empty ( $basepath )) {
$DB -> set_field ( 'context' , 'path' , $basepath . '/' . $id , array ( 'id' => $id ));
}
return get_context_instance_by_id ( $id );
2006-08-08 05:13:06 +00:00
}
2007-03-05 11:27:01 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns system context or NULL if can not be created yet .
2009-05-19 07:50:54 +00:00
*
* @ todo can not use get_record () because we do not know if query failed :- (
* switch to get_record () later
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2008-11-19 14:43:38 +00:00
* @ param bool $cache use caching
2010-03-31 07:41:31 +00:00
* @ return mixed system context or NULL
2007-01-30 10:10:25 +00:00
*/
2007-10-05 15:06:38 +00:00
function get_system_context ( $cache = true ) {
2009-03-23 03:54:50 +00:00
global $DB , $ACCESSLIB_PRIVATE ;
2007-10-05 15:06:38 +00:00
if ( $cache and defined ( 'SYSCONTEXTID' )) {
2009-03-23 03:54:50 +00:00
if ( is_null ( $ACCESSLIB_PRIVATE -> systemcontext )) {
$ACCESSLIB_PRIVATE -> systemcontext = new object ();
$ACCESSLIB_PRIVATE -> systemcontext -> id = SYSCONTEXTID ;
$ACCESSLIB_PRIVATE -> systemcontext -> contextlevel = CONTEXT_SYSTEM ;
$ACCESSLIB_PRIVATE -> systemcontext -> instanceid = 0 ;
$ACCESSLIB_PRIVATE -> systemcontext -> path = '/' . SYSCONTEXTID ;
$ACCESSLIB_PRIVATE -> systemcontext -> depth = 1 ;
2007-10-05 15:06:38 +00:00
}
2009-03-23 03:54:50 +00:00
return $ACCESSLIB_PRIVATE -> systemcontext ;
2007-10-05 15:06:38 +00:00
}
2008-11-04 23:07:14 +00:00
try {
2009-11-01 09:31:09 +00:00
$context = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_SYSTEM ));
2008-11-19 14:43:38 +00:00
} catch ( dml_exception $e ) {
2008-11-04 23:07:14 +00:00
//table does not exist yet, sorry
2010-03-31 07:41:31 +00:00
return NULL ;
2008-11-04 23:07:14 +00:00
}
if ( ! $context ) {
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
2008-11-19 14:43:38 +00:00
try {
2009-06-13 18:16:08 +00:00
$context -> id = $DB -> insert_record ( 'context' , $context );
2008-11-19 14:43:38 +00:00
} catch ( dml_exception $e ) {
2009-06-13 18:16:08 +00:00
// can not create context yet, sorry
2010-03-31 07:41:31 +00:00
return NULL ;
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 ;
2008-05-24 18:35:48 +00:00
$DB -> update_record ( 'context' , $context );
2007-10-05 15:06:38 +00:00
}
if ( ! defined ( 'SYSCONTEXTID' )) {
define ( 'SYSCONTEXTID' , $context -> id );
}
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> systemcontext = $context ;
return $ACCESSLIB_PRIVATE -> systemcontext ;
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
2009-05-22 02:03:55 +00:00
*
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $level
* @ param int $instanceid
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 ) {
2009-11-04 06:11:32 +00:00
global $DB , $ACCESSLIB_PRIVATE , $CFG ;
2007-10-09 16:07:15 +00:00
// 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
2008-05-24 18:35:48 +00:00
if ( $context = $DB -> get_record ( 'context' , array ( 'contextlevel' => $contextlevel , 'instanceid' => $instanceid ))) {
2008-05-27 13:26:00 +00:00
$result = $DB -> delete_records ( 'role_assignments' , array ( 'contextid' => $context -> id )) &&
$DB -> delete_records ( 'role_capabilities' , array ( 'contextid' => $context -> id )) &&
2009-09-04 00:36:43 +00:00
$DB -> delete_records ( 'context' , array ( 'id' => $context -> id )) &&
2009-10-01 14:41:20 +00:00
$DB -> delete_records ( 'role_names' , array ( 'contextid' => $context -> id ));
2007-10-09 16:07:15 +00:00
// 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
2009-03-23 03:54:50 +00:00
unset ( $ACCESSLIB_PRIVATE -> contexts [ $contextlevel ][ $instanceid ]);
unset ( $ACCESSLIB_PRIVATE -> contextsbyid [ $context -> id ]);
2007-10-09 16:07:15 +00:00
2009-05-06 09:24:45 +00:00
blocks_delete_all_for_context ( $context -> id );
2009-04-17 02:49:07 +00:00
filter_delete_all_for_context ( $context -> id );
2007-10-09 16:07:15 +00:00
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
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $contextlevel empty means all
2007-10-05 20:16:51 +00:00
* @ param bool $buildpaths update paths and depths
* @ return void
*/
2010-03-31 07:41:31 +00:00
function create_contexts ( $contextlevel = NULL , $buildpaths = true ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2007-10-05 20:16:51 +00:00
//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 ) {
2008-05-24 18:35:48 +00:00
$sql = " INSERT INTO { context} (contextlevel, instanceid)
2007-10-05 20:16:51 +00:00
SELECT " .CONTEXT_COURSECAT. " , cc . id
2008-05-24 18:35:48 +00:00
FROM { course } _categories cc
2007-10-05 20:16:51 +00:00
WHERE NOT EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { context } cx
2007-10-05 20:16:51 +00:00
WHERE cc . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_COURSECAT. " ) " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
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 ) {
2008-05-24 18:35:48 +00:00
$sql = " INSERT INTO { context} (contextlevel, instanceid)
2007-10-05 20:16:51 +00:00
SELECT " .CONTEXT_COURSE. " , c . id
2008-05-24 18:35:48 +00:00
FROM { course } c
2007-10-05 20:16:51 +00:00
WHERE NOT EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { context } cx
2007-10-05 20:16:51 +00:00
WHERE c . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_COURSE. " ) " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-10-05 20:16:51 +00:00
}
2009-07-13 08:37:34 +00:00
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_MODULE
or $contextlevel == CONTEXT_BLOCK ) {
2008-05-24 18:35:48 +00:00
$sql = " INSERT INTO { context} (contextlevel, instanceid)
2007-10-05 20:16:51 +00:00
SELECT " .CONTEXT_MODULE. " , cm . id
2008-05-24 18:35:48 +00:00
FROM { course } _modules cm
2007-10-05 20:16:51 +00:00
WHERE NOT EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { context } cx
2007-10-05 20:16:51 +00:00
WHERE cm . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_MODULE. " ) " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-10-05 20:16:51 +00:00
}
2009-07-13 08:37:34 +00:00
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_USER
or $contextlevel == CONTEXT_BLOCK ) {
2008-05-24 18:35:48 +00:00
$sql = " INSERT INTO { context} (contextlevel, instanceid)
2007-10-05 20:16:51 +00:00
SELECT " .CONTEXT_USER. " , u . id
2008-05-24 18:35:48 +00:00
FROM { user } u
2007-10-05 20:16:51 +00:00
WHERE u . deleted = 0
AND NOT EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { context } cx
2007-10-05 20:16:51 +00:00
WHERE u . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_USER. " ) " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-10-05 20:16:51 +00:00
}
2009-07-13 08:37:34 +00:00
if ( empty ( $contextlevel ) or $contextlevel == CONTEXT_BLOCK ) {
$sql = " INSERT INTO { context} (contextlevel, instanceid)
SELECT " .CONTEXT_BLOCK. " , bi . id
FROM { block_instances } bi
WHERE NOT EXISTS ( SELECT 'x'
FROM { context } cx
WHERE bi . id = cx . instanceid AND cx . contextlevel = " .CONTEXT_BLOCK. " ) " ;
$DB -> execute ( $sql );
}
2007-10-05 20:16:51 +00:00
if ( $buildpaths ) {
2008-05-24 18:35:48 +00:00
build_context_path ( false );
2007-10-05 20:16:51 +00:00
}
}
2007-09-19 06:50:53 +00:00
/**
* Remove stale context records
*
2009-05-22 02:03:55 +00:00
* @ global object
2007-09-19 06:50:53 +00:00
* @ return bool
*/
function cleanup_contexts () {
2008-05-24 18:35:48 +00:00
global $DB ;
2007-09-19 06:50:53 +00:00
2007-12-10 21:35:58 +00:00
$sql = " SELECT c.contextlevel,
2007-09-19 06:50:53 +00:00
c . instanceid AS instanceid
2008-05-24 18:35:48 +00:00
FROM { context } c
LEFT OUTER JOIN { course } _categories t
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " .CONTEXT_COURSECAT. "
2007-09-19 06:50:53 +00:00
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2008-05-24 18:35:48 +00:00
FROM { context } c
LEFT OUTER JOIN { course } t
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " .CONTEXT_COURSE. "
2007-09-19 06:50:53 +00:00
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2008-05-24 18:35:48 +00:00
FROM { context } c
LEFT OUTER JOIN { course } _modules t
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " .CONTEXT_MODULE. "
2007-09-19 06:50:53 +00:00
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2008-05-24 18:35:48 +00:00
FROM { context } c
LEFT OUTER JOIN { user } t
ON c . instanceid = t . id
WHERE t . id IS NULL AND c . contextlevel = " .CONTEXT_USER. "
2007-09-19 06:50:53 +00:00
UNION
2007-12-10 21:35:58 +00:00
SELECT c . contextlevel ,
c . instanceid
2008-05-24 18:35:48 +00:00
FROM { context } c
2009-05-07 08:55:10 +00:00
LEFT OUTER JOIN { block_instances } t
ON c . instanceid = t . id
2008-05-24 18:35:48 +00:00
WHERE t . id IS NULL AND c . contextlevel = " .CONTEXT_BLOCK. "
2007-09-19 06:50:53 +00:00
" ;
2009-11-07 08:52:56 +00:00
// transactions used only for performance reasons here
$transaction = $DB -> start_delegated_transaction ();
2008-05-24 18:35:48 +00:00
if ( $rs = $DB -> get_recordset_sql ( $sql )) {
foreach ( $rs as $ctx ) {
2009-11-07 08:52:56 +00:00
delete_context ( $ctx -> contextlevel , $ctx -> instanceid );
2007-09-19 06:50:53 +00:00
}
2008-05-24 18:35:48 +00:00
$rs -> close ();
2007-09-19 06:50:53 +00:00
}
2009-11-07 08:52:56 +00:00
$transaction -> allow_commit ();
2007-09-19 06:50:53 +00:00
return true ;
}
2008-12-18 17:52:29 +00:00
/**
2009-07-13 08:37:34 +00:00
* Preloads all contexts relating to a course : course , modules . Block contexts
* are no longer loaded here . The contexts for all the blocks on the current
* page are now efficiently loaded by { @ link block_manager :: load_blocks ()} .
2008-12-18 17:52:29 +00:00
*
* @ param int $courseid Course ID
2008-12-30 16:29:38 +00:00
* @ return void
2008-12-18 17:52:29 +00:00
*/
function preload_course_contexts ( $courseid ) {
2009-03-23 03:54:50 +00:00
global $DB , $ACCESSLIB_PRIVATE ;
2008-12-18 17:52:29 +00:00
// Users can call this multiple times without doing any harm
2009-03-23 03:54:50 +00:00
global $ACCESSLIB_PRIVATE ;
if ( array_key_exists ( $courseid , $ACCESSLIB_PRIVATE -> preloadedcourses )) {
2008-12-18 17:52:29 +00:00
return ;
}
2008-12-30 16:29:38 +00:00
$params = array ( $courseid , $courseid , $courseid );
$sql = " SELECT x.instanceid, x.id, x.contextlevel, x.path, x.depth
FROM { course_modules } cm
JOIN { context } x ON x . instanceid = cm . id
WHERE cm . course = ? AND x . contextlevel = " .CONTEXT_MODULE. "
UNION ALL
SELECT x . instanceid , x . id , x . contextlevel , x . path , x . depth
FROM { context } x
WHERE x . instanceid = ? AND x . contextlevel = " .CONTEXT_COURSE. " " ;
$rs = $DB -> get_recordset_sql ( $sql , $params );
2008-12-18 17:52:29 +00:00
foreach ( $rs as $context ) {
2009-03-23 03:54:50 +00:00
cache_context ( $context );
2008-12-18 17:52:29 +00:00
}
$rs -> close ();
2009-03-23 03:54:50 +00:00
$ACCESSLIB_PRIVATE -> preloadedcourses [ $courseid ] = true ;
2008-12-18 17:52:29 +00:00
}
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 .
2009-05-19 07:50:54 +00:00
*
* @ todo Remove code branch from previous fix MDL - 9016 which is no longer needed
*
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 ,
2009-05-19 07:50:54 +00:00
* for $level = CONTEXT_MODULE , this would be $cm -> id . And so on . Defaults to 0
2010-03-31 07:41:31 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* MUST_EXIST means throw exception if no record or multiple records found
2007-06-12 11:11:42 +00:00
* @ return object The context object .
2006-08-08 05:13:06 +00:00
*/
2010-03-31 07:41:31 +00:00
function get_context_instance ( $contextlevel , $instance = 0 , $strictness = IGNORE_MISSING ) {
2006-08-13 13:28:01 +00:00
2009-03-23 03:54:50 +00:00
global $DB , $ACCESSLIB_PRIVATE ;
2009-05-04 20:23:20 +00:00
static $allowed_contexts = array ( CONTEXT_SYSTEM , CONTEXT_USER , CONTEXT_COURSECAT , CONTEXT_COURSE , 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
2008-05-24 18:35:48 +00:00
// 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
2007-09-19 07:23:41 +00:00
// 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
2008-05-15 03:07:21 +00:00
print_error ( 'invalidcourselevel' );
2006-09-27 17:58:17 +00:00
}
2008-02-13 17:03:25 +00:00
if ( ! is_array ( $instance )) {
/// Check the cache
2009-03-23 03:54:50 +00:00
if ( isset ( $ACCESSLIB_PRIVATE -> contexts [ $contextlevel ][ $instance ])) { // Already cached
return $ACCESSLIB_PRIVATE -> contexts [ $contextlevel ][ $instance ];
2008-02-13 17:03:25 +00:00
}
/// Get it from the database, or create it
2008-05-24 18:35:48 +00:00
if ( ! $context = $DB -> get_record ( 'context' , array ( 'contextlevel' => $contextlevel , 'instanceid' => $instance ))) {
2010-03-31 07:41:31 +00:00
$context = create_context ( $contextlevel , $instance , $strictness );
2008-02-13 17:03:25 +00:00
}
/// Only add to cache if context isn't empty.
if ( ! empty ( $context )) {
2009-03-23 03:54:50 +00:00
cache_context ( $context );
2008-02-13 17:03:25 +00:00
}
return $context ;
2006-08-13 13:28:01 +00:00
}
2008-02-13 17:03:25 +00:00
/// ok, somebody wants to load several contexts to save some db queries ;-)
$instances = $instance ;
$result = array ();
foreach ( $instances as $key => $instance ) {
/// Check the cache first
2009-03-23 03:54:50 +00:00
if ( isset ( $ACCESSLIB_PRIVATE -> contexts [ $contextlevel ][ $instance ])) { // Already cached
$result [ $instance ] = $ACCESSLIB_PRIVATE -> contexts [ $contextlevel ][ $instance ];
2008-02-13 17:03:25 +00:00
unset ( $instances [ $key ]);
continue ;
}
2006-08-13 13:28:01 +00:00
}
2008-02-13 17:03:25 +00:00
if ( $instances ) {
2008-05-24 18:35:48 +00:00
list ( $instanceids , $params ) = $DB -> get_in_or_equal ( $instances , SQL_PARAMS_QM );
array_unshift ( $params , $contextlevel );
$sql = " SELECT instanceid, id, contextlevel, path, depth
FROM { context }
WHERE contextlevel = ? AND instanceid $instanceids " ;
if ( ! $contexts = $DB -> get_records_sql ( $sql , $params )) {
2008-02-13 17:03:25 +00:00
$contexts = array ();
}
foreach ( $instances as $instance ) {
if ( isset ( $contexts [ $instance ])) {
$context = $contexts [ $instance ];
} else {
$context = create_context ( $contextlevel , $instance );
}
if ( ! empty ( $context )) {
2009-03-23 03:54:50 +00:00
cache_context ( $context );
2008-02-13 17:03:25 +00:00
}
$result [ $instance ] = $context ;
}
2006-09-08 19:28:03 +00:00
}
2006-08-14 05:55:40 +00:00
2008-02-13 17:03:25 +00:00
return $result ;
2006-08-08 05:13:06 +00:00
}
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 .
2009-05-22 02:03:55 +00:00
*
2008-02-13 17:03:25 +00:00
* @ param mixed $id a context id or array of ids .
2010-03-07 09:28:54 +00:00
* @ param int $strictness IGNORE_MISSING means compatible mode , false returned if record not found , debug message if more found ;
* MUST_EXIST means throw exception if no record or multiple records found
2009-05-19 07:50:54 +00:00
* @ return mixed object , array of the context object , or false .
2006-08-13 15:48:57 +00:00
*/
2010-03-07 09:28:54 +00:00
function get_context_instance_by_id ( $id , $strictness = IGNORE_MISSING ) {
2009-03-23 03:54:50 +00:00
global $DB , $ACCESSLIB_PRIVATE ;
2006-08-23 01:29:52 +00:00
2007-10-05 15:06:38 +00:00
if ( $id == SYSCONTEXTID ) {
return get_system_context ();
}
2009-03-23 03:54:50 +00:00
if ( isset ( $ACCESSLIB_PRIVATE -> contextsbyid [ $id ])) { // Already cached
return $ACCESSLIB_PRIVATE -> contextsbyid [ $id ];
2006-08-13 15:48:57 +00:00
}
2010-03-07 09:28:54 +00:00
if ( $context = $DB -> get_record ( 'context' , array ( 'id' => $id ), '*' , $strictness )) {
2009-03-23 03:54:50 +00:00
cache_context ( $context );
2006-08-13 15:48:57 +00:00
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
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid
* @ param int $contextid
* @ param string $capability
2006-08-13 09:25:45 +00:00
*/
function get_local_override ( $roleid , $contextid , $capability ) {
2008-05-24 18:35:48 +00:00
global $DB ;
return $DB -> get_record ( 'role_capabilities' , array ( 'roleid' => $roleid , 'capability' => $capability , 'contextid' => $contextid ));
2006-08-13 09:25:45 +00:00
}
2010-03-07 09:28:54 +00:00
/**
* Returns context instance plus related course and cm instances
* @ param int $contextid
* @ return array of ( $context , $course , $cm )
*/
function get_context_info_array ( $contextid ) {
global $DB ;
$context = get_context_instance_by_id ( $contextid , MUST_EXIST );
2010-03-31 07:41:31 +00:00
$course = NULL ;
$cm = NULL ;
2010-03-07 09:28:54 +00:00
if ( $context -> contextlevel == CONTEXT_COURSE ) {
$course = $DB -> get_record ( 'course' , array ( 'id' => $context -> instanceid ), '*' , MUST_EXIST );
} else if ( $context -> contextlevel == CONTEXT_MODULE ) {
$cm = get_coursemodule_from_id ( '' , $context -> instanceid , 0 , false , MUST_EXIST );
$course = $DB -> get_record ( 'course' , array ( 'id' => $cm -> course ), '*' , MUST_EXIST );
} else if ( $context -> contextlevel == CONTEXT_BLOCK ) {
$parentcontexts = get_parent_contexts ( $context , false );
$parent = reset ( $parentcontexts );
$parent = get_context_instance_by_id ( $parent );
if ( $parent -> contextlevel == CONTEXT_COURSE ) {
$course = $DB -> get_record ( 'course' , array ( 'id' => $parent -> instanceid ), '*' , MUST_EXIST );
} else if ( $parent -> contextlevel == CONTEXT_MODULE ) {
$cm = get_coursemodule_from_id ( '' , $parent -> instanceid , 0 , false , MUST_EXIST );
$course = $DB -> get_record ( 'course' , array ( 'id' => $cm -> course ), '*' , MUST_EXIST );
}
}
return array ( $context , $course , $cm );
}
2006-08-13 09:25:45 +00:00
2006-08-08 05:13:06 +00:00
2009-05-19 07:50:54 +00:00
//////////////////////////////////////
// DB TABLE RELATED FUNCTIONS //
//////////////////////////////////////
2006-08-08 05:13:06 +00:00
2006-08-14 07:15:03 +00:00
/**
2006-08-08 05:13:06 +00:00
* function that creates a role
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param string $name role name
* @ param string $shortname role short name
* @ param string $description role description
2010-03-31 07:41:31 +00:00
* @ param string $archetype
2009-05-19 07:50:54 +00:00
* @ return mixed id or dml_exception
2006-08-08 05:13:06 +00:00
*/
2010-03-31 07:41:31 +00:00
function create_role ( $name , $shortname , $description , $archetype = '' ) {
2008-05-15 21:40:00 +00:00
global $DB ;
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( strpos ( $archetype , 'moodle/legacy:' ) !== false ) {
throw new coding_exception ( 'Use new role archetype parameter in create_role() instead of old legacy capabilities.' );
}
// verify role archetype actually exists
$archetypes = get_role_archetypes ();
if ( empty ( $archetypes [ $archetype ])) {
$archetype = '' ;
}
2008-11-18 07:10:00 +00:00
// Get the system context.
2009-01-17 23:24:31 +00:00
$context = get_context_instance ( CONTEXT_SYSTEM );
2006-09-18 17:40:22 +00:00
2008-11-18 07:10:00 +00:00
// Insert the role record.
2006-09-21 22:34:45 +00:00
$role = new object ();
2009-01-17 23:16:20 +00:00
$role -> name = $name ;
$role -> shortname = $shortname ;
2006-08-09 13:14:15 +00:00
$role -> description = $description ;
2010-03-31 07:41:31 +00:00
$role -> archetype = $archetype ;
2006-09-20 21:00:45 +00:00
2006-09-23 10:43:24 +00:00
//find free sortorder number
2008-11-18 07:10:00 +00:00
$role -> sortorder = $DB -> get_field ( 'role' , 'MAX(sortorder) + 1' , array ());
2008-11-18 09:28:05 +00:00
if ( empty ( $role -> sortorder )) {
$role -> sortorder = 1 ;
}
2008-11-18 07:10:00 +00:00
$id = $DB -> insert_record ( 'role' , $role );
2006-09-21 22:34:45 +00:00
2008-11-18 07:10:00 +00:00
return $id ;
2006-08-08 05:13:06 +00:00
}
2006-09-23 10:43:24 +00:00
/**
2009-05-19 07:50:54 +00:00
* Function that deletes a role and cleanups up after it
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ param int $roleid id of role to delete
2010-03-31 07:41:31 +00:00
* @ return bool lways true
2006-09-23 10:43:24 +00:00
*/
function delete_role ( $roleid ) {
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2007-09-13 13:44:35 +00:00
2010-03-31 07:41:31 +00:00
// first unssign all users
role_unassign ( $roleid );
2007-09-13 13:44:35 +00:00
2010-03-31 07:41:31 +00:00
// cleanup all references to this role, ignore errors
$DB -> delete_records ( 'role_capabilities' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_allow_assign' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_allow_assign' , array ( 'allowassign' => $roleid ));
$DB -> delete_records ( 'role_allow_override' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_allow_override' , array ( 'allowoverride' => $roleid ));
$DB -> delete_records ( 'role_names' , array ( 'roleid' => $roleid ));
$DB -> delete_records ( 'role_context_levels' , array ( 'roleid' => $roleid ));
2007-07-19 05:19:05 +00:00
2010-03-31 07:41:31 +00:00
// finally delete the role itself
2007-10-18 05:53:14 +00:00
// get this before the name is gone for logging
2008-05-15 21:40:00 +00:00
$rolename = $DB -> get_field ( 'role' , 'name' , array ( 'id' => $roleid ));
2008-05-24 18:35:48 +00:00
2010-03-31 07:41:31 +00:00
$DB -> delete_records ( 'role' , array ( 'id' => $roleid ));
2008-05-24 18:35:48 +00:00
2010-03-31 07:41:31 +00:00
add_to_log ( SITEID , 'role' , 'delete' , 'admin/roles/action=delete&roleid=' . $roleid , $rolename , '' );
2006-09-23 10:43:24 +00:00
2010-03-31 07:41:31 +00:00
return true ;
2006-09-23 10:43:24 +00:00
}
2006-08-08 05:13:06 +00:00
/**
* Function to write context specific overrides , or default capabilities .
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param string module string name
* @ param string capability string name
* @ param int contextid context id
* @ param int roleid role id
* @ param int permission int 1 , - 1 or - 1000 should not be writing if permission is 0
* @ return bool
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 ) {
2008-05-15 21:40:00 +00:00
global $USER , $DB ;
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
2008-05-15 21:40:00 +00:00
$existing = $DB -> get_record ( 'role_capabilities' , array ( '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 ;
2010-03-31 07:41:31 +00:00
$DB -> update_record ( 'role_capabilities' , $cap );
2006-09-12 06:15:33 +00:00
} else {
2008-05-15 21:40:00 +00:00
$c = $DB -> get_record ( 'context' , array ( 'id' => $contextid ));
2010-03-31 07:41:31 +00:00
$DB -> insert_record ( 'role_capabilities' , $cap );
2006-09-12 06:15:33 +00:00
}
2010-03-31 07:41:31 +00:00
return true ;
2006-08-08 05:13:06 +00:00
}
/**
* Unassign a capability from a role .
2009-11-01 11:31:16 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid the role id
* @ param string $capability the name of the capability
* @ return boolean success or failure
2006-08-08 05:13:06 +00:00
*/
function unassign_capability ( $capability , $roleid , $contextid = NULL ) {
2008-05-15 21:40:00 +00:00
global $DB ;
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( ! empty ( $contextid )) {
2007-08-02 08:28:29 +00:00
// delete from context rel, if this is the last override in this context
2010-03-31 07:41:31 +00:00
$DB -> delete_records ( 'role_capabilities' , array ( 'capability' => $capability , 'roleid' => $roleid , 'contextid' => $contextid ));
2006-08-09 13:14:15 +00:00
} else {
2010-03-31 07:41:31 +00:00
$DB -> delete_records ( 'role_capabilities' , array ( 'capability' => $capability , 'roleid' => $roleid ));
2006-08-09 13:14:15 +00:00
}
2010-03-31 07:41:31 +00:00
return true ;
2006-08-08 05:13:06 +00:00
}
/**
2009-05-19 07:50:54 +00:00
* Get the roles that have a given capability assigned to it
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 .
2009-05-22 02:03:55 +00:00
*
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param string $capability - capability name ( string )
2010-03-31 07:41:31 +00:00
* @ param string $permission - optional , the permission defined for this capability
2009-05-19 07:50:54 +00:00
* either CAP_ALLOW , CAP_PREVENT or CAP_PROHIBIT . Defaults to NULL
* @ param object $contect
* @ return mixed array or role objects
2006-08-08 05:13:06 +00:00
*/
2010-03-31 07:41:31 +00:00
function get_roles_with_capability ( $capability , $permission = NULL , $context = NULL ) {
2008-05-15 21:40:00 +00:00
global $CFG , $DB ;
2006-09-20 21:00:45 +00:00
2008-05-15 21:40:00 +00:00
$params = array ();
2008-05-24 18:35:48 +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
}
2008-05-15 21:40:00 +00:00
$contextstr = " AND (rc.contextid = ? OR rc.contextid IN $listofcontexts ) " ;
$params [] = $context -> id ;
2006-09-07 08:57:56 +00:00
} else {
$contextstr = '' ;
}
2006-09-20 21:00:45 +00:00
$selectroles = " SELECT r.*
2008-05-24 18:35:48 +00:00
FROM { role } r ,
{ role_capabilities } rc
2008-05-15 21:40:00 +00:00
WHERE rc . capability = ?
2008-05-24 18:35:48 +00:00
AND rc . roleid = r . id $contextstr " ;
2006-08-08 05:13:06 +00:00
2008-05-15 21:40:00 +00:00
array_unshift ( $params , $capability );
2006-08-08 05:13:06 +00:00
if ( isset ( $permission )) {
2008-05-15 21:40:00 +00:00
$selectroles .= " AND rc.permission = ? " ;
$params [] = $permission ;
2006-08-08 05:13:06 +00:00
}
2008-05-15 21:40:00 +00:00
return $DB -> get_records_sql ( $selectroles , $params );
2006-08-08 05:13:06 +00:00
}
/**
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 )
2009-11-01 11:31:16 +00:00
*
2009-05-19 07:50:54 +00:00
* @ param int $roleid the role of the id
* @ param int $userid userid
2010-04-07 07:07:37 +00:00
* @ param int $groupid_ignored - never implemented !
2009-05-19 07:50:54 +00:00
* @ param int $contextid id of the context
* @ param int $timestart time this assignment becomes effective defaults to 0
* @ param int $timeend time this assignemnt ceases to be effective defaults to 0
2010-03-31 07:41:31 +00:00
* @ param int $hidden_ignored - use roels with moodle / course : view capability or enrolemnt instead
2009-05-19 07:50:54 +00:00
* @ param string $enrol defaults to 'manual'
* @ param string $timemodified defaults to ''
* @ return int new id of the assigment
2006-08-08 05:13:06 +00:00
*/
2010-04-07 07:07:37 +00:00
function role_assign ( $roleid , $userid , $groupid_ignored , $contextid , $timestart = 0 , $timeend = 0 , $hidden_ignored = 0 , $enrol = 'manual' , $timemodified = '' ) {
2008-05-15 21:40:00 +00:00
global $USER , $CFG , $DB ;
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
}
2010-04-07 07:07:37 +00:00
if ( empty ( $userid )) {
debugging ( '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
2008-06-05 18:01:22 +00:00
if ( $userid && ! $DB -> record_exists ( 'user' , array ( '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
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
2010-04-07 07:07:37 +00:00
$ra = $DB -> get_record ( 'role_assignments' , array ( 'roleid' => $roleid , 'contextid' => $context -> id , 'userid' => $userid ));
2006-08-31 07:40:48 +00:00
if ( empty ( $ra )) { // Create a new entry
2008-07-06 19:30:12 +00:00
$ra = new object ();
$ra -> roleid = $roleid ;
$ra -> contextid = $context -> id ;
$ra -> userid = $userid ;
$ra -> 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
2008-07-06 19:30:12 +00:00
$ra -> timestart = round ( $timestart , - 2 );
$ra -> timeend = $timeend ;
$ra -> timemodified = $timemodified ;
$ra -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2006-08-31 07:40:48 +00:00
2009-06-13 18:16:08 +00:00
$ra -> id = $DB -> insert_record ( 'role_assignments' , $ra );
2006-08-31 07:40:48 +00:00
} else { // We already have one, just update it
2008-07-06 19:30:12 +00:00
$ra -> id = $ra -> id ;
$ra -> 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
2008-07-06 19:30:12 +00:00
$ra -> timestart = round ( $timestart , - 2 );
$ra -> timeend = $timeend ;
$ra -> timemodified = $timemodified ;
$ra -> modifierid = empty ( $USER -> id ) ? 0 : $USER -> id ;
2006-08-31 07:40:48 +00:00
2009-06-13 17:17:10 +00:00
$DB -> update_record ( 'role_assignments' , $ra );
2006-09-01 06:30:01 +00:00
}
2008-07-06 19:30:12 +00:00
/// mark context as dirty - modules might use has_capability() in xxx_role_assing()
/// again expensive, but needed
mark_context_dirty ( $context -> path );
2007-10-09 12:49:54 +00:00
2008-07-06 19:30:12 +00:00
if ( ! empty ( $USER -> id ) && $USER -> id == $userid ) {
/// If the user is the current user, then do full reload of capabilities too.
load_all_capabilities ();
}
2007-09-13 13:44:35 +00:00
2008-07-06 19:30:12 +00:00
/// Ask all the modules if anything needs to be done for this user
2009-06-19 14:25:56 +00:00
$mods = get_plugin_list ( 'mod' );
foreach ( $mods as $mod => $moddir ) {
include_once ( $moddir . '/lib.php' );
$functionname = $mod . '_role_assign' ;
if ( function_exists ( $functionname )) {
$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
2008-07-06 19:30:12 +00:00
if ( $context -> contextlevel == CONTEXT_COURSE ) {
2008-05-15 21:40:00 +00:00
if ( $parents = $DB -> get_records ( 'course_meta' , array ( 'child_course' => $context -> instanceid ))) {
2006-09-17 08:42:42 +00:00
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
2008-07-06 19:30:12 +00:00
events_trigger ( 'role_assigned' , $ra );
2008-10-09 13:52:39 +00:00
return $ra -> id ;
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 .
2009-05-22 02:03:55 +00:00
*
* @ global object
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid defaults to 0
* @ param int $userid defaults to 0
2010-04-07 07:07:37 +00:00
* @ param int $groupid_ignored never implemented
2009-05-19 07:50:54 +00:00
* @ param int $contextid defaults to 0
* @ param mixed $enrol unassign only if enrolment type matches , NULL means anything . Defaults to NULL
* @ return boolean success or failure
2006-08-08 05:13:06 +00:00
*/
2010-04-07 07:07:37 +00:00
function role_unassign ( $roleid = 0 , $userid = 0 , $groupid_ignored = 0 , $contextid = 0 , $enrol = NULL ) {
2006-09-13 06:35:25 +00:00
2008-05-24 18:35:48 +00:00
global $USER , $CFG , $DB ;
2008-08-18 06:20:50 +00:00
require_once ( $CFG -> dirroot . '/group/lib.php' );
2006-09-20 21:00:45 +00:00
2010-05-02 22:24:35 +00:00
$args = array ( 'roleid' , 'userid' , 'contextid' );
2006-09-01 06:10:45 +00:00
$select = array ();
2008-05-24 18:35:48 +00:00
$params = array ();
2006-09-01 06:10:45 +00:00
foreach ( $args as $arg ) {
if ( $$arg ) {
2008-05-24 18:35:48 +00:00
$select [] = " $arg = ? " ;
$params [] = $$arg ;
2006-09-01 06:10:45 +00:00
}
}
2007-03-22 12:27:52 +00:00
if ( ! empty ( $enrol )) {
2008-05-24 18:35:48 +00:00
$select [] = " enrol=? " ;
$params [] = $enrol ;
2007-03-22 12:27:52 +00:00
}
2006-09-13 06:35:25 +00:00
2006-09-01 06:10:45 +00:00
if ( $select ) {
2008-05-24 18:35:48 +00:00
if ( $ras = $DB -> get_records_select ( 'role_assignments' , implode ( ' AND ' , $select ), $params )) {
2009-06-19 14:25:56 +00:00
$mods = get_plugin_list ( 'mod' );
2006-09-17 08:42:42 +00:00
foreach ( $ras as $ra ) {
2006-09-17 08:53:57 +00:00
/// infinite loop protection when deleting recursively
2008-05-24 18:35:48 +00:00
if ( ! $ra = $DB -> get_record ( 'role_assignments' , array ( 'id' => $ra -> id ))) {
2006-09-17 08:53:57 +00:00
continue ;
}
2010-03-31 07:41:31 +00:00
$DB -> delete_records ( 'role_assignments' , array ( 'id' => $ra -> id ));
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
2009-06-19 14:25:56 +00:00
foreach ( $mods as $mod => $moddir ) {
include_once ( $moddir . '/lib.php' );
2006-09-17 08:42:42 +00:00
$functionname = $mod . '_role_unassign' ;
if ( function_exists ( $functionname )) {
$functionname ( $ra -> userid , $context ); // watch out, $context might be NULL if something goes wrong
}
}
2010-03-31 07:41:31 +00:00
/// now handle metacourse role unassigment and removing from goups if in course context
if ( $context -> contextlevel == CONTEXT_COURSE ) {
// cleanup leftover course groups/subscriptions etc when user has
// no capability to view course
// this may be slow, but this is the proper way of doing it
if ( ! has_capability ( 'moodle/course:participate' , $context , $ra -> userid )) {
// remove from groups
groups_delete_group_members ( $context -> instanceid , $ra -> userid );
// delete lastaccess records
$DB -> delete_records ( 'user_lastaccess' , array ( 'userid' => $ra -> userid , 'courseid' => $context -> instanceid ));
}
//unassign roles in metacourses if needed
if ( $parents = $DB -> get_records ( 'course_meta' , array ( 'child_course' => $context -> instanceid ))) {
foreach ( $parents as $parent ) {
sync_metacourse ( $parent -> parent_course );
}
}
}
events_trigger ( 'role_unassigned' , $ra );
}
}
}
return true ;
}
/**
* Enrol someone without using the default role in a course
*
* A convenience function to take care of the common case where you
* 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
* @ return bool
*/
function enrol_into_course ( $course , $user , $enrol ) {
$timestart = time ();
// 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 );
if ( $course -> enrolperiod ) {
$timeend = $timestart + $course -> enrolperiod ;
} else {
$timeend = 0 ;
}
if ( $role = get_default_course_role ( $course )) {
$context = get_context_instance ( CONTEXT_COURSE , $course -> id );
if ( ! role_assign ( $role -> id , $user -> id , 0 , $context -> id , $timestart , $timeend , 0 , $enrol )) {
return false ;
}
// force accessdata refresh for users visiting this context...
mark_context_dirty ( $context -> path );
email_welcome_message_to_user ( $course , $user );
add_to_log ( $course -> id , 'course' , 'enrol' ,
'view.php?id=' . $course -> id , $course -> id );
return true ;
}
return false ;
}
/**
* Determines if a user is currently logged in
*
* @ return bool
*/
function isloggedin () {
global $USER ;
return ( ! empty ( $USER -> id ));
}
/**
* Determines if a user is logged in as real guest user with username 'guest' .
*
* @ param int $user mixed user object or id , $USER if not specified
* @ return bool true if user is the real guest user , false if not logged in or other user
*/
function isguestuser ( $user = NULL ) {
global $USER , $DB , $CFG ;
// make sure we have the user id cached in config table, because we are going to use it a lot
if ( empty ( $CFG -> siteguest )) {
if ( ! $guestid = $DB -> get_field ( 'user' , 'id' , array ( 'username' => 'guest' , 'mnethostid' => $CFG -> mnet_localhost_id ))) {
// guest does not exist yet, weird
return false ;
}
set_config ( 'siteguest' , $guestid );
}
if ( $user === NULL ) {
$user = $USER ;
}
if ( $user === NULL ) {
// happens when setting the $USER
return false ;
} else if ( is_numeric ( $user )) {
return ( $CFG -> siteguest == $user );
} else if ( is_object ( $user )) {
if ( empty ( $user -> id )) {
return false ; // not logged in means is not be guest
} else {
return ( $CFG -> siteguest == $user -> id );
}
} else {
throw new coding_exception ( 'Invalid user parameter supplied for isguestuser() function!' );
}
}
/**
* Does user have a ( temporary or real ) guest access to course ?
*
* @ param object $context
* @ param object | int $user
* @ return bool
*/
function is_guest ( $context , $user = NULL ) {
// first find the course context
$coursecontext = get_course_context ( $context );
// make sure there is a real user specified
if ( $user === NULL ) {
$userid = ! empty ( $USER -> id ) ? $USER -> id : 0 ;
} else {
$userid = ! empty ( $user -> id ) ? $user -> id : $user ;
}
if ( isguestuser ( $userid )) {
// can not inspect or be enrolled
return true ;
}
if ( has_capability ( 'moodle/course:view' , $coursecontext , $user )) {
// viewing users appear out of nowhere, they are neither guests nor participants
return false ;
}
if ( has_capability ( 'moodle/course:participate' , $coursecontext , $userid , false )) {
return false ;
}
return true ;
}
/**
* Returns true if user has course : inspect capability in course ,
* this is intended for admins , managers ( aka small admins ), inspectors , etc .
*
* @ param object $context
* @ param int | object $user , if NULL $USER is used
* @ param string $withcapability extra capability name
* @ return bool
*/
function is_viewing ( $context , $user = NULL , $withcapability = '' ) {
global $USER ;
// first find the course context
$coursecontext = get_course_context ( $context );
if ( isguestuser ( $user )) {
// can not inspect
2010-04-30 15:36:26 +00:00
return false ;
2010-03-31 07:41:31 +00:00
}
if ( ! has_capability ( 'moodle/course:view' , $coursecontext , $user )) {
// admins are allowed to inspect courses
return false ;
}
if ( $withcapability and ! has_capability ( $withcapability , $context , $user )) {
// site admins always have the capability, but the enrolment above blocks
return false ;
}
return true ;
}
/**
* Returns true if user is enrolled ( is participating ) in course
* this is intended for students and teachers .
*
* @ param object $context
* @ param int | object $user , if NULL $USER is used , oherwise user object or id expected
* @ param string $withcapability extra capability name
* @ return bool
*/
function is_enrolled ( $context , $user = NULL , $withcapability = '' ) {
global $USER ;
// first find the course context
$coursecontext = get_course_context ( $context );
// make sure there is a real user specified
if ( $user === NULL ) {
$userid = ! empty ( $USER -> id ) ? $USER -> id : 0 ;
} else {
$userid = ! empty ( $user -> id ) ? $user -> id : $user ;
}
if ( empty ( $userid )) {
// not-logged-in!
return false ;
} else if ( isguestuser ( $userid )) {
// guest account can not be enrolled anywhere
return false ;
}
if ( $coursecontext -> instanceid != SITEID and ! has_capability ( 'moodle/course:participate' , $coursecontext , $userid , false )) {
// admins are not enrolled, everybody is "enrolled" in the frontpage course
return false ;
}
if ( $withcapability and ! has_capability ( $withcapability , $context , $userid )) {
return false ;
}
return true ;
}
/**
* Returns array with sql code and parameters returning all ids
* of users enrolled into course .
* @ param object $context
* @ param string $withcapability
* @ param int $groupid 0 means ignore groups , any other value limits the result by group id
* @ param string $prefix used for alias of user table , parameter names and in aliases of other used tables
* @ return array list ( $sql , $params )
*/
function get_enrolled_sql ( $context , $withcapability = '' , $groupid = 0 , $prefix = 'eu' ) {
global $DB ;
if ( $context -> contextlevel < CONTEXT_COURSE ) {
throw new coding_exception ( 'get_enrolled_sql() expects course context and bellow!' );
}
// first find the course context
if ( $context -> contextlevel == CONTEXT_COURSE ) {
$coursecontext = $context ;
} else if ( $context -> contextlevel == CONTEXT_MODULE ) {
$coursecontext = get_context_instance_by_id ( get_parent_contextid ( $context , MUST_EXIST ));
} else if ( $context -> contextlevel == CONTEXT_BLOCK ) {
$parentcontext = get_context_instance_by_id ( get_parent_contextid ( $context , MUST_EXIST ));
if ( $parentcontext -> contextlevel == CONTEXT_COURSE ) {
$coursecontext = $parentcontext ;
} else if ( $parentcontext -> contextlevel == CONTEXT_MODULE ) {
$coursecontext = get_context_instance_by_id ( get_parent_contextid ( $parentcontext , MUST_EXIST ));
} else {
throw new coding_exception ( 'Invalid context supplied to get_enrolled_sql()!' );
}
} else {
throw new coding_exception ( 'Invalid context supplied to get_enrolled_sql()!' );
}
list ( $contextids , $contextpaths ) = get_context_info_list ( $context );
list ( $coursecontextids , $coursecontextpaths ) = get_context_info_list ( $coursecontext );
// get all relevant capability info for all roles
if ( $withcapability ) {
list ( $incontexts , $params ) = $DB -> get_in_or_equal ( $contextids , SQL_PARAMS_NAMED , 'con00' );
$incaps = " IN (:participate, :withcap) " ;
$params [ 'participate' ] = 'moodle/course:participate' ;
$params [ 'withcap' ] = $withcapability ;
} else {
list ( $incontexts , $params ) = $DB -> get_in_or_equal ( $coursecontextids , SQL_PARAMS_NAMED , 'con00' );
$incaps = " = :participate " ;
$params [ 'participate' ] = 'moodle/course:participate' ;
}
$defs = array ();
$sql = " SELECT rc.id, rc.roleid, rc.permission, rc.capability, ctx.path
FROM { role_capabilities } rc
JOIN { context } ctx on rc . contextid = ctx . id
WHERE rc . contextid $incontexts AND rc . capability $incaps " ;
$rcs = $DB -> get_records_sql ( $sql , $params );
foreach ( $rcs as $rc ) {
$defs [ $rc -> capability ][ $rc -> path ][ $rc -> roleid ] = $rc -> permission ;
}
$courseaccess = array ();
if ( ! empty ( $defs [ 'moodle/course:participate' ])) {
foreach ( $coursecontextpaths as $path ) {
if ( empty ( $defs [ 'moodle/course:participate' ][ $path ])) {
continue ;
}
foreach ( $defs [ 'moodle/course:participate' ][ $path ] as $roleid => $perm ) {
if ( $perm == CAP_PROHIBIT ) {
$courseaccess [ $roleid ] = CAP_PROHIBIT ;
continue ;
}
if ( ! isset ( $courseaccess [ $roleid ])) {
$courseaccess [ $roleid ] = ( int ) $perm ;
}
}
}
}
$access = array ();
if ( ! empty ( $defs [ $withcapability ])) {
foreach ( $contextpaths as $path ) {
if ( empty ( $defs [ $withcapability ][ $path ])) {
continue ;
}
foreach ( $defs [ $withcapability ][ $path ] as $roleid => $perm ) {
if ( $perm == CAP_PROHIBIT ) {
$access [ $roleid ] = CAP_PROHIBIT ;
continue ;
}
if ( ! isset ( $access [ $roleid ])) {
$access [ $roleid ] = ( int ) $perm ;
}
}
}
}
unset ( $defs );
// make lists of roles that are needed and prohibited
$courseneeded = array (); // one of these is enough
$courseprohibited = array (); // must not have any of these
foreach ( $courseaccess as $roleid => $perm ) {
if ( $perm == CAP_PROHIBIT ) {
unset ( $courseneeded [ $roleid ]);
$courseprohibited [ $roleid ] = true ;
} else if ( $perm == CAP_ALLOW and empty ( $courseprohibited [ $roleid ])) {
$courseneeded [ $roleid ] = true ;
}
}
$needed = array (); // one of these is enough
$prohibited = array (); // must not have any of these
if ( $withcapability ) {
foreach ( $access as $roleid => $perm ) {
if ( $perm == CAP_PROHIBIT ) {
unset ( $needed [ $roleid ]);
$prohibited [ $roleid ] = true ;
} else if ( $perm == CAP_ALLOW and empty ( $prohibited [ $roleid ])) {
$needed [ $roleid ] = true ;
}
}
}
$isfrontpage = ( $coursecontext -> instanceid == SITEID );
2007-08-06 18:45:35 +00:00
2010-03-31 07:41:31 +00:00
$defaultuserroleid = isset ( $CFG -> defaultuserroleid ) ? $CFG -> defaultuserroleid : NULL ;
$defaultfrontpageroleid = isset ( $CFG -> defaultfrontpageroleid ) ? $CFG -> defaultfrontpageroleid : NULL ;
2007-08-06 18:45:35 +00:00
2010-03-31 07:41:31 +00:00
$nobody = false ;
2007-08-06 18:45:35 +00:00
2010-03-31 07:41:31 +00:00
if ( $isfrontpage ) {
// on the frontpage all users are kind of enrolled, we have to respect only the prohibits
$courseneeded = array ();
} else {
if ( empty ( $courseneeded )) {
$nobody = true ;
}
}
2008-07-06 19:30:12 +00:00
2010-03-31 07:41:31 +00:00
if ( $withcapability and ! $nobody ) {
if ( $isfrontpage ) {
if ( ! empty ( $prohibited [ $defaultuserroleid ]) or ! empty ( $prohibited [ $defaultfrontpageroleid ])) {
$nobody = true ;
} else if ( ! empty ( $neded [ $defaultuserroleid ]) or ! empty ( $neded [ $defaultfrontpageroleid ])) {
// everybody not having prohibit has the capability
$needed = array ();
} else if ( empty ( $needed )) {
$nobody = true ;
}
} else {
if ( ! empty ( $prohibited [ $defaultuserroleid ])) {
$nobody = true ;
} else if ( ! empty ( $neded [ $defaultuserroleid ])) {
// everybody not having prohibit has the capability
$needed = array ();
} else if ( empty ( $needed )) {
$nobody = true ;
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
2010-03-31 07:41:31 +00:00
if ( $nobody ) {
// nobody can match so return some SQL that does not return any results
return array ( " SELECT { $prefix } .id FROM { user} { $prefix } WHERE 1=2 " , array ());
}
2006-08-08 05:13:06 +00:00
2010-03-31 07:41:31 +00:00
$joins = array ();
$params = array ();
$wheres = array ( " { $prefix } .deleted = 0 AND { $prefix } .username <> 'guest' " );
2006-09-17 16:06:25 +00:00
2010-03-31 07:41:31 +00:00
if ( $courseneeded ) {
$ctxids = implode ( ',' , $coursecontextids );
$roleids = implode ( ',' , array_keys ( $courseneeded ));
$joins [] = " JOIN { role_assignments} { $prefix } _ra1 ON ( { $prefix } _ra1.userid = { $prefix } .id AND { $prefix } _ra1.roleid IN ( $roleids ) AND { $prefix } _ra1.contextid IN ( $ctxids )) " ;
2006-09-17 16:06:25 +00:00
}
2010-03-31 07:41:31 +00:00
if ( $courseprohibited ) {
$ctxids = implode ( ',' , $coursecontextids );
$roleids = implode ( ',' , array_keys ( $courseprohibited ));
$joins [] = " LEFT JOIN { role_assignments} { $prefix } _ra2 ON ( { $prefix } _ra2.userid = { $prefix } .id AND { $prefix } _ra2.roleid IN ( $roleids ) AND { $prefix } _ra2.contextid IN ( $ctxids )) " ;
$wheres [] = " { $prefix } _ra2 IS NULL " ;
}
2006-09-20 02:19:08 +00:00
2010-03-31 07:41:31 +00:00
if ( $needed ) {
$ctxids = implode ( ',' , $contextids );
$roleids = implode ( ',' , array_keys ( $needed ));
$joins [] = " JOIN { role_assignments} { $prefix } _ra3 ON ( { $prefix } _ra3.userid = { $prefix } .id AND { $prefix } _ra3.roleid IN ( $roleids ) AND { $prefix } _ra3.contextid IN ( $ctxids )) " ;
}
2006-09-20 02:19:08 +00:00
2010-03-31 07:41:31 +00:00
if ( $prohibited ) {
$ctxids = implode ( ',' , $contextids );
$roleids = implode ( ',' , array_keys ( $prohibited ));
$joins [] = " LEFT JOIN { role_assignments} { $prefix } _ra4 ON ( { $prefix } _ra4.userid = { $prefix } .id AND { $prefix } _ra4.roleid IN ( $roleids ) AND { $prefix } _ra4.contextid IN ( $ctxids )) " ;
$wheres [] = " { $prefix } _ra4 IS NULL " ;
}
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( $groupid ) {
$joins [] = " JOIN { groups_members} { $prefix } gm ON ( { $prefix } gm.userid = { $prefix } .id AND { $prefix } .roleid = : { $prefix } gmid) " ;
$params [ " { $prefix } gmid " ] = $groupid ;
}
2007-09-19 07:11:42 +00:00
2010-03-31 07:41:31 +00:00
$joins = implode ( " \n " , $joins );
$wheres = " WHERE " . implode ( " AND " , $wheres );
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
$sql = " SELECT DISTINCT { $prefix } .id
FROM { user } { $prefix }
$joins
$wheres " ;
2006-09-17 16:06:25 +00:00
2010-03-31 07:41:31 +00:00
return array ( $sql , $params );
}
/**
* Returns list of users enrolled into course .
* @ param object $context
* @ param string $withcapability
* @ param int $groupid 0 means ignore groups , any other value limits the result by group id
* @ param string $userfields requested user record fields
* @ param string $orderby
* @ param int $limitfrom return a subset of records , starting at this point ( optional , required if $limitnum is set ) .
* @ param int $limitnum return a subset comprising this many records ( optional , required if $limitfrom is set ) .
* @ return array of user records
*/
function get_enrolled_users ( $context , $withcapability = '' , $groupid = 0 , $userfields = 'u.*' , $orderby = '' , $limitfrom = 0 , $limitnum = 0 ) {
global $DB ;
list ( $esql , $params ) = get_enrolled_sql ( $context , $withcapability , $groupid );
$sql = " SELECT $userfields
FROM { user } u
JOIN ( $esql ) je ON je . id = u . id
WHERE u . deleted = 0 " ;
if ( $orderby ) {
$sql = " $sql ORDER BY $orderby " ;
} else {
$sql = " $sql ORDER BY u.lastname ASC, u.firstname ASC " ;
2006-09-17 16:06:25 +00:00
}
2010-03-31 07:41:31 +00:00
return $DB -> get_records_sql ( $sql , $params , $limitfrom , $limitnum );
2006-09-17 16:06:25 +00:00
}
2010-04-05 07:34:50 +00:00
/**
* Counts list of users enrolled into course ( as per above function )
* @ param object $context
* @ param string $withcapability
* @ param int $groupid 0 means ignore groups , any other value limits the result by group id
* @ return array of user records
*/
function count_enrolled_users ( $context , $withcapability = '' , $groupid = 0 ) {
global $DB ;
list ( $esql , $params ) = get_enrolled_sql ( $context , $withcapability , $groupid );
$sql = " SELECT count(u.id)
FROM { user } u
JOIN ( $esql ) je ON je . id = u . id
WHERE u . deleted = 0 " ;
return $DB -> count_records_sql ( $sql , $params );
}
2006-08-08 05:13:06 +00:00
/**
2009-05-19 07:50:54 +00:00
* Loads the capability definitions for the component ( from file ) .
*
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 .
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-06-19 14:25:56 +00:00
* @ param string $component full plugin name , examples : 'moodle' , 'mod_forum'
2009-05-19 07:50:54 +00:00
* @ return array array of capabilities
2006-08-08 05:13:06 +00:00
*/
function load_capability_def ( $component ) {
2009-06-19 14:25:56 +00:00
$defpath = get_component_directory ( $component ) . '/db/access.php' ;
2009-05-16 20:53:21 +00:00
2006-08-08 05:13:06 +00:00
$capabilities = array ();
if ( file_exists ( $defpath )) {
2006-12-12 17:23:31 +00:00
require ( $defpath );
2009-11-04 19:24:12 +00:00
if ( ! empty ( $ { $component . '_capabilities' })) {
2010-03-31 07:41:31 +00:00
// BC capability array name
2009-11-04 19:24:12 +00:00
// since 2.0 we prefer $capabilities instead - it is easier to use and matches db/* files
2010-03-31 07:41:31 +00:00
debugging ( 'componentname_capabilities array is deprecated, please use capabilities array only in access.php files' );
2009-11-04 19:24:12 +00:00
$capabilities = $ { $component . '_capabilities' };
}
2006-08-08 05:13:06 +00:00
}
2009-06-19 14:25:56 +00:00
2006-08-08 05:13:06 +00:00
return $capabilities ;
}
/**
2009-05-19 07:50:54 +00:00
* Gets the capabilities that have been cached in the database for this component .
2009-06-19 14:25:56 +00:00
* @ param string $component - examples : 'moodle' , 'mod_forum'
2009-05-19 07:50:54 +00:00
* @ return array array of capabilities
2006-08-08 05:13:06 +00:00
*/
function get_cached_capabilities ( $component = 'moodle' ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2009-06-19 14:25:56 +00:00
return $DB -> get_records ( 'capabilities' , array ( 'component' => $component ));
2006-08-08 05:13:06 +00:00
}
2007-03-03 21:07:07 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns default capabilities for given role archetype .
* @ param string $archetype role archetype
2007-03-03 21:07:07 +00:00
* @ return array
*/
2010-03-31 07:41:31 +00:00
function get_default_capabilities ( $archetype ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2010-03-31 07:41:31 +00:00
if ( ! $archetype ) {
return array ();
}
2007-03-03 21:07:07 +00:00
$alldefs = array ();
$defaults = array ();
$components = array ();
2010-03-31 07:41:31 +00:00
$allcaps = $DB -> get_records ( 'capabilities' );
2007-03-03 21:07:07 +00:00
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 ) {
2010-03-31 07:41:31 +00:00
if ( isset ( $def [ 'legacy' ][ $archetype ])) {
$defaults [ $name ] = $def [ 'legacy' ][ $archetype ];
2007-03-03 21:07:07 +00:00
}
}
return $defaults ;
}
2006-08-08 05:13:06 +00:00
2007-03-05 11:27:01 +00:00
/**
2010-03-31 07:41:31 +00:00
* Reset role capabilitites to default according to selected role archetype .
* If no archetype selected , removes all capabilities .
2007-03-05 11:27:01 +00:00
* @ param int @ roleid
*/
function reset_role_capabilities ( $roleid ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2010-03-31 07:41:31 +00:00
$role = $DB -> get_record ( 'role' , array ( 'id' => $roleid ), '*' , MUST_EXIST );
$defaultcaps = get_default_capabilities ( $role -> archetype );
2007-03-05 11:27:01 +00:00
$sitecontext = get_context_instance ( CONTEXT_SYSTEM );
2008-05-24 18:35:48 +00:00
$DB -> delete_records ( 'role_capabilities' , array ( 'roleid' => $roleid ));
2010-03-31 07:41:31 +00:00
foreach ( $defaultcaps as $cap => $permission ) {
assign_capability ( $cap , $permission , $roleid , $sitecontext -> id );
2007-03-05 11:27:01 +00:00
}
}
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
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param string $component examples : 'moodle' , 'mod/forum' , 'block/quiz_results'
2009-01-12 15:13:44 +00:00
* @ return boolean true if success , exception in case of any problems
2006-08-08 05:13:06 +00:00
*/
function update_capabilities ( $component = 'moodle' ) {
2009-08-18 05:20:12 +00:00
global $DB , $OUTPUT ;
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
}
2010-03-31 07:41:31 +00:00
if ( $cachedcap -> captype != $filecaps [ $cachedcap -> name ][ 'captype' ]) {
$updatecap = new object ();
$updatecap -> id = $cachedcap -> id ;
$updatecap -> captype = $filecaps [ $cachedcap -> name ][ 'captype' ];
$DB -> update_record ( 'capabilities' , $updatecap );
}
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' ];
2009-01-12 15:13:44 +00:00
$DB -> update_record ( 'capabilities' , $updatecap );
2007-03-14 21:42:38 +00:00
}
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' ];
2009-01-12 15:13:44 +00:00
$DB -> update_record ( 'capabilities' , $updatecap );
2006-08-31 08:36:36 +00:00
}
}
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 ) {
2010-03-31 07:41:31 +00:00
$capability = new object ();
2006-08-08 05:13:06 +00:00
$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
2009-01-12 15:13:44 +00:00
$DB -> insert_record ( 'capabilities' , $capability , false );
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 )){
2008-05-24 18:35:48 +00:00
if ( $rolecapabilities = $DB -> get_records ( 'role_capabilities' , array ( 'capability' => $capdef [ 'clonepermissionsfrom' ]))){
2007-05-27 04:53:02 +00:00
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 )){
2009-08-18 05:20:12 +00:00
echo $OUTPUT -> notification ( '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
}
2007-05-27 04:53:02 +00:00
// we ignore legacy key if we have cloned permissions
2010-03-31 07:41:31 +00:00
} else if ( isset ( $capdef [ 'legacy' ]) && is_array ( $capdef [ 'legacy' ])) {
assign_legacy_capabilities ( $capname , $capdef [ 'legacy' ]);
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
2008-12-12 10:50:25 +00:00
// reset static caches
2010-03-31 07:41:31 +00:00
$ACCESSLIB_PRIVATE -> capabilities = NULL ;
2008-12-12 10:50:25 +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 .
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param string $component examples : 'moodle' , 'mod/forum' , 'block/quiz_results'
* @ param array $newcapdef array of the new capability definitions that will be
2006-08-08 05:13:06 +00:00
* compared with the cached capabilities
2009-05-19 07:50:54 +00:00
* @ return int number of deprecated capabilities that have been removed
2006-08-08 05:13:06 +00:00
*/
function capabilities_cleanup ( $component , $newcapdef = NULL ) {
2008-05-24 18:35:48 +00:00
global $DB ;
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.
2009-06-03 20:00:08 +00:00
$DB -> delete_records ( 'capabilities' , array ( 'name' => $cachedcap -> name ));
$removedcount ++ ;
2006-08-08 05:13:06 +00:00
// Delete from roles.
2008-05-24 18:35:48 +00:00
if ( $roles = get_roles_with_capability ( $cachedcap -> name )) {
2006-08-08 05:13:06 +00:00
foreach ( $roles as $role ) {
2006-09-08 02:33:02 +00:00
if ( ! unassign_capability ( $cachedcap -> name , $role -> id )) {
2008-08-16 12:16:01 +00:00
print_error ( 'cannotunassigncap' , 'error' , '' , ( object ) array ( 'cap' => $cachedcap -> name , 'role' => $role -> name ));
2006-08-08 05:13:06 +00:00
}
}
}
} // End if.
}
}
return $removedcount ;
}
2009-05-19 07:50:54 +00:00
//////////////////
// UI FUNCTIONS //
//////////////////
2006-08-08 05:13:06 +00:00
2008-11-21 06:19:52 +00:00
/**
* @ param integer $contextlevel $context -> context level . One of the CONTEXT_ ... constants .
* @ return string the name for this type of context .
*/
function get_contextlevel_name ( $contextlevel ) {
2010-03-31 07:41:31 +00:00
static $strcontextlevels = NULL ;
2008-11-21 06:19:52 +00:00
if ( is_null ( $strcontextlevels )) {
$strcontextlevels = array (
CONTEXT_SYSTEM => get_string ( 'coresystem' ),
CONTEXT_USER => get_string ( 'user' ),
CONTEXT_COURSECAT => get_string ( 'category' ),
CONTEXT_COURSE => get_string ( 'course' ),
CONTEXT_MODULE => get_string ( 'activitymodule' ),
CONTEXT_BLOCK => get_string ( 'block' )
);
}
return $strcontextlevels [ $contextlevel ];
}
2006-08-08 05:13:06 +00:00
/**
2008-10-30 06:26:18 +00:00
* Prints human readable context identifier .
*
2009-05-22 02:03:55 +00:00
* @ global object
2008-10-30 06:26:18 +00:00
* @ param object $context the context .
* @ param boolean $withprefix whether to prefix the name of the context with the
* type of context , e . g . User , Course , Forum , etc .
* @ param boolean $short whether to user the short name of the thing . Only applies
* to course contexts
* @ return string the human readable context name .
2006-08-08 05:13:06 +00:00
*/
2007-05-22 10:09:22 +00:00
function print_context_name ( $context , $withprefix = true , $short = false ) {
2008-05-24 18:35:48 +00:00
global $DB ;
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
2009-07-13 08:37:34 +00:00
case CONTEXT_SYSTEM :
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
2006-09-15 14:09:16 +00:00
case CONTEXT_USER :
2008-05-24 18:35:48 +00:00
if ( $user = $DB -> get_record ( 'user' , array ( '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 ;
2009-07-13 08:37:34 +00:00
case CONTEXT_COURSECAT :
2008-05-24 18:35:48 +00:00
if ( $category = $DB -> get_record ( 'course_categories' , array ( '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
2009-07-13 08:37:34 +00:00
case CONTEXT_COURSE :
2008-09-05 04:06:17 +00:00
if ( $context -> instanceid == SITEID ) {
2008-11-12 10:12:33 +00:00
$name = get_string ( 'frontpage' , 'admin' );
2008-09-05 04:06:17 +00:00
} else {
if ( $course = $DB -> get_record ( 'course' , array ( 'id' => $context -> instanceid ))) {
if ( $withprefix ){
2007-05-22 10:09:22 +00:00
$name = get_string ( 'course' ) . ': ' ;
}
2008-11-24 07:27:11 +00:00
if ( $short ){
2008-09-05 04:06:17 +00:00
$name .= format_string ( $course -> shortname );
} else {
$name .= format_string ( $course -> fullname );
}
2007-03-19 04:49:49 +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
2009-07-13 08:37:34 +00:00
case CONTEXT_MODULE :
2008-10-30 06:26:18 +00:00
if ( $cm = $DB -> get_record_sql ( 'SELECT cm.*, md.name AS modname FROM {course_modules} cm ' .
'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?' , array ( $context -> instanceid ))) {
if ( $mod = $DB -> get_record ( $cm -> modname , array ( 'id' => $cm -> instance ))) {
2008-11-06 07:34:01 +00:00
if ( $withprefix ){
2008-10-30 06:26:18 +00:00
$name = get_string ( 'modulename' , $cm -> modname ) . ': ' ;
2008-11-06 07:34:01 +00:00
}
$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
2009-07-13 08:37:34 +00:00
case CONTEXT_BLOCK :
2009-05-07 08:55:10 +00:00
if ( $blockinstance = $DB -> get_record ( 'block_instances' , array ( 'id' => $context -> instanceid ))) {
global $CFG ;
require_once ( " $CFG->dirroot /blocks/moodleblock.class.php " );
require_once ( " $CFG->dirroot /blocks/ $blockinstance->blockname /block_ $blockinstance->blockname .php " );
$blockname = " block_ $blockinstance->blockname " ;
if ( $blockobject = new $blockname ()) {
if ( $withprefix ){
$name = get_string ( 'block' ) . ': ' ;
2006-09-05 06:30:12 +00:00
}
2009-05-07 08:55:10 +00:00
$name .= $blockobject -> title ;
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 :
2008-12-12 05:45:43 +00:00
print_error ( 'unknowncontext' );
2006-08-13 15:48:57 +00:00
return false ;
}
2008-10-30 06:26:18 +00:00
2006-08-13 15:48:57 +00:00
return $name ;
2006-08-08 05:13:06 +00:00
}
2008-10-30 06:26:18 +00:00
/**
2009-11-01 11:31:16 +00:00
* Get a URL for a context , if there is a natural one . For example , for
2008-10-30 06:26:18 +00:00
* CONTEXT_COURSE , this is the course page . For CONTEXT_USER it is the
* user profile page .
*
* @ param object $context the context .
2010-03-07 09:28:54 +00:00
* @ return moodle_url
2008-10-30 06:26:18 +00:00
*/
function get_context_url ( $context ) {
2010-03-07 09:28:54 +00:00
global $COURSE , $DB ;
2008-10-30 06:26:18 +00:00
switch ( $context -> contextlevel ) {
case CONTEXT_USER :
2010-05-04 13:04:35 +00:00
if ( $COURSE -> id == SITEID ) {
$url = new moodle_url ( '/user/profile.php' , array ( 'id' => $context -> instanceid ));
} else {
$url = new moodle_url ( '/user/view.php' , array ( 'id' => $context -> instanceid , 'courseid' => $COURSE -> id ));
2008-10-30 06:26:18 +00:00
}
2010-03-07 09:28:54 +00:00
return $url ;;
2008-10-30 06:26:18 +00:00
case CONTEXT_COURSECAT : // Coursecat -> coursecat or site
2010-03-07 09:28:54 +00:00
return new moodle_url ( '/course/category.php' , array ( 'id' => $context -> instanceid ));
2008-10-30 06:26:18 +00:00
case CONTEXT_COURSE : // 1 to 1 to course cat
2010-03-07 09:28:54 +00:00
if ( $context -> instanceid != SITEID ) {
return new moodle_url ( '/course/view.php' , array ( 'id' => $context -> instanceid ));
2008-10-30 06:26:18 +00:00
}
break ;
case CONTEXT_MODULE : // 1 to 1 to course
if ( $modname = $DB -> get_field_sql ( 'SELECT md.name AS modname FROM {course_modules} cm ' .
'JOIN {modules} md ON md.id = cm.module WHERE cm.id = ?' , array ( $context -> instanceid ))) {
2010-03-07 09:28:54 +00:00
return new moodle_url ( '/mod/' . $modname . '/view.php' , array ( 'id' => $context -> instanceid ));
2008-10-30 06:26:18 +00:00
}
break ;
case CONTEXT_BLOCK :
2010-03-07 09:28:54 +00:00
$parentcontexts = get_parent_contexts ( $context , false );
$parent = reset ( $parentcontexts );
$parent = get_context_instance_by_id ( $parent );
return get_context_url ( $parent );
2008-10-30 06:26:18 +00:00
}
2010-03-07 09:28:54 +00:00
return new moodle_url ( '/' );
2008-10-30 06:26:18 +00:00
}
2006-08-08 05:13:06 +00:00
2008-11-05 08:17:30 +00:00
/**
2009-05-19 07:50:54 +00:00
* Returns an array of all the known types of risk
2009-11-01 11:31:16 +00:00
* The array keys can be used , for example as CSS class names , or in calls to
2009-05-19 07:50:54 +00:00
* print_risk_icon . The values are the corresponding RISK_ constants .
2009-05-22 02:03:55 +00:00
*
2009-11-01 11:31:16 +00:00
* @ return array all the known types of risk .
2008-11-05 08:17:30 +00:00
*/
function get_all_risks () {
return array (
'riskmanagetrust' => RISK_MANAGETRUST ,
'riskconfig' => RISK_CONFIG ,
'riskxss' => RISK_XSS ,
'riskpersonal' => RISK_PERSONAL ,
'riskspam' => RISK_SPAM ,
'riskdataloss' => RISK_DATALOSS ,
);
}
/**
2009-05-19 07:50:54 +00:00
* Return a link to moodle docs for a given capability name
*
2009-05-22 02:03:55 +00:00
* @ global object
2008-11-05 08:17:30 +00:00
* @ param object $capability a capability - a row from the mdl_capabilities table .
* @ return string the human - readable capability name as a link to Moodle Docs .
*/
function get_capability_docs_link ( $capability ) {
global $CFG ;
$url = get_docs_url ( 'Capabilities/' . $capability -> name );
return '<a onclick="this.target=\'docspopup\'" href="' . $url . '">' . get_capability_string ( $capability -> name ) . '</a>' ;
}
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
*
2009-05-19 07:50:54 +00:00
* capabilities
2006-08-08 05:13:06 +00:00
* `name` varchar ( 150 ) NOT NULL ,
* `captype` varchar ( 50 ) NOT NULL ,
* `contextlevel` int ( 10 ) NOT NULL ,
* `component` varchar ( 100 ) NOT NULL ,
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object context
* @ return array
2006-08-08 05:13:06 +00:00
*/
2006-08-14 05:55:40 +00:00
function fetch_context_capabilities ( $context ) {
2008-07-24 21:59:13 +00:00
global $DB , $CFG ;
$sort = 'ORDER BY contextlevel,component,name' ; // To group them sensibly for display
2006-08-08 05:13:06 +00:00
2008-07-24 21:59:13 +00:00
$params = array ();
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
2008-07-24 21:59:13 +00:00
$SQL = " SELECT *
FROM { capabilities } " ;
2006-08-08 05:13:06 +00:00
break ;
2006-09-15 14:09:16 +00:00
case CONTEXT_USER :
2008-07-24 21:59:13 +00:00
$extracaps = array ( 'moodle/grade:viewall' );
list ( $extra , $params ) = $DB -> get_in_or_equal ( $extracaps , SQL_PARAMS_NAMED , 'cap0' );
$SQL = " SELECT *
2008-05-24 18:35:48 +00:00
FROM { capabilities }
2008-07-24 21:59:13 +00:00
WHERE contextlevel = " .CONTEXT_USER. "
OR name $extra " ;
2006-08-08 05:13:06 +00:00
break ;
2008-07-24 21:59:13 +00:00
case CONTEXT_COURSECAT : // course category context and bellow
$SQL = " SELECT *
FROM { capabilities }
WHERE contextlevel IN ( " .CONTEXT_COURSECAT. " , " .CONTEXT_COURSE. " , " .CONTEXT_MODULE. " , " .CONTEXT_BLOCK. " ) " ;
2006-08-08 05:13:06 +00:00
break ;
2008-07-24 21:59:13 +00:00
case CONTEXT_COURSE : // course context and bellow
$SQL = " SELECT *
FROM { capabilities }
WHERE contextlevel IN ( " .CONTEXT_COURSE. " , " .CONTEXT_MODULE. " , " .CONTEXT_BLOCK. " ) " ;
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_MODULE : // mod caps
2008-07-24 21:59:13 +00:00
$cm = $DB -> get_record ( 'course_modules' , array ( 'id' => $context -> instanceid ));
2008-05-24 18:35:48 +00:00
$module = $DB -> get_record ( 'modules' , array ( 'id' => $cm -> module ));
2006-09-20 21:00:45 +00:00
2008-07-24 21:59:13 +00:00
$modfile = " $CFG->dirroot /mod/ $module->name /lib.php " ;
if ( file_exists ( $modfile )) {
include_once ( $modfile );
$modfunction = $module -> name . '_get_extra_capabilities' ;
if ( function_exists ( $modfunction )) {
2009-11-01 11:31:16 +00:00
$extracaps = $modfunction ();
2008-07-24 21:59:13 +00:00
}
}
2009-04-02 16:32:12 +00:00
if ( empty ( $extracaps )) {
$extracaps = array ();
}
// All modules allow viewhiddenactivities. This is so you can hide
// the module then override to allow specific roles to see it.
// The actual check is in course page so not module-specific
$extracaps [] = " moodle/course:viewhiddenactivities " ;
list ( $extra , $params ) = $DB -> get_in_or_equal (
$extracaps , SQL_PARAMS_NAMED , 'cap0' );
$extra = " OR name $extra " ;
2008-07-24 21:59:13 +00:00
$SQL = " SELECT *
2008-05-24 18:35:48 +00:00
FROM { capabilities }
2008-08-06 05:07:46 +00:00
WHERE ( contextlevel = " .CONTEXT_MODULE. "
AND component = : component )
2008-07-24 21:59:13 +00:00
$extra " ;
2009-11-25 05:44:15 +00:00
$params [ 'component' ] = " mod_ $module->name " ;
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_BLOCK : // block caps
2009-05-08 07:47:50 +00:00
$bi = $DB -> get_record ( 'block_instances' , array ( 'id' => $context -> instanceid ));
2009-05-07 08:55:10 +00:00
$extra = '' ;
2009-05-08 07:47:50 +00:00
$extracaps = block_method_result ( $bi -> blockname , 'get_extra_capabilities' );
2009-05-07 08:55:10 +00:00
if ( $extracaps ) {
list ( $extra , $params ) = $DB -> get_in_or_equal ( $extracaps , SQL_PARAMS_NAMED , 'cap0' );
$extra = " OR name $extra " ;
2008-07-24 21:59:13 +00:00
}
$SQL = " SELECT *
2008-05-24 18:35:48 +00:00
FROM { capabilities }
2008-07-24 21:59:13 +00:00
WHERE ( contextlevel = " .CONTEXT_BLOCK. "
AND component = : component )
$extra " ;
2009-11-25 05:44:15 +00:00
$params [ 'component' ] = 'block_' . $bi -> blockname ;
2006-08-08 05:13:06 +00:00
break ;
default :
return false ;
}
2008-07-24 21:59:13 +00:00
if ( ! $records = $DB -> get_records_sql ( $SQL . ' ' . $sort , $params )) {
$records = array ();
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 08:30:49 +00:00
}
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 .
2009-05-22 02:03:55 +00:00
*
* @ global object
2006-08-15 08:29:29 +00:00
* @ param obj $context
2006-08-08 05:13:06 +00:00
* @ param int $roleid
2009-05-19 07:50:54 +00:00
* @ param string $cap capability , optional , defaults to ''
* @ param bool 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 = '' ) {
2008-05-24 18:35:48 +00:00
global $DB ;
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
2008-05-24 18:35:48 +00:00
$params = array ( $roleid );
2006-08-28 08:42:30 +00:00
if ( $cap ) {
2008-05-24 18:35:48 +00:00
$search = " AND rc.capability = ? " ;
$params [] = $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
2008-05-24 18:35:48 +00:00
$sql = " SELECT rc.*
FROM { role_capabilities } rc , { context } c
WHERE rc . contextid in $contexts
AND rc . roleid = ?
AND rc . contextid = c . id $search
ORDER BY c . contextlevel DESC , 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
2008-05-24 18:35:48 +00:00
if ( $records = $DB -> get_records_sql ( $sql , $params )) {
2006-09-05 03:07:56 +00:00
// 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
2009-05-19 07:50:54 +00:00
* @ param bool $capability optional , defaults to false
* @ return array
2006-08-08 05:13:06 +00:00
*/
2008-11-21 05:46:45 +00:00
function get_parent_contexts ( $context , $includeself = false ) {
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 );
2008-11-21 05:46:45 +00:00
if ( ! $includeself ) {
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
}
2008-05-12 15:28:34 +00:00
/**
* Return the id of the parent of this context , or false if there is no parent ( only happens if this
* is the site context . )
*
* @ param object $context
* @ return integer the id of the parent context .
*/
function get_parent_contextid ( $context ) {
$parentcontexts = get_parent_contexts ( $context );
if ( count ( $parentcontexts ) == 0 ) {
2008-05-24 18:35:48 +00:00
return false ;
2008-05-12 15:28:34 +00:00
}
return array_shift ( $parentcontexts );
}
2006-09-20 08:30:49 +00:00
2010-03-31 07:41:31 +00:00
/**
* Constructs array with contextids as first parameter and context paths ,
* in both cases bottom top including self .
*
* @ param object $context
* @ return array
*/
function get_context_info_list ( $context ) {
$contextids = explode ( '/' , ltrim ( $context -> path , '/' ));
$contextpaths = array ();
$contextids2 = $contextids ;
while ( $contextids2 ) {
$contextpaths [] = '/' . implode ( '/' , $contextids2 );
array_pop ( $contextids2 );
}
return array ( $contextids , $contextpaths );
}
/**
* Find course context
* @ param object $context - course or lower context
* @ return object context of the enclosing course , throws exception when related course context can not be found
*/
function get_course_context ( $context ) {
if ( empty ( $context -> contextlevel )) {
throw coding_exception ( 'Invalid context parameter.' );
} if ( $context -> contextlevel == CONTEXT_COURSE ) {
return $context ;
} else if ( $context -> contextlevel == CONTEXT_MODULE ) {
return get_context_instance_by_id ( get_parent_contextid ( $context , MUST_EXIST ));
} else if ( $context -> contextlevel == CONTEXT_BLOCK ) {
$parentcontext = get_context_instance_by_id ( get_parent_contextid ( $context , MUST_EXIST ));
if ( $parentcontext -> contextlevel == CONTEXT_COURSE ) {
return $parentcontext ;
} else if ( $parentcontext -> contextlevel == CONTEXT_MODULE ) {
return get_context_instance_by_id ( get_parent_contextid ( $parentcontext , MUST_EXIST ));
} else {
throw new coding_exception ( 'Invalid level of block context parameter.' );
}
}
throw new coding_exception ( 'Invalid context level of parameter.' );
}
2008-11-11 07:23:25 +00:00
/**
2009-05-19 07:50:54 +00:00
* Check if contect is the front page context or a context inside it
*
* Returns true if this context is the front page context , or a context inside it ,
* otherwise false .
2009-05-22 02:03:55 +00:00
*
2008-11-11 07:23:25 +00:00
* @ param object $context a context object .
2009-11-01 11:31:16 +00:00
* @ return bool
2008-11-11 07:23:25 +00:00
*/
function is_inside_frontpage ( $context ) {
$frontpagecontext = get_context_instance ( CONTEXT_COURSE , SITEID );
return strpos ( $context -> path . '/' , $frontpagecontext -> path . '/' ) === 0 ;
}
2008-11-25 07:29:14 +00:00
/**
2009-05-19 07:50:54 +00:00
* Runs get_records select on context table and returns the result
2008-11-25 07:29:14 +00:00
* Does get_records_select on the context table , and returns the results ordered
* by contextlevel , and then the natural sort order within each level .
* for the purpose of $select , you need to know that the context table has been
* aliased to ctx , so for example , you can call get_sorted_contexts ( 'ctx.depth = 3' );
*
2009-05-22 02:03:55 +00:00
* @ global object
2008-11-25 07:29:14 +00:00
* @ param string $select the contents of the WHERE clause . Remember to do ctx . fieldname .
* @ param array $params any parameters required by $select .
* @ return array the requested context records .
*/
function get_sorted_contexts ( $select , $params = array ()) {
global $DB ;
if ( $select ) {
$select = 'WHERE ' . $select ;
}
return $DB -> get_records_sql ( "
SELECT ctx .*
FROM { context } ctx
2009-05-07 08:55:10 +00:00
LEFT JOIN { user } u ON ctx . contextlevel = " . CONTEXT_USER . " AND u . id = ctx . instanceid
LEFT JOIN { course_categories } cat ON ctx . contextlevel = " . CONTEXT_COURSECAT . " AND cat . id = ctx . instanceid
LEFT JOIN { course } c ON ctx . contextlevel = " . CONTEXT_COURSE . " AND c . id = ctx . instanceid
LEFT JOIN { course_modules } cm ON ctx . contextlevel = " . CONTEXT_MODULE . " AND cm . id = ctx . instanceid
LEFT JOIN { block_instances } bi ON ctx . contextlevel = " . CONTEXT_BLOCK . " AND bi . id = ctx . instanceid
2008-11-25 07:29:14 +00:00
$select
2009-05-19 08:02:55 +00:00
ORDER BY ctx . contextlevel , bi . defaultregion , COALESCE ( cat . sortorder , c . sortorder , cm . section , bi . defaultweight ), u . lastname , u . firstname , cm . id
2008-11-25 07:29:14 +00:00
" , $params );
}
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
2009-07-13 08:37:34 +00:00
* NOT recurse into courses , nor return blocks on the category pages . If you
* want to do that , call it on the returned courses .
2007-09-19 06:52:34 +00:00
*
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 .
2009-05-19 07:50:54 +00:00
* @ return array Array of child records
2007-02-09 02:24:59 +00:00
*/
function get_child_contexts ( $context ) {
2009-03-23 03:54:50 +00:00
global $DB , $ACCESSLIB_PRIVATE ;
2007-09-19 06:52:34 +00:00
// 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
2009-11-25 05:44:15 +00:00
$array = array ();
2007-02-09 02:24:59 +00:00
switch ( $context -> contextlevel ) {
case CONTEXT_BLOCK :
// No children.
break ;
case CONTEXT_MODULE :
2009-07-13 08:37:34 +00:00
// Find
// - blocks under this context path.
$sql = " SELECT ctx.*
FROM { context } ctx
WHERE ctx . path LIKE ?
AND ctx . contextlevel = " .CONTEXT_BLOCK;
$params = array ( " { $context -> path } /% " , $context -> instanceid );
$records = $DB -> get_recordset_sql ( $sql , $params );
foreach ( $records as $rec ) {
cache_context ( $rec );
2009-11-25 05:44:15 +00:00
$array [ $rec -> id ] = $rec ;
2009-07-13 08:37:34 +00:00
}
break ;
2007-02-09 02:24:59 +00:00
case CONTEXT_COURSE :
2007-09-19 06:52:34 +00:00
// Find
2009-07-13 08:37:34 +00:00
// - modules and blocks under this context path.
2007-09-19 06:52:34 +00:00
$sql = " SELECT ctx.*
2008-05-24 18:35:48 +00:00
FROM { context } ctx
WHERE ctx . path LIKE ?
2009-05-04 20:23:20 +00:00
AND ctx . contextlevel IN ( " .CONTEXT_MODULE. " , " .CONTEXT_BLOCK. " ) " ;
2008-05-24 18:35:48 +00:00
$params = array ( " { $context -> path } /% " , $context -> instanceid );
2009-03-23 03:54:50 +00:00
$records = $DB -> get_recordset_sql ( $sql , $params );
foreach ( $records as $rec ) {
cache_context ( $rec );
2009-11-25 05:44:15 +00:00
$array [ $rec -> id ] = $rec ;
2007-10-10 12:19:27 +00:00
}
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.*
2008-05-24 18:35:48 +00:00
FROM { context } ctx
WHERE ctx . path LIKE ?
AND ctx . contextlevel IN ( " .CONTEXT_COURSECAT. " , " .CONTEXT_COURSE. " ) " ;
$params = array ( " { $context -> path } /% " );
2009-03-23 03:54:50 +00:00
$records = $DB -> get_recordset_sql ( $sql , $params );
foreach ( $records as $rec ) {
cache_context ( $rec );
2009-11-25 05:44:15 +00:00
$array [ $rec -> id ] = $rec ;
2007-02-09 02:24:59 +00:00
}
break ;
case CONTEXT_USER :
2009-07-13 08:37:34 +00:00
// Find
// - blocks under this context path.
$sql = " SELECT ctx.*
FROM { context } ctx
WHERE ctx . path LIKE ?
AND ctx . contextlevel = " .CONTEXT_BLOCK;
$params = array ( " { $context -> path } /% " , $context -> instanceid );
$records = $DB -> get_recordset_sql ( $sql , $params );
foreach ( $records as $rec ) {
cache_context ( $rec );
2009-11-25 05:44:15 +00:00
$array [ $rec -> id ] = $rec ;
2009-07-13 08:37:34 +00:00
}
break ;
2007-02-09 02:24:59 +00:00
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
2008-05-24 18:35:48 +00:00
$sql = " SELECT c.*
FROM { context } c
WHERE contextlevel != " .CONTEXT_SYSTEM;
2007-02-09 02:24:59 +00:00
2009-11-25 05:44:15 +00:00
$records = $DB -> get_records_sql ( $sql );
foreach ( $records as $rec ) {
$array [ $rec -> id ] = $rec ;
}
2007-02-09 02:24:59 +00:00
break ;
default :
2008-05-15 03:07:21 +00:00
print_error ( 'unknowcontext' , '' , '' , $context -> contextlevel );
2009-07-13 08:37:34 +00:00
return false ;
2007-02-09 02:24:59 +00:00
}
2009-11-25 05:44:15 +00:00
return $array ;
2007-02-09 02:24:59 +00:00
}
2006-09-20 08:30:49 +00:00
/**
* Gets a string for sql calls , searching for stuff in this context or above
2009-05-22 02:03:55 +00:00
*
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
2008-12-12 10:50:25 +00:00
/**
2010-03-31 07:41:31 +00:00
* Returns capability information ( cached )
2008-12-12 10:50:25 +00:00
*
* @ param string $capabilityname
2010-03-31 07:41:31 +00:00
* @ return object or NULL if capability not found
2008-12-12 10:50:25 +00:00
*/
2010-03-31 07:41:31 +00:00
function get_capability_info ( $capabilityname ) {
global $ACCESSLIB_PRIVATE , $DB ; // one request per page only
// TODO: cache this in shared memory if available, use new $CFG->roledefrev for version check
if ( empty ( $ACCESSLIB_PRIVATE -> capabilities )) {
$ACCESSLIB_PRIVATE -> capabilities = array ();
$caps = $DB -> get_records ( 'capabilities' , array (), 'id, name, captype, riskbitmask' );
foreach ( $caps as $cap ) {
$capname = $cap -> name ;
unset ( $cap -> id );
unset ( $cap -> name );
$ACCESSLIB_PRIVATE -> capabilities [ $capname ] = $cap ;
}
2008-09-08 07:00:49 +00:00
}
2010-03-31 07:41:31 +00:00
return isset ( $ACCESSLIB_PRIVATE -> capabilities [ $capabilityname ]) ? $ACCESSLIB_PRIVATE -> capabilities [ $capabilityname ] : NULL ;
2008-09-08 07:00: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 .
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ param string $capabilityname e . g . mod / choice : readresponses
* @ return string
2006-08-14 07:15:03 +00:00
*/
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 ]) {
2008-11-26 19:27:39 +00:00
case 'report' :
$string = get_string ( $stringname , 'report_' . $componentname );
break ;
2006-08-09 13:14:15 +00:00
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' :
2008-01-15 04:20:12 +00:00
if ( $componentname == 'local' ) {
$string = get_string ( $stringname , 'local' );
} else {
$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
2009-05-16 20:53:21 +00:00
case 'format' :
$string = get_string ( $stringname , 'editor_' . $componentname );
break ;
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 ;
2008-11-27 20:30:14 +00:00
case 'coursereport' :
$string = get_string ( $stringname , 'coursereport_' . $componentname );
break ;
2008-11-25 12:11:27 +00:00
case 'quizreport' :
$string = get_string ( $stringname , 'quiz_' . $componentname );
break ;
2009-08-07 08:59:47 +00:00
case 'repository' :
$string = get_string ( $stringname , 'repository_' . $componentname );
break ;
2009-10-26 19:41:06 +00:00
case 'local' :
$string = get_string ( $stringname , 'local_' . $componentname );
break ;
case 'webservice' :
$string = get_string ( $stringname , 'webservice_' . $componentname );
break ;
2009-11-01 11:31:16 +00:00
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 .
2009-05-22 02:03:55 +00:00
*
2009-05-19 07:50:54 +00:00
* @ param string $component
* @ param int $contextlevel
* @ return string | bool String is success , false if failed
2006-08-14 07:15:03 +00:00
*/
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 :
2010-04-22 15:37:54 +00:00
if ( preg_match ( '|^enrol|' , $component )) {
2006-09-12 20:03:08 +00:00
$langname = str_replace ( '/' , '_' , $component );
$string = get_string ( 'enrolname' , $langname );
2010-04-22 15:37:54 +00:00
} else if ( preg_match ( '|^block|' , $component )) {
2006-09-24 11:32:11 +00:00
$langname = str_replace ( '/' , '_' , $component );
2010-04-11 10:09:59 +00:00
$string = get_string ( 'pluginname' , $langname );
2008-01-15 04:20:12 +00:00
} else if ( preg_match ( '|^local|' , $component )) {
$langname = str_replace ( '/' , '_' , $component );
$string = get_string ( 'local' );
2010-04-22 15:37:54 +00:00
} else if ( preg_match ( '|^repository|' , $component )) {
$string = get_string ( 'repository' , 'repository' ) . ': ' . get_string ( 'repositoryname' , $component );
} else if ( preg_match ( '|^report|' , $component )) {
2008-11-26 19:27:39 +00:00
$string = get_string ( 'reports' );
2006-09-12 19:54:33 +00:00
} else {
$string = get_string ( 'coresystem' );
}
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 :
2010-04-22 15:37:54 +00:00
if ( preg_match ( '|^gradeimport|' , $component )) {
$string = get_string ( 'gradeimport' , 'grades' ) . ': ' . get_string ( 'modulename' , $component );
} else if ( preg_match ( '|^gradeexport|' , $component )) {
$string = get_string ( 'gradeexport' , 'grades' ) . ': ' . get_string ( 'modulename' , $component );
} else if ( preg_match ( '|^gradereport|' , $component )) {
$string = get_string ( 'gradereport' , 'grades' ) . ': ' . get_string ( 'modulename' , $component );
} else if ( preg_match ( '|^coursereport|' , $component )) {
2010-04-22 15:54:20 +00:00
$string = get_string ( 'coursereport' ) . ': ' . get_string ( 'pluginname' , $component );
2010-04-22 15:37:54 +00:00
} else if ( preg_match ( '|^webservice|' , $component )) {
2010-04-22 15:54:20 +00:00
$string = get_string ( 'webservice' , 'webservice' ) . ': ' . get_string ( 'pluginname' , $component );
2007-08-16 08:48:53 +00:00
} else {
$string = get_string ( 'course' );
}
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_MODULE :
2009-08-07 08:59:47 +00:00
if ( preg_match ( '|^quiz_([a-z_]*)|' , $component , $matches )){
2008-11-25 12:11:27 +00:00
$langname = 'quiz_' . $matches [ 1 ];
$string = get_string ( $matches [ 1 ] . ':componentname' , $langname );
2010-04-22 15:37:54 +00:00
} else if ( preg_match ( '|^moodle|' , $component )) {
$string = get_string ( 'coresystem' );
2008-11-25 12:11:27 +00:00
} else {
2010-04-22 15:54:20 +00:00
$string = get_string ( 'activity' ) . ': ' . get_string ( 'modulename' , preg_replace ( '#(\w+_)#' , '' , basename ( $component )));
2008-11-25 12:11:27 +00:00
}
2006-08-08 05:13:06 +00:00
break ;
case CONTEXT_BLOCK :
2010-04-22 15:37:54 +00:00
if ( $component == 'moodle' ){
2007-08-13 10:08:15 +00:00
$string = get_string ( 'block' );
} else {
2010-04-22 15:37:54 +00:00
$string = get_string ( 'block' ) . ': ' . get_string ( 'pluginname' , basename ( $component ));
2007-08-13 10:08:15 +00:00
}
2006-08-08 05:13:06 +00:00
break ;
default :
2008-12-12 05:45:43 +00:00
print_error ( 'unknowncontext' );
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 )
2010-03-31 07:41:31 +00:00
* from the list of roles that are visible on user profile page
* and participants page .
2009-05-19 07:50:54 +00:00
*
2010-03-31 07:41:31 +00:00
* @ param object $context
* @ return array
*/
function get_profile_roles ( $context ) {
global $CFG , $DB ;
if ( empty ( $CFG -> profileroles )) {
return array ();
}
$allowed = explode ( ',' , $CFG -> profileroles );
list ( $rallowed , $params ) = $DB -> get_in_or_equal ( $allowed , SQL_PARAMS_NAMED );
$contextlist = get_related_contexts_string ( $context );
$sql = " SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder
FROM { role_assignments } ra , { role } r
WHERE r . id = ra . roleid
AND ra . contextid $contextlist
AND r . id $rallowed
ORDER BY r . sortorder ASC " ;
return $DB -> get_records_sql ( $sql , $params );
}
/**
* Gets the list of roles assigned to this context and up ( parents )
2009-05-19 07:50:54 +00:00
*
2006-08-23 06:36:08 +00:00
* @ param object $context
* @ return array
*/
2010-03-31 07:41:31 +00:00
function get_roles_used_in_context ( $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2007-09-13 13:44:35 +00:00
2006-09-19 02:47:55 +00:00
$contextlist = get_related_contexts_string ( $context );
2006-09-20 21:00:45 +00:00
2008-05-24 18:35:48 +00:00
$sql = " SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder
FROM { role_assignments } ra , { role } r
2006-09-20 21:00:45 +00:00
WHERE r . id = ra . roleid
2008-05-24 18:35:48 +00:00
AND ra . contextid $contextlist
2006-09-20 08:30:49 +00:00
ORDER BY r . sortorder ASC " ;
2006-09-20 21:00:45 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> 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 .
2010-03-31 07:41:31 +00:00
* It is using the CFG -> profileroles to limit the list to only interesting roles .
* ( The permission tab has full details of user role assingments . )
2009-05-19 07:50:54 +00:00
*
* @ param int $userid
2010-03-31 07:41:31 +00:00
* @ param int $courseid
2006-08-23 06:36:08 +00:00
* @ return string
*/
2010-03-31 07:41:31 +00:00
function get_user_roles_in_course ( $userid , $courseid ) {
2008-05-30 11:06:49 +00:00
global $CFG , $DB , $USER ;
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
if ( empty ( $CFG -> profileroles )) {
return '' ;
}
if ( $courseid == SITEID ) {
$context = get_context_instance ( CONTEXT_SYSTEM );
} else {
$context = get_context_instance ( CONTEXT_COURSE , $courseid );
}
if ( empty ( $CFG -> profileroles )) {
return array ();
}
$allowed = explode ( ',' , $CFG -> profileroles );
list ( $rallowed , $params ) = $DB -> get_in_or_equal ( $allowed , SQL_PARAMS_NAMED );
$contextlist = get_related_contexts_string ( $context );
$sql = " SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder
FROM { role_assignments } ra , { role } r
WHERE r . id = ra . roleid
AND ra . contextid $contextlist
AND r . id $rallowed
AND ra . userid = : userid
ORDER BY r . sortorder ASC " ;
$params [ 'userid' ] = $userid ;
2006-08-15 08:29:29 +00:00
$rolestring = '' ;
2010-03-31 07:41:31 +00:00
2008-05-24 18:35:48 +00:00
if ( $roles = $DB -> get_records_sql ( $sql , $params )) {
2006-08-15 08:29:29 +00:00
foreach ( $roles as $userrole ) {
2010-03-31 07:41:31 +00:00
$rolenames [ $userrole -> id ] = $userrole -> name ;
2006-09-20 21:00:45 +00:00
}
2008-02-29 08:44:23 +00:00
$rolenames = role_fix_names ( $rolenames , $context ); // Substitute aliases
foreach ( $rolenames as $roleid => $rolename ) {
$rolenames [ $roleid ] = '<a href="' . $CFG -> wwwroot . '/user/index.php?contextid=' . $context -> id . '&roleid=' . $roleid . '">' . $rolename . '</a>' ;
}
$rolestring = implode ( ',' , $rolenames );
2006-08-15 08:29:29 +00:00
}
2006-09-20 21:00:45 +00:00
2010-03-31 07:41:31 +00:00
return $rolestring ;
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
2009-05-22 02:03:55 +00:00
*
* @ global object
2006-08-23 06:36:08 +00:00
* @ param object $context
2009-05-19 07:50:54 +00:00
* @ param int $targetroleid - the id of the role you want to assign users to
2006-08-23 06:36:08 +00:00
* @ return boolean
*/
2006-08-18 08:01:16 +00:00
function user_can_assign ( $context , $targetroleid ) {
2008-05-24 18:35:48 +00:00
global $DB ;
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
2008-05-24 18:35:48 +00:00
if ( $DB -> get_record ( 'role_allow_assign' , array ( 'roleid' => $userrole -> roleid , 'allowassign' => $targetroleid ))) {
2006-08-19 08:12:45 +00:00
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
}
2008-05-24 18:35:48 +00:00
/**
* Returns all site roles in correct sort order .
2009-05-22 02:03:55 +00:00
*
2008-05-24 18:35:48 +00:00
* @ return array
2006-09-23 12:51:00 +00:00
*/
function get_all_roles () {
2008-05-24 18:35:48 +00:00
global $DB ;
2010-03-31 07:41:31 +00:00
return $DB -> get_records ( 'role' , NULL , 'sortorder ASC' );
}
/**
* Returns roles of a specified archetype
* @ param string $archetype
* @ return array of full role records
*/
function get_archetype_roles ( $archetype ) {
global $DB ;
return $DB -> get_records ( 'role' , array ( 'archetype' => $archetype ));
2006-09-23 12:51:00 +00:00
}
2006-08-23 06:36:08 +00:00
/**
2010-03-31 07:41:31 +00:00
* Gets all the user roles assigned in this context , or higher contexts
2006-08-23 06:36:08 +00:00
* 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
2009-05-19 07:50:54 +00:00
*
2006-08-23 06:36:08 +00:00
* @ param object $context
* @ param int $userid
2009-05-19 07:50:54 +00:00
* @ param bool $checkparentcontexts defaults to true
* @ param string $order defaults to 'c.contextlevel DESC, r.sortorder ASC'
2006-08-23 06:36:08 +00:00
* @ return array
*/
2010-03-31 07:41:31 +00:00
function get_user_roles ( $context , $userid = 0 , $checkparentcontexts = true , $order = 'c.contextlevel DESC, r.sortorder ASC' ) {
2008-05-24 18:35:48 +00:00
global $USER , $DB ;
2006-08-19 08:12:45 +00:00
if ( empty ( $userid )) {
if ( empty ( $USER -> id )) {
return array ();
}
$userid = $USER -> id ;
}
2008-05-24 18:35:48 +00:00
if ( $checkparentcontexts ) {
$contextids = get_parent_contexts ( $context );
2006-08-19 08:12:45 +00:00
} else {
2008-05-24 18:35:48 +00:00
$contextids = array ();
2006-08-19 08:12:45 +00:00
}
2008-05-24 18:35:48 +00:00
$contextids [] = $context -> id ;
2006-08-19 08:12:45 +00:00
2008-05-24 18:35:48 +00:00
list ( $contextids , $params ) = $DB -> get_in_or_equal ( $contextids , SQL_PARAMS_QM );
array_unshift ( $params , $userid );
$sql = " SELECT ra.*, r.name, r.shortname
FROM { role_assignments } ra , { role } r , { context } c
WHERE ra . userid = ?
AND ra . roleid = r . id
AND ra . contextid = c . id
AND ra . contextid $contextids
ORDER BY $order " ;
2008-02-05 12:59:28 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> get_records_sql ( $sql , $params );
2006-08-18 08:01:16 +00:00
}
2006-08-23 06:36:08 +00:00
/**
2009-03-25 04:20:57 +00:00
* Creates a record in the role_allow_override table
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $sroleid source roleid
* @ param int $troleid target roleid
* @ return int id or false
2006-08-23 06:36:08 +00:00
*/
function allow_override ( $sroleid , $troleid ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-23 12:51:00 +00:00
$record = new object ();
2008-05-24 18:35:48 +00:00
$record -> roleid = $sroleid ;
2006-08-23 06:36:08 +00:00
$record -> allowoverride = $troleid ;
2009-03-25 04:20:57 +00:00
$DB -> insert_record ( 'role_allow_override' , $record );
2006-08-23 06:36:08 +00:00
}
/**
2009-03-25 04:20:57 +00:00
* Creates a record in the role_allow_assign table
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $sroleid source roleid
* @ param int $troleid target roleid
* @ return int id or false
2006-08-23 06:36:08 +00:00
*/
2008-11-18 09:28:05 +00:00
function allow_assign ( $fromroleid , $targetroleid ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2010-03-31 07:41:31 +00:00
$record = new object ();
2008-11-18 09:28:05 +00:00
$record -> roleid = $fromroleid ;
$record -> allowassign = $targetroleid ;
2009-03-25 04:20:57 +00:00
$DB -> insert_record ( 'role_allow_assign' , $record );
}
/**
* Creates a record in the role_allow_switch table
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $sroleid source roleid
* @ param int $troleid target roleid
* @ return int id or false
2009-03-25 04:20:57 +00:00
*/
function allow_switch ( $fromroleid , $targetroleid ) {
global $DB ;
2010-03-31 07:41:31 +00:00
$record = new object ();
2009-03-25 04:20:57 +00:00
$record -> roleid = $fromroleid ;
$record -> allowswitch = $targetroleid ;
$DB -> insert_record ( 'role_allow_switch' , $record );
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 assign in this context
2009-05-22 02:03:55 +00:00
*
* @ global object
* @ global object
2008-10-30 06:26:18 +00:00
* @ param object $context the context .
* @ param int $rolenamedisplay the type of role name to display . One of the
* ROLENAME_X constants . Default ROLENAME_ALIAS .
2009-05-19 07:50:54 +00:00
* @ param bool $withusercounts if true , count the number of users with each role .
2008-10-30 06:26:18 +00:00
* @ return array if $withusercounts is false , then an array $roleid => $rolename .
* if $withusercounts is true , returns a list of three arrays ,
* $rolenames , $rolecounts , and $nameswithcounts .
2006-08-23 06:36:08 +00:00
*/
2008-10-30 06:26:18 +00:00
function get_assignable_roles ( $context , $rolenamedisplay = ROLENAME_ALIAS , $withusercounts = false ) {
2008-07-23 16:10:06 +00:00
global $USER , $DB ;
2007-09-19 07:27:46 +00:00
2008-07-23 16:10:06 +00:00
if ( ! has_capability ( 'moodle/role:assign' , $context )) {
2008-11-06 07:34:01 +00:00
if ( $withusercounts ) {
return array ( array (), array (), array ());
} else {
return array ();
}
2008-09-06 13:17:15 +00:00
}
2008-07-23 16:10:06 +00:00
2010-03-31 07:41:31 +00:00
$parents = get_parent_contexts ( $context , true );
2008-07-23 16:10:06 +00:00
$contexts = implode ( ',' , $parents );
2008-10-30 06:26:18 +00:00
$params = array ();
$extrafields = '' ;
if ( $rolenamedisplay == ROLENAME_ORIGINALANDSHORT ) {
2010-03-31 07:41:31 +00:00
$extrafields .= ', r.shortname' ;
2008-10-30 06:26:18 +00:00
}
if ( $withusercounts ) {
$extrafields = ' , ( SELECT count ( u . id )
2009-01-17 23:16:20 +00:00
FROM { role_assignments } cra JOIN { user } u ON cra . userid = u . id
2010-03-31 07:41:31 +00:00
WHERE cra . roleid = r . id AND cra . contextid = : conid AND u . deleted = 0
2009-01-17 23:16:20 +00:00
) AS usercount ' ;
2008-10-30 06:26:18 +00:00
$params [ 'conid' ] = $context -> id ;
}
2010-03-31 07:41:31 +00:00
if ( is_siteadmin ()) {
2009-01-17 23:16:20 +00:00
// show all roles allowed in this context to admins
2010-03-31 07:41:31 +00:00
$assignrestriction = " " ;
} else {
$assignrestriction = " JOIN (SELECT DISTINCT raa.allowassign AS id
FROM { role_allow_assign } raa
JOIN { role_assignments } ra ON ra . roleid = raa . roleid
WHERE ra . userid = : userid AND ra . contextid IN ( $contexts )
) ar ON ar . id = r . id " ;
$params [ 'userid' ] = $USER -> id ;
2009-01-17 23:16:20 +00:00
}
2008-11-06 07:34:01 +00:00
$params [ 'contextlevel' ] = $context -> contextlevel ;
2010-03-31 07:41:31 +00:00
$sql = " SELECT r.id, r.name $extrafields
FROM { role } r
$assignrestriction
JOIN { role_context_levels } rcl ON r . id = rcl . roleid
WHERE rcl . contextlevel = : contextlevel
ORDER BY r . sortorder ASC " ;
$roles = $DB -> get_records_sql ( $sql , $params );
2007-09-19 07:27:46 +00:00
2008-10-30 06:26:18 +00:00
$rolenames = array ();
2008-07-23 16:10:06 +00:00
foreach ( $roles as $role ) {
2008-10-30 06:26:18 +00:00
$rolenames [ $role -> id ] = $role -> name ;
if ( $rolenamedisplay == ROLENAME_ORIGINALANDSHORT ) {
$rolenames [ $role -> id ] .= ' (' . $role -> shortname . ')' ;
2010-03-31 07:41:31 +00:00
}
2008-10-30 06:26:18 +00:00
}
if ( $rolenamedisplay != ROLENAME_ORIGINALANDSHORT ) {
$rolenames = role_fix_names ( $rolenames , $context , $rolenamedisplay );
2006-08-23 06:36:08 +00:00
}
2008-04-18 06:21:00 +00:00
2008-10-30 06:26:18 +00:00
if ( ! $withusercounts ) {
return $rolenames ;
}
$rolecounts = array ();
$nameswithcounts = array ();
foreach ( $roles as $role ) {
$nameswithcounts [ $role -> id ] = $rolenames [ $role -> id ] . ' (' . $roles [ $role -> id ] -> usercount . ')' ;
$rolecounts [ $role -> id ] = $roles [ $role -> id ] -> usercount ;
}
return array ( $rolenames , $rolecounts , $nameswithcounts );
2006-08-23 06:36:08 +00:00
}
2008-02-15 16:40:45 +00:00
/**
2009-05-19 07:50:54 +00:00
* Gets a list of roles that this user can switch to in a context
*
2009-03-23 08:15:21 +00:00
* Gets a list of roles that this user can switch to in a context , for the switchrole menu .
* This function just process the contents of the role_allow_switch table . You also need to
* test the moodle / role : switchroles to see if the user is allowed to switch in the first place .
2008-02-15 16:40:45 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2009-03-23 08:15:21 +00:00
* @ param object $context a context .
2009-05-19 07:50:54 +00:00
* @ return array an array $roleid => $rolename .
2008-02-15 16:40:45 +00:00
*/
2009-03-23 08:15:21 +00:00
function get_switchable_roles ( $context ) {
2008-07-23 16:10:06 +00:00
global $USER , $DB ;
2008-02-15 16:40:45 +00:00
2009-03-23 08:15:21 +00:00
$systemcontext = get_context_instance ( CONTEXT_SYSTEM );
2008-02-15 16:40:45 +00:00
2009-03-23 08:15:21 +00:00
$params = array ();
$extrajoins = '' ;
$extrawhere = '' ;
2010-03-31 07:41:31 +00:00
if ( ! is_siteadmin ()) {
// Admins are allowed to switch to any role with 'moodle/course:participate' in the
// role definition.
2009-03-23 08:15:21 +00:00
// Others are subject to the additional constraint that the switch-to role must be allowed by
// 'role_allow_switch' for some role they have assigned in this context or any parent.
$parents = get_parent_contexts ( $context );
$parents [] = $context -> id ;
$contexts = implode ( ',' , $parents );
$extrajoins = " JOIN { role_allow_switch} ras ON ras.allowswitch = rc.roleid
JOIN { role_assignments } ra ON ra . roleid = ras . roleid " ;
2010-03-31 07:41:31 +00:00
$extrawhere = " AND ra.userid = :userid AND ra.contextid IN ( $contexts ) " ;
2009-03-23 08:15:21 +00:00
$params [ 'userid' ] = $USER -> id ;
}
$query = "
SELECT r . id , r . name
FROM (
SELECT DISTINCT rc . roleid
FROM { role_capabilities } rc
$extrajoins
WHERE rc . capability = : viewcap
2009-03-25 04:20:57 +00:00
AND rc . permission = " . CAP_ALLOW . "
2009-03-23 08:15:21 +00:00
AND rc . contextid = : syscontextid
$extrawhere
) idlist
JOIN { role } r ON r . id = idlist . roleid
ORDER BY r . sortorder " ;
$params [ 'syscontextid' ] = $systemcontext -> id ;
2010-03-31 07:41:31 +00:00
$params [ 'viewcap' ] = 'moodle/course:participate' ;
2009-03-23 08:15:21 +00:00
$rolenames = $DB -> get_records_sql_menu ( $query , $params );
2008-10-30 06:26:18 +00:00
return role_fix_names ( $rolenames , $context , ROLENAME_ALIAS );
2008-02-15 16:40:45 +00:00
}
2009-03-25 04:20:57 +00:00
/**
* Get an array of role ids that might possibly be the target of a switchrole .
2010-03-31 07:41:31 +00:00
* Our policy is that you cannot switch to admin role
* and you can only switch to a role with moodle / course : participate . This method returns
2009-03-25 04:20:57 +00:00
* a list of those role ids .
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ return array an array whose keys are the allowed role ids .
2009-03-25 04:20:57 +00:00
*/
function get_allowed_switchable_roles () {
2010-03-31 07:41:31 +00:00
global $CFG , $DB ;
2009-03-25 04:20:57 +00:00
$systemcontext = get_context_instance ( CONTEXT_SYSTEM );
$query = "
SELECT DISTINCT rc . roleid , 1
FROM { role_capabilities } rc
2010-03-31 07:41:31 +00:00
JOIN { role } r ON r . id = rc . roleid
WHERE rc . capability = : participate
2009-03-25 04:20:57 +00:00
AND rc . permission = " . CAP_ALLOW . "
2010-03-31 07:41:31 +00:00
AND rc . contextid = : syscontextid " ;
$params = array ( 'syscontextid' => $systemcontext -> id , 'participate' => 'moodle/course:participate' );
2009-03-25 04:20:57 +00:00
return $DB -> get_records_sql_menu ( $query , $params );
}
2006-08-23 06:36:08 +00:00
/**
2008-11-05 08:17:30 +00:00
* Gets a list of roles that this user can override in this context .
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2008-11-05 08:17:30 +00:00
* @ param object $context the context .
* @ param int $rolenamedisplay the type of role name to display . One of the
* ROLENAME_X constants . Default ROLENAME_ALIAS .
2009-05-19 07:50:54 +00:00
* @ param bool $withcounts if true , count the number of overrides that are set for each role .
2008-11-05 08:17:30 +00:00
* @ return array if $withcounts is false , then an array $roleid => $rolename .
* if $withusercounts is true , returns a list of three arrays ,
* $rolenames , $rolecounts , and $nameswithcounts .
2006-08-23 06:36:08 +00:00
*/
2008-11-05 08:17:30 +00:00
function get_overridable_roles ( $context , $rolenamedisplay = ROLENAME_ALIAS , $withcounts = false ) {
2008-07-23 16:10:06 +00:00
global $USER , $DB ;
2006-08-23 06:36:08 +00:00
2008-11-05 08:17:30 +00:00
if ( ! has_any_capability ( array ( 'moodle/role:safeoverride' , 'moodle/role:override' ), $context )) {
2008-11-06 07:34:01 +00:00
if ( $withcounts ) {
return array ( array (), array (), array ());
} else {
return array ();
}
2008-08-18 18:36:53 +00:00
}
2008-07-23 16:10:06 +00:00
$parents = get_parent_contexts ( $context );
$parents [] = $context -> id ;
$contexts = implode ( ',' , $parents );
2008-11-05 08:17:30 +00:00
$params = array ();
$extrafields = '' ;
if ( $rolenamedisplay == ROLENAME_ORIGINALANDSHORT ) {
$extrafields .= ', ro.shortname' ;
}
$params [ 'userid' ] = $USER -> id ;
if ( $withcounts ) {
$extrafields = ' , ( SELECT count ( rc . id ) FROM { role_capabilities } rc
WHERE rc . roleid = ro . id AND rc . contextid = : conid ) AS overridecount ' ;
$params [ 'conid' ] = $context -> id ;
}
2010-03-31 07:41:31 +00:00
if ( is_siteadmin ()) {
2009-01-17 23:16:20 +00:00
// show all roles to admins
$roles = $DB -> get_records_sql ( "
2008-11-05 08:17:30 +00:00
SELECT ro . id , ro . name $extrafields
FROM { role } ro
2009-01-17 23:16:20 +00:00
ORDER BY ro . sortorder ASC " , $params );
2009-11-01 11:31:16 +00:00
2009-01-17 23:16:20 +00:00
} else {
$roles = $DB -> get_records_sql ( "
SELECT ro . id , ro . name $extrafields
FROM { role } ro
JOIN ( SELECT DISTINCT r . id
FROM { role } r
JOIN { role_allow_override } rao ON r . id = rao . allowoverride
JOIN { role_assignments } ra ON rao . roleid = ra . roleid
WHERE ra . userid = : userid AND ra . contextid IN ( $contexts )
2008-11-05 08:17:30 +00:00
) inline_view ON ro . id = inline_view . id
2009-01-17 23:16:20 +00:00
ORDER BY ro . sortorder ASC " , $params );
2008-07-23 16:10:06 +00:00
}
2006-09-17 07:00:47 +00:00
2008-11-05 08:17:30 +00:00
$rolenames = array ();
2008-07-23 16:10:06 +00:00
foreach ( $roles as $role ) {
2008-11-05 08:17:30 +00:00
$rolenames [ $role -> id ] = $role -> name ;
if ( $rolenamedisplay == ROLENAME_ORIGINALANDSHORT ) {
$rolenames [ $role -> id ] .= ' (' . $role -> shortname . ')' ;
}
}
if ( $rolenamedisplay != ROLENAME_ORIGINALANDSHORT ) {
$rolenames = role_fix_names ( $rolenames , $context , $rolenamedisplay );
2006-09-17 07:00:47 +00:00
}
2006-09-20 21:00:45 +00:00
2008-11-05 08:17:30 +00:00
if ( ! $withcounts ) {
return $rolenames ;
2008-11-06 07:34:01 +00:00
}
2008-11-05 08:17:30 +00:00
$rolecounts = array ();
$nameswithcounts = array ();
foreach ( $roles as $role ) {
$nameswithcounts [ $role -> id ] = $rolenames [ $role -> id ] . ' (' . $roles [ $role -> id ] -> overridecount . ')' ;
$rolecounts [ $role -> id ] = $roles [ $role -> id ] -> overridecount ;
}
return array ( $rolenames , $rolecounts , $nameswithcounts );
2006-08-23 06:36:08 +00:00
}
2006-08-28 08:42:30 +00:00
2008-11-06 07:34:01 +00:00
/**
2009-05-22 02:03:55 +00:00
* @ global object
2008-11-06 07:34:01 +00:00
* @ param integer $roleid the id of a role .
* @ return array list of the context levels at which this role may be assigned .
*/
function get_role_contextlevels ( $roleid ) {
global $DB ;
return $DB -> get_records_menu ( 'role_context_levels' , array ( 'roleid' => $roleid ),
'contextlevel' , 'id,contextlevel' );
}
2008-11-13 08:11:10 +00:00
/**
2009-05-22 02:03:55 +00:00
* @ global object
2008-11-13 08:11:10 +00:00
* @ param integer $contextlevel a contextlevel .
* @ return array list of role ids that are assignable at this context level .
*/
function get_roles_for_contextlevels ( $contextlevel ) {
global $DB ;
return $DB -> get_records_menu ( 'role_context_levels' , array ( 'contextlevel' => $contextlevel ),
'' , 'id,roleid' );
}
2008-11-06 07:34:01 +00:00
/**
2010-03-31 07:41:31 +00:00
* @ param string $rolearchetype one of the role archetypes - that is , one of the keys
* from the array returned by get_role_archetypes ();
2008-11-06 07:34:01 +00:00
* @ return array list of the context levels at which this type of role may be assigned by default .
*/
2010-03-31 07:41:31 +00:00
function get_default_contextlevels ( $rolearchetype ) {
2008-11-06 07:34:01 +00:00
static $defaults = array (
2010-03-31 07:41:31 +00:00
'manager' => array ( CONTEXT_SYSTEM , CONTEXT_COURSECAT , CONTEXT_COURSE ),
2008-11-06 07:34:01 +00:00
'coursecreator' => array ( CONTEXT_SYSTEM , CONTEXT_COURSECAT ),
'editingteacher' => array ( CONTEXT_COURSECAT , CONTEXT_COURSE , CONTEXT_MODULE ),
'teacher' => array ( CONTEXT_COURSECAT , CONTEXT_COURSE , CONTEXT_MODULE ),
'student' => array ( CONTEXT_COURSE , CONTEXT_MODULE ),
'guest' => array (),
2010-03-31 07:41:31 +00:00
'user' => array (),
'frontpage' => array ()
2008-11-06 07:34:01 +00:00
);
2010-03-31 07:41:31 +00:00
if ( isset ( $defaults [ $rolearchetype ])) {
return $defaults [ $rolearchetype ];
2008-11-18 07:10:00 +00:00
} else {
return array ();
}
2008-11-06 07:34:01 +00:00
}
/**
* Set the context levels at which a particular role can be assigned .
* Throws exceptions in case of error .
*
2009-05-22 02:03:55 +00:00
* @ global object
2008-11-06 07:34:01 +00:00
* @ param integer $roleid the id of a role .
* @ param array $contextlevels the context levels at which this role should be assignable .
*/
function set_role_contextlevels ( $roleid , array $contextlevels ) {
global $DB ;
2009-01-17 23:24:31 +00:00
$DB -> delete_records ( 'role_context_levels' , array ( 'roleid' => $roleid ));
2008-11-06 07:34:01 +00:00
$rcl = new stdClass ;
$rcl -> roleid = $roleid ;
foreach ( $contextlevels as $level ) {
$rcl -> contextlevel = $level ;
2009-01-17 23:24:31 +00:00
$DB -> insert_record ( 'role_context_levels' , $rcl , false , true );
2008-11-06 07:34:01 +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
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
2006-09-20 21:00:45 +00:00
* @ param object $course
2009-05-19 07:50:54 +00:00
* @ return object returns a role or NULL if none set
2006-09-17 16:06:25 +00:00
*/
function get_default_course_role ( $course ) {
2008-05-24 18:35:48 +00:00
global $DB , $CFG ;
2006-09-17 16:06:25 +00:00
/// First let's take the default role the course may have
if ( ! empty ( $course -> defaultrole )) {
2008-05-24 18:35:48 +00:00
if ( $role = $DB -> get_record ( 'role' , array ( 'id' => $course -> defaultrole ))) {
2006-09-17 16:06:25 +00:00
return $role ;
}
}
/// Otherwise the site setting should tell us
if ( $CFG -> defaultcourseroleid ) {
2008-05-24 18:35:48 +00:00
if ( $role = $DB -> get_record ( 'role' , array ( 'id' => $CFG -> defaultcourseroleid ))) {
2006-09-17 16:06:25 +00:00
return $role ;
}
}
/// It's unlikely we'll get here, but just in case, try and find a student role
2010-03-31 07:41:31 +00:00
if ( $studentroles = $DB -> get_records ( 'role' , array ( 'archetype' => 'student' ))) {
2006-09-17 16:06:25 +00:00
return array_shift ( $studentroles ); /// Take the first one
}
return NULL ;
}
2006-08-28 08:42:30 +00:00
/**
2008-01-06 23:23:58 +00:00
* Who has this capability in this context ?
*
* This can be a very expensive call - use sparingly and keep
* the results if you are going to need them again soon .
2008-05-24 18:35:48 +00:00
*
2008-01-06 23:23:58 +00:00
* Note if $fields is empty this function attempts to get u .*
* which can get rather large - and has a serious perf impact
* on some DBs .
*
2009-05-19 07:50:54 +00:00
* @ param object $context
2010-03-07 09:28:54 +00:00
* @ param string | array $capability - capability name ( s )
2009-05-19 07:50:54 +00:00
* @ param string $fields - fields to be pulled . The user table is aliased to 'u' . u . id MUST be included .
* @ param string $sort - the sort order . Default is lastaccess time .
* @ param mixed $limitfrom - number of records to skip ( offset )
* @ param mixed $limitnum - number of records to fetch
2010-03-07 09:28:54 +00:00
* @ param string | array $groups - single group or array of groups - only return
2007-06-26 16:16:46 +00:00
* users who are in one of these group ( s ) .
2010-03-07 09:28:54 +00:00
* @ param string | array $exceptions - list of users to exclude , comma separated or array
2010-03-31 07:41:31 +00:00
* @ param bool $doanything_ignored not used any more , admin accounts are never returned
* @ param bool $view_ignored - use get_enrolled_sql () instead
2009-05-19 07:50:54 +00:00
* @ param bool $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 .
2009-05-19 07:50:54 +00:00
* @ return mixed
2006-08-28 08:42:30 +00:00
*/
2010-03-07 09:28:54 +00:00
function get_users_by_capability ( $context , $capability , $fields = '' , $sort = '' , $limitfrom = '' , $limitnum = '' ,
2010-03-31 07:41:31 +00:00
$groups = '' , $exceptions = '' , $doanything_ignored = NULL , $view_ignored = NULL , $useviewallgroups = false ) {
2008-05-24 18:35:48 +00:00
global $CFG , $DB ;
2006-09-20 21:00:45 +00:00
2010-03-07 09:28:54 +00:00
if ( empty ( $context -> id )) {
throw new coding_exception ( 'Invalid context specified' );
}
2010-03-31 07:41:31 +00:00
$defaultuserroleid = isset ( $CFG -> defaultuserroleid ) ? $CFG -> defaultuserroleid : NULL ;
$defaultfrontpageroleid = isset ( $CFG -> defaultfrontpageroleid ) ? $CFG -> defaultfrontpageroleid : NULL ;
2010-03-07 09:28:54 +00:00
$ctxids = trim ( $context -> path , '/' );
2008-01-06 23:22:26 +00:00
$ctxids = str_replace ( '/' , ',' , $ctxids );
// Context is the frontpage
$iscoursepage = false ; // coursepage other than fp
2010-03-07 09:28:54 +00:00
$isfrontpage = false ;
2008-01-06 23:22:26 +00:00
if ( $context -> contextlevel == CONTEXT_COURSE ) {
if ( $context -> instanceid == SITEID ) {
$isfrontpage = true ;
} else {
$iscoursepage = true ;
}
}
2010-03-07 09:28:54 +00:00
$isfrontpage = ( $isfrontpage || is_inside_frontpage ( $context ));
2008-01-06 23:22:26 +00:00
2010-03-07 09:28:54 +00:00
$caps = ( array ) $capability ;
2008-05-24 18:35:48 +00:00
2010-03-07 09:28:54 +00:00
// contruct list of context paths bottom-->top
2010-03-31 07:41:31 +00:00
list ( $contextids , $paths ) = get_context_info_list ( $context );
2007-09-27 01:46:41 +00:00
2010-03-07 09:28:54 +00:00
// we need to find out all roles that have these capabilities either in definition or in overrides
$defs = array ();
list ( $incontexts , $params ) = $DB -> get_in_or_equal ( $contextids , SQL_PARAMS_NAMED , 'con000' );
list ( $incaps , $params2 ) = $DB -> get_in_or_equal ( $caps , SQL_PARAMS_NAMED , 'cap000' );
$params = array_merge ( $params , $params2 );
$sql = " SELECT rc.id, rc.roleid, rc.permission, rc.capability, ctx.path
FROM { role_capabilities } rc
JOIN { context } ctx on rc . contextid = ctx . id
WHERE rc . contextid $incontexts AND rc . capability $incaps " ;
2008-01-06 23:22:26 +00:00
2010-03-07 09:28:54 +00:00
$rcs = $DB -> get_records_sql ( $sql , $params );
foreach ( $rcs as $rc ) {
$defs [ $rc -> capability ][ $rc -> path ][ $rc -> roleid ] = $rc -> permission ;
2008-01-06 23:23:58 +00:00
}
2010-03-07 09:28:54 +00:00
// go through the permissions bottom-->top direction to evaluate the current permission,
// first one wins (prohibit is an exception that always wins)
$access = array ();
foreach ( $caps as $cap ) {
foreach ( $paths as $path ) {
if ( empty ( $defs [ $cap ][ $path ])) {
continue ;
}
foreach ( $defs [ $cap ][ $path ] as $roleid => $perm ) {
if ( $perm == CAP_PROHIBIT ) {
$access [ $cap ][ $roleid ] = CAP_PROHIBIT ;
continue ;
}
if ( ! isset ( $access [ $cap ][ $roleid ])) {
$access [ $cap ][ $roleid ] = ( int ) $perm ;
}
}
2009-10-05 17:08:16 +00:00
}
}
2010-03-07 09:28:54 +00:00
// make lists of roles that are needed and prohibited in this context
$needed = array (); // one of these is enough
$prohibited = array (); // must not have any of these
foreach ( $caps as $cap ) {
if ( empty ( $access [ $cap ])) {
continue ;
2007-06-26 16:16:46 +00:00
}
2010-03-07 09:28:54 +00:00
foreach ( $access [ $cap ] as $roleid => $perm ) {
if ( $perm == CAP_PROHIBIT ) {
unset ( $needed [ $cap ][ $roleid ]);
$prohibited [ $cap ][ $roleid ] = true ;
} else if ( $perm == CAP_ALLOW and empty ( $prohibited [ $cap ][ $roleid ])) {
$needed [ $cap ][ $roleid ] = true ;
}
2006-09-11 08:56:23 +00:00
}
2010-03-07 09:28:54 +00:00
if ( empty ( $needed [ $cap ]) or ! empty ( $prohibited [ $cap ][ $defaultuserroleid ])) {
// easy, nobody has the permission
unset ( $needed [ $cap ]);
unset ( $prohibited [ $cap ]);
} else if ( $isfrontpage and ! empty ( $prohibited [ $cap ][ $defaultfrontpageroleid ])) {
// everybody is disqualified on the frontapge
unset ( $needed [ $cap ]);
unset ( $prohibited [ $cap ]);
}
if ( empty ( $prohibited [ $cap ])) {
unset ( $prohibited [ $cap ]);
2008-05-25 10:16:53 +00:00
}
2008-01-06 23:22:26 +00:00
}
2008-01-06 23:22:08 +00:00
2010-03-07 09:28:54 +00:00
if ( empty ( $needed )) {
// there can not be anybody if no roles match this request
return array ();
2008-01-06 23:22:26 +00:00
}
2010-03-07 09:28:54 +00:00
if ( empty ( $prohibited )) {
// we can compact the needed roles
$n = array ();
foreach ( $needed as $cap ) {
foreach ( $cap as $roleid => $unused ) {
$n [ $roleid ] = true ;
}
}
$needed = array ( 'any' => $n );
unset ( $n );
2006-09-16 13:54:57 +00:00
}
2010-03-07 09:28:54 +00:00
/// ***** Set up default fields ******
2008-01-06 23:22:26 +00:00
if ( empty ( $fields )) {
if ( $iscoursepage ) {
2010-03-07 09:28:54 +00:00
$fields = 'u.*, ul.timeaccess AS lastaccess' ;
2008-01-06 23:22:26 +00:00
} else {
2008-01-06 23:24:14 +00:00
$fields = 'u.*' ;
2008-01-06 23:22:26 +00:00
}
2009-01-14 04:44:20 +00:00
} else {
2010-03-07 09:28:54 +00:00
if ( debugging ( '' , DEBUG_DEVELOPER ) && strpos ( $fields , 'u.*' ) === false && strpos ( $fields , 'u.id' ) === false ) {
debugging ( 'u.id must be included in the list of fields passed to get_users_by_capability().' , DEBUG_DEVELOPER );
2009-01-14 04:44:20 +00:00
}
2006-09-16 13:54:57 +00:00
}
2008-01-06 23:22:26 +00:00
/// Set up default sort
if ( empty ( $sort )) { // default to course lastaccess or just lastaccess
if ( $iscoursepage ) {
$sort = 'ul.timeaccess' ;
} else {
$sort = 'u.lastaccess' ;
}
}
2010-03-07 09:28:54 +00:00
$sortby = " ORDER BY $sort " ;
// Prepare query clauses
$wherecond = array ();
$params = array ();
$joins = array ();
2006-09-20 21:00:45 +00:00
2008-01-06 23:22:26 +00:00
// User lastaccess JOIN
2010-03-07 09:28:54 +00:00
if (( strpos ( $sort , 'ul.timeaccess' ) === false ) and ( strpos ( $fields , 'ul.timeaccess' ) === false )) {
// user_lastaccess is not required MDL-13810
2008-03-06 02:15:00 +00:00
} else {
2010-03-07 09:28:54 +00:00
if ( $iscoursepage ) {
$joins [] = " LEFT OUTER JOIN { user_lastaccess} ul ON (ul.userid = u.id AND ul.courseid = { $context -> instanceid } ) " ;
} else {
throw new coding_exception ( 'Invalid sort in get_users_by_capability(), ul.timeaccess allowed only for course contexts.' );
}
2008-01-06 23:22:26 +00:00
}
2010-03-07 09:28:54 +00:00
/// We never return deleted users or guest acount.
$wherecond [] = " u.deleted = 0 AND u.username <> 'guest' " ;
2008-01-06 23:23:24 +00:00
2010-03-07 09:28:54 +00:00
/// Groups
if ( $groups ) {
$groups = ( array ) $groups ;
list ( $grouptest , $grpparams ) = $DB -> get_in_or_equal ( $groups , SQL_PARAMS_NAMED , 'grp000' );
$grouptest = " u.id IN (SELECT userid FROM { groups_members} gm WHERE gm.groupid $grouptest ) " ;
$params = array_merge ( $params , $grpparams );
2008-01-06 23:23:24 +00:00
2010-03-07 09:28:54 +00:00
if ( $useviewallgroups ) {
$viewallgroupsusers = get_users_by_capability ( $context , 'moodle/site:accessallgroups' , 'u.id, u.id' , '' , '' , '' , '' , $exceptions );
$wherecond [] = " ( $grouptest OR u.id IN ( " . implode ( ',' , array_keys ( $viewallgroupsusers )) . '))' ;
2008-01-06 23:23:24 +00:00
} else {
2010-03-07 09:28:54 +00:00
$wherecond [] = " ( $grouptest ) " ;
}
2008-05-24 18:35:48 +00:00
}
2008-01-06 23:23:24 +00:00
2010-03-07 09:28:54 +00:00
/// User exceptions
if ( ! empty ( $exceptions )) {
$exceptions = ( array ) $exceptions ;
list ( $exsql , $exparams ) = $DB -> get_in_or_equal ( $exceptions , SQL_PARAMS_NAMED , 'exc000' , false );
$params = array_merge ( $params , $exparams );
$wherecond [] = " u.id $exsql " ;
}
2008-01-06 23:23:24 +00:00
2010-03-07 09:28:54 +00:00
// now add the needed and prohibited roles conditions as joins
if ( ! empty ( $needed [ 'any' ])) {
// simple case - there are no prohibits involved
if ( ! empty ( $needed [ 'any' ][ $defaultuserroleid ]) or ( $isfrontpage and ! empty ( $needed [ 'any' ][ $defaultfrontpageroleid ]))) {
// everybody
} else {
$joins [] = " JOIN (SELECT DISTINCT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
AND roleid IN ( " .implode(',', array_keys( $needed['any'] )) . " )
) ra ON ra . userid = u . id " ;
}
} else {
$unions = array ();
$everybody = false ;
foreach ( $needed as $cap => $unused ) {
if ( empty ( $prohibited [ $cap ])) {
if ( ! empty ( $needed [ $cap ][ $defaultuserroleid ]) or ( $isfrontpage and ! empty ( $needed [ $cap ][ $defaultfrontpageroleid ]))) {
$everybody = true ;
break ;
} else {
$unions [] = " SELECT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
2010-03-31 07:41:31 +00:00
AND roleid IN ( " .implode(',', array_keys( $needed[$cap] )) . " ) " ;
2008-01-06 23:24:25 +00:00
}
2010-03-07 09:28:54 +00:00
} else {
if ( ! empty ( $needed [ $cap ][ $defaultuserroleid ]) or ( $isfrontpage and ! empty ( $needed [ $cap ][ $defaultfrontpageroleid ]))) {
// everybody except the prohibitted - hiding does not matter
$unions [] = " SELECT id AS userid
FROM { user }
WHERE id NOT IN ( SELECT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
AND roleid IN ( " .implode(',', array_keys( $prohibited[$cap] )) . " )) " ;
2008-01-06 23:23:58 +00:00
} else {
2010-03-31 07:41:31 +00:00
$unions [] = " SELECT userid
FROM { role_assignments }
WHERE contextid IN ( $ctxids )
AND roleid IN ( " .implode(',', array_keys( $needed[$cap] )) . " )
AND roleid NOT IN ( " .implode(',', array_keys( $prohibited[$cap] )) . " ) " ;
2008-01-06 23:23:58 +00:00
}
}
}
2010-03-07 09:28:54 +00:00
if ( ! $everybody ) {
if ( count ( $unions ) > 1 ) {
$unions = implode ( ' UNION ' , $unions );
} else {
$unions = reset ( $unions );
2008-01-06 23:24:25 +00:00
}
2010-03-07 09:28:54 +00:00
$joins [] = " JOIN (SELECT DISTINCT userid FROM ( $unions ) us) ra ON ra.userid = u.id " ;
2008-01-06 23:24:25 +00:00
}
}
2008-01-06 23:23:58 +00:00
2010-03-07 09:28:54 +00:00
// Collect WHERE conditions and needed joins
$where = implode ( ' AND ' , $wherecond );
if ( $where !== '' ) {
$where = 'WHERE ' . $where ;
}
$joins = implode ( " \n " , $joins );
2008-01-06 23:24:25 +00:00
2010-03-07 09:28:54 +00:00
/// Ok, let's get the users!
$sql = " SELECT $fields
FROM { user } u
$joins
$where
ORDER BY $sort " ;
2008-01-06 23:24:25 +00:00
2010-03-07 09:28:54 +00:00
return $DB -> get_records_sql ( $sql , $params , $limitfrom , $limitnum );
2006-08-28 08:42:30 +00:00
}
2006-09-03 07:56:40 +00:00
2008-01-06 23:25:37 +00:00
/**
2009-05-19 07:50:54 +00:00
* Re - sort a users array based on a sorting policy
*
2008-01-06 23:25:37 +00:00
* Will re - sort a $users results array ( from get_users_by_capability (), usually )
* based on a sorting policy . This is to support the odd practice of
* sorting teachers by 'authority' , where authority was " lowest id of the role
* assignment " .
*
* Will execute 1 database query . Only suitable for small numbers of users , as it
* uses an u . id IN () clause .
*
* Notes about the sorting criteria .
*
* As a default , we cannot rely on role . sortorder because then
* admins / coursecreators will always win . That is why the sane
* rule " is locality matters most " , with sortorder as 2 nd
* consideration .
*
* If you want role . sortorder , use the 'sortorder' policy , and
* name explicitly what roles you want to cover . It ' s probably
* a good idea to see what roles have the capabilities you want
* ( array_diff () them against roiles that have 'can-do-anything'
* to weed out admin - ish roles . Or fetch a list of roles from
2010-03-31 07:41:31 +00:00
* variables like $CFG -> coursemanager .
2008-01-06 23:25:37 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param array $users Users array , keyed on userid
* @ param object $context
* @ param array $roles ids of the roles to include , optional
* @ param string $policy defaults to locality , more about
* @ return array sorted copy of the array
2008-01-06 23:25:37 +00:00
*/
function sort_by_roleassignment_authority ( $users , $context , $roles = array (), $sortpolicy = 'locality' ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2008-01-06 23:25:37 +00:00
$userswhere = ' ra.userid IN (' . implode ( ',' , array_keys ( $users )) . ')' ;
2008-05-24 18:35:48 +00:00
$contextwhere = 'AND ra.contextid IN (' . str_replace ( '/' , ',' , substr ( $context -> path , 1 )) . ')' ;
2008-01-06 23:25:37 +00:00
if ( empty ( $roles )) {
$roleswhere = '' ;
} else {
$roleswhere = ' AND ra.roleid IN (' . implode ( ',' , $roles ) . ')' ;
}
$sql = " SELECT ra.userid
2008-05-24 18:35:48 +00:00
FROM { role_assignments } ra
JOIN { role } r
ON ra . roleid = r . id
JOIN { context } ctx
ON ra . contextid = ctx . id
WHERE $userswhere
$contextwhere
$roleswhere " ;
2008-01-06 23:25:37 +00:00
// Default 'locality' policy -- read PHPDoc notes
// about sort policies...
2008-05-24 18:35:48 +00:00
$orderby = 'ORDER BY '
. 'ctx.depth DESC, ' /* locality wins */
. 'r.sortorder ASC, ' /* rolesorting 2nd criteria */
. 'ra.id' ; /* role assignment order tie-breaker */
2008-01-06 23:25:37 +00:00
if ( $sortpolicy === 'sortorder' ) {
2008-05-24 18:35:48 +00:00
$orderby = 'ORDER BY '
. 'r.sortorder ASC, ' /* rolesorting 2nd criteria */
. 'ra.id' ; /* role assignment order tie-breaker */
2008-01-06 23:25:37 +00:00
}
2008-05-24 18:35:48 +00:00
$sortedids = $DB -> get_fieldset_sql ( $sql . $orderby );
2008-01-06 23:25:37 +00:00
$sortedusers = array ();
$seen = array ();
foreach ( $sortedids as $id ) {
// Avoid duplicates
if ( isset ( $seen [ $id ])) {
continue ;
}
$seen [ $id ] = true ;
// assign
$sortedusers [ $id ] = $users [ $id ];
}
return $sortedusers ;
}
2006-09-12 07:37:23 +00:00
/**
2009-05-19 07:50:54 +00:00
* Gets all the users assigned this role in this context or higher
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $roleid ( can also be an array of ints ! )
* @ param object $context
* @ param bool $parent if true , get list of users assigned in higher context too
* @ 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 . )
2010-03-31 07:41:31 +00:00
* @ param bool $gethidden_ignored use enrolments instead
2009-05-19 07:50:54 +00:00
* @ param string $group defaults to ''
* @ param mixed $limitfrom defaults to ''
* @ param mixed $limitnum defaults to ''
* @ param string $extrawheretest defaults to ''
* @ param string $whereparams defaults to ''
* @ return array
2006-09-12 07:37:23 +00:00
*/
2008-10-30 10:49:15 +00:00
function get_role_users ( $roleid , $context , $parent = false , $fields = '' ,
2010-03-31 07:41:31 +00:00
$sort = 'u.lastname, u.firstname' , $gethidden_ignored = NULL , $group = '' ,
2008-10-30 10:49:15 +00:00
$limitfrom = '' , $limitnum = '' , $extrawheretest = '' , $whereparams = array ()) {
2008-05-24 18:35:48 +00:00
global $DB ;
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, ' .
2008-12-19 08:56:25 +00:00
'u.emailstop, u.lang, u.timezone, u.lastaccess, u.mnethostid, r.name as rolename' ;
2006-10-25 07:20:28 +00:00
}
2007-09-19 07:09:13 +00:00
$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
}
2008-05-24 18:35:48 +00:00
if ( $roleid ) {
list ( $rids , $params ) = $DB -> get_in_or_equal ( $roleid , SQL_PARAMS_QM );
$roleselect = " AND ra.roleid $rids " ;
2006-10-01 08:34:36 +00:00
} else {
2008-05-24 18:35:48 +00:00
$params = array ();
2006-10-01 08:34:36 +00:00
$roleselect = '' ;
}
2007-09-13 13:44:35 +00:00
2007-07-09 06:22:56 +00:00
if ( $group ) {
2008-05-24 18:35:48 +00:00
$groupjoin = " JOIN { groups_members} gm ON gm.userid = u.id " ;
$groupselect = " AND gm.groupid = ? " ;
$params [] = $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
2008-05-24 18:35:48 +00:00
array_unshift ( $params , $context -> id );
2008-10-30 10:49:15 +00:00
if ( $extrawheretest ) {
$extrawheretest = ' AND ' . $extrawheretest ;
$params = array_merge ( $params , $whereparams );
}
2008-05-24 18:35:48 +00:00
$sql = " SELECT $fields , ra.roleid
FROM { role_assignments } ra
JOIN { user } u ON u . id = ra . userid
JOIN { role } r ON ra . roleid = r . id
$groupjoin
WHERE ( ra . contextid = ? $parentcontexts )
$roleselect
$groupselect
2008-10-30 10:49:15 +00:00
$extrawheretest
2008-05-24 18:35:48 +00:00
ORDER BY $sort " ; // join now so that we can just use fullname() later
return $DB -> get_records_sql ( $sql , $params , $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
2009-11-01 11:31:16 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param mixed $roleid either int or an array of ints
* @ param object $context
* @ param bool $parent if true , get list of users assigned in higher context too
* @ return int Returns the result count
2006-09-28 04:42:49 +00:00
*/
function count_role_users ( $roleid , $context , $parent = false ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-28 04:42:49 +00:00
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 = '' ;
}
2008-12-19 08:45:44 +00:00
if ( $roleid ) {
list ( $rids , $params ) = $DB -> get_in_or_equal ( $roleid , SQL_PARAMS_QM );
$roleselect = " AND r.roleid $rids " ;
} else {
$params = array ();
$roleselect = '' ;
}
array_unshift ( $params , $context -> id );
2008-05-24 18:35:48 +00:00
$sql = " SELECT count(u.id)
FROM { role_assignments } r
JOIN { user } u ON u . id = r . userid
WHERE ( r . contextid = ? $parentcontexts )
2008-12-19 08:45:44 +00:00
$roleselect
AND u . deleted = 0 " ;
2006-09-28 04:42:49 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> count_records_sql ( $sql , $params );
2006-09-28 04:42:49 +00:00
}
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 .
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2007-05-14 12:11:47 +00:00
* @ param string $capability Capability in question
2010-03-31 07:41:31 +00:00
* @ param int $userid User ID or NULL for current user
2007-05-14 12:11:47 +00:00
* @ 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 .
*/
2008-05-24 18:35:48 +00:00
function get_user_capability_course ( $capability , $userid = NULL , $doanything = true , $fieldsexceptid = '' , $orderby = '' ) {
global $DB ;
2007-05-14 12:11:47 +00:00
// Convert fields list and ordering
2008-05-24 18:35:48 +00:00
$fieldlist = '' ;
if ( $fieldsexceptid ) {
$fields = explode ( ',' , $fieldsexceptid );
2007-05-14 12:11:47 +00:00
foreach ( $fields as $field ) {
2008-05-24 18:35:48 +00:00
$fieldlist .= ',c.' . $field ;
2007-05-14 12:11:47 +00:00
}
2007-09-13 13:44:35 +00:00
}
2008-05-24 18:35:48 +00:00
if ( $orderby ) {
$fields = explode ( ',' , $orderby );
$orderby = '' ;
2007-05-14 12:11:47 +00:00
foreach ( $fields as $field ) {
if ( $orderby ) {
2008-05-24 18:35:48 +00:00
$orderby .= ',' ;
2007-05-14 12:11:47 +00:00
}
2008-05-24 18:35:48 +00:00
$orderby .= 'c.' . $field ;
2007-05-14 12:11:47 +00:00
}
2008-05-24 18:35:48 +00:00
$orderby = 'ORDER BY ' . $orderby ;
2007-05-14 12:11:47 +00:00
}
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.
2008-05-24 18:35:48 +00:00
if ( ! $rs = $DB -> get_recordset_sql ( " SELECT x.*, c.id AS courseid $fieldlist
FROM { course } c
INNER JOIN { context } x
ON ( c . id = x . instanceid AND x . contextlevel = " .CONTEXT_COURSE. " )
$orderby " )) {
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
2008-05-24 18:35:48 +00:00
$courses = array ();
foreach ( $rs as $coursecontext ) {
if ( has_capability ( $capability , $coursecontext , $userid , $doanything )) {
2007-05-14 12:11:47 +00:00
// We've got the capability. Make the record look like a course record
// and store it
2008-05-24 18:35:48 +00:00
$coursecontext -> id = $coursecontext -> courseid ;
2007-05-14 12:11:47 +00:00
unset ( $coursecontext -> courseid );
unset ( $coursecontext -> contextlevel );
unset ( $coursecontext -> instanceid );
2008-05-24 18:35:48 +00:00
$courses [] = $coursecontext ;
2006-09-19 01:44:33 +00:00
}
}
2008-05-24 18:35:48 +00:00
$rs -> close ();
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
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2006-09-21 03:21:33 +00:00
* @ param object $context
* @ return array
*/
function get_roles_on_exact_context ( $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-21 22:34:45 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> get_records_sql ( " SELECT r.*
FROM { role_assignments } ra , { role } r
WHERE ra . roleid = r . id AND ra . contextid = ? " ,
array ( $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
2009-03-20 07:41:49 +00:00
* - that the requested role can be switched to in this context ( use get_switchable_roles )
2007-09-19 07:05:32 +00:00
* - 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
2008-05-24 18:35:48 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-03-20 07:41:49 +00:00
* @ param integer $roleid the role to switch to .
* @ param object $context the context in which to perform the switch .
* @ return bool success or failure .
2006-09-21 09:16:41 +00:00
*/
function role_switch ( $roleid , $context ) {
2008-05-24 18:35:48 +00:00
global $USER ;
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
2008-05-24 18:35:48 +00:00
//
// - If a switcheroo happens at a category with tons of courses
2007-09-19 07:05:32 +00:00
// (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])
2008-05-24 18:35:48 +00:00
//
// Note: it is not possible to switch to roles that do not have course:view
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 ;
2008-05-24 18:35:48 +00:00
2007-09-19 07:05:32 +00:00
// Load roledefs
$USER -> access = get_role_access_bycontext ( $roleid , $context ,
$USER -> access );
2006-09-21 09:16:41 +00:00
return true ;
}
2008-05-24 18:35:48 +00:00
/**
* Get any role that has an override on exact context
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $context
* @ return array
2008-05-24 18:35:48 +00:00
*/
2006-09-21 06:57:14 +00:00
function get_roles_with_override_on_context ( $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-21 22:34:45 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> get_records_sql ( " SELECT r.*
FROM { role_capabilities } rc , { role } r
WHERE rc . roleid = r . id AND rc . contextid = ? " ,
array ( $context -> id ));
2006-09-21 06:57:14 +00:00
}
2008-05-24 18:35:48 +00:00
/**
2009-05-19 07:50:54 +00:00
* Get all capabilities for this role on this context ( overrides )
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $role
* @ param object $context
* @ return array
2008-05-24 18:35:48 +00:00
*/
2006-09-21 06:57:14 +00:00
function get_capabilities_from_role_on_context ( $role , $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-21 22:34:45 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> get_records_sql ( " SELECT *
FROM { role_capabilities }
WHERE contextid = ? AND roleid = ? " ,
array ( $context -> id , $role -> id ));
2006-09-21 09:09:16 +00:00
}
2008-05-24 18:35:48 +00:00
/**
* Find out which roles has assignment on this context
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $context
* @ return array
*
2008-05-24 18:35:48 +00:00
*/
2006-09-22 01:46:45 +00:00
function get_roles_with_assignment_on_context ( $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-23 12:51:00 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> get_records_sql ( " SELECT r.*
FROM { role_assignments } ra , { role } r
WHERE ra . roleid = r . id AND ra . contextid = ? " ,
array ( $context -> id ));
2006-09-22 01:46:45 +00:00
}
2007-03-05 11:27:01 +00:00
/**
* Find all user assignemnt of users for this role , on this context
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param object $role
* @ param object $context
* @ return array
2006-09-21 09:09:16 +00:00
*/
function get_users_from_role_on_context ( $role , $context ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-09-21 22:34:45 +00:00
2008-05-24 18:35:48 +00:00
return $DB -> get_records_sql ( " SELECT *
FROM { role_assignments }
WHERE contextid = ? AND roleid = ? " ,
array ( $context -> id , $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
2009-11-01 11:31:16 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param int $userid
* @ param int $roleid
* @ param int $contextid
* @ return bool
2006-10-04 07:07:57 +00:00
*/
function user_has_role_assignment ( $userid , $roleid , $contextid = 0 ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2006-10-04 07:07:57 +00:00
if ( $contextid ) {
2008-05-24 18:35:48 +00:00
return $DB -> record_exists ( 'role_assignments' , array ( 'userid' => $userid , 'roleid' => $roleid , 'contextid' => $contextid ));
2006-10-04 07:07:57 +00:00
} else {
2008-05-24 18:35:48 +00:00
return $DB -> record_exists ( 'role_assignments' , array ( 'userid' => $userid , 'roleid' => $roleid ));
2006-10-04 07:07:57 +00:00
}
}
2007-01-12 07:41:33 +00:00
2008-02-21 09:20:20 +00:00
/**
* Get role name or alias if exists and format the text .
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2008-02-21 09:20:20 +00:00
* @ param object $role role object
* @ param object $coursecontext
2009-05-19 07:50:54 +00:00
* @ return string name of role in course context
2008-02-21 09:20:20 +00:00
*/
function role_get_name ( $role , $coursecontext ) {
2008-05-24 18:35:48 +00:00
global $DB ;
if ( $r = $DB -> get_record ( 'role_names' , array ( 'roleid' => $role -> id , 'contextid' => $coursecontext -> id ))) {
2008-02-29 08:44:23 +00:00
return strip_tags ( format_string ( $r -> name ));
2007-03-22 08:11:30 +00:00
} else {
2008-02-21 09:20:20 +00:00
return strip_tags ( format_string ( $role -> name ));
}
}
/**
* Prepare list of roles for display , apply aliases and format text
2009-05-22 02:03:55 +00:00
*
* @ global object
2008-11-13 08:11:10 +00:00
* @ param array $roleoptions array roleid => rolename or roleid => roleobject
* @ param object $context a context
2009-05-19 07:50:54 +00:00
* @ return array Array of context - specific role names , or role objexts with a -> localname field added .
2008-02-21 09:20:20 +00:00
*/
2008-04-18 06:21:00 +00:00
function role_fix_names ( $roleoptions , $context , $rolenamedisplay = ROLENAME_ALIAS ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2008-11-13 08:11:10 +00:00
// Make sure we are working with an array roleid => name. Normally we
// want to use the unlocalised name if the localised one is not present.
$newnames = array ();
foreach ( $roleoptions as $rid => $roleorname ) {
if ( $rolenamedisplay != ROLENAME_ALIAS_RAW ) {
if ( is_object ( $roleorname )) {
$newnames [ $rid ] = $roleorname -> name ;
} else {
$newnames [ $rid ] = $roleorname ;
}
} else {
$newnames [ $rid ] = '' ;
}
}
// If necessary, get the localised names.
2008-04-18 06:21:00 +00:00
if ( $rolenamedisplay != ROLENAME_ORIGINAL && ! empty ( $context -> id )) {
2008-11-13 08:11:10 +00:00
// Make sure we have a course context.
2009-07-13 08:37:34 +00:00
if ( $context -> contextlevel == CONTEXT_MODULE ) {
2008-04-18 06:21:00 +00:00
if ( $parentcontextid = array_shift ( get_parent_contexts ( $context ))) {
$context = get_context_instance_by_id ( $parentcontextid );
}
2009-07-13 08:37:34 +00:00
} else if ( $context -> contextlevel == CONTEXT_BLOCK ) {
do {
if ( $parentcontextid = array_shift ( get_parent_contexts ( $context ))) {
$context = get_context_instance_by_id ( $parentcontextid );
}
} while ( $parentcontextid && $context -> contextlevel != CONTEXT_COURSE );
2008-04-18 06:21:00 +00:00
}
2008-11-13 08:11:10 +00:00
// The get the relevant renames, and use them.
$aliasnames = $DB -> get_records ( 'role_names' , array ( 'contextid' => $context -> id ));
foreach ( $aliasnames as $alias ) {
if ( isset ( $newnames [ $alias -> roleid ])) {
if ( $rolenamedisplay == ROLENAME_ALIAS || $rolenamedisplay == ROLENAME_ALIAS_RAW ) {
$newnames [ $alias -> roleid ] = $alias -> name ;
} else if ( $rolenamedisplay == ROLENAME_BOTH ) {
$newnames [ $alias -> roleid ] = $alias -> name . ' (' . $roleoptions [ $alias -> roleid ] . ')' ;
2008-04-18 06:21:00 +00:00
}
2008-02-21 09:20:20 +00:00
}
}
}
2008-11-13 08:11:10 +00:00
// Finally, apply format_string and put the result in the right place.
foreach ( $roleoptions as $rid => $roleorname ) {
if ( $rolenamedisplay != ROLENAME_ALIAS_RAW ) {
$newnames [ $rid ] = strip_tags ( format_string ( $newnames [ $rid ]));
}
if ( is_object ( $roleorname )) {
$roleoptions [ $rid ] -> localname = $newnames [ $rid ];
} else {
$roleoptions [ $rid ] = $newnames [ $rid ];
}
2007-03-22 08:11:30 +00:00
}
2008-02-21 09:20:20 +00:00
return $roleoptions ;
2007-03-22 08:11:30 +00:00
}
2007-08-02 08:28:29 +00:00
2007-08-16 08:48:53 +00:00
/**
2009-05-19 07:50:54 +00:00
* Aids in detecting if a new line is required when reading a new capability
*
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
2009-05-19 07:50:54 +00:00
* 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 )
2007-08-16 08:48:53 +00:00
* but when we are in grade , all reports / import / export capabilites should be together
2009-05-19 07:50:54 +00:00
*
* @ param string $cap component string a
* @ param string $comp component string b
2009-11-01 11:31:16 +00:00
* @ param mixed $contextlevel
2009-05-19 07:50:54 +00:00
* @ return bool whether 2 component are in different " sections "
2007-08-16 08:48:53 +00:00
*/
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 );
2008-11-27 20:30:14 +00:00
// list of system reports
if (( $compsa [ 0 ] == 'report' ) && ( $compsb [ 0 ] == 'report' )) {
return false ;
}
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
}
2008-11-27 20:30:14 +00:00
if (( $compsa [ 0 ] == 'coursereport' ) && ( $compsb [ 0 ] == 'coursereport' )) {
return false ;
}
2007-08-16 08:48:53 +00:00
}
return ( $cap -> component != $comp || $cap -> contextlevel != $contextlevel );
2007-09-19 07:01:27 +00:00
}
2008-06-16 14:25:53 +00:00
/**
* Rebuild all related context depth and path caches
2009-05-22 02:03:55 +00:00
*
* @ global object
2009-05-19 07:50:54 +00:00
* @ param array $fixcontexts array of contexts , strongtyped
2008-06-16 14:25:53 +00:00
*/
function rebuild_contexts ( array $fixcontexts ) {
global $DB ;
foreach ( $fixcontexts as $context ) {
if ( $context -> path ) {
mark_context_dirty ( $context -> path );
}
$DB -> set_field_select ( 'context' , 'depth' , 0 , " path LIKE '%/ $context->id /%' " );
$DB -> set_field ( 'context' , 'depth' , 0 , array ( 'id' => $context -> id ));
}
build_context_path ( false );
}
2007-09-19 07:01:27 +00:00
/**
2007-09-19 07:29:07 +00:00
* Populate context . path and context . depth where missing .
2009-05-19 07:50:54 +00:00
*
* @ param bool $force force a complete rebuild of the path and depth fields , defaults to false
2007-09-19 07:01:27 +00:00
*/
2008-05-24 18:35:48 +00:00
function build_context_path ( $force = false ) {
global $CFG , $DB ;
2007-09-19 15:51:04 +00:00
2008-02-03 16:23:54 +00:00
// System context
$sitectx = get_system_context ( ! $force );
$base = '/' . $sitectx -> id ;
2007-09-19 07:01:27 +00:00
2007-09-19 07:29:07 +00:00
// Sitecourse
2008-05-24 18:35:48 +00:00
$sitecoursectx = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_COURSE , 'instanceid' => SITEID ));
2007-09-19 07:29:07 +00:00
if ( $force || $sitecoursectx -> path !== " $base / { $sitecoursectx -> id } " ) {
2008-05-24 18:35:48 +00:00
$DB -> set_field ( 'context' , 'path' , " $base / { $sitecoursectx -> id } " , array ( 'id' => $sitecoursectx -> id ));
$DB -> set_field ( 'context' , 'depth' , 2 , array ( 'id' => $sitecoursectx -> id ));
$sitecoursectx = $DB -> get_record ( 'context' , array ( 'contextlevel' => CONTEXT_COURSE , 'instanceid' => SITEID ));
2007-09-19 07:29:07 +00:00
}
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 ) " ;
2008-05-24 18:35:48 +00:00
$emptyclause = " AND ( { context}.path IS NULL
OR { 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
2008-06-22 20:42:19 +00:00
*
* Different code for each database - mostly for performance reasons
2007-09-20 07:37:50 +00:00
*/
2009-11-01 11:31:16 +00:00
$dbfamily = $DB -> get_dbfamily ();
2008-11-05 00:12:30 +00:00
if ( $dbfamily == 'mysql' ) {
2008-05-24 18:35:48 +00:00
$updatesql = " UPDATE { context} ct, { context_temp} temp
2007-09-21 08:52:43 +00:00
SET ct . path = temp . path ,
ct . depth = temp . depth
WHERE ct . id = temp . id " ;
2008-11-05 00:12:30 +00:00
} else if ( $dbfamily == 'oracle' ) {
2008-05-24 18:35:48 +00:00
$updatesql = " UPDATE { context} ct
2007-09-21 08:52:43 +00:00
SET ( ct . path , ct . depth ) =
( SELECT temp . path , temp . depth
2008-05-24 18:35:48 +00:00
FROM { context_temp } temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ct . id )
WHERE EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { context_temp } temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ct . id ) " ;
2008-11-05 00:12:30 +00:00
} else if ( $dbfamily == 'postgres' or $dbfamily == 'mssql' ) {
2008-05-24 18:35:48 +00:00
$updatesql = " UPDATE { context}
2007-09-21 08:52:43 +00:00
SET path = temp . path ,
depth = temp . depth
2008-05-24 18:35:48 +00:00
FROM { context_temp } temp
WHERE temp . id = { context } . id " ;
2008-06-22 20:42:19 +00:00
} else {
// sqlite and others
$updatesql = " UPDATE { context}
SET path = ( SELECT path FROM { context_temp } WHERE id = { context } . id ),
depth = ( SELECT depth FROM { context_temp } WHERE id = { context } . id )
2008-09-06 13:17:15 +00:00
WHERE id IN ( SELECT id FROM mdl_context_temp ) " ;
2007-09-20 01:03:35 +00:00
}
2007-09-20 07:37:50 +00:00
2007-09-19 07:01:27 +00:00
// Top level categories
2008-05-24 18:35:48 +00:00
$sql = " UPDATE { context}
SET depth = 2 , path = " . $DB->sql_concat ( " '$base/' " , 'id') . "
2007-09-20 07:37:50 +00:00
WHERE contextlevel = " .CONTEXT_COURSECAT. "
2007-09-19 19:13:49 +00:00
AND EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { course_categories } cc
WHERE cc . id = { context } . instanceid
2007-09-19 19:13:49 +00:00
AND cc . depth = 1 )
$emptyclause " ;
2007-09-21 08:52:43 +00:00
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2008-05-31 15:32:28 +00:00
$DB -> delete_records ( 'context_temp' );
2007-09-19 15:51:04 +00:00
2007-09-19 07:01:27 +00:00
// Deeper categories - one query per depthlevel
2008-05-24 18:35:48 +00:00
$maxdepth = $DB -> get_field_sql ( " SELECT MAX(depth)
FROM { course_categories } " );
for ( $n = 2 ; $n <= $maxdepth ; $n ++ ) {
2008-05-31 15:32:28 +00:00
$sql = " INSERT INTO { context_temp} (id, path, depth)
2008-05-24 18:35:48 +00:00
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , $n + 1
FROM { context } ctx
JOIN { course_categories } c ON ctx . instanceid = c . id
JOIN { 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'
2008-05-31 15:32:28 +00:00
FROM { context_temp } temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-10-26 07:58:23 +00:00
// this is needed after every loop
// MDL-11532
2008-05-24 18:35:48 +00:00
$DB -> execute ( $updatesql );
2008-05-31 15:32:28 +00:00
$DB -> delete_records ( 'context_temp' );
2007-09-19 07:01:27 +00:00
}
// Courses -- except sitecourse
2008-05-31 15:32:28 +00:00
$sql = " INSERT INTO { context_temp} (id, path, depth)
2008-05-24 18:35:48 +00:00
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1
FROM { context } ctx
JOIN { course } c ON ctx . instanceid = c . id
JOIN { context } pctx ON c . category = pctx . instanceid
2007-09-19 19:01:32 +00:00
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'
2008-05-31 15:32:28 +00:00
FROM { context_temp } temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-09-19 15:51:04 +00:00
2008-05-24 18:35:48 +00:00
$DB -> execute ( $updatesql );
2008-05-31 15:32:28 +00:00
$DB -> delete_records ( 'context_temp' );
2007-09-19 07:01:27 +00:00
// Module instances
2008-05-31 15:32:28 +00:00
$sql = " INSERT INTO { context_temp} (id, path, depth)
2008-05-24 18:35:48 +00:00
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1
FROM { context } ctx
JOIN { course_modules } cm ON ctx . instanceid = cm . id
JOIN { 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'
2008-05-31 15:32:28 +00:00
FROM { context_temp } temp
2007-09-21 08:52:43 +00:00
WHERE temp . id = ctx . id )
2007-09-20 00:16:22 +00:00
$ctxemptyclause " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-09-19 15:51:04 +00:00
2008-05-24 18:35:48 +00:00
$DB -> execute ( $updatesql );
2008-05-31 15:32:28 +00:00
$DB -> delete_records ( 'context_temp' );
2007-09-19 07:01:27 +00:00
// User
2008-05-24 18:35:48 +00:00
$sql = " UPDATE { context}
SET depth = 2 , path = " . $DB->sql_concat ( " '$base/' " , 'id'). "
2007-09-19 19:01:32 +00:00
WHERE contextlevel = " .CONTEXT_USER. "
2007-09-19 19:13:49 +00:00
AND EXISTS ( SELECT 'x'
2008-05-24 18:35:48 +00:00
FROM { user } u
WHERE u . id = { context } . instanceid )
2007-09-19 19:13:49 +00:00
$emptyclause " ;
2008-05-24 18:35:48 +00:00
$DB -> execute ( $sql );
2007-10-05 15:06:38 +00:00
2009-05-07 07:05:22 +00:00
// Blocks
$sql = " INSERT INTO { context_temp} (id, path, depth)
SELECT ctx . id , " . $DB->sql_concat ('pctx.path', " '/' " , 'ctx.id'). " , pctx . depth + 1
FROM { context } ctx
JOIN { block_instances } bi ON ctx . instanceid = bi . id
2009-07-10 05:58:59 +00:00
JOIN { context } pctx ON bi . parentcontextid = pctx . id
2009-05-07 07:05:22 +00:00
WHERE ctx . contextlevel = " .CONTEXT_BLOCK. "
AND NOT EXISTS ( SELECT 'x'
FROM { context_temp } temp
WHERE temp . id = ctx . id )
$ctxemptyclause " ;
$DB -> execute ( $sql );
$DB -> execute ( $updatesql );
$DB -> delete_records ( 'context_temp' );
2007-10-05 15:06:38 +00:00
// reset static course cache - it might have incorrect cached data
2009-03-23 03:54:50 +00:00
global $ACCESSLIB_PRIVATE ;
$ACCESSLIB_PRIVATE -> contexts = array ();
$ACCESSLIB_PRIVATE -> contextsbyid = array ();
2007-08-16 08:48:53 +00:00
}
2007-09-19 07:13:33 +00:00
/**
2009-05-19 07:50:54 +00:00
* Update the path field of the context and all dep . subcontexts that follow
*
2007-09-19 07:13:33 +00:00
* Update the path field of the context and
* all the dependent subcontexts that follow
2008-05-24 18:35:48 +00:00
* the move .
2007-09-19 07:13:33 +00:00
*
* The most important thing here is to be as
* DB efficient as possible . This op can have a
* massive impact in the DB .
*
2009-05-22 02:03:55 +00:00
* @ global object
2009-05-19 07:50:54 +00:00
* @ param obj $current context obj
* @ param obj $newparent new parent obj
2007-09-19 07:13:33 +00:00
*
*/
function context_moved ( $context , $newparent ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2007-09-19 07:13:33 +00:00
$frompath = $context -> path ;
$newpath = $newparent -> path . '/' . $context -> id ;
$setdepth = '' ;
2007-09-19 07:14:11 +00:00
if (( $newparent -> depth + 1 ) != $context -> depth ) {
2008-05-24 18:35:48 +00:00
$diff = $newparent -> depth - $context -> depth + 1 ;
$setdepth = " , depth = depth + $diff " ;
2007-09-19 07:13:33 +00:00
}
2008-05-24 18:35:48 +00:00
$sql = " UPDATE { context}
SET path = ?
$setdepth
WHERE path = ? " ;
$params = array ( $newpath , $frompath );
$DB -> execute ( $sql , $params );
2007-09-19 07:13:33 +00:00
2008-05-24 18:35:48 +00:00
$sql = " UPDATE { context}
2008-10-28 15:11:10 +00:00
SET path = " . $DB->sql_concat ( " ? " , $DB->sql_substr ( " path " , strlen( $frompath )+1)). "
2008-05-24 18:35:48 +00:00
$setdepth
WHERE path LIKE ? " ;
$params = array ( $newpath , " { $frompath } /% " );
$DB -> execute ( $sql , $params );
2007-09-19 07:13:33 +00:00
mark_context_dirty ( $frompath );
mark_context_dirty ( $newpath );
}
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
/**
2010-03-31 07:41:31 +00:00
* Preloads context information together with instances .
* NOTE : in future this function may return empty strings
* if we implement different caching .
*
* @ param string $joinon for example 'u.id'
* @ param string $contextlevel context level of instance in $joinon
* @ param string $tablealias context table alias
* @ return array with two values - select and join part
*/
function context_instance_preload_sql ( $joinon , $contextlevel , $tablealias ) {
$select = " , $tablealias .id AS ctxid, $tablealias .path AS ctxpath, $tablealias .depth AS ctxdepth, $tablealias .contextlevel AS ctxlevel, $tablealias .instanceid AS ctxinstance " ;
$join = " LEFT JOIN { context} $tablealias ON ( $tablealias .instanceid = $joinon AND $tablealias .contextlevel = $contextlevel ) " ;
return array ( $select , $join );
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
}
/**
2010-03-31 07:41:31 +00:00
* Preloads context information from db record and strips the cached info .
* The db request has to ontain both the $join and $select from context_instance_preload_sql ()
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
*
2010-03-31 07:41:31 +00:00
* @ param object $rec
* @ return void ( modifies $rec )
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
*/
2010-03-31 07:41:31 +00:00
function context_instance_preload ( stdClass $rec ) {
if ( empty ( $rec -> ctxid )) {
// $rec does not have enough data, passed here repeatedly or context does not exist yet
return ;
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
}
2010-03-31 07:41:31 +00:00
// note: in PHP5 the objects are passed by reference, no need to return $rec
$context = new object ();
$context -> id = $rec -> ctxid ; unset ( $rec -> ctxid );
$context -> path = $rec -> ctxpath ; unset ( $rec -> ctxpath );
$context -> depth = $rec -> ctxdepth ; unset ( $rec -> ctxdepth );
$context -> contextlevel = $rec -> ctxlevel ; unset ( $rec -> ctxlevel );
$context -> instanceid = $rec -> ctxinstance ; unset ( $rec -> ctxinstance );
cache_context ( $context );
course categories: Fix many bugs with category editing and permissions. Clean up code.
Bugs: MDL-17479, MDL-16426, MDL-16063, MDL-16013, MDL-15658, MDL-15556, MDL-15161, MDL-14925, MDL-13742, MDL-11557.
* Simplify category editing permissions to just moodle/category:manage and moodle/category:seehiddencategories.
* Enforce those correctly. (Note MDL 17502 is still outstanding.)
* Don't screw up category sort order when you just edit name or description.
* Niceties like where redirects go when you cancel or submit forms.
* Make sure a global course creator can see the site admin block.
* Don't allow a category to be made the child of one of its children!
* General code cleanup to bring key files more in line with best pracitice.
Apologies for the fact it is one big patch, rather than a series of smaller patches. However, categoryedit.php, category.php and index.php where in pretty bad shape and needed significant cleaning up. categoryedit.php, in particular, was almost completely rewritten.
Merged from MOODLE_19_STABLE.
2008-12-04 08:53:10 +00:00
}
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
2009-05-19 07:50:54 +00:00
* @ return array 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 .
2009-05-19 07:50:54 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
* @ global object
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 ) {
2009-03-23 03:54:50 +00:00
global $CFG , $ACCESSLIB_PRIVATE ;
2009-01-12 16:52:53 +00:00
2009-06-24 09:17:56 +00:00
if ( during_initial_install ()) {
2009-01-12 16:52:53 +00:00
return ;
}
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 );
2009-03-23 03:54:50 +00:00
if ( isset ( $ACCESSLIB_PRIVATE -> dirtycontexts )) {
$ACCESSLIB_PRIVATE -> dirtycontexts [ $path ] = 1 ;
2007-10-09 12:49:54 +00:00
}
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
2009-05-19 07:50:54 +00:00
* @ param obj | array $dirty Dirty contexts from get_dirty_contexts ()
2007-10-09 12:49:54 +00:00
* @ 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-12-18 20:51:07 +00:00
/**
2008-11-14 10:38:06 +00:00
* Fix the roles . sortorder field in the database , so it contains sequential integers ,
* and return an array of roleids in order .
2008-05-24 18:35:48 +00:00
*
2008-11-14 10:38:06 +00:00
* @ param array $allroles array of roles , as returned by get_all_roles ();
* @ return array $role -> sortorder =-> $role -> id with the keys in ascending order .
*/
function fix_role_sortorder ( $allroles ) {
$rolesort = array ();
$i = 0 ;
foreach ( $allroles as $role ) {
$rolesort [ $i ] = $role -> id ;
if ( $role -> sortorder != $i ) {
$r = new object ();
$r -> id = $role -> id ;
$r -> sortorder = $i ;
$DB -> update_record ( 'role' , $r );
$allroles [ $role -> id ] -> sortorder = $i ;
}
$i ++ ;
}
return $rolesort ;
}
/**
2008-11-18 07:10:00 +00:00
* Switch the sort order of two roles ( used in admin / roles / manage . php ) .
2007-12-18 20:51:07 +00:00
*
2009-05-22 02:03:55 +00:00
* @ global object
2008-11-18 07:10:00 +00:00
* @ param object $first The first role . Actually , only -> sortorder is used .
* @ param object $second The second role . Actually , only -> sortorder is used .
* @ return boolean success or failure
2007-12-18 20:51:07 +00:00
*/
function switch_roles ( $first , $second ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2008-11-18 07:10:00 +00:00
$temp = $DB -> get_field ( 'role' , 'MAX(sortorder) + 1' , array ());
$result = $DB -> set_field ( 'role' , 'sortorder' , $temp , array ( 'sortorder' => $first -> sortorder ));
$result = $result && $DB -> set_field ( 'role' , 'sortorder' , $first -> sortorder , array ( 'sortorder' => $second -> sortorder ));
$result = $result && $DB -> set_field ( 'role' , 'sortorder' , $second -> sortorder , array ( 'sortorder' => $temp ));
return $result ;
2007-12-18 20:51:07 +00:00
}
/**
* duplicates all the base definitions of a role
*
2009-05-22 02:03:55 +00:00
* @ global object
2007-12-19 23:32:53 +00:00
* @ param object $sourcerole role to copy from
2007-12-18 20:51:07 +00:00
* @ param int $targetrole id of role to copy to
*/
function role_cap_duplicate ( $sourcerole , $targetrole ) {
2008-05-24 18:35:48 +00:00
global $DB ;
2007-12-18 20:51:07 +00:00
$systemcontext = get_context_instance ( CONTEXT_SYSTEM );
2008-05-24 18:35:48 +00:00
$caps = $DB -> get_records_sql ( " SELECT *
FROM { role_capabilities }
WHERE roleid = ? AND contextid = ? " ,
2008-05-29 15:07:05 +00:00
array ( $sourcerole -> id , $systemcontext -> id ));
2007-12-18 20:51:07 +00:00
// adding capabilities
foreach ( $caps as $cap ) {
unset ( $cap -> id );
$cap -> roleid = $targetrole ;
2008-05-24 18:35:48 +00:00
$DB -> insert_record ( 'role_capabilities' , $cap );
2007-12-18 20:51:07 +00:00
}
2008-05-24 18:35:48 +00:00
}
2010-03-07 09:28:54 +00:00
/**
* Returns two lists , this can be used to find out if user has capability .
* Having any neede role and no forbidden role in this context means
* user has this capability in this context ,
*
* @ param object $context
* @ param string $capability
* @ return array ( $neededroles , $forbiddenroles )
*/
function get_roles_with_cap_in_context ( $context , $capability ) {
global $DB ;
$ctxids = trim ( $context -> path , '/' ); // kill leading slash
$ctxids = str_replace ( '/' , ',' , $ctxids );
$sql = " SELECT rc.id, rc.roleid, rc.permission, ctx.depth
FROM { role_capabilities } rc
JOIN { context } ctx ON ctx . id = rc . contextid
WHERE rc . capability = : cap AND ctx . id IN ( $ctxids )
ORDER BY rc . roleid ASC , ctx . depth DESC " ;
$params = array ( 'cap' => $capability );
if ( ! $capdefs = $DB -> get_records_sql ( $sql , $params )) {
// no cap definitions --> no capability
return array ( array (), array ());
}
$forbidden = array ();
$needed = array ();
foreach ( $capdefs as $def ) {
if ( isset ( $forbidden [ $def -> roleid ])) {
continue ;
}
if ( $def -> permission == CAP_PROHIBIT ) {
$forbidden [ $def -> roleid ] = $def -> roleid ;
unset ( $needed [ $def -> roleid ]);
continue ;
}
if ( ! isset ( $needed [ $def -> roleid ])) {
if ( $def -> permission == CAP_ALLOW ) {
$needed [ $def -> roleid ] = true ;
} else if ( $def -> permission == CAP_PREVENT ) {
$needed [ $def -> roleid ] = false ;
}
}
}
unset ( $capdefs );
// remove all those roles not allowing
foreach ( $needed as $key => $value ) {
if ( ! $value ) {
unset ( $needed [ $key ]);
} else {
$needed [ $key ] = $key ;
}
}
return array ( $needed , $forbidden );
}
/**
* This function verifies the prohibit comes from this context
* and there are no more prohibits in parent contexts .
* @ param object $context
* @ param string $capability name
* @ return bool
*/
function prohibit_is_removable ( $roleid , $context , $capability ) {
global $DB ;
$ctxids = trim ( $context -> path , '/' ); // kill leading slash
$ctxids = str_replace ( '/' , ',' , $ctxids );
$params = array ( 'roleid' => $roleid , 'cap' => $capability , 'prohibit' => CAP_PROHIBIT );
$sql = " SELECT ctx.id
FROM { role_capabilities } rc
JOIN { context } ctx ON ctx . id = rc . contextid
WHERE rc . roleid = : roleid AND rc . permission = : prohibit AND rc . capability = : cap AND ctx . id IN ( $ctxids )
ORDER BY ctx . depth DESC " ;
if ( ! $prohibits = $DB -> get_records_sql ( $sql , $params )) {
// no prohibits == nothing to remove
return true ;
}
if ( count ( $prohibits ) > 1 ) {
// more prohibints can not be removed
return false ;
}
return ! empty ( $prohibits [ $context -> id ]);
}
/**
* More user friendly role permission changing ,
* it should produce as few overrides as possible .
* @ param int $roleid
* @ param object $context
* @ param string $capname capability name
* @ param int $permission
* @ return void
*/
function role_change_permission ( $roleid , $context , $capname , $permission ) {
global $DB ;
if ( $permission == CAP_INHERIT ) {
unassign_capability ( $capname , $roleid , $context -> id );
mark_context_dirty ( $context -> path );
return ;
}
$ctxids = trim ( $context -> path , '/' ); // kill leading slash
$ctxids = str_replace ( '/' , ',' , $ctxids );
$params = array ( 'roleid' => $roleid , 'cap' => $capname );
$sql = " SELECT ctx.id, rc.permission, ctx.depth
FROM { role_capabilities } rc
JOIN { context } ctx ON ctx . id = rc . contextid
WHERE rc . roleid = : roleid AND rc . capability = : cap AND ctx . id IN ( $ctxids )
ORDER BY ctx . depth DESC " ;
if ( $existing = $DB -> get_records_sql ( $sql , $params )) {
foreach ( $existing as $e ) {
if ( $e -> permission == CAP_PROHIBIT ) {
// prohibit can not be overridden, no point in changing anything
return ;
}
}
$lowest = array_shift ( $existing );
if ( $lowest -> permission == $permission ) {
// permission already set in this context or parent - nothing to do
return ;
}
if ( $existing ) {
$parent = array_shift ( $existing );
if ( $parent -> permission == $permission ) {
// permission already set in parent context or parent - just unset in this context
// we do this because we want as few overrides as possible for performance reasons
unassign_capability ( $capname , $roleid , $context -> id );
mark_context_dirty ( $context -> path );
return ;
}
}
} else {
if ( $permission == CAP_PREVENT ) {
// nothing means role does not have permission
return ;
}
}
// assign the needed capability
assign_capability ( $capname , $permission , $roleid , $context -> id , true );
// force cap reloading
mark_context_dirty ( $context -> path );
}