/** * Loads all of the course sections into the navigation * * @param global_navigation $navigation * @param navigation_node $node The course node within the navigation */ public function extend_course_navigation($navigation, navigation_node $node) { // Display orphaned activities for the users who can see them. $context = context_course::instance($this->courseid); if (has_all_capabilities(array('moodle/course:viewhiddensections', 'moodle/course:viewhiddenactivities'), $context)) { $modinfo = get_fast_modinfo($this->courseid); if (!empty($modinfo->sections[1])) { $section1 = $modinfo->get_section_info(1); // Show orphaned activities. $orphanednode = $node->add(get_string('orphaned', 'format_singleactivity'), $this->get_view_url(1), navigation_node::TYPE_SECTION, null, $section1->id); $orphanednode->nodetype = navigation_node::NODETYPE_BRANCH; $orphanednode->add_class('orphaned'); foreach ($modinfo->sections[1] as $cmid) { $this->navigation_add_activity($orphanednode, $modinfo->cms[$cmid]); } } } }
/** * Returns the list of all editing actions that current user can perform on the module * * @param cm_info $mod The module to produce editing buttons for * @param int $indent The current indenting (default -1 means no move left-right actions) * @param int $sr The section to link back to (used for creating the links) * @return array array of action_link or pix_icon objects */ function course_get_cm_edit_actions_reduced(cm_info $mod, $indent = -1, $sr = null) { global $COURSE, $SITE; static $str; $coursecontext = context_course::instance($mod->course); $modcontext = context_module::instance($mod->id); $editcaps = array('moodle/course:manageactivities', 'moodle/course:activityvisibility', 'moodle/role:assign'); $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); //No permission to edit anything. if (!has_any_capability($editcaps, $modcontext) and !has_all_capabilities($dupecaps, $coursecontext)) { return array(); } $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext); if (!isset($str)) { $str = get_strings(array('delete', 'move', 'moveright', 'moveleft', 'editsettings', 'duplicate', 'hide', 'show'), 'moodle'); $str->assign = get_string('assignroles', 'role'); $str->groupsnone = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsnone")); $str->groupsseparate = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsseparate")); $str->groupsvisible = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsvisible")); } $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey())); if ($sr !== null) { $baseurl->param('sr', $sr); } $actions = array(); // Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php) // Note that restoring on front page is never allowed. if ($mod->course != SITEID && has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) { $actions['duplicate'] = new action_menu_link_secondary(new moodle_url($baseurl, array('duplicate' => $mod->id)), new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->duplicate, array('class' => 'editing_duplicate', 'data-action' => 'duplicate', 'data-sr' => $sr)); } // Delete. if ($hasmanageactivities) { $actions['delete'] = new action_menu_link_secondary(new moodle_url($baseurl, array('delete' => $mod->id)), new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->delete, array('class' => 'editing_delete', 'data-action' => 'delete')); } return $actions; }
/** * This function returns a nice list representing category tree * for display or to use in a form <select> element * * List is cached for 10 minutes * * For example, if you have a tree of categories like: * Miscellaneous (id = 1) * Subcategory (id = 2) * Sub-subcategory (id = 4) * Other category (id = 3) * Then after calling this function you will have * array(1 => 'Miscellaneous', * 2 => 'Miscellaneous / Subcategory', * 4 => 'Miscellaneous / Subcategory / Sub-subcategory', * 3 => 'Other category'); * * If you specify $requiredcapability, then only categories where the current * user has that capability will be added to $list. * If you only have $requiredcapability in a child category, not the parent, * then the child catgegory will still be included. * * If you specify the option $excludeid, then that category, and all its children, * are omitted from the tree. This is useful when you are doing something like * moving categories, where you do not want to allow people to move a category * to be the child of itself. * * See also {@link make_categories_options()} * * @param string/array $requiredcapability if given, only categories where the current * user has this capability will be returned. Can also be an array of capabilities, * in which case they are all required. * @param integer $excludeid Exclude this category and its children from the lists built. * @param string $separator string to use as a separator between parent and child category. Default ' / ' * @return array of strings */ public static function make_categories_list($requiredcapability = '', $excludeid = 0, $separator = ' / ') { global $DB; $coursecatcache = cache::make('core', 'coursecat'); // Check if we cached the complete list of user-accessible category names ($baselist) or list of ids with requried cap ($thislist). $basecachekey = 'catlist'; $baselist = $coursecatcache->get($basecachekey); if ($baselist !== false) { $baselist = false; } $thislist = false; if (!empty($requiredcapability)) { $requiredcapability = (array) $requiredcapability; $thiscachekey = 'catlist:' . serialize($requiredcapability); if ($baselist !== false && ($thislist = $coursecatcache->get($thiscachekey)) !== false) { $thislist = preg_split('|,|', $thislist, -1, PREG_SPLIT_NO_EMPTY); } } else { if ($baselist !== false) { $thislist = array_keys($baselist); } } if ($baselist === false) { // We don't have $baselist cached, retrieve it. Retrieve $thislist again in any case. $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT cc.id, cc.sortorder, cc.name, cc.visible, cc.parent, cc.path, {$ctxselect}\n FROM {course_categories} cc\n JOIN {context} ctx ON cc.id = ctx.instanceid AND ctx.contextlevel = :contextcoursecat\n ORDER BY cc.sortorder"; $rs = $DB->get_recordset_sql($sql, array('contextcoursecat' => CONTEXT_COURSECAT)); $baselist = array(); $thislist = array(); foreach ($rs as $record) { // If the category's parent is not visible to the user, it is not visible as well. if (!$record->parent || isset($baselist[$record->parent])) { $context = context_coursecat::instance($record->id); if (!$record->visible && !has_capability('moodle/category:viewhiddencategories', $context)) { // No cap to view category, added to neither $baselist nor $thislist continue; } $baselist[$record->id] = array('name' => format_string($record->name, true, array('context' => $context)), 'path' => $record->path); if (!empty($requiredcapability) && !has_all_capabilities($requiredcapability, $context)) { // No required capability, added to $baselist but not to $thislist. continue; } $thislist[] = $record->id; } } $rs->close(); $coursecatcache->set($basecachekey, $baselist); if (!empty($requiredcapability)) { $coursecatcache->set($thiscachekey, join(',', $thislist)); } } else { if ($thislist === false) { // We have $baselist cached but not $thislist. Simplier query is used to retrieve. $ctxselect = context_helper::get_preload_record_columns_sql('ctx'); $sql = "SELECT ctx.instanceid id, {$ctxselect}\n FROM {context} ctx WHERE ctx.contextlevel = :contextcoursecat"; $contexts = $DB->get_records_sql($sql, array('contextcoursecat' => CONTEXT_COURSECAT)); $thislist = array(); foreach (array_keys($baselist) as $id) { context_helper::preload_from_record($contexts[$id]); if (has_all_capabilities($requiredcapability, context_coursecat::instance($id))) { $thislist[] = $id; } } $coursecatcache->set($thiscachekey, join(',', $thislist)); } } // Now build the array of strings to return, mind $separator and $excludeid. $names = array(); foreach ($thislist as $id) { $path = preg_split('|/|', $baselist[$id]['path'], -1, PREG_SPLIT_NO_EMPTY); if (!$excludeid || !in_array($excludeid, $path)) { $namechunks = array(); foreach ($path as $parentid) { $namechunks[] = $baselist[$parentid]['name']; } $names[$id] = join($separator, $namechunks); } } return $names; }
/** * @param $list * @param $parents * @param string $requiredcapability * @param int $excludeid * @param null $category * @param string $path * @return mixed */ function make_categories_manager_list(&$list, &$parents, $requiredcapability = '', $excludeid = 0, $category = null, $path = "") { $requiredcapability = ''; // Initialize the arrays if needed. if (!is_array($list)) { $list = array(); } if (!is_array($parents)) { $parents = array(); } if (empty($category)) { // Start at the top level. $category = new stdClass(); $category->id = 0; } else { // This is the excluded category, don't include it. if ($excludeid > 0 && $excludeid == $category->id) { return; } $context = context_coursecat::instance($category->id); $categoryname = format_string($category->name, true, array('context' => $context)); // Update $path. if ($path) { $path = $path . ' / ' . $categoryname; } else { $path = $categoryname; } // Add this category to $list, if the permissions check out. if (empty($requiredcapability)) { $list[$category->id] = $path; } else { $requiredcapability = (array) $requiredcapability; if (has_all_capabilities($requiredcapability, $context)) { $list[$category->id] = $path; } } } // Add all the children recursively, while updating the parents array. if ($categories = get_child_manager_categories($category->id)) { foreach ($categories as $cat) { if (!empty($category->id)) { if (isset($parents[$category->id])) { $parents[$cat->id] = $parents[$category->id]; } $parents[$cat->id][] = $category->id; } make_categories_manager_list($list, $parents, $requiredcapability, $excludeid, $cat, $path); } } }
/** * Executes the search * * @global moodle_database $DB * @return int The number of results */ final public function search() { global $DB; if (!is_null($this->results)) { return $this->results; } $this->results = array(); $this->totalcount = 0; $contextlevel = $this->get_itemcontextlevel(); list($sql, $params) = $this->get_searchsql(); $blocksz = 5000; $offs = 0; // Get total number, to avoid some incorrect iterations $countsql = preg_replace('/ORDER BY.*/', '', $sql); $totalcourses = $DB->count_records_sql("SELECT COUNT(*) FROM ($countsql) sel", $params); // User to be checked is always the same (usually null, get it form first element) $firstcap = reset($this->requiredcapabilities); $userid = isset($firstcap['user']) ? $firstcap['user'] : null; // Extract caps to check, this saves us a bunch of iterations $requiredcaps = array(); foreach ($this->requiredcapabilities as $cap) { $requiredcaps[] = $cap['capability']; } // Iterate while we have records and haven't reached $this->maxresults. while ($totalcourses > $offs and $this->totalcount < self::$MAXRESULTS) { $resultset = $DB->get_records_sql($sql, $params, $offs, $blocksz); foreach ($resultset as $result) { context_instance_preload($result); $context = get_context_instance($contextlevel, $result->id); if (count($requiredcaps) > 0) { if (!has_all_capabilities($requiredcaps, $context, $userid)) { continue; } } // Check if we are over the limit. if ($this->totalcount+1 > self::$MAXRESULTS) { $this->hasmoreresults = true; break; } // If not, then continue. $this->totalcount++; $this->results[$result->id] = $result; } $offs += $blocksz; } return $this->totalcount; }
/** * Produces the editing buttons for a module * * @global core_renderer $OUTPUT * @staticvar type $str * @param stdClass $mod The module to produce editing buttons for * @param bool $absolute_ignored ignored - all links are absolute * @param bool $moveselect If true a move seleciton process is used (default true) * @param int $indent The current indenting * @param int $section The section to link back to * @return string XHTML for the editing buttons */ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $moveselect = true, $indent = -1, $section = -1) { global $CFG, $OUTPUT; static $str; $coursecontext = get_context_instance(CONTEXT_COURSE, $mod->course); $modcontext = get_context_instance(CONTEXT_MODULE, $mod->id); $editcaps = array('moodle/course:manageactivities', 'moodle/course:activityvisibility', 'moodle/role:assign'); $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); // no permission to edit anything if (!has_any_capability($editcaps, $modcontext) and !has_all_capabilities($dupecaps, $coursecontext)) { return false; } $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext); if (!isset($str)) { $str = new stdClass(); $str->assign = get_string("assignroles", 'role'); $str->delete = get_string("delete"); $str->move = get_string("move"); $str->moveup = get_string("moveup"); $str->movedown = get_string("movedown"); $str->moveright = get_string("moveright"); $str->moveleft = get_string("moveleft"); $str->update = get_string("update"); $str->duplicate = get_string("duplicate"); $str->hide = get_string("hide"); $str->show = get_string("show"); $str->groupsnone = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsnone")); $str->groupsseparate = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsseparate")); $str->groupsvisible = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsvisible")); $str->forcedgroupsnone = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsnone")); $str->forcedgroupsseparate = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsseparate")); $str->forcedgroupsvisible = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsvisible")); } $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey())); if ($section >= 0) { $baseurl->param('sr', $section); } $actions = array(); // leftright if ($hasmanageactivities) { if (right_to_left()) { // Exchange arrows on RTL $rightarrow = 't/left'; $leftarrow = 't/right'; } else { $rightarrow = 't/right'; $leftarrow = 't/left'; } if ($indent > 0) { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')), new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_moveleft', 'title' => $str->moveleft)); } if ($indent >= 0) { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')), new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_moveright', 'title' => $str->moveright)); } } // move if ($hasmanageactivities) { if ($moveselect) { $actions[] = new action_link(new moodle_url($baseurl, array('copy' => $mod->id)), new pix_icon('t/move', $str->move, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_move', 'title' => $str->move)); } else { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'move' => '-1')), new pix_icon('t/up', $str->moveup, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_moveup', 'title' => $str->moveup)); $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'move' => '1')), new pix_icon('t/down', $str->movedown, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_movedown', 'title' => $str->movedown)); } } // Update if ($hasmanageactivities) { $actions[] = new action_link(new moodle_url($baseurl, array('update' => $mod->id)), new pix_icon('t/edit', $str->update, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_update', 'title' => $str->update)); } // Duplicate (require both target import caps to be able to duplicate, see modduplicate.php) if (has_all_capabilities($dupecaps, $coursecontext)) { $actions[] = new action_link(new moodle_url($baseurl, array('duplicate' => $mod->id)), new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_duplicate', 'title' => $str->duplicate)); } // Delete if ($hasmanageactivities) { $actions[] = new action_link(new moodle_url($baseurl, array('delete' => $mod->id)), new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_delete', 'title' => $str->delete)); } // hideshow if (has_capability('moodle/course:activityvisibility', $modcontext)) { if ($mod->visible) { $actions[] = new action_link(new moodle_url($baseurl, array('hide' => $mod->id)), new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_hide', 'title' => $str->hide)); } else { $actions[] = new action_link(new moodle_url($baseurl, array('show' => $mod->id)), new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_show', 'title' => $str->show)); } } // groupmode if ($hasmanageactivities and $mod->groupmode !== false) { if ($mod->groupmode == SEPARATEGROUPS) { $groupmode = 0; $grouptitle = $str->groupsseparate; $forcedgrouptitle = $str->forcedgroupsseparate; $groupclass = 'editing_groupsseparate'; $groupimage = 't/groups'; } else { if ($mod->groupmode == VISIBLEGROUPS) { $groupmode = 1; $grouptitle = $str->groupsvisible; $forcedgrouptitle = $str->forcedgroupsvisible; $groupclass = 'editing_groupsvisible'; $groupimage = 't/groupv'; } else { $groupmode = 2; $grouptitle = $str->groupsnone; $forcedgrouptitle = $str->forcedgroupsnone; $groupclass = 'editing_groupsnone'; $groupimage = 't/groupn'; } } if ($mod->groupmodelink) { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'groupmode' => $groupmode)), new pix_icon($groupimage, $grouptitle, 'moodle', array('class' => 'iconsmall')), null, array('class' => $groupclass, 'title' => $grouptitle)); } else { $actions[] = new pix_icon($groupimage, $forcedgrouptitle, 'moodle', array('title' => $forcedgrouptitle, 'class' => 'iconsmall')); } } // Assign if (has_capability('moodle/role:assign', $modcontext)) { $actions[] = new action_link(new moodle_url('/' . $CFG->admin . '/roles/assign.php', array('contextid' => $modcontext->id)), new pix_icon('i/roles', $str->assign, 'moodle', array('class' => 'iconsmall')), null, array('class' => 'editing_assign', 'title' => $str->assign)); } $output = html_writer::start_tag('span', array('class' => 'commands')); foreach ($actions as $action) { if ($action instanceof renderable) { $output .= $OUTPUT->render($action); } else { $output .= $action; } } $output .= html_writer::end_tag('span'); return $output; }
/** * Add elements to grade form. * * @param MoodleQuickForm $mform * @param stdClass $data * @param array $params * @return void */ public function add_grade_form_elements(MoodleQuickForm $mform, stdClass $data, $params) { global $USER, $CFG; $settings = $this->get_instance(); $rownum = $params['rownum']; $last = $params['last']; $useridlistid = $params['useridlistid']; $userid = $params['userid']; $attemptnumber = $params['attemptnumber']; if (!$userid) { $cache = cache::make_from_params(cache_store::MODE_SESSION, 'mod_assign', 'useridlist'); if (!($useridlist = $cache->get($this->get_course_module()->id . '_' . $useridlistid))) { $useridlist = $this->get_grading_userid_list(); $cache->set($this->get_course_module()->id . '_' . $useridlistid, $useridlist); } } else { $useridlist = array($userid); $rownum = 0; $useridlistid = ''; } $userid = $useridlist[$rownum]; $grade = $this->get_user_grade($userid, false, $attemptnumber); $submission = null; if ($this->get_instance()->teamsubmission) { $submission = $this->get_group_submission($userid, 0, false, $attemptnumber); } else { $submission = $this->get_user_submission($userid, false, $attemptnumber); } // Add advanced grading. $gradingdisabled = $this->grading_disabled($userid); $gradinginstance = $this->get_grading_instance($userid, $grade, $gradingdisabled); $mform->addElement('header', 'gradeheader', get_string('grade')); if ($gradinginstance) { $gradingelement = $mform->addElement('grading', 'advancedgrading', get_string('grade') . ':', array('gradinginstance' => $gradinginstance)); if ($gradingdisabled) { $gradingelement->freeze(); } else { $mform->addElement('hidden', 'advancedgradinginstanceid', $gradinginstance->get_id()); $mform->setType('advancedgradinginstanceid', PARAM_INT); } } else { // Use simple direct grading. if ($this->get_instance()->grade > 0) { $name = get_string('gradeoutof', 'assign', $this->get_instance()->grade); if (!$gradingdisabled) { $gradingelement = $mform->addElement('text', 'grade', $name); $mform->addHelpButton('grade', 'gradeoutofhelp', 'assign'); $mform->setType('grade', PARAM_RAW); } else { $mform->addElement('hidden', 'grade', $name); $mform->hardFreeze('grade'); $mform->setType('grade', PARAM_RAW); $strgradelocked = get_string('gradelocked', 'assign'); $mform->addElement('static', 'gradedisabled', $name, $strgradelocked); $mform->addHelpButton('gradedisabled', 'gradeoutofhelp', 'assign'); } } else { $grademenu = array(-1 => get_string("nograde")) + make_grades_menu($this->get_instance()->grade); if (count($grademenu) > 1) { $gradingelement = $mform->addElement('select', 'grade', get_string('grade') . ':', $grademenu); // The grade is already formatted with format_float so it needs to be converted back to an integer. if (!empty($data->grade)) { $data->grade = (int) unformat_float($data->grade); } $mform->setType('grade', PARAM_INT); if ($gradingdisabled) { $gradingelement->freeze(); } } } } $gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, $userid); if (!empty($CFG->enableoutcomes)) { foreach ($gradinginfo->outcomes as $index => $outcome) { $options = make_grades_menu(-$outcome->scaleid); if ($outcome->grades[$userid]->locked) { $options[0] = get_string('nooutcome', 'grades'); $mform->addElement('static', 'outcome_' . $index . '[' . $userid . ']', $outcome->name . ':', $options[$outcome->grades[$userid]->grade]); } else { $options[''] = get_string('nooutcome', 'grades'); $attributes = array('id' => 'menuoutcome_' . $index); $mform->addElement('select', 'outcome_' . $index . '[' . $userid . ']', $outcome->name . ':', $options, $attributes); $mform->setType('outcome_' . $index . '[' . $userid . ']', PARAM_INT); $mform->setDefault('outcome_' . $index . '[' . $userid . ']', $outcome->grades[$userid]->grade); } } } $capabilitylist = array('gradereport/grader:view', 'moodle/grade:viewall'); if (has_all_capabilities($capabilitylist, $this->get_course_context())) { $urlparams = array('id' => $this->get_course()->id); $url = new moodle_url('/grade/report/grader/index.php', $urlparams); $usergrade = '-'; if (isset($gradinginfo->items[0]->grades[$userid]->str_grade)) { $usergrade = $gradinginfo->items[0]->grades[$userid]->str_grade; } $gradestring = $this->get_renderer()->action_link($url, $usergrade); } else { $usergrade = '-'; if (isset($gradinginfo->items[0]->grades[$userid]) && !$gradinginfo->items[0]->grades[$userid]->hidden) { $usergrade = $gradinginfo->items[0]->grades[$userid]->str_grade; } $gradestring = $usergrade; } if ($this->get_instance()->markingworkflow) { $states = $this->get_marking_workflow_states_for_current_user(); $options = array('' => get_string('markingworkflowstatenotmarked', 'assign')) + $states; $mform->addElement('select', 'workflowstate', get_string('markingworkflowstate', 'assign'), $options); $mform->addHelpButton('workflowstate', 'markingworkflowstate', 'assign'); } if ($this->get_instance()->markingallocation && has_capability('mod/assign:manageallocations', $this->context)) { $markers = get_users_by_capability($this->context, 'mod/assign:grade'); $markerlist = array('' => get_string('choosemarker', 'assign')); foreach ($markers as $marker) { $markerlist[$marker->id] = fullname($marker); } $mform->addElement('select', 'allocatedmarker', get_string('allocatedmarker', 'assign'), $markerlist); $mform->addHelpButton('allocatedmarker', 'allocatedmarker', 'assign'); $mform->disabledIf('allocatedmarker', 'workflowstate', 'eq', ASSIGN_MARKING_WORKFLOW_STATE_READYFORREVIEW); $mform->disabledIf('allocatedmarker', 'workflowstate', 'eq', ASSIGN_MARKING_WORKFLOW_STATE_INREVIEW); $mform->disabledIf('allocatedmarker', 'workflowstate', 'eq', ASSIGN_MARKING_WORKFLOW_STATE_READYFORRELEASE); $mform->disabledIf('allocatedmarker', 'workflowstate', 'eq', ASSIGN_MARKING_WORKFLOW_STATE_RELEASED); } $mform->addElement('static', 'currentgrade', get_string('currentgrade', 'assign'), $gradestring); if (count($useridlist) > 1) { $strparams = array('current' => $rownum + 1, 'total' => count($useridlist)); $name = get_string('outof', 'assign', $strparams); $mform->addElement('static', 'gradingstudent', get_string('gradingstudent', 'assign'), $name); } // Let feedback plugins add elements to the grading form. $this->add_plugin_grade_elements($grade, $mform, $data, $userid); // Hidden params. $mform->addElement('hidden', 'id', $this->get_course_module()->id); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'rownum', $rownum); $mform->setType('rownum', PARAM_INT); $mform->setConstant('rownum', $rownum); $mform->addElement('hidden', 'useridlistid', $useridlistid); $mform->setType('useridlistid', PARAM_INT); $mform->addElement('hidden', 'attemptnumber', $attemptnumber); $mform->setType('attemptnumber', PARAM_INT); $mform->addElement('hidden', 'ajax', optional_param('ajax', 0, PARAM_INT)); $mform->setType('ajax', PARAM_INT); if ($this->get_instance()->teamsubmission) { $mform->addElement('header', 'groupsubmissionsettings', get_string('groupsubmissionsettings', 'assign')); $mform->addElement('selectyesno', 'applytoall', get_string('applytoteam', 'assign')); $mform->setDefault('applytoall', 1); } // Do not show if we are editing a previous attempt. if ($attemptnumber == -1 && $this->get_instance()->attemptreopenmethod != ASSIGN_ATTEMPT_REOPEN_METHOD_NONE) { $mform->addElement('header', 'attemptsettings', get_string('attemptsettings', 'assign')); $attemptreopenmethod = get_string('attemptreopenmethod_' . $this->get_instance()->attemptreopenmethod, 'assign'); $mform->addElement('static', 'attemptreopenmethod', get_string('attemptreopenmethod', 'assign'), $attemptreopenmethod); $attemptnumber = 0; if ($submission) { $attemptnumber = $submission->attemptnumber; } $maxattempts = $this->get_instance()->maxattempts; if ($maxattempts == ASSIGN_UNLIMITED_ATTEMPTS) { $maxattempts = get_string('unlimitedattempts', 'assign'); } $mform->addelement('static', 'maxattemptslabel', get_string('maxattempts', 'assign'), $maxattempts); $mform->addelement('static', 'attemptnumberlabel', get_string('attemptnumber', 'assign'), $attemptnumber + 1); $ismanual = $this->get_instance()->attemptreopenmethod == ASSIGN_ATTEMPT_REOPEN_METHOD_MANUAL; $issubmission = !empty($submission); $isunlimited = $this->get_instance()->maxattempts == ASSIGN_UNLIMITED_ATTEMPTS; $islessthanmaxattempts = $issubmission && $submission->attemptnumber < $this->get_instance()->maxattempts - 1; if ($ismanual && (!$issubmission || $isunlimited || $islessthanmaxattempts)) { $mform->addElement('selectyesno', 'addattempt', get_string('addattempt', 'assign')); $mform->setDefault('addattempt', 0); } } $mform->addElement('hidden', 'action', 'submitgrade'); $mform->setType('action', PARAM_ALPHA); $buttonarray = array(); $name = get_string('savechanges', 'assign'); $buttonarray[] = $mform->createElement('submit', 'savegrade', $name); if (!$last) { $name = get_string('savenext', 'assign'); $buttonarray[] = $mform->createElement('submit', 'saveandshownext', $name); } $buttonarray[] = $mform->createElement('cancel', 'cancelbutton', get_string('cancel')); $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false); $mform->closeHeaderBefore('buttonar'); $buttonarray = array(); if ($rownum > 0) { $name = get_string('previous', 'assign'); $buttonarray[] = $mform->createElement('submit', 'nosaveandprevious', $name); } if (!$last) { $name = get_string('nosavebutnext', 'assign'); $buttonarray[] = $mform->createElement('submit', 'nosaveandnext', $name); } if (!empty($buttonarray)) { $mform->addGroup($buttonarray, 'navar', '', array(' '), false); } // The grading form does not work well with shortforms. $mform->setDisableShortforms(); }
// 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. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Link to user roles management. * * @package tool_cohortroles * @copyright 2015 Damyon Wiese * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ defined('MOODLE_INTERNAL') || die; // This tool's required capabilities. $capabilities = ['moodle/cohort:view', 'moodle/role:manage']; // Check if the user has all of the required capabilities. $context = context_system::instance(); $hasaccess = has_all_capabilities($capabilities, $context); // Add this admin page only if the user has all of the required capabilities. if ($hasaccess) { $str = get_string('managecohortroles', 'tool_cohortroles'); $url = new moodle_url('/admin/tool/cohortroles/index.php'); $ADMIN->add('roles', new admin_externalpage('toolcohortroles', $str, $url, $capabilities)); }
/** * Returns the list of all editing actions that current user can perform on the module * * @param cm_info $mod The module to produce editing buttons for * @param int $indent The current indenting (default -1 means no move left-right actions) * @param int $sr The section to link back to (used for creating the links) * @return array array of action_link or pix_icon objects */ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) { global $COURSE, $SITE; static $str; $coursecontext = context_course::instance($mod->course); $modcontext = context_module::instance($mod->id); $editcaps = array('moodle/course:manageactivities', 'moodle/course:activityvisibility', 'moodle/role:assign'); $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); // No permission to edit anything. if (!has_any_capability($editcaps, $modcontext) and !has_all_capabilities($dupecaps, $coursecontext)) { return array(); } $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext); if (!isset($str)) { $str = get_strings(array('delete', 'move', 'moveright', 'moveleft', 'editsettings', 'duplicate', 'hide', 'show'), 'moodle'); $str->assign = get_string('assignroles', 'role'); $str->groupsnone = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsnone")); $str->groupsseparate = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsseparate")); $str->groupsvisible = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsvisible")); } $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey())); if ($sr !== null) { $baseurl->param('sr', $sr); } $actions = array(); // Update. if ($hasmanageactivities) { $actions['update'] = new action_menu_link_secondary(new moodle_url($baseurl, array('update' => $mod->id)), new pix_icon('t/edit', $str->editsettings, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->editsettings, array('class' => 'editing_update', 'data-action' => 'update')); } // Indent. if ($hasmanageactivities && $indent >= 0) { $indentlimits = new stdClass(); $indentlimits->min = 0; $indentlimits->max = 16; if (right_to_left()) { // Exchange arrows on RTL $rightarrow = 't/left'; $leftarrow = 't/right'; } else { $rightarrow = 't/right'; $leftarrow = 't/left'; } if ($indent >= $indentlimits->max) { $enabledclass = 'hidden'; } else { $enabledclass = ''; } $actions['moveright'] = new action_menu_link_secondary(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')), new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->moveright, array('class' => 'editing_moveright ' . $enabledclass, 'data-action' => 'moveright', 'data-keepopen' => true)); if ($indent <= $indentlimits->min) { $enabledclass = 'hidden'; } else { $enabledclass = ''; } $actions['moveleft'] = new action_menu_link_secondary(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')), new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->moveleft, array('class' => 'editing_moveleft ' . $enabledclass, 'data-action' => 'moveleft', 'data-keepopen' => true)); } // Hide/Show. if (has_capability('moodle/course:activityvisibility', $modcontext)) { if ($mod->visible) { $actions['hide'] = new action_menu_link_secondary(new moodle_url($baseurl, array('hide' => $mod->id)), new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->hide, array('class' => 'editing_hide', 'data-action' => 'hide')); } else { $actions['show'] = new action_menu_link_secondary(new moodle_url($baseurl, array('show' => $mod->id)), new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->show, array('class' => 'editing_show', 'data-action' => 'show')); } } // Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php) // Note that restoring on front page is never allowed. if ($mod->course != SITEID && has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) { $actions['duplicate'] = new action_menu_link_secondary(new moodle_url($baseurl, array('duplicate' => $mod->id)), new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->duplicate, array('class' => 'editing_duplicate', 'data-action' => 'duplicate', 'data-sr' => $sr)); } // Groupmode. if ($hasmanageactivities && !$mod->coursegroupmodeforce) { if (plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) { if ($mod->effectivegroupmode == SEPARATEGROUPS) { $nextgroupmode = VISIBLEGROUPS; $grouptitle = $str->groupsseparate; $actionname = 'groupsseparate'; $groupimage = 'i/groups'; } else { if ($mod->effectivegroupmode == VISIBLEGROUPS) { $nextgroupmode = NOGROUPS; $grouptitle = $str->groupsvisible; $actionname = 'groupsvisible'; $groupimage = 'i/groupv'; } else { $nextgroupmode = SEPARATEGROUPS; $grouptitle = $str->groupsnone; $actionname = 'groupsnone'; $groupimage = 'i/groupn'; } } $actions[$actionname] = new action_menu_link_primary(new moodle_url($baseurl, array('id' => $mod->id, 'groupmode' => $nextgroupmode)), new pix_icon($groupimage, null, 'moodle', array('class' => 'iconsmall')), $grouptitle, array('class' => 'editing_' . $actionname, 'data-action' => $actionname, 'data-nextgroupmode' => $nextgroupmode, 'aria-live' => 'assertive')); } else { $actions['nogroupsupport'] = new action_menu_filler(); } } // Assign. if (has_capability('moodle/role:assign', $modcontext)) { $actions['assign'] = new action_menu_link_secondary(new moodle_url('/admin/roles/assign.php', array('contextid' => $modcontext->id)), new pix_icon('t/assignroles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->assign, array('class' => 'editing_assign', 'data-action' => 'assignroles')); } // Delete. if ($hasmanageactivities) { $actions['delete'] = new action_menu_link_secondary(new moodle_url($baseurl, array('delete' => $mod->id)), new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')), $str->delete, array('class' => 'editing_delete', 'data-action' => 'delete')); } return $actions; }
/** * Returns an array of courses the user is enrolled in, and for each course all of the assignments that the user can * view within that course. * * @param array $courseids An optional array of course ids. If provided only assignments within the given course * will be returned. If the user is not enrolled in a given course a warning will be generated and returned. * @param array $capabilities An array of additional capability checks you wish to be made on the course context. * @return An array of courses and warnings. * @since Moodle 2.4 */ public static function get_assignments($courseids = array(), $capabilities = array()) { global $USER, $DB; $params = self::validate_parameters(self::get_assignments_parameters(), array('courseids' => $courseids, 'capabilities' => $capabilities)); $warnings = array(); $fields = 'sortorder,shortname,fullname,timemodified'; $courses = enrol_get_users_courses($USER->id, true, $fields); // Used to test for ids that have been requested but can't be returned. if (count($params['courseids']) > 0) { foreach ($params['courseids'] as $courseid) { if (!in_array($courseid, array_keys($courses))) { unset($courses[$courseid]); $warnings[] = array('item' => 'course', 'itemid' => $courseid, 'warningcode' => '2', 'message' => 'User is not enrolled or does not have requested capability'); } } } foreach ($courses as $id => $course) { if (count($params['courseids']) > 0 && !in_array($id, $params['courseids'])) { unset($courses[$id]); } $context = context_course::instance($id); try { self::validate_context($context); } catch (Exception $e) { unset($courses[$id]); $warnings[] = array('item' => 'course', 'itemid' => $id, 'warningcode' => '1', 'message' => 'No access rights in course context ' . $e->getMessage() . $e->getTraceAsString()); continue; } if (count($params['capabilities']) > 0 && !has_all_capabilities($params['capabilities'], $context)) { unset($courses[$id]); } } $extrafields = 'm.id as assignmentid, ' . 'm.course, ' . 'm.nosubmissions, ' . 'm.submissiondrafts, ' . 'm.sendnotifications, ' . 'm.sendlatenotifications, ' . 'm.sendstudentnotifications, ' . 'm.duedate, ' . 'm.allowsubmissionsfromdate, ' . 'm.grade, ' . 'm.timemodified, ' . 'm.completionsubmit, ' . 'm.cutoffdate, ' . 'm.teamsubmission, ' . 'm.requireallteammemberssubmit, ' . 'm.teamsubmissiongroupingid, ' . 'm.blindmarking, ' . 'm.revealidentities, ' . 'm.attemptreopenmethod, ' . 'm.maxattempts, ' . 'm.markingworkflow, ' . 'm.markingallocation, ' . 'm.requiresubmissionstatement'; $coursearray = array(); foreach ($courses as $id => $course) { $assignmentarray = array(); // Get a list of assignments for the course. if ($modules = get_coursemodules_in_course('assign', $courses[$id]->id, $extrafields)) { foreach ($modules as $module) { $context = context_module::instance($module->id); try { self::validate_context($context); require_capability('mod/assign:view', $context); } catch (Exception $e) { $warnings[] = array('item' => 'module', 'itemid' => $module->id, 'warningcode' => '1', 'message' => 'No access rights in module context'); continue; } $configrecords = $DB->get_recordset('assign_plugin_config', array('assignment' => $module->assignmentid)); $configarray = array(); foreach ($configrecords as $configrecord) { $configarray[] = array('id' => $configrecord->id, 'assignment' => $configrecord->assignment, 'plugin' => $configrecord->plugin, 'subtype' => $configrecord->subtype, 'name' => $configrecord->name, 'value' => $configrecord->value); } $configrecords->close(); $assignmentarray[] = array('id' => $module->assignmentid, 'cmid' => $module->id, 'course' => $module->course, 'name' => $module->name, 'nosubmissions' => $module->nosubmissions, 'submissiondrafts' => $module->submissiondrafts, 'sendnotifications' => $module->sendnotifications, 'sendlatenotifications' => $module->sendlatenotifications, 'sendstudentnotifications' => $module->sendstudentnotifications, 'duedate' => $module->duedate, 'allowsubmissionsfromdate' => $module->allowsubmissionsfromdate, 'grade' => $module->grade, 'timemodified' => $module->timemodified, 'completionsubmit' => $module->completionsubmit, 'cutoffdate' => $module->cutoffdate, 'teamsubmission' => $module->teamsubmission, 'requireallteammemberssubmit' => $module->requireallteammemberssubmit, 'teamsubmissiongroupingid' => $module->teamsubmissiongroupingid, 'blindmarking' => $module->blindmarking, 'revealidentities' => $module->revealidentities, 'attemptreopenmethod' => $module->attemptreopenmethod, 'maxattempts' => $module->maxattempts, 'markingworkflow' => $module->markingworkflow, 'markingallocation' => $module->markingallocation, 'requiresubmissionstatement' => $module->requiresubmissionstatement, 'configs' => $configarray); } } $coursearray[] = array('id' => $courses[$id]->id, 'fullname' => $courses[$id]->fullname, 'shortname' => $courses[$id]->shortname, 'timemodified' => $courses[$id]->timemodified, 'assignments' => $assignmentarray); } $result = array('courses' => $coursearray, 'warnings' => $warnings); return $result; }
/** * Returns an array of courses the user is enrolled, and for each course all of the assignments that the user can * view within that course. * * @param array $courseids An optional array of course ids. If provided only assignments within the given course * will be returned. If the user is not enrolled in or can't view a given course a warning will be generated and returned. * @param array $capabilities An array of additional capability checks you wish to be made on the course context. * @param bool $includenotenrolledcourses Wheter to return courses that the user can see even if is not enroled in. * This requires the parameter $courseids to not be empty. * @return An array of courses and warnings. * @since Moodle 2.4 */ public static function get_assignments($courseids = array(), $capabilities = array(), $includenotenrolledcourses = false) { global $USER, $DB, $CFG; $params = self::validate_parameters(self::get_assignments_parameters(), array('courseids' => $courseids, 'capabilities' => $capabilities, 'includenotenrolledcourses' => $includenotenrolledcourses)); $warnings = array(); $courses = array(); $fields = 'sortorder,shortname,fullname,timemodified'; // If the courseids list is empty, we return only the courses where the user is enrolled in. if (empty($params['courseids'])) { $courses = enrol_get_users_courses($USER->id, true, $fields); $courseids = array_keys($courses); } else { if ($includenotenrolledcourses) { // In this case, we don't have to check here for enrolmnents. Maybe the user can see the course even if is not enrolled. $courseids = $params['courseids']; } else { // We need to check for enrolments. $mycourses = enrol_get_users_courses($USER->id, true, $fields); $mycourseids = array_keys($mycourses); foreach ($params['courseids'] as $courseid) { if (!in_array($courseid, $mycourseids)) { unset($courses[$courseid]); $warnings[] = array('item' => 'course', 'itemid' => $courseid, 'warningcode' => '2', 'message' => 'User is not enrolled or does not have requested capability'); } else { $courses[$courseid] = $mycourses[$courseid]; } } $courseids = array_keys($courses); } } foreach ($courseids as $cid) { try { $context = context_course::instance($cid); self::validate_context($context); // Check if this course was already loaded (by enrol_get_users_courses). if (!isset($courses[$cid])) { $courses[$cid] = get_course($cid); } $courses[$cid]->contextid = $context->id; } catch (Exception $e) { unset($courses[$cid]); $warnings[] = array('item' => 'course', 'itemid' => $cid, 'warningcode' => '1', 'message' => 'No access rights in course context ' . $e->getMessage()); continue; } if (count($params['capabilities']) > 0 && !has_all_capabilities($params['capabilities'], $context)) { unset($courses[$cid]); } } $extrafields = 'm.id as assignmentid, ' . 'm.course, ' . 'm.nosubmissions, ' . 'm.submissiondrafts, ' . 'm.sendnotifications, ' . 'm.sendlatenotifications, ' . 'm.sendstudentnotifications, ' . 'm.duedate, ' . 'm.allowsubmissionsfromdate, ' . 'm.grade, ' . 'm.timemodified, ' . 'm.completionsubmit, ' . 'm.cutoffdate, ' . 'm.teamsubmission, ' . 'm.requireallteammemberssubmit, ' . 'm.teamsubmissiongroupingid, ' . 'm.blindmarking, ' . 'm.revealidentities, ' . 'm.attemptreopenmethod, ' . 'm.maxattempts, ' . 'm.markingworkflow, ' . 'm.markingallocation, ' . 'm.requiresubmissionstatement, ' . 'm.preventsubmissionnotingroup, ' . 'm.intro, ' . 'm.introformat'; $coursearray = array(); foreach ($courses as $id => $course) { $assignmentarray = array(); // Get a list of assignments for the course. if ($modules = get_coursemodules_in_course('assign', $courses[$id]->id, $extrafields)) { foreach ($modules as $module) { $context = context_module::instance($module->id); try { self::validate_context($context); require_capability('mod/assign:view', $context); } catch (Exception $e) { $warnings[] = array('item' => 'module', 'itemid' => $module->id, 'warningcode' => '1', 'message' => 'No access rights in module context'); continue; } $assign = new assign($context, null, null); // Get configurations for only enabled plugins. $plugins = $assign->get_submission_plugins(); $plugins = array_merge($plugins, $assign->get_feedback_plugins()); $configarray = array(); foreach ($plugins as $plugin) { if ($plugin->is_enabled() && $plugin->is_visible()) { $configrecords = $plugin->get_config_for_external(); foreach ($configrecords as $name => $value) { $configarray[] = array('plugin' => $plugin->get_type(), 'subtype' => $plugin->get_subtype(), 'name' => $name, 'value' => $value); } } } $assignment = array('id' => $module->assignmentid, 'cmid' => $module->id, 'course' => $module->course, 'name' => $module->name, 'nosubmissions' => $module->nosubmissions, 'submissiondrafts' => $module->submissiondrafts, 'sendnotifications' => $module->sendnotifications, 'sendlatenotifications' => $module->sendlatenotifications, 'sendstudentnotifications' => $module->sendstudentnotifications, 'duedate' => $module->duedate, 'allowsubmissionsfromdate' => $module->allowsubmissionsfromdate, 'grade' => $module->grade, 'timemodified' => $module->timemodified, 'completionsubmit' => $module->completionsubmit, 'cutoffdate' => $module->cutoffdate, 'teamsubmission' => $module->teamsubmission, 'requireallteammemberssubmit' => $module->requireallteammemberssubmit, 'teamsubmissiongroupingid' => $module->teamsubmissiongroupingid, 'blindmarking' => $module->blindmarking, 'revealidentities' => $module->revealidentities, 'attemptreopenmethod' => $module->attemptreopenmethod, 'maxattempts' => $module->maxattempts, 'markingworkflow' => $module->markingworkflow, 'markingallocation' => $module->markingallocation, 'requiresubmissionstatement' => $module->requiresubmissionstatement, 'preventsubmissionnotingroup' => $module->preventsubmissionnotingroup, 'configs' => $configarray); // Return or not intro and file attachments depending on the plugin settings. if ($assign->show_intro()) { list($assignment['intro'], $assignment['introformat']) = external_format_text($module->intro, $module->introformat, $context->id, 'mod_assign', 'intro', null); $assignment['introfiles'] = external_util::get_area_files($context->id, 'mod_assign', 'intro', false, false); $assignment['introattachments'] = external_util::get_area_files($context->id, 'mod_assign', ASSIGN_INTROATTACHMENT_FILEAREA, 0); } if ($module->requiresubmissionstatement) { // Submission statement is required, return the submission statement value. $adminconfig = get_config('assign'); list($assignment['submissionstatement'], $assignment['submissionstatementformat']) = external_format_text($adminconfig->submissionstatement, FORMAT_MOODLE, $context->id, 'mod_assign', '', 0); } $assignmentarray[] = $assignment; } } $coursearray[] = array('id' => $courses[$id]->id, 'fullname' => external_format_string($courses[$id]->fullname, $course->contextid), 'shortname' => external_format_string($courses[$id]->shortname, $course->contextid), 'timemodified' => $courses[$id]->timemodified, 'assignments' => $assignmentarray); } $result = array('courses' => $coursearray, 'warnings' => $warnings); return $result; }
/** * Renders HTML to display one course module in a course section * * This includes link, content, availability, completion info and additional information * that module type wants to display (i.e. number of unread forum posts) * * This function calls: * {@link core_course_renderer::course_section_cm_name()} * {@link cm_info::get_after_link()} * {@link core_course_renderer::course_section_cm_text()} * {@link core_course_renderer::course_section_cm_availability()} * {@link core_course_renderer::course_section_cm_completion()} * {@link course_get_cm_edit_actions()} * {@link core_course_renderer::course_section_cm_edit_actions()} * * @param \stdClass $course * @param \completion_info $completioninfo * @param \cm_info $mod * @param int|null $sectionreturn * @param array $displayoptions * @return string */ public function course_section_cm($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) { global $COURSE; $output = ''; // We return empty string (because course module will not be displayed at all) // if: // 1) The activity is not visible to users // and // 2) The 'availableinfo' is empty, i.e. the activity was // hidden in a way that leaves no info, such as using the // eye icon. if (!$mod->uservisible && empty($mod->availableinfo)) { return $output; } $output .= '<div class="asset-wrapper">'; // TODO - add if can edit. // Drop section notice. $output .= '<a class="snap-move-note" href="#">' . get_string('movehere', 'theme_snap') . '</a>'; // Start the div for the activity content. $output .= "<div class='activityinstance'>"; // Display the link to the module (or do nothing if module has no url). $cmname = $this->course_section_cm_name($mod, $displayoptions); $assetlink = ''; // SHAME - For moodles ajax show/hide call to work it needs activityinstance > a to add a class of dimmed to. // This dimmed class is of course inaccessible junk. if (!empty($cmname)) { $assetlink = '<a></a><h4 class="snap-asset-link">' . $cmname . '</h4>'; } // Asset content. $contentpart = $this->course_section_cm_text($mod, $displayoptions); // Activity/resource type. $snapmodtype = $this->get_mod_type($mod)[0]; $assetmeta = "<span class='snap-assettype'>" . $snapmodtype . "</span>"; // Groups, Restriction and all that jazz metadata. // Completion tracking. $completiontracking = $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions); // Due date, feedback available and all the nice snap things. $snapcompletiondata = $this->module_meta_html($mod); $assetcompletionmeta = "<div class='snap-completion-meta'>" . $completiontracking . $snapcompletiondata . "</div>"; // Draft status - always output, shown via css of parent. $assetrestrictions = "<div class='draft-tag text text-warning'>" . get_string('draft', 'theme_snap') . "</div>"; $canmanagegroups = has_capability('moodle/course:managegroups', context_course::instance($mod->course)); if ($canmanagegroups && $mod->effectivegroupmode != NOGROUPS) { if ($mod->effectivegroupmode == VISIBLEGROUPS) { $groupinfo = get_string('groupsvisible'); } else { if ($mod->effectivegroupmode == SEPARATEGROUPS) { $groupinfo = get_string('groupsseparate'); } } $assetrestrictions .= "<div class='text'>{$groupinfo}</div>"; } // TODO - ask what this is... if (!empty($mod->groupingid) && $canmanagegroups) { // Grouping label. $groupings = groups_get_all_groupings($mod->course); $assetrestrictions .= "<div class='text text-danger'>" . format_string($groupings[$mod->groupingid]->name) . "</div>"; // TBD - add a title to show this is the Grouping... } $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $mod->context); // If the module isn't available, or we are a teacher (can view hidden activities) then get availability // info. $availabilityinfo = ''; if (!$mod->available || $canviewhidden) { $availabilityinfo = $this->course_section_cm_availability($mod, $displayoptions); } if ($availabilityinfo !== '') { $conditionalinfo = get_string('conditional', 'theme_snap'); $assetrestrictions .= "<div class='text text-danger'>{$conditionalinfo}.{$availabilityinfo}</div>"; } $assetrestrictions = "<div class='snap-restrictions-meta'>{$assetrestrictions}</div>"; $assetmeta .= $assetcompletionmeta . $assetrestrictions; // Build output. $postcontent = '<div class="snap-asset-meta" data-cmid="' . $mod->id . '">' . $mod->afterlink . $assetmeta . '</div>'; $output .= $assetlink . $contentpart . $postcontent; // Bail at this point if we aren't using a supported format. (Folder view is only partially supported). $supported = ['folderview', 'topics', 'weeks', 'site']; if (!in_array($COURSE->format, $supported)) { return parent::course_section_cm($course, $completioninfo, $mod, $sectionreturn, $displayoptions) . $assetmeta; } // Build up edit actions. $actions = ''; $actionsadvanced = array(); $coursecontext = context_course::instance($mod->course); $modcontext = context_module::instance($mod->id); $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey())); if (has_capability('moodle/course:update', $modcontext)) { $str = get_strings(array('delete', 'move', 'duplicate', 'hide', 'show', 'roles'), 'moodle'); // TODO - add snap strings here. // Move, Edit, Delete. if (has_capability('moodle/course:manageactivities', $modcontext)) { $movealt = get_string('move', 'theme_snap', $mod->get_formatted_name()); $moveicon = "<img title='{$movealt}' aria-hidden='true' class='svg-icon' src='" . $this->output->pix_url('move', 'theme') . "' />"; $editalt = get_string('edit', 'theme_snap', $mod->get_formatted_name()); $editicon = "<img title='{$editalt}' alt='{$editalt}' class='svg-icon' src='" . $this->output->pix_url('edit', 'theme') . "'/>"; $actions .= "<input id='snap-move-mod-{$mod->id}' class='js-snap-asset-move sr-only' type='checkbox'><label class='snap-asset-move' for='snap-move-mod-{$mod->id}'><span class='sr-only'>{$movealt}</span>{$moveicon}</label>"; $actions .= "<a class='snap-edit-asset' href='" . new moodle_url($baseurl, array('update' => $mod->id)) . "'>{$editicon}</a>"; $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('delete' => $mod->id)) . "'>{$str->delete}</a>"; } // Hide/Show. if (has_capability('moodle/course:activityvisibility', $modcontext)) { $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('hide' => $mod->id)) . "' class='editing_hide js_snap_hide'>{$str->hide}</a>"; $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('show' => $mod->id)) . "' class='editing_show js_snap_show'>{$str->show}</a>"; // AX click to change. } // Duplicate. $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); if (has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2) && plugin_supports('mod', $mod->modname, 'duplicate', true)) { $actionsadvanced[] = "<a href='" . new moodle_url($baseurl, array('duplicate' => $mod->id)) . "' class='js_snap_duplicate'>{$str->duplicate}</a>"; } // Asign roles. if (has_capability('moodle/role:assign', $modcontext)) { $actionsadvanced[] = "<a href='" . new moodle_url('/admin/roles/assign.php', array('contextid' => $modcontext->id)) . "'>{$str->roles}</a>"; } // Give local plugins a chance to add icons. $localplugins = array(); foreach (get_plugin_list_with_function('local', 'extend_module_editing_buttons') as $function) { $localplugins = array_merge($localplugins, $function($mod)); } // TODO - pld string is far too long.... $locallinks = ''; foreach ($localplugins as $localplugin) { $url = $localplugin->url; $text = $localplugin->text; $class = $localplugin->attributes['class']; $actionsadvanced[] = "<a href='{$url}' class='{$class}'>{$text}</a>"; } } $advancedactions = ''; if (!empty($actionsadvanced)) { $moreicon = "<img title='" . get_string('more', 'theme_snap') . "' alt='" . get_string('more', 'theme_snap') . "' class='svg-icon' src='" . $this->output->pix_url('more', 'theme') . "'/>"; $advancedactions = "<div class='dropdown snap-edit-more-dropdown'>\n <a href='#' class='dropdown-toggle snap-edit-asset-more' data-toggle='dropdown' aria-expanded='false' aria-haspopup='true'>{$moreicon}</a>\n <ul class='dropdown-menu'>"; foreach ($actionsadvanced as $action) { $advancedactions .= "<li>{$action}</li>"; } $advancedactions .= "</ul></div>"; } // Add actions menu. if ($actions) { $output .= "<div class='snap-asset-actions' role='region' aria-label='actions'>"; $output .= $actions . $advancedactions; $output .= "</div>"; } $output .= "</div>"; // Close .activityinstance. $output .= "</div>"; // Close .asset-wrapper. return $output; }
/** * Executes the search * * @global moodle_database $DB * @return int The number of results */ public final function search() { global $DB; if (!is_null($this->results)) { return $this->results; } $this->results = array(); $this->totalcount = 0; $contextlevel = $this->get_itemcontextlevel(); list($sql, $params) = $this->get_searchsql(); // Get total number, to avoid some incorrect iterations. $countsql = preg_replace('/ORDER BY.*/', '', $sql); $totalcourses = $DB->count_records_sql("SELECT COUNT(*) FROM ({$countsql}) sel", $params); if ($totalcourses > 0) { // User to be checked is always the same (usually null, get it from first element). $firstcap = reset($this->requiredcapabilities); $userid = isset($firstcap['user']) ? $firstcap['user'] : null; // Extract caps to check, this saves us a bunch of iterations. $requiredcaps = array(); foreach ($this->requiredcapabilities as $cap) { $requiredcaps[] = $cap['capability']; } // Iterate while we have records and haven't reached $this->maxresults. $resultset = $DB->get_recordset_sql($sql, $params); foreach ($resultset as $result) { context_helper::preload_from_record($result); $classname = context_helper::get_class_for_level($contextlevel); $context = $classname::instance($result->id); if (count($requiredcaps) > 0) { if (!has_all_capabilities($requiredcaps, $context, $userid)) { continue; } } // Check if we are over the limit. if ($this->totalcount + 1 > $this->maxresults) { $this->hasmoreresults = true; break; } // If not, then continue. $this->totalcount++; $this->results[$result->id] = $result; } $resultset->close(); } return $this->totalcount; }
function make_editing_buttons($mod, $absolute = false, $moveselect = true, $indent = -1, $section = -1) { global $CFG, $USER, $DB, $OUTPUT; static $str; static $sesskey; $modcontext = get_context_instance(CONTEXT_MODULE, $mod->id); // no permission to edit if (!has_capability('moodle/course:manageactivities', $modcontext)) { return false; } if (!isset($str)) { $str->assign = get_string("assignroles", 'role'); $str->delete = get_string("delete"); $str->move = get_string("move"); $str->moveup = get_string("moveup"); $str->movedown = get_string("movedown"); $str->moveright = get_string("moveright"); $str->moveleft = get_string("moveleft"); $str->update = get_string("update"); $str->duplicate = get_string("duplicate"); $str->hide = get_string("hide"); $str->show = get_string("show"); $str->clicktochange = get_string("clicktochange"); $str->forcedmode = get_string("forcedmode"); $str->groupsnone = get_string("groupsnone"); $str->groupsseparate = get_string("groupsseparate"); $str->groupsvisible = get_string("groupsvisible"); $sesskey = sesskey(); } if ($section >= 0) { $section = '&sr=' . $section; // Section return } else { $section = ''; } if ($absolute) { $path = $CFG->wwwroot . '/course'; } else { $path = '.'; } if (has_capability('moodle/course:activityvisibility', $modcontext)) { if ($mod->visible) { $hideshow = '<a class="editing_hide" title="' . $str->hide . '" href="' . $path . '/mod.php?hide=' . $mod->id . '&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/hide') . '" class="iconsmall" ' . ' alt="' . $str->hide . '" /></a>' . "\n"; } else { $hideshow = '<a class="editing_show" title="' . $str->show . '" href="' . $path . '/mod.php?show=' . $mod->id . '&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/show') . '" class="iconsmall" ' . ' alt="' . $str->show . '" /></a>' . "\n"; } } else { $hideshow = ''; } if ($mod->groupmode !== false) { if ($mod->groupmode == SEPARATEGROUPS) { $grouptitle = $str->groupsseparate; $groupclass = 'editing_groupsseparate'; $groupimage = $OUTPUT->pix_url('t/groups') . ''; $grouplink = $path . '/mod.php?id=' . $mod->id . '&groupmode=0&sesskey=' . $sesskey; } else { if ($mod->groupmode == VISIBLEGROUPS) { $grouptitle = $str->groupsvisible; $groupclass = 'editing_groupsvisible'; $groupimage = $OUTPUT->pix_url('t/groupv') . ''; $grouplink = $path . '/mod.php?id=' . $mod->id . '&groupmode=1&sesskey=' . $sesskey; } else { $grouptitle = $str->groupsnone; $groupclass = 'editing_groupsnone'; $groupimage = $OUTPUT->pix_url('t/groupn') . ''; $grouplink = $path . '/mod.php?id=' . $mod->id . '&groupmode=2&sesskey=' . $sesskey; } } if ($mod->groupmodelink) { $groupmode = '<a class="' . $groupclass . '" title="' . $grouptitle . ' (' . $str->clicktochange . ')" href="' . $grouplink . '">' . '<img src="' . $groupimage . '" class="iconsmall" ' . 'alt="' . $grouptitle . '" /></a>'; } else { $groupmode = '<img title="' . $grouptitle . ' (' . $str->forcedmode . ')" ' . ' src="' . $groupimage . '" class="iconsmall" ' . 'alt="' . $grouptitle . '" />'; } } else { $groupmode = ""; } if (has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $mod->course))) { if ($moveselect) { $move = '<a class="editing_move" title="' . $str->move . '" href="' . $path . '/mod.php?copy=' . $mod->id . '&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/move') . '" class="iconsmall" ' . ' alt="' . $str->move . '" /></a>' . "\n"; } else { $move = '<a class="editing_moveup" title="' . $str->moveup . '" href="' . $path . '/mod.php?id=' . $mod->id . '&move=-1&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/up') . '" class="iconsmall" ' . ' alt="' . $str->moveup . '" /></a>' . "\n" . '<a class="editing_movedown" title="' . $str->movedown . '" href="' . $path . '/mod.php?id=' . $mod->id . '&move=1&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/down') . '" class="iconsmall" ' . ' alt="' . $str->movedown . '" /></a>' . "\n"; } } else { $move = ''; } $leftright = ''; if (has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $mod->course))) { if (right_to_left()) { // Exchange arrows on RTL $rightarrow = 't/left'; $leftarrow = 't/right'; } else { $rightarrow = 't/right'; $leftarrow = 't/left'; } if ($indent > 0) { $leftright .= '<a class="editing_moveleft" title="' . $str->moveleft . '" href="' . $path . '/mod.php?id=' . $mod->id . '&indent=-1&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url($leftarrow) . '" class="iconsmall" ' . ' alt="' . $str->moveleft . '" /></a>' . "\n"; } if ($indent >= 0) { $leftright .= '<a class="editing_moveright" title="' . $str->moveright . '" href="' . $path . '/mod.php?id=' . $mod->id . '&indent=1&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url($rightarrow) . '" class="iconsmall" ' . ' alt="' . $str->moveright . '" /></a>' . "\n"; } } if (has_capability('moodle/course:managegroups', $modcontext)) { $context = get_context_instance(CONTEXT_MODULE, $mod->id); $assign = '<a class="editing_assign" title="' . $str->assign . '" href="' . $CFG->wwwroot . '/' . $CFG->admin . '/roles/assign.php?contextid=' . $context->id . '"><img src="' . $OUTPUT->pix_url('i/roles') . '" alt="' . $str->assign . '" class="iconsmall"/></a>'; } else { $assign = ''; } // Duplicate (require both target import caps to be able to duplicate, see modduplicate.php) $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); if (has_all_capabilities($dupecaps, get_context_instance(CONTEXT_COURSE, $mod->course))) { $duplicatemodule = '<a class="editing_duplicate" title="' . $str->duplicate . '" href="' . $path . '/mod.php?duplicate=' . $mod->id . '&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/copy') . '" class="iconsmall" ' . ' alt="' . $str->duplicate . '" /></a>' . "\n"; } else { $duplicatemodule = ''; } return '<span class="commands">' . "\n" . $leftright . $move . '<a class="editing_update" title="' . $str->update . '" href="' . $path . '/mod.php?update=' . $mod->id . '&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/edit') . '" class="iconsmall" ' . ' alt="' . $str->update . '" /></a>' . "\n" . $duplicatemodule . '<a class="editing_delete" title="' . $str->delete . '" href="' . $path . '/mod.php?delete=' . $mod->id . '&sesskey=' . $sesskey . $section . '"><img' . ' src="' . $OUTPUT->pix_url('t/delete') . '" class="iconsmall" ' . ' alt="' . $str->delete . '" /></a>' . "\n" . $hideshow . $groupmode . "\n" . $assign . '</span>'; }
/** * Produces the editing buttons for a module * * @global core_renderer $OUTPUT * @staticvar type $str * @param stdClass $mod The module to produce editing buttons for * @param bool $absolute_ignored ignored - all links are absolute * @param bool $moveselect If true a move seleciton process is used (default true) * @param int $indent The current indenting * @param int $section The section to link back to * @return string XHTML for the editing buttons */ function make_editing_buttons(stdClass $mod, $absolute_ignored = true, $moveselect = true, $indent = -1, $section = null) { global $CFG, $OUTPUT, $COURSE; static $str; $coursecontext = context_course::instance($mod->course); $modcontext = context_module::instance($mod->id); $editcaps = array('moodle/course:manageactivities', 'moodle/course:activityvisibility', 'moodle/role:assign'); $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); // no permission to edit anything if (!has_any_capability($editcaps, $modcontext) and !has_all_capabilities($dupecaps, $coursecontext)) { return false; } $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext); if (!isset($str)) { $str = new stdClass(); $str->assign = get_string("assignroles", 'role'); $str->delete = get_string("delete"); $str->move = get_string("move"); $str->moveup = get_string("moveup"); $str->movedown = get_string("movedown"); $str->moveright = get_string("moveright"); $str->moveleft = get_string("moveleft"); $str->update = get_string("update"); $str->duplicate = get_string("duplicate"); $str->hide = get_string("hide"); $str->show = get_string("show"); $str->groupsnone = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsnone")); $str->groupsseparate = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsseparate")); $str->groupsvisible = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsvisible")); $str->forcedgroupsnone = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsnone")); $str->forcedgroupsseparate = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsseparate")); $str->forcedgroupsvisible = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsvisible")); $str->edittitle = get_string('edittitle', 'moodle'); } $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey())); if ($section !== null) { $baseurl->param('sr', $section); } $actions = array(); // AJAX edit title if ($mod->modname !== 'label' && $hasmanageactivities && course_ajax_enabled($COURSE)) { $actions[] = new action_link(new moodle_url($baseurl, array('update' => $mod->id)), new pix_icon('t/editstring', $str->edittitle, 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')), null, array('class' => 'editing_title', 'title' => $str->edittitle)); } // leftright if ($hasmanageactivities) { if (right_to_left()) { // Exchange arrows on RTL $rightarrow = 't/left'; $leftarrow = 't/right'; } else { $rightarrow = 't/right'; $leftarrow = 't/left'; } if ($indent > 0) { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')), new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_moveleft', 'title' => $str->moveleft)); } if ($indent >= 0) { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')), new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_moveright', 'title' => $str->moveright)); } } // move if ($hasmanageactivities) { if ($moveselect) { $actions[] = new action_link(new moodle_url($baseurl, array('copy' => $mod->id)), new pix_icon('t/move', $str->move, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_move', 'title' => $str->move)); } else { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'move' => '-1')), new pix_icon('t/up', $str->moveup, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_moveup', 'title' => $str->moveup)); $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'move' => '1')), new pix_icon('t/down', $str->movedown, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_movedown', 'title' => $str->movedown)); } } // Update if ($hasmanageactivities) { $actions[] = new action_link(new moodle_url($baseurl, array('update' => $mod->id)), new pix_icon('t/edit', $str->update, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_update', 'title' => $str->update)); } // Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php) if (has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) { $actions[] = new action_link(new moodle_url($baseurl, array('duplicate' => $mod->id)), new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_duplicate', 'title' => $str->duplicate)); } // Delete if ($hasmanageactivities) { $actions[] = new action_link(new moodle_url($baseurl, array('delete' => $mod->id)), new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_delete', 'title' => $str->delete)); } // hideshow if (has_capability('moodle/course:activityvisibility', $modcontext)) { if ($mod->visible) { $actions[] = new action_link(new moodle_url($baseurl, array('hide' => $mod->id)), new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_hide', 'title' => $str->hide)); } else { $actions[] = new action_link(new moodle_url($baseurl, array('show' => $mod->id)), new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_show', 'title' => $str->show)); } } // groupmode if ($hasmanageactivities and $mod->groupmode !== false) { if ($mod->groupmode == SEPARATEGROUPS) { $groupmode = 0; $grouptitle = $str->groupsseparate; $forcedgrouptitle = $str->forcedgroupsseparate; $groupclass = 'editing_groupsseparate'; $groupimage = 't/groups'; } else { if ($mod->groupmode == VISIBLEGROUPS) { $groupmode = 1; $grouptitle = $str->groupsvisible; $forcedgrouptitle = $str->forcedgroupsvisible; $groupclass = 'editing_groupsvisible'; $groupimage = 't/groupv'; } else { $groupmode = 2; $grouptitle = $str->groupsnone; $forcedgrouptitle = $str->forcedgroupsnone; $groupclass = 'editing_groupsnone'; $groupimage = 't/groupn'; } } if ($mod->groupmodelink) { $actions[] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'groupmode' => $groupmode)), new pix_icon($groupimage, $grouptitle, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => $groupclass, 'title' => $grouptitle)); } else { $actions[] = new pix_icon($groupimage, $forcedgrouptitle, 'moodle', array('title' => $forcedgrouptitle, 'class' => 'iconsmall')); } } // Assign if (has_capability('moodle/role:assign', $modcontext)) { $actions[] = new action_link(new moodle_url('/' . $CFG->admin . '/roles/assign.php', array('contextid' => $modcontext->id)), new pix_icon('t/assignroles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_assign', 'title' => $str->assign)); } // The space added before the <span> is a ugly hack but required to set the CSS property white-space: nowrap // and having it to work without attaching the preceding text along with it. Hopefully the refactoring of // the course page HTML will allow this to be removed. $output = ' ' . html_writer::start_tag('span', array('class' => 'commands')); foreach ($actions as $action) { if ($action instanceof renderable) { $output .= $OUTPUT->render($action); } else { $output .= $action; } } $output .= html_writer::end_tag('span'); return $output; }
static function add($modulename, $courseid, $atstart = 0, $ifexists = 0, $moduleparams = null, $section = 0, $visible = 0, $permissionsoverrides = array()) { global $DB, $CFG; // Check module type exists if (!($module = $DB->get_record('modules', array('name' => $modulename), '*'))) { return array(false, 'Module type not found'); } // Check course exists if (!($course = $DB->get_record('course', array('id' => $courseid), '*'))) { return array(false, 'Course not found'); } // Check course is correct format if ($course->format == 'site' || $course->format == 'social' || $course->format == 'scorm') { return array(false, 'Course is not a weekly or topic type, skipping'); } // Check user has required permissions to add course module $requiredcapabilities = array('moodle/course:manageactivities', 'moodle/course:activityvisibility', 'moodle/role:override'); if (!has_all_capabilities($requiredcapabilities, context_course::instance($courseid))) { return array(false, 'Insufficient permissions to add course module'); } // Set course module initial data $newcm = new stdClass(); $newcm->course = $course->id; $newcm->module = $module->id; $newcm->modulename = $module->name; $newcm->section = 0; $newcm->instance = 0; $newcm->visible = $visible; $newcm->groupmode = 0; // No groups $newcm->groupingid = 0; $newcm->groupmembersonly = 0; $newcm->showdescription = 0; $newcm->cmidnumber = ''; // Check whether module plugin class exists for selected module otherwise use generic module plugin $modulepluginclass = 'module_plugin_' . $modulename; $modulepluginfilename = 'moduleplugins/' . $modulepluginclass . '.php'; if (file_exists($modulepluginfilename)) { include_once $modulepluginfilename; $moduleplugin = new $modulepluginclass($moduleparams, $newcm); } else { include_once 'moduleplugins/module_plugin_generic.php'; $moduleplugin = new module_plugin_generic($moduleparams, $newcm, $modulename); $modulepluginclass = 'module_plugin_generic'; } // Check that module params XML is valid if (!$modulepluginclass::check_params_xml($moduleparams)) { return array(false, 'Module parameters not valid'); } $newcm->name = (string) $moduleparams->title; $newcm->intro = (string) $moduleparams->description; $newcm->introformat = 1; // Check whether module instance with title already exists $sql = 'SELECT COUNT(*) AS count FROM {course_sections} AS cs JOIN {course_modules} AS cm ON cm.section = cs.id JOIN {modules} AS ms ON ms.id = cm.module JOIN {' . $module->name . '} AS m ON m.id = cm.instance WHERE cs.course = ? AND cs.section = ? AND m.name = ? AND ms.name = ?'; $instances = $DB->get_record_sql($sql, array($course->id, $section, $newcm->name, $module->name)); if ($instances->count > 0) { if ($ifexists == 0) { return array(false, 'Already exists, skipping'); } else { if ($ifexists == 2) { if (!self::delete($modulename, $course, $newcm->name, $section)) { return array(false, 'Error removing existing module instance(s), could not replace'); } } } } // Create course module if (!($newcm->coursemodule = add_course_module($newcm))) { return array(false, 'Could not create course module'); } // Create module instance $ret = $moduleplugin->create_instance(); if (!$ret[0]) { return $ret; } // Update course_modules DB row to reference new module instance $DB->set_field('course_modules', 'instance', $newcm->instance, array('id' => $newcm->coursemodule)); // course_modules and course_sections each contain a reference // to each other, so we have to update one of them twice. if ($atstart) { if (!($section = $DB->get_record('course_sections', array('course' => $newcm->course, 'section' => $newcm->section)))) { // Section doesn't already exist so create it in normal manner // $sectionid = add_mod_to_section($newcm); JAC change 20160809 // requires course_add_cm_to_section($courseorid, $cmid, $sectionnum, $beforemod = null) $sectionid = course_add_cm_to_section($newcm->course, $newcm->coursemodule, $newcm->section); } else { // Moodle's add_mod_to_section add before functionality is broken so we have to do this here $section->sequence = trim($section->sequence); if (empty($section->sequence)) { $newsequence = "{$newcm->coursemodule}"; } else { $newsequence = "{$newcm->coursemodule},{$section->sequence}"; } $DB->set_field("course_sections", "sequence", $newsequence, array("id" => $section->id)); $sectionid = $section->id; } } else { // $sectionid = add_mod_to_section($newcm); JAC change 20160809 $sectionid = course_add_cm_to_section($newcm->course, $newcm->coursemodule, $newcm->section); } $DB->set_field('course_modules', 'section', $sectionid, array('id' => $newcm->coursemodule)); // Trigger post create actions $ret = $moduleplugin->post_create_setup(); if (!$ret[0]) { self::delete($modulename, $course, $newcm->name, $section); return array(false, 'Error carrying out post creation setup. Error was: ' . $ret[1]); } // If $permissionsoverrides is not empty, override permissions of specified role capabilites if (count($permissionsoverrides) > 0) { $modcontext = context_module::instance($newcm->coursemodule); foreach ($permissionsoverrides as $permissionoverride) { $permission = $permissionoverride[2] == 'allow' ? CAP_ALLOW : CAP_PREVENT; role_change_permission($permissionoverride[0], $modcontext, $permissionoverride[1], $permission); } } // Trigger mod_created event with information about this module. $eventname = 'mod_created'; $eventdata = new stdClass(); $eventdata->modulename = $module->name; $eventdata->name = $newcm->name; $eventdata->cmid = $newcm->coursemodule; $eventdata->courseid = $course->id; $eventdata->userid = 0; events_trigger($eventname, $eventdata); // Rebuild course cache rebuild_course_cache($course->id); return array(true, ''); }
// May as well just bail aggressively here. print_error('invaliduserid'); } // Make sure the user has not been deleted if ($user->deleted) { $PAGE->set_title(get_string('userdeleted')); $PAGE->set_context(get_system_context()); echo $OUTPUT->header(); echo $OUTPUT->heading($PAGE->title); echo $OUTPUT->footer(); die; } $isloggedin = isloggedin(); $isguestuser = $isloggedin && isguestuser(); $isparent = !$iscurrentuser && $DB->record_exists('role_assignments', array('userid' => $USER->id, 'contextid' => $usercontext->id)); $hasparentaccess = $isparent && has_all_capabilities(array('moodle/user:viewdetails', 'moodle/user:readuserposts'), $usercontext); // Check whether a specific course has been requested if ($isspecificcourse) { // Get the requested course and its context $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid, MUST_EXIST); // We have a specific course to search, which we will also assume we are within. if ($hasparentaccess) { // A `parent` role won't likely have access to the course so we won't attempt // to enter it. We will however still make them jump through the normal // login hoops require_login(); $PAGE->set_context($coursecontext); $PAGE->set_course($course); } else { // Enter the course we are searching
/** * Returns an array of courses the user is enrolled in, and for each course all of the seplments that the user can * view within that course. * * @param array $courseids An optional array of course ids. If provided only seplments within the given course * will be returned. If the user is not enrolled in a given course a warning will be generated and returned. * @param array $capabilities An array of additional capability checks you wish to be made on the course context. * @return An array of courses and warnings. * @since Moodle 2.4 */ public static function get_seplments($courseids = array(), $capabilities = array()) { global $USER, $DB, $CFG; require_once "{$CFG->dirroot}/mod/sepl/locallib.php"; $params = self::validate_parameters(self::get_seplments_parameters(), array('courseids' => $courseids, 'capabilities' => $capabilities)); $warnings = array(); $fields = 'sortorder,shortname,fullname,timemodified'; $courses = enrol_get_users_courses($USER->id, true, $fields); // Used to test for ids that have been requested but can't be returned. if (count($params['courseids']) > 0) { foreach ($params['courseids'] as $courseid) { if (!in_array($courseid, array_keys($courses))) { unset($courses[$courseid]); $warnings[] = array('item' => 'course', 'itemid' => $courseid, 'warningcode' => '2', 'message' => 'User is not enrolled or does not have requested capability'); } } } foreach ($courses as $id => $course) { if (count($params['courseids']) > 0 && !in_array($id, $params['courseids'])) { unset($courses[$id]); } $context = context_course::instance($id); try { self::validate_context($context); } catch (Exception $e) { unset($courses[$id]); $warnings[] = array('item' => 'course', 'itemid' => $id, 'warningcode' => '1', 'message' => 'No access rights in course context ' . $e->getMessage() . $e->getTraceAsString()); continue; } if (count($params['capabilities']) > 0 && !has_all_capabilities($params['capabilities'], $context)) { unset($courses[$id]); } } $extrafields = 'm.id as seplmentid, ' . 'm.course, ' . 'm.nosubmissions, ' . 'm.submissiondrafts, ' . 'm.sendnotifications, ' . 'm.sendlatenotifications, ' . 'm.sendstudentnotifications, ' . 'm.duedate, ' . 'm.allowsubmissionsfromdate, ' . 'm.grade, ' . 'm.timemodified, ' . 'm.completionsubmit, ' . 'm.cutoffdate, ' . 'm.teamsubmission, ' . 'm.requireallteammemberssubmit, ' . 'm.teamsubmissiongroupingid, ' . 'm.blindmarking, ' . 'm.revealidentities, ' . 'm.attemptreopenmethod, ' . 'm.maxattempts, ' . 'm.markingworkflow, ' . 'm.markingallocation, ' . 'm.requiresubmissionstatement, ' . 'm.intro, ' . 'm.introformat'; $coursearray = array(); foreach ($courses as $id => $course) { $seplmentarray = array(); // Get a list of seplments for the course. if ($modules = get_coursemodules_in_course('sepl', $courses[$id]->id, $extrafields)) { foreach ($modules as $module) { $context = context_module::instance($module->id); try { self::validate_context($context); require_capability('mod/sepl:view', $context); } catch (Exception $e) { $warnings[] = array('item' => 'module', 'itemid' => $module->id, 'warningcode' => '1', 'message' => 'No access rights in module context'); continue; } $configrecords = $DB->get_recordset('sepl_plugin_config', array('seplment' => $module->seplmentid)); $configarray = array(); foreach ($configrecords as $configrecord) { $configarray[] = array('id' => $configrecord->id, 'seplment' => $configrecord->seplment, 'plugin' => $configrecord->plugin, 'subtype' => $configrecord->subtype, 'name' => $configrecord->name, 'value' => $configrecord->value); } $configrecords->close(); $seplment = array('id' => $module->seplmentid, 'cmid' => $module->id, 'course' => $module->course, 'name' => $module->name, 'nosubmissions' => $module->nosubmissions, 'submissiondrafts' => $module->submissiondrafts, 'sendnotifications' => $module->sendnotifications, 'sendlatenotifications' => $module->sendlatenotifications, 'sendstudentnotifications' => $module->sendstudentnotifications, 'duedate' => $module->duedate, 'allowsubmissionsfromdate' => $module->allowsubmissionsfromdate, 'grade' => $module->grade, 'timemodified' => $module->timemodified, 'completionsubmit' => $module->completionsubmit, 'cutoffdate' => $module->cutoffdate, 'teamsubmission' => $module->teamsubmission, 'requireallteammemberssubmit' => $module->requireallteammemberssubmit, 'teamsubmissiongroupingid' => $module->teamsubmissiongroupingid, 'blindmarking' => $module->blindmarking, 'revealidentities' => $module->revealidentities, 'attemptreopenmethod' => $module->attemptreopenmethod, 'maxattempts' => $module->maxattempts, 'markingworkflow' => $module->markingworkflow, 'markingallocation' => $module->markingallocation, 'requiresubmissionstatement' => $module->requiresubmissionstatement, 'configs' => $configarray); // Return or not intro and file attachments depending on the plugin settings. $sepl = new sepl($context, null, null); if ($sepl->show_intro()) { list($seplment['intro'], $seplment['introformat']) = external_format_text($module->intro, $module->introformat, $context->id, 'mod_sepl', ASSIGN_INTROATTACHMENT_FILEAREA, 0); $fs = get_file_storage(); if ($files = $fs->get_area_files($context->id, 'mod_sepl', ASSIGN_INTROATTACHMENT_FILEAREA, 0, 'timemodified', false)) { $seplment['introattachments'] = array(); foreach ($files as $file) { $filename = $file->get_filename(); $seplment['introattachments'][] = array('filename' => $filename, 'mimetype' => $file->get_mimetype(), 'fileurl' => moodle_url::make_webservice_pluginfile_url($context->id, 'mod_sepl', ASSIGN_INTROATTACHMENT_FILEAREA, 0, '/', $filename)->out(false)); } } } $seplmentarray[] = $seplment; } } $coursearray[] = array('id' => $courses[$id]->id, 'fullname' => $courses[$id]->fullname, 'shortname' => $courses[$id]->shortname, 'timemodified' => $courses[$id]->timemodified, 'seplments' => $seplmentarray); } $result = array('courses' => $coursearray, 'warnings' => $warnings); return $result; }
/** * Test has_capability(), has_any_capability() and has_all_capabilities(). */ public function test_has_capability_and_friends() { global $DB; $this->resetAfterTest(); $course = $this->getDataGenerator()->create_course(); $coursecontext = context_course::instance($course->id); $teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'), '*', MUST_EXIST); $teacher = $this->getDataGenerator()->create_user(); role_assign($teacherrole->id, $teacher->id, $coursecontext); $admin = $DB->get_record('user', array('username' => 'admin')); // Note: Here are used default capabilities, the full test is in permission evaluation bellow, // use two capabilities that teacher has and one does not, none of them should be allowed for not-logged-in user. $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupsection'))); $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/backup:backupcourse'))); $this->assertTrue($DB->record_exists('capabilities', array('name' => 'moodle/site:approvecourse'))); $sca = array('moodle/backup:backupsection', 'moodle/backup:backupcourse', 'moodle/site:approvecourse'); $sc = array('moodle/backup:backupsection', 'moodle/backup:backupcourse'); $this->setUser(0); $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext)); $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext)); $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext)); $this->assertFalse(has_any_capability($sca, $coursecontext)); $this->assertFalse(has_all_capabilities($sca, $coursecontext)); $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $teacher)); $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $teacher)); $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $teacher)); $this->assertTrue(has_any_capability($sca, $coursecontext, $teacher)); $this->assertTrue(has_all_capabilities($sc, $coursecontext, $teacher)); $this->assertFalse(has_all_capabilities($sca, $coursecontext, $teacher)); $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext, $admin)); $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext, $admin)); $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext, $admin)); $this->assertTrue(has_any_capability($sca, $coursecontext, $admin)); $this->assertTrue(has_all_capabilities($sc, $coursecontext, $admin)); $this->assertTrue(has_all_capabilities($sca, $coursecontext, $admin)); $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, $admin, false)); $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, $admin, false)); $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, $admin, false)); $this->assertFalse(has_any_capability($sca, $coursecontext, $admin, false)); $this->assertFalse(has_all_capabilities($sc, $coursecontext, $admin, false)); $this->assertFalse(has_all_capabilities($sca, $coursecontext, $admin, false)); $this->setUser($teacher); $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext)); $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext)); $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext)); $this->assertTrue(has_any_capability($sca, $coursecontext)); $this->assertTrue(has_all_capabilities($sc, $coursecontext)); $this->assertFalse(has_all_capabilities($sca, $coursecontext)); $this->setAdminUser(); $this->assertTrue(has_capability('moodle/backup:backupsection', $coursecontext)); $this->assertTrue(has_capability('moodle/backup:backupcourse', $coursecontext)); $this->assertTrue(has_capability('moodle/site:approvecourse', $coursecontext)); $this->assertTrue(has_any_capability($sca, $coursecontext)); $this->assertTrue(has_all_capabilities($sc, $coursecontext)); $this->assertTrue(has_all_capabilities($sca, $coursecontext)); $this->assertFalse(has_capability('moodle/backup:backupsection', $coursecontext, 0)); $this->assertFalse(has_capability('moodle/backup:backupcourse', $coursecontext, 0)); $this->assertFalse(has_capability('moodle/site:approvecourse', $coursecontext, 0)); $this->assertFalse(has_any_capability($sca, $coursecontext, 0)); $this->assertFalse(has_all_capabilities($sca, $coursecontext, 0)); }
/** * Used to add options to the Settings menu for the subpage * @param unknown_type $settings Don't know what this parameter is * @param navigation_node $subpagenode Navigation node object for subpage */ function subpage_extend_settings_navigation($settings, navigation_node $subpagenode) { global $PAGE; if ($PAGE->user_allowed_editing()) { $url = new moodle_url('/mod/subpage/view.php', array('id' => $PAGE->cm->id)); $url->param('sesskey', sesskey()); if ($PAGE->user_is_editing()) { $url->param('edit', 'off'); $editstring = get_string('turneditingoff'); } else { $url->param('edit', 'on'); $editstring = get_string('turneditingon'); } $node = navigation_node::create($editstring, $url, navigation_node::TYPE_SETTING, null, 'subpageeditingtoggle'); $subpagenode->add_node($node, 'modedit'); } if (has_all_capabilities(array('moodle/backup:backupsection', 'moodle/backup:backupactivity'), $PAGE->context)) { $url = new moodle_url('/mod/subpage/copy.php', array('id' => $PAGE->cm->id)); $node = navigation_node::create(get_string('copy', 'subpage'), $url, navigation_node::TYPE_SETTING, null, 'subpagecopy'); $subpagenode->add_node($node); } }
/** * Returns an array of plugin reports as grade_plugin_info objects * * @param int $courseid * @return array */ public static function get_plugins_reports($courseid) { global $SITE; if (self::$gradereports !== null) { return self::$gradereports; } $context = context_course::instance($courseid); $gradereports = array(); $gradepreferences = array(); foreach (core_component::get_plugin_list('gradereport') as $plugin => $plugindir) { //some reports make no sense if we're not within a course if ($courseid == $SITE->id && ($plugin == 'grader' || $plugin == 'user')) { continue; } // Remove ones we can't see if (!has_capability('gradereport/' . $plugin . ':view', $context)) { continue; } // Singleview doesn't doesn't accomodate for all cap combos yet, so this is hardcoded.. if ($plugin === 'singleview' && !has_all_capabilities(array('moodle/grade:viewall', 'moodle/grade:edit'), $context)) { continue; } $pluginstr = get_string('pluginname', 'gradereport_' . $plugin); $url = new moodle_url('/grade/report/' . $plugin . '/index.php', array('id' => $courseid)); $gradereports[$plugin] = new grade_plugin_info($plugin, $url, $pluginstr); // Add link to preferences tab if such a page exists if (file_exists($plugindir . '/preferences.php')) { $url = new moodle_url('/grade/report/' . $plugin . '/preferences.php', array('id' => $courseid)); $gradepreferences[$plugin] = new grade_plugin_info($plugin, $url, get_string('preferences', 'grades') . ': ' . $pluginstr); } } if (count($gradereports) == 0) { $gradereports = false; $gradepreferences = false; } else { if (count($gradepreferences) == 0) { $gradepreferences = false; asort($gradereports); } else { asort($gradereports); asort($gradepreferences); } } self::$gradereports = $gradereports; self::$gradereportpreferences = $gradepreferences; return self::$gradereports; }
/** * This function recursively travels the categories, building up a nice list * for display. It also makes an array that list all the parents for each * category. * * For example, if you have a tree of categories like: * Miscellaneous (id = 1) * Subcategory (id = 2) * Sub-subcategory (id = 4) * Other category (id = 3) * Then after calling this function you will have * $list = array(1 => 'Miscellaneous', 2 => 'Miscellaneous / Subcategory', * 4 => 'Miscellaneous / Subcategory / Sub-subcategory', * 3 => 'Other category'); * $parents = array(2 => array(1), 4 => array(1, 2)); * * If you specify $requiredcapability, then only categories where the current * user has that capability will be added to $list, although all categories * will still be added to $parents, and if you only have $requiredcapability * in a child category, not the parent, then the child catgegory will still be * included. * * If you specify the option $excluded, then that category, and all its children, * are omitted from the tree. This is useful when you are doing something like * moving categories, where you do not want to allow people to move a category * to be the child of itself. * * @param array $list For output, accumulates an array categoryid => full category path name * @param array $parents For output, accumulates an array categoryid => list of parent category ids. * @param string/array $requiredcapability if given, only categories where the current * user has this capability will be added to $list. Can also be an array of capabilities, * in which case they are all required. * @param integer $excludeid Omit this category and its children from the lists built. * @param object $category Build the tree starting at this category - otherwise starts at the top level. * @param string $path For internal use, as part of recursive calls. */ function make_categories_list(&$list, &$parents, $requiredcapability = '', $excludeid = 0, $category = NULL, $path = "") { // initialize the arrays if needed if (!is_array($list)) { $list = array(); } if (!is_array($parents)) { $parents = array(); } if (empty($category)) { // Start at the top level. $category = new stdClass(); $category->id = 0; } else { // This is the excluded category, don't include it. if ($excludeid > 0 && $excludeid == $category->id) { return; } // Update $path. if ($path) { $path = $path . ' / ' . format_string($category->name); } else { $path = format_string($category->name); } // Add this category to $list, if the permissions check out. if (empty($requiredcapability)) { $list[$category->id] = $path; } else { ensure_context_subobj_present($category, CONTEXT_COURSECAT); $requiredcapability = (array) $requiredcapability; if (has_all_capabilities($requiredcapability, $category->context)) { $list[$category->id] = $path; } } } // Add all the children recursively, while updating the parents array. if ($categories = get_child_categories($category->id)) { foreach ($categories as $cat) { if (!empty($category->id)) { if (isset($parents[$category->id])) { $parents[$cat->id] = $parents[$category->id]; } $parents[$cat->id][] = $category->id; } make_categories_list($list, $parents, $requiredcapability, $excludeid, $cat, $path); } } }
/** * add elements to grade form * * @param MoodleQuickForm $mform * @param stdClass $data * @param array $params * @return void */ public function add_grade_form_elements(MoodleQuickForm $mform, stdClass $data, $params) { global $USER, $CFG; $settings = $this->get_instance(); $rownum = $params['rownum']; $last = $params['last']; $useridlist = $params['useridlist']; $userid = $useridlist[$rownum]; $grade = $this->get_user_grade($userid, false); // add advanced grading $gradingdisabled = $this->grading_disabled($userid); $gradinginstance = $this->get_grading_instance($userid, $gradingdisabled); if ($gradinginstance) { $gradingelement = $mform->addElement('grading', 'advancedgrading', get_string('grade').':', array('gradinginstance' => $gradinginstance)); if ($gradingdisabled) { $gradingelement->freeze(); } else { $mform->addElement('hidden', 'advancedgradinginstanceid', $gradinginstance->get_id()); } } else { // use simple direct grading if ($this->get_instance()->grade > 0) { $gradingelement = $mform->addElement('text', 'grade', get_string('gradeoutof', 'assign',$this->get_instance()->grade)); $mform->addHelpButton('grade', 'gradeoutofhelp', 'assign'); $mform->setType('grade', PARAM_TEXT); if ($gradingdisabled) { $gradingelement->freeze(); } } else { $grademenu = make_grades_menu($this->get_instance()->grade); if (count($grademenu) > 0) { $gradingelement = $mform->addElement('select', 'grade', get_string('grade').':', $grademenu); $mform->setType('grade', PARAM_INT); if ($gradingdisabled) { $gradingelement->freeze(); } } } } $gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, $userid); if (!empty($CFG->enableoutcomes)) { foreach($gradinginfo->outcomes as $index=>$outcome) { $options = make_grades_menu(-$outcome->scaleid); if ($outcome->grades[$userid]->locked) { $options[0] = get_string('nooutcome', 'grades'); $mform->addElement('static', 'outcome_'.$index.'['.$userid.']', $outcome->name.':', $options[$outcome->grades[$userid]->grade]); } else { $options[''] = get_string('nooutcome', 'grades'); $attributes = array('id' => 'menuoutcome_'.$index ); $mform->addElement('select', 'outcome_'.$index.'['.$userid.']', $outcome->name.':', $options, $attributes ); $mform->setType('outcome_'.$index.'['.$userid.']', PARAM_INT); $mform->setDefault('outcome_'.$index.'['.$userid.']', $outcome->grades[$userid]->grade ); } } } if (has_all_capabilities(array('gradereport/grader:view', 'moodle/grade:viewall'), $this->get_course_context())) { $gradestring = $this->output->action_link(new moodle_url('/grade/report/grader/index.php', array('id'=>$this->get_course()->id)), $gradinginfo->items[0]->grades[$userid]->str_grade); } else { $gradestring = $gradinginfo->items[0]->grades[$userid]->str_grade; } $mform->addElement('static', 'finalgrade', get_string('currentgrade', 'assign').':', $gradestring); $mform->addElement('static', 'progress', '', get_string('gradingstudentprogress', 'assign', array('index'=>$rownum+1, 'count'=>count($useridlist)))); // plugins $this->add_plugin_grade_elements($grade, $mform, $data); // hidden params $mform->addElement('hidden', 'id', $this->get_course_module()->id); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'rownum', $rownum); $mform->setType('rownum', PARAM_INT); $mform->addElement('hidden', 'useridlist', implode(',', $useridlist)); $mform->setType('useridlist', PARAM_TEXT); $mform->addElement('hidden', 'ajax', optional_param('ajax', 0, PARAM_INT)); $mform->setType('ajax', PARAM_INT); if ($this->get_instance()->teamsubmission) { $mform->addElement('selectyesno', 'applytoall', get_string('applytoteam', 'assign')); $mform->setDefault('applytoall', 1); } $mform->addElement('hidden', 'action', 'submitgrade'); $mform->setType('action', PARAM_ALPHA); $buttonarray=array(); $buttonarray[] = $mform->createElement('submit', 'savegrade', get_string('savechanges', 'assign')); if (!$last) { $buttonarray[] = $mform->createElement('submit', 'saveandshownext', get_string('savenext','assign')); } $buttonarray[] = $mform->createElement('cancel', 'cancelbutton', get_string('cancel')); $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false); $mform->closeHeaderBefore('buttonar'); $buttonarray=array(); if ($rownum > 0) { $buttonarray[] = $mform->createElement('submit', 'nosaveandprevious', get_string('previous','assign')); } if (!$last) { $buttonarray[] = $mform->createElement('submit', 'nosaveandnext', get_string('nosavebutnext', 'assign')); } $mform->addGroup($buttonarray, 'navar', '', array(' '), false); }
/** * Returns the list of all editing actions that current user can perform on the module * * @param cm_info $mod The module to produce editing buttons for * @param int $indent The current indenting (default -1 means no move left-right actions) * @param int $sr The section to link back to (used for creating the links) * @return array array of action_link or pix_icon objects */ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) { global $COURSE, $SITE; static $str; $coursecontext = context_course::instance($mod->course); $modcontext = context_module::instance($mod->id); $editcaps = array('moodle/course:manageactivities', 'moodle/course:activityvisibility', 'moodle/role:assign'); $dupecaps = array('moodle/backup:backuptargetimport', 'moodle/restore:restoretargetimport'); // no permission to edit anything if (!has_any_capability($editcaps, $modcontext) and !has_all_capabilities($dupecaps, $coursecontext)) { return array(); } $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext); if (!isset($str)) { $str = get_strings(array('delete', 'move', 'moveright', 'moveleft', 'update', 'duplicate', 'hide', 'show', 'edittitle'), 'moodle'); $str->assign = get_string('assignroles', 'role'); $str->groupsnone = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsnone")); $str->groupsseparate = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsseparate")); $str->groupsvisible = get_string('clicktochangeinbrackets', 'moodle', get_string("groupsvisible")); $str->forcedgroupsnone = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsnone")); $str->forcedgroupsseparate = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsseparate")); $str->forcedgroupsvisible = get_string('forcedmodeinbrackets', 'moodle', get_string("groupsvisible")); } $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey())); if ($sr !== null) { $baseurl->param('sr', $sr); } $actions = array(); // AJAX edit title if ($mod->has_view() && $hasmanageactivities && ($mod->course == $COURSE->id && course_ajax_enabled($COURSE) || $mod->course == SITEID && course_ajax_enabled($SITE))) { // we will not display link if we are on some other-course page (where we should not see this module anyway) $actions['title'] = new action_link(new moodle_url($baseurl, array('update' => $mod->id)), new pix_icon('t/editstring', $str->edittitle, 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')), null, array('class' => 'editing_title', 'title' => $str->edittitle)); } // leftright if ($hasmanageactivities) { if (right_to_left()) { // Exchange arrows on RTL $rightarrow = 't/left'; $leftarrow = 't/right'; } else { $rightarrow = 't/right'; $leftarrow = 't/left'; } if ($indent > 0) { $actions['moveleft'] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '-1')), new pix_icon($leftarrow, $str->moveleft, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_moveleft', 'title' => $str->moveleft)); } if ($indent >= 0) { $actions['moveright'] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'indent' => '1')), new pix_icon($rightarrow, $str->moveright, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_moveright', 'title' => $str->moveright)); } } // move if ($hasmanageactivities) { $actions['move'] = new action_link(new moodle_url($baseurl, array('copy' => $mod->id)), new pix_icon('t/move', $str->move, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_move', 'title' => $str->move)); } // Update if ($hasmanageactivities) { $actions['update'] = new action_link(new moodle_url($baseurl, array('update' => $mod->id)), new pix_icon('t/edit', $str->update, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_update', 'title' => $str->update)); } // Duplicate (require both target import caps to be able to duplicate and backup2 support, see modduplicate.php) // note that restoring on front page is never allowed if ($mod->course != SITEID && has_all_capabilities($dupecaps, $coursecontext) && plugin_supports('mod', $mod->modname, FEATURE_BACKUP_MOODLE2)) { $actions['duplicate'] = new action_link(new moodle_url($baseurl, array('duplicate' => $mod->id)), new pix_icon('t/copy', $str->duplicate, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_duplicate', 'title' => $str->duplicate)); } // Delete if ($hasmanageactivities) { $actions['delete'] = new action_link(new moodle_url($baseurl, array('delete' => $mod->id)), new pix_icon('t/delete', $str->delete, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_delete', 'title' => $str->delete)); } // hideshow if (has_capability('moodle/course:activityvisibility', $modcontext)) { if ($mod->visible) { $actions['hide'] = new action_link(new moodle_url($baseurl, array('hide' => $mod->id)), new pix_icon('t/hide', $str->hide, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_hide', 'title' => $str->hide)); } else { $actions['show'] = new action_link(new moodle_url($baseurl, array('show' => $mod->id)), new pix_icon('t/show', $str->show, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_show', 'title' => $str->show)); } } // groupmode if ($hasmanageactivities and plugin_supports('mod', $mod->modname, FEATURE_GROUPS, 0)) { if ($mod->coursegroupmodeforce) { $modgroupmode = $mod->coursegroupmode; } else { $modgroupmode = $mod->groupmode; } if ($modgroupmode == SEPARATEGROUPS) { $groupmode = NOGROUPS; $grouptitle = $str->groupsseparate; $forcedgrouptitle = $str->forcedgroupsseparate; $actionname = 'groupsseparate'; $groupimage = 't/groups'; } else { if ($modgroupmode == VISIBLEGROUPS) { $groupmode = SEPARATEGROUPS; $grouptitle = $str->groupsvisible; $forcedgrouptitle = $str->forcedgroupsvisible; $actionname = 'groupsvisible'; $groupimage = 't/groupv'; } else { $groupmode = VISIBLEGROUPS; $grouptitle = $str->groupsnone; $forcedgrouptitle = $str->forcedgroupsnone; $actionname = 'groupsnone'; $groupimage = 't/groupn'; } } if (!$mod->coursegroupmodeforce) { $actions[$actionname] = new action_link(new moodle_url($baseurl, array('id' => $mod->id, 'groupmode' => $groupmode)), new pix_icon($groupimage, $grouptitle, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_' . $actionname, 'title' => $grouptitle)); } else { $actions[$actionname] = new pix_icon($groupimage, $forcedgrouptitle, 'moodle', array('title' => $forcedgrouptitle, 'class' => 'iconsmall')); } } // Assign if (has_capability('moodle/role:assign', $modcontext)) { $actions['assign'] = new action_link(new moodle_url('/admin/roles/assign.php', array('contextid' => $modcontext->id)), new pix_icon('t/assignroles', $str->assign, 'moodle', array('class' => 'iconsmall', 'title' => '')), null, array('class' => 'editing_assign', 'title' => $str->assign)); } return $actions; }
/** * Returns true if the user can change the visibility of this course. * * Note: this function does not check that the current user can access the course. * To do that please call require_login with the course, or if not possible call {@see course_in_list::can_access()} * * @return bool */ public function can_change_visibility() { // You must be able to both hide a course and view the hidden course. return has_all_capabilities(array('moodle/course:visibility', 'moodle/course:viewhiddencourses'), $this->get_context()); }
/** * Builds and returns the rows that will make up the right part of the grader report * @param boolean $displayaverages whether to display average rows in the table * @return array Array of html_table_row objects */ public function get_right_rows($displayaverages) { global $CFG, $USER, $OUTPUT, $DB, $PAGE; $rows = array(); $this->rowcount = 0; $numrows = count($this->gtree->get_levels()); $numusers = count($this->users); $gradetabindex = 1; $columnstounset = array(); $strgrade = $this->get_lang_string('grade'); $strfeedback = $this->get_lang_string("feedback"); $arrows = $this->get_sort_arrows(); $jsarguments = array('cfg' => array('ajaxenabled' => false), 'items' => array(), 'users' => array(), 'feedback' => array()); $jsscales = array(); // Get preferences once. $showactivityicons = $this->get_pref('showactivityicons'); $quickgrading = $this->get_pref('quickgrading'); $showquickfeedback = $this->get_pref('showquickfeedback'); $enableajax = $this->get_pref('enableajax'); $showanalysisicon = $this->get_pref('showanalysisicon'); // Get strings which are re-used inside the loop. $strftimedatetimeshort = get_string('strftimedatetimeshort'); $strexcludedgrades = get_string('excluded', 'grades'); $strerror = get_string('error'); foreach ($this->gtree->get_levels() as $key => $row) { $headingrow = new html_table_row(); $headingrow->attributes['class'] = 'heading_name_row'; foreach ($row as $columnkey => $element) { $sortlink = clone $this->baseurl; if (isset($element['object']->id)) { $sortlink->param('sortitemid', $element['object']->id); } $eid = $element['eid']; $object = $element['object']; $type = $element['type']; $categorystate = @$element['categorystate']; if (!empty($element['colspan'])) { $colspan = $element['colspan']; } else { $colspan = 1; } if (!empty($element['depth'])) { $catlevel = 'catlevel' . $element['depth']; } else { $catlevel = ''; } // Element is a filler if ($type == 'filler' or $type == 'fillerfirst' or $type == 'fillerlast') { $fillercell = new html_table_cell(); $fillercell->attributes['class'] = $type . ' ' . $catlevel; $fillercell->colspan = $colspan; $fillercell->text = ' '; // This is a filler cell; don't use a <th>, it'll confuse screen readers. $fillercell->header = false; $headingrow->cells[] = $fillercell; } else { if ($type == 'category') { // Element is a category $categorycell = new html_table_cell(); $categorycell->attributes['class'] = 'category ' . $catlevel; $categorycell->colspan = $colspan; $categorycell->text = $this->get_course_header($element); $categorycell->header = true; $categorycell->scope = 'col'; // Print icons if ($USER->gradeediting[$this->courseid]) { $categorycell->text .= $this->get_icons($element); } $headingrow->cells[] = $categorycell; } else { // Element is a grade_item if ($element['object']->id == $this->sortitemid) { if ($this->sortorder == 'ASC') { $arrow = $this->get_sort_arrow('up', $sortlink); } else { $arrow = $this->get_sort_arrow('down', $sortlink); } } else { $arrow = $this->get_sort_arrow('move', $sortlink); } $headerlink = $this->gtree->get_element_header($element, true, $showactivityicons, false, false, true); $itemcell = new html_table_cell(); $itemcell->attributes['class'] = $type . ' ' . $catlevel . ' highlightable' . ' i' . $element['object']->id; $itemcell->attributes['data-itemid'] = $element['object']->id; if ($element['object']->is_hidden()) { $itemcell->attributes['class'] .= ' dimmed_text'; } $singleview = ''; if (has_all_capabilities(array('gradereport/singleview:view', 'moodle/grade:viewall', 'moodle/grade:edit'), $this->context)) { $url = new moodle_url('/grade/report/singleview/index.php', array('id' => $this->course->id, 'item' => 'grade', 'itemid' => $element['object']->id)); $singleview = $OUTPUT->action_icon($url, new pix_icon('t/editstring', get_string('singleview', 'grades', $element['object']->get_name()))); } $itemcell->colspan = $colspan; $itemcell->text = shorten_text($headerlink) . $arrow . $singleview; $itemcell->header = true; $itemcell->scope = 'col'; $headingrow->cells[] = $itemcell; } } } $rows[] = $headingrow; } $rows = $this->get_right_icons_row($rows); // Preload scale objects for items with a scaleid and initialize tab indices $scaleslist = array(); $tabindices = array(); foreach ($this->gtree->get_items() as $itemid => $item) { $scale = null; if (!empty($item->scaleid)) { $scaleslist[] = $item->scaleid; $jsarguments['items'][$itemid] = array('id' => $itemid, 'name' => $item->get_name(true), 'type' => 'scale', 'scale' => $item->scaleid, 'decimals' => $item->get_decimals()); } else { $jsarguments['items'][$itemid] = array('id' => $itemid, 'name' => $item->get_name(true), 'type' => 'value', 'scale' => false, 'decimals' => $item->get_decimals()); } $tabindices[$item->id]['grade'] = $gradetabindex; $tabindices[$item->id]['feedback'] = $gradetabindex + $numusers; $gradetabindex += $numusers * 2; } $scalesarray = array(); if (!empty($scaleslist)) { $scalesarray = $DB->get_records_list('scale', 'id', $scaleslist); } $jsscales = $scalesarray; foreach ($this->users as $userid => $user) { if ($this->canviewhidden) { $altered = array(); $unknown = array(); } else { $hidingaffected = grade_grade::get_hiding_affected($this->grades[$userid], $this->gtree->get_items()); $altered = $hidingaffected['altered']; $unknown = $hidingaffected['unknown']; unset($hidingaffected); } $itemrow = new html_table_row(); $itemrow->id = 'user_' . $userid; $fullname = fullname($user); $jsarguments['users'][$userid] = $fullname; foreach ($this->gtree->items as $itemid => $unused) { $item =& $this->gtree->items[$itemid]; $grade = $this->grades[$userid][$item->id]; $itemcell = new html_table_cell(); $itemcell->id = 'u' . $userid . 'i' . $itemid; $itemcell->attributes['data-itemid'] = $itemid; // Get the decimal points preference for this item $decimalpoints = $item->get_decimals(); if (in_array($itemid, $unknown)) { $gradeval = null; } else { if (array_key_exists($itemid, $altered)) { $gradeval = $altered[$itemid]; } else { $gradeval = $grade->finalgrade; } } if (!empty($grade->finalgrade)) { $gradevalforjs = null; if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $gradevalforjs = (int) $gradeval; } else { $gradevalforjs = format_float($gradeval, $decimalpoints); } $jsarguments['grades'][] = array('user' => $userid, 'item' => $itemid, 'grade' => $gradevalforjs); } // MDL-11274 // Hide grades in the grader report if the current grader doesn't have 'moodle/grade:viewhidden' if (!$this->canviewhidden and $grade->is_hidden()) { if (!empty($CFG->grade_hiddenasdate) and $grade->get_datesubmitted() and !$item->is_category_item() and !$item->is_course_item()) { // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records $itemcell->text = "<span class='datesubmitted'>" . userdate($grade->get_datesubmitted(), $strftimedatetimeshort) . "</span>"; } else { $itemcell->text = '-'; } $itemrow->cells[] = $itemcell; continue; } // emulate grade element $eid = $this->gtree->get_grade_eid($grade); $element = array('eid' => $eid, 'object' => $grade, 'type' => 'grade'); $itemcell->attributes['class'] .= ' grade i' . $itemid; if ($item->is_category_item()) { $itemcell->attributes['class'] .= ' cat'; } if ($item->is_course_item()) { $itemcell->attributes['class'] .= ' course'; } if ($grade->is_overridden()) { $itemcell->attributes['class'] .= ' overridden'; $itemcell->attributes['aria-label'] = get_string('overriddengrade', 'gradereport_grader'); } if (!empty($grade->feedback)) { $feedback = wordwrap(trim(format_string($grade->feedback, $grade->feedbackformat)), 34, '<br>'); $itemcell->attributes['data-feedback'] = $feedback; $jsarguments['feedback'][] = array('user' => $userid, 'item' => $itemid, 'content' => $feedback); } if ($grade->is_excluded()) { // Adding white spaces before and after to prevent a screenreader from // thinking that the words are attached to the next/previous <span> or text. $itemcell->text .= " <span class='excludedfloater'>" . $strexcludedgrades . "</span> "; } // Do not show any icons if no grade (no record in DB to match) if (!$item->needsupdate and $USER->gradeediting[$this->courseid]) { $itemcell->text .= $this->get_icons($element); } $hidden = ''; if ($grade->is_hidden()) { $hidden = ' dimmed_text '; } $gradepass = '******'; if ($grade->is_passed($item)) { $gradepass = '******'; } else { if (is_null($grade->is_passed($item))) { $gradepass = ''; } } // if in editing mode, we need to print either a text box // or a drop down (for scales) // grades in item of type grade category or course are not directly editable if ($item->needsupdate) { $itemcell->text .= "<span class='gradingerror{$hidden}'>" . $strerror . "</span>"; } else { if ($USER->gradeediting[$this->courseid]) { if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $scale = $scalesarray[$item->scaleid]; $gradeval = (int) $gradeval; // scales use only integers $scales = explode(",", $scale->scale); // reindex because scale is off 1 // MDL-12104 some previous scales might have taken up part of the array // so this needs to be reset $scaleopt = array(); $i = 0; foreach ($scales as $scaleoption) { $i++; $scaleopt[$i] = $scaleoption; } if ($quickgrading and $grade->is_editable()) { $oldval = empty($gradeval) ? -1 : $gradeval; if (empty($item->outcomeid)) { $nogradestr = $this->get_lang_string('nograde'); } else { $nogradestr = $this->get_lang_string('nooutcome', 'grades'); } $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id' => 'grade_' . $userid . '_' . $item->id); $gradelabel = $fullname . ' ' . $item->itemname; $itemcell->text .= html_writer::label(get_string('useractivitygrade', 'gradereport_grader', $gradelabel), $attributes['id'], false, array('class' => 'accesshide')); $itemcell->text .= html_writer::select($scaleopt, 'grade[' . $userid . '][' . $item->id . ']', $gradeval, array(-1 => $nogradestr), $attributes); } else { if (!empty($scale)) { $scales = explode(",", $scale->scale); // invalid grade if gradeval < 1 if ($gradeval < 1) { $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>-</span>"; } else { $gradeval = $grade->grade_item->bounded_grade($gradeval); //just in case somebody changes scale $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>{$scales[$gradeval - 1]}</span>"; } } } } else { if ($item->gradetype != GRADE_TYPE_TEXT) { // Value type if ($quickgrading and $grade->is_editable()) { $value = format_float($gradeval, $decimalpoints); $gradelabel = $fullname . ' ' . $item->itemname; $itemcell->text .= '<label class="accesshide" for="grade_' . $userid . '_' . $item->id . '">' . get_string('useractivitygrade', 'gradereport_grader', $gradelabel) . '</label>'; $itemcell->text .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade'] . '" type="text" class="text" title="' . $strgrade . '" name="grade[' . $userid . '][' . $item->id . ']" id="grade_' . $userid . '_' . $item->id . '" value="' . $value . '" />'; } else { $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>" . format_float($gradeval, $decimalpoints) . "</span>"; } } } // If quickfeedback is on, print an input element if ($showquickfeedback and $grade->is_editable()) { $feedbacklabel = $fullname . ' ' . $item->itemname; $itemcell->text .= '<label class="accesshide" for="feedback_' . $userid . '_' . $item->id . '">' . get_string('useractivityfeedback', 'gradereport_grader', $feedbacklabel) . '</label>'; $itemcell->text .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'] . '" id="feedback_' . $userid . '_' . $item->id . '" size="6" title="' . $strfeedback . '" type="text" name="feedback[' . $userid . '][' . $item->id . ']" value="' . s($grade->feedback) . '" />'; } } else { // Not editing $gradedisplaytype = $item->get_displaytype(); if ($item->scaleid && !empty($scalesarray[$item->scaleid])) { $itemcell->attributes['class'] .= ' grade_type_scale'; } else { if ($item->gradetype != GRADE_TYPE_TEXT) { $itemcell->attributes['class'] .= ' grade_type_text'; } } if ($enableajax) { $canoverride = true; if ($item->is_category_item() || $item->is_course_item()) { $canoverride = (bool) get_config('moodle', 'grade_overridecat'); } if ($canoverride) { $itemcell->attributes['class'] .= ' clickable'; } } if ($item->needsupdate) { $itemcell->text .= "<span class='gradingerror{$hidden}{$gradepass}'>" . $error . "</span>"; } else { // The max and min for an aggregation may be different to the grade_item. if (!is_null($gradeval)) { $item->grademax = $grade->get_grade_max(); $item->grademin = $grade->get_grade_min(); } $itemcell->text .= "<span class='gradevalue{$hidden}{$gradepass}'>" . grade_format_gradevalue($gradeval, $item, true, $gradedisplaytype, null) . "</span>"; if ($showanalysisicon) { $itemcell->text .= $this->gtree->get_grade_analysis_icon($grade); } } } } if (!empty($this->gradeserror[$item->id][$userid])) { $itemcell->text .= $this->gradeserror[$item->id][$userid]; } $itemrow->cells[] = $itemcell; } $rows[] = $itemrow; } if ($enableajax) { $jsarguments['cfg']['ajaxenabled'] = true; $jsarguments['cfg']['scales'] = array(); foreach ($jsscales as $scale) { $jsarguments['cfg']['scales'][$scale->id] = explode(',', $scale->scale); } $jsarguments['cfg']['feedbacktrunclength'] = $this->feedback_trunc_length; // Student grades and feedback are already at $jsarguments['feedback'] and $jsarguments['grades'] } $jsarguments['cfg']['isediting'] = (bool) $USER->gradeediting[$this->courseid]; $jsarguments['cfg']['courseid'] = $this->courseid; $jsarguments['cfg']['studentsperpage'] = $this->get_students_per_page(); $jsarguments['cfg']['showquickfeedback'] = (bool) $showquickfeedback; $module = array('name' => 'gradereport_grader', 'fullpath' => '/grade/report/grader/module.js', 'requires' => array('base', 'dom', 'event', 'event-mouseenter', 'event-key', 'io-queue', 'json-parse', 'overlay')); $PAGE->requires->js_init_call('M.gradereport_grader.init_report', $jsarguments, false, $module); $PAGE->requires->strings_for_js(array('addfeedback', 'feedback', 'grade'), 'grades'); $PAGE->requires->strings_for_js(array('ajaxchoosescale', 'ajaxclicktoclose', 'ajaxerror', 'ajaxfailedupdate', 'ajaxfieldchanged'), 'gradereport_grader'); if (!$enableajax && $USER->gradeediting[$this->courseid]) { $PAGE->requires->yui_module('moodle-core-formchangechecker', 'M.core_formchangechecker.init', array(array('formid' => 'gradereport_grader'))); $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle'); } $rows = $this->get_right_range_row($rows); if ($displayaverages) { $rows = $this->get_right_avg_row($rows, true); $rows = $this->get_right_avg_row($rows); } return $rows; }
/** * A list of courses that match a search * * @global object * @global object * @param array $searchterms An array of search criteria * @param string $sort A field and direction to sort by * @param int $page The page number to get * @param int $recordsperpage The number of records per page * @param int $totalcount Passed in by reference. * @param array $requiredcapabilities Extra list of capabilities used to filter courses * @return object {@link $COURSE} records */ function get_courses_search($searchterms, $sort, $page, $recordsperpage, &$totalcount, $requiredcapabilities = array()) { global $CFG, $DB; if ($DB->sql_regex_supported()) { $REGEXP = $DB->sql_regex(true); $NOTREGEXP = $DB->sql_regex(false); } $searchcond = array(); $params = array(); $i = 0; // Thanks Oracle for your non-ansi concat and type limits in coalesce. MDL-29912 if ($DB->get_dbfamily() == 'oracle') { $concat = "(c.summary|| ' ' || c.fullname || ' ' || c.idnumber || ' ' || c.shortname)"; } else { $concat = $DB->sql_concat("COALESCE(c.summary, '')", "' '", 'c.fullname', "' '", 'c.idnumber', "' '", 'c.shortname'); } foreach ($searchterms as $searchterm) { $i++; $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle /// will use it to simulate the "-" operator with LIKE clause /// Under Oracle and MSSQL, trim the + and - operators and perform /// simpler LIKE (or NOT LIKE) queries if (!$DB->sql_regex_supported()) { if (substr($searchterm, 0, 1) == '-') { $NOT = true; } $searchterm = trim($searchterm, '+-'); } // TODO: +- may not work for non latin languages if (substr($searchterm, 0, 1) == '+') { $searchterm = trim($searchterm, '+-'); $searchterm = preg_quote($searchterm, '|'); $searchcond[] = "{$concat} {$REGEXP} :ss{$i}"; $params['ss' . $i] = "(^|[^a-zA-Z0-9]){$searchterm}([^a-zA-Z0-9]|\$)"; } else { if (substr($searchterm, 0, 1) == "-") { $searchterm = trim($searchterm, '+-'); $searchterm = preg_quote($searchterm, '|'); $searchcond[] = "{$concat} {$NOTREGEXP} :ss{$i}"; $params['ss' . $i] = "(^|[^a-zA-Z0-9]){$searchterm}([^a-zA-Z0-9]|\$)"; } else { $searchcond[] = $DB->sql_like($concat, ":ss{$i}", false, true, $NOT); $params['ss' . $i] = "%{$searchterm}%"; } } } if (empty($searchcond)) { $searchcond = array('1 = 1'); } $searchcond = implode(" AND ", $searchcond); $courses = array(); $c = 0; // counts how many visible courses we've seen // Tiki pagination $limitfrom = $page * $recordsperpage; $limitto = $limitfrom + $recordsperpage; $ccselect = ', ' . context_helper::get_preload_record_columns_sql('ctx'); $ccjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = c.id AND ctx.contextlevel = :contextlevel)"; $params['contextlevel'] = CONTEXT_COURSE; $sql = "SELECT c.* {$ccselect}\n FROM {course} c\n {$ccjoin}\n WHERE {$searchcond} AND c.id <> " . SITEID . "\n ORDER BY {$sort}"; $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $course) { // Preload contexts only for hidden courses or courses we need to return. context_helper::preload_from_record($course); $coursecontext = context_course::instance($course->id); if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) { continue; } if (!empty($requiredcapabilities)) { if (!has_all_capabilities($requiredcapabilities, $coursecontext)) { continue; } } // Don't exit this loop till the end // we need to count all the visible courses // to update $totalcount if ($c >= $limitfrom && $c < $limitto) { $courses[$course->id] = $course; } $c++; } $rs->close(); // our caller expects 2 bits of data - our return // array, and an updated $totalcount $totalcount = $c; return $courses; }
// can't do anything else with the front page echo " <td> </td>\n"; // category place echo " <td> </td>\n"; // select place echo " <td> </td>\n"; // edit place echo "</tr>\n"; continue; } echo "<tr>\n"; echo "<td><a {$linkcss} href=\"view.php?id={$course->id}\">" . highlight($search, $coursecontext->get_context_name(false)) . "</a></td>\n"; echo "<td>" . $displaylist[$course->category] . "</td>\n"; echo "<td>\n"; // If user has all required capabilities to move course then show selectable checkbox if (has_all_capabilities($capabilities, $coursecontext)) { echo "<input type=\"checkbox\" name=\"c{$course->id}\" />\n"; } else { echo "<input type=\"checkbox\" name=\"c{$course->id}\" disabled=\"disabled\" />\n"; } echo "</td>\n"; echo "<td>\n"; // checks whether user can update course settings if (has_capability('moodle/course:update', $coursecontext)) { echo "<a title=\"" . get_string("settings") . "\" href=\"{$CFG->wwwroot}/course/edit.php?id={$course->id}\">\n<img" . " src=\"" . $OUTPUT->pix_url('t/edit') . "\" class=\"iconsmall\" alt=\"" . get_string("settings") . "\" /></a>\n "; } // checks whether user can do role assignment if (has_capability('moodle/course:enrolreview', $coursecontext)) { echo '<a title="' . get_string('enrolledusers', 'enrol') . '" href="' . $CFG->wwwroot . '/enrol/users.php?id=' . $course->id . '">'; echo '<img src="' . $OUTPUT->pix_url('i/enrolusers') . '" class="iconsmall" alt="' . get_string('enrolledusers', 'enrol') . '" /></a> ' . "\n"; }
/** * Returns posts made by the selected user in the requested courses. * * This method can be used to return all of the posts made by the requested user * within the given courses. * For each course the access of the current user and requested user is checked * and then for each post access to the post and forum is checked as well. * * This function is safe to use with usercapabilities. * * @global moodle_database $DB * @param stdClass $user The user whose posts we want to get * @param array $courses The courses to search * @param bool $musthaveaccess If set to true errors will be thrown if the user * cannot access one or more of the courses to search * @param bool $discussionsonly If set to true only discussion starting posts * will be returned. * @param int $limitfrom The offset of records to return * @param int $limitnum The number of records to return * @return stdClass An object the following properties * ->totalcount: the total number of posts made by the requested user * that the current user can see. * ->courses: An array of courses the current user can see that the * requested user has posted in. * ->forums: An array of forums relating to the posts returned in the * property below. * ->posts: An array containing the posts to show for this request. */ function forum_get_posts_by_user($user, array $courses, $musthaveaccess = false, $discussionsonly = false, $limitfrom = 0, $limitnum = 50) { global $DB, $USER, $CFG; $return = new stdClass; $return->totalcount = 0; // The total number of posts that the current user is able to view $return->courses = array(); // The courses the current user can access $return->forums = array(); // The forums that the current user can access that contain posts $return->posts = array(); // The posts to display // First up a small sanity check. If there are no courses to check we can // return immediately, there is obviously nothing to search. if (empty($courses)) { return $return; } // A couple of quick setups $isloggedin = isloggedin(); $isguestuser = $isloggedin && isguestuser(); $iscurrentuser = $isloggedin && $USER->id == $user->id; // Checkout whether or not the current user has capabilities over the requested // user and if so they have the capabilities required to view the requested // users content. $usercontext = context_user::instance($user->id, MUST_EXIST); $hascapsonuser = !$iscurrentuser && $DB->record_exists('role_assignments', array('userid' => $USER->id, 'contextid' => $usercontext->id)); $hascapsonuser = $hascapsonuser && has_all_capabilities(array('moodle/user:viewdetails', 'moodle/user:readuserposts'), $usercontext); // Before we actually search each course we need to check the user's access to the // course. If the user doesn't have the appropraite access then we either throw an // error if a particular course was requested or we just skip over the course. foreach ($courses as $course) { $coursecontext = context_course::instance($course->id, MUST_EXIST); if ($iscurrentuser || $hascapsonuser) { // If it is the current user, or the current user has capabilities to the // requested user then all we need to do is check the requested users // current access to the course. // Note: There is no need to check group access or anything of the like // as either the current user is the requested user, or has granted // capabilities on the requested user. Either way they can see what the // requested user posted, although its VERY unlikely in the `parent` situation // that the current user will be able to view the posts in context. if (!is_viewing($coursecontext, $user) && !is_enrolled($coursecontext, $user)) { // Need to have full access to a course to see the rest of own info if ($musthaveaccess) { print_error('errorenrolmentrequired', 'forum'); } continue; } } else { // Check whether the current user is enrolled or has access to view the course // if they don't we immediately have a problem. if (!can_access_course($course)) { if ($musthaveaccess) { print_error('errorenrolmentrequired', 'forum'); } continue; } // Check whether the requested user is enrolled or has access to view the course // if they don't we immediately have a problem. if (!can_access_course($course, $user)) { if ($musthaveaccess) { print_error('notenrolled', 'forum'); } continue; } // If groups are in use and enforced throughout the course then make sure // we can meet in at least one course level group. // Note that we check if either the current user or the requested user have // the capability to access all groups. This is because with that capability // a user in group A could post in the group B forum. Grrrr. if (groups_get_course_groupmode($course) == SEPARATEGROUPS && $course->groupmodeforce && !has_capability('moodle/site:accessallgroups', $coursecontext) && !has_capability('moodle/site:accessallgroups', $coursecontext, $user->id)) { // If its the guest user to bad... the guest user cannot access groups if (!$isloggedin or $isguestuser) { // do not use require_login() here because we might have already used require_login($course) if ($musthaveaccess) { redirect(get_login_url()); } continue; } // Get the groups of the current user $mygroups = array_keys(groups_get_all_groups($course->id, $USER->id, $course->defaultgroupingid, 'g.id, g.name')); // Get the groups the requested user is a member of $usergroups = array_keys(groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid, 'g.id, g.name')); // Check whether they are members of the same group. If they are great. $intersect = array_intersect($mygroups, $usergroups); if (empty($intersect)) { // But they're not... if it was a specific course throw an error otherwise // just skip this course so that it is not searched. if ($musthaveaccess) { print_error("groupnotamember", '', $CFG->wwwroot."/course/view.php?id=$course->id"); } continue; } } } // Woo hoo we got this far which means the current user can search this // this course for the requested user. Although this is only the course accessibility // handling that is complete, the forum accessibility tests are yet to come. $return->courses[$course->id] = $course; } // No longer beed $courses array - lose it not it may be big unset($courses); // Make sure that we have some courses to search if (empty($return->courses)) { // If we don't have any courses to search then the reality is that the current // user doesn't have access to any courses is which the requested user has posted. // Although we do know at this point that the requested user has posts. if ($musthaveaccess) { print_error('permissiondenied'); } else { return $return; } } // Next step: Collect all of the forums that we will want to search. // It is important to note that this step isn't actually about searching, it is // about determining which forums we can search by testing accessibility. $forums = forum_get_forums_user_posted_in($user, array_keys($return->courses), $discussionsonly); // Will be used to build the where conditions for the search $forumsearchwhere = array(); // Will be used to store the where condition params for the search $forumsearchparams = array(); // Will record forums where the user can freely access everything $forumsearchfullaccess = array(); // DB caching friendly $now = round(time(), -2); // For each course to search we want to find the forums the user has posted in // and providing the current user can access the forum create a search condition // for the forum to get the requested users posts. foreach ($return->courses as $course) { // Now we need to get the forums $modinfo = get_fast_modinfo($course); if (empty($modinfo->instances['forum'])) { // hmmm, no forums? well at least its easy... skip! continue; } // Iterate foreach ($modinfo->get_instances_of('forum') as $forumid => $cm) { if (!$cm->uservisible or !isset($forums[$forumid])) { continue; } // Get the forum in question $forum = $forums[$forumid]; // This is needed for functionality later on in the forum code.... $forum->cm = $cm; // Check that either the current user can view the forum, or that the // current user has capabilities over the requested user and the requested // user can view the discussion if (!has_capability('mod/forum:viewdiscussion', $cm->context) && !($hascapsonuser && has_capability('mod/forum:viewdiscussion', $cm->context, $user->id))) { continue; } // This will contain forum specific where clauses $forumsearchselect = array(); if (!$iscurrentuser && !$hascapsonuser) { // Make sure we check group access if (groups_get_activity_groupmode($cm, $course) == SEPARATEGROUPS and !has_capability('moodle/site:accessallgroups', $cm->context)) { $groups = $modinfo->get_groups($cm->groupingid); $groups[] = -1; list($groupid_sql, $groupid_params) = $DB->get_in_or_equal($groups, SQL_PARAMS_NAMED, 'grps'.$forumid.'_'); $forumsearchparams = array_merge($forumsearchparams, $groupid_params); $forumsearchselect[] = "d.groupid $groupid_sql"; } // hidden timed discussions if (!empty($CFG->forum_enabletimedposts) && !has_capability('mod/forum:viewhiddentimedposts', $cm->context)) { $forumsearchselect[] = "(d.userid = :userid{$forumid} OR (d.timestart < :timestart{$forumid} AND (d.timeend = 0 OR d.timeend > :timeend{$forumid})))"; $forumsearchparams['userid'.$forumid] = $user->id; $forumsearchparams['timestart'.$forumid] = $now; $forumsearchparams['timeend'.$forumid] = $now; } // qanda access if ($forum->type == 'qanda' && !has_capability('mod/forum:viewqandawithoutposting', $cm->context)) { // We need to check whether the user has posted in the qanda forum. $discussionspostedin = forum_discussions_user_has_posted_in($forum->id, $user->id); if (!empty($discussionspostedin)) { $forumonlydiscussions = array(); // Holds discussion ids for the discussions the user is allowed to see in this forum. foreach ($discussionspostedin as $d) { $forumonlydiscussions[] = $d->id; } list($discussionid_sql, $discussionid_params) = $DB->get_in_or_equal($forumonlydiscussions, SQL_PARAMS_NAMED, 'qanda'.$forumid.'_'); $forumsearchparams = array_merge($forumsearchparams, $discussionid_params); $forumsearchselect[] = "(d.id $discussionid_sql OR p.parent = 0)"; } else { $forumsearchselect[] = "p.parent = 0"; } } if (count($forumsearchselect) > 0) { $forumsearchwhere[] = "(d.forum = :forum{$forumid} AND ".implode(" AND ", $forumsearchselect).")"; $forumsearchparams['forum'.$forumid] = $forumid; } else { $forumsearchfullaccess[] = $forumid; } } else { // The current user/parent can see all of their own posts $forumsearchfullaccess[] = $forumid; } } } // If we dont have any search conditions, and we don't have any forums where // the user has full access then we just return the default. if (empty($forumsearchwhere) && empty($forumsearchfullaccess)) { return $return; } // Prepare a where condition for the full access forums. if (count($forumsearchfullaccess) > 0) { list($fullidsql, $fullidparams) = $DB->get_in_or_equal($forumsearchfullaccess, SQL_PARAMS_NAMED, 'fula'); $forumsearchparams = array_merge($forumsearchparams, $fullidparams); $forumsearchwhere[] = "(d.forum $fullidsql)"; } // Prepare SQL to both count and search. // We alias user.id to useridx because we forum_posts already has a userid field and not aliasing this would break // oracle and mssql. $userfields = user_picture::fields('u', null, 'useridx'); $countsql = 'SELECT COUNT(*) '; $selectsql = 'SELECT p.*, d.forum, d.name AS discussionname, '.$userfields.' '; $wheresql = implode(" OR ", $forumsearchwhere); if ($discussionsonly) { if ($wheresql == '') { $wheresql = 'p.parent = 0'; } else { $wheresql = 'p.parent = 0 AND ('.$wheresql.')'; } } $sql = "FROM {forum_posts} p JOIN {forum_discussions} d ON d.id = p.discussion JOIN {user} u ON u.id = p.userid WHERE ($wheresql) AND p.userid = :userid "; $orderby = "ORDER BY p.modified DESC"; $forumsearchparams['userid'] = $user->id; // Set the total number posts made by the requested user that the current user can see $return->totalcount = $DB->count_records_sql($countsql.$sql, $forumsearchparams); // Set the collection of posts that has been requested $return->posts = $DB->get_records_sql($selectsql.$sql.$orderby, $forumsearchparams, $limitfrom, $limitnum); // We need to build an array of forums for which posts will be displayed. // We do this here to save the caller needing to retrieve them themselves before // printing these forums posts. Given we have the forums already there is // practically no overhead here. foreach ($return->posts as $post) { if (!array_key_exists($post->forum, $return->forums)) { $return->forums[$post->forum] = $forums[$post->forum]; } } return $return; }
/** * @param stdclass $user the owner of the stage */ public function __construct(stdclass $user) { global $DB; $stringstree = array(); // tree of strings to simulate ORDER BY component, stringid, lang, branch $this->strings = array(); // final list populated from the stringstree $stage = mlang_persistent_stage::instance_for_user($user->id, $user->sesskey); $needed = array(); // describes all strings that we will have to load to displaye the stage if (has_capability('local/amos:importfile', get_system_context(), $user)) { $this->importform = new local_amos_importfile_form(new moodle_url('/local/amos/importfile.php'), local_amos_importfile_options()); } if (has_capability('local/amos:commit', get_system_context(), $user)) { $this->mergeform = new local_amos_merge_form(new moodle_url('/local/amos/merge.php'), local_amos_merge_options()); } if (has_capability('local/amos:stage', get_system_context(), $user)) { $this->diffform = new local_amos_diff_form(new moodle_url('/local/amos/diff.php'), local_amos_diff_options()); } if (has_all_capabilities(array('local/amos:execute', 'local/amos:stage'), get_system_context(), $user)) { $this->executeform = new local_amos_execute_form(new moodle_url('/local/amos/execute.php'), local_amos_execute_options()); } foreach ($stage->get_iterator() as $component) { foreach ($component->get_iterator() as $staged) { if (!isset($needed[$component->version->code][$component->lang][$component->name])) { $needed[$component->version->code][$component->lang][$component->name] = array(); } $needed[$component->version->code][$component->lang][$component->name][] = $staged->id; $needed[$component->version->code]['en'][$component->name][] = $staged->id; $string = new stdclass(); $string->component = $component->name; $string->branch = $component->version->code; $string->version = $component->version->label; $string->language = $component->lang; $string->stringid = $staged->id; $string->text = $staged->text; $string->timemodified = $staged->timemodified; $string->deleted = $staged->deleted; $string->original = null; // is populated in the next step $string->current = null; // dtto $string->new = $staged->text; $string->committable = false; $stringstree[$string->component][$string->stringid][$string->language][$string->branch] = $string; } } // order by component ksort($stringstree); foreach ($stringstree as $subtree) { // order by stringid ksort($subtree); foreach ($subtree as $subsubtree) { // order by language ksort($subsubtree); foreach ($subsubtree as $subsubsubtree) { // order by branch ksort($subsubsubtree); foreach ($subsubsubtree as $string) { $this->strings[] = $string; } } } } unset($stringstree); $fver = array(); $flng = array(); $fcmp = array(); foreach ($needed as $branch => $languages) { $fver[$branch] = true; foreach ($languages as $language => $components) { $flng[$language] = true; foreach ($components as $component => $strings) { $fcmp[$component] = true; $needed[$branch][$language][$component] = mlang_component::from_snapshot($component, $language, mlang_version::by_code($branch), null, false, false, $strings); } } } $this->filterfields->fver = array_keys($fver); $this->filterfields->flng = array_keys($flng); $this->filterfields->fcmp = array_keys($fcmp); $allowedlangs = mlang_tools::list_allowed_languages($user->id); foreach ($this->strings as $string) { if (!empty($allowedlangs['X']) or !empty($allowedlangs[$string->language])) { $string->committable = true; } if (!$needed[$string->branch]['en'][$string->component]->has_string($string->stringid)) { $string->original = '*DELETED*'; } else { $string->original = $needed[$string->branch]['en'][$string->component]->get_string($string->stringid)->text; } if ($needed[$string->branch][$string->language][$string->component] instanceof mlang_component) { $string->current = $needed[$string->branch][$string->language][$string->component]->get_string($string->stringid); if ($string->current instanceof mlang_string) { $string->current = $string->current->text; } } if (empty(mlang_version::by_code($string->branch)->translatable)) { $string->committable = false; } } }