Merge branch 'MDL-13114-master' of git://github.com/FMCorz/moodle
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing the base import form.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
/**
|
||||
* Base import form.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_base_form extends moodleform {
|
||||
|
||||
/**
|
||||
* Empty definition.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function definition() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the import settings part.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function add_import_options() {
|
||||
$mform = $this->_form;
|
||||
|
||||
// Upload settings and file.
|
||||
$mform->addElement('header', 'importoptionshdr', get_string('importoptions', 'tool_uploadcourse'));
|
||||
$mform->setExpanded('importoptionshdr', true);
|
||||
|
||||
$choices = array(
|
||||
tool_uploadcourse_processor::MODE_CREATE_NEW => get_string('createnew', 'tool_uploadcourse'),
|
||||
tool_uploadcourse_processor::MODE_CREATE_ALL => get_string('createall', 'tool_uploadcourse'),
|
||||
tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE => get_string('createorupdate', 'tool_uploadcourse'),
|
||||
tool_uploadcourse_processor::MODE_UPDATE_ONLY => get_string('updateonly', 'tool_uploadcourse')
|
||||
);
|
||||
$mform->addElement('select', 'options[mode]', get_string('mode', 'tool_uploadcourse'), $choices);
|
||||
|
||||
$choices = array(
|
||||
tool_uploadcourse_processor::UPDATE_NOTHING => get_string('nochanges', 'tool_uploadcourse'),
|
||||
tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY => get_string('updatewithdataonly', 'tool_uploadcourse'),
|
||||
tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS =>
|
||||
get_string('updatewithdataordefaults', 'tool_uploadcourse'),
|
||||
tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS => get_string('updatemissing', 'tool_uploadcourse')
|
||||
);
|
||||
$mform->addElement('select', 'options[updatemode]', get_string('updatemode', 'tool_uploadcourse'), $choices);
|
||||
$mform->setDefault('options[updatemode]', tool_uploadcourse_processor::UPDATE_NOTHING);
|
||||
$mform->disabledIf('options[updatemode]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$mform->disabledIf('options[updatemode]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
|
||||
$mform->addElement('selectyesno', 'options[allowdeletes]', get_string('allowdeletes', 'tool_uploadcourse'));
|
||||
$mform->setDefault('options[allowdeletes]', 0);
|
||||
$mform->disabledIf('options[allowdeletes]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$mform->disabledIf('options[allowdeletes]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
|
||||
$mform->addElement('selectyesno', 'options[allowrenames]', get_string('allowrenames', 'tool_uploadcourse'));
|
||||
$mform->setDefault('options[allowrenames]', 0);
|
||||
$mform->disabledIf('options[allowrenames]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$mform->disabledIf('options[allowrenames]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
|
||||
$mform->addElement('selectyesno', 'options[allowresets]', get_string('allowresets', 'tool_uploadcourse'));
|
||||
$mform->setDefault('options[allowresets]', 0);
|
||||
$mform->disabledIf('options[allowresets]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$mform->disabledIf('options[allowresets]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,898 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing the course class.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
|
||||
/**
|
||||
* Course class.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_course {
|
||||
|
||||
/** Outcome of the process: creating the course */
|
||||
const DO_CREATE = 1;
|
||||
|
||||
/** Outcome of the process: updating the course */
|
||||
const DO_UPDATE = 2;
|
||||
|
||||
/** Outcome of the process: deleting the course */
|
||||
const DO_DELETE = 3;
|
||||
|
||||
/** @var array final import data. */
|
||||
protected $data = array();
|
||||
|
||||
/** @var array default values. */
|
||||
protected $defaults = array();
|
||||
|
||||
/** @var array enrolment data. */
|
||||
protected $enrolmentdata;
|
||||
|
||||
/** @var array errors. */
|
||||
protected $errors = array();
|
||||
|
||||
/** @var int the ID of the course that had been processed. */
|
||||
protected $id;
|
||||
|
||||
/** @var array containing options passed from the processor. */
|
||||
protected $importoptions = array();
|
||||
|
||||
/** @var int import mode. Matches tool_uploadcourse_processor::MODE_* */
|
||||
protected $mode;
|
||||
|
||||
/** @var array course import options. */
|
||||
protected $options = array();
|
||||
|
||||
/** @var int constant value of self::DO_*, what to do with that course */
|
||||
protected $do;
|
||||
|
||||
/** @var bool set to true once we have prepared the course */
|
||||
protected $prepared = false;
|
||||
|
||||
/** @var bool set to true once we have started the process of the course */
|
||||
protected $processstarted = false;
|
||||
|
||||
/** @var array course import data. */
|
||||
protected $rawdata = array();
|
||||
|
||||
/** @var array restore directory. */
|
||||
protected $restoredata;
|
||||
|
||||
/** @var string course shortname. */
|
||||
protected $shortname;
|
||||
|
||||
/** @var array errors. */
|
||||
protected $statuses = array();
|
||||
|
||||
/** @var int update mode. Matches tool_uploadcourse_processor::UPDATE_* */
|
||||
protected $updatemode;
|
||||
|
||||
/** @var array fields allowed as course data. */
|
||||
static protected $validfields = array('fullname', 'shortname', 'idnumber', 'category', 'visible', 'startdate',
|
||||
'summary', 'format', 'theme', 'lang', 'newsitems', 'showgrades', 'showreports', 'legacyfiles', 'maxbytes',
|
||||
'groupmode', 'groupmodeforce', 'groupmodeforce', 'enablecompletion');
|
||||
|
||||
/** @var array fields required on course creation. */
|
||||
static protected $mandatoryfields = array('fullname', 'category');
|
||||
|
||||
/** @var array fields which are considered as options. */
|
||||
static protected $optionfields = array('delete' => false, 'rename' => null, 'backupfile' => null,
|
||||
'templatecourse' => null, 'reset' => false);
|
||||
|
||||
/** @var array options determining what can or cannot be done at an import level. */
|
||||
static protected $importoptionsdefaults = array('canrename' => false, 'candelete' => false, 'canreset' => false,
|
||||
'reset' => false, 'restoredir' => null, 'shortnametemplate' => null);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param int $mode import mode, constant matching tool_uploadcourse_processor::MODE_*
|
||||
* @param int $updatemode update mode, constant matching tool_uploadcourse_processor::UPDATE_*
|
||||
* @param array $rawdata raw course data.
|
||||
* @param array $defaults default course data.
|
||||
* @param array $importoptions import options.
|
||||
*/
|
||||
public function __construct($mode, $updatemode, $rawdata, $defaults = array(), $importoptions = array()) {
|
||||
|
||||
if ($mode !== tool_uploadcourse_processor::MODE_CREATE_NEW &&
|
||||
$mode !== tool_uploadcourse_processor::MODE_CREATE_ALL &&
|
||||
$mode !== tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE &&
|
||||
$mode !== tool_uploadcourse_processor::MODE_UPDATE_ONLY) {
|
||||
throw new coding_exception('Incorrect mode.');
|
||||
} else if ($updatemode !== tool_uploadcourse_processor::UPDATE_NOTHING &&
|
||||
$updatemode !== tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY &&
|
||||
$updatemode !== tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS &&
|
||||
$updatemode !== tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS) {
|
||||
throw new coding_exception('Incorrect update mode.');
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->updatemode = $updatemode;
|
||||
|
||||
if (isset($rawdata['shortname'])) {
|
||||
$this->shortname = $rawdata['shortname'];
|
||||
}
|
||||
$this->rawdata = $rawdata;
|
||||
$this->defaults = $defaults;
|
||||
|
||||
// Extract course options.
|
||||
foreach (self::$optionfields as $option => $default) {
|
||||
$this->options[$option] = isset($rawdata[$option]) ? $rawdata[$option] : $default;
|
||||
}
|
||||
|
||||
// Import options.
|
||||
foreach (self::$importoptionsdefaults as $option => $default) {
|
||||
$this->importoptions[$option] = isset($importoptions[$option]) ? $importoptions[$option] : $default;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the mode allow for course creation?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_create() {
|
||||
return in_array($this->mode, array(tool_uploadcourse_processor::MODE_CREATE_ALL,
|
||||
tool_uploadcourse_processor::MODE_CREATE_NEW,
|
||||
tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the mode allow for course deletion?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_delete() {
|
||||
return $this->importoptions['candelete'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the mode only allow for course creation?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_only_create() {
|
||||
return in_array($this->mode, array(tool_uploadcourse_processor::MODE_CREATE_ALL,
|
||||
tool_uploadcourse_processor::MODE_CREATE_NEW));
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the mode allow for course rename?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_rename() {
|
||||
return $this->importoptions['canrename'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the mode allow for course reset?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_reset() {
|
||||
return $this->importoptions['canreset'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the mode allow for course update?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_update() {
|
||||
return in_array($this->mode,
|
||||
array(
|
||||
tool_uploadcourse_processor::MODE_UPDATE_ONLY,
|
||||
tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE)
|
||||
) && $this->updatemode != tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can we use default values?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function can_use_defaults() {
|
||||
return in_array($this->updatemode, array(tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS,
|
||||
tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the current course.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function delete() {
|
||||
global $DB;
|
||||
$this->id = $DB->get_field_select('course', 'id', 'shortname = :shortname',
|
||||
array('shortname' => $this->shortname), MUST_EXIST);
|
||||
return delete_course($this->id, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log an error
|
||||
*
|
||||
* @param string $code error code.
|
||||
* @param lang_string $message error message.
|
||||
* @return void
|
||||
*/
|
||||
protected function error($code, lang_string $message) {
|
||||
if (array_key_exists($code, $this->errors)) {
|
||||
throw new coding_exception('Error code already defined');
|
||||
}
|
||||
$this->errors[$code] = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether the course exists or not.
|
||||
*
|
||||
* @param string $shortname the shortname to use to check if the course exists. Falls back on $this->shortname if empty.
|
||||
* @return bool
|
||||
*/
|
||||
protected function exists($shortname = null) {
|
||||
global $DB;
|
||||
if (is_null($shortname)) {
|
||||
$shortname = $this->shortname;
|
||||
}
|
||||
if (!empty($shortname) || is_numeric($shortname)) {
|
||||
return $DB->record_exists('course', array('shortname' => $shortname));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data that will be used upon saving.
|
||||
*
|
||||
* @return null|array
|
||||
*/
|
||||
public function get_data() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the errors found during preparation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble the course data based on defaults.
|
||||
*
|
||||
* This returns the final data to be passed to create_course().
|
||||
*
|
||||
* @param array $data current data.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_final_create_data($data) {
|
||||
foreach (self::$validfields as $field) {
|
||||
if (!isset($data[$field]) && isset($this->defaults[$field])) {
|
||||
$data[$field] = $this->defaults[$field];
|
||||
}
|
||||
}
|
||||
$data['shortname'] = $this->shortname;
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assemble the course data based on defaults.
|
||||
*
|
||||
* This returns the final data to be passed to update_course().
|
||||
*
|
||||
* @param array $data current data.
|
||||
* @param bool $usedefaults are defaults allowed?
|
||||
* @param bool $missingonly ignore fields which are already set.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_final_update_data($data, $usedefaults = false, $missingonly = false) {
|
||||
global $DB;
|
||||
$newdata = array();
|
||||
$existingdata = $DB->get_record('course', array('shortname' => $this->shortname));
|
||||
foreach (self::$validfields as $field) {
|
||||
if ($missingonly) {
|
||||
if (!is_null($existingdata->$field) and $existingdata->$field !== '') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (isset($data[$field])) {
|
||||
$newdata[$field] = $data[$field];
|
||||
} else if ($usedefaults && isset($this->defaults[$field])) {
|
||||
$newdata[$field] = $this->defaults[$field];
|
||||
}
|
||||
}
|
||||
$newdata['id'] = $existingdata->id;
|
||||
return $newdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ID of the processed course.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function get_id() {
|
||||
if (!$this->processstarted) {
|
||||
throw new coding_exception('The course has not been processed yet!');
|
||||
}
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the directory of the object to restore.
|
||||
*
|
||||
* @return string|false subdirectory in $CFG->tempdir/backup/...
|
||||
*/
|
||||
protected function get_restore_content_dir() {
|
||||
$backupfile = null;
|
||||
$shortname = null;
|
||||
|
||||
if (!empty($this->options['backupfile'])) {
|
||||
$backupfile = $this->options['backupfile'];
|
||||
} else if (!empty($this->options['templatecourse']) || is_numeric($this->options['templatecourse'])) {
|
||||
$shortname = $this->options['templatecourse'];
|
||||
}
|
||||
|
||||
$errors = array();
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir($backupfile, $shortname, $errors);
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $key => $message) {
|
||||
$this->error($key, $message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($dir) && !empty($this->importoptions['restoredir'])) {
|
||||
$dir = $this->importoptions['restoredir'];
|
||||
}
|
||||
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the errors found during preparation.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_statuses() {
|
||||
return $this->statuses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether there were errors with this course.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function has_errors() {
|
||||
return !empty($this->errors);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and prepares the data.
|
||||
*
|
||||
* @return bool false is any error occured.
|
||||
*/
|
||||
public function prepare() {
|
||||
global $DB;
|
||||
$this->prepared = true;
|
||||
|
||||
// Validate the shortname.
|
||||
if (!empty($this->shortname) || is_numeric($this->shortname)) {
|
||||
if ($this->shortname !== clean_param($this->shortname, PARAM_TEXT)) {
|
||||
$this->error('invalidshortname', new lang_string('invalidshortname', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$exists = $this->exists();
|
||||
|
||||
// Do we want to delete the course?
|
||||
if ($this->options['delete']) {
|
||||
if (!$exists) {
|
||||
$this->error('cannotdeletecoursenotexist', new lang_string('cannotdeletecoursenotexist', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if (!$this->can_delete()) {
|
||||
$this->error('coursedeletionnotallowed', new lang_string('coursedeletionnotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->do = self::DO_DELETE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Can we create/update the course under those conditions?
|
||||
if ($exists) {
|
||||
if ($this->mode === tool_uploadcourse_processor::MODE_CREATE_NEW) {
|
||||
$this->error('courseexistsanduploadnotallowed',
|
||||
new lang_string('courseexistsanduploadnotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (!$this->can_create()) {
|
||||
$this->error('coursedoesnotexistandcreatenotallowed',
|
||||
new lang_string('coursedoesnotexistandcreatenotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Basic data.
|
||||
$coursedata = array();
|
||||
foreach ($this->rawdata as $field => $value) {
|
||||
if (!in_array($field, self::$validfields)) {
|
||||
continue;
|
||||
} else if ($field == 'shortname') {
|
||||
// Let's leave it apart from now, use $this->shortname only.
|
||||
continue;
|
||||
}
|
||||
$coursedata[$field] = $value;
|
||||
}
|
||||
|
||||
$mode = $this->mode;
|
||||
$updatemode = $this->updatemode;
|
||||
$usedefaults = $this->can_use_defaults();
|
||||
|
||||
// Resolve the category, and fail if not found.
|
||||
$errors = array();
|
||||
$catid = tool_uploadcourse_helper::resolve_category($this->rawdata, $errors);
|
||||
if (empty($errors)) {
|
||||
$coursedata['category'] = $catid;
|
||||
} else {
|
||||
foreach ($errors as $key => $message) {
|
||||
$this->error($key, $message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the course does not exist, or will be forced created.
|
||||
if (!$exists || $mode === tool_uploadcourse_processor::MODE_CREATE_ALL) {
|
||||
|
||||
// Mandatory fields upon creation.
|
||||
$errors = array();
|
||||
foreach (self::$mandatoryfields as $field) {
|
||||
if ((!isset($coursedata[$field]) || $coursedata[$field] === '') &&
|
||||
(!isset($this->defaults[$field]) || $this->defaults[$field] === '')) {
|
||||
$errors[] = $field;
|
||||
}
|
||||
}
|
||||
if (!empty($errors)) {
|
||||
$this->error('missingmandatoryfields', new lang_string('missingmandatoryfields', 'tool_uploadcourse',
|
||||
implode(', ', $errors)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Should the course be renamed?
|
||||
if (!empty($this->options['rename']) || is_numeric($this->options['rename'])) {
|
||||
if (!$this->can_update()) {
|
||||
$this->error('canonlyrenameinupdatemode', new lang_string('canonlyrenameinupdatemode', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if (!$exists) {
|
||||
$this->error('cannotrenamecoursenotexist', new lang_string('cannotrenamecoursenotexist', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if (!$this->can_rename()) {
|
||||
$this->error('courserenamingnotallowed', new lang_string('courserenamingnotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if ($this->options['rename'] !== clean_param($this->options['rename'], PARAM_TEXT)) {
|
||||
$this->error('invalidshortname', new lang_string('invalidshortname', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if ($this->exists($this->options['rename'])) {
|
||||
$this->error('cannotrenameshortnamealreadyinuse',
|
||||
new lang_string('cannotrenameshortnamealreadyinuse', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if (isset($coursedata['idnumber']) &&
|
||||
$DB->count_records_select('course', 'idnumber = :idn AND shortname != :sn',
|
||||
array('idn' => $coursedata['idnumber'], 'sn' => $this->shortname)) > 0) {
|
||||
$this->error('cannotrenameidnumberconflict', new lang_string('cannotrenameidnumberconflict', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
$coursedata['shortname'] = $this->options['rename'];
|
||||
$this->status('courserenamed', new lang_string('courserenamed', 'tool_uploadcourse',
|
||||
array('from' => $this->shortname, 'to' => $coursedata['shortname'])));
|
||||
}
|
||||
|
||||
// Should we generate a shortname?
|
||||
if (empty($this->shortname) && !is_numeric($this->shortname)) {
|
||||
if (empty($this->importoptions['shortnametemplate'])) {
|
||||
$this->error('missingshortnamenotemplate', new lang_string('missingshortnamenotemplate', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if (!$this->can_only_create()) {
|
||||
$this->error('cannotgenerateshortnameupdatemode',
|
||||
new lang_string('cannotgenerateshortnameupdatemode', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else {
|
||||
$newshortname = tool_uploadcourse_helper::generate_shortname($coursedata,
|
||||
$this->importoptions['shortnametemplate']);
|
||||
if (is_null($newshortname)) {
|
||||
$this->error('generatedshortnameinvalid', new lang_string('generatedshortnameinvalid', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if ($this->exists($newshortname)) {
|
||||
if ($mode === tool_uploadcourse_processor::MODE_CREATE_NEW) {
|
||||
$this->error('generatedshortnamealreadyinuse',
|
||||
new lang_string('generatedshortnamealreadyinuse', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
$exists = true;
|
||||
}
|
||||
$this->status('courseshortnamegenerated', new lang_string('courseshortnamegenerated', 'tool_uploadcourse',
|
||||
$newshortname));
|
||||
$this->shortname = $newshortname;
|
||||
}
|
||||
}
|
||||
|
||||
// If exists, but we only want to create courses, increment the shortname.
|
||||
if ($exists && $mode === tool_uploadcourse_processor::MODE_CREATE_ALL) {
|
||||
$original = $this->shortname;
|
||||
$this->shortname = tool_uploadcourse_helper::increment_shortname($this->shortname);
|
||||
$exists = false;
|
||||
if ($this->shortname != $original) {
|
||||
$this->status('courseshortnameincremented', new lang_string('courseshortnameincremented', 'tool_uploadcourse',
|
||||
array('from' => $original, 'to' => $this->shortname)));
|
||||
if (isset($coursedata['idnumber'])) {
|
||||
$originalidn = $coursedata['idnumber'];
|
||||
$coursedata['idnumber'] = tool_uploadcourse_helper::increment_idnumber($coursedata['idnumber']);
|
||||
if ($originalidn != $coursedata['idnumber']) {
|
||||
$this->status('courseidnumberincremented', new lang_string('courseidnumberincremented', 'tool_uploadcourse',
|
||||
array('from' => $originalidn, 'to' => $coursedata['idnumber'])));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the course does not exist, ensure that the ID number is not taken.
|
||||
if (!$exists && isset($coursedata['idnumber'])) {
|
||||
if ($DB->count_records_select('course', 'idnumber = :idn', array('idn' => $coursedata['idnumber'])) > 0) {
|
||||
$this->error('idnumberalreadyinuse', new lang_string('idnumberalreadyinuse', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ultimate check mode vs. existence.
|
||||
switch ($mode) {
|
||||
case tool_uploadcourse_processor::MODE_CREATE_NEW:
|
||||
case tool_uploadcourse_processor::MODE_CREATE_ALL:
|
||||
if ($exists) {
|
||||
$this->error('courseexistsanduploadnotallowed',
|
||||
new lang_string('courseexistsanduploadnotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case tool_uploadcourse_processor::MODE_UPDATE_ONLY:
|
||||
if (!$exists) {
|
||||
$this->error('coursedoesnotexistandcreatenotallowed',
|
||||
new lang_string('coursedoesnotexistandcreatenotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
// No break!
|
||||
case tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE:
|
||||
if ($exists) {
|
||||
if ($updatemode === tool_uploadcourse_processor::UPDATE_NOTHING) {
|
||||
$this->error('updatemodedoessettonothing',
|
||||
new lang_string('updatemodedoessettonothing', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// O_o Huh?! This should really never happen here!
|
||||
$this->error('unknownimportmode', new lang_string('unknownimportmode', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get final data.
|
||||
if ($exists) {
|
||||
$missingonly = ($updatemode === tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS);
|
||||
$coursedata = $this->get_final_update_data($coursedata, $usedefaults, $missingonly);
|
||||
$this->do = self::DO_UPDATE;
|
||||
} else {
|
||||
$coursedata = $this->get_final_create_data($coursedata);
|
||||
$this->do = self::DO_CREATE;
|
||||
}
|
||||
|
||||
// Course start date.
|
||||
if (!empty($coursedata['startdate'])) {
|
||||
$coursedata['startdate'] = strtotime($coursedata['startdate']);
|
||||
}
|
||||
|
||||
// Add role renaming.
|
||||
$errors = array();
|
||||
$rolenames = tool_uploadcourse_helper::get_role_names($this->rawdata, $errors);
|
||||
if (!empty($errors)) {
|
||||
foreach ($errors as $key => $message) {
|
||||
$this->error($key, $message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
foreach ($rolenames as $rolekey => $rolename) {
|
||||
$coursedata[$rolekey] = $rolename;
|
||||
}
|
||||
|
||||
// Some validation.
|
||||
if (!empty($coursedata['format']) && !in_array($coursedata['format'], tool_uploadcourse_helper::get_course_formats())) {
|
||||
$this->error('invalidcourseformat', new lang_string('invalidcourseformat', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Saving data.
|
||||
$this->data = $coursedata;
|
||||
$this->enrolmentdata = tool_uploadcourse_helper::get_enrolment_data($this->rawdata);
|
||||
|
||||
// Restore data.
|
||||
// TODO log warnings.
|
||||
$this->restoredata = $this->get_restore_content_dir();
|
||||
|
||||
// We can only reset courses when allowed and we are updating the course.
|
||||
if ($this->importoptions['reset'] || $this->options['reset']) {
|
||||
if ($this->do !== self::DO_UPDATE) {
|
||||
$this->error('canonlyresetcourseinupdatemode',
|
||||
new lang_string('canonlyresetcourseinupdatemode', 'tool_uploadcourse'));
|
||||
return false;
|
||||
} else if (!$this->can_reset()) {
|
||||
$this->error('courseresetnotallowed', new lang_string('courseresetnotallowed', 'tool_uploadcourse'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proceed with the import of the course.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function proceed() {
|
||||
global $CFG, $USER;
|
||||
|
||||
if (!$this->prepared) {
|
||||
throw new coding_exception('The course has not been prepared.');
|
||||
} else if ($this->has_errors()) {
|
||||
throw new moodle_exception('Cannot proceed, errors were detected.');
|
||||
} else if ($this->processstarted) {
|
||||
throw new coding_exception('The process has already been started.');
|
||||
}
|
||||
$this->processstarted = true;
|
||||
|
||||
if ($this->do === self::DO_DELETE) {
|
||||
if ($this->delete()) {
|
||||
$this->status('coursedeleted', new lang_string('coursedeleted', 'tool_uploadcourse'));
|
||||
} else {
|
||||
$this->error('errorwhiledeletingcourse', new lang_string('errorwhiledeletingcourse', 'tool_uploadcourse'));
|
||||
}
|
||||
return true;
|
||||
} else if ($this->do === self::DO_CREATE) {
|
||||
$course = create_course((object) $this->data);
|
||||
$this->id = $course->id;
|
||||
$this->status('coursecreated', new lang_string('coursecreated', 'tool_uploadcourse'));
|
||||
} else if ($this->do === self::DO_UPDATE) {
|
||||
$course = (object) $this->data;
|
||||
update_course($course);
|
||||
$this->id = $course->id;
|
||||
$this->status('courseupdated', new lang_string('courseupdated', 'tool_uploadcourse'));
|
||||
} else {
|
||||
// Strangely the outcome has not been defined, or is unknown!
|
||||
throw new coding_exception('Unknown outcome!');
|
||||
}
|
||||
|
||||
// Restore a course.
|
||||
if (!empty($this->restoredata)) {
|
||||
$rc = new restore_controller($this->restoredata, $course->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_IMPORT, $USER->id, backup::TARGET_CURRENT_ADDING);
|
||||
|
||||
// Check if the format conversion must happen first.
|
||||
if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
|
||||
$rc->convert();
|
||||
}
|
||||
if ($rc->execute_precheck()) {
|
||||
$rc->execute_plan();
|
||||
$this->status('courserestored', new lang_string('courserestored', 'tool_uploadcourse'));
|
||||
} else {
|
||||
$this->error('errorwhilerestoringcourse', new lang_string('errorwhilerestoringthecourse', 'tool_uploadcourse'));
|
||||
}
|
||||
$rc->destroy();
|
||||
}
|
||||
|
||||
// Proceed with enrolment data.
|
||||
$this->process_enrolment_data($course);
|
||||
|
||||
// Reset the course.
|
||||
if ($this->importoptions['reset'] || $this->options['reset']) {
|
||||
if ($this->do === self::DO_UPDATE && $this->can_reset()) {
|
||||
$this->reset($course);
|
||||
$this->status('coursereset', new lang_string('coursereset', 'tool_uploadcourse'));
|
||||
}
|
||||
}
|
||||
|
||||
// Mark context as dirty.
|
||||
$context = context_course::instance($course->id);
|
||||
$context->mark_dirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the enrolment data for the course.
|
||||
*
|
||||
* @param object $course course record.
|
||||
* @return void
|
||||
*/
|
||||
protected function process_enrolment_data($course) {
|
||||
global $DB;
|
||||
|
||||
$enrolmentdata = $this->enrolmentdata;
|
||||
if (empty($enrolmentdata)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$enrolmentplugins = tool_uploadcourse_helper::get_enrolment_plugins();
|
||||
$instances = enrol_get_instances($course->id, false);
|
||||
foreach ($enrolmentdata as $enrolmethod => $method) {
|
||||
|
||||
$instance = null;
|
||||
foreach ($instances as $i) {
|
||||
if ($i->enrol == $enrolmethod) {
|
||||
$instance = $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$todelete = isset($method['delete']) && $method['delete'];
|
||||
$todisable = isset($method['disable']) && $method['disable'];
|
||||
unset($method['delete']);
|
||||
unset($method['disable']);
|
||||
|
||||
if (!empty($instance) && $todelete) {
|
||||
// Remove the enrolment method.
|
||||
foreach ($instances as $instance) {
|
||||
if ($instance->enrol == $enrolmethod) {
|
||||
$plugin = $enrolmentplugins[$instance->enrol];
|
||||
$plugin->delete_instance($instance);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (!empty($instance) && $todisable) {
|
||||
// Disable the enrolment.
|
||||
foreach ($instances as $instance) {
|
||||
if ($instance->enrol == $enrolmethod) {
|
||||
$plugin = $enrolmentplugins[$instance->enrol];
|
||||
$plugin->update_status($instance, ENROL_INSTANCE_DISABLED);
|
||||
$enrol_updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$plugin = null;
|
||||
if (empty($instance)) {
|
||||
$plugin = $enrolmentplugins[$enrolmethod];
|
||||
$instance = new stdClass();
|
||||
$instance->id = $plugin->add_default_instance($course);
|
||||
$instance->roleid = $plugin->get_config('roleid');
|
||||
$instance->status = ENROL_INSTANCE_ENABLED;
|
||||
} else {
|
||||
$plugin = $enrolmentplugins[$instance->enrol];
|
||||
$plugin->update_status($instance, ENROL_INSTANCE_ENABLED);
|
||||
}
|
||||
|
||||
// Now update values.
|
||||
foreach ($method as $k => $v) {
|
||||
$instance->{$k} = $v;
|
||||
}
|
||||
|
||||
// Sort out the start, end and date.
|
||||
$instance->enrolstartdate = (isset($method['startdate']) ? strtotime($method['startdate']) : 0);
|
||||
$instance->enrolenddate = (isset($method['enddate']) ? strtotime($method['enddate']) : 0);
|
||||
|
||||
// Is the enrolment period set?
|
||||
if (isset($method['enrolperiod']) && ! empty($method['enrolperiod'])) {
|
||||
if (preg_match('/^\d+$/', $method['enrolperiod'])) {
|
||||
$method['enrolperiod'] = (int) $method['enrolperiod'];
|
||||
} else {
|
||||
// Try and convert period to seconds.
|
||||
$method['enrolperiod'] = strtotime('1970-01-01 GMT + ' . $method['enrolperiod']);
|
||||
}
|
||||
$instance->enrolperiod = $method['enrolperiod'];
|
||||
}
|
||||
if ($instance->enrolstartdate > 0 && isset($method['enrolperiod'])) {
|
||||
$instance->enrolenddate = $instance->enrolstartdate + $method['enrolperiod'];
|
||||
}
|
||||
if ($instance->enrolenddate > 0) {
|
||||
$instance->enrolperiod = $instance->enrolenddate - $instance->enrolstartdate;
|
||||
}
|
||||
if ($instance->enrolenddate < $instance->enrolstartdate) {
|
||||
$instance->enrolenddate = $instance->enrolstartdate;
|
||||
}
|
||||
|
||||
// Sort out the given role. This does not filter the roles allowed in the course.
|
||||
if (isset($method['role'])) {
|
||||
$roleids = tool_uploadcourse_helper::get_role_ids();
|
||||
if (isset($roleids[$method['role']])) {
|
||||
$instance->roleid = $roleids[$method['role']];
|
||||
}
|
||||
}
|
||||
|
||||
$instance->timemodified = time();
|
||||
$DB->update_record('enrol', $instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current course.
|
||||
*
|
||||
* This does not reset any of the content of the activities.
|
||||
*
|
||||
* @param stdClass $course the course object of the course to reset.
|
||||
* @return array status array of array component, item, error.
|
||||
*/
|
||||
protected function reset($course) {
|
||||
global $DB;
|
||||
|
||||
$resetdata = new stdClass();
|
||||
$resetdata->id = $course->id;
|
||||
$resetdata->reset_start_date = time();
|
||||
$resetdata->reset_logs = true;
|
||||
$resetdata->reset_events = true;
|
||||
$resetdata->reset_notes = true;
|
||||
$resetdata->delete_blog_associations = true;
|
||||
$resetdata->reset_completion = true;
|
||||
$resetdata->reset_roles_overrides = true;
|
||||
$resetdata->reset_roles_local = true;
|
||||
$resetdata->reset_groups_members = true;
|
||||
$resetdata->reset_groups_remove = true;
|
||||
$resetdata->reset_groupings_members = true;
|
||||
$resetdata->reset_groupings_remove = true;
|
||||
$resetdata->reset_gradebook_items = true;
|
||||
$resetdata->reset_gradebook_grades = true;
|
||||
$resetdata->reset_comments = true;
|
||||
|
||||
if (empty($course->startdate)) {
|
||||
$course->startdate = $DB->get_field_select('course', 'startdate', 'id = :id', array('id' => $course->id));
|
||||
}
|
||||
$resetdata->reset_start_date_old = $course->startdate;
|
||||
|
||||
// Add roles.
|
||||
$roles = tool_uploadcourse_helper::get_role_ids();
|
||||
$resetdata->unenrol_users = array_values($roles);
|
||||
$resetdata->unenrol_users[] = 0; // Enrolled without role.
|
||||
|
||||
return reset_course_userdata($resetdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log a status
|
||||
*
|
||||
* @param string $code status code.
|
||||
* @param lang_string $message status message.
|
||||
* @return void
|
||||
*/
|
||||
protected function status($code, lang_string $message) {
|
||||
if (array_key_exists($code, $this->statuses)) {
|
||||
throw new coding_exception('Status code already defined');
|
||||
}
|
||||
$this->statuses[$code] = $message;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,486 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing the helper class.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir . '/coursecatlib.php');
|
||||
require_once($CFG->dirroot . '/cache/lib.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
|
||||
/**
|
||||
* Class containing a set of helpers.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_helper {
|
||||
|
||||
/**
|
||||
* Remove the restore content from disk and cache.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function clean_restore_content() {
|
||||
global $CFG;
|
||||
if (!empty($CFG->keeptempdirectoriesonbackup)) {
|
||||
$cache = cache::make('tool_uploadcourse', 'helper');
|
||||
$backupids = (array) $cache->get('backupids');
|
||||
foreach ($backupids as $cachekey => $backupid) {
|
||||
$cache->delete($cachekey);
|
||||
fulldelete("$CFG->tempdir/backup/$backupid/");
|
||||
}
|
||||
$cache->delete('backupids');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a shortname based on a template.
|
||||
*
|
||||
* @param array|object $data course data.
|
||||
* @param string $templateshortname template of shortname.
|
||||
* @return null|string shortname based on the template, or null when an error occured.
|
||||
*/
|
||||
public static function generate_shortname($data, $templateshortname) {
|
||||
if (empty($templateshortname) && !is_numeric($templateshortname)) {
|
||||
return null;
|
||||
}
|
||||
if (strpos($templateshortname, '%') === false) {
|
||||
return $templateshortname;
|
||||
}
|
||||
|
||||
$course = (object) $data;
|
||||
$fullname = isset($course->fullname) ? $course->fullname : '';
|
||||
$idnumber = isset($course->idnumber) ? $course->idnumber : '';
|
||||
|
||||
$callback = partial(array('tool_uploadcourse_helper', 'generate_shortname_callback'), $fullname, $idnumber);
|
||||
$result = preg_replace_callback('/(?<!%)%([+~-])?(\d)*([fi])/', $callback, $templateshortname);
|
||||
|
||||
if (!is_null($result)) {
|
||||
$result = clean_param($result, PARAM_TEXT);
|
||||
}
|
||||
|
||||
if (empty($result) && !is_numeric($result)) {
|
||||
$result = null;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback used when generating a shortname based on a template.
|
||||
*
|
||||
* @param string $fullname full name.
|
||||
* @param string $idnumber ID number.
|
||||
* @param array $block result from preg_replace_callback.
|
||||
* @return string
|
||||
*/
|
||||
public static function generate_shortname_callback($fullname, $idnumber, $block) {
|
||||
switch ($block[3]) {
|
||||
case 'f':
|
||||
$repl = $fullname;
|
||||
break;
|
||||
case 'i':
|
||||
$repl = $idnumber;
|
||||
break;
|
||||
default:
|
||||
return $block[0];
|
||||
}
|
||||
|
||||
switch ($block[1]) {
|
||||
case '+':
|
||||
$repl = textlib::strtoupper($repl);
|
||||
break;
|
||||
case '-':
|
||||
$repl = textlib::strtolower($repl);
|
||||
break;
|
||||
case '~':
|
||||
$repl = textlib::strtotitle($repl);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($block[2])) {
|
||||
$repl = textlib::substr($repl, 0, $block[2]);
|
||||
}
|
||||
|
||||
return $repl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the available course formats.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_course_formats() {
|
||||
return array_keys(core_component::get_plugin_list('format'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract enrolment data from passed data.
|
||||
*
|
||||
* Constructs an array of methods, and their options:
|
||||
* array(
|
||||
* 'method1' => array(
|
||||
* 'option1' => value,
|
||||
* 'option2' => value
|
||||
* ),
|
||||
* 'method2' => array(
|
||||
* 'option1' => value,
|
||||
* 'option2' => value
|
||||
* )
|
||||
* )
|
||||
*
|
||||
* @param array $data data to extract the enrolment data from.
|
||||
* @return array
|
||||
*/
|
||||
public static function get_enrolment_data($data) {
|
||||
$enrolmethods = array();
|
||||
$enroloptions = array();
|
||||
foreach ($data as $field => $value) {
|
||||
|
||||
// Enrolmnent data.
|
||||
$matches = array();
|
||||
if (preg_match('/^enrolment_(\d+)(_(.+))?$/', $field, $matches)) {
|
||||
$key = $matches[1];
|
||||
if (!isset($enroloptions[$key])) {
|
||||
$enroloptions[$key] = array();
|
||||
}
|
||||
if (empty($matches[3])) {
|
||||
$enrolmethods[$key] = $value;
|
||||
} else {
|
||||
$enroloptions[$key][$matches[3]] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Combining enrolment methods and their options in a single array.
|
||||
$enrolmentdata = array();
|
||||
if (!empty($enrolmethods)) {
|
||||
$enrolmentplugins = self::get_enrolment_plugins();
|
||||
foreach ($enrolmethods as $key => $method) {
|
||||
if (!array_key_exists($method, $enrolmentplugins)) {
|
||||
// Error!
|
||||
continue;
|
||||
}
|
||||
$enrolmentdata[$enrolmethods[$key]] = $enroloptions[$key];
|
||||
}
|
||||
}
|
||||
return $enrolmentdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the enrolment plugins.
|
||||
*
|
||||
* The result is cached for faster execution.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_enrolment_plugins() {
|
||||
$cache = cache::make('tool_uploadcourse', 'helper');
|
||||
if (($enrol = $cache->get('enrol')) === false) {
|
||||
$enrol = enrol_get_plugins(false);
|
||||
$cache->set('enrol', $enrol);
|
||||
}
|
||||
return $enrol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restore content tempdir.
|
||||
*
|
||||
* The tempdir is the sub directory in which the backup has been extracted.
|
||||
* This caches the result for better performance.
|
||||
*
|
||||
* @param string $backupfile path to a backup file.
|
||||
* @param string $shortname shortname of a course.
|
||||
* @param array $errors will be populated with errors found.
|
||||
* @return string|false false when the backup couldn't retrieved.
|
||||
*/
|
||||
public static function get_restore_content_dir($backupfile = null, $shortname = null, &$errors = array()) {
|
||||
global $CFG, $DB, $USER;
|
||||
|
||||
$cachekey = null;
|
||||
if (!empty($backupfile)) {
|
||||
$backupfile = realpath($backupfile);
|
||||
$cachekey = 'backup_path:' . $backupfile;
|
||||
} else if (!empty($shortname) || is_numeric($shortname)) {
|
||||
$cachekey = 'backup_sn:' . $shortname;
|
||||
}
|
||||
|
||||
if (empty($cachekey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$cache = cache::make('tool_uploadcourse', 'helper');
|
||||
if (($backupid = $cache->get($cachekey)) === false) {
|
||||
// Use false instead of null because it would consider that the cache
|
||||
// key has not been set.
|
||||
$backupid = false;
|
||||
if (!empty($backupfile)) {
|
||||
if (!is_readable($backupfile)) {
|
||||
$errors['cannotreadbackupfile'] = new lang_string('cannotreadbackupfile', 'tool_uploadcourse');
|
||||
} else {
|
||||
// Extracting the backup file.
|
||||
$packer = get_file_packer('application/vnd.moodle.backup');
|
||||
$backupid = restore_controller::get_tempdir_name(SITEID, $USER->id);
|
||||
$path = "$CFG->tempdir/backup/$backupid/";
|
||||
$result = $packer->extract_to_pathname($backupfile, $path);
|
||||
if (!$result) {
|
||||
$errors['invalidbackupfile'] = new lang_string('invalidbackupfile', 'tool_uploadcourse');
|
||||
}
|
||||
}
|
||||
} else if (!empty($shortname) || is_numeric($shortname)) {
|
||||
// Creating restore from an existing course.
|
||||
$courseid = $DB->get_field('course', 'id', array('shortname' => $shortname), IGNORE_MISSING);
|
||||
if (!empty($courseid)) {
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $courseid, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $USER->id);
|
||||
$bc->execute_plan();
|
||||
$backupid = $bc->get_backupid();
|
||||
$bc->destroy();
|
||||
} else {
|
||||
$errors['coursetorestorefromdoesnotexist'] =
|
||||
new lang_string('coursetorestorefromdoesnotexist', 'tool_uploadcourse');
|
||||
}
|
||||
}
|
||||
$cache->set($cachekey, $backupid);
|
||||
|
||||
// Store all the directories to be able to remove them in self::clean_restore_content().
|
||||
$backupids = (array) $cache->get('backupids');
|
||||
$backupids[$cachekey] = $backupid;
|
||||
$cache->set('backupids', $backupids);
|
||||
}
|
||||
|
||||
return $backupid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the role IDs.
|
||||
*
|
||||
* The result is cached for faster execution.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_role_ids() {
|
||||
$cache = cache::make('tool_uploadcourse', 'helper');
|
||||
if (($roles = $cache->get('roles')) === false) {
|
||||
$roles = array();
|
||||
$rolesraw = get_all_roles();
|
||||
foreach ($rolesraw as $role) {
|
||||
$roles[$role->shortname] = $role->id;
|
||||
}
|
||||
$cache->set('roles', $roles);
|
||||
}
|
||||
return $roles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the role renaming data from the passed data.
|
||||
*
|
||||
* @param array $data data to extract the names from.
|
||||
* @param array $errors will be populated with errors found.
|
||||
* @return array where the key is the role_<id>, the value is the new name.
|
||||
*/
|
||||
public static function get_role_names($data, &$errors = array()) {
|
||||
$rolenames = array();
|
||||
$rolesids = self::get_role_ids();
|
||||
$invalidroles = array();
|
||||
foreach ($data as $field => $value) {
|
||||
|
||||
$matches = array();
|
||||
if (preg_match('/^role_(.+)?$/', $field, $matches)) {
|
||||
if (!isset($rolesids[$matches[1]])) {
|
||||
$invalidroles[] = $matches[1];
|
||||
continue;
|
||||
}
|
||||
$rolenames['role_' . $rolesids[$matches[1]]] = $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (!empty($invalidroles)) {
|
||||
$errors['invalidroles'] = new lang_string('invalidroles', 'tool_uploadcourse', implode(', ', $invalidroles));
|
||||
}
|
||||
|
||||
// Roles names.
|
||||
return $rolenames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to increment an ID number.
|
||||
*
|
||||
* This first checks if the ID number is in use.
|
||||
*
|
||||
* @param string $idnumber ID number to increment.
|
||||
* @return string new ID number.
|
||||
*/
|
||||
public static function increment_idnumber($idnumber) {
|
||||
global $DB;
|
||||
while ($DB->record_exists('course', array('idnumber' => $idnumber))) {
|
||||
$matches = array();
|
||||
if (!preg_match('/(.*?)([0-9]+)$/', $idnumber, $matches)) {
|
||||
$newidnumber = $idnumber . '_2';
|
||||
} else {
|
||||
$newidnumber = $matches[1] . ((int) $matches[2] + 1);
|
||||
}
|
||||
$idnumber = $newidnumber;
|
||||
}
|
||||
return $idnumber;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to increment a shortname.
|
||||
*
|
||||
* This considers that the shortname passed has to be incremented.
|
||||
*
|
||||
* @param string $shortname shortname to increment.
|
||||
* @return string new shortname.
|
||||
*/
|
||||
public static function increment_shortname($shortname) {
|
||||
global $DB;
|
||||
do {
|
||||
$matches = array();
|
||||
if (!preg_match('/(.*?)([0-9]+)$/', $shortname, $matches)) {
|
||||
$newshortname = $shortname . '_2';
|
||||
} else {
|
||||
$newshortname = $matches[1] . ($matches[2]+1);
|
||||
}
|
||||
$shortname = $newshortname;
|
||||
} while ($DB->record_exists('course', array('shortname' => $shortname)));
|
||||
return $shortname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a category based on the data passed.
|
||||
*
|
||||
* Key accepted are:
|
||||
* - category, which is supposed to be a category ID.
|
||||
* - category_idnumber
|
||||
* - category_path, array of categories from parent to child.
|
||||
*
|
||||
* @param array $data to resolve the category from.
|
||||
* @param array $errors will be populated with errors found.
|
||||
* @return int category ID.
|
||||
*/
|
||||
public static function resolve_category($data, &$errors = array()) {
|
||||
$catid = null;
|
||||
|
||||
if (!empty($data['category'])) {
|
||||
$category = coursecat::get((int) $data['category'], IGNORE_MISSING);
|
||||
if (!empty($category) && !empty($category->id)) {
|
||||
$catid = $category->id;
|
||||
} else {
|
||||
$errors['couldnotresolvecatgorybyid'] =
|
||||
new lang_string('couldnotresolvecatgorybyid', 'tool_uploadcourse');
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($catid) && !empty($data['category_idnumber'])) {
|
||||
$catid = self::resolve_category_by_idnumber($data['category_idnumber']);
|
||||
if (empty($catid)) {
|
||||
$errors['couldnotresolvecatgorybyidnumber'] =
|
||||
new lang_string('couldnotresolvecatgorybyidnumber', 'tool_uploadcourse');
|
||||
}
|
||||
}
|
||||
if (empty($catid) && !empty($data['category_path'])) {
|
||||
$catid = self::resolve_category_by_path(explode(' / ', $data['category_path']));
|
||||
if (empty($catid)) {
|
||||
$errors['couldnotresolvecatgorybypath'] =
|
||||
new lang_string('couldnotresolvecatgorybypath', 'tool_uploadcourse');
|
||||
}
|
||||
}
|
||||
|
||||
return $catid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a category by ID number.
|
||||
*
|
||||
* @param string $idnumber category ID number.
|
||||
* @return int category ID.
|
||||
*/
|
||||
public static function resolve_category_by_idnumber($idnumber) {
|
||||
global $DB;
|
||||
$cache = cache::make('tool_uploadcourse', 'helper');
|
||||
$cachekey = 'cat_idn_' . $idnumber;
|
||||
if (($id = $cache->get($cachekey)) === false) {
|
||||
$params = array('idnumber' => $idnumber);
|
||||
$id = $DB->get_field_select('course_categories', 'id', 'idnumber = :idnumber', $params, IGNORE_MISSING);
|
||||
|
||||
// Little hack to be able to differenciate between the cache not set and a category not found.
|
||||
if ($id === false) {
|
||||
$id = -1;
|
||||
}
|
||||
|
||||
$cache->set($cachekey, $id);
|
||||
}
|
||||
|
||||
// Little hack to be able to differenciate between the cache not set and a category not found.
|
||||
if ($id == -1) {
|
||||
$id = false;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a category by path.
|
||||
*
|
||||
* @param array $path category names indexed from parent to children.
|
||||
* @return int category ID.
|
||||
*/
|
||||
public static function resolve_category_by_path(array $path) {
|
||||
global $DB;
|
||||
$cache = cache::make('tool_uploadcourse', 'helper');
|
||||
$cachekey = 'cat_path_' . serialize($path);
|
||||
if (($id = $cache->get($cachekey)) === false) {
|
||||
$parent = 0;
|
||||
$sql = 'name = :name AND parent = :parent';
|
||||
while ($name = array_shift($path)) {
|
||||
$params = array('name' => $name, 'parent' => $parent);
|
||||
if ($records = $DB->get_records_select('course_categories', $sql, $params, null, 'id, parent')) {
|
||||
if (count($records) > 1) {
|
||||
// Too many records with the same name!
|
||||
$id = -1;
|
||||
break;
|
||||
}
|
||||
$record = reset($records);
|
||||
$id = $record->id;
|
||||
$parent = $record->id;
|
||||
} else {
|
||||
// Not found.
|
||||
$id = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$cache->set($cachekey, $id);
|
||||
}
|
||||
|
||||
// We save -1 when the category has not been found to be able to know if the cache was set.
|
||||
if ($id == -1) {
|
||||
$id = false;
|
||||
}
|
||||
return $id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing processor class.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir . '/csvlib.class.php');
|
||||
|
||||
/**
|
||||
* Processor class.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_processor {
|
||||
|
||||
/**
|
||||
* Create courses that do not exist yet.
|
||||
*/
|
||||
const MODE_CREATE_NEW = 1;
|
||||
|
||||
/**
|
||||
* Create all courses, appending a suffix to the shortname if the course exists.
|
||||
*/
|
||||
const MODE_CREATE_ALL = 2;
|
||||
|
||||
/**
|
||||
* Create courses, and update the ones that already exist.
|
||||
*/
|
||||
const MODE_CREATE_OR_UPDATE = 3;
|
||||
|
||||
/**
|
||||
* Only update existing courses.
|
||||
*/
|
||||
const MODE_UPDATE_ONLY = 4;
|
||||
|
||||
/**
|
||||
* During update, do not update anything... O_o Huh?!
|
||||
*/
|
||||
const UPDATE_NOTHING = 0;
|
||||
|
||||
/**
|
||||
* During update, only use data passed from the CSV.
|
||||
*/
|
||||
const UPDATE_ALL_WITH_DATA_ONLY = 1;
|
||||
|
||||
/**
|
||||
* During update, use either data from the CSV, or defaults.
|
||||
*/
|
||||
const UPDATE_ALL_WITH_DATA_OR_DEFAUTLS = 2;
|
||||
|
||||
/**
|
||||
* During update, update missing values from either data from the CSV, or defaults.
|
||||
*/
|
||||
const UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS = 3;
|
||||
|
||||
/** @var int processor mode. */
|
||||
protected $mode;
|
||||
|
||||
/** @var int upload mode. */
|
||||
protected $updatemode;
|
||||
|
||||
/** @var bool are renames allowed. */
|
||||
protected $allowrenames = false;
|
||||
|
||||
/** @var bool are deletes allowed. */
|
||||
protected $allowdeletes = false;
|
||||
|
||||
/** @var bool are resets allowed. */
|
||||
protected $allowresets = false;
|
||||
|
||||
/** @var string path to a restore file. */
|
||||
protected $restorefile;
|
||||
|
||||
/** @var string shortname of the course to be restored. */
|
||||
protected $templatecourse;
|
||||
|
||||
/** @var string reset courses after processing them. */
|
||||
protected $reset;
|
||||
|
||||
/** @var string template to generate a course shortname. */
|
||||
protected $shortnametemplate;
|
||||
|
||||
/** @var csv_import_reader */
|
||||
protected $cir;
|
||||
|
||||
/** @var array default values. */
|
||||
protected $defaults = array();
|
||||
|
||||
/** @var array CSV columns. */
|
||||
protected $columns = array();
|
||||
|
||||
/** @var array of errors where the key is the line number. */
|
||||
protected $errors = array();
|
||||
|
||||
/** @var int line number. */
|
||||
protected $linenb = 0;
|
||||
|
||||
/** @var bool whether the process has been started or not. */
|
||||
protected $processstarted = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param csv_import_reader $cir import reader object
|
||||
* @param array $options options of the process
|
||||
* @param array $defaults default data value
|
||||
*/
|
||||
public function __construct(csv_import_reader $cir, array $options, array $defaults = array()) {
|
||||
|
||||
if (!isset($options['mode']) || !in_array($options['mode'], array(self::MODE_CREATE_NEW, self::MODE_CREATE_ALL,
|
||||
self::MODE_CREATE_OR_UPDATE, self::MODE_UPDATE_ONLY))) {
|
||||
throw new coding_exception('Unknown process mode');
|
||||
}
|
||||
|
||||
// Force int to make sure === comparison work as expected.
|
||||
$this->mode = (int) $options['mode'];
|
||||
|
||||
$this->updatemode = self::UPDATE_NOTHING;
|
||||
if (isset($options['updatemode'])) {
|
||||
// Force int to make sure === comparison work as expected.
|
||||
$this->updatemode = (int) $options['updatemode'];
|
||||
}
|
||||
if (isset($options['allowrenames'])) {
|
||||
$this->allowrenames = $options['allowrenames'];
|
||||
}
|
||||
if (isset($options['allowdeletes'])) {
|
||||
$this->allowdeletes = $options['allowdeletes'];
|
||||
}
|
||||
if (isset($options['allowresets'])) {
|
||||
$this->allowresets = $options['allowresets'];
|
||||
}
|
||||
|
||||
if (isset($options['restorefile'])) {
|
||||
$this->restorefile = $options['restorefile'];
|
||||
}
|
||||
if (isset($options['templatecourse'])) {
|
||||
$this->templatecourse = $options['templatecourse'];
|
||||
}
|
||||
if (isset($options['reset'])) {
|
||||
$this->reset = $options['reset'];
|
||||
}
|
||||
if (isset($options['shortnametemplate'])) {
|
||||
$this->shortnametemplate = $options['shortnametemplate'];
|
||||
}
|
||||
|
||||
$this->cir = $cir;
|
||||
$this->columns = $cir->get_columns();
|
||||
$this->defaults = $defaults;
|
||||
$this->validate();
|
||||
$this->reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the process.
|
||||
*
|
||||
* @param object $tracker the output tracker to use.
|
||||
* @return void
|
||||
*/
|
||||
public function execute($tracker = null) {
|
||||
if ($this->processstarted) {
|
||||
throw new coding_exception('Process has already been started');
|
||||
}
|
||||
$this->processstarted = true;
|
||||
|
||||
if (empty($tracker)) {
|
||||
$tracker = new tool_uploadcourse_tracker(tool_uploadcourse_tracker::NO_OUTPUT);
|
||||
}
|
||||
$tracker->start();
|
||||
|
||||
$total = 0;
|
||||
$created = 0;
|
||||
$updated = 0;
|
||||
$deleted = 0;
|
||||
$errors = 0;
|
||||
|
||||
// Loop over the CSV lines.
|
||||
while ($line = $this->cir->next()) {
|
||||
$this->linenb++;
|
||||
$total++;
|
||||
|
||||
$data = $this->parse_line($line);
|
||||
$course = $this->get_course($data);
|
||||
if ($course->prepare()) {
|
||||
$course->proceed();
|
||||
|
||||
$status = $course->get_statuses();
|
||||
if (array_key_exists('coursecreated', $status)) {
|
||||
$created++;
|
||||
} else if (array_key_exists('courseupdated', $status)) {
|
||||
$updated++;
|
||||
} else if (array_key_exists('coursedeleted', $status)) {
|
||||
$deleted++;
|
||||
}
|
||||
|
||||
$data = array_merge($data, $course->get_data(), array('id' => $course->get_id()));
|
||||
$tracker->output($this->linenb, true, $status, $data);
|
||||
} else {
|
||||
$errors++;
|
||||
$tracker->output($this->linenb, false, $course->get_errors(), $data);
|
||||
}
|
||||
}
|
||||
|
||||
$tracker->finish();
|
||||
$tracker->results($total, $created, $updated, $deleted, $errors);
|
||||
|
||||
$this->remove_restore_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a course import object.
|
||||
*
|
||||
* @param array $data data to import the course with.
|
||||
* @return tool_uploadcourse_course
|
||||
*/
|
||||
protected function get_course($data) {
|
||||
$importoptions = array(
|
||||
'candelete' => $this->allowdeletes,
|
||||
'canrename' => $this->allowrenames,
|
||||
'canreset' => $this->allowresets,
|
||||
'reset' => $this->reset,
|
||||
'restoredir' => $this->get_restore_content_dir(),
|
||||
'shortnametemplate' => $this->shortnametemplate
|
||||
);
|
||||
return new tool_uploadcourse_course($this->mode, $this->updatemode, $data, $this->defaults, $importoptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_errors() {
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the directory of the object to restore.
|
||||
*
|
||||
* @return string subdirectory in $CFG->tempdir/backup/...
|
||||
*/
|
||||
protected function get_restore_content_dir() {
|
||||
$backupfile = null;
|
||||
$shortname = null;
|
||||
|
||||
if (!empty($this->restorefile)) {
|
||||
$backupfile = $this->restorefile;
|
||||
} else if (!empty($this->templatecourse) || is_numeric($this->templatecourse)) {
|
||||
$shortname = $this->templatecourse;
|
||||
}
|
||||
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir($backupfile, $shortname);
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Log errors on the current line.
|
||||
*
|
||||
* @param array $errors array of errors
|
||||
* @return void
|
||||
*/
|
||||
protected function log_error($errors) {
|
||||
if (empty($errors)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($errors as $code => $langstring) {
|
||||
if (!isset($this->errors[$this->linenb])) {
|
||||
$this->errors[$this->linenb] = array();
|
||||
}
|
||||
$this->errors[$this->linenb][$code] = $langstring;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a line to return an array(column => value)
|
||||
*
|
||||
* @param array $line returned by csv_import_reader
|
||||
* @return array
|
||||
*/
|
||||
protected function parse_line($line) {
|
||||
$data = array();
|
||||
foreach ($line as $keynum => $value) {
|
||||
if (!isset($this->columns[$keynum])) {
|
||||
// This should not happen.
|
||||
continue;
|
||||
}
|
||||
|
||||
$key = $this->columns[$keynum];
|
||||
$data[$key] = $value;
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a preview of the import.
|
||||
*
|
||||
* This only returns passed data, along with the errors.
|
||||
*
|
||||
* @param integer $rows number of rows to preview.
|
||||
* @param object $tracker the output tracker to use.
|
||||
* @return array of preview data.
|
||||
*/
|
||||
public function preview($rows = 10, $tracker = null) {
|
||||
if ($this->processstarted) {
|
||||
throw new coding_exception('Process has already been started');
|
||||
}
|
||||
$this->processstarted = true;
|
||||
|
||||
if (empty($tracker)) {
|
||||
$tracker = new tool_uploadcourse_tracker(tool_uploadcourse_tracker::NO_OUTPUT);
|
||||
}
|
||||
$tracker->start();
|
||||
|
||||
// Loop over the CSV lines.
|
||||
$preview = array();
|
||||
while (($line = $this->cir->next()) && $rows > $this->linenb) {
|
||||
$this->linenb++;
|
||||
$data = $this->parse_line($line);
|
||||
$course = $this->get_course($data);
|
||||
$result = $course->prepare();
|
||||
if (!$result) {
|
||||
$tracker->output($this->linenb, $result, $course->get_errors(), $data);
|
||||
} else {
|
||||
$tracker->output($this->linenb, $result, $course->get_statuses(), $data);
|
||||
}
|
||||
$row = $data;
|
||||
$preview[$this->linenb] = $row;
|
||||
}
|
||||
|
||||
$tracker->finish();
|
||||
$this->remove_restore_content();
|
||||
|
||||
return $preview;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the restore object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function remove_restore_content() {
|
||||
tool_uploadcourse_helper::clean_restore_content();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current process.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
public function reset() {
|
||||
$this->processstarted = false;
|
||||
$this->linenb = 0;
|
||||
$this->cir->init();
|
||||
$this->errors = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function validate() {
|
||||
if (empty($this->columns)) {
|
||||
throw new moodle_exception('cannotreadtmpfile', 'error');
|
||||
} else if (count($this->columns) < 2) {
|
||||
throw new moodle_exception('csvfewcolumns', 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing the step 1 of the upload form.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/formslib.php');
|
||||
|
||||
/**
|
||||
* Upload a file CVS file with course information.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_step1_form extends tool_uploadcourse_base_form {
|
||||
|
||||
/**
|
||||
* The standard form definiton.
|
||||
* @return void
|
||||
*/
|
||||
public function definition () {
|
||||
$mform = $this->_form;
|
||||
|
||||
$mform->addElement('header', 'generalhdr', get_string('general'));
|
||||
|
||||
$mform->addElement('filepicker', 'coursefile', get_string('file'));
|
||||
$mform->addRule('coursefile', null, 'required');
|
||||
|
||||
$choices = csv_import_reader::get_delimiter_list();
|
||||
$mform->addElement('select', 'delimiter_name', get_string('csvdelimiter', 'tool_uploadcourse'), $choices);
|
||||
if (array_key_exists('cfg', $choices)) {
|
||||
$mform->setDefault('delimiter_name', 'cfg');
|
||||
} else if (get_string('listsep', 'langconfig') == ';') {
|
||||
$mform->setDefault('delimiter_name', 'semicolon');
|
||||
} else {
|
||||
$mform->setDefault('delimiter_name', 'comma');
|
||||
}
|
||||
|
||||
$choices = textlib::get_encodings();
|
||||
$mform->addElement('select', 'encoding', get_string('encoding', 'tool_uploadcourse'), $choices);
|
||||
$mform->setDefault('encoding', 'UTF-8');
|
||||
|
||||
$choices = array('10' => 10, '20' => 20, '100' => 100, '1000' => 1000, '100000' => 100000);
|
||||
$mform->addElement('select', 'previewrows', get_string('rowpreviewnum', 'tool_uploadcourse'), $choices);
|
||||
$mform->setType('previewrows', PARAM_INT);
|
||||
|
||||
$this->add_import_options();
|
||||
|
||||
$mform->addElement('hidden', 'showpreview', 1);
|
||||
$mform->setType('showpreview', PARAM_INT);
|
||||
|
||||
$this->add_action_buttons(false, get_string('preview', 'tool_uploadcourse'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Bulk course upload step 2.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Specify course upload details.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
|
||||
|
||||
/**
|
||||
* The standard form definiton.
|
||||
* @return void.
|
||||
*/
|
||||
public function definition () {
|
||||
global $CFG;
|
||||
|
||||
$mform = $this->_form;
|
||||
$data = $this->_customdata['data'];
|
||||
$courseconfig = get_config('moodlecourse');
|
||||
|
||||
// Import options.
|
||||
$this->add_import_options();
|
||||
|
||||
// Course options.
|
||||
$mform->addElement('header', 'courseoptionshdr', get_string('courseprocess', 'tool_uploadcourse'));
|
||||
$mform->setExpanded('courseoptionshdr', true);
|
||||
|
||||
$mform->addElement('text', 'options[shortnametemplate]', get_string('shortnametemplate', 'tool_uploadcourse'),
|
||||
'maxlength="100" size="20"');
|
||||
$mform->setType('options[shortnametemplate]', PARAM_RAW);
|
||||
$mform->addHelpButton('options[shortnametemplate]', 'shortnametemplate', 'tool_uploadcourse');
|
||||
$mform->disabledIf('options[shortnametemplate]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE);
|
||||
$mform->disabledIf('options[shortnametemplate]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_UPDATE_ONLY);
|
||||
|
||||
$contextid = $this->_customdata['contextid'];
|
||||
$mform->addElement('hidden', 'contextid', $contextid);
|
||||
$mform->setType('contextid', PARAM_INT);
|
||||
$mform->addElement('filepicker', 'options[restorefile]', get_string('templatefile', 'tool_uploadcourse'));
|
||||
$mform->addHelpButton('options[restorefile]', 'templatefile', 'tool_uploadcourse');
|
||||
|
||||
$mform->addElement('text', 'options[templatecourse]', get_string('coursetemplatename', 'tool_uploadcourse'));
|
||||
$mform->setType('options[templatecourse]', PARAM_TEXT);
|
||||
$mform->addHelpButton('options[templatecourse]', 'coursetemplatename', 'tool_uploadcourse');
|
||||
|
||||
$mform->addElement('selectyesno', 'options[reset]', get_string('reset', 'tool_uploadcourse'));
|
||||
$mform->setDefault('options[reset]', 0);
|
||||
$mform->disabledIf('options[reset]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$mform->disabledIf('options[reset]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
$mform->disabledIf('options[reset]', 'options[allowresets]', 'eq', 0);
|
||||
|
||||
// Default values.
|
||||
$mform->addElement('header', 'defaultheader', get_string('defaultvalues', 'tool_uploadcourse'));
|
||||
$mform->setExpanded('defaultheader', true);
|
||||
|
||||
$displaylist = coursecat::make_categories_list('moodle/course:create');
|
||||
$mform->addElement('select', 'defaults[category]', get_string('coursecategory'), $displaylist);
|
||||
$mform->addHelpButton('defaults[category]', 'coursecategory');
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = get_string('hide');
|
||||
$choices['1'] = get_string('show');
|
||||
$mform->addElement('select', 'defaults[visible]', get_string('visible'), $choices);
|
||||
$mform->addHelpButton('defaults[visible]', 'visible');
|
||||
$mform->setDefault('defaults[visible]', $courseconfig->visible);
|
||||
|
||||
$mform->addElement('date_selector', 'defaults[startdate]', get_string('startdate'));
|
||||
$mform->addHelpButton('defaults[startdate]', 'startdate');
|
||||
$mform->setDefault('defaults[startdate]', time() + 3600 * 24);
|
||||
|
||||
$courseformats = get_sorted_course_formats(true);
|
||||
$formcourseformats = array();
|
||||
foreach ($courseformats as $courseformat) {
|
||||
$formcourseformats[$courseformat] = get_string('pluginname', "format_$courseformat");
|
||||
}
|
||||
$mform->addElement('select', 'defaults[format]', get_string('format'), $formcourseformats);
|
||||
$mform->addHelpButton('defaults[format]', 'format');
|
||||
$mform->setDefault('defaults[format]', $courseconfig->format);
|
||||
|
||||
if (!empty($CFG->allowcoursethemes)) {
|
||||
$themeobjects = get_list_of_themes();
|
||||
$themes=array();
|
||||
$themes[''] = get_string('forceno');
|
||||
foreach ($themeobjects as $key => $theme) {
|
||||
if (empty($theme->hidefromselector)) {
|
||||
$themes[$key] = get_string('pluginname', 'theme_'.$theme->name);
|
||||
}
|
||||
}
|
||||
$mform->addElement('select', 'defaults[theme]', get_string('forcetheme'), $themes);
|
||||
}
|
||||
|
||||
$languages = array();
|
||||
$languages[''] = get_string('forceno');
|
||||
$languages += get_string_manager()->get_list_of_translations();
|
||||
$mform->addElement('select', 'defaults[lang]', get_string('forcelanguage'), $languages);
|
||||
$mform->setDefault('defaults[lang]', $courseconfig->lang);
|
||||
|
||||
$options = range(0, 10);
|
||||
$mform->addElement('select', 'defaults[newsitems]', get_string('newsitemsnumber'), $options);
|
||||
$mform->addHelpButton('defaults[newsitems]', 'newsitemsnumber');
|
||||
$mform->setDefault('defaults[newsitems]', $courseconfig->newsitems);
|
||||
|
||||
$mform->addElement('selectyesno', 'defaults[showgrades]', get_string('showgrades'));
|
||||
$mform->addHelpButton('defaults[showgrades]', 'showgrades');
|
||||
$mform->setDefault('defaults[showgrades]', $courseconfig->showgrades);
|
||||
|
||||
$mform->addElement('selectyesno', 'defaults[showreports]', get_string('showreports'));
|
||||
$mform->addHelpButton('defaults[showreports]', 'showreports');
|
||||
$mform->setDefault('defaults[showreports]', $courseconfig->showreports);
|
||||
|
||||
if (!empty($CFG->legacyfilesinnewcourses)) {
|
||||
$mform->addElement('select', 'defaults[legacyfiles]', get_string('courselegacyfiles'), $choices);
|
||||
$mform->addHelpButton('defaults[legacyfiles]', 'courselegacyfiles');
|
||||
if (!isset($courseconfig->legacyfiles)) {
|
||||
$courseconfig->legacyfiles = 0;
|
||||
}
|
||||
$mform->setDefault('defaults[legacyfiles]', $courseconfig->legacyfiles);
|
||||
}
|
||||
|
||||
$choices = get_max_upload_sizes($CFG->maxbytes);
|
||||
$mform->addElement('select', 'defaults[maxbytes]', get_string('maximumupload'), $choices);
|
||||
$mform->addHelpButton('defaults[maxbytes]', 'maximumupload');
|
||||
$mform->setDefault('defaults[maxbytes]', $courseconfig->maxbytes);
|
||||
|
||||
$choices = array();
|
||||
$choices[NOGROUPS] = get_string('groupsnone', 'group');
|
||||
$choices[SEPARATEGROUPS] = get_string('groupsseparate', 'group');
|
||||
$choices[VISIBLEGROUPS] = get_string('groupsvisible', 'group');
|
||||
$mform->addElement('select', 'defaults[groupmode]', get_string('groupmode', 'group'), $choices);
|
||||
$mform->addHelpButton('defaults[groupmode]', 'groupmode', 'group');
|
||||
$mform->setDefault('defaults[groupmode]', $courseconfig->groupmode);
|
||||
|
||||
$mform->addElement('selectyesno', 'defaults[groupmodeforce]', get_string('groupmodeforce', 'group'));
|
||||
$mform->addHelpButton('defaults[groupmodeforce]', 'groupmodeforce', 'group');
|
||||
$mform->setDefault('defaults[groupmodeforce]', $courseconfig->groupmodeforce);
|
||||
|
||||
// Hidden fields.
|
||||
$mform->addElement('hidden', 'importid');
|
||||
$mform->setType('importid', PARAM_INT);
|
||||
|
||||
$mform->addElement('hidden', 'previewrows');
|
||||
$mform->setType('previewrows', PARAM_INT);
|
||||
|
||||
$this->add_action_buttons(true, get_string('uploadcourses', 'tool_uploadcourse'));
|
||||
|
||||
$this->set_data($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add actopm buttons.
|
||||
*
|
||||
* @param bool $cancel whether to show cancel button, default true
|
||||
* @param string $submitlabel label for submit button, defaults to get_string('savechanges')
|
||||
* @return void
|
||||
*/
|
||||
public function add_action_buttons($cancel = true, $submitlabel = null) {
|
||||
$mform =& $this->_form;
|
||||
$buttonarray = array();
|
||||
$buttonarray[] = &$mform->createElement('submit', 'showpreview', get_string('preview', 'tool_uploadcourse'));
|
||||
$buttonarray[] = &$mform->createElement('submit', 'submitbutton', $submitlabel);
|
||||
$buttonarray[] = &$mform->createElement('cancel');
|
||||
$mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
|
||||
$mform->closeHeaderBefore('buttonar');
|
||||
}
|
||||
|
||||
/**
|
||||
* Server side validation.
|
||||
* @param array $data - form data
|
||||
* @param object $files - form files
|
||||
* @return array $errors - form errors
|
||||
*/
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
$columns = $this->_customdata['columns'];
|
||||
$optype = $data['options']['mode'];
|
||||
|
||||
// Look for other required data.
|
||||
if ($optype != tool_uploadcourse_processor::MODE_UPDATE_ONLY) {
|
||||
if (!in_array('fullname', $columns)) {
|
||||
if (isset($errors['mode'])) {
|
||||
$errors['mode'] .= ' ';
|
||||
}
|
||||
$errors['mode'] .= get_string('missingfield', 'error', 'fullname');
|
||||
}
|
||||
if (!in_array('summary', $columns)) {
|
||||
if (isset($errors['mode'])) {
|
||||
$errors['mode'] .= ' ';
|
||||
}
|
||||
$errors['mode'] .= get_string('missingfield', 'error', 'summary');
|
||||
}
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Output tracker.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir . '/weblib.php');
|
||||
|
||||
/**
|
||||
* Class output tracker.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_tracker {
|
||||
|
||||
/**
|
||||
* Constant to output nothing.
|
||||
*/
|
||||
const NO_OUTPUT = 0;
|
||||
|
||||
/**
|
||||
* Constant to output HTML.
|
||||
*/
|
||||
const OUTPUT_HTML = 1;
|
||||
|
||||
/**
|
||||
* Constant to output plain text.
|
||||
*/
|
||||
const OUTPUT_PLAIN = 2;
|
||||
|
||||
/**
|
||||
* @var array columns to display.
|
||||
*/
|
||||
protected $columns = array('line', 'result', 'id', 'shortname', 'fullname', 'idnumber', 'status');
|
||||
|
||||
/**
|
||||
* @var int row number.
|
||||
*/
|
||||
protected $rownb = 0;
|
||||
|
||||
/**
|
||||
* @var int chosen output mode.
|
||||
*/
|
||||
protected $outputmode;
|
||||
|
||||
/**
|
||||
* @var object output buffer.
|
||||
*/
|
||||
protected $buffer;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $outputmode desired output mode.
|
||||
*/
|
||||
public function __construct($outputmode = self::NO_OUTPUT) {
|
||||
$this->outputmode = $outputmode;
|
||||
if ($this->outputmode == self::OUTPUT_PLAIN) {
|
||||
$this->buffer = new progress_trace_buffer(new text_progress_trace());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish the output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function finish() {
|
||||
if ($this->outputmode == self::NO_OUTPUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->outputmode == self::OUTPUT_HTML) {
|
||||
echo html_writer::end_tag('table');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the results.
|
||||
*
|
||||
* @param int $total total courses.
|
||||
* @param int $created count of courses created.
|
||||
* @param int $updated count of courses updated.
|
||||
* @param int $deleted count of courses deleted.
|
||||
* @param int $errors count of errors.
|
||||
* @return void
|
||||
*/
|
||||
public function results($total, $created, $updated, $deleted, $errors) {
|
||||
if ($this->outputmode == self::NO_OUTPUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
$message = array(
|
||||
get_string('coursestotal', 'tool_uploadcourse', $total),
|
||||
get_string('coursescreated', 'tool_uploadcourse', $created),
|
||||
get_string('coursesupdated', 'tool_uploadcourse', $updated),
|
||||
get_string('coursesdeleted', 'tool_uploadcourse', $deleted),
|
||||
get_string('courseserrors', 'tool_uploadcourse', $errors)
|
||||
);
|
||||
|
||||
if ($this->outputmode == self::OUTPUT_PLAIN) {
|
||||
foreach ($message as $msg) {
|
||||
$this->buffer->output($msg);
|
||||
}
|
||||
} else if ($this->outputmode == self::OUTPUT_HTML) {
|
||||
$buffer = new progress_trace_buffer(new html_list_progress_trace());
|
||||
foreach ($message as $msg) {
|
||||
$buffer->output($msg);
|
||||
}
|
||||
$buffer->finished();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Output one more line.
|
||||
*
|
||||
* @param int $line line number.
|
||||
* @param bool $outcome success or not?
|
||||
* @param array $status array of statuses.
|
||||
* @param array $data extra data to display.
|
||||
* @return void
|
||||
*/
|
||||
public function output($line, $outcome, $status, $data) {
|
||||
global $OUTPUT;
|
||||
if ($this->outputmode == self::NO_OUTPUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->outputmode == self::OUTPUT_PLAIN) {
|
||||
$message = array(
|
||||
$line,
|
||||
$outcome ? 'OK' : 'NOK',
|
||||
isset($data['id']) ? $data['id'] : '',
|
||||
isset($data['shortname']) ? $data['shortname'] : '',
|
||||
isset($data['fullname']) ? $data['fullname'] : '',
|
||||
isset($data['idnumber']) ? $data['idnumber'] : ''
|
||||
);
|
||||
$this->buffer->output(implode("\t", $message));
|
||||
if (!empty($status)) {
|
||||
foreach ($status as $st) {
|
||||
$this->buffer->output($st, 1);
|
||||
}
|
||||
}
|
||||
} else if ($this->outputmode == self::OUTPUT_HTML) {
|
||||
$ci = 0;
|
||||
$this->rownb++;
|
||||
if (is_array($status)) {
|
||||
$status = implode(html_writer::empty_tag('br'), $status);
|
||||
}
|
||||
if ($outcome) {
|
||||
$outcome = $OUTPUT->pix_icon('i/valid', '');
|
||||
} else {
|
||||
$outcome = $OUTPUT->pix_icon('i/invalid', '');
|
||||
}
|
||||
echo html_writer::start_tag('tr', array('class' => 'r' . $this->rownb % 2));
|
||||
echo html_writer::tag('td', $line, array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', $outcome, array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['id']) ? $data['id'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['shortname']) ? $data['shortname'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['fullname']) ? $data['fullname'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', isset($data['idnumber']) ? $data['idnumber'] : '', array('class' => 'c' . $ci++));
|
||||
echo html_writer::tag('td', $status, array('class' => 'c' . $ci++));
|
||||
echo html_writer::end_tag('tr');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the output.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function start() {
|
||||
if ($this->outputmode == self::NO_OUTPUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->outputmode == self::OUTPUT_PLAIN) {
|
||||
$columns = array_flip($this->columns);
|
||||
unset($columns['status']);
|
||||
$columns = array_flip($columns);
|
||||
$this->buffer->output(implode("\t", $columns));
|
||||
} else if ($this->outputmode == self::OUTPUT_HTML) {
|
||||
$ci = 0;
|
||||
echo html_writer::start_tag('table', array('class' => 'generaltable boxaligncenter flexible-wrap',
|
||||
'summary' => get_string('uploadcoursesresult', 'tool_uploadcourse')));
|
||||
echo html_writer::start_tag('tr', array('class' => 'heading r' . $this->rownb));
|
||||
echo html_writer::tag('th', get_string('csvline', 'tool_uploadcourse'),
|
||||
array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::tag('th', get_string('result', 'tool_uploadcourse'), array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::tag('th', get_string('id', 'tool_uploadcourse'), array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::tag('th', get_string('shortname'), array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::tag('th', get_string('fullname'), array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::tag('th', get_string('idnumber'), array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::tag('th', get_string('status'), array('class' => 'c' . $ci++, 'scope' => 'col'));
|
||||
echo html_writer::end_tag('tr');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* CLI Bulk course registration script from a comma separated file.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2012 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require_once($CFG->libdir . '/coursecatlib.php');
|
||||
require_once($CFG->libdir . '/csvlib.class.php');
|
||||
|
||||
$courseconfig = get_config('moodlecourse');
|
||||
|
||||
// Now get cli options.
|
||||
list($options, $unrecognized) = cli_get_params(array(
|
||||
'help' => false,
|
||||
'mode' => '',
|
||||
'updatemode' => 'nothing',
|
||||
'file' => '',
|
||||
'delimiter' => 'comma',
|
||||
'encoding' => 'UTF-8',
|
||||
'shortnametemplate' => '',
|
||||
'templatecourse' => false,
|
||||
'restorefile' => false,
|
||||
'allowdeletes' => false,
|
||||
'allowrenames' => false,
|
||||
'allowresets' => false,
|
||||
'reset' => false,
|
||||
'category' => coursecat::get_default()->id,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
'm' => 'mode',
|
||||
'u' => 'updatemode',
|
||||
'f' => 'file',
|
||||
'd' => 'delimiter',
|
||||
'e' => 'encoding',
|
||||
't' => 'templatecourse',
|
||||
'r' => 'restorefile',
|
||||
'g' => 'format',
|
||||
));
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
$help =
|
||||
"Execute Course Upload.
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
-m, --mode Import mode: createnew, createall, createorupdate, update
|
||||
-u, --updatemode Update mode: nothing, dataonly, dataordefaults¸ missingonly
|
||||
-f, --file CSV file
|
||||
-d, --delimiter CSV delimiter: colon, semicolon, tab, cfg, comma
|
||||
-e, --encoding CSV file encoding: utf8, ... etc
|
||||
-t, --templatecourse Shortname of the course to restore after import
|
||||
-r, --restorefile Backup file to restore after import
|
||||
--reset Run the course reset after each course import
|
||||
--allowdeletes Allow courses to be deleted
|
||||
--allowrenames Allow courses to be renamed
|
||||
--allowresets Allow courses to be reset
|
||||
--shortnametemplate Template to generate the shortname from
|
||||
--category ID of default category (--updatemode dataordefaults will use this value)
|
||||
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/tool/uploadcourse/cli/uploadcourse.php --action=createnew \\
|
||||
--updatemode=dataonly --file=./courses.csv --delimiter=comma
|
||||
";
|
||||
|
||||
if ($options['help']) {
|
||||
echo $help;
|
||||
die();
|
||||
}
|
||||
echo "Moodle course uploader running ...\n";
|
||||
|
||||
$processoroptions = array(
|
||||
'allowdeletes' => $options['allowdeletes'],
|
||||
'allowrenames' => $options['allowrenames'],
|
||||
'allowresets' => $options['allowresets'],
|
||||
'reset' => $options['reset'],
|
||||
'shortnametemplate' => $options['shortnametemplate']
|
||||
);
|
||||
|
||||
// Confirm that the mode is valid.
|
||||
$modes = array(
|
||||
'createnew' => tool_uploadcourse_processor::MODE_CREATE_NEW,
|
||||
'createall' => tool_uploadcourse_processor::MODE_CREATE_ALL,
|
||||
'createorupdate' => tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE,
|
||||
'update' => tool_uploadcourse_processor::MODE_UPDATE_ONLY
|
||||
);
|
||||
if (!isset($options['mode']) || !isset($modes[$options['mode']])) {
|
||||
echo get_string('invalidmode', 'tool_uploadcourse')."\n";
|
||||
echo $help;
|
||||
die();
|
||||
}
|
||||
$processoroptions['mode'] = $modes[$options['mode']];
|
||||
|
||||
// Check that the update mode is valid.
|
||||
$updatemodes = array(
|
||||
'nothing' => tool_uploadcourse_processor::UPDATE_NOTHING,
|
||||
'dataonly' => tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY,
|
||||
'dataordefaults' => tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS,
|
||||
'missingonly' => tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS
|
||||
);
|
||||
if (($processoroptions['mode'] === tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE ||
|
||||
$processoroptions['mode'] === tool_uploadcourse_processor::MODE_UPDATE_ONLY)
|
||||
&& (!isset($options['updatemode']) || !isset($updatemodes[$options['updatemode']]))) {
|
||||
echo get_string('invalideupdatemode', 'tool_uploadcourse')."\n";
|
||||
echo $help;
|
||||
die();
|
||||
}
|
||||
$processoroptions['updatemode'] = $updatemodes[$options['updatemode']];
|
||||
|
||||
// File.
|
||||
if (!empty($options['file'])) {
|
||||
$options['file'] = realpath($options['file']);
|
||||
}
|
||||
if (!file_exists($options['file'])) {
|
||||
echo get_string('invalidcsvfile', 'tool_uploadcourse')."\n";
|
||||
echo $help;
|
||||
die();
|
||||
}
|
||||
|
||||
// Encoding.
|
||||
$encodings = textlib::get_encodings();
|
||||
if (!isset($encodings[$options['encoding']])) {
|
||||
echo get_string('invalidencoding', 'tool_uploadcourse')."\n";
|
||||
echo $help;
|
||||
die();
|
||||
}
|
||||
|
||||
// Default values.
|
||||
$defaults = array();
|
||||
$defaults['category'] = $options['category'];
|
||||
$defaults['startdate'] = time() + 3600 * 24;
|
||||
$defaults['newsitems'] = $courseconfig->newsitems;
|
||||
$defaults['showgrades'] = $courseconfig->showgrades;
|
||||
$defaults['showreports'] = $courseconfig->showreports;
|
||||
$defaults['maxbytes'] = $courseconfig->maxbytes;
|
||||
$defaults['legacyfiles'] = $CFG->legacyfilesinnewcourses;
|
||||
$defaults['groupmode'] = $courseconfig->groupmode;
|
||||
$defaults['groupmodeforce'] = $courseconfig->groupmodeforce;
|
||||
$defaults['visible'] = $courseconfig->visible;
|
||||
$defaults['lang'] = $courseconfig->lang;
|
||||
|
||||
// Course template.
|
||||
if (isset($options['templatecourse'])) {
|
||||
$processoroptions['templatecourse'] = $options['templatecourse'];
|
||||
}
|
||||
|
||||
// Restore file.
|
||||
if ($options['restorefile']) {
|
||||
$options['restorefile'] = realpath($options['restorefile']);
|
||||
}
|
||||
if ($options['restorefile'] && !file_exists($options['restorefile'])) {
|
||||
echo get_string('invalidrestorefile', 'tool_uploadcourse')."\n";
|
||||
echo $help;
|
||||
die();
|
||||
}
|
||||
$processoroptions['restorefile'] = $options['restorefile'];
|
||||
|
||||
// Emulate normal session.
|
||||
cron_setup_user();
|
||||
|
||||
// Let's get started!
|
||||
$content = file_get_contents($options['file']);
|
||||
$importid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($importid, 'uploadcourse');
|
||||
$readcount = $cir->load_csv_content($content, $options['encoding'], $options['delimiter']);
|
||||
unset($content);
|
||||
if ($readcount === false) {
|
||||
print_error('csvfileerror', 'tool_uploadcourse', '', $cir->get_error());
|
||||
} else if ($readcount == 0) {
|
||||
print_error('csvemptyfile', 'error', '', $cir->get_error());
|
||||
}
|
||||
$processor = new tool_uploadcourse_processor($cir, $processoroptions, $defaults);
|
||||
$processor->execute(new tool_uploadcourse_tracker(tool_uploadcourse_tracker::OUTPUT_PLAIN));
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Cache definitions.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$definitions = array(
|
||||
'helper' => array(
|
||||
'mode' => cache_store::MODE_REQUEST,
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Bulk course registration script from a comma separated file.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require(__DIR__ . '/../../../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/coursecatlib.php');
|
||||
require_once($CFG->libdir . '/csvlib.class.php');
|
||||
|
||||
admin_externalpage_setup('tooluploadcourse');
|
||||
|
||||
$importid = optional_param('importid', '', PARAM_INT);
|
||||
$previewrows = optional_param('previewrows', 10, PARAM_INT);
|
||||
|
||||
$returnurl = new moodle_url('/admin/tool/uploadcourse/index.php');
|
||||
|
||||
if (empty($importid)) {
|
||||
$mform1 = new tool_uploadcourse_step1_form();
|
||||
if ($form1data = $mform1->get_data()) {
|
||||
$importid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($importid, 'uploadcourse');
|
||||
$content = $mform1->get_file_content('coursefile');
|
||||
$readcount = $cir->load_csv_content($content, $form1data->encoding, $form1data->delimiter_name);
|
||||
unset($content);
|
||||
if ($readcount === false) {
|
||||
print_error('csvfileerror', 'tool_uploadcourse', $returnurl, $cir->get_error());
|
||||
} else if ($readcount == 0) {
|
||||
print_error('csvemptyfile', 'error', $returnurl, $cir->get_error());
|
||||
}
|
||||
} else {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading_with_help(get_string('uploadcourses', 'tool_uploadcourse'), 'uploadcourses', 'tool_uploadcourse');
|
||||
$mform1->display();
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
$cir = new csv_import_reader($importid, 'uploadcourse');
|
||||
}
|
||||
|
||||
// Data to set in the form.
|
||||
$data = array('importid' => $importid, 'previewrows' => $previewrows);
|
||||
if (!empty($form1data)) {
|
||||
// Get options from the first form to pass it onto the second.
|
||||
foreach ($form1data->options as $key => $value) {
|
||||
$data["options[$key]"] = $value;
|
||||
}
|
||||
}
|
||||
$context = context_system::instance();
|
||||
$mform2 = new tool_uploadcourse_step2_form(null, array('contextid' => $context->id, 'columns' => $cir->get_columns(),
|
||||
'data' => $data));
|
||||
|
||||
// If a file has been uploaded, then process it.
|
||||
if ($form2data = $mform2->is_cancelled()) {
|
||||
$cir->cleanup(true);
|
||||
redirect($returnurl);
|
||||
} else if ($form2data = $mform2->get_data()) {
|
||||
|
||||
$options = (array) $form2data->options;
|
||||
$defaults = (array) $form2data->defaults;
|
||||
$processor = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
if (isset($form2data->showpreview)) {
|
||||
echo $OUTPUT->heading(get_string('uploadcoursespreview', 'tool_uploadcourse'));
|
||||
$processor->preview($previewrows, new tool_uploadcourse_tracker(tool_uploadcourse_tracker::OUTPUT_HTML));
|
||||
$mform2->display();
|
||||
} else {
|
||||
echo $OUTPUT->heading(get_string('uploadcoursesresult', 'tool_uploadcourse'));
|
||||
$processor->execute(new tool_uploadcourse_tracker(tool_uploadcourse_tracker::OUTPUT_HTML));
|
||||
echo $OUTPUT->continue_button($returnurl);
|
||||
}
|
||||
|
||||
} else {
|
||||
$processor = new tool_uploadcourse_processor($cir, $form1data->options, array());
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('uploadcoursespreview', 'tool_uploadcourse'));
|
||||
$processor->preview($previewrows, new tool_uploadcourse_tracker(tool_uploadcourse_tracker::OUTPUT_HTML));
|
||||
$mform2->display();
|
||||
}
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'tool_uploadcourse'.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['allowdeletes'] = 'Allow deletes';
|
||||
$string['allowrenames'] = 'Allow renames';
|
||||
$string['allowresets'] = 'Allow resets';
|
||||
$string['cachedef_helper'] = 'Helper caching';
|
||||
$string['cannotdeletecoursenotexist'] = 'Cannot delete a course that does not exist';
|
||||
$string['cannotgenerateshortnameupdatemode'] = 'Cannot generate a shortname when updates are allowed';
|
||||
$string['cannotreadbackupfile'] = 'Cannot read the backup file';
|
||||
$string['cannotrenamecoursenotexist'] = 'Cannot rename a course that does not exist';
|
||||
$string['cannotrenameidnumberconflict'] = 'Cannot rename the course, the ID number conflicts with an existing course';
|
||||
$string['cannotrenameshortnamealreadyinuse'] = 'Cannot rename the course, the shortname is already used';
|
||||
$string['canonlyrenameinupdatemode'] = 'Can only rename a course when update is allowed';
|
||||
$string['canonlyresetcourseinupdatemode'] = 'Can only reset a course in update mode';
|
||||
$string['couldnotresolvecatgorybyid'] = 'Could not resolve category by ID';
|
||||
$string['couldnotresolvecatgorybyidnumber'] = 'Could not resolve category by ID number';
|
||||
$string['couldnotresolvecatgorybypath'] = 'Could not resolve category by path';
|
||||
$string['coursecreated'] = 'Course created';
|
||||
$string['coursedeleted'] = 'Course deleted';
|
||||
$string['coursedeletionnotallowed'] = 'Course deletion is not allowed';
|
||||
$string['coursedoesnotexistandcreatenotallowed'] = 'The course does not exist and creating course is not allowed';
|
||||
$string['courseexistsanduploadnotallowed'] = 'The course exists and update is not allowed';
|
||||
$string['courseidnumberincremented'] = 'Course ID number incremented {$a->from} -> {$a->to}';
|
||||
$string['courseprocess'] = 'Course process';
|
||||
$string['courserenamed'] = 'Course renamed';
|
||||
$string['courserenamingnotallowed'] = 'Course renaming is not allowed';
|
||||
$string['coursereset'] = 'Course reset';
|
||||
$string['courseresetnotallowed'] = 'Course reset now allowed';
|
||||
$string['courserestored'] = 'Course restored';
|
||||
$string['coursestotal'] = 'Courses total: {$a}';
|
||||
$string['coursescreated'] = 'Courses created: {$a}';
|
||||
$string['coursesupdated'] = 'Courses updated: {$a}';
|
||||
$string['coursesdeleted'] = 'Courses deleted: {$a}';
|
||||
$string['courseserrors'] = 'Courses errors: {$a}';
|
||||
$string['courseshortnameincremented'] = 'Course shortname incremented {$a->from} -> {$a->to}';
|
||||
$string['courseshortnamegenerated'] = 'Course shortname generated: {$a}';
|
||||
$string['coursetemplatename'] = 'Restore from this course after upload';
|
||||
$string['coursetemplatename_help'] = 'Enter an existing course shortname to use as a template for the creation of all courses.';
|
||||
$string['coursetorestorefromdoesnotexist'] = 'The course to restore from does not exist';
|
||||
$string['courseupdated'] = 'Course updated';
|
||||
$string['createall'] = 'Create all, increment shortname if needed';
|
||||
$string['createnew'] = 'Create new courses only, skip existing ones';
|
||||
$string['createorupdate'] = 'Create new courses, or update existing ones';
|
||||
$string['csvdelimiter'] = 'CSV delimiter';
|
||||
$string['csvfileerror'] = 'There is something wrong with the format of the CSV file. Please check the number of headings and columns match, and that the delimiter and file encoding are correct: {$a}';
|
||||
$string['csvline'] = 'Line';
|
||||
$string['defaultvalues'] = 'Default course values';
|
||||
$string['encoding'] = 'Encoding';
|
||||
$string['errorwhilerestoringcourse'] = 'Error while restoring the course';
|
||||
$string['errorwhiledeletingcourse'] = 'Error while deleting the course';
|
||||
$string['generatedshortnameinvalid'] = 'The generated shortname is invalid';
|
||||
$string['generatedshortnamealreadyinuse'] = 'The generated shortname is already in use';
|
||||
$string['id'] = 'ID';
|
||||
$string['importoptions'] = 'Import options';
|
||||
$string['idnumberalreadyinuse'] = 'ID number already used by a course';
|
||||
$string['invalidbackupfile'] = 'Invalid backup file';
|
||||
$string['invalidcourseformat'] = 'Invalid course format';
|
||||
$string['invalidcsvfile'] = 'Invalid input CSV file';
|
||||
$string['invalidencoding'] = 'Invalid encoding';
|
||||
$string['invalidmode'] = 'Invalid mode selected';
|
||||
$string['invalideupdatemode'] = 'Invalid update mode selected';
|
||||
$string['invalidroles'] = 'Invalid role names: {$a}';
|
||||
$string['invalidshortname'] = 'Invalid shortname';
|
||||
$string['missingmandatoryfields'] = 'Missing value for mandatory fields: {$a}';
|
||||
$string['missingshortnamenotemplate'] = 'Missing shortname and shortname template not set';
|
||||
$string['mode'] = 'Upload mode';
|
||||
$string['nochanges'] = 'No changes';
|
||||
$string['pluginname'] = 'Course upload';
|
||||
$string['preview'] = 'Preview';
|
||||
$string['reset'] = 'Reset course after upload';
|
||||
$string['result'] = 'Result';
|
||||
$string['restoreafterimport'] = 'Restore after import';
|
||||
$string['rowpreviewnum'] = 'Preview rows';
|
||||
$string['shortnametemplate'] = 'Template to generate a shortname';
|
||||
$string['shortnametemplate_help'] = 'The short name of the course is displayed in the navigation. You may use template syntax here (%f = fullname, %i = idnumber), or enter an initial value that is incremented.';
|
||||
$string['templatefile'] = 'Restore from this file after upload';
|
||||
$string['templatefile_help'] = 'Select a file to use as a template for the creation of all courses.';
|
||||
$string['unknownimportmode'] = 'Unknown import mode';
|
||||
$string['updatemissing'] = 'Fill in missing from CSV data and defaults';
|
||||
$string['updatemode'] = 'Update mode';
|
||||
$string['updatemodedoessettonothing'] = 'Update mode does not allow anything to be updated';
|
||||
$string['updateonly'] = 'Only update existing courses';
|
||||
$string['updatewithdataordefaults'] = 'Update with CSV data and defaults';
|
||||
$string['updatewithdataonly'] = 'Update with CSV data only';
|
||||
$string['uploadcourses'] = 'Upload courses';
|
||||
$string['uploadcourses_help'] = 'Courses may be uploaded via text file. The format of the file should be as follows:
|
||||
|
||||
* Each line of the file contains one record
|
||||
* Each record is a series of data separated by commas (or other delimiters)
|
||||
* The first record contains a list of fieldnames defining the format of the rest of the file
|
||||
* Required fieldnames are shortname, fullname, summary and category';
|
||||
$string['uploadcoursespreview'] = 'Upload courses preview';
|
||||
$string['uploadcoursesresult'] = 'Upload courses results';
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Link to CSV course upload.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('courses', new admin_externalpage('tooluploadcourse',
|
||||
get_string('uploadcourses', 'tool_uploadcourse'), "/admin/tool/uploadcourse/index.php"));
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
@tool @tool_uploadcourse @_only_local
|
||||
Feature: An admin can create courses using a CSV file
|
||||
In order to create courses using a CSV file
|
||||
As an admin
|
||||
I need to be able to upload a CSV file and navigate through the import process
|
||||
|
||||
Background:
|
||||
Given the following "courses" exists:
|
||||
| fullname | shortname | category |
|
||||
| First course | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
And I expand "Site administration" node
|
||||
And I expand "Courses" node
|
||||
And I follow "Upload courses"
|
||||
|
||||
@javascript
|
||||
Scenario: Creation of unexisting courses
|
||||
Given I upload "admin/tool/uploadcourse/tests/fixtures/courses.csv" file to "File" filepicker
|
||||
And I click on "Preview" "button"
|
||||
When I click on "Upload courses" "button"
|
||||
Then I should see "The course exists and update is not allowed"
|
||||
And I should see "Course created"
|
||||
And I should see "Courses total: 3"
|
||||
And I should see "Courses created: 2"
|
||||
And I should see "Courses errors: 1"
|
||||
And I follow "Home"
|
||||
And I should see "Course 2"
|
||||
And I should see "Course 3"
|
||||
|
||||
@javascript
|
||||
Scenario: Creation of existing courses
|
||||
Given I upload "admin/tool/uploadcourse/tests/fixtures/courses.csv" file to "File" filepicker
|
||||
And I select "Create all, increment shortname if needed" from "Upload mode"
|
||||
And I click on "Preview" "button"
|
||||
When I click on "Upload courses" "button"
|
||||
Then I should see "Course created"
|
||||
And I should see "Course shortname incremented C1 -> C2"
|
||||
And I should see "Course shortname incremented C2 -> C3"
|
||||
And I should see "Course shortname incremented C3 -> C4"
|
||||
And I should see "Courses total: 3"
|
||||
And I should see "Courses created: 3"
|
||||
And I should see "Courses errors: 0"
|
||||
And I follow "Home"
|
||||
And I should see "Course 1"
|
||||
And I should see "Course 2"
|
||||
And I should see "Course 3"
|
||||
@@ -0,0 +1,32 @@
|
||||
@tool @tool_uploadcourse @_only_local
|
||||
Feature: An admin can update courses using a CSV file
|
||||
In order to update courses using a CSV file
|
||||
As an admin
|
||||
I need to be able to upload a CSV file and navigate through the import process
|
||||
|
||||
Background:
|
||||
Given the following "courses" exists:
|
||||
| fullname | shortname | category |
|
||||
| Some random name | C1 | 0 |
|
||||
And I log in as "admin"
|
||||
And I expand "Site administration" node
|
||||
And I expand "Courses" node
|
||||
And I follow "Upload courses"
|
||||
|
||||
@javascript
|
||||
Scenario: Updating a course fullname
|
||||
Given I upload "admin/tool/uploadcourse/tests/fixtures/courses.csv" file to "File" filepicker
|
||||
And I select "Only update existing courses" from "Upload mode"
|
||||
And I select "Update with CSV data only" from "Update mode"
|
||||
And I click on "Preview" "button"
|
||||
When I click on "Upload courses" "button"
|
||||
Then I should see "Course updated"
|
||||
And I should see "The course does not exist and creating course is not allowed"
|
||||
And I should see "Courses total: 3"
|
||||
And I should see "Courses updated: 1"
|
||||
And I should see "Courses created: 0"
|
||||
And I should see "Courses errors: 2"
|
||||
And I follow "Home"
|
||||
And I should see "Course 1"
|
||||
And I should not see "Course 2"
|
||||
And I should not see "Course 3"
|
||||
@@ -0,0 +1,923 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing tests for the course class.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
/**
|
||||
* Course test case.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
|
||||
*/
|
||||
class tool_uploadcourse_course_testcase extends advanced_testcase {
|
||||
|
||||
public function test_proceed_without_prepare() {
|
||||
$this->resetAfterTest(true);
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array();
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->setExpectedException('coding_exception');
|
||||
$co->proceed();
|
||||
}
|
||||
|
||||
public function test_proceed_when_prepare_failed() {
|
||||
$this->resetAfterTest(true);
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array();
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->setExpectedException('moodle_exception');
|
||||
$co->proceed();
|
||||
}
|
||||
|
||||
public function test_proceed_when_already_started() {
|
||||
$this->resetAfterTest(true);
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('shortname' => 'test', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->setExpectedException('coding_exception');
|
||||
$co->proceed();
|
||||
}
|
||||
|
||||
public function test_invalid_shortname() {
|
||||
$this->resetAfterTest(true);
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('shortname' => '<invalid>', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('invalidshortname', $co->get_errors());
|
||||
}
|
||||
|
||||
public function test_create() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Existing course.
|
||||
$c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1', 'summary' => 'Yay!'));
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
|
||||
// Try to add a new course.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$data = array('shortname' => 'newcourse', 'fullname' => 'New course', 'summary' => 'New', 'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'newcourse')));
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'newcourse')));
|
||||
|
||||
// Try to add a new course, that already exists.
|
||||
$coursecount = $DB->count_records('course', array());
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$data = array('shortname' => 'c1', 'fullname' => 'C1FN', 'summary' => 'C1', 'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('courseexistsanduploadnotallowed', $co->get_errors());
|
||||
$this->assertEquals($coursecount, $DB->count_records('course', array()));
|
||||
$this->assertNotEquals('C1', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
|
||||
|
||||
// Try to add new with shortname incrementation.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
|
||||
$data = array('shortname' => 'c1', 'fullname' => 'C1FN', 'summary' => 'C1', 'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c2')));
|
||||
}
|
||||
|
||||
public function test_delete() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c2 = $this->getDataGenerator()->create_course();
|
||||
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname)));
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'DoesNotExist')));
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
|
||||
// Try delete when option not available.
|
||||
$importoptions = array('candelete' => false);
|
||||
$data = array('shortname' => $c1->shortname, 'delete' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('coursedeletionnotallowed', $co->get_errors());
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname)));
|
||||
|
||||
// Try delete when not requested.
|
||||
$importoptions = array('candelete' => true);
|
||||
$data = array('shortname' => $c1->shortname, 'delete' => 0);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => $c1->shortname)));
|
||||
|
||||
// Try delete when requested.
|
||||
$importoptions = array('candelete' => true);
|
||||
$data = array('shortname' => $c1->shortname, 'delete' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => $c1->shortname)));
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => $c2->shortname)));
|
||||
|
||||
// Try deleting non-existing record, this should not fail.
|
||||
$data = array('shortname' => 'DoesNotExist', 'delete' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('cannotdeletecoursenotexist', $co->get_errors());
|
||||
}
|
||||
|
||||
public function test_update() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1'));
|
||||
|
||||
// Try to update with existing shortnames, not allowing creation, and updating nothing.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('shortname' => 'c1', 'fullname' => 'New fullname');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('updatemodedoessettonothing', $co->get_errors());
|
||||
|
||||
// Try to update with non-existing shortnames.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'DoesNotExist', 'fullname' => 'New fullname');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('coursedoesnotexistandcreatenotallowed', $co->get_errors());
|
||||
|
||||
// Try a proper update.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'c1', 'fullname' => 'New fullname');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('New fullname', $DB->get_field_select('course', 'fullname', 'shortname = :s', array('s' => 'c1')));
|
||||
|
||||
// Try a proper update with defaults.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
|
||||
$data = array('shortname' => 'c1', 'fullname' => 'Another fullname');
|
||||
$defaults = array('fullname' => 'Not this one', 'summary' => 'Awesome summary');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('Another fullname', $DB->get_field_select('course', 'fullname', 'shortname = :s', array('s' => 'c1')));
|
||||
$this->assertEquals('Awesome summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
|
||||
|
||||
// Try a proper update missing only.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS;
|
||||
$DB->set_field('course', 'summary', '', array('shortname' => 'c1'));
|
||||
$this->assertEquals('', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
|
||||
$data = array('shortname' => 'c1', 'summary' => 'Fill in summary');
|
||||
$defaults = array('summary' => 'Do not use this summary');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('Fill in summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
|
||||
|
||||
// Try a proper update missing only using defaults.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_MISSING_WITH_DATA_OR_DEFAUTLS;
|
||||
$DB->set_field('course', 'summary', '', array('shortname' => 'c1'));
|
||||
$this->assertEquals('', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
|
||||
$data = array('shortname' => 'c1');
|
||||
$defaults = array('summary' => 'Use this summary');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaults);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('Use this summary', $DB->get_field_select('course', 'summary', 'shortname = :s', array('s' => 'c1')));
|
||||
}
|
||||
|
||||
public function test_data_saved() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array(
|
||||
'shortname' => 'c1',
|
||||
'fullname' => 'Fullname',
|
||||
'category' => '1',
|
||||
'visible' => '0',
|
||||
'startdate' => '8 June 1990',
|
||||
'idnumber' => '123abc',
|
||||
'summary' => 'Summary',
|
||||
'format' => 'weeks',
|
||||
'theme' => 'afterburner',
|
||||
'lang' => 'en',
|
||||
'newsitems' => '7',
|
||||
'showgrades' => '0',
|
||||
'showreports' => '1',
|
||||
'legacyfiles' => '1',
|
||||
'maxbytes' => '1234',
|
||||
'groupmode' => '2',
|
||||
'groupmodeforce' => '1',
|
||||
'enablecompletion' => '1',
|
||||
|
||||
'role_teacher' => 'Knight',
|
||||
'role_manager' => 'Jedi',
|
||||
|
||||
'enrolment_1' => 'guest',
|
||||
'enrolment_2' => 'self',
|
||||
'enrolment_2_roleid' => '1',
|
||||
'enrolment_3' => 'manual',
|
||||
'enrolment_3_disable' => '1',
|
||||
);
|
||||
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$course = $DB->get_record('course', array('shortname' => 'c1'));
|
||||
$ctx = context_course::instance($course->id);
|
||||
|
||||
$this->assertEquals($data['fullname'], $course->fullname);
|
||||
$this->assertEquals($data['category'], $course->category);
|
||||
$this->assertEquals($data['visible'], $course->visible);
|
||||
$this->assertEquals(mktime(0, 0, 0, 6, 8, 1990), $course->startdate);
|
||||
$this->assertEquals($data['idnumber'], $course->idnumber);
|
||||
$this->assertEquals($data['summary'], $course->summary);
|
||||
$this->assertEquals($data['format'], $course->format);
|
||||
$this->assertEquals($data['theme'], $course->theme);
|
||||
$this->assertEquals($data['lang'], $course->lang);
|
||||
$this->assertEquals($data['newsitems'], $course->newsitems);
|
||||
$this->assertEquals($data['showgrades'], $course->showgrades);
|
||||
$this->assertEquals($data['showreports'], $course->showreports);
|
||||
$this->assertEquals($data['legacyfiles'], $course->legacyfiles);
|
||||
$this->assertEquals($data['maxbytes'], $course->maxbytes);
|
||||
$this->assertEquals($data['groupmode'], $course->groupmode);
|
||||
$this->assertEquals($data['groupmodeforce'], $course->groupmodeforce);
|
||||
$this->assertEquals($data['enablecompletion'], $course->enablecompletion);
|
||||
|
||||
// Roles.
|
||||
$roleids = array();
|
||||
$roles = get_all_roles();
|
||||
foreach ($roles as $role) {
|
||||
$roleids[$role->shortname] = $role->id;
|
||||
}
|
||||
$this->assertEquals('Knight', $DB->get_field_select('role_names', 'name',
|
||||
'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['teacher'])));
|
||||
$this->assertEquals('Jedi', $DB->get_field_select('role_names', 'name',
|
||||
'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['manager'])));
|
||||
|
||||
// Enrolment methods.
|
||||
$enroldata = array();
|
||||
$instances = enrol_get_instances($course->id, false);
|
||||
$this->assertCount(3, $instances);
|
||||
foreach ($instances as $instance) {
|
||||
$enroldata[$instance->enrol] = $instance;
|
||||
}
|
||||
|
||||
$this->assertNotEmpty($enroldata['guest']);
|
||||
$this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['guest']->status);
|
||||
$this->assertNotEmpty($enroldata['self']);
|
||||
$this->assertEquals($data['enrolment_2_roleid'], $enroldata['self']->roleid);
|
||||
$this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['self']->status);
|
||||
$this->assertNotEmpty($enroldata['manual']);
|
||||
$this->assertEquals(ENROL_INSTANCE_DISABLED, $enroldata['manual']->status);
|
||||
|
||||
// Update existing course.
|
||||
$cat = $this->getDataGenerator()->create_category();
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array(
|
||||
'shortname' => 'c1',
|
||||
'fullname' => 'Fullname 2',
|
||||
'category' => $cat->id,
|
||||
'visible' => '1',
|
||||
'startdate' => '11 June 1984',
|
||||
'idnumber' => 'changeidn',
|
||||
'summary' => 'Summary 2',
|
||||
'format' => 'topics',
|
||||
'theme' => 'clean',
|
||||
'lang' => '',
|
||||
'newsitems' => '2',
|
||||
'showgrades' => '1',
|
||||
'showreports' => '0',
|
||||
'legacyfiles' => '0',
|
||||
'maxbytes' => '4321',
|
||||
'groupmode' => '1',
|
||||
'groupmodeforce' => '0',
|
||||
'enablecompletion' => '0',
|
||||
|
||||
'role_teacher' => 'Teacher',
|
||||
'role_manager' => 'Manager',
|
||||
|
||||
'enrolment_1' => 'guest',
|
||||
'enrolment_1_disable' => '1',
|
||||
'enrolment_2' => 'self',
|
||||
'enrolment_2_roleid' => '2',
|
||||
'enrolment_3' => 'manual',
|
||||
'enrolment_3_delete' => '1',
|
||||
);
|
||||
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$course = $DB->get_record('course', array('shortname' => 'c1'));
|
||||
$ctx = context_course::instance($course->id);
|
||||
|
||||
$this->assertEquals($data['fullname'], $course->fullname);
|
||||
$this->assertEquals($data['category'], $course->category);
|
||||
$this->assertEquals($data['visible'], $course->visible);
|
||||
$this->assertEquals(mktime(0, 0, 0, 6, 11, 1984), $course->startdate);
|
||||
$this->assertEquals($data['idnumber'], $course->idnumber);
|
||||
$this->assertEquals($data['summary'], $course->summary);
|
||||
$this->assertEquals($data['format'], $course->format);
|
||||
$this->assertEquals($data['theme'], $course->theme);
|
||||
$this->assertEquals($data['lang'], $course->lang);
|
||||
$this->assertEquals($data['newsitems'], $course->newsitems);
|
||||
$this->assertEquals($data['showgrades'], $course->showgrades);
|
||||
$this->assertEquals($data['showreports'], $course->showreports);
|
||||
$this->assertEquals($data['legacyfiles'], $course->legacyfiles);
|
||||
$this->assertEquals($data['maxbytes'], $course->maxbytes);
|
||||
$this->assertEquals($data['groupmode'], $course->groupmode);
|
||||
$this->assertEquals($data['groupmodeforce'], $course->groupmodeforce);
|
||||
$this->assertEquals($data['enablecompletion'], $course->enablecompletion);
|
||||
|
||||
// Roles.
|
||||
$roleids = array();
|
||||
$roles = get_all_roles();
|
||||
foreach ($roles as $role) {
|
||||
$roleids[$role->shortname] = $role->id;
|
||||
}
|
||||
$this->assertEquals('Teacher', $DB->get_field_select('role_names', 'name',
|
||||
'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['teacher'])));
|
||||
$this->assertEquals('Manager', $DB->get_field_select('role_names', 'name',
|
||||
'roleid = :roleid AND contextid = :ctxid', array('ctxid' => $ctx->id, 'roleid' => $roleids['manager'])));
|
||||
|
||||
// Enrolment methods.
|
||||
$enroldata = array();
|
||||
$instances = enrol_get_instances($course->id, false);
|
||||
$this->assertCount(2, $instances);
|
||||
foreach ($instances as $instance) {
|
||||
$enroldata[$instance->enrol] = $instance;
|
||||
}
|
||||
|
||||
$this->assertNotEmpty($enroldata['guest']);
|
||||
$this->assertEquals(ENROL_INSTANCE_DISABLED, $enroldata['guest']->status);
|
||||
$this->assertNotEmpty($enroldata['self']);
|
||||
$this->assertEquals($data['enrolment_2_roleid'], $enroldata['self']->roleid);
|
||||
$this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['self']->status);
|
||||
}
|
||||
|
||||
public function test_default_data_saved() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array(
|
||||
'shortname' => 'c1',
|
||||
);
|
||||
$defaultdata = array(
|
||||
'fullname' => 'Fullname',
|
||||
'category' => '1',
|
||||
'visible' => '0',
|
||||
'startdate' => '8 June 1990',
|
||||
'idnumber' => '123abc',
|
||||
'summary' => 'Summary',
|
||||
'format' => 'weeks',
|
||||
'theme' => 'afterburner',
|
||||
'lang' => 'en',
|
||||
'newsitems' => '7',
|
||||
'showgrades' => '0',
|
||||
'showreports' => '1',
|
||||
'legacyfiles' => '1',
|
||||
'maxbytes' => '1234',
|
||||
'groupmode' => '2',
|
||||
'groupmodeforce' => '1',
|
||||
'enablecompletion' => '1',
|
||||
);
|
||||
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$course = $DB->get_record('course', array('shortname' => 'c1'));
|
||||
$ctx = context_course::instance($course->id);
|
||||
|
||||
$this->assertEquals($defaultdata['fullname'], $course->fullname);
|
||||
$this->assertEquals($defaultdata['category'], $course->category);
|
||||
$this->assertEquals($defaultdata['visible'], $course->visible);
|
||||
$this->assertEquals(mktime(0, 0, 0, 6, 8, 1990), $course->startdate);
|
||||
$this->assertEquals($defaultdata['idnumber'], $course->idnumber);
|
||||
$this->assertEquals($defaultdata['summary'], $course->summary);
|
||||
$this->assertEquals($defaultdata['format'], $course->format);
|
||||
$this->assertEquals($defaultdata['theme'], $course->theme);
|
||||
$this->assertEquals($defaultdata['lang'], $course->lang);
|
||||
$this->assertEquals($defaultdata['newsitems'], $course->newsitems);
|
||||
$this->assertEquals($defaultdata['showgrades'], $course->showgrades);
|
||||
$this->assertEquals($defaultdata['showreports'], $course->showreports);
|
||||
$this->assertEquals($defaultdata['legacyfiles'], $course->legacyfiles);
|
||||
$this->assertEquals($defaultdata['maxbytes'], $course->maxbytes);
|
||||
$this->assertEquals($defaultdata['groupmode'], $course->groupmode);
|
||||
$this->assertEquals($defaultdata['groupmodeforce'], $course->groupmodeforce);
|
||||
$this->assertEquals($defaultdata['enablecompletion'], $course->enablecompletion);
|
||||
|
||||
// Update.
|
||||
$cat = $this->getDataGenerator()->create_category();
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
|
||||
$data = array(
|
||||
'shortname' => 'c1',
|
||||
);
|
||||
$defaultdata = array(
|
||||
'fullname' => 'Fullname 2',
|
||||
'category' => $cat->id,
|
||||
'visible' => '1',
|
||||
'startdate' => '11 June 1984',
|
||||
'idnumber' => 'changedid',
|
||||
'summary' => 'Summary 2',
|
||||
'format' => 'topics',
|
||||
'theme' => 'clean',
|
||||
'lang' => '',
|
||||
'newsitems' => '2',
|
||||
'showgrades' => '1',
|
||||
'showreports' => '0',
|
||||
'legacyfiles' => '0',
|
||||
'maxbytes' => '1111',
|
||||
'groupmode' => '1',
|
||||
'groupmodeforce' => '0',
|
||||
'enablecompletion' => '0',
|
||||
);
|
||||
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$course = $DB->get_record('course', array('shortname' => 'c1'));
|
||||
$ctx = context_course::instance($course->id);
|
||||
|
||||
$this->assertEquals($defaultdata['fullname'], $course->fullname);
|
||||
$this->assertEquals($defaultdata['category'], $course->category);
|
||||
$this->assertEquals($defaultdata['visible'], $course->visible);
|
||||
$this->assertEquals(mktime(0, 0, 0, 6, 11, 1984), $course->startdate);
|
||||
$this->assertEquals($defaultdata['idnumber'], $course->idnumber);
|
||||
$this->assertEquals($defaultdata['summary'], $course->summary);
|
||||
$this->assertEquals($defaultdata['format'], $course->format);
|
||||
$this->assertEquals($defaultdata['theme'], $course->theme);
|
||||
$this->assertEquals($defaultdata['lang'], $course->lang);
|
||||
$this->assertEquals($defaultdata['newsitems'], $course->newsitems);
|
||||
$this->assertEquals($defaultdata['showgrades'], $course->showgrades);
|
||||
$this->assertEquals($defaultdata['showreports'], $course->showreports);
|
||||
$this->assertEquals($defaultdata['legacyfiles'], $course->legacyfiles);
|
||||
$this->assertEquals($defaultdata['maxbytes'], $course->maxbytes);
|
||||
$this->assertEquals($defaultdata['groupmode'], $course->groupmode);
|
||||
$this->assertEquals($defaultdata['groupmodeforce'], $course->groupmodeforce);
|
||||
$this->assertEquals($defaultdata['enablecompletion'], $course->enablecompletion);
|
||||
}
|
||||
|
||||
public function test_rename() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course(array('shortname' => 'c1'));
|
||||
$c2 = $this->getDataGenerator()->create_course(array('shortname' => 'c2'));
|
||||
|
||||
// Cannot rename when creating.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'c1', 'rename' => 'newshortname');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('courseexistsanduploadnotallowed', $co->get_errors());
|
||||
|
||||
// Cannot rename when creating.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'c1', 'rename' => 'newshortname', 'category' => 1, 'summary' => 'S', 'fullname' => 'F');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('canonlyrenameinupdatemode', $co->get_errors());
|
||||
|
||||
// Error when not allowed to rename the course.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => false);
|
||||
$data = array('shortname' => 'c1', 'rename' => 'newshortname');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('courserenamingnotallowed', $co->get_errors());
|
||||
|
||||
// Can rename when updating.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'c1', 'rename' => 'newshortname');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('newshortname', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id)));
|
||||
|
||||
// Can rename when updating.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'newshortname', 'rename' => 'newshortname2');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('newshortname2', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id)));
|
||||
|
||||
// Error when course does not exist.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'DoesNotExist', 'rename' => 'c1', 'category' => 1, 'summary' => 'S', 'fullname' => 'F');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('cannotrenamecoursenotexist', $co->get_errors());
|
||||
|
||||
// Renaming still updates the other values.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_OR_DEFAUTLS;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'newshortname2', 'rename' => 'c1', 'fullname' => 'Another fullname!');
|
||||
$defaultdata = array('summary' => 'New summary!');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, $defaultdata, $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertEquals('c1', $DB->get_field_select('course', 'shortname', 'id = :id', array('id' => $c1->id)));
|
||||
$this->assertEquals('New summary!', $DB->get_field_select('course', 'summary', 'id = :id', array('id' => $c1->id)));
|
||||
$this->assertEquals('Another fullname!', $DB->get_field_select('course', 'fullname', 'id = :id', array('id' => $c1->id)));
|
||||
|
||||
// Renaming with invalid shortname.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'c1', 'rename' => '<span>invalid</span>');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('invalidshortname', $co->get_errors());
|
||||
|
||||
// Renaming with invalid shortname.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_OR_UPDATE;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$importoptions = array('canrename' => true);
|
||||
$data = array('shortname' => 'c1', 'rename' => 'c2');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('cannotrenameshortnamealreadyinuse', $co->get_errors());
|
||||
}
|
||||
|
||||
public function test_restore_course() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id));
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'A1', 'templatecourse' => $c1->shortname, 'summary' => 'A', 'category' => 1,
|
||||
'fullname' => 'A1');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$course = $DB->get_record('course', array('shortname' => 'A1'));
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$found = false;
|
||||
foreach ($modinfo->get_cms() as $cmid => $cm) {
|
||||
if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found);
|
||||
|
||||
// Restore the time limit to prevent warning.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
public function test_restore_file() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id));
|
||||
|
||||
// Restore from a file, checking that the file takes priority over the templatecourse.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'A1', 'backupfile' => __DIR__ . '/fixtures/backup.mbz',
|
||||
'summary' => 'A', 'category' => 1, 'fullname' => 'A1', 'templatecourse' => $c1->shortname);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$course = $DB->get_record('course', array('shortname' => 'A1'));
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$found = false;
|
||||
foreach ($modinfo->get_cms() as $cmid => $cm) {
|
||||
if ($cm->modname == 'glossary' && $cm->name == 'Imported Glossary') {
|
||||
$found = true;
|
||||
} else if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
|
||||
// We should not find this!
|
||||
$this->assertTrue(false);
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found);
|
||||
|
||||
// Restore the time limit to prevent warning.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the reset on groups, group members and enrolments.
|
||||
*/
|
||||
public function test_reset() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c1ctx = context_course::instance($c1->id);
|
||||
$studentrole = $DB->get_record('role', array('shortname' => 'student'));
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
|
||||
|
||||
$u1 = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($u1->id, $c1->id, $studentrole->id);
|
||||
$this->assertCount(1, get_enrolled_users($c1ctx));
|
||||
|
||||
$g1 = $this->getDataGenerator()->create_group(array('courseid' => $c1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $g1->id, 'userid' => $u1->id));
|
||||
$this->assertEquals(1, $DB->count_records('groups', array('courseid' => $c1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
|
||||
|
||||
// Wrong mode.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'DoesNotExist', 'reset' => '1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('canonlyresetcourseinupdatemode', $co->get_errors());
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
|
||||
$this->assertCount(1, get_enrolled_users($c1ctx));
|
||||
|
||||
// Reset not allowed.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c1->shortname, 'reset' => '1');
|
||||
$importoptions = array('canreset' => false);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('courseresetnotallowed', $co->get_errors());
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
|
||||
$this->assertCount(1, get_enrolled_users($c1ctx));
|
||||
|
||||
// Reset allowed but not requested.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c1->shortname, 'reset' => '0');
|
||||
$importoptions = array('canreset' => true);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
|
||||
$this->assertCount(1, get_enrolled_users($c1ctx));
|
||||
|
||||
// Reset passed as a default parameter, should not be taken in account.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c1->shortname);
|
||||
$importoptions = array('canreset' => true);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array('reset' => 1), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertTrue($DB->record_exists('groups', array('id' => $g1->id)));
|
||||
$this->assertTrue($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
|
||||
$this->assertCount(1, get_enrolled_users($c1ctx));
|
||||
|
||||
// Reset executed from data.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c1->shortname, 'reset' => 1);
|
||||
$importoptions = array('canreset' => true);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertFalse($DB->record_exists('groups', array('id' => $g1->id)));
|
||||
$this->assertFalse($DB->record_exists('groups_members', array('groupid' => $g1->id, 'userid' => $u1->id)));
|
||||
$this->assertCount(0, get_enrolled_users($c1ctx));
|
||||
|
||||
// Reset executed from import option.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c1->shortname, 'reset' => 0);
|
||||
$importoptions = array('reset' => 1, 'canreset' => true);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
|
||||
$g1 = $this->getDataGenerator()->create_group(array('courseid' => $c1->id));
|
||||
$this->getDataGenerator()->create_group_member(array('groupid' => $g1->id, 'userid' => $u1->id));
|
||||
$this->assertEquals(1, $DB->count_records('groups', array('courseid' => $c1->id)));
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
$this->assertFalse($DB->record_exists('groups', array('id' => $g1->id)));
|
||||
}
|
||||
|
||||
public function test_create_bad_category() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Ensure fails when category cannot be resolved upon creation.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'c1', 'summary' => 'summary', 'fullname' => 'FN', 'category' => 'Wrong cat');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('couldnotresolvecatgorybyid', $co->get_errors());
|
||||
|
||||
// Ensure fails when category cannot be resolved upon update.
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c1->shortname, 'category' => 'Wrong cat');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('couldnotresolvecatgorybyid', $co->get_errors());
|
||||
}
|
||||
|
||||
public function test_enrolment_data() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'c1', 'summary' => 'S', 'fullname' => 'FN', 'category' => '1');
|
||||
$data['enrolment_1'] = 'manual';
|
||||
$data['enrolment_1_role'] = 'teacher';
|
||||
$data['enrolment_1_startdate'] = '2nd July 2013';
|
||||
$data['enrolment_1_enddate'] = '2nd August 2013';
|
||||
$data['enrolment_1_enrolperiod'] = '10 days';
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertTrue($co->prepare());
|
||||
$co->proceed();
|
||||
|
||||
// Enrolment methods.
|
||||
$enroldata = array();
|
||||
$instances = enrol_get_instances($co->get_id(), false);
|
||||
foreach ($instances as $instance) {
|
||||
$enroldata[$instance->enrol] = $instance;
|
||||
}
|
||||
|
||||
$this->assertNotEmpty($enroldata['manual']);
|
||||
$this->assertEquals(ENROL_INSTANCE_ENABLED, $enroldata['manual']->status);
|
||||
$this->assertEquals(strtotime($data['enrolment_1_startdate']), $enroldata['manual']->enrolstartdate);
|
||||
$this->assertEquals(strtotime('1970-01-01 GMT + ' . $data['enrolment_1_enrolperiod']), $enroldata['manual']->enrolperiod);
|
||||
$this->assertEquals(strtotime('12th July 2013'), $enroldata['manual']->enrolenddate);
|
||||
}
|
||||
|
||||
public function test_idnumber_problems() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course(array('shortname' => 'sntaken', 'idnumber' => 'taken'));
|
||||
$c2 = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create with existing ID number.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => 'c2', 'summary' => 'summary', 'fullname' => 'FN', 'category' => '1',
|
||||
'idnumber' => $c1->idnumber);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('idnumberalreadyinuse', $co->get_errors());
|
||||
|
||||
// Rename to existing ID number.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('shortname' => $c2->shortname, 'rename' => 'SN', 'idnumber' => $c1->idnumber);
|
||||
$importoptions = array('canrename' => true);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('cannotrenameidnumberconflict', $co->get_errors());
|
||||
|
||||
// Incrementing shortname increments idnumber.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('shortname' => $c1->shortname, 'idnumber' => $c1->idnumber, 'summary' => 'S', 'fullname' => 'F',
|
||||
'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array());
|
||||
$this->assertTrue($co->prepare());
|
||||
$this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses());
|
||||
$this->assertArrayHasKey('courseidnumberincremented', $co->get_statuses());
|
||||
$data = $co->get_data();
|
||||
$this->assertEquals('sntaken_2', $data['shortname']);
|
||||
$this->assertEquals('taken_2', $data['idnumber']);
|
||||
|
||||
// Incrementing shortname increments idnumber unless available.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('shortname' => $c1->shortname, 'idnumber' => 'nottaken', 'summary' => 'S', 'fullname' => 'F',
|
||||
'category' => 1);
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array());
|
||||
$this->assertTrue($co->prepare());
|
||||
$this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses());
|
||||
$this->assertArrayNotHasKey('courseidnumberincremented', $co->get_statuses());
|
||||
$data = $co->get_data();
|
||||
$this->assertEquals('sntaken_2', $data['shortname']);
|
||||
$this->assertEquals('nottaken', $data['idnumber']);
|
||||
}
|
||||
|
||||
public function test_generate_shortname() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course(array('shortname' => 'taken'));
|
||||
|
||||
// Generate a shortname.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1', 'idnumber' => 'IDN');
|
||||
$importoptions = array('shortnametemplate' => '%i');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses());
|
||||
|
||||
// Generate a shortname without a template.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), array());
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('missingshortnamenotemplate', $co->get_errors());
|
||||
|
||||
// Generate a shortname in update mode.
|
||||
$mode = tool_uploadcourse_processor::MODE_UPDATE_ONLY;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_ALL_WITH_DATA_ONLY;
|
||||
$data = array('summary' => 'summary', 'fullname' => 'FN', 'category' => '1');
|
||||
$importoptions = array('shortnametemplate' => '%f');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
// Commented because we never get here as the course without shortname does not exist.
|
||||
// $this->assertArrayHasKey('cannotgenerateshortnameupdatemode', $co->get_errors());
|
||||
|
||||
// Generate a shortname to a course that already exists.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1');
|
||||
$importoptions = array('shortnametemplate' => '%f');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertFalse($co->prepare());
|
||||
$this->assertArrayHasKey('generatedshortnamealreadyinuse', $co->get_errors());
|
||||
|
||||
// Generate a shortname to a course that already exists will be incremented.
|
||||
$mode = tool_uploadcourse_processor::MODE_CREATE_ALL;
|
||||
$updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
|
||||
$data = array('summary' => 'summary', 'fullname' => 'taken', 'category' => '1');
|
||||
$importoptions = array('shortnametemplate' => '%f');
|
||||
$co = new tool_uploadcourse_course($mode, $updatemode, $data, array(), $importoptions);
|
||||
$this->assertTrue($co->prepare());
|
||||
$this->assertArrayHasKey('courseshortnamegenerated', $co->get_statuses());
|
||||
$this->assertArrayHasKey('courseshortnameincremented', $co->get_statuses());
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
shortname,fullname,summary,category,idnumber
|
||||
C1,Course 1,Summary 1,1,ID1
|
||||
C2,Course 2,Summary 2,1,ID2
|
||||
C3,Course 3,Summary 3,1,ID3
|
||||
|
@@ -0,0 +1,389 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing tests for the helper.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
/**
|
||||
* Helper test case.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_helper_testcase extends advanced_testcase {
|
||||
|
||||
public function test_generate_shortname() {
|
||||
$data = (object) array('fullname' => 'Ah bh Ch 01 02 03', 'idnumber' => 'ID123');
|
||||
|
||||
$this->assertSame($data->fullname, tool_uploadcourse_helper::generate_shortname($data, '%f'));
|
||||
$this->assertSame($data->idnumber, tool_uploadcourse_helper::generate_shortname($data, '%i'));
|
||||
$this->assertSame('Ah Bh Ch', tool_uploadcourse_helper::generate_shortname($data, '%~8f'));
|
||||
$this->assertSame('AH BH CH', tool_uploadcourse_helper::generate_shortname($data, '%+8f'));
|
||||
$this->assertSame('id123', tool_uploadcourse_helper::generate_shortname($data, '%-i'));
|
||||
$this->assertSame('[Ah bh Ch] = ID123', tool_uploadcourse_helper::generate_shortname($data, '[%8f] = %i'));
|
||||
$this->assertSame('0', tool_uploadcourse_helper::generate_shortname($data, '0'));
|
||||
$this->assertSame('%unknown', tool_uploadcourse_helper::generate_shortname($data, '%unknown'));
|
||||
|
||||
$this->assertNull(tool_uploadcourse_helper::generate_shortname($data, ''));
|
||||
$this->assertNull(tool_uploadcourse_helper::generate_shortname(array(), '%f'));
|
||||
}
|
||||
|
||||
public function test_get_course_formats() {
|
||||
$result = tool_uploadcourse_helper::get_course_formats();
|
||||
$this->assertSame(array_keys(get_plugin_list('format')), $result);
|
||||
// Should be similar as first result, as cached.
|
||||
$this->assertSame($result, tool_uploadcourse_helper::get_course_formats());
|
||||
}
|
||||
|
||||
public function test_get_enrolment_data() {
|
||||
$this->resetAfterTest(true);
|
||||
$data = array(
|
||||
'enrolment_1' => 'unknown',
|
||||
'enrolment_1_foo' => '1',
|
||||
'enrolment_1_bar' => '2',
|
||||
'enrolment_2' => 'self',
|
||||
'enrolment_2_delete' => '1',
|
||||
'enrolment_2_foo' => 'a',
|
||||
'enrolment_2_bar' => '1',
|
||||
'enrolment_3' => 'manual',
|
||||
'enrolment_3_disable' => '2',
|
||||
'enrolment_3_foo' => 'b',
|
||||
'enrolment_3_bar' => '2',
|
||||
'enrolment_4' => 'database',
|
||||
'enrolment_4_foo' => 'x',
|
||||
'enrolment_4_bar' => '3',
|
||||
'enrolment_5_test3' => 'test3',
|
||||
'enrolment_5_test2' => 'test2',
|
||||
'enrolment_5_test1' => 'test1',
|
||||
'enrolment_5' => 'flatfile',
|
||||
);
|
||||
$expected = array(
|
||||
'self' => array(
|
||||
'delete' => '1',
|
||||
'foo' => 'a',
|
||||
'bar' => '1',
|
||||
),
|
||||
'manual' => array(
|
||||
'disable' => '2',
|
||||
'foo' => 'b',
|
||||
'bar' => '2',
|
||||
),
|
||||
'database' => array(
|
||||
'foo' => 'x',
|
||||
'bar' => '3',
|
||||
),
|
||||
'flatfile' => array(
|
||||
'test3' => 'test3',
|
||||
'test2' => 'test2',
|
||||
'test1' => 'test1',
|
||||
)
|
||||
);
|
||||
$this->assertSame(tool_uploadcourse_helper::get_enrolment_data($data), $expected);
|
||||
}
|
||||
|
||||
public function test_get_enrolment_plugins() {
|
||||
$this->resetAfterTest(true);
|
||||
$actual = tool_uploadcourse_helper::get_enrolment_plugins();
|
||||
$this->assertSame(array_keys(enrol_get_plugins(false)), array_keys($actual));
|
||||
// This should be identical as cached.
|
||||
$secondactual = tool_uploadcourse_helper::get_enrolment_plugins();
|
||||
$this->assertEquals($actual, $secondactual);
|
||||
}
|
||||
|
||||
public function test_get_restore_content_dir() {
|
||||
global $CFG;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c2 = $this->getDataGenerator()->create_course((object) array('shortname' => 'Yay'));
|
||||
|
||||
// Creating backup file.
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $c1->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2);
|
||||
$bc->execute_plan();
|
||||
$result = $bc->get_results();
|
||||
$this->assertTrue(isset($result['backup_destination']));
|
||||
$c1backupfile = $result['backup_destination']->copy_content_to_temp();
|
||||
$bc->destroy();
|
||||
|
||||
// Creating backup file.
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $c2->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_GENERAL, 2);
|
||||
$bc->execute_plan();
|
||||
$result = $bc->get_results();
|
||||
$this->assertTrue(isset($result['backup_destination']));
|
||||
$c2backupfile = $result['backup_destination']->copy_content_to_temp();
|
||||
$bc->destroy();
|
||||
|
||||
// Checking restore dir.
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir($c1backupfile, null);
|
||||
$bcinfo = backup_general_helper::get_backup_information($dir);
|
||||
$this->assertEquals($bcinfo->original_course_id, $c1->id);
|
||||
$this->assertEquals($bcinfo->original_course_fullname, $c1->fullname);
|
||||
|
||||
// Do it again, it should be the same directory.
|
||||
$dir2 = tool_uploadcourse_helper::get_restore_content_dir($c1backupfile, null);
|
||||
$this->assertEquals($dir, $dir2);
|
||||
|
||||
// Get the second course.
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir($c2backupfile, null);
|
||||
$bcinfo = backup_general_helper::get_backup_information($dir);
|
||||
$this->assertEquals($bcinfo->original_course_id, $c2->id);
|
||||
$this->assertEquals($bcinfo->original_course_fullname, $c2->fullname);
|
||||
|
||||
// Checking with a shortname.
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir(null, $c1->shortname);
|
||||
$bcinfo = backup_general_helper::get_backup_information($dir);
|
||||
$this->assertEquals($bcinfo->original_course_id, $c1->id);
|
||||
$this->assertEquals($bcinfo->original_course_fullname, $c1->fullname);
|
||||
|
||||
// Do it again, it should be the same directory.
|
||||
$dir2 = tool_uploadcourse_helper::get_restore_content_dir(null, $c1->shortname);
|
||||
$this->assertEquals($dir, $dir2);
|
||||
|
||||
// Get the second course.
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir(null, $c2->shortname);
|
||||
$bcinfo = backup_general_helper::get_backup_information($dir);
|
||||
$this->assertEquals($bcinfo->original_course_id, $c2->id);
|
||||
$this->assertEquals($bcinfo->original_course_fullname, $c2->fullname);
|
||||
|
||||
// Get a course that does not exist.
|
||||
$errors = array();
|
||||
$dir = tool_uploadcourse_helper::get_restore_content_dir(null, 'DoesNotExist', $errors);
|
||||
$this->assertFalse($dir);
|
||||
$this->assertArrayHasKey('coursetorestorefromdoesnotexist', $errors);
|
||||
|
||||
// Cleaning content directories.
|
||||
$oldcfg = isset($CFG->keeptempdirectoriesonbackup) ? $CFG->keeptempdirectoriesonbackup : false;
|
||||
$dir = "$CFG->tempdir/backup/$dir";
|
||||
$this->assertTrue(file_exists($dir));
|
||||
|
||||
$CFG->keeptempdirectoriesonbackup = false;
|
||||
tool_uploadcourse_helper::clean_restore_content();
|
||||
$this->assertTrue(file_exists($dir));
|
||||
|
||||
$CFG->keeptempdirectoriesonbackup = true;
|
||||
tool_uploadcourse_helper::clean_restore_content();
|
||||
$this->assertFalse(file_exists($dir));
|
||||
|
||||
$CFG->keeptempdirectoriesonbackup = $oldcfg;
|
||||
|
||||
// Restore the time limit to prevent warning.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
public function test_get_role_ids() {
|
||||
$this->getDataGenerator();
|
||||
// Mimic function result.
|
||||
$expected = array();
|
||||
$roles = get_all_roles();
|
||||
foreach ($roles as $role) {
|
||||
$expected[$role->shortname] = $role->id;
|
||||
}
|
||||
|
||||
$actual = tool_uploadcourse_helper::get_role_ids();
|
||||
$this->assertSame($actual, $expected);
|
||||
|
||||
// Check cache.
|
||||
$this->assertSame($actual, tool_uploadcourse_helper::get_role_ids());
|
||||
}
|
||||
|
||||
public function test_get_role_names() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
create_role('Villain', 'villain', 'The bad guys');
|
||||
$data = array(
|
||||
'role_student' => 'Padawan',
|
||||
'role_teacher' => 'Guardian',
|
||||
'role_editingteacher' => 'Knight',
|
||||
'role_manager' => 'Master',
|
||||
'role_villain' => 'Jabba the Hutt',
|
||||
'role_android' => 'R2D2',
|
||||
);
|
||||
|
||||
// Get the role IDs, but need to force the cache reset as a new role is defined.
|
||||
$roleids = tool_uploadcourse_helper::get_role_ids(true);
|
||||
|
||||
$expected = array(
|
||||
'role_' . $roleids['student'] => 'Padawan',
|
||||
'role_' . $roleids['teacher'] => 'Guardian',
|
||||
'role_' . $roleids['editingteacher'] => 'Knight',
|
||||
'role_' . $roleids['manager'] => 'Master',
|
||||
'role_' . $roleids['villain'] => 'Jabba the Hutt',
|
||||
);
|
||||
|
||||
$errors = array();
|
||||
$actual = tool_uploadcourse_helper::get_role_names($data, $errors);
|
||||
$this->assertSame($actual, $expected);
|
||||
$this->assertArrayHasKey('invalidroles', $errors);
|
||||
}
|
||||
|
||||
public function test_increment_idnumber() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course(array('idnumber' => 'C1'));
|
||||
$c2 = $this->getDataGenerator()->create_course(array('idnumber' => 'C2'));
|
||||
$c3 = $this->getDataGenerator()->create_course(array('idnumber' => 'Yo'));
|
||||
|
||||
$this->assertEquals('C3', tool_uploadcourse_helper::increment_idnumber('C1'));
|
||||
$this->assertEquals('Yo_2', tool_uploadcourse_helper::increment_idnumber('Yo'));
|
||||
$this->assertEquals('DoesNotExist', tool_uploadcourse_helper::increment_idnumber('DoesNotExist'));
|
||||
}
|
||||
|
||||
public function test_increment_shortname() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course(array('shortname' => 'C1'));
|
||||
$c2 = $this->getDataGenerator()->create_course(array('shortname' => 'C2'));
|
||||
$c3 = $this->getDataGenerator()->create_course(array('shortname' => 'Yo'));
|
||||
|
||||
// FYI: increment_shortname assumes that the course exists, and so increment the shortname immediately.
|
||||
$this->assertEquals('C3', tool_uploadcourse_helper::increment_shortname('C1'));
|
||||
$this->assertEquals('Yo_2', tool_uploadcourse_helper::increment_shortname('Yo'));
|
||||
$this->assertEquals('DoesNotExist_2', tool_uploadcourse_helper::increment_shortname('DoesNotExist'));
|
||||
}
|
||||
|
||||
public function test_resolve_category() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_category(array('name' => 'First level'));
|
||||
$c2 = $this->getDataGenerator()->create_category(array('name' => 'Second level', 'parent' => $c1->id));
|
||||
$c3 = $this->getDataGenerator()->create_category(array('idnumber' => 'C3'));
|
||||
|
||||
$data = array(
|
||||
'category' => $c1->id,
|
||||
'category_path' => $c1->name . ' / ' . $c2->name,
|
||||
'category_idnumber' => $c3->idnumber,
|
||||
);
|
||||
|
||||
$this->assertEquals($c1->id, tool_uploadcourse_helper::resolve_category($data));
|
||||
unset($data['category']);
|
||||
$this->assertEquals($c3->id, tool_uploadcourse_helper::resolve_category($data));
|
||||
unset($data['category_idnumber']);
|
||||
$this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category($data));
|
||||
|
||||
// Adding unexisting data.
|
||||
$errors = array();
|
||||
$data['category_idnumber'] = 1234;
|
||||
$this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category($data, $errors));
|
||||
$this->assertArrayHasKey('couldnotresolvecatgorybyidnumber', $errors);
|
||||
$errors = array();
|
||||
$data['category'] = 1234;
|
||||
$this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category($data, $errors));
|
||||
$this->assertArrayHasKey('couldnotresolvecatgorybyid', $errors);
|
||||
$errors = array();
|
||||
$data['category_path'] = 'Not exist';
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category($data, $errors));
|
||||
$this->assertArrayHasKey('couldnotresolvecatgorybypath', $errors);
|
||||
}
|
||||
|
||||
public function test_resolve_category_by_idnumber() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_category(array('idnumber' => 'C1'));
|
||||
$c2 = $this->getDataGenerator()->create_category(array('idnumber' => 'C2'));
|
||||
|
||||
// Doubled for cache check.
|
||||
$this->assertEquals($c1->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C1'));
|
||||
$this->assertEquals($c1->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C1'));
|
||||
$this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C2'));
|
||||
$this->assertEquals($c2->id, tool_uploadcourse_helper::resolve_category_by_idnumber('C2'));
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_idnumber('DoesNotExist'));
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_idnumber('DoesNotExist'));
|
||||
}
|
||||
|
||||
public function test_resolve_category_by_path() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$cat1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1'));
|
||||
$cat1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.1', 'parent' => $cat1->id));
|
||||
$cat1_1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.1.1', 'parent' => $cat1_1->id));
|
||||
$cat1_1_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.1.2', 'parent' => $cat1_1->id));
|
||||
$cat1_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 1.2', 'parent' => $cat1->id));
|
||||
|
||||
$cat2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2'));
|
||||
$cat2_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.1', 'parent' => $cat2->id, 'visible' => false));
|
||||
$cat2_1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.1.1', 'parent' => $cat2_1->id));
|
||||
$cat2_1_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.1.2', 'parent' => $cat2_1->id));
|
||||
$cat2_2 = $this->getDataGenerator()->create_category(array('name' => 'Cat 2.2', 'parent' => $cat2->id));
|
||||
|
||||
$cat3 = $this->getDataGenerator()->create_category(array('name' => 'Cat 3'));
|
||||
$cat3_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1 Doubled', 'parent' => $cat3->id));
|
||||
$cat3_1b = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1 Doubled', 'parent' => $cat3->id));
|
||||
$cat3_1_1 = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1.1', 'parent' => $cat3_1->id));
|
||||
$cat3_fakedouble = $this->getDataGenerator()->create_category(array('name' => 'Cat 3.1.1', 'parent' => $cat3->id));
|
||||
|
||||
// Existing categories. Doubled for cache testing.
|
||||
$path = array('Cat 1');
|
||||
$this->assertEquals($cat1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
$path = array('Cat 1', 'Cat 1.1', 'Cat 1.1.2');
|
||||
$this->assertEquals($cat1_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat1_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
$path = array('Cat 1', 'Cat 1.2');
|
||||
$this->assertEquals($cat1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
$path = array('Cat 2');
|
||||
$this->assertEquals($cat2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
// Hidden category.
|
||||
$path = array('Cat 2', 'Cat 2.1');
|
||||
$this->assertEquals($cat2_1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat2_1->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
// Hidden parent.
|
||||
$path = array('Cat 2', 'Cat 2.1', 'Cat 2.1.2');
|
||||
$this->assertEquals($cat2_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat2_1_2->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
// Does not exist.
|
||||
$path = array('No cat 3', 'Cat 1.2');
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
$path = array('Cat 2', 'Cat 2.x');
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
// Name conflict.
|
||||
$path = array('Cat 3', 'Cat 3.1 Doubled');
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
$path = array('Cat 3', 'Cat 3.1 Doubled', 'Cat 3.1.1');
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEmpty(tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
|
||||
$path = array('Cat 3', 'Cat 3.1.1');
|
||||
$this->assertEquals($cat3_fakedouble->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
$this->assertEquals($cat3_fakedouble->id, tool_uploadcourse_helper::resolve_category_by_path($path));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* File containing tests for the processor.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/csvlib.class.php');
|
||||
|
||||
/**
|
||||
* Processor test case.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2013 Frédéric Massart
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_uploadcourse_processor_testcase extends advanced_testcase {
|
||||
|
||||
public function test_basic() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$content = array(
|
||||
"shortname,fullname,summary",
|
||||
"c1,Course 1,Course 1 summary",
|
||||
"c2,Course 2,Course 2 summary",
|
||||
);
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
$defaults = array('category' => '1');
|
||||
|
||||
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'c2')));
|
||||
$p->execute();
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$this->assertTrue($DB->record_exists('course', array('shortname' => 'c2')));
|
||||
}
|
||||
|
||||
public function test_restore_template_course() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$c1 = $this->getDataGenerator()->create_course();
|
||||
$c1f1 = $this->getDataGenerator()->create_module('forum', array('course' => $c1->id));
|
||||
|
||||
$content = array(
|
||||
"shortname,fullname,summary",
|
||||
"c2,Course 2,Course 2 summary",
|
||||
);
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW, 'templatecourse' => $c1->shortname);
|
||||
$defaults = array('category' => '1');
|
||||
|
||||
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'c2')));
|
||||
$p->execute();
|
||||
$c2 = $DB->get_record('course', array('shortname' => 'c2'));
|
||||
$modinfo = get_fast_modinfo($c2);
|
||||
$found = false;
|
||||
foreach ($modinfo->get_cms() as $cmid => $cm) {
|
||||
if ($cm->modname == 'forum' && $cm->name == $c1f1->name) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found);
|
||||
|
||||
// Restore the time limit to prevent warning.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
public function test_restore_restore_file() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$content = array(
|
||||
"shortname,fullname,summary",
|
||||
"c1,Course 1,Course 1 summary",
|
||||
);
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array(
|
||||
'mode' => tool_uploadcourse_processor::MODE_CREATE_NEW,
|
||||
'restorefile' => __DIR__ . '/fixtures/backup.mbz',
|
||||
'templatecourse' => 'DoesNotExist' // Restorefile takes priority.
|
||||
);
|
||||
$defaults = array('category' => '1');
|
||||
|
||||
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
$this->assertFalse($DB->record_exists('course', array('shortname' => 'c1')));
|
||||
$p->execute();
|
||||
$c1 = $DB->get_record('course', array('shortname' => 'c1'));
|
||||
$modinfo = get_fast_modinfo($c1);
|
||||
$found = false;
|
||||
foreach ($modinfo->get_cms() as $cmid => $cm) {
|
||||
if ($cm->modname == 'glossary' && $cm->name == 'Imported Glossary') {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
$this->assertTrue($found);
|
||||
|
||||
// Restore the time limit to prevent warning.
|
||||
set_time_limit(0);
|
||||
}
|
||||
|
||||
public function test_shortname_template() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$content = array(
|
||||
"shortname,fullname,summary,idnumber",
|
||||
",Course 1,C1 Summary,ID123",
|
||||
);
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW, 'shortnametemplate' => '%i: %f');
|
||||
$defaults = array('category' => '1');
|
||||
|
||||
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
$this->assertFalse($DB->record_exists('course', array('idnumber' => 'ID123')));
|
||||
$p->execute();
|
||||
$this->assertTrue($DB->record_exists('course', array('idnumber' => 'ID123')));
|
||||
$c = $DB->get_record('course', array('idnumber' => 'ID123'));
|
||||
$this->assertEquals('ID123: Course 1', $c->shortname);
|
||||
}
|
||||
|
||||
public function test_empty_csv() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$content = array();
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$this->setExpectedException('moodle_exception');
|
||||
$p = new tool_uploadcourse_processor($cir, $options, array());
|
||||
}
|
||||
|
||||
public function test_not_enough_columns() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$content = array(
|
||||
"shortname",
|
||||
"c1",
|
||||
);
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_NEW);
|
||||
$this->setExpectedException('moodle_exception');
|
||||
$p = new tool_uploadcourse_processor($cir, $options, array());
|
||||
}
|
||||
|
||||
public function test_preview() {
|
||||
global $DB;
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
$content = array(
|
||||
"shortname,fullname,summary",
|
||||
"c1,Course 1,Course 1 summary",
|
||||
"c2,Course 2,Course 2 summary",
|
||||
);
|
||||
$content = implode("\n", $content);
|
||||
$iid = csv_import_reader::get_new_iid('uploadcourse');
|
||||
$cir = new csv_import_reader($iid, 'uploadcourse');
|
||||
$cir->load_csv_content($content, 'utf-8', 'comma');
|
||||
$cir->init();
|
||||
|
||||
$options = array('mode' => tool_uploadcourse_processor::MODE_CREATE_ALL);
|
||||
$defaults = array('category' => '1');
|
||||
|
||||
$p = new tool_uploadcourse_processor($cir, $options, $defaults);
|
||||
// Nothing special to expect here, just make sure no exceptions are thrown.
|
||||
$p->preview();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Plugin version info.
|
||||
*
|
||||
* @package tool_uploadcourse
|
||||
* @copyright 2011 Piers Harding
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2013070200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2013062100; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_uploadcourse'; // Full name of the plugin (used for diagnostics).
|
||||
+1
-1
@@ -840,7 +840,7 @@ class plugin_manager {
|
||||
'dbtransfer', 'generator', 'health', 'innodb', 'installaddon',
|
||||
'langimport', 'multilangupgrade', 'phpunit', 'profiling',
|
||||
'qeupgradehelper', 'replace', 'spamcleaner', 'timezoneimport',
|
||||
'unittest', 'uploaduser', 'unsuproles', 'xmldb'
|
||||
'unittest', 'uploadcourse', 'uploaduser', 'unsuproles', 'xmldb'
|
||||
),
|
||||
|
||||
'webservice' => array(
|
||||
|
||||
Reference in New Issue
Block a user