/** * It add to the access ctrl array the data * needed by a user for a given context * * @param $userid integer - the id of the user * @param $context context obj - needs path! * @param $accessdata array accessdata array */ function load_subcontext($userid, $context, &$accessdata) { global $CFG, $DB; /* Get the additional RAs and relevant rolecaps * - role assignments - with role_caps * - relevant role caps * - above this user's RAs * - below this user's RAs - limited to course level */ $base = "/" . SYSCONTEXTID; // // 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 // // - 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. // if ($context->contextlevel !== CONTEXT_COURSE && $context->path !== "{$base}/{$context->id}") { // Case BLOCK/MODULE/GROUP hanging from a course // 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 $courses = explode('/', get_course_from_path($context->path)); $targetid = array_pop($courses); $context = get_context_instance_by_id($targetid); } // // Role assignments in the context and below // $sql = "SELECT ctx.path, ra.roleid\n FROM {role_assignments} ra\n JOIN {context} ctx\n ON ra.contextid=ctx.id\n WHERE ra.userid = ?\n AND (ctx.path = ? OR ctx.path LIKE ?)\n ORDER BY ctx.depth, ctx.path, ra.roleid"; $params = array($userid, $context->path, $context->path . "/%"); $rs = $DB->get_recordset_sql($sql, $params); // // Read in the RAs, preventing duplicates // if ($rs) { $localroles = array(); $lastseen = ''; foreach ($rs as $ra) { if (!isset($accessdata['ra'][$ra->path])) { $accessdata['ra'][$ra->path] = array(); } // only add if is not a repeat caused // by capability join... // (this check is cheaper than in_array()) if ($lastseen !== $ra->path . ':' . $ra->roleid) { $lastseen = $ra->path . ':' . $ra->roleid; array_push($accessdata['ra'][$ra->path], $ra->roleid); array_push($localroles, $ra->roleid); } } $rs->close(); } // // Walk up and down the tree to grab all the roledefs // of interest to our user... // // NOTES // - we use IN() but the number of roles is very limited. // $courseroles = aggregate_roles_from_accessdata($context, $accessdata); // Do we have any interesting "local" roles? $localroles = array_diff($localroles, $courseroles); // only "new" local roles $wherelocalroles = ''; if (count($localroles)) { // Role defs for local roles in 'higher' contexts... $contexts = substr($context->path, 1); // kill leading slash $contexts = str_replace('/', ',', $contexts); $localroleids = implode(',', $localroles); $wherelocalroles = "OR (rc.roleid IN ({$localroleids})\n AND ctx.id IN ({$contexts}))"; } // We will want overrides for all of them $whereroles = ''; if ($roleids = implode(',', array_merge($courseroles, $localroles))) { $whereroles = "rc.roleid IN ({$roleids}) AND"; } $sql = "SELECT ctx.path, rc.roleid, rc.capability, rc.permission\n FROM {role_capabilities} rc\n JOIN {context} ctx\n ON rc.contextid=ctx.id\n WHERE ({$whereroles}\n (ctx.id=? OR ctx.path LIKE ?))\n {$wherelocalroles}\n ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC "; $params = array($context->id, $context->path . "/%"); $newrdefs = array(); if ($rs = $DB->get_recordset_sql($sql, $params)) { foreach ($rs as $rd) { $k = "{$rd->path}:{$rd->roleid}"; if (!array_key_exists($k, $newrdefs)) { $newrdefs[$k] = array(); } $newrdefs[$k][$rd->capability] = $rd->permission; } $rs->close(); } else { debugging('Bad SQL encountered!'); } compact_rdefs($newrdefs); foreach ($newrdefs as $key => $value) { $accessdata['rdef'][$key] =& $newrdefs[$key]; } // error_log("loaded {$context->path}"); $accessdata['loaded'][] = $context->path; }
/** * It add to the access ctrl array the data * needed by a user for a given context * * @param $userid integer - the id of the user * @param $context context obj - needs path! * @param $accessdata array accessdata array * */ function get_user_access_bycontext($userid, $context, $accessdata = NULL) { global $CFG; /* Get the additional RAs and relevant rolecaps * - role assignments - with role_caps * - relevant role caps * - above this user's RAs * - below this user's RAs - limited to course level */ // Roles already in use in this context if (is_null($accessdata)) { $accessdata = array(); // named list $accessdata['ra'] = array(); $accessdata['rdef'] = array(); $accessdata['loaded'] = array(); } $base = "/" . SYSCONTEXTID; // // 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 // // - 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. // if ($context->contextlevel !== CONTEXT_COURSE && $context->path !== "{$base}/{$context->id}") { // Case BLOCK/MODULE/GROUP hanging from a course // 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 $targetid = array_pop(explode('/', get_course_from_path($context->path))); $context = get_context_instance_by_id($targetid); } // // Role assignments in the context and below // $sql = "SELECT ctx.path, ra.roleid\n FROM {$CFG->prefix}role_assignments ra\n JOIN {$CFG->prefix}context ctx\n ON ra.contextid=ctx.id\n WHERE ra.userid = {$userid}\n AND (ctx.path = '{$context->path}' OR ctx.path LIKE '{$context->path}/%')\n ORDER BY ctx.depth, ctx.path"; $rs = get_recordset_sql($sql); // // Read in the RAs // $localroles = array(); if ($rs->RecordCount()) { while ($ra = rs_fetch_next_record($rs)) { if (!isset($accessdata['ra'][$ra->path])) { $accessdata['ra'][$ra->path] = array(); } array_push($accessdata['ra'][$ra->path], $ra->roleid); array_push($localroles, $ra->roleid); } } rs_close($rs); // // Walk up and down the tree to grab all the roledefs // of interest to our user... // // NOTES // - we use IN() but the number of roles is very limited. // $courseroles = aggregate_roles_from_accessdata($context, $accessdata); // Do we have any interesting "local" roles? $localroles = array_diff($localroles, $courseroles); // only "new" local roles $wherelocalroles = ''; if (count($localroles)) { // Role defs for local roles in 'higher' contexts... $contexts = substr($context->path, 1); // kill leading slash $contexts = str_replace('/', ',', $contexts); $localroleids = implode(',', $localroles); $wherelocalroles = "OR (rc.roleid IN ({$localroleids}) \n AND ctx.id IN ({$contexts}))"; } // We will want overrides for all of them $whereroles = ''; if ($roleids = implode(',', array_merge($courseroles, $localroles))) { $whereroles = "rc.roleid IN ({$roleids}) AND"; } $sql = "SELECT ctx.path, rc.roleid, rc.capability, rc.permission\n FROM {$CFG->prefix}role_capabilities rc\n JOIN {$CFG->prefix}context ctx\n ON rc.contextid=ctx.id\n WHERE ({$whereroles}\n (ctx.id={$context->id} OR ctx.path LIKE '{$context->path}/%'))\n {$wherelocalroles}\n ORDER BY ctx.depth ASC, ctx.path DESC, rc.roleid ASC "; if ($rs = get_recordset_sql($sql)) { if ($rs->RecordCount()) { while ($rd = rs_fetch_next_record($rs)) { $k = "{$rd->path}:{$rd->roleid}"; $accessdata['rdef'][$k][$rd->capability] = $rd->permission; } } rs_close($rs); } else { debugging('Bad SQL encountered!'); } // TODO: compact capsets? error_log("loaded {$context->path}"); $accessdata['loaded'][] = $context->path; return $accessdata; }