/** * Parse all callbacks and builds the tree. * * @param integer $user ID of the user for which the profile is displayed. * @param bool $iscurrentuser true if the profile being viewed is of current user, else false. * @param \stdClass $course Course object * * @return tree Fully build tree to be rendered on my profile page. */ public static function build_tree($user, $iscurrentuser, $course = null) { global $CFG; $tree = new tree(); // Add core nodes. require_once $CFG->libdir . "/myprofilelib.php"; core_myprofile_navigation($tree, $user, $iscurrentuser, $course); // Core components. $components = \core_component::get_core_subsystems(); foreach ($components as $component => $directory) { if (empty($directory)) { continue; } $file = $directory . "/lib.php"; if (is_readable($file)) { require_once $file; $function = "core_" . $component . "_myprofile_navigation"; if (function_exists($function)) { $function($tree, $user, $iscurrentuser, $course); } } } // Plugins. $types = \core_component::get_plugin_types(); foreach ($types as $type => $dir) { $pluginlist = get_plugin_list_with_function($type, "myprofile_navigation", "lib.php"); foreach ($pluginlist as $function) { $function($tree, $user, $iscurrentuser, $course); } } $tree->sort_categories(); return $tree; }
/** * Display overview for courses * * @param array $courses courses for which overview needs to be shown * @return array html overview */ function block_course_overview_get_overviews($courses) { $htmlarray = array(); if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { foreach ($modules as $fname) { $fname($courses, $htmlarray); } } return $htmlarray; }
/** * Gather a list of dndupload handlers from the different mods * * @param object $course The course this is being added to (to check course_allowed_module() ) */ public function __construct($course, $modnames = null) { global $CFG, $PAGE; // Add some default types to handle. // Note: 'Files' type is hard-coded into the Javascript as this needs to be ... // ... treated a little differently. $this->register_type('url', array('url', 'text/uri-list', 'text/x-moz-url'), get_string('addlinkhere', 'moodle'), get_string('nameforlink', 'moodle'), get_string('whatforlink', 'moodle'), 10); $this->register_type('text/html', array('text/html'), get_string('addpagehere', 'moodle'), get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 20); $this->register_type('text', array('text', 'text/plain'), get_string('addpagehere', 'moodle'), get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 30); // Loop through all modules to find handlers. $mods = get_plugin_list_with_function('mod', 'dndupload_register'); foreach ($mods as $component => $funcname) { list($modtype, $modname) = normalize_component($component); if ($modnames && !array_key_exists($modname, $modnames)) { continue; // Module is deactivated (hidden) at the site level. } if (!course_allowed_module($course, $modname)) { continue; // User does not have permission to add this module to the course. } $resp = $funcname(); if (!$resp) { continue; } if (isset($resp['files'])) { foreach ($resp['files'] as $file) { $this->register_file_handler($file['extension'], $modname, $file['message']); } } if (isset($resp['addtypes'])) { foreach ($resp['addtypes'] as $type) { if (isset($type['priority'])) { $priority = $type['priority']; } else { $priority = 100; } if (!isset($type['handlermessage'])) { $type['handlermessage'] = ''; } $this->register_type($type['identifier'], $type['datatransfertypes'], $type['addmessage'], $type['namemessage'], $type['handlermessage'], $priority); } } if (isset($resp['types'])) { foreach ($resp['types'] as $type) { $noname = !empty($type['noname']); $this->register_type_handler($type['identifier'], $modname, $type['message'], $noname); } } $PAGE->requires->string_for_js('pluginname', $modname); } }
/** * Display overview for courses * * @param array $courses courses for which overview needs to be shown * @return array html overview */ function block_course_overview_get_overviews($courses) { $htmlarray = array(); if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { // Split courses list into batches with no more than MAX_MODINFO_CACHE_SIZE courses in one batch. // Otherwise we exceed the cache limit in get_fast_modinfo() and rebuild it too often. if (defined('MAX_MODINFO_CACHE_SIZE') && MAX_MODINFO_CACHE_SIZE > 0 && count($courses) > MAX_MODINFO_CACHE_SIZE) { $batches = array_chunk($courses, MAX_MODINFO_CACHE_SIZE, true); } else { $batches = array($courses); } foreach ($batches as $courses) { foreach ($modules as $fname) { $fname($courses, $htmlarray); } } } return $htmlarray; }
/** * This function gives local plugins an opportunity to modify the settings navigation. */ protected function load_local_plugin_settings() { foreach (get_plugin_list_with_function('local', 'extend_settings_navigation') as $function) { $function($this, $this->context); } }
/** * This function loads all of the front page settings into the settings navigation. * This function is called when the user is on the front page, or $COURSE==$SITE * @param bool $forceopen (optional) * @return navigation_node */ protected function load_front_page_settings($forceopen = false) { global $SITE, $CFG; $course = clone $SITE; $coursecontext = context_course::instance($course->id); // Course context $frontpage = $this->add(get_string('frontpagesettings'), null, self::TYPE_SETTING, null, 'frontpage'); if ($forceopen) { $frontpage->force_open(); } $frontpage->id = 'frontpagesettings'; if ($this->page->user_allowed_editing()) { // Add the turn on/off settings $url = new moodle_url('/course/view.php', array('id' => $course->id, 'sesskey' => sesskey())); if ($this->page->user_is_editing()) { $url->param('edit', 'off'); $editstring = get_string('turneditingoff'); } else { $url->param('edit', 'on'); $editstring = get_string('turneditingon'); } $frontpage->add($editstring, $url, self::TYPE_SETTING, null, null, new pix_icon('i/edit', '')); } if (has_capability('moodle/course:update', $coursecontext)) { // Add the course settings link $url = new moodle_url('/admin/settings.php', array('section' => 'frontpagesettings')); $frontpage->add(get_string('editsettings'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/settings', '')); } // add enrol nodes enrol_add_course_navigation($frontpage, $course); // Manage filters if (has_capability('moodle/filter:manage', $coursecontext) && count(filter_get_available_in_context($coursecontext)) > 0) { $url = new moodle_url('/filter/manage.php', array('contextid' => $coursecontext->id)); $frontpage->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/filter', '')); } // View course reports. if (has_capability('moodle/site:viewreports', $coursecontext)) { // Basic capability for listing of reports. $frontpagenav = $frontpage->add(get_string('reports'), null, self::TYPE_CONTAINER, null, 'frontpagereports', new pix_icon('i/stats', '')); $coursereports = core_component::get_plugin_list('coursereport'); foreach ($coursereports as $report => $dir) { $libfile = $CFG->dirroot . '/course/report/' . $report . '/lib.php'; if (file_exists($libfile)) { require_once $libfile; $reportfunction = $report . '_report_extend_navigation'; if (function_exists($report . '_report_extend_navigation')) { $reportfunction($frontpagenav, $course, $coursecontext); } } } $reports = get_plugin_list_with_function('report', 'extend_navigation_course', 'lib.php'); foreach ($reports as $reportfunction) { $reportfunction($frontpagenav, $course, $coursecontext); } } // Backup this course if (has_capability('moodle/backup:backupcourse', $coursecontext)) { $url = new moodle_url('/backup/backup.php', array('id' => $course->id)); $frontpage->add(get_string('backup'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/backup', '')); } // Restore to this course if (has_capability('moodle/restore:restorecourse', $coursecontext)) { $url = new moodle_url('/backup/restorefile.php', array('contextid' => $coursecontext->id)); $frontpage->add(get_string('restore'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/restore', '')); } // Questions require_once $CFG->libdir . '/questionlib.php'; question_extend_settings_navigation($frontpage, $coursecontext)->trim_if_empty(); // Manage files if ($course->legacyfiles == 2 and has_capability('moodle/course:managefiles', $this->context)) { //hiden in new installs $url = new moodle_url('/files/index.php', array('contextid' => $coursecontext->id)); $frontpage->add(get_string('sitelegacyfiles'), $url, self::TYPE_SETTING, null, null, new pix_icon('i/folder', '')); } // Let plugins hook into frontpage navigation. $pluginsfunction = get_plugins_with_function('extend_navigation_frontpage', 'lib.php'); foreach ($pluginsfunction as $plugintype => $plugins) { foreach ($plugins as $pluginfunction) { $pluginfunction($frontpage, $course, $coursecontext); } } return $frontpage; }
/** * Clear a course out completely, deleting all content but don't delete the course itself. * * This function does not verify any permissions. * * Please note this function also deletes all user enrolments, * enrolment instances and role assignments by default. * * $options: * - 'keep_roles_and_enrolments' - false by default * - 'keep_groups_and_groupings' - false by default * * @param int $courseid The id of the course that is being deleted * @param bool $showfeedback Whether to display notifications of each action the function performs. * @param array $options extra options * @return bool true if all the removals succeeded. false if there were any failures. If this * method returns false, some of the removals will probably have succeeded, and others * failed, but you have no way of knowing which. */ function remove_course_contents($courseid, $showfeedback = true, array $options = null) { global $CFG, $DB, $OUTPUT; require_once $CFG->libdir . '/badgeslib.php'; require_once $CFG->libdir . '/completionlib.php'; require_once $CFG->libdir . '/questionlib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/group/lib.php'; require_once $CFG->dirroot . '/tag/coursetagslib.php'; require_once $CFG->dirroot . '/comment/lib.php'; require_once $CFG->dirroot . '/rating/lib.php'; require_once $CFG->dirroot . '/notes/lib.php'; // Handle course badges. badges_handle_course_deletion($courseid); // NOTE: these concatenated strings are suboptimal, but it is just extra info... $strdeleted = get_string('deleted') . ' - '; // Some crazy wishlist of stuff we should skip during purging of course content. $options = (array) $options; $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); $coursecontext = context_course::instance($courseid); $fs = get_file_storage(); // Delete course completion information, this has to be done before grades and enrols. $cc = new completion_info($course); $cc->clear_criteria(); if ($showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('completion', 'completion'), 'notifysuccess'); } // Remove all data from gradebook - this needs to be done before course modules // because while deleting this information, the system may need to reference // the course modules that own the grades. remove_course_grades($courseid, $showfeedback); remove_grade_letters($coursecontext, $showfeedback); // Delete course blocks in any all child contexts, // they may depend on modules so delete them first. $childcontexts = $coursecontext->get_child_contexts(); // Returns all subcontexts since 2.2. foreach ($childcontexts as $childcontext) { blocks_delete_all_for_context($childcontext->id); } unset($childcontexts); blocks_delete_all_for_context($coursecontext->id); if ($showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('type_block_plural', 'plugin'), 'notifysuccess'); } // Delete every instance of every module, // this has to be done before deleting of course level stuff. $locations = core_component::get_plugin_list('mod'); foreach ($locations as $modname => $moddir) { if ($modname === 'NEWMODULE') { continue; } if ($module = $DB->get_record('modules', array('name' => $modname))) { include_once "{$moddir}/lib.php"; // Shows php warning only if plugin defective. $moddelete = $modname . '_delete_instance'; // Delete everything connected to an instance. $moddeletecourse = $modname . '_delete_course'; // Delete other stray stuff (uncommon). if ($instances = $DB->get_records($modname, array('course' => $course->id))) { foreach ($instances as $instance) { if ($cm = get_coursemodule_from_instance($modname, $instance->id, $course->id)) { // Delete activity context questions and question categories. question_delete_activity($cm, $showfeedback); } if (function_exists($moddelete)) { // This purges all module data in related tables, extra user prefs, settings, etc. $moddelete($instance->id); } else { // NOTE: we should not allow installation of modules with missing delete support! debugging("Defective module '{$modname}' detected when deleting course contents: missing function {$moddelete}()!"); $DB->delete_records($modname, array('id' => $instance->id)); } if ($cm) { // Delete cm and its context - orphaned contexts are purged in cron in case of any race condition. context_helper::delete_instance(CONTEXT_MODULE, $cm->id); $DB->delete_records('course_modules', array('id' => $cm->id)); } } } if (function_exists($moddeletecourse)) { // Execute ptional course cleanup callback. $moddeletecourse($course, $showfeedback); } if ($instances and $showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('pluginname', $modname), 'notifysuccess'); } } else { // Ooops, this module is not properly installed, force-delete it in the next block. } } // We have tried to delete everything the nice way - now let's force-delete any remaining module data. // Remove all data from availability and completion tables that is associated // with course-modules belonging to this course. Note this is done even if the // features are not enabled now, in case they were enabled previously. $DB->delete_records_select('course_modules_completion', 'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)', array($courseid)); // Remove course-module data. $cms = $DB->get_records('course_modules', array('course' => $course->id)); foreach ($cms as $cm) { if ($module = $DB->get_record('modules', array('id' => $cm->module))) { try { $DB->delete_records($module->name, array('id' => $cm->instance)); } catch (Exception $e) { // Ignore weird or missing table problems. } } context_helper::delete_instance(CONTEXT_MODULE, $cm->id); $DB->delete_records('course_modules', array('id' => $cm->id)); } if ($showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('type_mod_plural', 'plugin'), 'notifysuccess'); } // Cleanup the rest of plugins. $cleanuplugintypes = array('report', 'coursereport', 'format'); foreach ($cleanuplugintypes as $type) { $plugins = get_plugin_list_with_function($type, 'delete_course', 'lib.php'); foreach ($plugins as $plugin => $pluginfunction) { $pluginfunction($course->id, $showfeedback); } if ($showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('type_' . $type . '_plural', 'plugin'), 'notifysuccess'); } } // Delete questions and question categories. question_delete_course($course, $showfeedback); if ($showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('questions', 'question'), 'notifysuccess'); } // Make sure there are no subcontexts left - all valid blocks and modules should be already gone. $childcontexts = $coursecontext->get_child_contexts(); // Returns all subcontexts since 2.2. foreach ($childcontexts as $childcontext) { $childcontext->delete(); } unset($childcontexts); // Remove all roles and enrolments by default. if (empty($options['keep_roles_and_enrolments'])) { // This hack is used in restore when deleting contents of existing course. role_unassign_all(array('contextid' => $coursecontext->id, 'component' => ''), true); enrol_course_delete($course); if ($showfeedback) { echo $OUTPUT->notification($strdeleted . get_string('type_enrol_plural', 'plugin'), 'notifysuccess'); } } // Delete any groups, removing members and grouping/course links first. if (empty($options['keep_groups_and_groupings'])) { groups_delete_groupings($course->id, $showfeedback); groups_delete_groups($course->id, $showfeedback); } // Filters be gone! filter_delete_all_for_context($coursecontext->id); // Notes, you shall not pass! note_delete_all($course->id); // Die comments! comment::delete_comments($coursecontext->id); // Ratings are history too. $delopt = new stdclass(); $delopt->contextid = $coursecontext->id; $rm = new rating_manager(); $rm->delete_ratings($delopt); // Delete course tags. coursetag_delete_course_tags($course->id, $showfeedback); // Delete calendar events. $DB->delete_records('event', array('courseid' => $course->id)); $fs->delete_area_files($coursecontext->id, 'calendar'); // Delete all related records in other core tables that may have a courseid // This array stores the tables that need to be cleared, as // table_name => column_name that contains the course id. $tablestoclear = array('backup_courses' => 'courseid', 'user_lastaccess' => 'courseid'); foreach ($tablestoclear as $table => $col) { $DB->delete_records($table, array($col => $course->id)); } // Delete all course backup files. $fs->delete_area_files($coursecontext->id, 'backup'); // Cleanup course record - remove links to deleted stuff. $oldcourse = new stdClass(); $oldcourse->id = $course->id; $oldcourse->summary = ''; $oldcourse->cacherev = 0; $oldcourse->legacyfiles = 0; $oldcourse->enablecompletion = 0; if (!empty($options['keep_groups_and_groupings'])) { $oldcourse->defaultgroupingid = 0; } $DB->update_record('course', $oldcourse); // Delete course sections. $DB->delete_records('course_sections', array('course' => $course->id)); // Delete legacy, section and any other course files. $fs->delete_area_files($coursecontext->id, 'course'); // Files from summary and section. // Delete all remaining stuff linked to context such as files, comments, ratings, etc. if (empty($options['keep_roles_and_enrolments']) and empty($options['keep_groups_and_groupings'])) { // Easy, do not delete the context itself... $coursecontext->delete_content(); } else { // Hack alert!!!! // We can not drop all context stuff because it would bork enrolments and roles, // there might be also files used by enrol plugins... } // Delete legacy files - just in case some files are still left there after conversion to new file api, // also some non-standard unsupported plugins may try to store something there. fulldelete($CFG->dataroot . '/' . $course->id); // Delete from cache to reduce the cache size especially makes sense in case of bulk course deletion. $cachemodinfo = cache::make('core', 'coursemodinfo'); $cachemodinfo->delete($courseid); // Trigger a course content deleted event. $event = \core\event\course_content_deleted::create(array('objectid' => $course->id, 'context' => $coursecontext, 'other' => array('shortname' => $course->shortname, 'fullname' => $course->fullname, 'options' => $options))); $event->add_record_snapshot('course', $course); $event->trigger(); return true; }
/** * Return activities overview for the given courses. * * @param array $courseids a list of course ids * @return array of warnings and the activities overview * @since Moodle 3.2 * @throws moodle_exception */ public static function get_activities_overview($courseids) { global $USER; // Parameter validation. $params = self::validate_parameters(self::get_activities_overview_parameters(), array('courseids' => $courseids)); $courseoverviews = array(); list($courses, $warnings) = external_util::validate_courses($params['courseids']); if (!empty($courses)) { // Add lastaccess to each course (required by print_overview function). // We need the complete user data, the ws server does not load a complete one. $user = get_complete_user_data('id', $USER->id); foreach ($courses as $course) { if (isset($user->lastcourseaccess[$course->id])) { $course->lastaccess = $user->lastcourseaccess[$course->id]; } else { $course->lastaccess = 0; } } $overviews = array(); if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { foreach ($modules as $fname) { $fname($courses, $overviews); } } // Format output. foreach ($overviews as $courseid => $modules) { $courseoverviews[$courseid]['id'] = $courseid; $courseoverviews[$courseid]['overviews'] = array(); foreach ($modules as $modname => $overviewtext) { $courseoverviews[$courseid]['overviews'][] = array('module' => $modname, 'overviewtext' => $overviewtext); } } } $result = array('courses' => $courseoverviews, 'warnings' => $warnings); return $result; }
/** * Get a list of reports that support the given store instance. * * @param string $logstore Name of the store. * * @return array List of supported reports */ public function get_supported_reports($logstore) { $allstores = self::get_store_plugins(); if (empty($allstores[$logstore])) { // Store doesn't exist. return array(); } $reports = get_plugin_list_with_function('report', 'supports_logstore', 'lib.php'); $enabled = $this->stores; if (empty($enabled[$logstore])) { // Store is not enabled, init an instance. $classname = '\\' . $logstore . '\\log\\store'; $instance = new $classname($this); } else { $instance = $enabled[$logstore]; } $return = array(); foreach ($reports as $report => $fulldir) { if (component_callback($report, 'supports_logstore', array($instance), false)) { $return[$report] = get_string('pluginname', $report); } } return $return; }
/** * 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; }
/** * an adaptation of the standard print_course_overview() * @param array $courses a course array to print * @param boolean $return if true returns the string * @return the rendered view if return is true */ function local_print_course_overview($courses, $options = array()) { global $PAGE, $OUTPUT; $renderer = $PAGE->get_renderer('local_my'); // Be sure we have something in lastaccess. foreach ($courses as $cid => $c) { $courses[$cid]->lastaccess = 0 + @$courses[$cid]->lastaccess; } $overviews = array(); if ($modules = get_plugin_list_with_function('mod', 'print_overview')) { foreach ($modules as $fname) { $fname($courses, $overviews); } } $str = ''; $str .= '<div class="courselist">'; foreach ($courses as $cid => $c) { $str .= '<div>'; if (empty($options['nocompletion'])) { $str .= $renderer->course_completion_gauge($c, 'div', $options['gaugewidth'], $options['gaugeheight']); } $str .= $renderer->course_simple_div($c); $str .= '</div>'; } $str .= '</div>'; return $str; }
/** * Initialize search conditions from plugins * local_*_get_question_bank_search_conditions() must return an array of * \core_question\bank\search\condition objects. */ protected function init_search_conditions() { $searchplugins = get_plugin_list_with_function('local', 'get_question_bank_search_conditions'); foreach ($searchplugins as $component => $function) { foreach ($function($this) as $searchobject) { $this->add_searchcondition($searchobject); } } }
// 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/>. /** * On install, builds the search data for all existing content. * * @package local_ousearch * @copyright 2014 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ require __DIR__ . '/../../config.php'; // Check administrator or similar. require_login(); require_capability('moodle/site:config', context_system::instance()); $url = new moodle_url('/local/ousearch/postinstall.php'); $PAGE->set_url($url); $PAGE->set_context(context_system::instance()); echo $OUTPUT->header(); if ($_SERVER['REQUEST_METHOD'] === 'POST' && confirm_sesskey()) { require_once __DIR__ . '/searchlib.php'; $plugins = get_plugin_list_with_function('mod', 'ousearch_update_all'); foreach ($plugins as $plugin => $fn) { $fn(true); } } else { echo $OUTPUT->box(get_string('postinstall', 'local_ousearch')); echo $OUTPUT->single_button($url, get_string('continue')); } echo $OUTPUT->footer();
/** * Extend the LTI services through the ltisource plugins * * @param stdClass $data LTI request data * @return bool * @throws coding_exception */ function lti_extend_lti_services($data) { $plugins = get_plugin_list_with_function('ltisource', $data->messagetype); if (!empty($plugins)) { // There can only be one. if (count($plugins) > 1) { throw new coding_exception('More than one ltisource plugin handler found'); } $data->xml = new SimpleXMLElement($data->body); $callback = current($plugins); call_user_func($callback, $data); return true; } return false; }
/** * Call a hook present in a subplugin * * @param string $hookname The hookname (function without franken style prefix) * @param object $data Object containing data to be used by the hook function * @return bool Allways false */ function local_ltiprovider_call_hook($hookname, $data) { $plugins = get_plugin_list_with_function('ltiproviderextension', $hookname); if (!empty($plugins)) { foreach ($plugins as $plugin) { call_user_func($plugin, $data); } } return false; }
/** * This function calls the module function to inject module settings into the * settings navigation tree. * * This only gets called if there is a corrosponding function in the modules * lib file. * * For examples mod/forum/lib.php {@link forum_extend_settings_navigation()} * * @return navigation_node|false */ protected function load_module_settings() { global $CFG; if (!$this->page->cm && $this->context->contextlevel == CONTEXT_MODULE && $this->context->instanceid) { $cm = get_coursemodule_from_id(false, $this->context->instanceid, 0, false, MUST_EXIST); $this->page->set_cm($cm, $this->page->course); } $file = $CFG->dirroot . '/mod/' . $this->page->activityname . '/lib.php'; if (file_exists($file)) { require_once $file; } $modulenode = $this->add(get_string('pluginadministration', $this->page->activityname)); $modulenode->force_open(); // Settings for the module if (has_capability('moodle/course:manageactivities', $this->page->cm->context)) { $url = new moodle_url('/course/modedit.php', array('update' => $this->page->cm->id, 'return' => true, 'sesskey' => sesskey())); $modulenode->add(get_string('editsettings'), $url, navigation_node::TYPE_SETTING, null, 'modedit'); } // Assign local roles if (count(get_assignable_roles($this->page->cm->context)) > 0) { $url = new moodle_url('/' . $CFG->admin . '/roles/assign.php', array('contextid' => $this->page->cm->context->id)); $modulenode->add(get_string('localroles', 'role'), $url, self::TYPE_SETTING, null, 'roleassign'); } // Override roles if (has_capability('moodle/role:review', $this->page->cm->context) or count(get_overridable_roles($this->page->cm->context)) > 0) { $url = new moodle_url('/' . $CFG->admin . '/roles/permissions.php', array('contextid' => $this->page->cm->context->id)); $modulenode->add(get_string('permissions', 'role'), $url, self::TYPE_SETTING, null, 'roleoverride'); } // Check role permissions if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override', 'moodle/role:assign'), $this->page->cm->context)) { $url = new moodle_url('/' . $CFG->admin . '/roles/check.php', array('contextid' => $this->page->cm->context->id)); $modulenode->add(get_string('checkpermissions', 'role'), $url, self::TYPE_SETTING, null, 'rolecheck'); } // Manage filters if (has_capability('moodle/filter:manage', $this->page->cm->context) && count(filter_get_available_in_context($this->page->cm->context)) > 0) { $url = new moodle_url('/filter/manage.php', array('contextid' => $this->page->cm->context->id)); $modulenode->add(get_string('filters', 'admin'), $url, self::TYPE_SETTING, null, 'filtermanage'); } // Add reports $reports = get_plugin_list_with_function('report', 'extend_navigation_module', 'lib.php'); foreach ($reports as $reportfunction) { $reportfunction($modulenode, $this->page->cm); } // Add a backup link $featuresfunc = $this->page->activityname . '_supports'; if (function_exists($featuresfunc) && $featuresfunc(FEATURE_BACKUP_MOODLE2) && has_capability('moodle/backup:backupactivity', $this->page->cm->context)) { $url = new moodle_url('/backup/backup.php', array('id' => $this->page->cm->course, 'cm' => $this->page->cm->id)); $modulenode->add(get_string('backup'), $url, self::TYPE_SETTING, null, 'backup'); } // Restore this activity $featuresfunc = $this->page->activityname . '_supports'; if (function_exists($featuresfunc) && $featuresfunc(FEATURE_BACKUP_MOODLE2) && has_capability('moodle/restore:restoreactivity', $this->page->cm->context)) { $url = new moodle_url('/backup/restorefile.php', array('contextid' => $this->page->cm->context->id)); $modulenode->add(get_string('restore'), $url, self::TYPE_SETTING, null, 'restore'); } // Allow the active advanced grading method plugin to append its settings $featuresfunc = $this->page->activityname . '_supports'; if (function_exists($featuresfunc) && $featuresfunc(FEATURE_ADVANCED_GRADING) && has_capability('moodle/grade:managegradingforms', $this->page->cm->context)) { require_once $CFG->dirroot . '/grade/grading/lib.php'; $gradingman = get_grading_manager($this->page->cm->context, $this->page->activityname); $gradingman->extend_settings_navigation($this, $modulenode); } $function = $this->page->activityname . '_extend_settings_navigation'; if (!function_exists($function)) { return $modulenode; } $function($this, $modulenode); // Remove the module node if there are no children if (empty($modulenode->children)) { $modulenode->remove(); } return $modulenode; }
/** * Executes cron functions for a specific type of plugin. * * @param string $plugintype Plugin type (e.g. 'report') * @param string $description If specified, will display 'Starting (whatever)' * and 'Finished (whatever)' lines, otherwise does not display */ function cron_execute_plugin_type($plugintype, $description = null) { global $DB; // Get list from plugin => function for all plugins $plugins = get_plugin_list_with_function($plugintype, 'cron'); // Modify list for backward compatibility (different files/names) $plugins = cron_bc_hack_plugin_functions($plugintype, $plugins); // Return if no plugins with cron function to process if (!$plugins) { return; } if ($description) { mtrace('Starting ' . $description); } foreach ($plugins as $component => $cronfunction) { $dir = core_component::get_component_directory($component); // Get cron period if specified in version.php, otherwise assume every cron $cronperiod = 0; if (file_exists("{$dir}/version.php")) { $plugin = new stdClass(); include "{$dir}/version.php"; if (isset($plugin->cron)) { $cronperiod = $plugin->cron; } } // Using last cron and cron period, don't run if it already ran recently $lastcron = get_config($component, 'lastcron'); if ($cronperiod && $lastcron) { if ($lastcron + $cronperiod > time()) { // do not execute cron yet continue; } } mtrace('Processing cron function for ' . $component . '...'); cron_trace_time_and_memory(); $pre_dbqueries = $DB->perf_get_queries(); $pre_time = microtime(true); $cronfunction(); mtrace("done. (" . ($DB->perf_get_queries() - $pre_dbqueries) . " dbqueries, " . round(microtime(true) - $pre_time, 2) . " seconds)"); set_config('lastcron', time(), $component); @set_time_limit(0); } if ($description) { mtrace('Finished ' . $description); } }
/** * Extend the LTI services through the ltisource plugins * * @param stdClass $data LTI request data * @return bool * @throws coding_exception */ function lti_extend_lti_services($data) { $plugins = get_plugin_list_with_function('ltisource', $data->messagetype); if (!empty($plugins)) { try { // There can only be one if (count($plugins) > 1) { throw new coding_exception('More than one ltisource plugin handler found'); } $callback = current($plugins); call_user_func($callback, $data); } catch (moodle_exception $e) { $error = $e->getMessage(); if (debugging('', DEBUG_DEVELOPER)) { $error .= ' ' . format_backtrace(get_exception_info($e)->backtrace); } $responsexml = lti_get_response_xml('failure', $error, $data->messageid, $data->messagetype); header('HTTP/1.0 400 bad request'); echo $responsexml->asXML(); } return true; } return false; }
/** * This function gives local plugins an opportunity to modify the settings navigation. */ protected function load_local_plugin_settings() { // Get all local plugins with an extend_settings_navigation function in their lib.php file foreach (get_plugin_list_with_function('local', 'extends_settings_navigation') as $function) { // Call each function providing this (the settings navigation) and the current context. $function($this, $this->context); } }
/** * Check for course updates in the given context level instances (only modules supported right Now) * * @param stdClass $course course object * @param array $tocheck instances to check for updates * @param array $filter check only for updates in these areas * @return array list of warnings and instances with updates information * @since Moodle 3.2 */ function course_check_updates($course, $tocheck, $filter = array()) { global $CFG, $DB; $instances = array(); $warnings = array(); $modulescallbacksupport = array(); $modinfo = get_fast_modinfo($course); $supportedplugins = get_plugin_list_with_function('mod', 'check_updates_since'); // Check instances. foreach ($tocheck as $instance) { if ($instance['contextlevel'] == 'module') { // Check module visibility. try { $cm = $modinfo->get_cm($instance['id']); } catch (Exception $e) { $warnings[] = array('item' => 'module', 'itemid' => $instance['id'], 'warningcode' => 'cmidnotincourse', 'message' => 'This module id does not belong to this course.'); continue; } if (!$cm->uservisible) { $warnings[] = array('item' => 'module', 'itemid' => $instance['id'], 'warningcode' => 'nonuservisible', 'message' => 'You don\'t have access to this module.'); continue; } if (empty($supportedplugins['mod_' . $cm->modname])) { $warnings[] = array('item' => 'module', 'itemid' => $instance['id'], 'warningcode' => 'missingcallback', 'message' => 'This module does not implement the check_updates_since callback: ' . $instance['contextlevel']); continue; } // Retrieve the module instance. $instances[] = array('contextlevel' => $instance['contextlevel'], 'id' => $instance['id'], 'updates' => call_user_func($cm->modname . '_check_updates_since', $cm, $instance['since'], $filter)); } else { $warnings[] = array('item' => 'contextlevel', 'itemid' => $instance['id'], 'warningcode' => 'contextlevelnotsupported', 'message' => 'Context level not yet supported ' . $instance['contextlevel']); } } return array($instances, $warnings); }