Beispiel #1
0
 /**
  * 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();
 }
Beispiel #4
0
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;
}
Beispiel #5
0
/**
 * 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()));
}
Beispiel #6
0
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;
}
Beispiel #7
0
 /**
  * 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;
     }
 }
Beispiel #8
0
 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);
}
Beispiel #11
0
/**
 * 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);
}
Beispiel #12
0
/**
 * 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;
}
Beispiel #13
0
/**
 * 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)));
 }
Beispiel #15
0
/**
 * 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));
    }
}
Beispiel #16
0
 /**
  * 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();
 }
Beispiel #17
0
    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();
}
Beispiel #18
0
function useredit_update_interests($user, $csv_tag_names)
{
    tag_set('user', $user->id, explode(',', $csv_tag_names));
}
Beispiel #19
0
/**
 * 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;
}
Beispiel #20
0
/**
 * 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;
    }
}
Beispiel #21
0
        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);
}
Beispiel #22
0
/**
 * 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);
}
Beispiel #23
0
 } 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);
         }
Beispiel #24
0
 /**
  * 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);
 }
Beispiel #25
0
    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);
        }
    }
Beispiel #26
0
/**
 * 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);
}
Beispiel #27
0
    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 .= "&section=" . 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();
 }
Beispiel #29
0
    /**
     * 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);
 }