/** * Test the tag_set function. * This function was deprecated in 3.1 */ public function test_tag_set_get() { global $DB; // Create a course to tag. $course = $this->getDataGenerator()->create_course(); // Create the tag and tag instance. tag_set('course', $course->id, array('A random tag'), 'core', context_course::instance($course->id)->id); $this->assertDebuggingCalled(); // Get the tag instance that should have been created. $taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST); $this->assertEquals('core', $taginstance->component); $this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid); $tagbyname = tag_get('name', 'A random tag'); $this->assertDebuggingCalled(); $this->assertEquals('A random tag', $tagbyname->rawname); $this->assertEmpty(tag_get('name', 'Non existing tag')); $this->assertDebuggingCalled(); $tagbyid = tag_get('id', $tagbyname->id); $this->assertDebuggingCalled(); $this->assertEquals('A random tag', $tagbyid->rawname); $tagid = $tagbyname->id; $this->assertEmpty(tag_get('id', $tagid + 1)); $this->assertDebuggingCalled(); tag_set('tag', $tagid, array('Some related tag')); $this->assertDebuggingCalled(); $relatedtags = tag_get_related_tags($tagid); $this->assertDebuggingCalled(); $this->assertCount(1, $relatedtags); $this->assertEquals('Some related tag', $relatedtags[0]->rawname); $tagids = tag_get_id(array('A random tag', 'Some related tag')); $this->assertDebuggingCalled(); $this->assertCount(2, $tagids); $this->assertEquals($tagid, $tagids['a random tag']); $this->assertEquals($relatedtags[0]->id, $tagids['some related tag']); }
/** * Save the wikitags list * * @param Object $WS WikiStorage * @param String $taglist Comma-separated tags */ function wiki_tags_save_tags($WS, $taglist) { global $COURSE; add_to_log($COURSE->id, 'wiki', 'save tags', addslashes("view.php?id={$WS->cm->id}&page={$WS->page}"), $WS->dfwiki->id, $WS->cm->id); $page = wiki_page_last_version($WS->page, $WS); // delete the tags of the current wiki page version /* *$tagids = tag_get_tags_ids('wiki', $taglist); *foreach ($tagids as $tagid) * tag_delete_instance('wiki', $page->created, $tagid); */ // add the tags to the next wiki page tag_set('wiki', $page->created, explode(',', $taglist)); }
/** * Test the tag_set function. */ public function test_tag_set() { global $DB; // Create a course to tag. $course = $this->getDataGenerator()->create_course(); // Create the tag and tag instance. tag_set('course', $course->id, array('A random tag'), 'core', context_course::instance($course->id)->id); // Get the tag instance that should have been created. $taginstance = $DB->get_record('tag_instance', array('itemtype' => 'course', 'itemid' => $course->id), '*', MUST_EXIST); $this->assertEquals('core', $taginstance->component); $this->assertEquals(context_course::instance($course->id)->id, $taginstance->contextid); // Now call the tag_set function without specifying the component or contextid and // ensure the function debugging is called. tag_set('course', $course->id, array('Another tag')); $this->assertDebuggingCalled(); }
function forumng_update_instance($forumng) { global $DB, $CFG; require_once dirname(__FILE__) . '/mod_forumng.php'; // Get the tag lib.php. require_once $CFG->dirroot . '/tag/lib.php'; $forumng->id = $forumng->instance; $previous = $DB->get_record('forumng', array('id' => $forumng->id), '*', MUST_EXIST); $DB->update_record('forumng', $forumng); $forum = mod_forumng::get_from_id($forumng->id, mod_forumng::CLONE_DIRECT); $forum->updated($previous); if (isset($forumng->settags)) { $context = $forum->get_context(true); tag_set('forumng', $forumng->id, $forumng->settags, 'mod_forumng', $context->id); } return true; }
/** * Given a record in the {blog_external} table, checks the blog's URL * for new entries not yet copied into Moodle. * Also attempts to identify and remove deleted blog entries * * @param object $externalblog * @return boolean False if the Feed is invalid */ function blog_sync_external_entries($externalblog) { global $CFG, $DB; require_once $CFG->libdir . '/simplepie/moodle_simplepie.php'; $rssfile = new moodle_simplepie_file($externalblog->url); $filetest = new SimplePie_Locator($rssfile); if (!$filetest->is_feed($rssfile)) { $externalblog->failedlastsync = 1; $DB->update_record('blog_external', $externalblog); return false; } else { if (!empty($externalblog->failedlastsync)) { $externalblog->failedlastsync = 0; $DB->update_record('blog_external', $externalblog); } } $rss = new moodle_simplepie($externalblog->url); if (empty($rss->data)) { return null; } //used to identify blog posts that have been deleted from the source feed $oldesttimestamp = null; $uniquehashes = array(); foreach ($rss->get_items() as $entry) { // If filtertags are defined, use them to filter the entries by RSS category if (!empty($externalblog->filtertags)) { $containsfiltertag = false; $categories = $entry->get_categories(); $filtertags = explode(',', $externalblog->filtertags); $filtertags = array_map('trim', $filtertags); $filtertags = array_map('strtolower', $filtertags); foreach ($categories as $category) { if (in_array(trim(strtolower($category->term)), $filtertags)) { $containsfiltertag = true; } } if (!$containsfiltertag) { continue; } } $uniquehashes[] = $entry->get_permalink(); $newentry = new stdClass(); $newentry->userid = $externalblog->userid; $newentry->module = 'blog_external'; $newentry->content = $externalblog->id; $newentry->uniquehash = $entry->get_permalink(); $newentry->publishstate = 'site'; $newentry->format = FORMAT_HTML; // Clean subject of html, just in case $newentry->subject = clean_param($entry->get_title(), PARAM_TEXT); // Observe 128 max chars in DB // TODO: +1 to raise this to 255 if (textlib::strlen($newentry->subject) > 128) { $newentry->subject = textlib::substr($newentry->subject, 0, 125) . '...'; } $newentry->summary = $entry->get_description(); //used to decide whether to insert or update //uses enty permalink plus creation date if available $existingpostconditions = array('uniquehash' => $entry->get_permalink()); //our DB doesnt allow null creation or modified timestamps so check the external blog supplied one $entrydate = $entry->get_date('U'); if (!empty($entrydate)) { $existingpostconditions['created'] = $entrydate; } //the post ID or false if post not found in DB $postid = $DB->get_field('post', 'id', $existingpostconditions); $timestamp = null; if (empty($entrydate)) { $timestamp = time(); } else { $timestamp = $entrydate; } //only set created if its a new post so we retain the original creation timestamp if the post is edited if ($postid === false) { $newentry->created = $timestamp; } $newentry->lastmodified = $timestamp; if (empty($oldesttimestamp) || $timestamp < $oldesttimestamp) { //found an older post $oldesttimestamp = $timestamp; } if (textlib::strlen($newentry->uniquehash) > 255) { // The URL for this item is too long for the field. Rather than add // the entry without the link we will skip straight over it. // RSS spec says recommended length 500, we use 255. debugging('External blog entry skipped because of oversized URL', DEBUG_DEVELOPER); continue; } if ($postid === false) { $id = $DB->insert_record('post', $newentry); // Set tags if ($tags = tag_get_tags_array('blog_external', $externalblog->id)) { tag_set('post', $id, $tags); } } else { $newentry->id = $postid; $DB->update_record('post', $newentry); } } // Look at the posts we have in the database to check if any of them have been deleted from the feed. // Only checking posts within the time frame returned by the rss feed. Older items may have been deleted or // may just not be returned anymore. We can't tell the difference so we leave older posts alone. $sql = "SELECT id, uniquehash\n FROM {post}\n WHERE module = 'blog_external'\n AND " . $DB->sql_compare_text('content') . " = " . $DB->sql_compare_text(':blogid') . "\n AND created > :ts"; $dbposts = $DB->get_records_sql($sql, array('blogid' => $externalblog->id, 'ts' => $oldesttimestamp)); $todelete = array(); foreach ($dbposts as $dbpost) { if (!in_array($dbpost->uniquehash, $uniquehashes)) { $todelete[] = $dbpost->id; } } $DB->delete_records_list('post', 'id', $todelete); $DB->update_record('blog_external', array('id' => $externalblog->id, 'timefetched' => time())); }
function restore_create_blogs($restore, $xml_file) { global $CFG; $status = true; //Check it exists if (!file_exists($xml_file)) { $status = false; } //Get info from xml if ($status) { //info will contain the number of blogs in the backup file //in backup_ids->info will be the real info (serialized) $info = restore_read_xml_blogs($restore, $xml_file); //If we have info, then process blogs & blog_tags if ($info > 0) { //Count how many we have $blogcount = count_records('backup_ids', 'backup_code', $restore->backup_unique_code, 'table_name', 'blog'); if ($blogcount) { //Number of records to get in every chunk $recordset_size = 4; //Process blog if ($blogcount) { $counter = 0; while ($counter < $blogcount) { //Fetch recordset_size records in each iteration $recs = get_records_select("backup_ids", "table_name = 'blog' AND backup_code = '{$restore->backup_unique_code}'", "old_id", "old_id", $counter, $recordset_size); if ($recs) { foreach ($recs as $rec) { //Get the full record from backup_ids $data = backup_getid($restore->backup_unique_code, "blog", $rec->old_id); if ($data) { //Now get completed xmlized object $info = $data->info; //traverse_xmlize($info); //Debug //print_object ($GLOBALS['traverse_array']); //Debug //$GLOBALS['traverse_array']=""; //Debug //Now build the BLOG record structure $dbrec = new object(); $dbrec->module = backup_todb($info['BLOG']['#']['MODULE']['0']['#']); $dbrec->userid = backup_todb($info['BLOG']['#']['USERID']['0']['#']); $dbrec->courseid = backup_todb($info['BLOG']['#']['COURSEID']['0']['#']); $dbrec->groupid = backup_todb($info['BLOG']['#']['GROUPID']['0']['#']); $dbrec->moduleid = backup_todb($info['BLOG']['#']['MODULEID']['0']['#']); $dbrec->coursemoduleid = backup_todb($info['BLOG']['#']['COURSEMODULEID']['0']['#']); $dbrec->subject = backup_todb($info['BLOG']['#']['SUBJECT']['0']['#']); $dbrec->summary = backup_todb($info['BLOG']['#']['SUMMARY']['0']['#']); $dbrec->content = backup_todb($info['BLOG']['#']['CONTENT']['0']['#']); $dbrec->uniquehash = backup_todb($info['BLOG']['#']['UNIQUEHASH']['0']['#']); $dbrec->rating = backup_todb($info['BLOG']['#']['RATING']['0']['#']); $dbrec->format = backup_todb($info['BLOG']['#']['FORMAT']['0']['#']); $dbrec->attachment = backup_todb($info['BLOG']['#']['ATTACHMENT']['0']['#']); $dbrec->publishstate = backup_todb($info['BLOG']['#']['PUBLISHSTATE']['0']['#']); $dbrec->lastmodified = backup_todb($info['BLOG']['#']['LASTMODIFIED']['0']['#']); $dbrec->created = backup_todb($info['BLOG']['#']['CREATED']['0']['#']); $dbrec->usermodified = backup_todb($info['BLOG']['#']['USERMODIFIED']['0']['#']); //We have to recode the userid field $user = backup_getid($restore->backup_unique_code, "user", $dbrec->userid); if ($user) { //echo "User ".$dbrec->userid." to user ".$user->new_id."<br />"; //Debug $dbrec->userid = $user->new_id; } //Check if the record doesn't exist in DB! $exist = get_record('post', 'userid', $dbrec->userid, 'subject', $dbrec->subject, 'created', $dbrec->created); $newblogid = 0; if (!$exist) { //Not exist. Insert $newblogid = insert_record('post', $dbrec); } //Going to restore related tags. Check they are enabled and we have inserted a blog if ($CFG->usetags && $newblogid) { //Look for tags in this blog if (isset($info['BLOG']['#']['BLOG_TAGS']['0']['#']['BLOG_TAG'])) { $tagsarr = $info['BLOG']['#']['BLOG_TAGS']['0']['#']['BLOG_TAG']; //Iterate over tags $tags = array(); for ($i = 0; $i < sizeof($tagsarr); $i++) { $tag_info = $tagsarr[$i]; ///traverse_xmlize($tag_info); //Debug ///print_object ($GLOBALS['traverse_array']); //Debug ///$GLOBALS['traverse_array']=""; //Debug $name = backup_todb($tag_info['#']['NAME']['0']['#']); $rawname = backup_todb($tag_info['#']['RAWNAME']['0']['#']); $tags[] = $rawname; //Rawname is all we need } tag_set('post', $newblogid, $tags); //Add all the tags in one API call } } } //Do some output $counter++; if ($counter % 10 == 0) { if (!defined('RESTORE_SILENTLY')) { echo "."; if ($counter % 200 == 0) { echo "<br />"; } } backup_flush(300); } } } } } } } } return $status; }
/** * Tests the function that deletes a course module * * @param string $type The type of module for the test * @param array $options The options for the module creation * @dataProvider provider_course_delete_module */ public function test_course_delete_module($type, $options) { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); // Create course and modules. $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); $options['course'] = $course->id; // Generate an assignment with due date (will generate a course event). $module = $this->getDataGenerator()->create_module($type, $options); // Get the module context. $modcontext = context_module::instance($module->cmid); // Verify context exists. $this->assertInstanceOf('context_module', $modcontext); // Make module specific messes. switch ($type) { case 'assign': // Add some tags to this assignment. tag_set('assign', $module->id, array('Tag 1', 'Tag 2', 'Tag 3'), 'mod_assign', $modcontext->id); // Confirm the tag instances were added. $criteria = array('component' => 'mod_assign', 'contextid' => $modcontext->id); $this->assertEquals(3, $DB->count_records('tag_instance', $criteria)); // Verify event assignment event has been generated. $eventcount = $DB->count_records('event', array('instance' => $module->id, 'modulename' => $type)); $this->assertEquals(1, $eventcount); break; case 'quiz': $qgen = $this->getDataGenerator()->get_plugin_generator('core_question'); $qcat = $qgen->create_question_category(array('contextid' => $modcontext->id)); $questions = array($qgen->create_question('shortanswer', null, array('category' => $qcat->id)), $qgen->create_question('shortanswer', null, array('category' => $qcat->id))); $this->expectOutputRegex('/' . get_string('unusedcategorydeleted', 'question') . '/'); break; default: break; } // Run delete.. course_delete_module($module->cmid); // Verify the context has been removed. $this->assertFalse(context_module::instance($module->cmid, IGNORE_MISSING)); // Verify the course_module record has been deleted. $cmcount = $DB->count_records('course_modules', array('id' => $module->cmid)); $this->assertEmpty($cmcount); // Test clean up of module specific messes. switch ($type) { case 'assign': // Verify event assignment events have been removed. $eventcount = $DB->count_records('event', array('instance' => $module->id, 'modulename' => $type)); $this->assertEmpty($eventcount); // Verify the tag instances were deleted. $criteria = array('component' => 'mod_assign', 'contextid' => $modcontext->id); $this->assertEquals(0, $DB->count_records('tag_instance', $criteria)); break; case 'quiz': // Verify category deleted. $criteria = array('contextid' => $modcontext->id); $this->assertEquals(0, $DB->count_records('question_categories', $criteria)); // Verify questions deleted. $criteria = array('category' => $qcat->id); $this->assertEquals(0, $DB->count_records('question', $criteria)); break; default: break; } }
protected function process_tag($data) { global $CFG, $DB; $data = (object) $data; $newquestion = $this->get_new_parentid('question'); if (!empty($CFG->usetags)) { // if enabled in server // TODO: This is highly inefficient. Each time we add one tag // we fetch all the existing because tag_set() deletes them // so everything must be reinserted on each call $tags = array(); $existingtags = tag_get_tags('question', $newquestion); // Re-add all the existitng tags foreach ($existingtags as $existingtag) { $tags[] = $existingtag->rawname; } // Add the one being restored $tags[] = $data->rawname; // Get the category, so we can then later get the context. $categoryid = $this->get_new_parentid('question_category'); if (empty($this->cachedcategory) || $this->cachedcategory->id != $categoryid) { $this->cachedcategory = $DB->get_record('question_categories', array('id' => $categoryid)); } // Send all the tags back to the question tag_set('question', $newquestion, $tags, 'core_question', $this->cachedcategory->contextid); } }
function booking_update_instance($booking) { global $DB; // Given an object containing all the necessary data, // (defined by the form in mod.html) this function // will update an existing instance with new data. // we have to prepare the bookingclosingtimes as an $arrray, currently they are in $booking as $key (string) $booking->id = $booking->instance; $booking->timemodified = time(); if (isset($booking->additionalfields) && count($booking->additionalfields) > 0) { $booking->additionalfields = implode(',', $booking->additionalfields); } if (isset($booking->categoryid) && count($booking->categoryid) > 0) { $booking->categoryid = implode(',', $booking->categoryid); } tag_set('booking', $booking->id, $booking->tags); $cm = get_coursemodule_from_instance('booking', $booking->id); $context = context_module::instance($cm->id); file_save_draft_area_files($booking->myfilemanager, $context->id, 'mod_booking', 'myfilemanager', $booking->id, array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 50)); if (empty($booking->timerestrict)) { $booking->timeopen = 0; $booking->timeclose = 0; } // Copy the text fields out: $booking->bookedtext = $booking->bookedtext['text']; $booking->waitingtext = $booking->waitingtext['text']; $booking->statuschangetext = $booking->statuschangetext['text']; $booking->deletedtext = $booking->deletedtext['text']; $booking->pollurltext = $booking->pollurltext['text']; $booking->pollurlteacherstext = $booking->pollurlteacherstext['text']; $booking->notificationtext = $booking->notificationtext['text']; $booking->userleave = $booking->userleave['text']; //update, delete or insert answers if (!empty($booking->option)) { foreach ($booking->option as $key => $value) { $value = trim($value); $option = new stdClass(); $option->text = $value; $option->bookingid = $booking->id; if (isset($booking->limit[$key])) { $option->maxanswers = $booking->limit[$key]; } $option->timemodified = time(); if (isset($booking->optionid[$key]) && !empty($booking->optionid[$key])) { //existing booking record $option->id = $booking->optionid[$key]; if (isset($value) && $value != '') { $DB->update_record("booking_options", $option); } else { //empty old option - needs to be deleted. $DB->delete_records("booking_options", array("id" => $option->id)); } } else { if (isset($value) && $value != '') { $DB->insert_record("booking_options", $option); } } } } return $DB->update_record('booking', $booking); }
function useredit_update_interests($user, $interests) { tag_set('user', $user->id, $interests); }
/** * Removes a tag from a record, without overwriting other current tags. * * @param string $record_type the type of record to tag ('post' for blogs, * 'user' for users, etc. * @param int $record_id the id of the record to tag * @param string $tag the tag to delete * @return void */ function tag_set_delete($record_type, $record_id, $tag) { $new_tags = array(); foreach (tag_get_tags($record_type, $record_id) as $current_tag) { if ($current_tag->name != $tag) { // Keep all tags but the one specified $new_tags[] = $current_tag->name; } } return tag_set($record_type, $record_id, $new_tags); }
/** * 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/lib.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'); $callbacks = get_plugins_with_function('delete_course', 'lib.php'); foreach ($cleanuplugintypes as $type) { if (!empty($callbacks[$type])) { foreach ($callbacks[$type] as $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. tag_set('course', $course->id, array(), 'core', $coursecontext->id); // 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; 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; }
/** * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * * Any plugin that needs to purge user data should register the 'user_deleted' event. * * @param object $user User object before delete * @return boolean always true */ function delete_user($user) { global $CFG, $DB; require_once $CFG->libdir . '/grouplib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/message/lib.php'; require_once $CFG->dirroot . '/tag/lib.php'; // delete all grades - backup is kept in grade_grades_history table grade_user_delete($user->id); //move unread messages from this user to read message_move_userfrom_unread2read($user->id); // TODO: remove from cohorts using standard API here // remove user tags tag_set('user', $user->id, array()); // unconditionally unenrol from all courses enrol_user_delete($user); // unenrol from all roles in all contexts role_unassign_all(array('userid' => $user->id)); // this might be slow but it is really needed - modules might do some extra cleanup! //now do a brute force cleanup // remove from all cohorts $DB->delete_records('cohort_members', array('userid' => $user->id)); // remove from all groups $DB->delete_records('groups_members', array('userid' => $user->id)); // brute force unenrol from all courses $DB->delete_records('user_enrolments', array('userid' => $user->id)); // purge user preferences $DB->delete_records('user_preferences', array('userid' => $user->id)); // purge user extra profile info $DB->delete_records('user_info_data', array('userid' => $user->id)); // last course access not necessary either $DB->delete_records('user_lastaccess', array('userid' => $user->id)); // now do a final accesslib cleanup - removes all role assignments in user context and context itself delete_context(CONTEXT_USER, $user->id); // workaround for bulk deletes of users with the same email address $delname = "{$user->email}." . time(); while ($DB->record_exists('user', array('username' => $delname))) { // no need to use mnethostid here $delname++; } // mark internal user record as "deleted" $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = $delname; // Remember it just in case $updateuser->email = md5($user->username); // Store hash of username, useful importing/restoring users $updateuser->idnumber = ''; // Clear this field to free it up $updateuser->timemodified = time(); $DB->update_record('user', $updateuser); // notify auth plugin - do not block the delete even when plugin fails $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); // any plugin that needs to cleanup should register this event events_trigger('user_deleted', $user); return true; }
public function test_course_delete_module() { global $DB; $this->resetAfterTest(true); $this->setAdminUser(); // Create course and modules. $course = $this->getDataGenerator()->create_course(array('numsections' => 5)); // Generate an assignment with due date (will generate a course event). $assign = $this->getDataGenerator()->create_module('assign', array('duedate' => time(), 'course' => $course->id)); // Get the module context. $modcontext = context_module::instance($assign->cmid); // Verify context exists. $this->assertInstanceOf('context_module', $modcontext); // Add some tags to this assignment. tag_set('assign', $assign->id, array('Tag 1', 'Tag 2', 'Tag 3'), 'mod_assign', $modcontext->id); // Confirm the tag instances were added. $this->assertEquals(3, $DB->count_records('tag_instance', array('component' => 'mod_assign', 'contextid' => $modcontext->id))); // Verify event assignment event has been generated. $eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign')); $this->assertEquals(1, $eventcount); // Run delete.. course_delete_module($assign->cmid); // Verify the context has been removed. $this->assertFalse(context_module::instance($assign->cmid, IGNORE_MISSING)); // Verify the course_module record has been deleted. $cmcount = $DB->count_records('course_modules', array('id' => $assign->cmid)); $this->assertEmpty($cmcount); // Verify event assignment events have been removed. $eventcount = $DB->count_records('event', array('instance' => $assign->id, 'modulename' => 'assign')); $this->assertEmpty($eventcount); // Verify the tag instances were deleted. $this->assertEquals(0, $DB->count_records('tag_instance', array('component' => 'mod_assign', 'contextid' => $modcontext->id))); }
/** * Update a course. * * Please note this functions does not verify any access control, * the calling code is responsible for all validation (usually it is the form definition). * * @param object $data - all the data needed for an entry in the 'course' table * @param array $editoroptions course description editor options * @return void */ function update_course($data, $editoroptions = NULL) { global $DB, $CFG; require_once $CFG->dirroot . '/tag/lib.php'; $data->timemodified = time(); $oldcourse = course_get_format($data->id)->get_course(); $context = context_course::instance($oldcourse->id); if ($editoroptions) { $data = file_postupdate_standard_editor($data, 'summary', $editoroptions, $context, 'course', 'summary', 0); } if ($overviewfilesoptions = course_overviewfiles_options($data->id)) { $data = file_postupdate_standard_filemanager($data, 'overviewfiles', $overviewfilesoptions, $context, 'course', 'overviewfiles', 0); } // Check we don't have a duplicate shortname. if (!empty($data->shortname) && $oldcourse->shortname != $data->shortname) { if ($DB->record_exists_sql('SELECT id from {course} WHERE shortname = ? AND id <> ?', array($data->shortname, $data->id))) { throw new moodle_exception('shortnametaken', '', '', $data->shortname); } } // Check we don't have a duplicate idnumber. if (!empty($data->idnumber) && $oldcourse->idnumber != $data->idnumber) { if ($DB->record_exists_sql('SELECT id from {course} WHERE idnumber = ? AND id <> ?', array($data->idnumber, $data->id))) { throw new moodle_exception('courseidnumbertaken', '', '', $data->idnumber); } } if (!isset($data->category) or empty($data->category)) { // prevent nulls and 0 in category field unset($data->category); } $changesincoursecat = $movecat = (isset($data->category) and $oldcourse->category != $data->category); if (!isset($data->visible)) { // data not from form, add missing visibility info $data->visible = $oldcourse->visible; } if ($data->visible != $oldcourse->visible) { // reset the visibleold flag when manually hiding/unhiding course $data->visibleold = $data->visible; $changesincoursecat = true; } else { if ($movecat) { $newcategory = $DB->get_record('course_categories', array('id' => $data->category)); if (empty($newcategory->visible)) { // make sure when moving into hidden category the course is hidden automatically $data->visible = 0; } } } // Update with the new data $DB->update_record('course', $data); // make sure the modinfo cache is reset rebuild_course_cache($data->id); // update course format options with full course data course_get_format($data->id)->update_course_format_options($data, $oldcourse); $course = $DB->get_record('course', array('id' => $data->id)); if ($movecat) { $newparent = context_coursecat::instance($course->category); $context->update_moved($newparent); } $fixcoursesortorder = $movecat || isset($data->sortorder) && $oldcourse->sortorder != $data->sortorder; if ($fixcoursesortorder) { fix_course_sortorder(); } // purge appropriate caches in case fix_course_sortorder() did not change anything cache_helper::purge_by_event('changesincourse'); if ($changesincoursecat) { cache_helper::purge_by_event('changesincoursecat'); } // Test for and remove blocks which aren't appropriate anymore blocks_remove_inappropriate($course); // Save any custom role names. save_local_role_names($course->id, $data); // update enrol settings enrol_course_updated(false, $course, $data); // Update course tags. if ($CFG->usetags && isset($data->tags)) { tag_set('course', $course->id, $data->tags, 'core', context_course::instance($course->id)->id); } // Trigger a course updated event. $event = \core\event\course_updated::create(array('objectid' => $course->id, 'context' => context_course::instance($course->id), 'other' => array('shortname' => $course->shortname, 'fullname' => $course->fullname))); $event->set_legacy_logdata(array($course->id, 'course', 'update', 'edit.php?id=' . $course->id, $course->id)); $event->trigger(); if ($oldcourse->format !== $course->format) { // Remove all options stored for the previous format // We assume that new course format migrated everything it needed watching trigger // 'course_updated' and in method format_XXX::update_course_format_options() $DB->delete_records('course_format_options', array('courseid' => $course->id, 'format' => $oldcourse->format)); } }
/** * Given one restoreid, create in DB all the users present * in backup_ids having newitemid = 0, as far as * precheck_included_users() have left them there * ready to be created. Also, annotate their newids * once created for later reference */ public static function create_included_users($basepath, $restoreid, $userid) { global $CFG, $DB; $authcache = array(); // Cache to get some bits from authentication plugins $languages = get_string_manager()->get_list_of_translations(); // Get languages for quick search later $themes = get_list_of_themes(); // Get themes for quick search later // Iterate over all the included users with newitemid = 0, have to create them $rs = $DB->get_recordset('backup_ids_temp', array('backupid' => $restoreid, 'itemname' => 'user', 'newitemid' => 0), '', 'itemid, parentitemid'); foreach ($rs as $recuser) { $user = (object) self::get_backup_ids_record($restoreid, 'user', $recuser->itemid)->info; // if user lang doesn't exist here, use site default if (!array_key_exists($user->lang, $languages)) { $user->lang = $CFG->lang; } // if user theme isn't available on target site or they are disabled, reset theme if (!empty($user->theme)) { if (empty($CFG->allowuserthemes) || !in_array($user->theme, $themes)) { $user->theme = ''; } } // if user to be created has mnet auth and its mnethostid is $CFG->mnet_localhost_id // that's 100% impossible as own server cannot be accesed over mnet. Change auth to email/manual if ($user->auth == 'mnet' && $user->mnethostid == $CFG->mnet_localhost_id) { // Respect registerauth if ($CFG->registerauth == 'email') { $user->auth = 'email'; } else { $user->auth = 'manual'; } } unset($user->mnethosturl); // Not needed anymore // Disable pictures based on global setting if (!empty($CFG->disableuserimages)) { $user->picture = 0; } // We need to analyse the AUTH field to recode it: // - if the auth isn't enabled in target site, $CFG->registerauth will decide // - finally, if the auth resulting isn't enabled, default to 'manual' if (!is_enabled_auth($user->auth)) { if ($CFG->registerauth == 'email') { $user->auth = 'email'; } else { $user->auth = 'manual'; } } if (!is_enabled_auth($user->auth)) { // Final auth check verify, default to manual if not enabled $user->auth = 'manual'; } // Now that we know the auth method, for users to be created without pass // if password handling is internal and reset password is available // we set the password to "restored" (plain text), so the login process // will know how to handle that situation in order to allow the user to // recover the password. MDL-20846 if (empty($user->password)) { // Only if restore comes without password if (!array_key_exists($user->auth, $authcache)) { // Not in cache $userauth = new stdClass(); $authplugin = get_auth_plugin($user->auth); $userauth->preventpassindb = $authplugin->prevent_local_passwords(); $userauth->isinternal = $authplugin->is_internal(); $userauth->canresetpwd = $authplugin->can_reset_password(); $authcache[$user->auth] = $userauth; } else { $userauth = $authcache[$user->auth]; // Get from cache } // Most external plugins do not store passwords locally if (!empty($userauth->preventpassindb)) { $user->password = '******'; // If Moodle is responsible for storing/validating pwd and reset functionality is available, mark } else { if ($userauth->isinternal and $userauth->canresetpwd) { $user->password = '******'; } } } // Creating new user, we must reset the policyagreed always $user->policyagreed = 0; // Set time created if empty if (empty($user->timecreated)) { $user->timecreated = time(); } // Done, let's create the user and annotate its id $newuserid = $DB->insert_record('user', $user); self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, $newuserid); // Let's create the user context and annotate it (we need it for sure at least for files) // but for deleted users that don't have a context anymore (MDL-30192). We are done for them // and nothing else (custom fields, prefs, tags, files...) will be created. if (empty($user->deleted)) { $newuserctxid = $user->deleted ? 0 : get_context_instance(CONTEXT_USER, $newuserid)->id; self::set_backup_ids_record($restoreid, 'context', $recuser->parentitemid, $newuserctxid); // Process custom fields if (isset($user->custom_fields)) { // if present in backup foreach ($user->custom_fields['custom_field'] as $udata) { $udata = (object) $udata; // If the profile field has data and the profile shortname-datatype is defined in server if ($udata->field_data) { if ($field = $DB->get_record('user_info_field', array('shortname' => $udata->field_name, 'datatype' => $udata->field_type))) { /// Insert the user_custom_profile_field $rec = new stdClass(); $rec->userid = $newuserid; $rec->fieldid = $field->id; $rec->data = $udata->field_data; $DB->insert_record('user_info_data', $rec); } } } } // Process tags if (!empty($CFG->usetags) && isset($user->tags)) { // if enabled in server and present in backup $tags = array(); foreach ($user->tags['tag'] as $usertag) { $usertag = (object) $usertag; $tags[] = $usertag->rawname; } tag_set('user', $newuserid, $tags); } // Process preferences if (isset($user->preferences)) { // if present in backup foreach ($user->preferences['preference'] as $preference) { $preference = (object) $preference; // Prepare the record and insert it $preference->userid = $newuserid; $status = $DB->insert_record('user_preferences', $preference); } } // Create user files in pool (profile, icon, private) by context restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'icon', $recuser->parentitemid, $userid); restore_dbops::send_files_to_pool($basepath, $restoreid, 'user', 'profile', $recuser->parentitemid, $userid); } } $rs->close(); }
foreach ($values as $value) { if (!preg_match('/value(\\d+)/', $value, $matches)) { continue; } insert_record('course_classification', (object) array('course' => $course->id, 'value' => $matches[1])); $cleanvalues[] = $matches[1]; } // update the manual tags tag_set('course', $course->id, explode(',', $formdata->tags)); // update the classification tags $ctag_arr = array(); $sql = "SELECT value FROM {$CFG->prefix}classification_value WHERE id IN ( " . implode(',', $cleanvalues) . ")"; if (!empty($cleanvalues) && ($ctags = get_records_sql($sql))) { foreach ($ctags as $ctag) { $ctag_arr[] = strtolower($ctag->value); } } tag_set('courseclassification', $course->id, $ctag_arr); //set the tags (or clear them if none selected) commit_sql(); events_trigger('lp_classification', $course->id); notify(get_string('changessaved'), 'notifysuccess'); print_continue($CFG->wwwroot . '/course/view.php?id=' . $course->id); } else { $post = new object(); if ($itemptags = tag_get_tags_csv('course', $course->id, TAG_RETURN_TEXT, 'default')) { $post->tags = $itemptags; } $mform->set_data($post); $mform->display(); }
function useredit_update_interests($user, $csv_tag_names) { tag_set('user', $user->id, explode(',', $csv_tag_names)); }
/** * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * * Any plugin that needs to purge user data should register the 'user_deleted' event. * * @param stdClass $user full user object before delete * @return boolean success * @throws coding_exception if invalid $user parameter detected */ function delete_user(stdClass $user) { global $CFG, $DB; require_once $CFG->libdir . '/grouplib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/message/lib.php'; require_once $CFG->dirroot . '/tag/lib.php'; require_once $CFG->dirroot . '/user/lib.php'; // Make sure nobody sends bogus record type as parameter. if (!property_exists($user, 'id') or !property_exists($user, 'username')) { throw new coding_exception('Invalid $user parameter in delete_user() detected'); } // Better not trust the parameter and fetch the latest info this will be very expensive anyway. if (!($user = $DB->get_record('user', array('id' => $user->id)))) { debugging('Attempt to delete unknown user account.'); return false; } // There must be always exactly one guest record, originally the guest account was identified by username only, // now we use $CFG->siteguest for performance reasons. if ($user->username === 'guest' or isguestuser($user)) { debugging('Guest user account can not be deleted.'); return false; } // Admin can be theoretically from different auth plugin, but we want to prevent deletion of internal accoutns only, // if anything goes wrong ppl may force somebody to be admin via config.php setting $CFG->siteadmins. if ($user->auth === 'manual' and is_siteadmin($user)) { debugging('Local administrator accounts can not be deleted.'); return false; } // Keep user record before updating it, as we have to pass this to user_deleted event. $olduser = clone $user; // Keep a copy of user context, we need it for event. $usercontext = context_user::instance($user->id); // Delete all grades - backup is kept in grade_grades_history table. grade_user_delete($user->id); // Move unread messages from this user to read. message_move_userfrom_unread2read($user->id); // TODO: remove from cohorts using standard API here. // Remove user tags. tag_set('user', $user->id, array(), 'core', $usercontext->id); // Unconditionally unenrol from all courses. enrol_user_delete($user); // Unenrol from all roles in all contexts. // This might be slow but it is really needed - modules might do some extra cleanup! role_unassign_all(array('userid' => $user->id)); // Now do a brute force cleanup. // Remove from all cohorts. $DB->delete_records('cohort_members', array('userid' => $user->id)); // Remove from all groups. $DB->delete_records('groups_members', array('userid' => $user->id)); // Brute force unenrol from all courses. $DB->delete_records('user_enrolments', array('userid' => $user->id)); // Purge user preferences. $DB->delete_records('user_preferences', array('userid' => $user->id)); // Purge user extra profile info. $DB->delete_records('user_info_data', array('userid' => $user->id)); // Purge log of previous password hashes. $DB->delete_records('user_password_history', array('userid' => $user->id)); // Last course access not necessary either. $DB->delete_records('user_lastaccess', array('userid' => $user->id)); // Remove all user tokens. $DB->delete_records('external_tokens', array('userid' => $user->id)); // Unauthorise the user for all services. $DB->delete_records('external_services_users', array('userid' => $user->id)); // Remove users private keys. $DB->delete_records('user_private_key', array('userid' => $user->id)); // Remove users customised pages. $DB->delete_records('my_pages', array('userid' => $user->id, 'private' => 1)); // Force logout - may fail if file based sessions used, sorry. \core\session\manager::kill_user_sessions($user->id); // Workaround for bulk deletes of users with the same email address. $delname = clean_param($user->email . "." . time(), PARAM_USERNAME); while ($DB->record_exists('user', array('username' => $delname))) { // No need to use mnethostid here. $delname++; } // Mark internal user record as "deleted". $updateuser = new stdClass(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = $delname; // Remember it just in case. $updateuser->email = md5($user->username); // Store hash of username, useful importing/restoring users. $updateuser->idnumber = ''; // Clear this field to free it up. $updateuser->picture = 0; $updateuser->timemodified = time(); // Don't trigger update event, as user is being deleted. user_update_user($updateuser, false, false); // Now do a final accesslib cleanup - removes all role assignments in user context and context itself. context_helper::delete_instance(CONTEXT_USER, $user->id); // Any plugin that needs to cleanup should register this event. // Trigger event. $event = \core\event\user_deleted::create(array('objectid' => $user->id, 'relateduserid' => $user->id, 'context' => $usercontext, 'other' => array('username' => $user->username, 'email' => $user->email, 'idnumber' => $user->idnumber, 'picture' => $user->picture, 'mnethostid' => $user->mnethostid))); $event->add_record_snapshot('user', $olduser); $event->trigger(); // We will update the user's timemodified, as it will be passed to the user_deleted event, which // should know about this updated property persisted to the user's table. $user->timemodified = $updateuser->timemodified; // Notify auth plugin - do not block the delete even when plugin fails. $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); return true; }
/** * Marks user deleted in internal user database and notifies the auth plugin. * Also unenrols user from all roles and does other cleanup. * @param object $user Userobject before delete (without system magic quotes) * @return boolean success */ function delete_user($user) { global $CFG; require_once $CFG->libdir . '/grouplib.php'; require_once $CFG->libdir . '/gradelib.php'; require_once $CFG->dirroot . '/message/lib.php'; begin_sql(); // delete all grades - backup is kept in grade_grades_history table if ($grades = grade_grade::fetch_all(array('userid' => $user->id))) { foreach ($grades as $grade) { $grade->delete('userdelete'); } } //move unread messages from this user to read message_move_userfrom_unread2read($user->id); // remove from all groups delete_records('groups_members', 'userid', $user->id); // unenrol from all roles in all contexts role_unassign(0, $user->id); // this might be slow but it is really needed - modules might do some extra cleanup! // now do a final accesslib cleanup - removes all role assingments in user context and context itself delete_context(CONTEXT_USER, $user->id); require_once $CFG->dirroot . '/tag/lib.php'; tag_set('user', $user->id, array()); // workaround for bulk deletes of users with the same email address $delname = addslashes("{$user->email}." . time()); while (record_exists('user', 'username', $delname)) { // no need to use mnethostid here $delname++; } // mark internal user record as "deleted" $updateuser = new object(); $updateuser->id = $user->id; $updateuser->deleted = 1; $updateuser->username = $delname; // Remember it just in case $updateuser->email = md5($user->username); // Store hash of username, useful importing/restoring users $updateuser->idnumber = ''; // Clear this field to free it up $updateuser->timemodified = time(); if (update_record('user', $updateuser)) { commit_sql(); // notify auth plugin - do not block the delete even when plugin fails $authplugin = get_auth_plugin($user->auth); $authplugin->user_delete($user); events_trigger('user_deleted', $user); return true; } else { rollback_sql(); return false; } }
if (has_capability('moodle/tag:manage', $systemcontext)) { // rename tag if (!tag_rename($tag->id, $tagnew->rawname)) { print_error('errorupdatingrecord', 'tag'); } } //log tag changes activity //if tag name exist from form, renaming is allow. record log action as rename //otherwise, record log action as update if (isset($tagnew->name) && $tag->name != $tagnew->name) { add_to_log($COURSE->id, 'tag', 'update', 'index.php?id=' . $tag->id, $tag->name . '->' . $tagnew->name); } elseif ($tag->description != $tagnew->description) { add_to_log($COURSE->id, 'tag', 'update', 'index.php?id=' . $tag->id, $tag->name); } //updated related tags tag_set('tag', $tagnew->id, explode(',', trim($tagnew->relatedtags))); //print_object($tagnew); die(); redirect($CFG->wwwroot . '/tag/index.php?tag=' . rawurlencode($tag->name)); // must use $tag here, as the name isn't in the edit form } } $PAGE->navbar->add(get_string('tags', 'tag'), new moodle_url('/tag/search.php')); $PAGE->navbar->add($tagname); $PAGE->navbar->add(get_string('edit')); $PAGE->set_title(get_string('tag', 'tag') . ' - ' . $tagname); $PAGE->set_heading($COURSE->fullname); echo $OUTPUT->header(); echo $OUTPUT->heading($tagname, 2); if (!empty($errorstring)) { echo $OUTPUT->notification($errorstring); }
/** * Updates a users interests. * * @param stdClass $user * @param array $interests */ function useredit_update_interests($user, $interests) { tag_set('user', $user->id, $interests, 'core', context_user::instance($user->id)->id); }
} else { // We are acutally saving the question. if (!empty($question->id)) { question_require_capability_on($question, 'edit'); } else { require_capability('moodle/question:add', context::instance_by_id($newcontextid)); if (!empty($fromform->makecopy) && !$question->formoptions->cansaveasnew) { print_error('nopermissions', '', '', 'edit'); } } $question = $qtypeobj->save_question($question, $fromform); if (!empty($CFG->usetags) && isset($fromform->tags)) { // A wizardpage from multipe pages questiontype like calculated may not // allow editing the question tags, hence the isset($fromform->tags) test. require_once $CFG->dirroot . '/tag/lib.php'; tag_set('question', $question->id, $fromform->tags); } } // Purge this question from the cache. question_bank::notify_question_edited($question->id); if ($qtypeobj->finished_edit_wizard($fromform) || $movecontext) { if ($inpopup) { echo $OUTPUT->notification(get_string('changessaved'), ''); close_window(3); } else { $returnurl->param('lastchanged', $question->id); if ($appendqnumstring) { $returnurl->param($appendqnumstring, $question->id); $returnurl->param('sesskey', sesskey()); $returnurl->param('cmid', $cmid); }
/** * function to attach tags into an entry * @return void */ public function add_tags_info() { $tags = array(); if ($otags = optional_param('otags', '', PARAM_INT)) { foreach ($otags as $tagid) { // TODO : make this use the tag name in the form if ($tag = tag_get('id', $tagid)) { $tags[] = $tag->name; } } } tag_set('post', $this->id, $tags); }
public function process_tag($data) { global $CFG, $DB; $data = (object)$data; if (!empty($CFG->usetags)) { // if enabled in server // TODO: This is highly inneficient. Each time we add one tag // we fetch all the existing because tag_set() deletes them // so everything must be reinserted on each call $tags = array(); $existingtags = tag_get_tags('course', $this->get_courseid()); // Re-add all the existitng tags foreach ($existingtags as $existingtag) { $tags[] = $existingtag->rawname; } // Add the one being restored $tags[] = $data->rawname; // Send all the tags back to the course tag_set('course', $this->get_courseid(), $tags); } }
/** * function to attach tags into a post * @param int postid - id of the blog */ function add_tags_info($postid) { $tags = array(); if ($otags = optional_param('otags', '', PARAM_INT)) { foreach ($otags as $tagid) { // TODO : make this use the tag name in the form if ($tag = tag_get('id', $tagid)) { $tags[] = $tag->name; } } } $manual_tags = optional_param('ptags', '', PARAM_NOTAGS); $tags = array_merge($tags, explode(',', $manual_tags)); tag_set('post', $postid, $tags); }
protected function print_save() { global $CFG, $USER, $OUTPUT, $PAGE; $url = $CFG->wwwroot . '/mod/wiki/edit.php?pageid=' . $this->page->id; if (!empty($this->section)) { $url .= "§ion=" . urlencode($this->section); } $params = array( 'attachmentoptions' => page_wiki_edit::$attachmentoptions, 'format' => $this->format, 'version' => $this->versionnumber, 'contextid' => $this->modcontext->id ); if ($this->format != 'html') { $params['fileitemid'] = $this->page->id; $params['component'] = 'mod_wiki'; $params['filearea'] = 'attachments'; } $form = new mod_wiki_edit_form($url, $params); $save = false; $data = false; if ($data = $form->get_data()) { if ($this->format == 'html') { $data = file_postupdate_standard_editor($data, 'newcontent', page_wiki_edit::$attachmentoptions, $this->modcontext, 'mod_wiki', 'attachments', $this->subwiki->id); } if (isset($this->section)) { $save = wiki_save_section($this->page, $this->section, $data->newcontent, $USER->id); } else { $save = wiki_save_page($this->page, $data->newcontent, $USER->id); } } if ($save && $data) { if (!empty($CFG->usetags)) { tag_set('wiki_pages', $this->page->id, $data->tags); } $message = '<p>' . get_string('saving', 'wiki') . '</p>'; if (!empty($save['sections'])) { foreach ($save['sections'] as $s) { $message .= '<p>' . get_string('repeatedsection', 'wiki', $s) . '</p>'; } } if ($this->versionnumber + 1 != $save['version']) { $message .= '<p>' . get_string('wrongversionsave', 'wiki') . '</p>'; } if (isset($errors) && !empty($errors)) { foreach ($errors as $e) { $message .= "<p>" . get_string('filenotuploadederror', 'wiki', $e->get_filename()) . "</p>"; } } //deleting old locks wiki_delete_locks($this->page->id, $USER->id, $this->section); $url = new moodle_url('view.php', array('pageid' => $this->page->id, 'group' => $this->subwiki->groupid)); redirect($url); } else { print_error('savingerror', 'wiki'); } }
/** * Edits discussion settings. These parameters may be set to the NOCHANGE * constant if not being altered. * @param int $groupid Group ID * @param int $timestart Seconds since epoch that this becomes visible, * null/0 if always * @param int $timeend Seconds since epoch that this disappear, null/0 if * it doesn't * @param bool $locked True if discussion should be locked * @param bool $sticky True if discussion should be sticky * @param array $tags */ public function edit_settings($groupid, $timestart, $timeend, $locked, $sticky, array $tags = null) { global $DB, $CFG; require_once $CFG->dirroot . '/tag/lib.php'; // Apply defaults if ($groupid === self::NOCHANGE) { $groupid = $this->discussionfields->groupid; } if ($timestart === self::NOCHANGE) { $timestart = $this->discussionfields->timestart; } if ($timeend === self::NOCHANGE) { $timeend = $this->discussionfields->timeend; } if ($locked === self::NOCHANGE) { $locked = $this->discussionfields->locked; } if ($sticky === self::NOCHANGE) { $sticky = $this->discussionfields->sticky; } // Normalise entries to match db values $timestart = $timestart ? $timestart : 0; $timeend = $timeend ? $timeend : 0; $sticky = $sticky ? 1 : 0; if ($locked === true) { $locked = 1; } if (!($locked == 1 || $locked == 2)) { $locked = 0; } $groupid = $groupid ? $groupid : null; // Start transaction in case there are multiple changes relating to // search $transaction = $DB->start_delegated_transaction(); $update = new StdClass(); if ($groupid != $this->discussionfields->groupid) { $update->groupid = $groupid; // When group changes, need to redo the search data; must remove it // before changing group or it won't be able to find the old // search documents any more (because it looks for them under the // new group id). $this->ismakingsearchchange = true; $root = $this->get_root_post(); $root->search_update(); $root->search_update_children(); $this->ismakingsearchchange = false; } if ($timestart != $this->discussionfields->timestart) { $update->timestart = $timestart; $root = $this->get_root_post(); // When $timestart is not the same as $this->discussionfields->timestart // and the discussion root post ($root) has no children. if (!$root->has_children()) { // Then the root post created and modified times are set to $timestart. // Note will need to do this using DB function as no method to do this in classes. if ($timestart == 0) { $timestart = time(); } $revisedroot = new stdClass(); $revisedroot->created = $timestart; $revisedroot->modified = $timestart; $revisedroot->id = $root->get_id(); $DB->update_record('forumng_posts', $revisedroot); } } if ($timeend != $this->discussionfields->timeend) { $update->timeend = $timeend; } if ($locked != $this->discussionfields->locked) { $update->locked = $locked; } if ($sticky != $this->discussionfields->sticky) { $update->sticky = $sticky; } // Update tags if required. if ($tags != null) { $context = $this->get_forum()->get_context(true); tag_set('forumng_discussions', $this->discussionfields->id, $tags, 'mod_forumng', $context->id); } if (count((array) $update) == 0) { // No change $transaction->allow_commit(); return; } $update->id = $this->discussionfields->id; $DB->update_record('forumng_discussions', $update); // Update in memory (needed for the next group bit) $this->uncache(); foreach ($update as $key => $value) { $this->discussionfields->{$key} = $value; } // Update group if required if (isset($update->groupid)) { // When group has changed, must add items to the new group $root = $this->get_root_post(); $root->search_update(); $root->search_update_children(); } // End transaction $transaction->allow_commit(); }
/** * Process the file * This method should not normally be overidden * @param object $category * @return bool success */ public function importprocess($category) { global $USER, $CFG, $DB, $OUTPUT; $context = $category->context; $this->importcontext = $context; // reset the timer in case file upload was slow set_time_limit(0); // STAGE 1: Parse the file echo $OUTPUT->notification(get_string('parsingquestions', 'question'), 'notifysuccess'); if (! $lines = $this->readdata($this->filename)) { echo $OUTPUT->notification(get_string('cannotread', 'question')); return false; } if (!$questions = $this->readquestions($lines, $context)) { // Extract all the questions echo $OUTPUT->notification(get_string('noquestionsinfile', 'question')); return false; } // STAGE 2: Write data to database echo $OUTPUT->notification(get_string('importingquestions', 'question', $this->count_questions($questions)), 'notifysuccess'); // check for errors before we continue if ($this->stoponerror and ($this->importerrors>0)) { echo $OUTPUT->notification(get_string('importparseerror', 'question')); return true; } // get list of valid answer grades $gradeoptionsfull = question_bank::fraction_options_full(); // check answer grades are valid // (now need to do this here because of 'stop on error': MDL-10689) $gradeerrors = 0; $goodquestions = array(); foreach ($questions as $question) { if (!empty($question->fraction) and (is_array($question->fraction))) { $fractions = $question->fraction; $answersvalid = true; // in case they are! foreach ($fractions as $key => $fraction) { $newfraction = match_grade_options($gradeoptionsfull, $fraction, $this->matchgrades); if ($newfraction === false) { $answersvalid = false; } else { $fractions[$key] = $newfraction; } } if (!$answersvalid) { echo $OUTPUT->notification(get_string('invalidgrade', 'question')); ++$gradeerrors; continue; } else { $question->fraction = $fractions; } } $goodquestions[] = $question; } $questions = $goodquestions; // check for errors before we continue if ($this->stoponerror && $gradeerrors > 0) { return false; } // count number of questions processed $count = 0; foreach ($questions as $question) { // Process and store each question // reset the php timeout set_time_limit(0); // check for category modifiers if ($question->qtype == 'category') { if ($this->catfromfile) { // find/create category object $catpath = $question->category; $newcategory = $this->create_category_path($catpath); if (!empty($newcategory)) { $this->category = $newcategory; } } continue; } $question->context = $context; $count++; echo "<hr /><p><b>$count</b>. ".$this->format_question_text($question)."</p>"; $question->category = $this->category->id; $question->stamp = make_unique_id_code(); // Set the unique code (not to be changed) $question->createdby = $USER->id; $question->timecreated = time(); $question->modifiedby = $USER->id; $question->timemodified = time(); $question->id = $DB->insert_record('question', $question); if (isset($question->questiontextfiles)) { foreach ($question->questiontextfiles as $file) { question_bank::get_qtype($question->qtype)->import_file( $context, 'question', 'questiontext', $question->id, $file); } } if (isset($question->generalfeedbackfiles)) { foreach ($question->generalfeedbackfiles as $file) { question_bank::get_qtype($question->qtype)->import_file( $context, 'question', 'generalfeedback', $question->id, $file); } } $this->questionids[] = $question->id; // Now to save all the answers and type-specific options $result = question_bank::get_qtype($question->qtype)->save_question_options($question); if (!empty($CFG->usetags) && isset($question->tags)) { require_once($CFG->dirroot . '/tag/lib.php'); tag_set('question', $question->id, $question->tags); } if (!empty($result->error)) { echo $OUTPUT->notification($result->error); return false; } if (!empty($result->notice)) { echo $OUTPUT->notification($result->notice); return true; } // Give the question a unique version stamp determined by question_hash() $DB->set_field('question', 'version', question_hash($question), array('id' => $question->id)); } return true; }
/** * Test the tag added event. */ public function test_tag_added() { global $DB; // Create a course to tag. $course = $this->getDataGenerator()->create_course(); // Trigger and capture the event for tagging a course. $sink = $this->redirectEvents(); tag_set('course', $course->id, array('A tag'), 'core', context_course::instance($course->id)->id); $events = $sink->get_events(); $event = $events[1]; // Check that the tag was added to the course and that the event data is valid. $this->assertEquals(1, $DB->count_records('tag_instance', array('component' => 'core'))); $this->assertInstanceOf('\\core\\event\\tag_added', $event); $this->assertEquals(context_course::instance($course->id), $event->get_context()); $expected = array($course->id, 'coursetags', 'add', 'tag/search.php?query=A+tag', 'Course tagged'); $this->assertEventLegacyLogData($expected, $event); // Create a question to tag. $questiongenerator = $this->getDataGenerator()->get_plugin_generator('core_question'); $cat = $questiongenerator->create_question_category(); $question = $questiongenerator->create_question('shortanswer', null, array('category' => $cat->id)); // Trigger and capture the event for tagging a question. $this->assertEquals(1, $DB->count_records('tag_instance')); $sink = $this->redirectEvents(); tag_set('question', $question->id, array('A tag'), 'core_question', $cat->contextid); $events = $sink->get_events(); $event = reset($events); // Check that the tag was added to the question and the event data is valid. $this->assertEquals(1, $DB->count_records('tag_instance', array('component' => 'core'))); $this->assertInstanceOf('\\core\\event\\tag_added', $event); $this->assertEquals(context_system::instance(), $event->get_context()); $expected = null; $this->assertEventLegacyLogData($expected, $event); }