/**
  * Test remove_course_content deletes course contents
  * TODO Add asserts to verify other data related to course is deleted as well.
  */
 public function test_remove_course_contents()
 {
     $this->resetAfterTest();
     $course = $this->getDataGenerator()->create_course();
     $user = $this->getDataGenerator()->create_user();
     $gen = $this->getDataGenerator()->get_plugin_generator('core_notes');
     $note = $gen->create_instance(array('courseid' => $course->id, 'userid' => $user->id));
     $this->assertNotEquals(false, note_load($note->id));
     remove_course_contents($course->id, false);
     $this->assertFalse(note_load($note->id));
 }
Example #2
0
 /**
  * Test that triggering a course_content_deleted event works as expected.
  */
 public function test_course_content_deleted_event()
 {
     global $DB;
     $this->resetAfterTest();
     // Create the course.
     $course = $this->getDataGenerator()->create_course();
     // Get the course from the DB. The data generator adds some extra properties, such as
     // numsections, to the course object which will fail the assertions later on.
     $course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST);
     // Save the course context before we delete the course.
     $coursecontext = context_course::instance($course->id);
     // Catch the update event.
     $sink = $this->redirectEvents();
     remove_course_contents($course->id, false);
     // Capture the event.
     $events = $sink->get_events();
     $sink->close();
     // Validate the event.
     $event = array_pop($events);
     $this->assertInstanceOf('\\core\\event\\course_content_deleted', $event);
     $this->assertEquals('course', $event->objecttable);
     $this->assertEquals($course->id, $event->objectid);
     $this->assertEquals($coursecontext->id, $event->contextid);
     $this->assertEquals($course, $event->get_record_snapshot('course', $course->id));
     $this->assertEquals('course_content_removed', $event->get_legacy_eventname());
     // The legacy data also passed the context and options in the course object.
     $course->context = $coursecontext;
     $course->options = array();
     $this->assertEventLegacyData($course, $event);
     $this->assertEventContextNotUsed($event);
 }
Example #3
0
/**
 * Delete a course, including all related data from the database, and any associated files.
 *
 * @param mixed $courseorid The id of the course or course object to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseorid, $showfeedback = true)
{
    global $DB;
    if (is_object($courseorid)) {
        $courseid = $courseorid->id;
        $course = $courseorid;
    } else {
        $courseid = $courseorid;
        if (!($course = $DB->get_record('course', array('id' => $courseid)))) {
            return false;
        }
    }
    $context = context_course::instance($courseid);
    // Frontpage course can not be deleted!!
    if ($courseid == SITEID) {
        return false;
    }
    // Allow plugins to use this course before we completely delete it.
    if ($pluginsfunction = get_plugins_with_function('pre_course_delete')) {
        foreach ($pluginsfunction as $plugintype => $plugins) {
            foreach ($plugins as $pluginfunction) {
                $pluginfunction($course);
            }
        }
    }
    // Make the course completely empty.
    remove_course_contents($courseid, $showfeedback);
    // Delete the course and related context instance.
    context_helper::delete_instance(CONTEXT_COURSE, $courseid);
    $DB->delete_records("course", array("id" => $courseid));
    $DB->delete_records("course_format_options", array("courseid" => $courseid));
    // Reset all course related caches here.
    if (class_exists('format_base', false)) {
        format_base::reset_course_cache($courseid);
    }
    // Trigger a course deleted event.
    $event = \core\event\course_deleted::create(array('objectid' => $course->id, 'context' => $context, 'other' => array('shortname' => $course->shortname, 'fullname' => $course->fullname, 'idnumber' => $course->idnumber)));
    $event->add_record_snapshot('course', $course);
    $event->trigger();
    return true;
}
Example #4
0
/**
 * Delete a course, including all related data from the database,
 * and any associated files from the moodledata folder.
 *
 * @param mixed $courseorid The id of the course or course object to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseorid, $showfeedback = true)
{
    global $CFG;
    $result = true;
    if (is_object($courseorid)) {
        $courseid = $courseorid->id;
        $course = $courseorid;
    } else {
        $courseid = $courseorid;
        if (!($course = get_record('course', 'id', $courseid))) {
            return false;
        }
    }
    // frontpage course can not be deleted!!
    if ($courseid == SITEID) {
        return false;
    }
    if (!remove_course_contents($courseid, $showfeedback)) {
        if ($showfeedback) {
            notify("An error occurred while deleting some of the course contents.");
        }
        $result = false;
    }
    if (!delete_records("course", "id", $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the main course record.");
        }
        $result = false;
    }
    /// Delete all roles and overiddes in the course context
    if (!delete_context(CONTEXT_COURSE, $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the main course context.");
        }
        $result = false;
    }
    if (!fulldelete($CFG->dataroot . '/' . $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the course files.");
        }
        $result = false;
    }
    if ($result) {
        //trigger events
        events_trigger('course_deleted', $course);
    }
    return $result;
}
Example #5
0
function restore_execute(&$restore, $info, $course_header, &$errorstr)
{
    global $CFG, $USER;
    $status = true;
    //Checks for the required files/functions to restore every module
    //and include them
    if ($allmods = get_records("modules")) {
        foreach ($allmods as $mod) {
            $modname = $mod->name;
            $modfile = "{$CFG->dirroot}/mod/{$modname}/restorelib.php";
            //If file exists and we have selected to restore that type of module
            if (file_exists($modfile) and !empty($restore->mods[$modname]) and $restore->mods[$modname]->restore) {
                include_once $modfile;
            }
        }
    }
    if (!defined('RESTORE_SILENTLY')) {
        //Start the main table
        echo "<table cellpadding=\"5\">";
        echo "<tr><td>";
        //Start the main ul
        echo "<ul>";
    }
    //Location of the xml file
    $xml_file = $CFG->dataroot . "/temp/backup/" . $restore->backup_unique_code . "/moodle.xml";
    //Preprocess the moodle.xml file spliting into smaller chucks (modules, users, logs...)
    //for optimal parsing later in the restore process.
    if (!empty($CFG->experimentalsplitrestore)) {
        if (!defined('RESTORE_SILENTLY')) {
            echo '<li>' . get_string('preprocessingbackupfile') . '</li>';
        }
        //First of all, split moodle.xml into handy files
        if (!restore_split_xml($xml_file, $restore)) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Error proccessing moodle.xml file. Process ended.");
            } else {
                $errorstr = "Error proccessing moodle.xml file. Process ended.";
            }
            return false;
        }
    }
    //If we've selected to restore into new course
    //create it (course)
    //Saving conversion id variables into backup_tables
    if ($restore->restoreto == RESTORETO_NEW_COURSE) {
        if (!defined('RESTORE_SILENTLY')) {
            echo '<li>' . get_string('creatingnewcourse') . '</li>';
        }
        $oldidnumber = $course_header->course_idnumber;
        if (!($status = restore_create_new_course($restore, $course_header))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Error while creating the new empty course.");
            } else {
                $errorstr = "Error while creating the new empty course.";
                return false;
            }
        }
        //Print course fullname and shortname and category
        if ($status) {
            if (!defined('RESTORE_SILENTLY')) {
                echo "<ul>";
                echo "<li>" . $course_header->course_fullname . " (" . $course_header->course_shortname . ")" . '</li>';
                echo "<li>" . get_string("category") . ": " . $course_header->category->name . '</li>';
                if (!empty($oldidnumber)) {
                    echo "<li>" . get_string("nomoreidnumber", "moodle", $oldidnumber) . "</li>";
                }
                echo "</ul>";
                //Put the destination course_id
            }
            $restore->course_id = $course_header->course_id;
        }
        if ($status = restore_open_html($restore, $course_header)) {
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>Creating the Restorelog.html in the course backup folder</li>";
            }
        }
    } else {
        $course = get_record("course", "id", $restore->course_id);
        if ($course) {
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>" . get_string("usingexistingcourse");
                echo "<ul>";
                echo "<li>" . get_string("from") . ": " . $course_header->course_fullname . " (" . $course_header->course_shortname . ")" . '</li>';
                echo "<li>" . get_string("to") . ": " . format_string($course->fullname) . " (" . format_string($course->shortname) . ")" . '</li>';
                if ($restore->deleting) {
                    echo "<li>" . get_string("deletingexistingcoursedata") . '</li>';
                } else {
                    echo "<li>" . get_string("addingdatatoexisting") . '</li>';
                }
                echo "</ul></li>";
            }
            //If we have selected to restore deleting, we do it now.
            if ($restore->deleting) {
                if (!defined('RESTORE_SILENTLY')) {
                    echo "<li>" . get_string("deletingolddata") . '</li>';
                }
                $status = remove_course_contents($restore->course_id, false) and delete_dir_contents($CFG->dataroot . "/" . $restore->course_id, "backupdata");
                if ($status) {
                    //Now , this situation is equivalent to the "restore to new course" one (we
                    //have a course record and nothing more), so define it as "to new course"
                    $restore->restoreto = RESTORETO_NEW_COURSE;
                } else {
                    if (!defined('RESTORE_SILENTLY')) {
                        notify("An error occurred while deleting some of the course contents.");
                    } else {
                        $errrostr = "An error occurred while deleting some of the course contents.";
                        return false;
                    }
                }
            }
        } else {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Error opening existing course.");
                $status = false;
            } else {
                $errorstr = "Error opening existing course.";
                return false;
            }
        }
    }
    //Now create users as needed
    if ($status and ($restore->users == 0 or $restore->users == 1)) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingusers") . "<br />";
        }
        if (!($status = restore_create_users($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore users.");
            } else {
                $errorstr = "Could not restore users.";
                return false;
            }
        }
        //Now print info about the work done
        if ($status) {
            $recs = get_records_sql("select old_id, new_id from {$CFG->prefix}backup_ids\n                                     where backup_code = '{$restore->backup_unique_code}' and\n                                     table_name = 'user'");
            //We've records
            if ($recs) {
                $new_count = 0;
                $exists_count = 0;
                $student_count = 0;
                $teacher_count = 0;
                $counter = 0;
                //Iterate, filling counters
                foreach ($recs as $rec) {
                    //Get full record, using backup_getids
                    $record = backup_getid($restore->backup_unique_code, "user", $rec->old_id);
                    if (strpos($record->info, "new") !== false) {
                        $new_count++;
                    }
                    if (strpos($record->info, "exists") !== false) {
                        $exists_count++;
                    }
                    if (strpos($record->info, "student") !== false) {
                        $student_count++;
                    } else {
                        if (strpos($record->info, "teacher") !== false) {
                            $teacher_count++;
                        }
                    }
                    //Do some output
                    $counter++;
                    if ($counter % 10 == 0) {
                        if (!defined('RESTORE_SILENTLY')) {
                            echo ".";
                            if ($counter % 200 == 0) {
                                echo "<br />";
                            }
                        }
                        backup_flush(300);
                    }
                }
                if (!defined('RESTORE_SILENTLY')) {
                    //Now print information gathered
                    echo " (" . get_string("new") . ": " . $new_count . ", " . get_string("existing") . ": " . $exists_count . ")";
                    echo "<ul>";
                    echo "<li>" . get_string("students") . ": " . $student_count . '</li>';
                    echo "<li>" . get_string("teachers") . ": " . $teacher_count . '</li>';
                    echo "</ul>";
                }
            } else {
                if (!defined('RESTORE_SILENTLY')) {
                    notify("No users were found!");
                }
                // no need to return false here, it's recoverable.
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo "</li>";
        }
    }
    //Now create groups as needed
    if ($status and ($restore->groups == RESTORE_GROUPS_ONLY or $restore->groups == RESTORE_GROUPS_GROUPINGS)) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatinggroups");
        }
        if (!($status = restore_create_groups($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore groups!");
            } else {
                $errorstr = "Could not restore groups!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create groupings as needed
    if ($status and ($restore->groups == RESTORE_GROUPINGS_ONLY or $restore->groups == RESTORE_GROUPS_GROUPINGS)) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatinggroupings");
        }
        if (!($status = restore_create_groupings($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore groupings!");
            } else {
                $errorstr = "Could not restore groupings!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create groupingsgroups as needed
    if ($status and $restore->groups == RESTORE_GROUPS_GROUPINGS) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatinggroupingsgroups");
        }
        if (!($status = restore_create_groupings_groups($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore groups in groupings!");
            } else {
                $errorstr = "Could not restore groups in groupings!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create the course_sections and their associated course_modules
    //we have to do this after groups and groupings are restored, because we need the new groupings id
    if ($status) {
        //Into new course
        if ($restore->restoreto == RESTORETO_NEW_COURSE) {
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>" . get_string("creatingsections");
            }
            if (!($status = restore_create_sections($restore, $xml_file))) {
                if (!defined('RESTORE_SILENTLY')) {
                    notify("Error creating sections in the existing course.");
                } else {
                    $errorstr = "Error creating sections in the existing course.";
                    return false;
                }
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
            //Into existing course
        } else {
            if ($restore->restoreto != RESTORETO_NEW_COURSE) {
                if (!defined('RESTORE_SILENTLY')) {
                    echo "<li>" . get_string("checkingsections");
                }
                if (!($status = restore_create_sections($restore, $xml_file))) {
                    if (!defined('RESTORE_SILENTLY')) {
                        notify("Error creating sections in the existing course.");
                    } else {
                        $errorstr = "Error creating sections in the existing course.";
                        return false;
                    }
                }
                if (!defined('RESTORE_SILENTLY')) {
                    echo '</li>';
                }
                //Error
            } else {
                if (!defined('RESTORE_SILENTLY')) {
                    notify("Neither a new course or an existing one was specified.");
                    $status = false;
                } else {
                    $errorstr = "Neither a new course or an existing one was specified.";
                    return false;
                }
            }
        }
    }
    //Now create metacourse info
    if ($status and $restore->metacourse) {
        //Only to new courses!
        if ($restore->restoreto == RESTORETO_NEW_COURSE) {
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>" . get_string("creatingmetacoursedata");
            }
            if (!($status = restore_create_metacourse($restore, $xml_file))) {
                if (!defined('RESTORE_SILENTLY')) {
                    notify("Error creating metacourse in the course.");
                } else {
                    $errorstr = "Error creating metacourse in the course.";
                    return false;
                }
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
        }
    }
    //Now create categories and questions as needed
    if ($status) {
        include_once "{$CFG->dirroot}/question/restorelib.php";
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingcategoriesandquestions");
            echo "<ul>";
        }
        if (!($status = restore_create_questions($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore categories and questions!");
            } else {
                $errorstr = "Could not restore categories and questions!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo "</ul></li>";
        }
    }
    //Now create user_files as needed
    if ($status and $restore->user_files) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("copyinguserfiles");
        }
        if (!($status = restore_user_files($restore))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore user files!");
            } else {
                $errorstr = "Could not restore user files!";
                return false;
            }
        }
        //If all is ok (and we have a counter)
        if ($status and $status !== true) {
            //Inform about user dirs created from backup
            if (!defined('RESTORE_SILENTLY')) {
                echo "<ul>";
                echo "<li>" . get_string("userzones") . ": " . $status;
                echo "</li></ul>";
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create course files as needed
    if ($status and $restore->course_files) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("copyingcoursefiles");
        }
        if (!($status = restore_course_files($restore))) {
            if (empty($status)) {
                notify("Could not restore course files!");
            } else {
                $errorstr = "Could not restore course files!";
                return false;
            }
        }
        //If all is ok (and we have a counter)
        if ($status and $status !== true) {
            //Inform about user dirs created from backup
            if (!defined('RESTORE_SILENTLY')) {
                echo "<ul>";
                echo "<li>" . get_string("filesfolders") . ": " . $status . '</li>';
                echo "</ul>";
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo "</li>";
        }
    }
    //Now create site files as needed
    if ($status and $restore->site_files) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string('copyingsitefiles');
        }
        if (!($status = restore_site_files($restore))) {
            if (empty($status)) {
                notify("Could not restore site files!");
            } else {
                $errorstr = "Could not restore site files!";
                return false;
            }
        }
        //If all is ok (and we have a counter)
        if ($status and $status !== true) {
            //Inform about user dirs created from backup
            if (!defined('RESTORE_SILENTLY')) {
                echo "<ul>";
                echo "<li>" . get_string("filesfolders") . ": " . $status . '</li>';
                echo "</ul>";
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo "</li>";
        }
    }
    //Now create messages as needed
    if ($status and $restore->messages) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingmessagesinfo");
        }
        if (!($status = restore_create_messages($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore messages!");
            } else {
                $errorstr = "Could not restore messages!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo "</li>";
        }
    }
    //Now create blogs as needed
    if ($status and $restore->blogs) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingblogsinfo");
        }
        if (!($status = restore_create_blogs($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore blogs!");
            } else {
                $errorstr = "Could not restore blogs!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo "</li>";
        }
    }
    //Now create scales as needed
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingscales");
        }
        if (!($status = restore_create_scales($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore custom scales!");
            } else {
                $errorstr = "Could not restore custom scales!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create events as needed
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingevents");
        }
        if (!($status = restore_create_events($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore course events!");
            } else {
                $errorstr = "Could not restore course events!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create course modules as needed
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatingcoursemodules");
        }
        if (!($status = restore_create_modules($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore modules!");
            } else {
                $errorstr = "Could not restore modules!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Bring back the course blocks -- do it AFTER the modules!!!
    if ($status) {
        //If we are deleting and bringing into a course or making a new course, same situation
        if ($restore->restoreto == RESTORETO_CURRENT_DELETING || $restore->restoreto == RESTORETO_EXISTING_DELETING || $restore->restoreto == RESTORETO_NEW_COURSE) {
            if (!defined('RESTORE_SILENTLY')) {
                echo '<li>' . get_string('creatingblocks');
            }
            $course_header->blockinfo = !empty($course_header->blockinfo) ? $course_header->blockinfo : NULL;
            if (!($status = restore_create_blocks($restore, $info->backup_block_format, $course_header->blockinfo, $xml_file))) {
                if (!defined('RESTORE_SILENTLY')) {
                    notify('Error while creating the course blocks');
                } else {
                    $errorstr = "Error while creating the course blocks";
                    return false;
                }
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
        }
    }
    if ($status) {
        //If we are deleting and bringing into a course or making a new course, same situation
        if ($restore->restoreto == RESTORETO_CURRENT_DELETING || $restore->restoreto == RESTORETO_EXISTING_DELETING || $restore->restoreto == RESTORETO_NEW_COURSE) {
            if (!defined('RESTORE_SILENTLY')) {
                echo '<li>' . get_string('courseformatdata');
            }
            if (!($status = restore_set_format_data($restore, $xml_file))) {
                $error = "Error while setting the course format data";
                if (!defined('RESTORE_SILENTLY')) {
                    notify($error);
                } else {
                    $errorstr = $error;
                    return false;
                }
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
        }
    }
    //Now create log entries as needed
    if ($status and $restore->logs) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("creatinglogentries");
        }
        if (!($status = restore_create_logs($restore, $xml_file))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not restore logs!");
            } else {
                $errorstr = "Could not restore logs!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now, if all is OK, adjust the instance field in course_modules !!
    //this also calculates the final modinfo information so, after this,
    //code needing it can be used (like role_assignments. MDL-13740)
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("checkinginstances");
        }
        if (!($status = restore_check_instances($restore))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not adjust instances in course_modules!");
            } else {
                $errorstr = "Could not adjust instances in course_modules!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now, if all is OK, adjust activity events
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("refreshingevents");
        }
        if (!($status = restore_refresh_events($restore))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not refresh events for activities!");
            } else {
                $errorstr = "Could not refresh events for activities!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now, if all is OK, adjust inter-activity links
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("decodinginternallinks");
        }
        if (!($status = restore_decode_content_links($restore))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not decode content links!");
            } else {
                $errorstr = "Could not decode content links!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now, with backup files prior to version 2005041100,
    //convert all the wiki texts in the course to markdown
    if ($status && $restore->backup_version < 2005041100) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("convertingwikitomarkdown");
        }
        if (!($status = restore_convert_wiki2markdown($restore))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not convert wiki texts to markdown!");
            } else {
                $errorstr = "Could not convert wiki texts to markdown!";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Now create gradebook as needed -- AFTER modules and blocks!!!
    if ($status) {
        if ($restore->backup_version > 2007090500) {
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>" . get_string("creatinggradebook");
            }
            if (!($status = restore_create_gradebook($restore, $xml_file))) {
                if (!defined('RESTORE_SILENTLY')) {
                    notify("Could not restore gradebook!");
                } else {
                    $errorstr = "Could not restore gradebook!";
                    return false;
                }
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
        } else {
            // for moodle versions before 1.9, those grades need to be converted to use the new gradebook
            // this code needs to execute *after* the course_modules are sorted out
            if (!defined('RESTORE_SILENTLY')) {
                echo "<li>" . get_string("migratinggrades");
            }
            /// force full refresh of grading data before migration == crete all items first
            if (!($status = restore_migrate_old_gradebook($restore, $xml_file))) {
                if (!defined('RESTORE_SILENTLY')) {
                    notify("Could not migrate gradebook!");
                } else {
                    $errorstr = "Could not migrade gradebook!";
                    return false;
                }
            }
            if (!defined('RESTORE_SILENTLY')) {
                echo '</li>';
            }
        }
        /// force full refresh of grading data after all items are created
        grade_force_full_regrading($restore->course_id);
        grade_grab_course_grades($restore->course_id);
    }
    /*******************************************************************************
     ************* Restore of Roles and Capabilities happens here ******************
     *******************************************************************************/
    // try to restore roles even when restore is going to fail - teachers might have
    // at least some role assigned - this is not correct though
    $status = restore_create_roles($restore, $xml_file) && $status;
    $status = restore_roles_settings($restore, $xml_file) && $status;
    //Now if all is OK, update:
    //   - course modinfo field
    //   - categories table
    //   - add user as teacher
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("checkingcourse");
        }
        //categories table
        $course = get_record("course", "id", $restore->course_id);
        fix_course_sortorder();
        // Check if the user has course update capability in the newly restored course
        // there is no need to load his capabilities again, because restore_roles_settings
        // would have loaded it anyway, if there is any assignments.
        // fix for MDL-6831
        $newcontext = get_context_instance(CONTEXT_COURSE, $restore->course_id);
        if (!has_capability('moodle/course:manageactivities', $newcontext)) {
            // fix for MDL-9065, use the new config setting if exists
            if ($CFG->creatornewroleid) {
                role_assign($CFG->creatornewroleid, $USER->id, 0, $newcontext->id);
            } else {
                if ($legacyteachers = get_roles_with_capability('moodle/legacy:editingteacher', CAP_ALLOW, get_context_instance(CONTEXT_SYSTEM))) {
                    if ($legacyteacher = array_shift($legacyteachers)) {
                        role_assign($legacyteacher->id, $USER->id, 0, $newcontext->id);
                    }
                } else {
                    notify('Could not find a legacy teacher role. You might need your moodle admin to assign a role with editing privilages to this course.');
                }
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    //Cleanup temps (files and db)
    if ($status) {
        if (!defined('RESTORE_SILENTLY')) {
            echo "<li>" . get_string("cleaningtempdata");
        }
        if (!($status = clean_temp_data($restore))) {
            if (!defined('RESTORE_SILENTLY')) {
                notify("Could not clean up temporary data from files and database");
            } else {
                $errorstr = "Could not clean up temporary data from files and database";
                return false;
            }
        }
        if (!defined('RESTORE_SILENTLY')) {
            echo '</li>';
        }
    }
    // this is not a critical check - the result can be ignored
    if (restore_close_html($restore)) {
        if (!defined('RESTORE_SILENTLY')) {
            echo '<li>Closing the Restorelog.html file.</li>';
        }
    } else {
        if (!defined('RESTORE_SILENTLY')) {
            notify("Could not close the restorelog.html file");
        }
    }
    if (!defined('RESTORE_SILENTLY')) {
        //End the main ul
        echo "</ul>";
        //End the main table
        echo "</td></tr>";
        echo "</table>";
    }
    return $status;
}
/**
 * Delete a course, including all related data from the database, and any associated files.
 *
 * @param mixed $courseorid The id of the course or course object to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseorid, $showfeedback = true)
{
    global $DB;
    if (is_object($courseorid)) {
        $courseid = $courseorid->id;
        $course = $courseorid;
    } else {
        $courseid = $courseorid;
        if (!($course = $DB->get_record('course', array('id' => $courseid)))) {
            return false;
        }
    }
    $context = context_course::instance($courseid);
    // Frontpage course can not be deleted!!
    if ($courseid == SITEID) {
        return false;
    }
    // Make the course completely empty.
    remove_course_contents($courseid, $showfeedback);
    // Delete the course and related context instance.
    context_helper::delete_instance(CONTEXT_COURSE, $courseid);
    $DB->delete_records("course", array("id" => $courseid));
    $DB->delete_records("course_format_options", array("courseid" => $courseid));
    // Trigger a course deleted event.
    $event = \core\event\course_deleted::create(array('objectid' => $course->id, 'context' => $context, 'other' => array('shortname' => $course->shortname, 'fullname' => $course->fullname, 'idnumber' => $course->idnumber)));
    $event->add_record_snapshot('course', $course);
    $event->trigger();
    return true;
}
Example #7
0
/**
 * Delete a course, including all related data from the database,
 * and any associated files.
 *
 * @global object
 * @global object
 * @param mixed $courseorid The id of the course or course object to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseorid, $showfeedback = true)
{
    global $DB;
    if (is_object($courseorid)) {
        $courseid = $courseorid->id;
        $course = $courseorid;
    } else {
        $courseid = $courseorid;
        if (!($course = $DB->get_record('course', array('id' => $courseid)))) {
            return false;
        }
    }
    $context = get_context_instance(CONTEXT_COURSE, $courseid);
    // frontpage course can not be deleted!!
    if ($courseid == SITEID) {
        return false;
    }
    // make the course completely empty
    remove_course_contents($courseid, $showfeedback);
    // delete the course and related context instance
    delete_context(CONTEXT_COURSE, $courseid);
    $DB->delete_records("course", array("id" => $courseid));
    //trigger events
    $course->context = $context;
    // you can not fetch context in the event because it was already deleted
    events_trigger('course_deleted', $course);
    return true;
}
Example #8
0
 /**
  * Deletes all of the content associated with the given course (courseid)
  * @param int $courseid
  * @param array $options
  * @return bool True for success
  */
 public static function delete_course_content($courseid, array $options = null)
 {
     return remove_course_contents($courseid, false, $options);
 }
Example #9
0
/**
 * Delete a course, including all related data from the database,
 * and any associated files.
 *
 * @global object
 * @global object
 * @param mixed $courseorid The id of the course or course object to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseorid, $showfeedback = true)
{
    global $DB;
    if (is_object($courseorid)) {
        $courseid = $courseorid->id;
        $course = $courseorid;
    } else {
        $courseid = $courseorid;
        if (!($course = $DB->get_record('course', array('id' => $courseid)))) {
            return false;
        }
    }
    $context = get_context_instance(CONTEXT_COURSE, $courseid);
    // frontpage course can not be deleted!!
    if ($courseid == SITEID) {
        return false;
    }
    // make the course completely empty
    remove_course_contents($courseid, $showfeedback);
    // delete the course and related context instance
    delete_context(CONTEXT_COURSE, $courseid);
    // We will update the course's timemodified, as it will be passed to the course_deleted event,
    // which should know about this updated property, as this event is meant to pass the full course record
    $course->timemodified = time();
    $DB->delete_records("course", array("id" => $courseid));
    //trigger events
    $course->context = $context;
    // you can not fetch context in the event because it was already deleted
    events_trigger('course_deleted', $course);
    return true;
}
/**
 * Duplicate a course
 *
 * @param int $courseid
 * @param string $fullname Duplicated course fullname
 * @param int $newcourse Destination course
 * @param array $options List of backup options
 * @return stdClass New course info
 */
function local_ltiprovider_duplicate_course($courseid, $newcourse, $visible = 1, $options = array(), $useridcreating = null, $context)
{
    global $CFG, $USER, $DB;
    require_once $CFG->dirroot . '/backup/util/includes/backup_includes.php';
    require_once $CFG->dirroot . '/backup/util/includes/restore_includes.php';
    if (empty($USER)) {
        // Emulate session.
        cron_setup_user();
    }
    // Context validation.
    if (!($course = $DB->get_record('course', array('id' => $courseid)))) {
        throw new moodle_exception('invalidcourseid', 'error');
    }
    $removeoptions = array();
    $removeoptions['keep_roles_and_enrolments'] = true;
    $removeoptions['keep_groups_and_groupings'] = true;
    remove_course_contents($newcourse->id, false, $removeoptions);
    $backupdefaults = array('activities' => 1, 'blocks' => 1, 'filters' => 1, 'users' => 0, 'role_assignments' => 0, 'comments' => 0, 'userscompletion' => 0, 'logs' => 0, 'grade_histories' => 0);
    $backupsettings = array();
    // Check for backup and restore options.
    if (!empty($options)) {
        foreach ($options as $option) {
            // Strict check for a correct value (allways 1 or 0, true or false).
            $value = clean_param($option['value'], PARAM_INT);
            if ($value !== 0 and $value !== 1) {
                throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
            }
            if (!isset($backupdefaults[$option['name']])) {
                throw new moodle_exception('invalidextparam', 'webservice', '', $option['name']);
            }
            $backupsettings[$option['name']] = $value;
        }
    }
    // Backup the course.
    $admin = get_admin();
    $bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $admin->id);
    foreach ($backupsettings as $name => $value) {
        $bc->get_plan()->get_setting($name)->set_value($value);
    }
    $backupid = $bc->get_backupid();
    $backupbasepath = $bc->get_plan()->get_basepath();
    $bc->execute_plan();
    $results = $bc->get_results();
    $file = $results['backup_destination'];
    $bc->destroy();
    // Restore the backup immediately.
    // Check if we need to unzip the file because the backup temp dir does not contains backup files.
    if (!file_exists($backupbasepath . "/moodle_backup.xml")) {
        $file->extract_to_pathname(get_file_packer(), $backupbasepath);
    }
    $rc = new restore_controller($backupid, $newcourse->id, backup::INTERACTIVE_NO, backup::MODE_SAMESITE, $admin->id, backup::TARGET_CURRENT_DELETING);
    foreach ($backupsettings as $name => $value) {
        $setting = $rc->get_plan()->get_setting($name);
        if ($setting->get_status() == backup_setting::NOT_LOCKED) {
            $setting->set_value($value);
        }
    }
    if (!$rc->execute_precheck()) {
        $precheckresults = $rc->get_precheck_results();
        if (is_array($precheckresults) && !empty($precheckresults['errors'])) {
            if (empty($CFG->keeptempdirectoriesonbackup)) {
                fulldelete($backupbasepath);
            }
            $errorinfo = '';
            foreach ($precheckresults['errors'] as $error) {
                $errorinfo .= $error;
            }
            if (array_key_exists('warnings', $precheckresults)) {
                foreach ($precheckresults['warnings'] as $warning) {
                    $errorinfo .= $warning;
                }
            }
            throw new moodle_exception('backupprecheckerrors', 'webservice', '', $errorinfo);
        }
    }
    $rc->execute_plan();
    $rc->destroy();
    $course = $DB->get_record('course', array('id' => $newcourse->id), '*', MUST_EXIST);
    $course->visible = $visible;
    $course->fullname = $newcourse->fullname;
    $course->shortname = $newcourse->shortname;
    $course->idnumber = $newcourse->idnumber;
    // Set shortname and fullname back.
    $DB->update_record('course', $course);
    if (empty($CFG->keeptempdirectoriesonbackup)) {
        fulldelete($backupbasepath);
    }
    // Delete the course backup file created by this WebService. Originally located in the course backups area.
    $file->delete();
    // We have to unenroll all the user except the one that create the course.
    if (get_config('local_ltiprovider', 'duplicatecourseswithoutusers') and $useridcreating) {
        require_once $CFG->dirroot . '/group/lib.php';
        // Previous to unenrol users, we assign some type of activities to the user that created the course.
        if ($user = $DB->get_record('user', array('id' => $useridcreating))) {
            if ($databases = $DB->get_records('data', array('course' => $course->id))) {
                foreach ($databases as $data) {
                    $DB->execute("UPDATE {data_records} SET userid = ? WHERE dataid = ?", array($user->id, $data->id));
                }
            }
            if ($glossaries = $DB->get_records('glossary', array('course' => $course->id))) {
                foreach ($glossaries as $glossary) {
                    $DB->execute("UPDATE {glossary_entries} SET userid = ? WHERE glossaryid = ?", array($user->id, $glossary->id));
                }
            }
            // Same for questions.
            $newcoursecontextid = context_course::instance($course->id);
            if ($qcategories = $DB->get_records('question_categories', array('contextid' => $newcoursecontextid->id))) {
                foreach ($qcategories as $qcategory) {
                    $DB->execute("UPDATE {question} SET createdby = ?, modifiedby = ? WHERE category = ?", array($user->id, $user->id, $qcategory->id));
                }
            }
            // Enrol the user.
            if ($tool = $DB->get_record('local_ltiprovider', array('contextid' => $newcoursecontextid->id))) {
                $roles = explode(',', strtolower($context->info['roles']));
                local_ltiprovider_enrol_user($tool, $user, $roles, true);
            }
            // Now, we unenrol all the users except the one who created the course.
            $plugins = enrol_get_plugins(true);
            $instances = enrol_get_instances($course->id, true);
            foreach ($instances as $key => $instance) {
                if (!isset($plugins[$instance->enrol])) {
                    unset($instances[$key]);
                    continue;
                }
            }
            $sql = "SELECT ue.*\n                          FROM {user_enrolments} ue\n                          JOIN {enrol} e ON (e.id = ue.enrolid AND e.courseid = :courseid)\n                          JOIN {context} c ON (c.contextlevel = :courselevel AND c.instanceid = e.courseid)";
            $params = array('courseid' => $course->id, 'courselevel' => CONTEXT_COURSE);
            $rs = $DB->get_recordset_sql($sql, $params);
            foreach ($rs as $ue) {
                if ($ue->userid == $user->id) {
                    continue;
                }
                if (!isset($instances[$ue->enrolid])) {
                    continue;
                }
                $instance = $instances[$ue->enrolid];
                $plugin = $plugins[$instance->enrol];
                if (!$plugin->allow_unenrol($instance) and !$plugin->allow_unenrol_user($instance, $ue)) {
                    continue;
                }
                $plugin->unenrol_user($instance, $ue->userid);
            }
            $rs->close();
            groups_delete_group_members($course->id);
            groups_delete_groups($course->id, false);
            groups_delete_groupings_groups($course->id, false);
            groups_delete_groupings($course->id, false);
        }
    }
    return $course;
}
 /**
  * Test that triggering a course_content_deleted event works as expected.
  */
 public function test_course_content_deleted_event()
 {
     global $DB;
     $this->resetAfterTest();
     // Create the course.
     $course = $this->getDataGenerator()->create_course();
     // Get the course from the DB. The data generator adds some extra properties, such as
     // numsections, to the course object which will fail the assertions later on.
     $course = $DB->get_record('course', array('id' => $course->id), '*', MUST_EXIST);
     // Save the course context before we delete the course.
     $coursecontext = context_course::instance($course->id);
     // Catch the update event.
     $sink = $this->redirectEvents();
     // Call remove_course_contents() which will trigger the course_content_deleted event.
     // This function prints out data to the screen, which we do not want during a PHPUnit
     // test, so use ob_start and ob_end_clean to prevent this.
     ob_start();
     remove_course_contents($course->id);
     ob_end_clean();
     // Capture the event.
     $events = $sink->get_events();
     $sink->close();
     // Validate the event.
     $event = $events[0];
     $this->assertInstanceOf('\\core\\event\\course_content_deleted', $event);
     $this->assertEquals('course', $event->objecttable);
     $this->assertEquals($course->id, $event->objectid);
     $this->assertEquals($coursecontext->id, $event->contextid);
     $this->assertEquals($course, $event->get_record_snapshot('course', $course->id));
     $this->assertEquals('course_content_removed', $event->get_legacy_eventname());
     // The legacy data also passed the context and options in the course object.
     $course->context = $coursecontext;
     $course->options = array();
     $this->assertEventLegacyData($course, $event);
 }
Example #12
0
/**
 * Delete a course, including all related data from the database,
 * and any associated files from the moodledata folder.
 *
 * @param int $courseid The id of the course to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseid, $showfeedback = true)
{
    global $CFG;
    require_once $CFG->libdir . '/gradelib.php';
    $result = true;
    if (!remove_course_contents($courseid, $showfeedback)) {
        if ($showfeedback) {
            notify("An error occurred while deleting some of the course contents.");
        }
        $result = false;
    }
    remove_course_grades($courseid, $showfeedback);
    if (!delete_records("course", "id", $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the main course record.");
        }
        $result = false;
    }
    if (!delete_records('context', 'contextlevel', CONTEXT_COURSE, 'instanceid', $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the main context record.");
        }
        $result = false;
    }
    if (!fulldelete($CFG->dataroot . '/' . $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the course files.");
        }
        $result = false;
    }
    return $result;
}
Example #13
0
/**
 * Delete a course, including all related data from the database,
 * and any associated files from the moodledata folder.
 *
 * @param int $courseid The id of the course to delete.
 * @param bool $showfeedback Whether to display notifications of each action the function performs.
 * @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 delete_course($courseid, $showfeedback = true)
{
    global $CFG;
    require_once $CFG->libdir . '/gradelib.php';
    $result = true;
    // frontpage course can not be deleted!!
    if ($courseid == SITEID) {
        return false;
    }
    $context = get_context_instance(CONTEXT_COURSE, $courseid);
    if (!remove_course_contents($courseid, $showfeedback)) {
        if ($showfeedback) {
            notify("An error occurred while deleting some of the course contents.");
        }
        $result = false;
    }
    remove_course_grades($courseid, $showfeedback);
    remove_grade_letters($context, $showfeedback);
    if (!delete_records("course", "id", $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the main course record.");
        }
        $result = false;
    }
    /// Delete all roles and overiddes in the course context
    if (!delete_context(CONTEXT_COURSE, $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the main course context.");
        }
        $result = false;
    }
    if (!fulldelete($CFG->dataroot . '/' . $courseid)) {
        if ($showfeedback) {
            notify("An error occurred while deleting the course files.");
        }
        $result = false;
    }
    return $result;
}
 /**
  * Deletes all of the content associated with the given course (courseid)
  * @param int $courseid
  * @return bool True for success
  */
 public static function delete_course_content($courseid)
 {
     return remove_course_contents($courseid, false);
 }