diff --git a/admin/cli/install.php b/admin/cli/install.php
index dc65e318d14..79ff0b7126d 100644
--- a/admin/cli/install.php
+++ b/admin/cli/install.php
@@ -425,7 +425,8 @@ if (isset($maturity)) {
exit(1);
}
} else {
- cli_error(get_string('maturitycorewarning', 'admin'));
+ cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_error(get_string('maturityallowunstable', 'admin'));
}
}
}
@@ -677,7 +678,9 @@ if (!$envstatus) {
// Test plugin dependencies.
require_once($CFG->libdir . '/pluginlib.php');
-if (!plugin_manager::instance()->all_plugins_ok($version)) {
+$failed = array();
+if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
cli_error(get_string('pluginschecktodo', 'admin'));
}
diff --git a/admin/cli/install_database.php b/admin/cli/install_database.php
index 2524c4101eb..313f3521d40 100644
--- a/admin/cli/install_database.php
+++ b/admin/cli/install_database.php
@@ -161,7 +161,9 @@ if (!$envstatus) {
// Test plugin dependencies.
require_once($CFG->libdir . '/pluginlib.php');
-if (!plugin_manager::instance()->all_plugins_ok($version)) {
+$failed = array();
+if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
cli_error(get_string('pluginschecktodo', 'admin'));
}
diff --git a/admin/cli/mysql_engine.php b/admin/cli/mysql_engine.php
index 3b51f413446..6bc3642a1d4 100644
--- a/admin/cli/mysql_engine.php
+++ b/admin/cli/mysql_engine.php
@@ -34,8 +34,8 @@ if ($DB->get_dbfamily() !== 'mysql') {
}
// now get cli options
-list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'engine'=>false),
- array('h'=>'help', 'l'=>'list'));
+list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'engine'=>false, 'available'=>false),
+ array('h'=>'help', 'l'=>'list', 'a'=>'available'));
if ($unrecognized) {
$unrecognized = implode("\n ", $unrecognized);
@@ -52,6 +52,7 @@ and does not support transactions.
Options:
--engine=ENGINE Convert MySQL tables to different engine
-l, --list Show table information
+-a, --available Show list of available engines
-h, --help Print out this help
Example:
@@ -59,7 +60,11 @@ Example:
";
if (!empty($options['engine'])) {
+ $engines = mysql_get_engines();
$engine = clean_param($options['engine'], PARAM_ALPHA);
+ if (!isset($engines[strtoupper($engine)])) {
+ cli_error("Error: engine '$engine' is not available on this server!");
+ }
echo "Converting tables to '$engine' for $CFG->wwwroot:\n";
$prefix = $DB->get_prefix();
@@ -68,9 +73,11 @@ if (!empty($options['engine'])) {
$rs = $DB->get_recordset_sql($sql);
$converted = 0;
$skipped = 0;
+ $errors = 0;
foreach ($rs as $table) {
- if ($table->engine === $engine) {
- echo str_pad($table->name, 40). " - NO CONVERSION NEEDED\n";
+ if (strtoupper($table->engine) === strtoupper($engine)) {
+ $newengine = mysql_get_table_engine($table->name);
+ echo str_pad($table->name, 40). " - NO CONVERSION NEEDED ($newengine)\n";
$skipped++;
continue;
}
@@ -78,16 +85,22 @@ if (!empty($options['engine'])) {
try {
$DB->change_database_structure("ALTER TABLE {$table->name} ENGINE = $engine");
+ $newengine = mysql_get_table_engine($table->name);
+ if (strtoupper($newengine) !== strtoupper($engine)) {
+ echo "ERROR ($newengine)\n";
+ $errors++;
+ continue;
+ }
+ echo "DONE ($newengine)\n";
+ $converted++;
} catch (moodle_exception $e) {
echo $e->getMessage()."\n";
- $skipped++;
+ $errors++;
continue;
}
- echo "DONE\n";
- $converted++;
}
$rs->close();
- echo "Converted: $converted, skipped: $skipped\n";
+ echo "Converted: $converted, skipped: $skipped, errors: $errors\n";
exit(0); // success
} else if (!empty($options['list'])) {
@@ -115,7 +128,53 @@ if (!empty($options['engine'])) {
}
exit(0); // success
+} else if (!empty($options['available'])) {
+ echo "List of available MySQL engines for $CFG->wwwroot:\n";
+ $engines = mysql_get_engines();
+ foreach ($engines as $engine) {
+ echo " $engine\n";
+ }
+ die;
+
} else {
echo $help;
die;
}
+
+
+
+// ========== Some functions ==============
+
+function mysql_get_engines() {
+ global $DB;
+
+ $sql = "SHOW Engines";
+ $rs = $DB->get_recordset_sql($sql);
+ $engines = array();
+ foreach ($rs as $engine) {
+ if (strtoupper($engine->support) !== 'YES' and strtoupper($engine->support) !== 'DEFAULT') {
+ continue;
+ }
+ $engines[strtoupper($engine->engine)] = $engine->engine;
+ if (strtoupper($engine->support) === 'DEFAULT') {
+ $engines[strtoupper($engine->engine)] .= ' (default)';
+ }
+ }
+ $rs->close();
+
+ return $engines;
+}
+
+function mysql_get_table_engine($tablename) {
+ global $DB;
+
+ $engine = null;
+ $sql = "SHOW TABLE STATUS WHERE Name = '$tablename'"; // no special chars expected here
+ $rs = $DB->get_recordset_sql($sql);
+ if ($rs->valid()) {
+ $record = $rs->current();
+ $engine = $record->engine;
+ }
+ $rs->close();
+ return $engine;
+}
diff --git a/admin/cli/upgrade.php b/admin/cli/upgrade.php
index 33e66cc3a4f..1fae897c8cb 100644
--- a/admin/cli/upgrade.php
+++ b/admin/cli/upgrade.php
@@ -109,7 +109,9 @@ if (!$envstatus) {
}
// Test plugin dependencies.
-if (!plugin_manager::instance()->all_plugins_ok($version)) {
+$failed = array();
+if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ cli_problem(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
cli_error(get_string('pluginschecktodo', 'admin'));
}
@@ -132,7 +134,8 @@ if (isset($maturity)) {
echo get_string('morehelp') . ': ' . get_docs_url('admin/versions') . PHP_EOL;
cli_separator();
} else {
- cli_error(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_error(get_string('maturityallowunstable', 'admin'));
}
}
}
diff --git a/admin/index.php b/admin/index.php
index 5b01be2749b..bf3eea52aa6 100644
--- a/admin/index.php
+++ b/admin/index.php
@@ -152,6 +152,20 @@ if (!core_tables_exist()) {
die();
}
+ // check plugin dependencies
+ $failed = array();
+ if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ $PAGE->navbar->add(get_string('pluginscheck', 'admin'));
+ $PAGE->set_title($strinstallation);
+ $PAGE->set_heading($strinstallation . ' - Moodle ' . $CFG->target_release);
+
+ $output = $PAGE->get_renderer('core', 'admin');
+ $url = new moodle_url('/admin/index.php', array('agreelicense' => 1, 'confirmrelease' => 1, 'lang' => $CFG->lang));
+ echo $output->unsatisfied_dependencies_page($version, $failed, $url);
+ die();
+ }
+ unset($failed);
+
//TODO: add a page with list of non-standard plugins here
$strdatabasesetup = get_string('databasesetup');
@@ -238,6 +252,15 @@ if ($version > $CFG->version) { // upgrade
$reloadurl = new moodle_url('/admin/index.php', array('confirmupgrade' => 1, 'confirmrelease' => 1));
+ // check plugin dependencies first
+ $failed = array();
+ if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ $output = $PAGE->get_renderer('core', 'admin');
+ echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
+ die();
+ }
+ unset($failed);
+
if ($fetchupdates) {
// no sesskey support guaranteed here
if (empty($CFG->disableupdatenotifications)) {
@@ -290,6 +313,16 @@ if (moodle_needs_upgrading()) {
}
$output = $PAGE->get_renderer('core', 'admin');
+
+ // check plugin dependencies first
+ $failed = array();
+ if (!plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+ echo $output->unsatisfied_dependencies_page($version, $failed, $PAGE->url);
+ die();
+ }
+ unset($failed);
+
+ // dependencies check passed, let's rock!
echo $output->upgrade_plugin_check_page(plugin_manager::instance(), available_update_checker::instance(),
$version, $showallplugins,
new moodle_url($PAGE->url),
diff --git a/admin/oauth2callback.php b/admin/oauth2callback.php
new file mode 100644
index 00000000000..364c0023de0
--- /dev/null
+++ b/admin/oauth2callback.php
@@ -0,0 +1,38 @@
+.
+
+/**
+ * An oauth2 redirection endpoint which can be used for an application:
+ * http://tools.ietf.org/html/draft-ietf-oauth-v2-26#section-3.1.2
+ *
+ * This is used because some oauth servers will not allow a redirect urls
+ * with get params (like repository callback) and that needs to be called
+ * using the state param.
+ *
+ * @package core
+ * @copyright 2012 Dan Poltawski
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(dirname(dirname(__FILE__)).'/config.php');
+
+// The authorization code generated by the authorization server.
+$code = required_param('code', PARAM_RAW);
+// The state parameter we've given (used in moodle as a redirect url).
+$state = required_param('state', PARAM_URL);
+
+redirect(new moodle_url($state, array('code' => $code)));
diff --git a/admin/renderer.php b/admin/renderer.php
index b7a1bab12db..9b689a6903e 100644
--- a/admin/renderer.php
+++ b/admin/renderer.php
@@ -107,6 +107,29 @@ class core_admin_renderer extends plugin_renderer_base {
return $output;
}
+ /**
+ * Displays the list of plugins with unsatisfied dependencies
+ *
+ * @param double|string|int $version Moodle on-disk version
+ * @param array $failed list of plugins with unsatisfied dependecies
+ * @param moodle_url $reloadurl URL of the page to recheck the dependencies
+ * @return string HTML
+ */
+ public function unsatisfied_dependencies_page($version, array $failed, moodle_url $reloadurl) {
+ $output = '';
+
+ $output .= $this->header();
+ $output .= $this->heading(get_string('pluginscheck', 'admin'));
+ $output .= $this->warning(get_string('pluginscheckfailed', 'admin', array('pluginslist' => implode(', ', array_unique($failed)))));
+ $output .= $this->plugins_check_table(plugin_manager::instance(), $version, array('xdep' => true));
+ $output .= $this->warning(get_string('pluginschecktodo', 'admin'));
+ $output .= $this->continue_button($reloadurl);
+
+ $output .= $this->footer();
+
+ return $output;
+ }
+
/**
* Display the 'You are about to upgrade Moodle' page. The first page
* during upgrade.
@@ -197,19 +220,15 @@ class core_admin_renderer extends plugin_renderer_base {
$output .= $this->box_end();
$output .= $this->upgrade_reload($reloadurl);
- if ($pluginman->all_plugins_ok($version)) {
- if ($pluginman->some_plugins_updatable()) {
- $output .= $this->container_start('upgradepluginsinfo');
- $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin'));
- $output .= $this->container_end();
- }
- $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get');
- $button->class = 'continuebutton';
- $output .= $this->render($button);
- } else {
- $output .= $this->box(get_string('pluginschecktodo', 'admin'), 'environmentbox errorbox');
+ if ($pluginman->some_plugins_updatable()) {
+ $output .= $this->container_start('upgradepluginsinfo');
+ $output .= $this->help_icon('upgradepluginsinfo', 'core_admin', get_string('upgradepluginsfirst', 'core_admin'));
+ $output .= $this->container_end();
}
+ $button = new single_button($continueurl, get_string('upgradestart', 'admin'), 'get');
+ $button->class = 'continuebutton';
+ $output .= $this->render($button);
$output .= $this->footer();
return $output;
@@ -563,13 +582,14 @@ class core_admin_renderer extends plugin_renderer_base {
* This default implementation renders all plugins into one big table. The rendering
* options support:
* (bool)full = false: whether to display up-to-date plugins, too
+ * (bool)xdep = false: display the plugins with unsatisified dependecies only
*
* @param plugin_manager $pluginman provides information about the plugins.
* @param int $version the version of the Moodle code from version.php.
* @param array $options rendering options
* @return string HTML code
*/
- public function plugins_check_table(plugin_manager $pluginman, $version, array $options = null) {
+ public function plugins_check_table(plugin_manager $pluginman, $version, array $options = array()) {
global $CFG;
$plugininfo = $pluginman->get_plugins();
@@ -578,11 +598,8 @@ class core_admin_renderer extends plugin_renderer_base {
return '';
}
- if (empty($options)) {
- $options = array(
- 'full' => false,
- );
- }
+ $options['full'] = isset($options['full']) ? (bool)$options['full'] : false;
+ $options['xdep'] = isset($options['xdep']) ? (bool)$options['xdep'] : false;
$table = new html_table();
$table->id = 'plugins-check';
@@ -666,16 +683,28 @@ class core_admin_renderer extends plugin_renderer_base {
$statusisboring = in_array($statuscode, array(
plugin_manager::PLUGIN_STATUS_NODB, plugin_manager::PLUGIN_STATUS_UPTODATE));
- $dependenciesok = $pluginman->are_dependencies_satisfied(
- $plugin->get_other_required_plugins());
- if ($isstandard and $statusisboring and $dependenciesok and empty($availableupdates)) {
+
+ $coredependency = $plugin->is_core_dependency_satisfied($version);
+ $otherpluginsdependencies = $pluginman->are_dependencies_satisfied($plugin->get_other_required_plugins());
+ $dependenciesok = $coredependency && $otherpluginsdependencies;
+
+ if ($options['xdep']) {
+ // we want to see only plugins with failed dependencies
+ if ($dependenciesok) {
+ continue;
+ }
+
+ } else if ($isstandard and $statusisboring and $dependenciesok and empty($availableupdates)) {
+ // no change is going to happen to the plugin - display it only
+ // if the user wants to see the full list
if (empty($options['full'])) {
continue;
}
- } else {
- $numofhighlighted[$type]++;
}
+ // ok, the plugin should be displayed
+ $numofhighlighted[$type]++;
+
$row->cells = array($displayname, $rootdir, $source,
$versiondb, $versiondisk, $requires, $status);
$plugintyperows[] = $row;
@@ -691,7 +720,11 @@ class core_admin_renderer extends plugin_renderer_base {
$sumofhighlighted = array_sum($numofhighlighted);
- if ($sumofhighlighted == 0) {
+ if ($options['xdep']) {
+ // we do not want to display no heading and links in this mode
+ $out = '';
+
+ } else if ($sumofhighlighted == 0) {
$out = $this->output->container_start('nonehighlighted', 'plugins-check-info');
$out .= $this->output->heading(get_string('nonehighlighted', 'core_plugin'));
if (empty($options['full'])) {
diff --git a/admin/repository.php b/admin/repository.php
index c3409a5b5a0..b3494cab5a5 100644
--- a/admin/repository.php
+++ b/admin/repository.php
@@ -1,12 +1,27 @@
.
require_once(dirname(dirname(__FILE__)) . '/config.php');
require_once($CFG->dirroot . '/repository/lib.php');
require_once($CFG->libdir . '/adminlib.php');
-$repository = optional_param('repos', '', PARAM_FORMAT);
-$action = optional_param('action', '', PARAM_ALPHA);
-$sure = optional_param('sure', '', PARAM_ALPHA);
+$repository = optional_param('repos', '', PARAM_ALPHANUMEXT);
+$action = optional_param('action', '', PARAM_ACTION);
+$sure = optional_param('sure', '', PARAM_ALPHA);
+$downloadcontents = optional_param('downloadcontents', false, PARAM_BOOL);
$display = true; // fall through to normal display
@@ -42,6 +57,10 @@ $configstr = get_string('manage', 'repository');
$return = true;
+if (!empty($action)) {
+ require_sesskey();
+}
+
/**
* Helper function that generates a moodle_url object
* relevant to the repository
@@ -152,10 +171,10 @@ if (($action == 'edit') || ($action == 'new')) {
// Display instances list and creation form
if ($action == 'edit') {
- $instanceoptionnames = repository::static_function($repository, 'get_instance_option_names');
- if (!empty($instanceoptionnames)) {
- repository::display_instances_list(get_context_instance(CONTEXT_SYSTEM), $repository);
- }
+ $instanceoptionnames = repository::static_function($repository, 'get_instance_option_names');
+ if (!empty($instanceoptionnames)) {
+ repository::display_instances_list(context_system::instance(), $repository);
+ }
}
}
} else if ($action == 'show') {
@@ -185,7 +204,8 @@ if (($action == 'edit') || ($action == 'new')) {
if (!confirm_sesskey()) {
print_error('confirmsesskeybad', '', $baseurl);
}
- if ($repositorytype->delete()) {
+
+ if ($repositorytype->delete($downloadcontents)) {
redirect($baseurl);
} else {
print_error('instancenotdeleted', 'repository', $baseurl);
@@ -193,7 +213,34 @@ if (($action == 'edit') || ($action == 'new')) {
exit;
} else {
echo $OUTPUT->header();
- echo $OUTPUT->confirm(get_string('confirmremove', 'repository', $repositorytype->get_readablename()), $sesskeyurl . '&action=delete&repos=' . $repository . '&sure=yes', $baseurl);
+
+ $message = get_string('confirmremove', 'repository', $repositorytype->get_readablename());
+
+ $output = $OUTPUT->box_start('generalbox', 'notice');
+ $output .= html_writer::tag('p', $message);
+
+ $removeurl = new moodle_url($sesskeyurl);
+ $removeurl->params(array(
+ 'action' =>'delete',
+ 'repos' => $repository,
+ 'sure' => 'yes',
+ ));
+
+ $removeanddownloadurl = new moodle_url($sesskeyurl);
+ $removeanddownloadurl->params(array(
+ 'action' =>'delete',
+ 'repos'=> $repository,
+ 'sure' => 'yes',
+ 'downloadcontents' => 1,
+ ));
+
+ $output .= $OUTPUT->single_button($removeurl, get_string('continueuninstall', 'repository'));
+ $output .= $OUTPUT->single_button($removeanddownloadurl, get_string('continueuninstallanddownload', 'repository'));
+ $output .= $OUTPUT->single_button($baseurl, get_string('cancel'));
+ $output .= $OUTPUT->box_end();
+
+ echo $output;
+
$return = false;
}
} else if ($action == 'moveup') {
@@ -255,7 +302,7 @@ if (($action == 'edit') || ($action == 'new')) {
// Calculate number of instances in order to display them for the Moodle administrator
if (!empty($instanceoptionnames)) {
$params = array();
- $params['context'] = array(get_system_context());
+ $params['context'] = array(context_system::instance());
$params['onlyvisible'] = false;
$params['type'] = $typename;
$admininstancenumber = count(repository::static_function($typename, 'get_instances', $params));
diff --git a/admin/repositoryinstance.php b/admin/repositoryinstance.php
index e75193d0be4..fe751464192 100644
--- a/admin/repositoryinstance.php
+++ b/admin/repositoryinstance.php
@@ -1,18 +1,35 @@
.
require_once(dirname(dirname(__FILE__)) . '/config.php');
require_once($CFG->dirroot . '/repository/lib.php');
require_once($CFG->libdir . '/adminlib.php');
+require_sesskey();
+
// id of repository
$edit = optional_param('edit', 0, PARAM_INT);
-$new = optional_param('new', '', PARAM_FORMAT);
+$new = optional_param('new', '', PARAM_PLUGIN);
$hide = optional_param('hide', 0, PARAM_INT);
$delete = optional_param('delete', 0, PARAM_INT);
$sure = optional_param('sure', '', PARAM_ALPHA);
$type = optional_param('type', '', PARAM_PLUGIN);
+$downloadcontents = optional_param('downloadcontents', false, PARAM_BOOL);
-$context = get_context_instance(CONTEXT_SYSTEM);
+$context = context_system::instance();
$pagename = 'repositorycontroller';
@@ -24,16 +41,20 @@ if ($edit){
$pagename = 'repositoryinstancenew';
}
-admin_externalpage_setup($pagename);
-require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
+admin_externalpage_setup($pagename, '', null, new moodle_url('/admin/repositoryinstances.php'));
+require_capability('moodle/site:config', $context);
+
+$baseurl = new moodle_url("/$CFG->admin/repositoryinstance.php", array('sesskey'=>sesskey()));
+
+$parenturl = new moodle_url("/$CFG->admin/repository.php", array(
+ 'sesskey'=>sesskey(),
+ 'action'=>'edit',
+));
-$sesskeyurl = "$CFG->wwwroot/$CFG->admin/repositoryinstance.php?sesskey=" . sesskey();
-$baseurl = "$CFG->wwwroot/$CFG->admin/repository.php?session=". sesskey() .'&action=edit&repos=';
if ($new) {
- $baseurl .= $new;
-}
-else {
- $baseurl .= $type;
+ $parenturl->param('repos', $new);
+} else {
+ $parenturl->param('repos', $type);
}
$return = true;
@@ -48,7 +69,7 @@ if (!empty($edit) || !empty($new)) {
$typeid = $instance->options['typeid'];
} else {
$plugin = $new;
- $typeid = $new;
+ $typeid = null;
$instance = null;
}
@@ -57,12 +78,9 @@ if (!empty($edit) || !empty($new)) {
// end setup, begin output
if ($mform->is_cancelled()){
- redirect($baseurl);
+ redirect($parenturl);
exit;
} else if ($fromform = $mform->get_data()){
- if (!confirm_sesskey()) {
- print_error('confirmsesskeybad', '', $baseurl);
- }
if ($edit) {
$settings = array();
$settings['name'] = $fromform->name;
@@ -77,13 +95,13 @@ if (!empty($edit) || !empty($new)) {
}
$success = $instance->set_option($settings);
} else {
- $success = repository::static_function($plugin, 'create', $plugin, 0, get_system_context(), $fromform);
+ $success = repository::static_function($plugin, 'create', $plugin, 0, $context, $fromform);
$data = data_submitted();
}
if ($success) {
- redirect($baseurl);
+ redirect($parenturl);
} else {
- print_error('instancenotsaved', 'repository', $baseurl);
+ print_error('instancenotsaved', 'repository', $parenturl);
}
exit;
} else {
@@ -95,9 +113,6 @@ if (!empty($edit) || !empty($new)) {
$return = false;
}
} else if (!empty($hide)) {
- if (!confirm_sesskey()) {
- print_error('confirmsesskeybad', '', $baseurl);
- }
$instance = repository::get_type_by_typename($hide);
$instance->hide();
$return = true;
@@ -108,25 +123,38 @@ if (!empty($edit) || !empty($new)) {
throw new repository_exception('readonlyinstance', 'repository');
}
if ($sure) {
- if (!confirm_sesskey()) {
- print_error('confirmsesskeybad', '', $baseurl);
- }
- if ($instance->delete()) {
+ if ($instance->delete($downloadcontents)) {
$deletedstr = get_string('instancedeleted', 'repository');
- redirect($baseurl, $deletedstr, 3);
+ redirect($parenturl, $deletedstr, 3);
} else {
- print_error('instancenotdeleted', 'repository', $baseurl);
+ print_error('instancenotdeleted', 'repository', $parenturl);
}
exit;
}
echo $OUTPUT->header();
- echo $OUTPUT->confirm(get_string('confirmdelete', 'repository', $instance->name), "$sesskeyurl&type=$type'&delete=$delete'&sure=yes", "$CFG->wwwroot/$CFG->admin/repositoryinstance.php?session=". sesskey());
+ echo $OUTPUT->box_start('generalbox', 'notice');
+ $continueurl = new moodle_url($baseurl, array(
+ 'type' => $type,
+ 'delete' => $delete,
+ 'sure' => 'yes',
+ ));
+ $continueanddownloadurl = new moodle_url($continueurl, array(
+ 'downloadcontents' => 1
+ ));
+ $message = get_string('confirmdelete', 'repository', $instance->name);
+ echo html_writer::tag('p', $message);
+
+ echo $OUTPUT->single_button($continueurl, get_string('continueuninstall', 'repository'));
+ echo $OUTPUT->single_button($continueanddownloadurl, get_string('continueuninstallanddownload', 'repository'));
+ echo $OUTPUT->single_button($parenturl, get_string('cancel'));
+
+ echo $OUTPUT->box_end();
+
$return = false;
}
if (!empty($return)) {
-
- redirect($baseurl);
+ redirect($parenturl);
}
echo $OUTPUT->footer();
diff --git a/admin/settings/development.php b/admin/settings/development.php
index 9d7b5a09981..e55e1f28f00 100644
--- a/admin/settings/development.php
+++ b/admin/settings/development.php
@@ -13,6 +13,8 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
$temp->add(new admin_setting_configcheckbox('enablesafebrowserintegration', new lang_string('enablesafebrowserintegration', 'admin'), new lang_string('configenablesafebrowserintegration', 'admin'), 0));
$temp->add(new admin_setting_configcheckbox('enablegroupmembersonly', new lang_string('enablegroupmembersonly', 'admin'), new lang_string('configenablegroupmembersonly', 'admin'), 0));
+ $temp->add(new admin_setting_configcheckbox('dndallowtextandlinks', new lang_string('dndallowtextandlinks', 'admin'), new lang_string('configdndallowtextandlinks', 'admin'), 0));
+
$ADMIN->add('experimental', $temp);
// "debugging" settingpage
diff --git a/admin/settings/plugins.php b/admin/settings/plugins.php
index 6d192b6d37d..638aa4009b7 100644
--- a/admin/settings/plugins.php
+++ b/admin/settings/plugins.php
@@ -330,12 +330,12 @@ if ($hassiteconfig) {
$typeoptionnames = repository::static_function($repositorytype->get_typename(), 'get_type_option_names');
$instanceoptionnames = repository::static_function($repositorytype->get_typename(), 'get_instance_option_names');
if (!empty($typeoptionnames) || !empty($instanceoptionnames)) {
- $ADMIN->add('repositorysettings',
- new admin_externalpage('repositorysettings'.$repositorytype->get_typename(),
- $repositorytype->get_readablename(),
- $url . '?action=edit&repos=' . $repositorytype->get_typename()),
- 'moodle/site:config');
- }
+
+ $params = array('action'=>'edit', 'sesskey'=>sesskey(), 'repos'=>$repositorytype->get_typename());
+ $settingsurl = new moodle_url("/$CFG->admin/repository.php", $params);
+ $repositoryexternalpage = new admin_externalpage('repositorysettings'.$repositorytype->get_typename(), $repositorytype->get_readablename(), $settingsurl);
+ $ADMIN->add('repositorysettings', $repositoryexternalpage);
+ }
}
}
@@ -370,7 +370,7 @@ if ($hassiteconfig) {
// to set the page layout on all admin pages.
// $wsdoclink = $OUTPUT->doc_link('How_to_get_a_security_key');
$url = new moodle_url(get_docs_url('How_to_get_a_security_key'));
- $wsdoclink = html_writer::tag('a', new lang_string('supplyinfo'),array('href'=>$url));
+ $wsdoclink = html_writer::tag('a', new lang_string('supplyinfo', 'webservice'), array('href'=>$url));
$temp->add(new admin_setting_configcheckbox('enablewsdocumentation', new lang_string('enablewsdocumentation',
'admin'), new lang_string('configenablewsdocumentation', 'admin', $wsdoclink), false));
$ADMIN->add('webservicesettings', $temp);
diff --git a/admin/timezone.php b/admin/timezone.php
index 34e1fa40fda..e031be44bbe 100644
--- a/admin/timezone.php
+++ b/admin/timezone.php
@@ -9,6 +9,9 @@
$zone = clean_param($zone, PARAM_PATH);
}
+ $PAGE->set_url('/admin/timezone.php');
+ $PAGE->set_context(context_system::instance());
+
require_login();
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
@@ -18,7 +21,6 @@
$strusers = get_string("users");
$strall = get_string("all");
- $PAGE->set_url('/admin/timezone.php');
$PAGE->set_title($strtimezone);
$PAGE->set_heading($strtimezone);
$PAGE->navbar->add($strtimezone);
diff --git a/admin/tool/assignmentupgrade/batchupgrade.php b/admin/tool/assignmentupgrade/batchupgrade.php
index 20ebf5c9958..31bca246490 100644
--- a/admin/tool/assignmentupgrade/batchupgrade.php
+++ b/admin/tool/assignmentupgrade/batchupgrade.php
@@ -22,16 +22,20 @@
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
+define('NO_OUTPUT_BUFFERING', true);
+
require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentstable.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentsbatchform.php');
require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentstable.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
require_sesskey();
// admin_externalpage_setup calls require_login and checks moodle/site:config
admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrade_url('batchupgrade'));
+
+$PAGE->set_pagelayout('maintenance');
$PAGE->navbar->add(get_string('batchupgrade', 'tool_assignmentupgrade'));
$renderer = $PAGE->get_renderer('tool_assignmentupgrade');
@@ -41,7 +45,26 @@ if (!$confirm) {
print_error('invalidrequest');
die();
}
-$result = tool_assignmentupgrade_upgrade_multiple_assignments(optional_param('upgradeall', 0, PARAM_BOOL),
- explode(',', optional_param('selected', '', PARAM_TEXT)));
+raise_memory_limit(MEMORY_EXTRA);
+session_get_instance()->write_close(); // release session
-echo $renderer->convert_multiple_assignments_result($result);
+echo $renderer->header();
+echo $renderer->heading(get_string('batchupgrade', 'tool_assignmentupgrade'));
+
+$current = 0;
+if (optional_param('upgradeall', false, PARAM_BOOL)) {
+ $assignmentids = tool_assignmentupgrade_load_all_upgradable_assignmentids();
+} else {
+ $assignmentids = explode(',', optional_param('selected', '', PARAM_TEXT));
+}
+$total = count($assignmentids);
+
+foreach ($assignmentids as $assignmentid) {
+ list($summary, $success, $log) = tool_assignmentupgrade_upgrade_assignment($assignmentid);
+ $current += 1;
+ echo $renderer->heading(get_string('upgradeprogress', 'tool_assignmentupgrade', array('current'=>$current, 'total'=>$total)), 3);
+ echo $renderer->convert_assignment_result($summary, $success, $log);
+}
+
+echo $renderer->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
+echo $renderer->footer();
diff --git a/admin/tool/assignmentupgrade/index.php b/admin/tool/assignmentupgrade/index.php
index bb7ff493b10..f4cd1797d73 100644
--- a/admin/tool/assignmentupgrade/index.php
+++ b/admin/tool/assignmentupgrade/index.php
@@ -34,8 +34,8 @@
*/
require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
// admin_externalpage_setup calls require_login and checks moodle/site:config
admin_externalpage_setup('assignmentupgrade');
@@ -47,4 +47,4 @@ $actions = array();
$header = get_string('pluginname', 'tool_assignmentupgrade');
$actions[] = tool_assignmentupgrade_action::make('listnotupgraded');
-echo $renderer->index_page($header, $actions);
\ No newline at end of file
+echo $renderer->index_page($header, $actions);
diff --git a/admin/tool/assignmentupgrade/lang/en/tool_assignmentupgrade.php b/admin/tool/assignmentupgrade/lang/en/tool_assignmentupgrade.php
index 3b3734bc247..e9a61dcb381 100644
--- a/admin/tool/assignmentupgrade/lang/en/tool_assignmentupgrade.php
+++ b/admin/tool/assignmentupgrade/lang/en/tool_assignmentupgrade.php
@@ -26,6 +26,7 @@ $string['areyousure'] = 'Are you sure?';
$string['areyousuremessage'] = 'Are you sure you want to upgrade the assignment "{$a->name}"?';
$string['assignmentid'] = 'Assignment ID';
$string['assignmentnotfound'] = 'Assignment could not be found (id={$a})';
+$string['assignmentsperpage'] = 'Assignments per page';
$string['assignmenttype'] = 'Assignment type';
$string['backtoindex'] = 'Back to index';
$string['batchoperations'] = 'Batch operations';
@@ -43,6 +44,7 @@ $string['pluginname'] = 'Assignment upgrade helper';
$string['select'] = 'Select';
$string['submissions'] = 'Submissions';
$string['supported'] = 'Upgrade';
+$string['updatetable'] = 'Update table';
$string['unknown'] = 'Unknown';
$string['upgradeassignmentsummary'] = 'Upgrade assignment: {$a->name} (Course: {$a->shortname})';
$string['upgradeassignmentsuccess'] = 'Result: Upgrade successful';
@@ -52,5 +54,6 @@ $string['upgradeselected'] = 'Upgrade selected assignments';
$string['upgradeselectedcount'] = 'Upgrade {$a} selected assignments?';
$string['upgradeall'] = 'Upgrade all assignments';
$string['upgradeallconfirm'] = 'Upgrade all assignments?';
+$string['upgradeprogress'] = 'Upgrade assignment {$a->current} of {$a->total}';
$string['upgradesingle'] = 'Upgrade single assignment';
$string['viewcourse'] = 'View the course with the converted assignment';
diff --git a/admin/tool/assignmentupgrade/listnotupgraded.php b/admin/tool/assignmentupgrade/listnotupgraded.php
index 37605a5d36a..b03883adf4a 100644
--- a/admin/tool/assignmentupgrade/listnotupgraded.php
+++ b/admin/tool/assignmentupgrade/listnotupgraded.php
@@ -23,10 +23,11 @@
*/
require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentstable.php');
-require_once(dirname(__FILE__) . '/upgradableassignmentsbatchform.php');
require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentstable.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/upgradableassignmentsbatchform.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/paginationform.php');
// admin_externalpage_setup calls require_login and checks moodle/site:config
admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrade_url('listnotupgraded'));
@@ -34,16 +35,26 @@ $PAGE->navbar->add(get_string('listnotupgraded', 'tool_assignmentupgrade'));
$renderer = $PAGE->get_renderer('tool_assignmentupgrade');
-$perpage = get_user_preferences('tool_assignmentupgrade_perpage', 5);
+$perpage = optional_param('perpage', 0, PARAM_INT);
+if (!$perpage) {
+ $perpage = get_user_preferences('tool_assignmentupgrade_perpage', 100);
+} else {
+ set_user_preference('tool_assignmentupgrade_perpage', $perpage);
+}
$assignments = new tool_assignmentupgrade_assignments_table($perpage);
$batchform = new tool_assignmentupgrade_batchoperations_form();
$data = $batchform->get_data();
+
if ($data && $data->selectedassignments != '' || $data && isset($data->upgradeall)) {
require_sesskey();
echo $renderer->confirm_batch_operation_page($data);
} else {
- echo $renderer->assignment_list_page($assignments, $batchform);
+ $paginationform = new tool_assignmentupgrade_pagination_form();
+ $pagedata = new stdClass();
+ $pagedata->perpage = $perpage;
+ $paginationform->set_data($pagedata);
+ echo $renderer->assignment_list_page($assignments, $batchform, $paginationform);
}
diff --git a/admin/tool/assignmentupgrade/locallib.php b/admin/tool/assignmentupgrade/locallib.php
index 5b814859fc3..6ea1883a4d3 100644
--- a/admin/tool/assignmentupgrade/locallib.php
+++ b/admin/tool/assignmentupgrade/locallib.php
@@ -170,54 +170,33 @@ function tool_assignmentupgrade_load_all_upgradable_assignmentids() {
/**
- * Convert a list of assignments from the old format to the new one.
- * @param bool $upgradeall - Upgrade all possible assignments
- * @param array $assignmentids An array of assignment ids to upgrade
- * @return array of $entry['assignmentsummary' => (result from tool_assignmentupgrade_get_assignment)
- * $entry['success'] => boolean
- * $entry['log'] => string - upgrade log
+ * Upgrade a single assignment. This is used by both upgrade single and upgrade batch
+ *
+ * @param int $assignmentid - The assignment id to upgrade
+ * @return array(string, boolean, string) -
+ * The array contains
+ * - the assignment summary (returned by tool_assignmentupgrade_get_assignment)
+ * - success
+ * - the upgrade log
*/
-function tool_assignmentupgrade_upgrade_multiple_assignments($upgradeall, $assignmentids) {
+function tool_assignmentupgrade_upgrade_assignment($assignmentid) {
global $CFG;
- require_once($CFG->dirroot . '/mod/assign/locallib.php');
require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
- $upgrades = array();
-
- if ($upgradeall) {
- $assignmentids = tool_assignmentupgrade_load_all_upgradable_assignmentids();
- }
$assignment_upgrader = new assign_upgrade_manager();
- foreach ($assignmentids as $assignmentid) {
- $info = tool_assignmentupgrade_get_assignment($assignmentid);
- if ($info) {
- $log = '';
- $success = $assignment_upgrader->upgrade_assignment($assignmentid, $log);
- } else {
- $success = false;
- $log = get_string('assignmentnotfound', 'tool_assignmentupgrade', $assignmentid);
- $info = new stdClass();
- $info->name = get_string('unknown', 'tool_assignmentupgrade');
- $info->shortname = get_string('unknown', 'tool_assignmentupgrade');
- }
-
- $upgrades[] = array('assignmentsummary'=>$info, 'success'=>$success, 'log'=>$log);
+ $info = tool_assignmentupgrade_get_assignment($assignmentid);
+ if ($info) {
+ $log = '';
+ $success = $assignment_upgrader->upgrade_assignment($assignmentid, $log);
+ } else {
+ $success = false;
+ $log = get_string('assignmentnotfound', 'tool_assignmentupgrade', $assignmentid);
+ $info = new stdClass();
+ $info->name = get_string('unknown', 'tool_assignmentupgrade');
+ $info->shortname = get_string('unknown', 'tool_assignmentupgrade');
}
- return $upgrades;
-}
-/**
- * Convert a single assignment from the old format to the new one.
- * @param stdClass $assignmentinfo An object containing information about this class
- * @param string $log This gets appended to with the details of the conversion process
- * @return boolean This is the overall result (true/false)
- */
-function tool_assignmentupgrade_upgrade_assignment($assignmentinfo, &$log) {
- global $CFG;
- require_once($CFG->dirroot . '/mod/assign/locallib.php');
- require_once($CFG->dirroot . '/mod/assign/upgradelib.php');
- $assignment_upgrader = new assign_upgrade_manager();
- return $assignment_upgrader->upgrade_assignment($assignmentinfo->id, $log);
+ return array($info, $success, $log);
}
/**
diff --git a/admin/tool/assignmentupgrade/module.js b/admin/tool/assignmentupgrade/module.js
index 829f99a34ad..edee839835f 100644
--- a/admin/tool/assignmentupgrade/module.js
+++ b/admin/tool/assignmentupgrade/module.js
@@ -61,6 +61,11 @@ M.tool_assignmentupgrade = {
}
});
+ var perpage = Y.one('#id_perpage');
+ perpage.on('change', function(e) {
+ window.onbeforeunload = null;
+ Y.one('.tool_assignmentupgrade_paginationform form').submit();
+ });
}
}
diff --git a/admin/tool/assignmentupgrade/paginationform.php b/admin/tool/assignmentupgrade/paginationform.php
new file mode 100644
index 00000000000..3efb8d4d508
--- /dev/null
+++ b/admin/tool/assignmentupgrade/paginationform.php
@@ -0,0 +1,59 @@
+.
+
+/**
+ * This file contains the forms to create and edit an instance of this module
+ *
+ * @package tool_assignmentupgrade
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
+
+
+/** Include formslib.php */
+require_once ($CFG->libdir.'/formslib.php');
+
+/**
+ * Assignment upgrade table display options
+ *
+ * @package tool_assignmentupgrade
+ * @copyright 2012 NetSpot {@link http://www.netspot.com.au}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tool_assignmentupgrade_pagination_form extends moodleform {
+ /**
+ * Define this form - called from the parent constructor
+ */
+ function definition() {
+ $mform = $this->_form;
+ $instance = $this->_customdata;
+
+ $mform->addElement('header', 'general', get_string('assignmentsperpage', 'tool_assignmentupgrade'));
+ // visible elements
+ $options = array(10=>'10', 20=>'20', 50=>'50', 100=>'100');
+ $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options);
+
+ // hidden params
+ $mform->addElement('hidden', 'action', 'saveoptions');
+ $mform->setType('action', PARAM_ALPHA);
+
+ // buttons
+ $this->add_action_buttons(false, get_string('updatetable', 'tool_assignmentupgrade'));
+ }
+}
+
diff --git a/admin/tool/assignmentupgrade/renderer.php b/admin/tool/assignmentupgrade/renderer.php
index 16c013c9108..ddb8cfabad4 100644
--- a/admin/tool/assignmentupgrade/renderer.php
+++ b/admin/tool/assignmentupgrade/renderer.php
@@ -112,9 +112,10 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
* Render the list of assignments that still need to be upgraded page.
* @param tool_assignmentupgrade_assignments_table $assignments of data about assignments.
* @param tool_assignmentupgrade_batchoperations_form $batchform Submitted form with list of assignments to upgrade
+ * @param tool_assignmentupgrade_pagination_form $paginationform Form which contains the preferences for paginating the table
* @return string html to output.
*/
- public function assignment_list_page(tool_assignmentupgrade_assignments_table $assignments, tool_assignmentupgrade_batchoperations_form $batchform) {
+ public function assignment_list_page(tool_assignmentupgrade_assignments_table $assignments, tool_assignmentupgrade_batchoperations_form $batchform, tool_assignmentupgrade_pagination_form $paginationform) {
$output = '';
$output .= $this->header();
$this->page->requires->js_init_call('M.tool_assignmentupgrade.init_upgrade_table', array());
@@ -126,6 +127,10 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
$output .= $this->container_start('tool_assignmentupgrade_upgradetable');
+ $output .= $this->container_start('tool_assignmentupgrade_paginationform');
+ $output .= $this->moodleform($paginationform);
+ $output .= $this->container_end();
+
$output .= $this->flexible_table($assignments, $assignments->get_rows_per_page(), true);
$output .= $this->container_end();
@@ -140,43 +145,6 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
return $output;
}
- /**
- * Render the result of an assignment conversion
- * @param array $assignments - An array of arrays with keys $entry['assignmentsummary', 'success', 'log']
- * See convert_assignment_result for more description of these keys.
- * @return string html to output.
- */
- public function convert_multiple_assignments_result($assignments) {
- $output = '';
- $output .= $this->header();
- $output .= $this->heading(get_string('batchupgrade', 'tool_assignmentupgrade'));
-
- foreach ($assignments as $assignment) {
- $assignmentsummary = $assignment['assignmentsummary'];
- $success = $assignment['success'];
- $log = $assignment['log'];
-
- $output .= $this->heading(get_string('upgradeassignmentsummary', 'tool_assignmentupgrade', $assignmentsummary), 5);
- if ($success) {
- $output .= $this->container(get_string('upgradeassignmentsuccess', 'tool_assignmentupgrade'));
-
- } else {
- $output .= $this->container(get_string('upgradeassignmentfailed', 'tool_assignmentupgrade', $assignment));
- }
- if (isset($assignmentsummary->courseid)) {
- $output .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$assignmentsummary->courseid)) ,get_string('viewcourse', 'tool_assignmentupgrade'));
- }
-
-
- }
-
- $output .= $this->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
-
-
- $output .= $this->footer();
- return $output;
- }
-
/**
* Render the result of an assignment conversion
* @param stdClass $assignmentsummary data about the assignment to upgrade.
@@ -186,19 +154,17 @@ class tool_assignmentupgrade_renderer extends plugin_renderer_base {
*/
public function convert_assignment_result($assignmentsummary, $success, $log) {
$output = '';
- $output .= $this->header();
- $output .= $this->heading(get_string('conversioncomplete', 'tool_assignmentupgrade'));
+ $output .= $this->container_start('tool_assignmentupgrade_result');
+ $output .= $this->container(get_string('upgradeassignmentsummary', 'tool_assignmentupgrade', $assignmentsummary));
if (!$success) {
- $output .= get_string('conversionfailed', 'tool_assignmentupgrade', $log);
+ $output .= $this->container(get_string('conversionfailed', 'tool_assignmentupgrade', $log));
} else {
- $output .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$assignmentsummary->courseid)) ,get_string('viewcourse', 'tool_assignmentupgrade'));
+ $output .= $this->container(get_string('upgradeassignmentsuccess', 'tool_assignmentupgrade'));
+ $output .= $this->container(html_writer::link(new moodle_url('/course/view.php', array('id'=>$assignmentsummary->courseid)) ,get_string('viewcourse', 'tool_assignmentupgrade')));
}
+ $output .= $this->container_end();
- $output .= $this->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
-
-
- $output .= $this->footer();
return $output;
}
diff --git a/admin/tool/assignmentupgrade/styles.css b/admin/tool/assignmentupgrade/styles.css
index 0188dc416eb..277400bded1 100644
--- a/admin/tool/assignmentupgrade/styles.css
+++ b/admin/tool/assignmentupgrade/styles.css
@@ -8,4 +8,4 @@
#page-admin-tool-assignmentupgrade-listnotupgraded .tool_assignmentupgrade_upgradetable tr.selectedrow td { background-color: #ffeecc; }
#page-admin-tool-assignmentupgrade-listnotupgraded .tool_assignmentupgrade_upgradetable tr.unselectedrow td { background-color: white; }
-
+#page-admin-tool-assignmentupgrade-listnotupgraded .tool_assignmentupgrade_paginationform .hidden { display: none; }
diff --git a/admin/tool/assignmentupgrade/upgradableassignmentstable.php b/admin/tool/assignmentupgrade/upgradableassignmentstable.php
index 0e4830ba602..307a8c95f61 100644
--- a/admin/tool/assignmentupgrade/upgradableassignmentstable.php
+++ b/admin/tool/assignmentupgrade/upgradableassignmentstable.php
@@ -70,12 +70,11 @@ class tool_assignmentupgrade_assignments_table extends table_sql implements rend
$from = '{assignment} a JOIN {course} c ON a.course = c.id ' .
' LEFT JOIN {assignment_submissions} s ON a.id = s.assignment';
-
$where = '1 = 1';
$where .= ' GROUP BY a.id, a.name, a.assignmenttype, c.shortname, c.id ';
$this->set_sql($fields, $from, $where, array());
- $this->set_count_sql('SELECT COUNT(*) FROM ' . $from, array());
+ $this->set_count_sql('SELECT COUNT(*) FROM {assignment} a JOIN {course} c ON a.course = c.id', array());
$columns = array();
$headers = array();
diff --git a/admin/tool/assignmentupgrade/upgradesingle.php b/admin/tool/assignmentupgrade/upgradesingle.php
index 2464ebea56c..5125bbbfa66 100644
--- a/admin/tool/assignmentupgrade/upgradesingle.php
+++ b/admin/tool/assignmentupgrade/upgradesingle.php
@@ -23,8 +23,8 @@
*/
require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
require_sesskey();
@@ -36,13 +36,11 @@ admin_externalpage_setup('assignmentupgrade', '', array(), tool_assignmentupgrad
$PAGE->navbar->add(get_string('upgradesingle', 'tool_assignmentupgrade'));
$renderer = $PAGE->get_renderer('tool_assignmentupgrade');
-$assignmentinfo = tool_assignmentupgrade_get_assignment($assignmentid);
-if (!$assignmentinfo) {
- print_error('invalidrequest');
- die();
-}
-
$log = '';
-$result = tool_assignmentupgrade_upgrade_assignment($assignmentinfo, $log);
+list($summary, $success, $log) = tool_assignmentupgrade_upgrade_assignment($assignmentid);
-echo $renderer->convert_assignment_result($assignmentinfo, $result, $log);
+echo $renderer->header();
+echo $renderer->heading(get_string('conversioncomplete', 'tool_assignmentupgrade'));
+echo $renderer->convert_assignment_result($summary, $success, $log);
+echo $renderer->continue_button(tool_assignmentupgrade_url('listnotupgraded'));
+echo $renderer->footer();
diff --git a/admin/tool/assignmentupgrade/upgradesingleconfirm.php b/admin/tool/assignmentupgrade/upgradesingleconfirm.php
index 0325b4a09d4..b7ec24c52e9 100644
--- a/admin/tool/assignmentupgrade/upgradesingleconfirm.php
+++ b/admin/tool/assignmentupgrade/upgradesingleconfirm.php
@@ -23,8 +23,8 @@
*/
require_once(dirname(__FILE__) . '/../../../config.php');
-require_once(dirname(__FILE__) . '/locallib.php');
require_once($CFG->libdir . '/adminlib.php');
+require_once($CFG->dirroot . '/admin/tool/assignmentupgrade/locallib.php');
require_sesskey();
diff --git a/admin/tool/bloglevelupgrade/index.php b/admin/tool/bloglevelupgrade/index.php
index 9c87eec8227..bd2a5310b37 100644
--- a/admin/tool/bloglevelupgrade/index.php
+++ b/admin/tool/bloglevelupgrade/index.php
@@ -121,7 +121,7 @@ function bloglevelupgrade_entries($blogentries, $forum, $cm, $groupid=-1) {
$discussion->groupid = $groupid;
$message = '';
- $discussionid = forum_add_discussion($discussion, null, $message);
+ $discussionid = forum_add_discussion($discussion, null, $message, $blogentry->userid);
// Copy file attachment records
$fs = get_file_storage();
diff --git a/admin/tool/unittest/coveragefile.php b/admin/tool/unittest/coveragefile.php
index 8c17b60e3eb..d3c8737a4e8 100644
--- a/admin/tool/unittest/coveragefile.php
+++ b/admin/tool/unittest/coveragefile.php
@@ -60,9 +60,8 @@ if (!isset($args[0]) || !in_array($args[0], $alloweddirs)) {
print_error('invalidarguments');
}
-// only serve some controlled extensions
-$allowedextensions = array('text/html', 'text/css', 'image/gif', 'application/x-javascript');
-if (!in_array(mimeinfo('type', $filepath), $allowedextensions)) {
+// only serve some controlled extensions/mimetypes
+if (!file_extension_in_typegroup($filepath, array('web_file', 'web_image'), true)) {
print_error('invalidarguments');
}
diff --git a/auth/shibboleth/index.php b/auth/shibboleth/index.php
index 7bc8f90c892..a1e4a1c3840 100644
--- a/auth/shibboleth/index.php
+++ b/auth/shibboleth/index.php
@@ -30,6 +30,7 @@
/// If we can find the Shibboleth attribute, save it in session and return to main login page
if (!empty($_SERVER[$pluginconfig->user_attribute])) { // Shibboleth auto-login
+ $frm = new stdClass();
$frm->username = strtolower($_SERVER[$pluginconfig->user_attribute]);
$frm->password = substr(base64_encode($_SERVER[$pluginconfig->user_attribute]),0,8);
// The random password consists of the first 8 letters of the base 64 encoded user ID
diff --git a/backup/backupfilesedit_form.php b/backup/backupfilesedit_form.php
index 7906a080d1a..36a4030da07 100644
--- a/backup/backupfilesedit_form.php
+++ b/backup/backupfilesedit_form.php
@@ -27,7 +27,7 @@ class backup_files_edit_form extends moodleform {
function definition() {
$mform =& $this->_form;
$contextid = $this->_customdata['contextid'];
- $options = array('subdirs'=>0, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
+ $options = array('subdirs'=>0, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL | FILE_REFERENCE);
$mform->addElement('filemanager', 'files_filemanager', get_string('files'), null, $options);
$mform->addElement('hidden', 'contextid', $this->_customdata['contextid']);
$mform->addElement('hidden', 'currentcontext', $this->_customdata['currentcontext']);
diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php
index e7b6018cdf3..a2fa9488605 100644
--- a/backup/moodle2/backup_stepslib.php
+++ b/backup/moodle2/backup_stepslib.php
@@ -1404,7 +1404,7 @@ class backup_final_files_structure_step extends backup_structure_step {
'contenthash', 'contextid', 'component', 'filearea', 'itemid',
'filepath', 'filename', 'userid', 'filesize',
'mimetype', 'status', 'timecreated', 'timemodified',
- 'source', 'author', 'license', 'sortorder'));
+ 'source', 'author', 'license', 'sortorder', 'reference', 'repositoryid'));
// Build the tree
@@ -1412,9 +1412,12 @@ class backup_final_files_structure_step extends backup_structure_step {
// Define sources
- $file->set_source_sql("SELECT f.*
+ $file->set_source_sql("SELECT f.*, r.repositoryid, r.reference
FROM {files} f
- JOIN {backup_ids_temp} bi ON f.id = bi.itemid
+ LEFT JOIN {files_reference} r
+ ON r.id = f.referencefileid
+ JOIN {backup_ids_temp} bi
+ ON f.id = bi.itemid
WHERE bi.backupid = ?
AND bi.itemname = 'filefinal'", array(backup::VAR_BACKUPID));
@@ -1442,6 +1445,8 @@ class backup_main_structure_step extends backup_structure_step {
$info['backup_date'] = time();
$info['backup_uniqueid']= $this->get_backupid();
$info['mnet_remoteusers']=backup_controller_dbops::backup_includes_mnet_remote_users($this->get_backupid());
+ $info['include_file_references_to_external_content'] =
+ backup_controller_dbops::backup_includes_file_references($this->get_backupid());
$info['original_wwwroot']=$CFG->wwwroot;
$info['original_site_identifier_hash'] = md5(get_site_identifier());
$info['original_course_id'] = $this->get_courseid();
@@ -1461,7 +1466,7 @@ class backup_main_structure_step extends backup_structure_step {
$information = new backup_nested_element('information', null, array(
'name', 'moodle_version', 'moodle_release', 'backup_version',
- 'backup_release', 'backup_date', 'mnet_remoteusers', 'original_wwwroot',
+ 'backup_release', 'backup_date', 'mnet_remoteusers', 'include_file_references_to_external_content', 'original_wwwroot',
'original_site_identifier_hash', 'original_course_id',
'original_course_fullname', 'original_course_shortname', 'original_course_startdate',
'original_course_contextid', 'original_system_contextid'));
@@ -1584,8 +1589,12 @@ class backup_store_backup_file extends backup_execution_step {
// Calculate the zip fullpath (in OS temp area it's always backup.mbz)
$zipfile = $basepath . '/backup.mbz';
+ $has_file_references = backup_controller_dbops::backup_includes_file_references($this->get_backupid());
// Perform storage and return it (TODO: shouldn't be array but proper result object)
- return array('backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile));
+ return array(
+ 'backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile),
+ 'include_file_references_to_external_content' => $has_file_references
+ );
}
}
diff --git a/backup/moodle2/backup_xml_transformer.class.php b/backup/moodle2/backup_xml_transformer.class.php
index a3770d03528..25c8503bcf7 100644
--- a/backup/moodle2/backup_xml_transformer.class.php
+++ b/backup/moodle2/backup_xml_transformer.class.php
@@ -27,6 +27,13 @@
defined('MOODLE_INTERNAL') || die();
+// Cache for storing link encoders, so that we don't need to call
+// register_link_encoders each time backup_xml_transformer is constructed
+// TODO MDL-25290 replace global with MUC code.
+global $LINKS_ENCODERS_CACHE;
+
+$LINKS_ENCODERS_CACHE = array();
+
/**
* Class implementing the @xml_contenttrasnformed logic to be applied in moodle2 backups
*
@@ -131,7 +138,19 @@ class backup_xml_transformer extends xml_contenttransformer {
return $result;
}
+ /**
+ * Register all available content link encoders
+ *
+ * @return array encoder
+ * @todo MDL-25290 replace LINKS_ENCODERS_CACHE global with MUC code
+ */
private function register_link_encoders() {
+ global $LINKS_ENCODERS_CACHE;
+ // If encoder is linked, then return cached encoder.
+ if (!empty($LINKS_ENCODERS_CACHE)) {
+ return $LINKS_ENCODERS_CACHE;
+ }
+
$encoders = array();
// Add the course encoder
@@ -160,6 +179,7 @@ class backup_xml_transformer extends xml_contenttransformer {
// Add local encodes
// TODO: Any interest? 1.9 never had that.
+ $LINKS_ENCODERS_CACHE = $encoders;
return $encoders;
}
}
diff --git a/backup/moodle2/restore_final_task.class.php b/backup/moodle2/restore_final_task.class.php
index e8831d71651..377011eef26 100644
--- a/backup/moodle2/restore_final_task.class.php
+++ b/backup/moodle2/restore_final_task.class.php
@@ -135,6 +135,7 @@ class restore_final_task extends restore_task {
$rules[] = new restore_log_rule('course', 'report outline', 'report/outline/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report participation', 'report/participation/index.php?id={course}', '{course}');
$rules[] = new restore_log_rule('course', 'report stats', 'report/stats/index.php?id={course}', '{course}');
+ $rules[] = new restore_log_rule('course', 'view section', 'view.php?id={course}§ion={course_sectionnumber}', '{course_section}');
// module 'user' rules
$rules[] = new restore_log_rule('user', 'view', 'view.php?id={user}&course={course}', '{user}');
diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php
index fda860c9cf1..d87cdb94db9 100644
--- a/backup/moodle2/restore_stepslib.php
+++ b/backup/moodle2/restore_stepslib.php
@@ -586,11 +586,23 @@ class restore_load_included_files extends restore_structure_step {
return array($file);
}
- // Processing functions go here
+ /**
+ * Processing functions go here
+ *
+ * @param array $data one file record including repositoryid and reference
+ */
public function process_file($data) {
$data = (object)$data; // handy
+ $isreference = !empty($data->repositoryid);
+ $issamesite = $this->task->is_samesite();
+
+ // If it's not samesite, we skip file refernces
+ if (!$issamesite && $isreference) {
+ return;
+ }
+
// load it if needed:
// - it it is one of the annotated inforef files (course/section/activity/block)
// - it is one "user", "group", "grouping", "grade", "question" or "qtype_xxxx" component file (that aren't sent to inforef ever)
@@ -601,6 +613,7 @@ class restore_load_included_files extends restore_structure_step {
$data->component == 'grouping' || $data->component == 'grade' ||
$data->component == 'question' || substr($data->component, 0, 5) == 'qtype');
if ($isfileref || $iscomponent) {
+ // Process files
restore_dbops::set_backup_files_record($this->get_restoreid(), $data);
}
}
@@ -1034,6 +1047,7 @@ class restore_section_structure_step extends restore_structure_step {
global $CFG, $DB;
$data = (object)$data;
$oldid = $data->id; // We'll need this later
+ $oldsection = $data->number;
$restorefiles = false;
@@ -1086,10 +1100,12 @@ class restore_section_structure_step extends restore_structure_step {
$DB->update_record('course_sections', $section);
$newitemid = $secrec->id;
+ $oldsection = $secrec->section;
}
// Annotate the section mapping, with restorefiles option if needed
$this->set_mapping('course_section', $oldid, $newitemid, $restorefiles);
+ $this->set_mapping('course_sectionnumber', $oldsection, $section->section, $restorefiles);
// set the new course_section id in the task
$this->task->set_sectionid($newitemid);
@@ -2528,7 +2544,7 @@ class restore_module_structure_step extends restore_structure_step {
$data = (object)$data;
$oldid = $data->id;
-
+ $oldsection = $data->sectionnumber;
$this->task->set_old_moduleversion($data->version);
$data->course = $this->task->get_courseid();
@@ -2555,6 +2571,7 @@ class restore_module_structure_step extends restore_structure_step {
'course' => $this->get_courseid(),
'section' => 1);
$data->section = $DB->insert_record('course_sections', $sectionrec); // section 1
+ $this->set_mapping('course_sectionnumber', $oldsection, $sectionrec->section, $restorefiles);
}
$data->groupingid= $this->get_mappingid('grouping', $data->groupingid); // grouping
if (!$CFG->enablegroupmembersonly) { // observe groupsmemberonly
diff --git a/backup/util/dbops/backup_controller_dbops.class.php b/backup/util/dbops/backup_controller_dbops.class.php
index c77aeb6e4c4..68c17526d2f 100644
--- a/backup/util/dbops/backup_controller_dbops.class.php
+++ b/backup/util/dbops/backup_controller_dbops.class.php
@@ -409,6 +409,27 @@ abstract class backup_controller_dbops extends backup_dbops {
return (int)(bool)$count;
}
+ /**
+ * Given the backupid, detect if the backup contains references to external contents
+ *
+ * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org}
+ * @return int
+ */
+ public static function backup_includes_file_references($backupid) {
+ global $CFG, $DB;
+
+ $sql = "SELECT count(r.repositoryid)
+ FROM {files} f
+ LEFT JOIN {files_reference} r
+ ON r.id = f.referencefileid
+ JOIN {backup_ids_temp} bi
+ ON f.id = bi.itemid
+ WHERE bi.backupid = ?
+ AND bi.itemname = 'filefinal'";
+ $count = $DB->count_records_sql($sql, array($backupid));
+ return (int)(bool)$count;
+ }
+
/**
* Given the courseid, return some course related information we want to transport
*
diff --git a/backup/util/dbops/restore_dbops.class.php b/backup/util/dbops/restore_dbops.class.php
index 25f2e533d1c..81dbaf6ea75 100644
--- a/backup/util/dbops/restore_dbops.class.php
+++ b/backup/util/dbops/restore_dbops.class.php
@@ -28,6 +28,38 @@
* TODO: Finish phpdocs
*/
abstract class restore_dbops {
+ /**
+ * Keep cache of backup records.
+ * @var array
+ * @todo MDL-25290 static should be replaced with MUC code.
+ */
+ private static $backupidscache = array();
+ /**
+ * Keep track of backup ids which are cached.
+ * @var array
+ * @todo MDL-25290 static should be replaced with MUC code.
+ */
+ private static $backupidsexist = array();
+ /**
+ * Count is expensive, so manually keeping track of
+ * backupidscache, to avoid memory issues.
+ * @var int
+ * @todo MDL-25290 static should be replaced with MUC code.
+ */
+ private static $backupidscachesize = 2048;
+ /**
+ * Count is expensive, so manually keeping track of
+ * backupidsexist, to avoid memory issues.
+ * @var int
+ * @todo MDL-25290 static should be replaced with MUC code.
+ */
+ private static $backupidsexistsize = 10240;
+ /**
+ * Slice backupids cache to add more data.
+ * @var int
+ * @todo MDL-25290 static should be replaced with MUC code.
+ */
+ private static $backupidsslice = 512;
/**
* Return one array containing all the tasks that have been included
@@ -151,6 +183,135 @@ abstract class restore_dbops {
return $problems;
}
+ /**
+ * Return cached backup id's
+ *
+ * @param int $restoreid id of backup
+ * @param string $itemname name of the item
+ * @param int $itemid id of item
+ * @return array backup id's
+ * @todo MDL-25290 replace static backupids* with MUC code
+ */
+ protected static function get_backup_ids_cached($restoreid, $itemname, $itemid) {
+ global $DB;
+
+ $key = "$itemid $itemname $restoreid";
+
+ // If record exists in cache then return.
+ if (isset(self::$backupidsexist[$key]) && isset(self::$backupidscache[$key])) {
+ // Return a copy of cached data, to avoid any alterations in cached data.
+ return clone self::$backupidscache[$key];
+ }
+
+ // Clean cache, if it's full.
+ if (self::$backupidscachesize <= 0) {
+ // Remove some records, to keep memory in limit.
+ self::$backupidscache = array_slice(self::$backupidscache, self::$backupidsslice, null, true);
+ self::$backupidscachesize = self::$backupidscachesize + self::$backupidsslice;
+ }
+ if (self::$backupidsexistsize <= 0) {
+ self::$backupidsexist = array_slice(self::$backupidsexist, self::$backupidsslice, null, true);
+ self::$backupidsexistsize = self::$backupidsexistsize + self::$backupidsslice;
+ }
+
+ // Retrive record from database.
+ $record = array(
+ 'backupid' => $restoreid,
+ 'itemname' => $itemname,
+ 'itemid' => $itemid
+ );
+ if ($dbrec = $DB->get_record('backup_ids_temp', $record)) {
+ self::$backupidsexist[$key] = $dbrec->id;
+ self::$backupidscache[$key] = $dbrec;
+ self::$backupidscachesize--;
+ self::$backupidsexistsize--;
+ return $dbrec;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * Cache backup ids'
+ *
+ * @param int $restoreid id of backup
+ * @param string $itemname name of the item
+ * @param int $itemid id of item
+ * @param array $extrarecord extra record which needs to be updated
+ * @return void
+ * @todo MDL-25290 replace static BACKUP_IDS_* with MUC code
+ */
+ protected static function set_backup_ids_cached($restoreid, $itemname, $itemid, $extrarecord) {
+ global $DB;
+
+ $key = "$itemid $itemname $restoreid";
+
+ $record = array(
+ 'backupid' => $restoreid,
+ 'itemname' => $itemname,
+ 'itemid' => $itemid,
+ );
+
+ // If record is not cached then add one.
+ if (!isset(self::$backupidsexist[$key])) {
+ // If we have this record in db, then just update this.
+ if ($existingrecord = $DB->get_record('backup_ids_temp', $record)) {
+ self::$backupidsexist[$key] = $existingrecord->id;
+ self::$backupidsexistsize--;
+ self::update_backup_cached_record($record, $extrarecord, $key, $existingrecord);
+ } else {
+ // Add new record to cache and db.
+ $recorddefault = array (
+ 'newitemid' => 0,
+ 'parentitemid' => null,
+ 'info' => null);
+ $record = array_merge($record, $recorddefault, $extrarecord);
+ $record['id'] = $DB->insert_record('backup_ids_temp', $record);
+ self::$backupidsexist[$key] = $record['id'];
+ self::$backupidsexistsize--;
+ if (self::$backupidscachesize > 0) {
+ // Cache new records if we haven't got many yet.
+ self::$backupidscache[$key] = (object) $record;
+ self::$backupidscachesize--;
+ }
+ }
+ } else {
+ self::update_backup_cached_record($record, $extrarecord, $key);
+ }
+ }
+
+ /**
+ * Updates existing backup record
+ *
+ * @param array $record record which needs to be updated
+ * @param array $extrarecord extra record which needs to be updated
+ * @param string $key unique key which is used to identify cached record
+ * @param stdClass $existingrecord (optional) existing record
+ */
+ protected static function update_backup_cached_record($record, $extrarecord, $key, $existingrecord = null) {
+ global $DB;
+ // Update only if extrarecord is not empty.
+ if (!empty($extrarecord)) {
+ $extrarecord['id'] = self::$backupidsexist[$key];
+ $DB->update_record('backup_ids_temp', $extrarecord);
+ // Update existing cache or add new record to cache.
+ if (isset(self::$backupidscache[$key])) {
+ $record = array_merge((array)self::$backupidscache[$key], $extrarecord);
+ self::$backupidscache[$key] = (object) $record;
+ } else if (self::$backupidscachesize > 0) {
+ if ($existingrecord) {
+ self::$backupidscache[$key] = $existingrecord;
+ } else {
+ // Retrive record from database and cache updated records.
+ self::$backupidscache[$key] = $DB->get_record('backup_ids_temp', $record);
+ }
+ $record = array_merge((array)self::$backupidscache[$key], $extrarecord);
+ self::$backupidscache[$key] = (object) $record;
+ self::$backupidscachesize--;
+ }
+ }
+ }
+
/**
* Given one role, as loaded from XML, perform the best possible matching against the assignable
* roles, using different fallback alternatives (shortname, archetype, editingteacher => teacher, defaultcourseroleid)
@@ -685,6 +846,9 @@ abstract class restore_dbops {
$rs = $DB->get_recordset_sql($sql, $params);
foreach ($rs as $rec) {
$file = (object)unserialize(base64_decode($rec->info));
+
+ $isreference = !empty($file->repositoryid);
+
// ignore root dirs (they are created automatically)
if ($file->filepath == '/' && $file->filename == '.') {
continue;
@@ -697,10 +861,12 @@ abstract class restore_dbops {
$fs->create_directory($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->userid);
continue;
}
+
// arrived here, file found
// Find file in backup pool
$backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash);
- if (!file_exists($backuppath)) {
+
+ if (!file_exists($backuppath) && !$isreference) {
throw new restore_dbops_exception('file_not_found_in_pool', $file);
}
if (!$fs->file_exists($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->filename)) {
@@ -717,7 +883,11 @@ abstract class restore_dbops {
'author' => $file->author,
'license' => $file->license,
'sortorder' => $file->sortorder);
- $fs->create_file_from_pathname($file_record, $backuppath);
+ if ($isreference) {
+ $fs->create_file_from_reference($file_record, $file->repositoryid, $file->reference);
+ } else {
+ $fs->create_file_from_pathname($file_record, $backuppath);
+ }
}
}
$rs->close();
@@ -1204,21 +1374,13 @@ abstract class restore_dbops {
public static function set_backup_files_record($restoreid, $filerec) {
global $DB;
+ // Store external files info in `info` field
$filerec->info = base64_encode(serialize($filerec)); // Serialize the whole rec in info
$filerec->backupid = $restoreid;
$DB->insert_record('backup_files_temp', $filerec);
}
-
public static function set_backup_ids_record($restoreid, $itemname, $itemid, $newitemid = 0, $parentitemid = null, $info = null) {
- global $DB;
-
- // Build the basic (mandatory) record info
- $record = array(
- 'backupid' => $restoreid,
- 'itemname' => $itemname,
- 'itemid' => $itemid
- );
// Build conditionally the extra record info
$extrarecord = array();
if ($newitemid != 0) {
@@ -1231,34 +1393,16 @@ abstract class restore_dbops {
$extrarecord['info'] = base64_encode(serialize($info));
}
- // TODO: Analyze if some static (and limited) cache by the 3 params could save us a bunch of get_record() calls
- // Note: Sure it will! And also will improve getter
- if (!$dbrec = $DB->get_record('backup_ids_temp', $record)) { // Need to insert the complete record
- $DB->insert_record('backup_ids_temp', array_merge($record, $extrarecord));
-
- } else { // Need to update the extra record info if there is something to
- if (!empty($extrarecord)) {
- $extrarecord['id'] = $dbrec->id;
- $DB->update_record('backup_ids_temp', $extrarecord);
- }
- }
+ self::set_backup_ids_cached($restoreid, $itemname, $itemid, $extrarecord);
}
public static function get_backup_ids_record($restoreid, $itemname, $itemid) {
- global $DB;
+ $dbrec = self::get_backup_ids_cached($restoreid, $itemname, $itemid);
- // Build the basic (mandatory) record info to look for
- $record = array(
- 'backupid' => $restoreid,
- 'itemname' => $itemname,
- 'itemid' => $itemid
- );
- // TODO: Analyze if some static (and limited) cache by the 3 params could save us a bunch of get_record() calls
- if ($dbrec = $DB->get_record('backup_ids_temp', $record)) {
- if ($dbrec->info != null) {
- $dbrec->info = unserialize(base64_decode($dbrec->info));
- }
+ if ($dbrec && isset($dbrec->info) && is_string($dbrec->info)) {
+ $dbrec->info = unserialize(base64_decode($dbrec->info));
}
+
return $dbrec;
}
diff --git a/backup/util/helper/backup_cron_helper.class.php b/backup/util/helper/backup_cron_helper.class.php
index d25c7945634..94a7a873189 100644
--- a/backup/util/helper/backup_cron_helper.class.php
+++ b/backup/util/helper/backup_cron_helper.class.php
@@ -315,6 +315,7 @@ abstract class backup_cron_automated_helper {
*/
public static function launch_automated_backup($course, $starttime, $userid) {
+ $outcome = true;
$config = get_config('backup');
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE, backup::INTERACTIVE_NO, backup::MODE_AUTOMATED, $userid);
@@ -347,7 +348,7 @@ abstract class backup_cron_automated_helper {
$bc->set_status(backup::STATUS_AWAITING);
- $outcome = $bc->execute_plan();
+ $bc->execute_plan();
$results = $bc->get_results();
$file = $results['backup_destination'];
$dir = $config->backup_auto_destination;
@@ -363,16 +364,17 @@ abstract class backup_cron_automated_helper {
}
}
- $outcome = true;
- } catch (backup_exception $e) {
- $bc->log('backup_auto_failed_on_course', backup::LOG_WARNING, $course->shortname);
+ } catch (moodle_exception $e) {
+ $bc->log('backup_auto_failed_on_course', backup::LOG_ERROR, $course->shortname); // Log error header.
+ $bc->log('Exception: ' . $e->errorcode, backup::LOG_ERROR, $e->a, 1); // Log original exception problem.
+ $bc->log('Debug: ' . $e->debuginfo, backup::LOG_DEBUG, null, 1); // Log original debug information.
$outcome = false;
}
$bc->destroy();
unset($bc);
- return true;
+ return $outcome;
}
/**
diff --git a/backup/util/helper/backup_file_manager.class.php b/backup/util/helper/backup_file_manager.class.php
index fb6477a6996..9941af7f4b6 100644
--- a/backup/util/helper/backup_file_manager.class.php
+++ b/backup/util/helper/backup_file_manager.class.php
@@ -73,6 +73,10 @@ class backup_file_manager {
$fs = get_file_storage();
$file = $fs->get_file_instance($filerecorid);
+ // If the file is external file, skip copying.
+ if ($file->is_external_file()) {
+ return;
+ }
// Calculate source and target paths (use same subdirs strategy for both)
$targetfilepath = self::get_backup_storage_base_dir($backupid) . '/' .
diff --git a/backup/util/helper/backup_general_helper.class.php b/backup/util/helper/backup_general_helper.class.php
index 73b5d3b4014..ff5dc89ddd1 100644
--- a/backup/util/helper/backup_general_helper.class.php
+++ b/backup/util/helper/backup_general_helper.class.php
@@ -145,6 +145,12 @@ abstract class backup_general_helper extends backup_helper {
$info->original_course_startdate= $infoarr['original_course_startdate'];
$info->original_course_contextid= $infoarr['original_course_contextid'];
$info->original_system_contextid= $infoarr['original_system_contextid'];
+ // Moodle backup file don't have this option before 2.3
+ if (!empty($infoarr['include_file_references_to_external_content'])) {
+ $info->include_file_references_to_external_content = 1;
+ } else {
+ $info->include_file_references_to_external_content = 0;
+ }
$info->type = $infoarr['details']['detail'][0]['type'];
$info->format = $infoarr['details']['detail'][0]['format'];
$info->mode = $infoarr['details']['detail'][0]['mode'];
diff --git a/backup/util/helper/convert_helper.class.php b/backup/util/helper/convert_helper.class.php
index 8f481dec7f2..e5d21b8fbaf 100644
--- a/backup/util/helper/convert_helper.class.php
+++ b/backup/util/helper/convert_helper.class.php
@@ -55,12 +55,6 @@ abstract class convert_helper {
$converters = array();
- // Only apply for backup converters if the (experimental) setting enables it.
- // This will be out once we get proper support of backup converters. MDL-29956
- if (!$restore && empty($CFG->enablebackupconverters)) {
- return $converters;
- }
-
$plugins = get_list_of_plugins('backup/converter');
foreach ($plugins as $name) {
$filename = $restore ? 'lib.php' : 'backuplib.php';
diff --git a/backup/util/plan/base_plan.class.php b/backup/util/plan/base_plan.class.php
index 3ed176b0bbf..eab1869d6d3 100644
--- a/backup/util/plan/base_plan.class.php
+++ b/backup/util/plan/base_plan.class.php
@@ -61,7 +61,12 @@ abstract class base_plan implements checksumable, executable {
// Append task settings to plan array, if not present, for comodity
foreach ($task->get_settings() as $key => $setting) {
if (!in_array($setting, $this->settings)) {
- $this->settings[] = $setting;
+ $name = $setting->get_name();
+ if (!isset($this->settings[$name])) {
+ $this->settings[$name] = $setting;
+ } else {
+ throw new base_plan_exception('multiple_settings_by_name_found', $name);
+ }
}
}
}
@@ -84,23 +89,16 @@ abstract class base_plan implements checksumable, executable {
/**
* return one setting by name, useful to request root/course settings
- * that are, by definition, unique by name. Throws exception if multiple
- * are found
+ * that are, by definition, unique by name.
*
- * TODO: Change this to string indexed array for quicker lookup. Not critical
+ * @param string $name name of the setting
+ * @throws base_plan_exception if setting name is not found.
*/
public function get_setting($name) {
$result = null;
- foreach ($this->settings as $key => $setting) {
- if ($setting->get_name() == $name) {
- if ($result != null) {
- throw new base_plan_exception('multiple_settings_by_name_found', $name);
- } else {
- $result = $setting;
- }
- }
- }
- if (!$result) {
+ if (isset($this->settings[$name])) {
+ $result = $this->settings[$name];
+ } else {
throw new base_plan_exception('setting_by_name_not_found', $name);
}
return $result;
diff --git a/backup/util/ui/backup_ui_stage.class.php b/backup/util/ui/backup_ui_stage.class.php
index 2cc20455259..799556157e0 100644
--- a/backup/util/ui/backup_ui_stage.class.php
+++ b/backup/util/ui/backup_ui_stage.class.php
@@ -124,6 +124,8 @@ class backup_ui_stage_initial extends backup_ui_stage {
// Store as a variable so we can iterate by reference
$tasks = $this->ui->get_tasks();
// Iterate all tasks by reference
+ $add_settings = array();
+ $dependencies = array();
foreach ($tasks as &$task) {
// For the initial stage we are only interested in the root settings
if ($task instanceof backup_root_task) {
@@ -134,17 +136,23 @@ class backup_ui_stage_initial extends backup_ui_stage {
if ($setting->get_name() == 'filename') {
continue;
}
- $form->add_setting($setting, $task);
+ $add_settings[] = array($setting, $task);
}
// Then add all dependencies
foreach ($settings as &$setting) {
if ($setting->get_name() == 'filename') {
continue;
}
- $form->add_dependencies($setting);
+ $dependencies[] = $setting;
}
}
}
+ // Add all settings at once.
+ $form->add_settings($add_settings);
+ // Add dependencies.
+ foreach ($dependencies as $depsetting) {
+ $form->add_dependencies($depsetting);
+ }
$this->stageform = $form;
}
// Return the form
@@ -226,6 +234,8 @@ class backup_ui_stage_schema extends backup_ui_stage {
$tasks = $this->ui->get_tasks();
$content = '';
$courseheading = false;
+ $add_settings = array();
+ $dependencies = array();
foreach ($tasks as $task) {
if (!($task instanceof backup_root_task)) {
if (!$courseheading) {
@@ -235,11 +245,11 @@ class backup_ui_stage_schema extends backup_ui_stage {
}
// First add each setting
foreach ($task->get_settings() as $setting) {
- $form->add_setting($setting, $task);
+ $add_settings[] = array($setting, $task);
}
// The add all the dependencies
foreach ($task->get_settings() as $setting) {
- $form->add_dependencies($setting);
+ $dependencies[] = $setting;
}
} else if ($this->ui->enforce_changed_dependencies()) {
// Only show these settings if dependencies changed them.
@@ -254,6 +264,10 @@ class backup_ui_stage_schema extends backup_ui_stage {
}
}
}
+ $form->add_settings($add_settings);
+ foreach ($dependencies as $depsetting) {
+ $form->add_dependencies($depsetting);
+ }
$this->stageform = $form;
}
return $this->stageform;
@@ -470,6 +484,9 @@ class backup_ui_stage_complete extends backup_ui_stage_final {
$output = '';
$output .= $renderer->box_start();
+ if (!empty($this->results['include_file_references_to_external_content'])) {
+ $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem');
+ }
$output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess');
$output .= $renderer->continue_button($restorerul);
$output .= $renderer->box_end();
diff --git a/backup/util/ui/base_moodleform.class.php b/backup/util/ui/base_moodleform.class.php
index ad992602083..e0ffc0f9fcf 100644
--- a/backup/util/ui/base_moodleform.class.php
+++ b/backup/util/ui/base_moodleform.class.php
@@ -136,24 +136,38 @@ abstract class base_moodleform extends moodleform {
* @return bool
*/
function add_setting(backup_setting $setting, base_task $task=null) {
+ return $this->add_settings(array(array($setting, $task)));
+ }
+ /**
+ * Adds multiple backup_settings as elements to the form
+ * @param array $settingstasks Consists of array($setting, $task) elements
+ * @return bool
+ */
+ public function add_settings(array $settingstasks) {
global $OUTPUT;
- // If the setting cant be changed or isn't visible then add it as a fixed setting.
- if (!$setting->get_ui()->is_changeable() || $setting->get_visibility() != backup_setting::VISIBLE) {
- return $this->add_fixed_setting($setting, $task);
- }
+ $defaults = array();
+ foreach ($settingstasks as $st) {
+ list($setting, $task) = $st;
+ // If the setting cant be changed or isn't visible then add it as a fixed setting.
+ if (!$setting->get_ui()->is_changeable() || $setting->get_visibility() != backup_setting::VISIBLE) {
+ $this->add_fixed_setting($setting, $task);
+ continue;
+ }
- // First add the formatting for this setting
- $this->add_html_formatting($setting);
+ // First add the formatting for this setting
+ $this->add_html_formatting($setting);
- // The call the add method with the get_element_properties array
- call_user_func_array(array($this->_form, 'addElement'), $setting->get_ui()->get_element_properties($task, $OUTPUT));
- $this->_form->setDefault($setting->get_ui_name(), $setting->get_value());
- if ($setting->has_help()) {
- list($identifier, $component) = $setting->get_help();
- $this->_form->addHelpButton($setting->get_ui_name(), $identifier, $component);
+ // Then call the add method with the get_element_properties array
+ call_user_func_array(array($this->_form, 'addElement'), $setting->get_ui()->get_element_properties($task, $OUTPUT));
+ $defaults[$setting->get_ui_name()] = $setting->get_value();
+ if ($setting->has_help()) {
+ list($identifier, $component) = $setting->get_help();
+ $this->_form->addHelpButton($setting->get_ui_name(), $identifier, $component);
+ }
+ $this->_form->addElement('html', html_writer::end_tag('div'));
}
- $this->_form->addElement('html', html_writer::end_tag('div'));
+ $this->_form->setDefaults($defaults);
return true;
}
/**
@@ -317,4 +331,4 @@ abstract class base_moodleform extends moodleform {
$this->definition_after_data();
}
}
-}
\ No newline at end of file
+}
diff --git a/backup/util/ui/renderer.php b/backup/util/ui/renderer.php
index 7afcdfd368a..9e0ab9dd4f9 100644
--- a/backup/util/ui/renderer.php
+++ b/backup/util/ui/renderer.php
@@ -92,6 +92,16 @@ class core_backup_renderer extends plugin_renderer_base {
$html .= $this->backup_detail_pair(get_string('originalwwwroot', 'backup'),
html_writer::tag('span', $details->original_wwwroot, array('class'=>'originalwwwroot')).
html_writer::tag('span', '['.$details->original_site_identifier_hash.']', array('class'=>'sitehash sub-detail')));
+ if (!empty($details->include_file_references_to_external_content)) {
+ $message = '';
+ if (backup_general_helper::backup_is_samesite($details)) {
+ $message = $yestick . ' ' . get_string('filereferencessamesite', 'backup');
+ } else {
+ $message = $notick . ' ' . get_string('filereferencesnotsamesite', 'backup');
+ }
+ $html .= $this->backup_detail_pair(get_string('includefilereferences', 'backup'), $message);
+ }
+
$html .= html_writer::end_tag('div');
$html .= html_writer::start_tag('div', array('class'=>'backup-section settings-section'));
diff --git a/blocks/activity_modules/block_activity_modules.php b/blocks/activity_modules/block_activity_modules.php
index c290b2444f4..2aa257865c9 100644
--- a/blocks/activity_modules/block_activity_modules.php
+++ b/blocks/activity_modules/block_activity_modules.php
@@ -1,5 +1,8 @@
libdir . '/filelib.php');
+
class block_activity_modules extends block_list {
function init() {
$this->title = get_string('pluginname', 'block_activity_modules');
@@ -50,7 +53,7 @@ class block_activity_modules extends block_list {
foreach ($modfullnames as $modname => $modfullname) {
if ($modname === 'resources') {
- $icon = ' ';
+ $icon = $OUTPUT->pix_icon(file_extension_icon('.htm'), '', 'moodle', array('class' => 'icon')). ' ';
$this->content->items[] = ''.$icon.$modfullname.'';
} else {
$icon = '
';
diff --git a/blocks/private_files/block_private_files.php b/blocks/private_files/block_private_files.php
index 594f27600f5..bf4cc89c10b 100644
--- a/blocks/private_files/block_private_files.php
+++ b/blocks/private_files/block_private_files.php
@@ -62,7 +62,7 @@ class block_private_files extends block_base {
$renderer = $this->page->get_renderer('block_private_files');
$this->content->text = $renderer->private_files_tree();
if (has_capability('moodle/user:manageownfiles', $this->context)) {
- $this->content->text .= $OUTPUT->single_button(new moodle_url('/user/filesedit.php', array('returnurl'=>$PAGE->url->out())), get_string('myfilesmanage'), 'get');
+ $this->content->text .= $OUTPUT->single_button(new moodle_url('/user/files.php', array('returnurl'=>$PAGE->url->out())), get_string('myfilesmanage'), 'get');
}
$this->content->footer = '';
diff --git a/blocks/private_files/edit.php b/blocks/private_files/edit.php
index 5a7667bbd76..67b1e70d5bc 100644
--- a/blocks/private_files/edit.php
+++ b/blocks/private_files/edit.php
@@ -45,7 +45,7 @@ $PAGE->set_pagelayout('mydashboard');
$PAGE->set_pagetype('user-private-files');
$data = new stdClass();
-$options = array('subdirs'=>1, 'maxbytes'=>$CFG->userquota, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
+$options = array('subdirs'=>1, 'maxbytes'=>$CFG->userquota, 'maxfiles'=>-1, 'accepted_types'=>'*');
file_prepare_standard_filemanager($data, 'files', $options, $context, 'user', 'private', 0);
$mform = new block_private_files_form(null, array('data'=>$data, 'options'=>$options));
diff --git a/blocks/private_files/renderer.php b/blocks/private_files/renderer.php
index 5c27971e55a..eb109faa1b8 100644
--- a/blocks/private_files/renderer.php
+++ b/blocks/private_files/renderer.php
@@ -65,14 +65,13 @@ class block_private_files_renderer extends plugin_renderer_base {
}
$result = '
+ *- ...
+ * - ...
+ * ...
+ *
+ * + * @return {object} section list configuration */ -M.course.format.get_section_selector = function(Y) { - return 'li.section'; +M.course.format.get_config = function() { + return { + container_node : 'ul', + container_class : 'topics', + section_node : 'li', + section_class : 'section' + }; } /** @@ -25,13 +36,32 @@ M.course.format.get_section_selector = function(Y) { M.course.format.swap_sections = function(Y, node1, node2) { var CSS = { COURSECONTENT : 'course-content', - LEFT : 'left', SECTIONADDMENUS : 'section_add_menus' }; var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y)); - // Swap left block - sectionlist.item(node1).one('.'+CSS.LEFT).swap(sectionlist.item(node2).one('.'+CSS.LEFT)); // Swap menus sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS)); } + +/** + * Process sections after ajax response + * + * @param {YUI} Y YUI3 instance + * @param {array} response ajax response + * @param {string} sectionfrom first affected section + * @param {string} sectionto last affected section + * @return void + */ +M.course.format.process_sections = function(Y, sectionlist, response, sectionfrom, sectionto) { + var CSS = { + SECTIONNAME : 'sectionname' + }; + + if (response.action == 'move') { + // update titles in all affected sections + for (var i = sectionfrom; i <= sectionto; i++) { + sectionlist.item(i).one('.'+CSS.SECTIONNAME).setContent(response.sectiontitles[i]); + } + } +} diff --git a/course/format/topics/lib.php b/course/format/topics/lib.php index 710abaf318e..e8632fcab8b 100644 --- a/course/format/topics/lib.php +++ b/course/format/topics/lib.php @@ -80,3 +80,24 @@ function callback_topics_ajax_support() { $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); return $ajaxsupport; } + +/** + * Callback function to do some action after section move + * + * @param stdClass $course The course entry from DB + * @return array This will be passed in ajax respose. + */ +function callback_topics_ajax_section_move($course) { + global $COURSE, $PAGE; + + $titles = array(); + rebuild_course_cache($course->id); + $modinfo = get_fast_modinfo($COURSE); + $renderer = $PAGE->get_renderer('format_topics'); + if ($renderer && ($sections = $modinfo->get_section_info_all())) { + foreach ($sections as $number => $section) { + $titles[$number] = $renderer->section_title($section, $course); + } + } + return array('sectiontitles' => $titles, 'action' => 'move'); +} diff --git a/course/format/topics/renderer.php b/course/format/topics/renderer.php index 7050488c5b1..5ef126f5987 100644 --- a/course/format/topics/renderer.php +++ b/course/format/topics/renderer.php @@ -102,23 +102,4 @@ class format_topics_renderer extends format_section_renderer_base { return array_merge($controls, parent::section_edit_controls($course, $section, $onsectionpage)); } - - /** - * Generate the content to displayed on the left part of a section - * - * before course modules are included - * @param stdClass $section The course_section entry from DB - * @param stdClass $course The course entry from DB - * @param bool $onsectionpage true if being printed on a section page - * @return string HTML to output. - */ - protected function section_left_content($section, $course, $onsectionpage) { - $o = parent::section_left_content($section, $course, $onsectionpage); - - if ($section->section > 0) { - $o.= $section->section; - } - - return $o; - } } diff --git a/course/format/weeks/format.js b/course/format/weeks/format.js index 78c20631b70..f410e07d357 100644 --- a/course/format/weeks/format.js +++ b/course/format/weeks/format.js @@ -1,17 +1,28 @@ -// Javascript functions for course format +// Javascript functions for Weeks course format M.course = M.course || {}; M.course.format = M.course.format || {}; /** - * Get section list for this format + * Get sections config for this format * - * @param {YUI} Y YUI3 instance - * @return {string} section list selector + * The section structure is: + *+ *- ...
+ * - ...
+ * ...
+ *
+ * + * @return {object} section list configuration */ -M.course.format.get_section_selector = function(Y) { - return 'li.section'; +M.course.format.get_config = function() { + return { + container_node : 'ul', + container_class : 'weeks', + section_node : 'li', + section_class : 'section' + }; } /** @@ -25,16 +36,32 @@ M.course.format.get_section_selector = function(Y) { M.course.format.swap_sections = function(Y, node1, node2) { var CSS = { COURSECONTENT : 'course-content', - LEFT : 'left', SECTIONADDMENUS : 'section_add_menus', - WEEKDATES: 'weekdates' }; var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y)); - // Swap left block - sectionlist.item(node1).one('.'+CSS.LEFT).swap(sectionlist.item(node2).one('.'+CSS.LEFT)); // Swap menus sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS)); - // Swap week dates - sectionlist.item(node1).one('.'+CSS.WEEKDATES).swap(sectionlist.item(node2).one('.'+CSS.WEEKDATES)); +} + +/** + * Process sections after ajax response + * + * @param {YUI} Y YUI3 instance + * @param {array} response ajax response + * @param {string} sectionfrom first affected section + * @param {string} sectionto last affected section + * @return void + */ +M.course.format.process_sections = function(Y, sectionlist, response, sectionfrom, sectionto) { + var CSS = { + SECTIONNAME : 'sectionname' + }; + + if (response.action == 'move') { + // update titles in all affected sections + for (var i = sectionfrom; i <= sectionto; i++) { + sectionlist.item(i).one('.'+CSS.SECTIONNAME).setContent(response.sectiontitles[i]); + } + } } diff --git a/course/format/weeks/lib.php b/course/format/weeks/lib.php index 9201c9e2d6f..a1e1ea9cd16 100644 --- a/course/format/weeks/lib.php +++ b/course/format/weeks/lib.php @@ -67,25 +67,20 @@ function callback_weeks_definition() { function callback_weeks_get_section_name($course, $section) { // We can't add a node without text if (!empty($section->name)) { - // Return the name the user set - return format_string($section->name, true, array('context' => get_context_instance(CONTEXT_COURSE, $course->id))); + // Return the name the user set. + return format_string($section->name, true, array('context' => context_course::instance($course->id))); } else if ($section->section == 0) { - // Return the section0name + // Return the general section. return get_string('section0name', 'format_weeks'); } else { - // Got to work out the date of the week so that we can show it - $sections = get_all_sections($course->id); - $weekdate = $course->startdate+7200; - foreach ($sections as $sec) { - if ($sec->id == $section->id) { - break; - } else if ($sec->section != 0) { - $weekdate += 604800; - } - } - $strftimedateshort = ' '.get_string('strftimedateshort'); - $weekday = userdate($weekdate, $strftimedateshort); - $endweekday = userdate($weekdate+518400, $strftimedateshort); + $dates = format_weeks_get_section_dates($section, $course); + + // We subtract 24 hours for display purposes. + $dates->end = ($dates->end - 86400); + + $dateformat = ' '.get_string('strftimedateshort'); + $weekday = userdate($dates->start, $dateformat); + $endweekday = userdate($dates->end, $dateformat); return $weekday.' - '.$endweekday; } } @@ -102,3 +97,44 @@ function callback_weeks_ajax_support() { $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); return $ajaxsupport; } + +/** + * Return the start and end date of the passed section + * + * @param stdClass $section The course_section entry from the DB + * @param stdClass $course The course entry from DB + * @return stdClass property start for startdate, property end for enddate + */ +function format_weeks_get_section_dates($section, $course) { + $oneweekseconds = 604800; + // Hack alert. We add 2 hours to avoid possible DST problems. (e.g. we go into daylight + // savings and the date changes. + $startdate = $course->startdate + 7200; + + $dates = new stdClass(); + $dates->start = $startdate + ($oneweekseconds * ($section->section - 1)); + $dates->end = $dates->start + $oneweekseconds; + + return $dates; +} + +/** + * Callback function to do some action after section move + * + * @param stdClass $course The course entry from DB + * @return array This will be passed in ajax respose. + */ +function callback_weeks_ajax_section_move($course) { + global $COURSE, $PAGE; + + $titles = array(); + rebuild_course_cache($course->id); + $modinfo = get_fast_modinfo($COURSE); + $renderer = $PAGE->get_renderer('format_weeks'); + if ($renderer && ($sections = $modinfo->get_section_info_all())) { + foreach ($sections as $number => $section) { + $titles[$number] = $renderer->section_title($section, $course); + } + } + return array('sectiontitles' => $titles, 'action' => 'move'); +} diff --git a/course/format/weeks/renderer.php b/course/format/weeks/renderer.php index 33d640281b6..e87936ccbf5 100644 --- a/course/format/weeks/renderer.php +++ b/course/format/weeks/renderer.php @@ -26,6 +26,7 @@ defined('MOODLE_INTERNAL') || die(); require_once($CFG->dirroot.'/course/format/renderer.php'); +require_once($CFG->dirroot.'/course/format/weeks/lib.php'); /** @@ -58,4 +59,22 @@ class format_weeks_renderer extends format_section_renderer_base { protected function page_title() { return get_string('weeklyoutline'); } + + /** + * Is the section passed in the current section? + * + * @param stdClass $section The course_section entry from the DB + * @param stdClass $course The course entry from DB + * @return bool true if the section is current + */ + protected function is_section_current($section, $course) { + if ($section->section < 1) { + return false; + } + + $timenow = time(); + $dates = format_weeks_get_section_dates($section, $course); + + return (($timenow >= $dates->start) && ($timenow < $dates->end)); + } } diff --git a/course/lib.php b/course/lib.php index 9a64052c153..a5566d6a6bc 100644 --- a/course/lib.php +++ b/course/lib.php @@ -1518,13 +1518,6 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false, //Accessibility: for files get description via icon, this is very ugly hack! $altname = ''; $altname = $mod->modfullname; - if (!empty($customicon)) { - $archetype = plugin_supports('mod', $mod->modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER); - if ($archetype == MOD_ARCHETYPE_RESOURCE) { - $mimetype = mimeinfo_from_icon('type', $customicon); - $altname = get_mimetype_description($mimetype); - } - } // Avoid unnecessary duplication: if e.g. a forum name already // includes the word forum (or Forum, etc) then it is unhelpful // to include that in the accessible description that is added. @@ -1735,7 +1728,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false, // see the activity itself, or for staff) if (!$mod->uservisible) { echo '$activity->name
"; + if (!empty($activity->name)) { + echo html_writer::tag('h2', $activity->name); + } $inbox = true; } else if ($activity->type == 'activity') { @@ -230,16 +232,17 @@ if (!empty($activities)) { $cm = $modinfo->cms[$activity->cmid]; if ($cm->visible) { - $linkformat = ''; + $class = ''; } else { - $linkformat = 'class="dimmed"'; + $class = 'dimmed'; } $name = format_string($cm->name); $modfullname = $modnames[$cm->modname]; - $image = "$image $modfullname". - " wwwroot/mod/$cm->modname/view.php?id=$cm->id\" $linkformat>$name
"; + $image = $OUTPUT->pix_icon('icon', $modfullname, $cm->modname, array('class' => 'icon smallicon')); + $link = html_writer::link(new moodle_url("/mod/$cm->modname/view.php", + array("id" => $cm->id)), $name, array('class' => $class)); + echo html_writer::tag('h3', "$image $modfullname $link"); } } else { @@ -269,7 +272,7 @@ if (!empty($activities)) { } else { - echo '' . get_string('norecentactivity') . '
'; + echo html_writer::tag('h3', get_string('norecentactivity'), array('class' => 'mdl-align')); } diff --git a/course/rest.php b/course/rest.php index 5152563ad92..6efd228db65 100644 --- a/course/rest.php +++ b/course/rest.php @@ -89,6 +89,15 @@ switch($requestmethod) { case 'move': move_section_to($course, $id, $value); + // See if format wants to do something about it + $libfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php'; + $functionname = 'callback_'.$course->format.'_ajax_section_move'; + if (!function_exists($functionname) && file_exists($libfile)) { + require_once $libfile; + } + if (function_exists($functionname)) { + echo json_encode($functionname($course)); + } break; } rebuild_course_cache($course->id); diff --git a/course/view.php b/course/view.php index a7b1784b1c5..de3798102d2 100644 --- a/course/view.php +++ b/course/view.php @@ -88,8 +88,18 @@ require_once($CFG->dirroot.'/calendar/lib.php'); /// This is after login because it needs $USER - //TODO: danp do we need different urls? - add_to_log($course->id, 'course', 'view', "view.php?id=$course->id", "$course->id"); + $logparam = 'id='. $course->id; + $loglabel = 'view'; + $infoid = $course->id; + if(!empty($section)) { + $logparam .= '§ion='. $section; + $loglabel = 'view section'; + $sectionparams = array('course' => $course->id, 'section' => $section); + if ($coursesections = $DB->get_record('course_sections', $sectionparams, 'id', MUST_EXIST)) { + $infoid = $coursesections->id; + } + } + add_to_log($course->id, 'course', $loglabel, "view.php?". $logparam, $infoid); $course->format = clean_param($course->format, PARAM_ALPHA); if (!file_exists($CFG->dirroot.'/course/format/'.$course->format.'/format.php')) { diff --git a/course/yui/coursebase/coursebase.js b/course/yui/coursebase/coursebase.js index 713ad709d95..b02c36263c0 100644 --- a/course/yui/coursebase/coursebase.js +++ b/course/yui/coursebase/coursebase.js @@ -52,6 +52,171 @@ YUI.add('moodle-course-coursebase', function(Y) { // Ensure that M.course exists and that coursebase is initialised correctly M.course = M.course || {}; M.course.coursebase = M.course.coursebase || new COURSEBASE(); + + // Abstract functions that needs to be defined per format (course/format/somename/format.js) + M.course.format = M.course.format || {} + + /** + * Swap section (should be defined in format.js if requred) + * + * @param {YUI} Y YUI3 instance + * @param {string} node1 node to swap to + * @param {string} node2 node to swap with + * @return {NodeList} section list + */ + M.course.format.swap_sections = M.course.format.swap_sections || function(Y, node1, node2) { + return null; + } + + /** + * Process sections after ajax response (should be defined in format.js) + * If some response is expected, we pass it over to format, as it knows better + * hot to process it. + * + * @param {YUI} Y YUI3 instance + * @param {NodeList} list of sections + * @param {array} response ajax response + * @param {string} sectionfrom first affected section + * @param {string} sectionto last affected section + * @return void + */ + M.course.format.process_sections = M.course.format.process_sections || function(Y, sectionlist, response, sectionfrom, sectionto) { + return null; + } + + /** + * Get sections config for this format, for examples see function definition + * in the formats. + * + * @return {object} section list configuration + */ + M.course.format.get_config = M.course.format.get_config || function() { + return { + container_node : null, // compulsory + container_class : null, // compulsory + section_wrapper_node : null, // optional + section_wrapper_class : null, // optional + section_node : null, // compulsory + section_class : null // compulsory + } + } + + /** + * Get section list for this format (usually items inside container_node.container_class selector) + * + * @param {YUI} Y YUI3 instance + * @return {string} section selector + */ + M.course.format.get_section_selector = M.course.format.get_section_selector || function(Y) { + var config = M.course.format.get_config(); + if (config.section_node && config.section_class) { + return config.section_node + '.' + config.section_class; + } + console.log('section_node and section_class are not defined in M.course.format.get_config'); + return null; + } + + /** + * Get section wraper for this format (only used in case when each + * container_node.container_class node is wrapped in some other element). + * + * @param {YUI} Y YUI3 instance + * @return {string} section wrapper selector or M.course.format.get_section_selector + * if section_wrapper_node and section_wrapper_class are not defined in the format config. + */ + M.course.format.get_section_wrapper = M.course.format.get_section_wrapper || function(Y) { + var config = M.course.format.get_config(); + if (config.section_wrapper_node && config.section_wrapper_class) { + return config.section_wrapper_node + '.' + config.section_wrapper_class; + } + return M.course.format.get_section_selector(Y); + } + + /** + * Get the tag of container node + * + * @return {string} tag of container node. + */ + M.course.format.get_containernode = M.course.format.get_containernode || function() { + var config = M.course.format.get_config(); + if (config.container_node) { + return config.container_node; + } else { + console.log('container_node is not defined in M.course.format.get_config'); + } + } + + /** + * Get the class of container node + * + * @return {string} class of the container node. + */ + M.course.format.get_containerclass = M.course.format.get_containerclass || function() { + var config = M.course.format.get_config(); + if (config.container_class) { + return config.container_class; + } else { + console.log('container_class is not defined in M.course.format.get_config'); + } + } + + /** + * Get the tag of draggable node (section wrapper if exists, otherwise section) + * + * @return {string} tag of the draggable node. + */ + M.course.format.get_sectionwrappernode = M.course.format.get_sectionwrappernode || function() { + var config = M.course.format.get_config(); + if (config.section_wrapper_node) { + return config.section_wrapper_node; + } else { + return config.section_node; + } + } + + /** + * Get the class of draggable node (section wrapper if exists, otherwise section) + * + * @return {string} class of the draggable node. + */ + M.course.format.get_sectionwrapperclass = M.course.format.get_sectionwrapperclass || function() { + var config = M.course.format.get_config(); + if (config.section_wrapper_class) { + return config.section_wrapper_class; + } else { + return config.section_class; + } + } + + /** + * Get the tag of section node + * + * @return {string} tag of section node. + */ + M.course.format.get_sectionnode = M.course.format.get_sectionnode || function() { + var config = M.course.format.get_config(); + if (config.section_node) { + return config.section_node; + } else { + console.log('section_node is not defined in M.course.format.get_config'); + } + } + + /** + * Get the class of section node + * + * @return {string} class of the section node. + */ + M.course.format.get_sectionclass = M.course.format.get_sectionclass || function() { + var config = M.course.format.get_config(); + if (config.section_class) { + return config.section_class; + } else { + console.log('section_class is not defined in M.course.format.get_config'); + } + + } + }, '@VERSION@', { requires : ['base', 'node'] diff --git a/course/yui/dragdrop/dragdrop.js b/course/yui/dragdrop/dragdrop.js index c3ed979443b..080cace768d 100644 --- a/course/yui/dragdrop/dragdrop.js +++ b/course/yui/dragdrop/dragdrop.js @@ -17,9 +17,7 @@ YUI.add('moodle-course-dragdrop', function(Y) { SECTION : 'section', SECTIONADDMENUS : 'section_add_menus', SECTIONHANDLE : 'section-handle', - SUMMARY : 'summary', - TOPICS : 'topics', - WEEKDATES: 'weekdates' + SUMMARY : 'summary' }; var DRAGSECTION = function() { @@ -31,16 +29,17 @@ YUI.add('moodle-course-dragdrop', function(Y) { initializer : function(params) { // Set group for parent class this.groups = ['section']; - this.samenodeclass = CSS.SECTION; - this.parentnodeclass = CSS.TOPICS; + this.samenodeclass = M.course.format.get_sectionwrapperclass(); + this.parentnodeclass = M.course.format.get_containerclass(); // Check if we are in single section mode if (Y.Node.one('.'+CSS.JUMPMENU)) { return false; } // Initialise sections dragging - if (M.course.format && M.course.format.get_section_selector && typeof(M.course.format.get_section_selector) == 'function') { - this.sectionlistselector = '.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y); + this.sectionlistselector = M.course.format.get_section_wrapper(Y); + if (this.sectionlistselector) { + this.sectionlistselector = '.'+CSS.COURSECONTENT+' '+this.sectionlistselector; this.setup_for_section(this.sectionlistselector); } }, @@ -109,17 +108,24 @@ YUI.add('moodle-course-dragdrop', function(Y) { // Get our drag object var drag = e.target; // Creat a dummy structure of the outer elemnents for clean styles application - var ul = Y.Node.create(''); - ul.addClass(CSS.TOPICS); - var li = Y.Node.create(''); - li.addClass(CSS.SECTION); - li.setStyle('margin', 0); - li.setContent(drag.get('node').get('innerHTML')); - ul.appendChild(li); - drag.get('dragNode').setContent(ul); + var containernode = Y.Node.create('<'+M.course.format.get_containernode()+'>'+M.course.format.get_containernode()+'>'); + containernode.addClass(M.course.format.get_containerclass()); + var sectionnode = Y.Node.create('<'+ M.course.format.get_sectionwrappernode()+'>'+ M.course.format.get_sectionwrappernode()+'>'); + sectionnode.addClass( M.course.format.get_sectionwrapperclass()); + sectionnode.setStyle('margin', 0); + sectionnode.setContent(drag.get('node').get('innerHTML')); + containernode.appendChild(sectionnode); + drag.get('dragNode').setContent(containernode); drag.get('dragNode').addClass(CSS.COURSECONTENT); }, + drag_dropmiss : function(e) { + // Missed the target, but we assume the user intended to drop it + // on the last last ghost node location, e.drag and e.drop should be + // prepared by global_drag_dropmiss parent so simulate drop_hit(e). + this.drop_hit(e); + }, + drop_hit : function(e) { var drag = e.drag; // Get a reference to our drag node @@ -173,9 +179,16 @@ YUI.add('moodle-course-dragdrop', function(Y) { lightbox.show(); }, success: function(tid, response) { - window.setTimeout(function(e) { - lightbox.hide(); - }, 250); + // Update section titles, we can't simply swap them as + // they might have custom title + try { + var responsetext = Y.JSON.parse(response.responseText); + if (responsetext.error) { + new M.core.ajaxException(responsetext); + } + M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend); + } catch (e) {} + // Classic bubble sort algorithm is applied to the section // nodes between original drag node location and the new one. do { @@ -186,16 +199,19 @@ YUI.add('moodle-course-dragdrop', function(Y) { var sectionid = sectionlist.item(i-1).get('id'); sectionlist.item(i-1).set('id', sectionlist.item(i).get('id')); sectionlist.item(i).set('id', sectionid); - // See what format needs to be swapped - if (M.course.format && M.course.format.swap_sections && typeof(M.course.format.swap_sections) == 'function') { - M.course.format.swap_sections(Y, i-1, i); - } + // See what format needs to swap + M.course.format.swap_sections(Y, i-1, i); // Update flag swapped = true; } } loopend = loopend - 1; } while (swapped); + + // Finally, hide the lightbox + window.setTimeout(function(e) { + lightbox.hide(); + }, 250); }, failure: function(tid, response) { this.ajax_failure(response); @@ -232,8 +248,9 @@ YUI.add('moodle-course-dragdrop', function(Y) { this.parentnodeclass = CSS.SECTION; // Go through all sections - if (M.course.format && M.course.format.get_section_selector && typeof(M.course.format.get_section_selector) == 'function') { - var sectionlistselector = '.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y); + var sectionlistselector = M.course.format.get_section_selector(Y); + if (sectionlistselector) { + sectionlistselector = '.'+CSS.COURSECONTENT+' '+sectionlistselector; this.setup_for_section(sectionlistselector); M.course.coursebase.register_module(this); M.course.dragres = this; @@ -263,7 +280,7 @@ YUI.add('moodle-course-dragdrop', function(Y) { padding: '20 0 20 0' }); // Go through each li element and make them draggable - this.setup_for_resource('li#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY); + this.setup_for_resource('#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY); }, this); }, /** @@ -311,14 +328,19 @@ YUI.add('moodle-course-dragdrop', function(Y) { drag.get('dragNode').all('img.iconsmall').setStyle('vertical-align', 'baseline'); }, + drag_dropmiss : function(e) { + // Missed the target, but we assume the user intended to drop it + // on the last last ghost node location, e.drag and e.drop should be + // prepared by global_drag_dropmiss parent so simulate drop_hit(e). + this.drop_hit(e); + }, + drop_hit : function(e) { var drag = e.drag; // Get a reference to our drag node var dragnode = drag.get('node'); var dropnode = e.drop.get('node'); - var sectionselector = M.course.format.get_section_selector(Y); - // Add spinner if it not there var spinner = M.util.add_spinner(Y, dragnode.one(CSS.COMMANDSPAN)); @@ -336,7 +358,7 @@ YUI.add('moodle-course-dragdrop', function(Y) { params['class'] = 'resource'; params.field = 'move'; params.id = Number(this.get_resource_id(dragnode)); - params.sectionId = this.get_section_id(dropnode.ancestor(sectionselector)); + params.sectionId = this.get_section_id(dropnode.ancestor(M.course.format.get_section_wrapper(Y), true)); if (dragnode.next()) { params.beforeId = Number(this.get_resource_id(dragnode.next())); diff --git a/course/yui/toolboxes/toolboxes.js b/course/yui/toolboxes/toolboxes.js index 6dfcce0bd7d..024785ebf4b 100644 --- a/course/yui/toolboxes/toolboxes.js +++ b/course/yui/toolboxes/toolboxes.js @@ -28,7 +28,7 @@ YUI.add('moodle-course-toolboxes', function(Y) { MOVELEFTCLASS : 'editing_moveleft', MOVERIGHT : 'a.editing_moveright', PAGECONTENT : 'div#page-content', - RIGHTDIV : 'div.right', + RIGHTSIDE : '.right', SECTIONHIDDENCLASS : 'hidden', SECTIONIDPREFIX : 'section-', SECTIONLI : 'li.section', @@ -384,7 +384,7 @@ YUI.add('moodle-course-toolboxes', function(Y) { e.preventDefault(); // Return early if the current section is hidden - var section = e.target.ancestor(CSS.SECTIONLI); + var section = e.target.ancestor(M.course.format.get_section_selector(Y)); if (section && section.hasClass(CSS.SECTIONHIDDENCLASS)) { return; } @@ -649,17 +649,17 @@ YUI.add('moodle-course-toolboxes', function(Y) { }, _setup_for_section : function(toolboxtarget) { // Section Highlighting - this.replace_button(toolboxtarget, CSS.RIGHTDIV + ' ' + CSS.HIGHLIGHT, this.toggle_highlight); + this.replace_button(toolboxtarget, CSS.RIGHTSIDE + ' ' + CSS.HIGHLIGHT, this.toggle_highlight); // Section Visibility - this.replace_button(toolboxtarget, CSS.RIGHTDIV + ' ' + CSS.SHOWHIDE, this.toggle_hide_section); + this.replace_button(toolboxtarget, CSS.RIGHTSIDE + ' ' + CSS.SHOWHIDE, this.toggle_hide_section); }, toggle_hide_section : function(e) { // Prevent the default button action e.preventDefault(); // Get the section we're working on - var section = e.target.ancestor(CSS.SECTIONLI); + var section = e.target.ancestor(M.course.format.get_section_selector(Y)); var button = e.target.ancestor('a', true); var hideicon = button.one('img'); @@ -691,7 +691,7 @@ YUI.add('moodle-course-toolboxes', function(Y) { var data = { 'class' : 'section', 'field' : 'visible', - 'id' : this.get_section_id(section), + 'id' : this.get_section_id(section.ancestor(M.course.format.get_section_wrapper(Y), true)), 'value' : value }; @@ -725,7 +725,7 @@ YUI.add('moodle-course-toolboxes', function(Y) { e.preventDefault(); // Get the section we're working on - var section = e.target.ancestor(CSS.SECTIONLI); + var section = e.target.ancestor(M.course.format.get_section_selector(Y)); var button = e.target.ancestor('a', true); var buttonicon = button.one('img'); @@ -736,22 +736,22 @@ YUI.add('moodle-course-toolboxes', function(Y) { // Set the current highlighted item text var old_string = M.util.get_string('markthistopic', 'moodle'); Y.one(CSS.PAGECONTENT) - .all(CSS.SECTIONLI + '.current ' + CSS.HIGHLIGHT) + .all(M.course.format.get_section_selector(Y) + '.current ' + CSS.HIGHLIGHT) .set('title', old_string); Y.one(CSS.PAGECONTENT) - .all(CSS.SECTIONLI + '.current ' + CSS.HIGHLIGHT + ' img') + .all(M.course.format.get_section_selector(Y) + '.current ' + CSS.HIGHLIGHT + ' img') .set('title', old_string) .set('alt', old_string) .set('src', M.util.image_url('i/marker')); // Remove the highlighting from all sections - var allsections = Y.one(CSS.PAGECONTENT).all(CSS.SECTIONLI) + var allsections = Y.one(CSS.PAGECONTENT).all(M.course.format.get_section_selector(Y)) .removeClass('current'); // Then add it if required to the selected section if (!togglestatus) { section.addClass('current'); - value = this.get_section_id(section); + value = this.get_section_id(section.ancestor(M.course.format.get_section_wrapper(Y), true)); var new_string = M.util.get_string('markedthistopic', 'moodle'); button .set('title', new_string); diff --git a/draftfile.php b/draftfile.php index baeceaf7af7..ede57069134 100644 --- a/draftfile.php +++ b/draftfile.php @@ -36,6 +36,7 @@ if (isguestuser()) { } $relativepath = get_file_argument(); +$preview = optional_param('preview', null, PARAM_ALPHANUM); // relative path must start with '/' if (!$relativepath) { @@ -84,4 +85,4 @@ if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->get_filename() == // finally send the file // ======================================== session_get_instance()->write_close(); // unlock session during fileserving -send_stored_file($file, 0, false, true); // force download - security first! +send_stored_file($file, 0, false, true, array('preview' => $preview)); // force download - security first! diff --git a/enrol/externallib.php b/enrol/externallib.php index 57b6ac13efd..08438e18b77 100644 --- a/enrol/externallib.php +++ b/enrol/externallib.php @@ -207,7 +207,7 @@ class core_enrol_external extends external_api { $exceptionparam = new stdClass(); $exceptionparam->message = $e->getMessage(); $exceptionparam->courseid = $params['courseid']; - throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam)); + throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); } if ($courseid == SITEID) { @@ -543,7 +543,7 @@ class moodle_enrol_external extends external_api { $exceptionparam = new stdClass(); $exceptionparam->message = $e->getMessage(); $exceptionparam->courseid = $params['courseid']; - throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam)); + throw new moodle_exception('errorcoursecontextnotvalid' , 'webservice', '', $exceptionparam); } if ($courseid == SITEID) { diff --git a/enrol/mnet/enrol.php b/enrol/mnet/enrol.php index 7a0a0af5a63..c09cd7e4601 100644 --- a/enrol/mnet/enrol.php +++ b/enrol/mnet/enrol.php @@ -145,6 +145,7 @@ class enrol_mnet_mnetservice_enrol { // users {@link http://tracker.moodle.org/browse/MDL-21327} $user = mnet_strip_user((object)$userdata, mnet_fields_to_import($client)); $user->mnethostid = $client->id; + $user->auth = 'mnet'; try { $user->id = $DB->insert_record('user', $user); } catch (Exception $e) { diff --git a/files/coursefilesedit_form.php b/files/coursefilesedit_form.php index e5498dcec18..fadd387413d 100644 --- a/files/coursefilesedit_form.php +++ b/files/coursefilesedit_form.php @@ -21,7 +21,7 @@ class coursefiles_edit_form extends moodleform { function definition() { $mform =& $this->_form; $contextid = $this->_customdata['contextid']; - $options = array('subdirs'=>1, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL); + $options = array('subdirs'=>1, 'maxfiles'=>-1, 'accepted_types'=>'*'); $mform->addElement('filemanager', 'files_filemanager', '', null, $options); $mform->addElement('hidden', 'contextid', $this->_customdata['contextid']); $this->set_data($this->_customdata['data']); diff --git a/files/filebrowser_ajax.php b/files/filebrowser_ajax.php index 2d651e95765..a8b638b5c54 100644 --- a/files/filebrowser_ajax.php +++ b/files/filebrowser_ajax.php @@ -70,10 +70,10 @@ switch ($action) { if ($child->is_directory()) { $fileitem['isdir'] = true; $fileitem['url'] = $url->out(false); - $fileitem['icon'] = $OUTPUT->pix_icon('f/folder', get_string('icon')); + $fileitem['icon'] = $OUTPUT->pix_icon(file_folder_icon(), get_string('icon')); } else { $fileitem['url'] = $child->get_url(); - $fileitem['icon'] = $OUTPUT->pix_icon('f/'.mimeinfo('icon', $child->get_visible_name()), get_string('icon')); + $fileitem['icon'] = $OUTPUT->pix_icon(file_file_icon($child), get_string('icon')); } $tree[] = $fileitem; } diff --git a/files/renderer.php b/files/renderer.php index 15971636267..3728a23443c 100644 --- a/files/renderer.php +++ b/files/renderer.php @@ -56,25 +56,31 @@ class core_files_renderer extends plugin_renderer_base { $html .= $this->output->box_start(); $table = new html_table(); - $table->head = array(get_string('filename', 'backup'), get_string('size'), get_string('modified')); - $table->align = array('left', 'right', 'right'); + $table->head = array(get_string('name'), get_string('lastmodified'), get_string('size', 'repository'), get_string('type', 'repository')); + $table->align = array('left', 'left', 'left', 'left'); $table->width = '100%'; $table->data = array(); foreach ($tree->tree as $file) { - if (!empty($file['isdir'])) { - $table->data[] = array( - html_writer::link($file['url'], $this->output->pix_icon('f/folder', 'icon') . ' ' . $file['filename']), - '', - $file['filedate'], - ); - } else { - $table->data[] = array( - html_writer::link($file['url'], $this->output->pix_icon('f/'.mimeinfo('icon', $file['filename']), get_string('icon')) . ' ' . $file['filename']), - $file['filesize'], - $file['filedate'], - ); + $filedate = $filesize = $filetype = ''; + if ($file['filedate']) { + $filedate = userdate($file['filedate'], get_string('strftimedatetimeshort', 'langconfig')); } + if (empty($file['isdir'])) { + if ($file['filesize']) { + $filesize = display_size($file['filesize']); + } + $fileicon = file_file_icon($file, 24); + $filetype = get_mimetype_description($file); + } else { + $fileicon = file_folder_icon(24); + } + $table->data[] = array( + html_writer::link($file['url'], $this->output->pix_icon($fileicon, get_string('icon')) . ' ' . $file['filename']), + $filedate, + $filesize, + $filetype + ); } $html .= html_writer::table($table); @@ -82,8 +88,818 @@ class core_files_renderer extends plugin_renderer_base { $html .= $this->output->box_end(); return $html; } -} + /** + * Prints the file manager and initializes all necessary libraries + * + *
+ * $fm = new form_filemanager($options); + * $output = get_renderer('core', 'files'); + * echo $output->render($fm); + *+ * + * @param form_filemanager $fm File manager to render + * @return string HTML fragment + */ + public function render_form_filemanager($fm) { + static $filemanagertemplateloaded; + $html = $this->fm_print_generallayout($fm); + $module = array( + 'name'=>'form_filemanager', + 'fullpath'=>'/lib/form/filemanager.js', + 'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'), + 'strings' => array( + array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'), + array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'), + array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'), + array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'), + array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'), + array('confirmrenamefile', 'repository') + ) + ); + if (empty($filemanagertemplateloaded)) { + $filemanagertemplateloaded = true; + $this->page->requires->js_init_call('M.form_filemanager.set_templates', + array($this->filemanager_js_templates()), true, $module); + } + $this->page->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module); + + // non javascript file manager + $html .= ''; + + + return $html; + } + + /** + * Returns html for displaying one file manager + * + * The main element in HTML must have id="filemanager-{$client_id}" and + * class="filemanager fm-loading"; + * After all necessary code on the page (both html and javascript) is loaded, + * the class fm-loading will be removed and added class fm-loaded; + * The main element (class=filemanager) will be assigned the following classes: + * 'fm-maxfiles' - when filemanager has maximum allowed number of files; + * 'fm-nofiles' - when filemanager has no files at all (although there might be folders); + * 'fm-noitems' - when current view (folder) has no items - neither files nor folders; + * 'fm-updating' - when current view is being updated (usually means that loading icon is to be displayed); + * 'fm-nomkdir' - when 'Make folder' action is unavailable (empty($fm->options->subdirs) == true) + * + * Element with class 'filemanager-container' will be holding evens for dnd upload (dragover, etc.). + * It will have class: + * 'dndupload-ready' - when a file is being dragged over the browser + * 'dndupload-over' - when file is being dragged over this filepicker (additional to 'dndupload-ready') + * 'dndupload-uploading' - during the upload process (note that after dnd upload process is + * over, the file manager will refresh the files list and therefore will have for a while class + * fm-updating. Both waiting processes should look similar so the images don't jump for user) + * + * If browser supports Drag-and-drop, the body element will have class 'dndsupported', + * otherwise - 'dndnotsupported'; + * + * Element with class 'fp-content' will be populated with files list; + * Element with class 'fp-btn-add' will hold onclick event for adding a file (opening filepicker); + * Element with class 'fp-btn-mkdir' will hold onclick event for adding new folder; + * Element with class 'fp-btn-download' will hold onclick event for download action; + * + * Element with class 'fp-path-folder' is a template for one folder in path toolbar. + * It will hold mouse click event and will be assigned classes first/last/even/odd respectfully. + * Parent element will receive class 'empty' when there are no folders to be displayed; + * The content of subelement with class 'fp-path-folder-name' will be substituted with folder name; + * + * Element with class 'fp-viewbar' will have the class 'enabled' or 'disabled' when view mode + * can be changed or not; + * Inside element with class 'fp-viewbar' there are expected elements with classes + * 'fp-vb-icons', 'fp-vb-tree' and 'fp-vb-details'. They will handle onclick events to switch + * between the view modes, the last clicked element will have the class 'checked'; + * + * @param form_filemanager $fm + * @return string + */ + private function fm_print_generallayout($fm) { + global $OUTPUT; + $options = $fm->options; + $client_id = $options->client_id; + $straddfile = get_string('addfile', 'repository'); + $strmakedir = get_string('makeafolder', 'moodle'); + $strdownload = get_string('downloadfolder', 'repository'); + $strloading = get_string('loading', 'repository'); + $strdroptoupload = get_string('droptoupload', 'moodle'); + $icon_progress = $OUTPUT->pix_icon('i/loading_small', $strloading).''; + $restrictions = $this->fm_print_restrictions($fm); + $strdndenabled = get_string('dndenabled_insentence', 'moodle').$OUTPUT->help_icon('dndenabled'); + $strdndenabledinbox = get_string('dndenabled_inbox', 'moodle'); + $loading = get_string('loading', 'repository'); + + $html = ' +New folder name:
++ '.get_string('create').' + '.get_string('cancel').' +
'.get_string('loading', 'repository').'
+