exit(1);
}
} else {
- cli_error(get_string('maturitycorewarning', 'admin'));
+ cli_problem(get_string('maturitycorewarning', 'admin', $maturitylevel));
+ cli_error(get_string('maturityallowunstable', 'admin'));
}
}
}
// 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'));
}
// 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'));
}
}
// 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);
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:
";
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();
$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;
}
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'])) {
}
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;
+}
}
// 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'));
}
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'));
}
}
}
echo 'Moodle requires the iconv PHP extension. Please install or enable the iconv extension.';
die();
}
-if (iconv('UTF-8', 'UTF-8//IGNORE', 'abc') !== 'abc') {
- // known to be broken in mid-2011 MAMP installations
- echo 'Broken iconv PHP extension detected, installation/upgrade can not continue.';
- die();
-}
define('NO_OUTPUT_BUFFERING', true);
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');
$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)) {
}
$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),
array('minmaturity' => $CFG->updateminmaturity, 'notifybuilds' => $CFG->updatenotifybuilds));
$availableupdatesfetch = $updateschecker->get_last_timefetched();
+$buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
+//check if the site is registered on Moodle.org
+$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
+
admin_externalpage_setup('adminnotifications');
if ($fetchupdates) {
$output = $PAGE->get_renderer('core', 'admin');
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
- $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch);
+ $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
+ $registered);
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * 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_LOCALURL);
+
+$redirecturl = new moodle_url($state);
+$params = $redirecturl->params();
+
+if (isset($params['sesskey']) and confirm_sesskey($params['sesskey'])) {
+ $redirecturl->param('oauth2code', $code);
+ redirect($redirecturl);
+} else {
+ print_error('invalidsesskey');
+}
$token = optional_param('token', '', PARAM_TEXT);
$error = optional_param('error', '', PARAM_ALPHANUM);
-admin_externalpage_setup('registrationindex');
+admin_externalpage_setup('registrationhubs');
if (!empty($error) and $error == 'urlalreadyexist') {
throw new moodle_exception('urlalreadyregistered', 'hub',
$geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
$contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
$emailalert = get_config('hub', 'site_emailalert_' . $cleanhuburl);
+ $emailalert = ($emailalert === 0) ? 0 : 1;
$coursesnumber = get_config('hub', 'site_coursesnumber_' . $cleanhuburl);
$usersnumber = get_config('hub', 'site_usersnumber_' . $cleanhuburl);
$roleassignmentsnumber = get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl);
$mform->setType('description', PARAM_TEXT);
$mform->addHelpButton('description', 'sitedesc', 'hub');
- $mform->addElement('static', 'urlstring', get_string('siteurl', 'hub'), $CFG->wwwroot);
- $mform->addHelpButton('urlstring', 'siteurl', 'hub');
-
$languages = get_string_manager()->get_list_of_languages();
collatorlib::asort($languages);
$mform->addElement('select', 'language', get_string('sitelang', 'hub'),
$mform->addHelpButton('language', 'sitelang', 'hub');
$mform->setDefault('language', $language);
- $mform->addElement('static', 'versionstring', get_string('siteversion', 'hub'), $CFG->version);
- $mform->addElement('hidden', 'moodleversion', $CFG->version);
- $mform->setType('moodleversion', PARAM_INT);
- $mform->addHelpButton('versionstring', 'siteversion', 'hub');
-
- $mform->addElement('static', 'releasestring', get_string('siterelease', 'hub'), $CFG->release);
- $mform->addElement('hidden', 'moodlerelease', $CFG->release);
- $mform->setType('moodlerelease', PARAM_TEXT);
- $mform->addHelpButton('releasestring', 'siterelease', 'hub');
-
$mform->addElement('textarea', 'address', get_string('postaladdress', 'hub'),
array('rows' => 4, 'cols' => 41));
$mform->setType('address', PARAM_TEXT);
//TODO site logo
$mform->addElement('hidden', 'imageurl', ''); //TODO: temporary
$mform->setType('imageurl', PARAM_URL);
+
+ $mform->addElement('static', 'urlstring', get_string('siteurl', 'hub'), $CFG->wwwroot);
+ $mform->addHelpButton('urlstring', 'siteurl', 'hub');
+
+ $mform->addElement('static', 'versionstring', get_string('siteversion', 'hub'), $CFG->version);
+ $mform->addElement('hidden', 'moodleversion', $CFG->version);
+ $mform->setType('moodleversion', PARAM_INT);
+ $mform->addHelpButton('versionstring', 'siteversion', 'hub');
+
+ $mform->addElement('static', 'releasestring', get_string('siterelease', 'hub'), $CFG->release);
+ $mform->addElement('hidden', 'moodlerelease', $CFG->release);
+ $mform->setType('moodlerelease', PARAM_TEXT);
+ $mform->addHelpButton('releasestring', 'siterelease', 'hub');
+
/// Display statistic that are going to be retrieve by the hub
$coursecount = $DB->count_records('course') - 1;
$usercount = $DB->count_records('user', array('deleted' => 0));
+++ /dev/null
-<?php
-// This file is part of Moodle - http://moodle.org/
-//
-// Moodle is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// Moodle is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
-
-/*
- * @package moodle
- * @subpackage registration
- * @author Jerome Mouneyrac <jerome@mouneyrac.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL
- * @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
- *
- * Thsi page displays a hub selector or a hub URL + password. Then it will redirect to
- * the site registration form (with the selected hub as parameter)
-*/
-
-require('../../config.php');
-
-require_once($CFG->libdir.'/adminlib.php');
-require_once($CFG->dirroot.'/' . $CFG->admin . '/registration/forms.php');
-
-admin_externalpage_setup('registrationselector');
-
-$hubselectorform = new hub_selector_form();
-$fromform = $hubselectorform->get_data();
-
-//// Redirect to the registration form if an URL has been choosen ////
-
-$selectedhuburl = optional_param('publichub', false, PARAM_URL);
-$unlistedhuburl = optional_param('unlistedurl', false, PARAM_TEXT);
-$password = optional_param('password', '', PARAM_RAW);
-
-if (!empty($unlistedhuburl)) {
- if (clean_param($unlistedhuburl, PARAM_URL) !== '') {
- $huburl = $unlistedhuburl;
- }
-} else if (!empty($selectedhuburl)) {
- $huburl = $selectedhuburl;
-}
-
-
-//redirect
-if (!empty($huburl) and confirm_sesskey()) {
- $hubname = optional_param(clean_param($huburl, PARAM_ALPHANUMEXT), '', PARAM_TEXT);
- $params = array('sesskey' => sesskey(), 'huburl' => $huburl,
- 'password' => $password, 'hubname' => $hubname);
- redirect(new moodle_url($CFG->wwwroot."/" . $CFG->admin . "/registration/register.php",
- $params));
-}
-
-
-//// OUTPUT ////
-
-echo $OUTPUT->header();
-echo $OUTPUT->heading(get_string('registeron', 'hub'), 3, 'main');
-$hubselectorform->display();
-echo $OUTPUT->footer();
\ No newline at end of file
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
*
- * On this page the administrator select if he wants to register on Moodle.org or
- * a specific hub
+ * On this page the administrator selects which hub he wants to register,
+ * except for MOOCH. Admins can register with MOOCH with the top admin menu "Registration" link.
+ * On this page the administrator can also unregister from any hubs, including MOOCH.
*/
require('../../config.php');
require_once($CFG->dirroot . '/course/publish/lib.php');
require_once($CFG->dirroot . "/webservice/xmlrpc/lib.php");
-admin_externalpage_setup('registrationindex');
+admin_externalpage_setup('registrationhubs');
$renderer = $PAGE->get_renderer('core', 'register');
}
}
-echo $OUTPUT->header();
-
-//do not check sesskey if confirm = false because this script is linked into email message
-if (!empty($errormessage)) {
- echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
-}
if (empty($cancel) and $unregistration and !$confirm) {
+
+ echo $OUTPUT->header();
+
+ //do not check sesskey if confirm = false because this script is linked into email message
+ if (!empty($errormessage)) {
+ echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
+ }
+
$hub = $registrationmanager->get_registeredhub($huburl);
echo $OUTPUT->heading(get_string('unregisterfrom', 'hub', $hub->hubname), 3, 'main');
if ($cleanregdata) {
$siteunregistrationform = new site_unregistration_form('',
array('huburl' => $huburl, 'hubname' => $hub->hubname));
}
+
$siteunregistrationform->display();
} else {
$registeredonmoodleorg = false;
$registeredonmoodleorg = true;
}
- echo $OUTPUT->heading(get_string('registeron', 'hub'), 3, 'main');
- echo $renderer->registrationselector($registeredonmoodleorg);
+ // load the hub selector form
+ $hubselectorform = new hub_selector_form();
+ $fromform = $hubselectorform->get_data();
+ $selectedhuburl = optional_param('publichub', false, PARAM_URL);
+ $unlistedhuburl = optional_param('unlistedurl', false, PARAM_TEXT);
+ $password = optional_param('password', '', PARAM_RAW);
+
+ if (!empty($unlistedhuburl)) {
+ if (clean_param($unlistedhuburl, PARAM_URL) !== '') {
+ $huburl = $unlistedhuburl;
+ }
+ } else if (!empty($selectedhuburl)) {
+ $huburl = $selectedhuburl;
+ }
+
+ // a hub has been selected, redirect to the hub registration page
+ if (empty($cancel) and !empty($huburl) and confirm_sesskey()) {
+ $hubname = optional_param(clean_param($huburl, PARAM_ALPHANUMEXT), '', PARAM_TEXT);
+ $params = array('sesskey' => sesskey(), 'huburl' => $huburl,
+ 'password' => $password, 'hubname' => $hubname);
+ redirect(new moodle_url($CFG->wwwroot . "/" . $CFG->admin . "/registration/register.php",
+ $params));
+ }
+
+ echo $OUTPUT->header();
+
+ //check if the site is registered on Moodle.org and display a message about registering on MOOCH
+ $registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
+ if (empty($registered)) {
+ $warningmsg = get_string('registermoochtips', 'hub');
+ $warningmsg .= $renderer->single_button(new moodle_url('register.php', array('huburl' => HUB_MOODLEORGHUBURL
+ , 'hubname' => 'Moodle.org')), get_string('register', 'admin'));
+ echo $renderer->box($warningmsg, 'buttons mdl-align generalbox adminwarning');
+ }
+
+ //do not check sesskey if confirm = false because this script is linked into email message
+ if (!empty($errormessage)) {
+ echo $OUTPUT->notification(get_string('unregistrationerror', 'hub', $errormessage));
+ }
+
+ echo $OUTPUT->heading(get_string('registerwith', 'hub'));
+
+ $hubselectorform->display();
if (extension_loaded('xmlrpc')) {
$hubs = $registrationmanager->get_registered_on_hubs();
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL
* @copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
*
- * This page displays the site registration form.
+ * This page displays the site registration form for Moodle.org/MOOCH or for a different hub.
* It handles redirection to the hub to continue the registration workflow process.
* It also handles update operation by web service.
*/
require_once($CFG->dirroot . '/webservice/lib.php');
require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/lib.php');
-admin_externalpage_setup('registrationindex');
-
$huburl = required_param('huburl', PARAM_URL);
$huburl = rtrim($huburl, "/");
+
+if ($huburl == HUB_MOODLEORGHUBURL) { // register to Moodle.org
+ admin_externalpage_setup('registrationmoodleorg');
+} else { //register to a hub
+ admin_externalpage_setup('registrationhub');
+}
+
$password = optional_param('password', '', PARAM_TEXT);
$hubname = optional_param('hubname', '', PARAM_TEXT);
-if (!confirm_sesskey()) {
- throw new moodle_exception('missingparameter');
-}
$registrationmanager = new registration_manager();
echo $error;
}
+//some Moodle.org resitration explanation
+if ($huburl == HUB_MOODLEORGHUBURL) {
+ echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
+ $renderer = $PAGE->get_renderer('core', 'register');
+ echo $renderer->moodleorg_registration_message();
+}
+
$siteregistrationform->display();
echo $OUTPUT->footer();
*/
class core_register_renderer extends plugin_renderer_base {
+ /**
+ * Display Moodle.org registration message about benefit to register on Moodle.org
+ *
+ * @return string
+ */
+ public function moodleorg_registration_message() {
+ $moodleorgurl = html_writer::link('http://moodle.org', 'Moodle.org');
+ $moodleorgstatsurl = html_writer::link('http://moodle.org/stats', get_string('statsmoodleorg', 'admin'));
+ $moochurl = html_writer::link(HUB_MOODLEORGHUBURL, 'MOOCH');
+ $moodleorgregmsg = get_string('registermoodleorg', 'admin', $moodleorgurl);
+ $items = array(get_string('registermoodleorgli1', 'admin'),
+ get_string('registermoodleorgli2', 'admin', $moodleorgstatsurl),
+ get_string('registermoodleorgli3', 'admin', $moochurl));
+ $moodleorgregmsg .= html_writer::alist($items);
+ return $moodleorgregmsg;
+ }
+
/**
* Display a box message confirming a site registration (add or update)
* @param string $confirmationmessage
return $this->output->box($message);
}
- /**
- * Display the page to register on Moodle.org or on a specific hub
- */
- public function registrationselector($updatemoodleorg = false) {
- global $CFG;
- $table = new html_table();
- $table->head = array(get_string('moodleorg', 'hub'), get_string('specifichub', 'hub'));
- $table->size = array('50%', '50%');
- //$table->attributes['class'] = 'registerindextable';
- //Moodle.org information cell
- $moodleorgcell = get_string('moodleorgregistrationdetail', 'hub');
- $moodleorgcell .= html_writer::empty_tag('br') . html_writer::empty_tag('br');
- $moodleorgcell = html_writer::tag('div', $moodleorgcell, array('class' => 'justifytext'));
-
- //Specific hub information cell
- $specifichubcell = get_string('specifichubregistrationdetail', 'hub');
- $specifichubcell .= html_writer::empty_tag('br') . html_writer::empty_tag('br');
- $specifichubcell = html_writer::tag('div', $specifichubcell, array('class' => 'justifytext'));
-
- //add information cells
- $cells = array($moodleorgcell, $specifichubcell);
- $row = new html_table_row($cells);
- $table->data[] = $row;
-
- //Moodle.org button cell
- $registeronmoodleorgurl = new moodle_url("/" . $CFG->admin . "/registration/register.php",
- array('sesskey' => sesskey(), 'huburl' => HUB_MOODLEORGHUBURL
- , 'hubname' => 'Moodle.org'));
- $registeronmoodleorgbutton = new single_button($registeronmoodleorgurl,
- $updatemoodleorg ? get_string('updatesite', 'hub', 'Moodle.org') : get_string('registeronmoodleorg', 'hub'));
- $registeronmoodleorgbutton->class = 'centeredbutton';
- $registeronmoodleorgbuttonhtml = $this->output->render($registeronmoodleorgbutton);
- $moodleorgcell = $registeronmoodleorgbuttonhtml;
-
- //Specific hub button cell
- $registeronspecifichuburl = new moodle_url("/" . $CFG->admin . "/registration/hubselector.php",
- array('sesskey' => sesskey()));
- $registeronspecifichubbutton = new single_button($registeronspecifichuburl,
- get_string('registeronspecifichub', 'hub'));
- $registeronspecifichubbutton->class = 'centeredbutton';
- $registeronspecifichubbuttonhtml = $this->output->render($registeronspecifichubbutton);
- $specifichubcell = $registeronspecifichubbuttonhtml;
-
- //add button cells
- $cells = array($moodleorgcell, $specifichubcell);
- $row = new html_table_row($cells);
- $table->data[] = $row;
-
- return html_writer::table($table);
- }
-
/**
* Display the listing of registered on hub
*/
$hubname = optional_param('hubname', '', PARAM_TEXT);
$token = optional_param('token', '', PARAM_TEXT);
-admin_externalpage_setup('registrationindex');
+admin_externalpage_setup('registrationhubs');
//check that we are waiting a confirmation from this hub, and check that the token is correct
$registrationmanager = new registration_manager();
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.
$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;
* @param bool $cronoverdue warn cron not running
* @param bool $dbproblems warn db has problems
* @param bool $maintenancemode warn in maintenance mode
+ * @param bool $buggyiconvnomb warn iconv problems
* @param array|null $availableupdates array of available_update_info objects or null
* @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
*
* @return string HTML to output.
*/
public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
- $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch) {
+ $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
+ $buggyiconvnomb, $registered) {
global $CFG;
$output = '';
$output .= empty($CFG->disableupdatenotifications) ? $this->available_updates($availableupdates, $availableupdatesfetch) : '';
$output .= $this->insecure_dataroot_warning($insecuredataroot);
$output .= $this->display_errors_warning($errorsdisplayed);
+ $output .= $this->buggy_iconv_warning($buggyiconvnomb);
$output .= $this->cron_overdue_warning($cronoverdue);
$output .= $this->db_problems($dbproblems);
$output .= $this->maintenance_mode_warning($maintenancemode);
+ $output .= $this->registration_warning($registered);
//////////////////////////////////////////////////////////////////////////////////////////////////
//// IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
return $this->warning(get_string('displayerrorswarning', 'admin'));
}
+ /**
+ * Render an appropriate message if iconv is buggy and mbstring missing.
+ * @param bool $buggyiconvnomb
+ * @return string HTML to output.
+ */
+ protected function buggy_iconv_warning($buggyiconvnomb) {
+ if (!$buggyiconvnomb) {
+ return '';
+ }
+
+ return $this->warning(get_string('warningiconvbuggy', 'admin'));
+ }
+
/**
* Render an appropriate message if cron has not been run recently.
* @param bool $cronoverdue
return $updateinfo;
}
+ /**
+ * Display a warning about not being registered on Moodle.org if necesary.
+ *
+ * @param boolean $registered true if the site is registered on Moodle.org
+ * @return string HTML to output.
+ */
+ protected function registration_warning($registered) {
+
+ if (!$registered) {
+
+ $registerbutton = $this->single_button(new moodle_url('registration/register.php',
+ array('huburl' => HUB_MOODLEORGHUBURL, 'hubname' => 'Moodle.org')),
+ get_string('register', 'admin'));
+
+ return $this->warning( get_string('registrationwarning', 'admin')
+ . ' ' . $this->help_icon('registration', 'admin') . $registerbutton );
+ }
+
+ return '';
+ }
+
/**
* Helper method to render the information about the available Moodle update
*
* 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();
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';
$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;
$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'])) {
$ADMIN->add('server', $temp);
-$ADMIN->add('server', new admin_externalpage('adminregistration', new lang_string('registration','admin'), "$CFG->wwwroot/$CFG->admin/registration/index.php"));
+$ADMIN->add('server', new admin_externalpage('adminregistration', new lang_string('hubs', 'admin'),
+ "$CFG->wwwroot/$CFG->admin/registration/index.php"));
// "update notifications" settingpage
if (empty($CFG->disableupdatenotifications)) {
$ADMIN->add('root', new admin_externalpage('adminnotifications', new lang_string('notifications'), "$CFG->wwwroot/$CFG->admin/index.php"));
-$ADMIN->add('root', new admin_externalpage('registrationindex', new lang_string('registration','admin'),
- "$CFG->wwwroot/$CFG->admin/registration/index.php"));
-$ADMIN->add('root', new admin_externalpage('registration', new lang_string('registeron','hub'),
+$ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_string('registration', 'admin'),
+ "$CFG->wwwroot/$CFG->admin/registration/register.php?huburl=" . HUB_MOODLEORGHUBURL . "&hubname=Moodle.org"));
+$ADMIN->add('root', new admin_externalpage('registrationhub', new lang_string('registerwith', 'hub'),
"$CFG->wwwroot/$CFG->admin/registration/register.php", 'moodle/site:config', true));
-$ADMIN->add('root', new admin_externalpage('registrationselector', new lang_string('registeron','hub'),
- "$CFG->wwwroot/$CFG->admin/registration/hubselector.php", 'moodle/site:config', true));
+$ADMIN->add('root', new admin_externalpage('registrationhubs', new lang_string('hubs', 'admin'),
+ "$CFG->wwwroot/$CFG->admin/registration/index.php", 'moodle/site:config', true));
$ADMIN->add('root', new admin_externalpage('siteregistrationconfirmed',
new lang_string('registrationconfirmed', 'hub'),
$CFG->wwwroot."/".$CFG->admin."/registration/confirmregistration.php", 'moodle/site:config', true));
$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();
/// 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
$file->set_source_sql("SELECT f.*, r.repositoryid, r.reference
FROM {files} f
- JOIN {files_reference} r
+ LEFT JOIN {files_reference} r
ON r.id = f.referencefileid
JOIN {backup_ids_temp} bi
ON f.id = bi.itemid
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
*
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
// Add local encodes
// TODO: Any interest? 1.9 never had that.
+ $LINKS_ENCODERS_CACHE = $encoders;
return $encoders;
}
}
$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}');
global $CFG, $DB;
$data = (object)$data;
$oldid = $data->id; // We'll need this later
+ $oldsection = $data->number;
$restorefiles = false;
$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);
public function process_availability($data) {
global $DB;
$data = (object)$data;
+
$data->coursesectionid = $this->task->get_sectionid();
+
// NOTE: Other values in $data need updating, but these (cm,
- // grade items) have not yet been restored.
- $DB->insert_record('course_sections_availability', $data);
+ // grade items) have not yet been restored, so are done later.
+
+ $newid = $DB->insert_record('course_sections_availability', $data);
+
+ // We do not need to map between old and new id but storing a mapping
+ // means it gets added to the backup_ids table to record which ones
+ // need updating. The mapping is stored with $newid => $newid for
+ // convenience.
+ $this->set_mapping('course_sections_availability', $newid, $newid);
}
protected function after_execute() {
$sectionid = $this->get_task()->get_sectionid();
- // Get data object for current section availability (if any)
- // TODO: This can be processing already existing records, we need to be able to know which ones
- // are the just restored ones, perhaps creating 'course_sections_availability' mappings for them.
- // TODO: Also, this must avoid duplicates, so if one course module or one grade item already is being
- // used for some availability rule... we need to handle that carefully.
+ // Get data object for current section availability (if any).
$data = $DB->get_record('course_sections_availability',
array('coursesectionid' => $sectionid), 'id, sourcecmid, gradeitemid', IGNORE_MISSING);
- // Update mappings
+ // If it exists, update mappings.
if ($data) {
+ // Only update mappings for entries which are created by this restore.
+ // Otherwise, when you restore to an existing course, it will mess up
+ // existing section availability entries.
+ if (!$this->get_mappingid('course_sections_availability', $data->id, false)) {
+ return;
+ }
+
+ // Update source cmid / grade id to new value.
$data->sourcecmid = $this->get_mappingid('course_module', $data->sourcecmid);
if (!$data->sourcecmid) {
$data->sourcecmid = null;
$data = (object)$data;
$oldid = $data->id;
-
+ $oldsection = $data->sectionnumber;
$this->task->set_old_moduleversion($data->version);
$data->course = $this->task->get_courseid();
'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
$sql = "SELECT count(r.repositoryid)
FROM {files} f
- JOIN {files_reference} r
+ LEFT JOIN {files_reference} r
ON r.id = f.referencefileid
JOIN {backup_ids_temp} bi
ON f.id = bi.itemid
* 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
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)
$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) {
$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;
}
*/
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);
$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;
}
}
- $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;
}
/**
// 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);
+ }
}
}
}
/**
* 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;
// 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) {
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
$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) {
}
// 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.
}
}
}
+ $form->add_settings($add_settings);
+ foreach ($dependencies as $depsetting) {
+ $form->add_dependencies($depsetting);
+ }
$this->stageform = $form;
}
return $this->stageform;
* @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;
}
/**
$this->definition_after_data();
}
}
-}
\ No newline at end of file
+}
$days_title = calendar_get_days();
$summary = get_string('calendarheading', 'calendar', userdate(make_timestamp($y, $m), get_string('strftimemonthyear')));
- $summary = get_string('tabledata', 'access', $summary);
$content .= '<table class="minicalendar calendartable" summary="'.$summary.'">'; // Begin table
$content .= '<tr class="weekdays">'; // Header row: day names
$DB->update_record('course', $course);
}
+$url = course_get_url($course);
+$url->set_anchor('changenumsections');
// Redirect to where we were..
-redirect(course_get_url($course));
+redirect($url);
*/
abstract protected function page_title();
+ /**
+ * Generate the section title
+ *
+ * @param stdClass $section The course_section entry from DB
+ * @param stdClass $course The course entry from DB
+ * @return string HTML to output.
+ */
+ public function section_title($section, $course) {
+ $title = get_section_name($course, $section);
+ if ($section->section != 0 && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
+ $title = html_writer::link(course_get_url($course, $section->section), $title);
+ }
+ return $title;
+ }
+
/**
* Generate the content to displayed on the right 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
+ * @param bool $onsectionpage true if being printed on a single-section page
* @return string HTML to output.
*/
protected function section_header($section, $course, $onsectionpage) {
$o = '';
$currenttext = '';
$sectionstyle = '';
- $linktitle = false;
if ($section->section != 0) {
// Only in the non-general sections.
} else if ($this->is_section_current($section, $course)) {
$sectionstyle = ' current';
}
- $linktitle = ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE);
}
$o.= html_writer::start_tag('li', array('id' => 'section-'.$section->section,
$o.= html_writer::start_tag('div', array('class' => 'content'));
if (!$onsectionpage) {
- $title = get_section_name($course, $section);
- if ($linktitle) {
- $title = html_writer::link(course_get_url($course, $section->section), $title);
- }
- $o.= $this->output->heading($title, 3, 'sectionname');
+ $o.= $this->output->heading($this->section_title($section, $course), 3, 'sectionname');
}
$o.= html_writer::start_tag('div', array('class' => 'summary'));
$completioninfo = new completion_info($course);
echo $completioninfo->display_help_icon();
- print_section($course, $thissection, $mods, $modnamesused, true);
+ print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, true);
if ($PAGE->user_is_editing()) {
print_section_add_menus($course, $displaysection, $modnames);
}
echo $this->end_section_list();
- echo html_writer::start_tag('div', array('class' => 'mdl-right'));
+ echo html_writer::start_tag('div', array('id' => 'changenumsections', 'class' => 'mdl-right'));
// Increase number of sections.
$straddsection = get_string('increasesections', 'moodle');
-// Javascript functions for course format
+// Javascript functions for Topics course format
M.course = M.course || {};
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]);
+ }
+ }
+}
$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');
+}
-// Javascript functions for course format
+// Javascript functions for Weeks course format
M.course = M.course || {};
M.course.format.swap_sections = function(Y, node1, node2) {
var CSS = {
COURSECONTENT : 'course-content',
- LEFT : 'left',
SECTIONADDMENUS : 'section_add_menus',
- WEEKDATES: 'sectionname'
};
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]);
+ }
+ }
}
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');
+}
// see the activity itself, or for staff)
if (!$mod->uservisible) {
echo '<div class="availabilityinfo">'.$mod->availableinfo.'</div>';
- } else if ($canviewhidden && !empty($CFG->enableavailability)) {
+ } else if ($canviewhidden && !empty($CFG->enableavailability) && $mod->visible) {
$ci = new condition_info($mod);
$fullinfo = $ci->get_full_information();
if($fullinfo) {
}
$n++;
}
+ // After moving section, rebuild course cache.
+ rebuild_course_cache($course->id, true);
return true;
}
echo $OUTPUT->spacer(array('height'=>30, 'br'=>true)); // should be done with CSS instead
}
echo $OUTPUT->box_start();
- echo "<h2>$activity->name</h2>";
+ if (!empty($activity->name)) {
+ echo html_writer::tag('h2', $activity->name);
+ }
$inbox = true;
} else if ($activity->type == 'activity') {
$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 = "<img src=\"" . $OUTPUT->pix_url('icon', $cm->modname) . "\" class=\"icon\" alt=\"$modfullname\" />";
- echo "<h3>$image $modfullname".
- " <a href=\"$CFG->wwwroot/mod/$cm->modname/view.php?id=$cm->id\" $linkformat>$name</a></h3>";
+ $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 {
} else {
- echo '<h3><center>' . get_string('norecentactivity') . '</center></h3>';
+ echo html_writer::tag('h3', get_string('norecentactivity'), array('class' => 'mdl-align'));
}
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);
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')) {
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
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
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 {
}
loopend = loopend - 1;
} while (swapped);
+
+ // Finally, hide the lightbox
+ window.setTimeout(function(e) {
+ lightbox.hide();
+ }, 250);
},
failure: function(tid, response) {
this.ajax_failure(response);
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
$strmakedir = get_string('makeafolder', 'moodle');
$strdownload = get_string('downloadfolder', 'repository');
$strloading = get_string('loading', 'repository');
- $strnofilesattached = get_string('nofilesattached', 'repository');
$strdroptoupload = get_string('droptoupload', 'moodle');
$icon_progress = $OUTPUT->pix_icon('i/loading_small', $strloading).'';
$restrictions = $this->fm_print_restrictions($fm);
<div class="filemanager-container" >
<div class="fm-content-wrapper">
<div class="fp-content"></div>
- <div class="fm-empty-container <!--mdl-align-->">'.$strnofilesattached.'
+ <div class="fm-empty-container <!--mdl-align-->">
<span class="dndupload-message">'.$strdndenabledinbox.'<br/><span class="dndupload-arrow"></span></span>
</div>
<div class="dndupload-target">'.$strdroptoupload.'<br/><span class="dndupload-arrow"></span></div>
*/
private function fm_js_template_mkdir() {
$rv = '
-<div class="fp-mkdir-dlg">
- <p>New folder name:</p>
- <input type="text"><br/>
- <a class="{!}fp-dlg-butcreate fp-panel-button" href="#">'.get_string('create').'</a>
+<div class="filemanager fp-mkdir-dlg">
+ <div class="fp-mkdir-dlg-text">'.get_string('newfoldername','repository').'<br/><input type="text" /></div>
+ <a class="{!}fp-dlg-butcreate fp-panel-button" href="#">'.get_string('makeafolder').'</a>
<a class="{!}fp-dlg-butcancel fp-panel-button" href="#">'.get_string('cancel').'</a>
</div>';
return preg_replace('/\{\!\}/', '', $rv);
<tr class="{!}fp-saveas"><td class="mdl-right"><label>'.get_string('name', 'moodle').'</label>:</td>
<td class="mdl-left"><input type="text"/></td></tr>
<tr class="{!}fp-author"><td class="mdl-right"><label>'.get_string('author', 'repository').'</label>:</td>
- <td class="mdl-left"><input type="text" /></td></tr>
+ <td class="mdl-left"><input type="text"/></td></tr>
<tr class="{!}fp-license"><td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
<td class="mdl-left"><select></select></td></tr>
<tr class="{!}fp-path"><td class="mdl-right"><label>'.get_string('path', 'moodle').'</label>:</td>
<td class="mdl-left"><select></select></td></tr>
<tr class="{!}fp-original"><td class="mdl-right"><label>'.get_string('original', 'repository').'</label>:</td>
- <td class="mdl-left"><span class="fp-originloading">'.$icon_progress.' '.$strloading.'</span><span class="fp-value"/></td></tr>
+ <td class="mdl-left"><span class="fp-originloading">'.$icon_progress.' '.$strloading.'</span><span class="fp-value"></span></td></tr>
<tr class="{!}fp-reflist"><td class="mdl-right"><label>'.get_string('referenceslist', 'repository').'</label>:</td>
- <td class="mdl-left"><p class="{!}fp-refcount"/><span class="fp-reflistloading">'.$icon_progress.' '.$strloading.'</span><ul class="fp-value"/></td></tr>
+ <td class="mdl-left"><p class="{!}fp-refcount"></p><span class="fp-reflistloading">'.$icon_progress.' '.$strloading.'</span><ul class="fp-value"></ul></td></tr>
</table>
</form>
<p class="{!}fp-thumbnail"></p>
</p>
</form>
<div class="fp-fileinfo">
- <div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"/></div>
- <div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"/></div>
- <div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"/></div>
- <div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"/></div>
+ <div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"></span></div>
+ <div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"></span></div>
+ <div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"></span></div>
+ <div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"></span></div>
</div>
</div>';
return preg_replace('/\{\!\}/', '', $rv);
<div class="file-picker fp-generallayout">
<div class="fp-repo-area">
<ul class="fp-list">
- <li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" width="16" height="16" /> <span class="{!}fp-repo-name" /span></a></li>
+ <li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" width="16" height="16" /> <span class="{!}fp-repo-name"></span></a></li>
</ul>
</div>
<div class="fp-repo-items">
<div>
<div class="{!}fp-toolbar">
<div class="{!}fp-tb-back"><a href="#">'.get_string('back', 'repository').'</a></div>
- <div class="{!}fp-tb-search fp-search"><form/></div>
+ <div class="{!}fp-tb-search"><form></form></div>
<div class="{!}fp-tb-refresh"><a href="#"><img src="'.$this->pix_url('a/refresh').'" /></a></div>
<div class="{!}fp-tb-logout"><img src="'.$this->pix_url('a/logout').'" /><a href="#"></a></div>
<div class="{!}fp-tb-manage"><a href="#"><img src="'.$this->pix_url('a/setting').'" /> '.get_string('manageurl', 'repository').'</a></div>
<a class="{!}fp-vb-details" href="#"></a>
<a class="{!}fp-vb-tree" href="#"></a>
</div>
- <div class="fp-clear-right"></div>
+ <div class="fp-clear-left"></div>
</div>
<div class="fp-pathbar">
<span class="{!}fp-path-folder"><a class="{!}fp-path-folder-name" href="#"></a></span>
</form>
<p class="{!}fp-thumbnail"></p>
<div class="fp-fileinfo">
- <div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"/></div>
- <div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"/></div>
- <div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"/></div>
- <div class="{!}fp-license">'.get_string('license', 'moodle').': <span class="fp-value"/></div>
- <div class="{!}fp-author">'.get_string('author', 'repository').': <span class="fp-value"/></div>
- <div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"/></div>
+ <div class="{!}fp-datemodified">'.get_string('lastmodified', 'moodle').': <span class="fp-value"></span></div>
+ <div class="{!}fp-datecreated">'.get_string('datecreated', 'repository').': <span class="fp-value"></span></div>
+ <div class="{!}fp-size">'.get_string('size', 'repository').': <span class="fp-value"></span></div>
+ <div class="{!}fp-license">'.get_string('license', 'moodle').': <span class="fp-value"></span></div>
+ <div class="{!}fp-author">'.get_string('author', 'repository').': <span class="fp-value"></span></div>
+ <div class="{!}fp-dimensions">'.get_string('dimensions', 'repository').': <span class="fp-value"></span></div>
</div>
</div>';
return preg_replace('/\{\!\}/', '', $rv);
<td class="mdl-left"><input type="text"/></td></tr>
<tr class="{!}fp-setlicense">
<td class="mdl-right"><label>'.get_string('chooselicense', 'repository').'</label>:</td>
- <td class="mdl-left"><select/></td></tr>
+ <td class="mdl-left"><select></select></td></tr>
</table>
</form>
<div><button class="{!}fp-upload-btn">'.get_string('upload', 'repository').'</button></div>
*/
private function fp_js_template_error() {
$rv = '
-<div class="fp-content-error" ><div class="{!}fp-error" /></div>';
+<div class="fp-content-error" ><div class="{!}fp-error"></div></div>';
return preg_replace('/\{\!\}/', '', $rv);
}
<p class="{!}fp-dlg-text"></p>
<a class="{!}fp-dlg-butoverwrite fp-panel-button" href="#">'.get_string('overwrite', 'repository').'</a>
<a class="{!}fp-dlg-butcancel fp-panel-button" href="#">'.get_string('cancel').'</a>
- <a class="{!}fp-dlg-butrename fp-panel-button" href="#"/>
+ <a class="{!}fp-dlg-butrename fp-panel-button" href="#"></a>
</div>';
return preg_replace('/\{\!\}/', '', $rv);
}
<td align="right"><label></label></td>
<td align="left"><select></select></td></tr>
<tr class="{!}fp-login-input">
- <td class="label"><label /></td>
+ <td class="label"><label></label></td>
<td class="input"><input/></td></tr>
<tr class="{!}fp-login-radiogroup">
- <td align="right" width="30%" valign="top"><label /></td>
- <td align="left" valign="top"><p class="{!}fp-login-radio"><input /> <label /></p></td></tr>
+ <td align="right" width="30%" valign="top"><label></label></td>
+ <td align="left" valign="top"><p class="{!}fp-login-radio"><input /> <label></label></p></td></tr>
</table>
<p><button class="{!}fp-login-submit">'.get_string('submit', 'repository').'</button></p>
</form>
* Default contents is one text input field with name="s"
*/
public function repository_default_searchform() {
- $str = '<input class="search-entry" name="s" value="Search" />';
+ $str = '<div class="fp-def-search"><input name="s" value='.get_string('search', 'repository').' /></div>';
return $str;
}
}
// form processing
} else if ($data = $mform->get_data(false)) {
- if (is_array($data->feedback)) {
+ if (isset($data->feedback) && is_array($data->feedback)) {
$data->feedbackformat = $data->feedback['format'];
$data->feedback = $data->feedback['text'];
}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class graded_users_iterator {
- public $course;
- public $grade_items;
- public $groupid;
- public $users_rs;
- public $grades_rs;
- public $gradestack;
- public $sortfield1;
- public $sortorder1;
- public $sortfield2;
- public $sortorder2;
+
+ /**
+ * The couse whose users we are interested in
+ */
+ protected $course;
+
+ /**
+ * An array of grade items or null if only user data was requested
+ */
+ protected $grade_items;
+
+ /**
+ * The group ID we are interested in. 0 means all groups.
+ */
+ protected $groupid;
+
+ /**
+ * A recordset of graded users
+ */
+ protected $users_rs;
+
+ /**
+ * A recordset of user grades (grade_grade instances)
+ */
+ protected $grades_rs;
+
+ /**
+ * Array used when moving to next user while iterating through the grades recordset
+ */
+ protected $gradestack;
+
+ /**
+ * The first field of the users table by which the array of users will be sorted
+ */
+ protected $sortfield1;
+
+ /**
+ * Should sortfield1 be ASC or DESC
+ */
+ protected $sortorder1;
+
+ /**
+ * The second field of the users table by which the array of users will be sorted
+ */
+ protected $sortfield2;
+
+ /**
+ * Should sortfield2 be ASC or DESC
+ */
+ protected $sortorder2;
/**
* Should users whose enrolment has been suspended be ignored?
* @param string $sortfield2 The second field of the users table by which the array of users will be sorted
* @param string $sortorder2 The order in which the second sorting field will be sorted (ASC or DESC)
*/
- public function graded_users_iterator($course, $grade_items=null, $groupid=0,
+ public function __construct($course, $grade_items=null, $groupid=0,
$sortfield1='lastname', $sortorder1='ASC',
$sortfield2='firstname', $sortorder2='ASC') {
$this->course = $course;
/**
* Initialise the iterator
+ *
* @return boolean success
*/
public function init() {
* Returns information about the next user
* @return mixed array of user info, all grades and feedback or null when no more users found
*/
- function next_user() {
+ public function next_user() {
if (!$this->users_rs) {
return false; // no users present
}
}
/**
- * Close the iterator, do not forget to call this function.
- * @return void
+ * Close the iterator, do not forget to call this function
*/
- function close() {
+ public function close() {
if ($this->users_rs) {
$this->users_rs->close();
$this->users_rs = null;
/**
- * _push
+ * Add a grade_grade instance to the grade stack
*
* @param grade_grade $grade Grade object
*
* @return void
*/
- function _push($grade) {
+ private function _push($grade) {
array_push($this->gradestack, $grade);
}
/**
- * _pop
+ * Remove a grade_grade instance from the grade stack
*
- * @return object current grade object
+ * @return grade_grade current grade object
*/
- function _pop() {
+ private function _pop() {
global $DB;
if (empty($this->gradestack)) {
if (empty($this->grades_rs) || !$this->grades_rs->valid()) {
echo 'Moodle requires the iconv PHP extension. Please install or enable the iconv extension.';
die();
}
-if (iconv('UTF-8', 'UTF-8//IGNORE', 'abc') !== 'abc') {
- // known to be broken in mid-2011 MAMP installations
- echo 'Broken iconv PHP extension detected, installation can not continue.';
- die;
-}
if (PHP_INT_SIZE > 4) {
// most probably 64bit PHP - we need a lot more memory
<?php
+
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
/**
- * Add event handlers for the googledocs portfolio.
+ * Automatically generated strings for Moodle 2.3dev installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
*
- * @package portfolio_googledocs
- * @category event
- * @copyright 2009 Penny Leach
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-$handlers = array (
- 'user_deleted' => array (
- 'handlerfile' => '/portfolio/googledocs/lib.php',
- 'handlerfunction' => 'portfolio_googledocs_user_deleted',
- 'schedule' => 'cron',
- 'internal' => 0,
- ),
-);
-
+defined('MOODLE_INTERNAL') || die();
+$string['environmentrequireinstall'] = 'debe estar instalado y activado';
--- /dev/null
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle 2.3dev installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package installer
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['databasehost'] = 'host de la Base de Datos';
+$string['environmentsub2'] = 'Cada versión de Moodle tiene algún requisito mÃnimo de la versión de PHP y un número obligatorio de extensiones de PHP. Una comprobación del entorno completo se realiza antes de cada instalación y actualización. Por favor, póngase en contacto con el administrador del servidor si no sabe cómo instalar la nueva versión o habilitar las extensiones PHP.';
+$string['errorsinenvironment'] = '¡La comprobación del entorno falló!';
+$string['welcomep20'] = 'Si está viendo esta página es porque ha podido ejecutar el paquete <strong>{$a->packname} {$a->packversion}</strong> en su computadora. !Enhorabuena!';
+$string['welcomep30'] = 'Esta versión de <strong>{$a->installername}</strong> incluye las aplicaciones necesarias para que <strong>Moodle</strong> funcione en su computadora principalmente:';
+$string['welcomep60'] = 'Las siguientes páginas le guiarán a través de algunos sencillos pasos para configurar y ajustar <strong>Moodle</strong> en su computadora. Puede utilizar los valores por defecto sugeridos o, de forma opcional, modificarlos para que se ajusten a sus necesidades.';
$string['skipblock'] = 'Skip block';
$string['skipnavigation'] = 'Skip navigation';
$string['skipto'] = 'Skip to {$a}';
-$string['tabledata'] = 'Data table, {$a}';
-$string['tablelayout'] = 'Layout table, {$a}';
$string['tocontent'] = 'Skip to main content';
$string['tonavigation'] = 'Go to navigation';
$string['youarehere'] = 'You are here';
$string['enablegravatar'] = 'Enable Gravatar';
$string['enablegravatar_help'] = 'When enabled Moodle will attempt to fetch a user profile picture from Gravatar if the user has not uploaded an image.';
$string['enablegroupmembersonly'] = 'Enable group members only';
-$string['enablemobilewebservice'] = 'Enable mobile web service';
+$string['enablemobilewebservice'] = 'Enable web services for mobile devices';
$string['enablerecordcache'] = 'Enable record cache';
$string['enablerssfeeds'] = 'Enable RSS feeds';
$string['enablesafebrowserintegration'] = 'Enable Safe Exam Browser integration';
$string['htmlsettings'] = 'HTML settings';
$string['http'] = 'HTTP';
$string['httpsecurity'] = 'HTTP security';
+$string['hubs'] = 'Hubs';
$string['change'] = 'change';
$string['checkboxno'] = 'No';
$string['checkboxyes'] = 'Yes';
$string['maturity100'] = 'Beta';
$string['maturity150'] = 'Release candidate';
$string['maturity200'] = 'Stable version';
+$string['maturityallowunstable'] = 'Hint: You may want to run this script with --allow-unstable option';
$string['maturitycoreinfo'] = 'Your site is currently running unstable "{$a}" development code.';
$string['maturitycorewarning'] = 'The version of Moodle that you are about to install or upgrade to contains
unstable "{$a}" development code that is not suitable for use on most production
$string['pleaseregister'] = 'Please register your site to remove this button';
$string['plugin'] = 'Plugin';
$string['plugins'] = 'Plugins';
+$string['pluginscheck'] = 'Plugin dependencies check';
+$string['pluginscheckfailed'] = 'Dependencies check failed for {$a->pluginslist}';
$string['pluginschecktodo'] = 'You must solve all the plugin requirements before proceeding to install this Moodle version!';
$string['pluginsoverview'] = 'Plugins overview';
$string['profilecategory'] = 'Category';
$string['rcachettl'] = 'Record cache TTL';
$string['recaptchaprivatekey'] = 'ReCAPTCHA private key';
$string['recaptchapublickey'] = 'ReCAPTCHA public key';
+$string['register'] = 'Register your site';
+$string['registermoodleorg'] = 'When you register your site with {$a}';
+$string['registermoodleorgli1'] = 'You are added to a low-volume mailing list for important notifications such as security alerts and new releases of Moodle.';
+$string['registermoodleorgli2'] = 'Statistics about your site will be added to the {$a} of the worldwide Moodle community.';
+$string['registermoodleorgli3'] = 'Your site is also registered with the Moodle.org Open Community Hub ({$a}), allowing users with the publish courses capability (by default only managers) the option of publishing courses to MOOCH.';
+$string['registerwithmoodleorg'] = 'Register with Moodle.org';
$string['registration'] = 'Registration';
+$string['registration_help'] = 'It is recommended to register on Moodle.org to receive security email alerts, to contribute to the Moodle growth and statistics, or to be able to share courses on MOOCH.';
+$string['registrationwarning'] = 'Your site is not yet registered.';
$string['releasenoteslink'] = 'For information about this version of Moodle, please see the online <a target="_blank" href="{$a}">Release Notes</a>';
$string['rememberusername'] = 'Remember username';
$string['rememberusername_desc'] = 'Enable if you want to store permanent cookies with usernames during user login. Permanent cookies may be considered a privacy issue if used without consent.';
$string['stats'] = 'Statistics';
$string['statsfirstrun'] = 'Maximum processing interval';
$string['statsmaxruntime'] = 'Maximum runtime';
+$string['statsmoodleorg'] = 'statistics';
$string['statsruntimedays'] = 'Days to process';
$string['statsruntimestart'] = 'Run at';
$string['statsuserthreshold'] = 'User threshold';
$string['validateerror'] = 'This value was not valid:';
$string['verifychangedemail'] = 'Restrict domains when changing email';
$string['warningcurrentsetting'] = 'Invalid current value: {$a}';
+$string['warningiconvbuggy'] = 'Your version of the iconv library does not support the //IGNORE modifier. You should install the mbstring extension which can be used instead for cleaning strings containing invalid UTF-8 characters.';
$string['webproxy'] = 'Web proxy';
$string['webproxyinfo'] = 'Fill in following options if your Moodle server can not access internet directly. Internet access is required for download of environment data, language packs, RSS feeds, timezones, etc.<br /><em>PHP cURL extension is highly recommended.</em>';
$string['xmlrpcrecommended'] = 'The xmlrpc extension is needed for hub communication, and useful for web services and Moodle networking';
$string['logourl'] = 'Logo URL';
$string['modulenumberaverage'] = 'Average number of course modules ({$a})';
$string['moodleorg'] = 'Moodle.org';
-$string['moodleorgregistrationdetail'] = 'The main community hub is called MOOCH, at hub.moodle.org. By registering your site with MOOCH you will contribute to the statistics of the worldwide Moodle community. You can also join a low-volume mailing list providing early notifications of security fixes and new releases of Moodle.';
-$string['moodleorgregistrationdetail2'] = 'This option allows you to register your Moodle site with MOOCH, at hub.moodle.org. Registration is free.
-The main benefit of registering is that you will be added to a low-volume mailing list for important notifications such as security alerts and new releases of Moodle.
-By default, your information will be kept private, and will never be sold or passed on to anyone else. The only reason for collecting this information is for support purposes, and to help build up a statistical picture of the Moodle community as a whole.
-If you choose, you can allow your site name, country and URL to be added to the public list of Moodle Sites.
-All new registrations are verified manually before they are added to the list, but once you are added you can update your registration (and your entry on the public list) at any time.';
$string['mustselectsubject'] = 'You must select a subject';
$string['name'] = 'Name';
$string['name_help'] = 'This name will be showing in the course listing.';
$string['registeredsites'] = 'Registered sites';
$string['registrationinfo'] = 'Registration information';
$string['registeredmoodleorg'] = 'Moodle.org ({$a})';
-$string['registeredon'] = 'Registered with';
+$string['registeredon'] = 'Hubs with which you are registered';
+$string['registermoochtips'] = 'To be registered with Moodle.org Open Community Hub (MOOCH), your site must be registered with Moodle.org.';
$string['registersite'] = 'Register with {$a}';
-$string['registeron'] = 'Register your site';
-$string['registeronmoodleorg'] = 'Register with Moodle.org (MOOCH)';
-$string['registeronspecifichub'] = 'Register with a specific hub';
+$string['registerwith'] = 'Register with a hub';
$string['registrationconfirmed'] = 'Site registration confirmed';
$string['registrationconfirmedon'] = 'You are now registered on the hub {$a}. You are now able to publish courses to this hub, using the "Publish" link in course administration menus.';
$string['registrationupdated'] = 'Registration has been updated.';
$string['siteversion_help'] = 'The Moodle version of this site.';
$string['subject'] = 'Subject';
$string['subject_help'] = 'Select the main subject area which the course covers.';
-$string['specifichub'] = 'Specific hub';
$string['specifichubregistrationdetail'] = 'You can also register your site with other community hubs.';
$string['statistics'] = 'Statistics privacy';
$string['status'] = 'Hub listing';
$string['dndenabled'] = 'Drag and drop available';
$string['dndenabled_help'] = 'You can drag one or more files from your desktop and drop them onto the box below to upload them.<br />Note: this may not work with other web browsers';
$string['dndenabled_insentence'] = 'drag and drop available';
-$string['dndenabled_inbox'] = 'drag and drop files here to upload them';
+$string['dndenabled_inbox'] = 'You can drag and drop files here to add them.';
$string['dnduploadwithoutcontent'] = 'This upload does not have any content';
$string['dndworkingfiletextlink'] = 'Drag and drop files, text or links onto course sections to upload them';
$string['dndworkingfilelink'] = 'Drag and drop files or links onto course sections to upload them';
$string['checkforupdateslast'] = 'Last check done on {$a}';
$string['displayname'] = 'Plugin name';
$string['moodleversion'] = 'Moodle {$a}';
-$string['nonehighlighted'] = 'No plugins require your attention during this upgrade';
+$string['nonehighlighted'] = 'No plugins require your attention now';
$string['nonehighlightedinfo'] = 'Display the list of all installed plugins anyway';
$string['noneinstalled'] = 'No plugins of this type are installed';
$string['notes'] = 'Notes';
$string['requires'] = 'Requires';
$string['rootdir'] = 'Directory';
$string['settings'] = 'Settings';
-$string['somehighlighted'] = 'Number of plugins requiring attention during this upgrade: {$a}';
+$string['somehighlighted'] = 'Number of plugins requiring your attention: {$a}';
$string['somehighlightedinfo'] = 'Display the full list of installed plugins';
$string['somehighlightedonly'] = 'Display only plugins requiring your attention';
$string['source'] = 'Source';
$string['manageurl'] = 'Manage';
$string['manageuserrepository'] = 'Manage individual repository';
$string['moving'] = 'Moving';
+$string['newfoldername'] = 'New folder name:';
$string['noenter'] = 'Nothing entered';
$string['nofilesattached'] = 'No files attached';
$string['nofilesavailable'] = 'No files available';
$string['nofunctions'] = 'This service has no functions.';
$string['norequiredcapability'] = 'No required capability';
$string['notoken'] = 'The token list is empty.';
-$string['onesystemcontrolling'] = 'One system controlling Moodle with a token';
-$string['onesystemcontrollingdescription'] = 'The following steps help you to set up the Moodle web service for a system to control Moodle. These steps also help to set up the recommended token (security keys) authentication method.';
+$string['onesystemcontrolling'] = 'Allow an external system to control Moodle';
+$string['onesystemcontrollingdescription'] = 'The following steps help you to set up the Moodle web services to allow an external system to interact with Moodle. This includes setting up a token (security key) authentication method.';
$string['operation'] = 'Operation';
$string['optional'] = 'Optional';
$string['passwordisexpired'] = 'Password is expired.';
// Loop through completions, and mark as complete
$rs = $DB->get_recordset_sql($sql);
foreach ($rs as $record) {
- $completion = new completion_criteria_completion($record, DATA_OBJECT_FETCH_BY_KEY);
+ $completion = new completion_criteria_completion((array) $record, DATA_OBJECT_FETCH_BY_KEY);
$completion->mark_complete($record->timecompleted);
}
$rs->close();
// Loop through completions, and mark as complete
$rs = $DB->get_recordset_sql($sql);
foreach ($rs as $record) {
- $completion = new completion_criteria_completion($record, DATA_OBJECT_FETCH_BY_KEY);
- $completion->mark_complete($record['timecompleted']);
+ $completion = new completion_criteria_completion((array) $record, DATA_OBJECT_FETCH_BY_KEY);
+ $completion->mark_complete($record->timecompleted);
}
$rs->close();
}
// Loop through completions, and mark as complete
$rs = $DB->get_recordset_sql($sql, array(time()));
foreach ($rs as $record) {
- $completion = new completion_criteria_completion($record, DATA_OBJECT_FETCH_BY_KEY);
- $completion->mark_complete($record['timeend']);
+ $completion = new completion_criteria_completion((array) $record, DATA_OBJECT_FETCH_BY_KEY);
+ $completion->mark_complete($record->timeend);
}
$rs->close();
}
$now = time();
$rs = $DB->get_recordset_sql($sql, array($now, $now));
foreach ($rs as $record) {
- $completion = new completion_criteria_completion($record, DATA_OBJECT_FETCH_BY_KEY);
+ $completion = new completion_criteria_completion((array) $record, DATA_OBJECT_FETCH_BY_KEY);
// Use time start if not 0, otherwise use timeenrolled
if ($record->otimestart) {
// Loop through completions, and mark as complete
$rs = $DB->get_recordset_sql($sql);
foreach ($rs as $record) {
- $completion = new completion_criteria_completion($record, DATA_OBJECT_FETCH_BY_KEY);
- $completion->mark_complete($record['timecompleted']);
+ $completion = new completion_criteria_completion((array) $record, DATA_OBJECT_FETCH_BY_KEY);
+ $completion->mark_complete($record->timecompleted);
}
$rs->close();
}
* @return bool
*/
public function is_tracked_user($userid) {
- global $DB;
-
- $tracked = $this->generate_tracked_user_sql();
-
- $sql = "SELECT u.id ";
- $sql .= $tracked->sql;
- $sql .= ' AND u.id = :userid';
-
- $params = $tracked->data;
- $params['userid'] = (int)$userid;
- return $DB->record_exists_sql($sql, $params);
+ return is_enrolled(context_course::instance($this->course->id), $userid, '', true);
}
/**
- * Return number of users whose progress is tracked in this course
+ * Returns the number of users whose progress is tracked in this course.
*
- * Optionally supply a search's where clause, or a group id
+ * Optionally supply a search's where clause, or a group id.
*
- * @param string $where Where clause sql
- * @param array $where_params Where clause params
+ * @param string $where Where clause sql (use 'u.whatever' for user table fields)
+ * @param array $whereparams Where clause params
* @param int $groupid Group id
- * @return int
+ * @return int Number of tracked users
*/
- public function get_num_tracked_users($where = '', $where_params = array(), $groupid = 0) {
+ public function get_num_tracked_users($where = '', $whereparams = array(), $groupid = 0) {
global $DB;
- $tracked = $this->generate_tracked_user_sql($groupid);
-
- $sql = "SELECT COUNT(u.id) ";
- $sql .= $tracked->sql;
-
+ list($enrolledsql, $enrolledparams) = get_enrolled_sql(
+ context_course::instance($this->course->id), '', $groupid, true);
+ $sql = 'SELECT COUNT(eu.id) FROM (' . $enrolledsql . ') eu JOIN {user} u ON u.id = eu.id';
if ($where) {
- $sql .= " AND $where";
+ $sql .= " WHERE $where";
}
- $params = array_merge($tracked->data, $where_params);
+ $params = array_merge($enrolledparams, $whereparams);
return $DB->count_records_sql($sql, $params);
}
/**
- * Return array of users whose progress is tracked in this course
+ * Return array of users whose progress is tracked in this course.
*
- * Optionally supply a search's where caluse, group id, sorting, paging
+ * Optionally supply a search's where clause, group id, sorting, paging.
*
- * @param string $where Where clause sql (optional)
- * @param array $where_params Where clause params (optional)
- * @param integer $groupid Group ID to restrict to (optional)
+ * @param string $where Where clause sql, referring to 'u.' fields (optional)
+ * @param array $whereparams Where clause params (optional)
+ * @param int $groupid Group ID to restrict to (optional)
* @param string $sort Order by clause (optional)
- * @param integer $limitfrom Result start (optional)
- * @param integer $limitnum Result max size (optional)
+ * @param int $limitfrom Result start (optional)
+ * @param int $limitnum Result max size (optional)
* @param context $extracontext If set, includes extra user information fields
* as appropriate to display for current user in this context
- * @return array
+ * @return array Array of user objects with standard user fields
*/
- public function get_tracked_users($where = '', $where_params = array(), $groupid = 0,
+ public function get_tracked_users($where = '', $whereparams = array(), $groupid = 0,
$sort = '', $limitfrom = '', $limitnum = '', context $extracontext = null) {
global $DB;
- $tracked = $this->generate_tracked_user_sql($groupid);
- $params = $tracked->data;
+ list($enrolledsql, $params) = get_enrolled_sql(
+ context_course::instance($this->course->id), '', $groupid, true);
- $sql = "
- SELECT
- u.id,
- u.firstname,
- u.lastname,
- u.idnumber
- ";
+ $sql = 'SELECT u.id, u.firstname, u.lastname, u.idnumber';
if ($extracontext) {
$sql .= get_extra_user_fields_sql($extracontext, 'u', '', array('idnumber'));
}
-
- $sql .= $tracked->sql;
+ $sql .= ' FROM (' . $enrolledsql . ') eu JOIN {user} u ON u.id = eu.id';
if ($where) {
$sql .= " AND $where";
- $params = array_merge($params, $where_params);
+ $params = array_merge($params, $whereparams);
}
if ($sort) {
$sql .= " ORDER BY $sort";
}
- $users = $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
- return $users ? $users : array(); // In case it returns false
- }
-
- /**
- * Generate the SQL for finding tracked users in this course
- *
- * Returns an object containing the sql fragment and an array of
- * bound data params.
- *
- * @param integer $groupid
- * @return stdClass With two properties, sql (string), and data (array)
- */
- public function generate_tracked_user_sql($groupid = 0) {
- global $CFG;
-
- $return = new stdClass();
- $return->sql = '';
- $return->data = array();
-
- if (!empty($CFG->gradebookroles)) {
- $roles = ' AND ra.roleid IN ('.$CFG->gradebookroles.')';
- } else {
- // This causes it to default to everyone (if there is no student role)
- $roles = '';
- }
-
- // Build context sql
- $context = get_context_instance(CONTEXT_COURSE, $this->course->id);
- $parentcontexts = substr($context->path, 1); // kill leading slash
- $parentcontexts = str_replace('/', ',', $parentcontexts);
- if ($parentcontexts !== '') {
- $parentcontexts = ' OR ra.contextid IN ('.$parentcontexts.' )';
- }
-
- $groupjoin = '';
- $groupselect = '';
- if ($groupid) {
- $groupjoin = "JOIN {groups_members} gm
- ON gm.userid = u.id";
- $groupselect = " AND gm.groupid = :groupid ";
-
- $return->data['groupid'] = $groupid;
- }
-
- $return->sql = "
- FROM
- {user} u
- INNER JOIN
- {role_assignments} ra
- ON ra.userid = u.id
- INNER JOIN
- {role} r
- ON r.id = ra.roleid
- INNER JOIN
- {user_enrolments} ue
- ON ue.userid = u.id
- INNER JOIN
- {enrol} e
- ON e.id = ue.enrolid
- INNER JOIN
- {course} c
- ON c.id = e.courseid
- $groupjoin
- WHERE
- (ra.contextid = :contextid $parentcontexts)
- AND c.id = :courseid
- AND ue.status = 0
- AND e.status = 0
- AND ue.timestart < :now1
- AND (ue.timeend > :now2 OR ue.timeend = 0)
- $groupselect
- $roles
- ";
-
- $now = time();
- $return->data['now1'] = $now;
- $return->data['now2'] = $now;
- $return->data['contextid'] = $context->id;
- $return->data['courseid'] = $this->course->id;
-
- return $return;
+ return $DB->get_records_sql($sql, $params, $limitfrom, $limitnum);
}
/**
* @param object $cm Moodle course-module object. May have extra fields
* ->conditionsgrade, ->conditionscompletion which should come from
* get_fast_modinfo. Should have ->availablefrom, ->availableuntil,
- * and ->showavailability, ->course; but the only required thing is ->id.
+ * and ->showavailability, ->course, ->visible; but the only required
+ * thing is ->id.
* @param int $expectingmissing Used to control whether or not a developer
* debugging message (performance warning) will be displayed if some of
* the above data is missing and needs to be retrieved; a
* @return array Array of field names
*/
protected function get_main_table_fields() {
- return array('id', 'course', 'availablefrom', 'availableuntil', 'showavailability');
+ return array('id', 'course', 'visible',
+ 'availablefrom', 'availableuntil', 'showavailability');
}
/**
}
}
+ // If the item is marked as 'not visible' then we don't change the available
+ // flag (visible/available are treated distinctly), but we remove any
+ // availability info. If the item is hidden with the eye icon, it doesn't
+ // make sense to show 'Available from <date>' or similar, because even
+ // when that date arrives it will still not be available unless somebody
+ // toggles the eye icon.
+ if (!$this->item->visible) {
+ $information = '';
+ }
+
$information = trim($information);
return $available;
}
* @return mixed
*/
function min_optional_param($name, $default, $type) {
- $value = $default;
if (isset($_GET[$name])) {
$value = $_GET[$name];
} else if (isset($_GET['amp;'.$name])) {
// very, very, very ugly hack, unfortunately $OUTPUT->pix_url() is not used properly in javascript code :-(
$value = $_GET['amp;'.$name];
+
+ } else if (isset($_POST[$name])) {
+ $value = $_POST[$name];
+
+ } else {
+ return $default;
}
return min_clean_param($value, $type);
/**
* Minimalistic parameter cleaning function.
- * Can not use optional param because moodlelib.php is not loaded yet
- * @param string $name
- * @param mixed $default
+ *
+ * Note: Can not use optional param because moodlelib.php is not loaded yet.
+ *
+ * @param string $value
* @param string $type
* @return mixed
*/
function min_clean_param($value, $type) {
switch($type) {
- case 'RAW': $value = iconv('UTF-8', 'UTF-8//IGNORE', $value);
+ case 'RAW': $value = min_fix_utf8((string)$value);
break;
case 'INT': $value = (int)$value;
break;
return $value;
}
+/**
+ * Minimalistic UTF-8 sanitisation.
+ *
+ * Note: This duplicates fix_utf8() intentionally for now.
+ *
+ * @param string $value
+ * @return string
+ */
+function min_fix_utf8($value) {
+ // Lower error reporting because glibc throws bogus notices.
+ $olderror = error_reporting();
+ if ($olderror & E_NOTICE) {
+ error_reporting($olderror ^ E_NOTICE);
+ }
+
+ static $buggyiconv = null;
+ if ($buggyiconv === null) {
+ $buggyiconv = (!function_exists('iconv') or iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
+ }
+
+ if ($buggyiconv) {
+ if (function_exists('mb_convert_encoding')) {
+ $subst = mb_substitute_character();
+ mb_substitute_character('');
+ $result = mb_convert_encoding($value, 'utf-8', 'utf-8');
+ mb_substitute_character($subst);
+
+ } else {
+ // Warn admins on admin/index.php page.
+ $result = $value;
+ }
+
+ } else {
+ $result = iconv('UTF-8', 'UTF-8//IGNORE', $value);
+ }
+
+ if ($olderror & E_NOTICE) {
+ error_reporting($olderror);
+ }
+
+ return $result;
+}
+
/**
* This method tries to enable output compression if possible.
* This function must be called before any output or headers.
/**
* Returns the slashargument part of the URL.
- * Note: ".php" is NOT allowed in slasharguments!
+ *
+ * Note: ".php" is NOT allowed in slasharguments,
+ * it is intended for ASCII characters only.
*
* @return string
*/
// Send login failures notification - brute force protection in moodle is weak,
// we should at least send notices early in each cron execution
- if (!empty($CFG->notifyloginfailures)) {
- notify_login_failures();
- mtrace(' Notified login failured');
+ if (notify_login_failures()) {
+ mtrace(' Notified login failures');
}
* Note that this function must be only executed from the cron script
* It uses the cache_flags system to store temporary records, deleting them
* by name before finishing
+ *
+ * @return bool True if executed, false if not
*/
function notify_login_failures() {
global $CFG, $DB, $OUTPUT;
+ if (empty($CFG->notifyloginfailures)) {
+ return false;
+ }
+
$recip = get_users_from_config($CFG->notifyloginfailures, 'moodle/site:config');
if (empty($CFG->lastnotifyfailure)) {
$CFG->lastnotifyfailure=0;
}
+ // If it has been less than an hour, or if there are no recipients, don't execute.
+ if (((time() - HOURSECS) < $CFG->lastnotifyfailure) || !is_array($recip) || count($recip) <= 0) {
+ return false;
+ }
+
// we need to deal with the threshold stuff first.
if (empty($CFG->notifyloginthreshold)) {
$CFG->notifyloginthreshold = 10; // default to something sensible.
}
$rs->close();
- // If we haven't run in the last hour and
- // we have something useful to report and we
- // are actually supposed to be reporting to somebody
- if ((time() - HOURSECS) > $CFG->lastnotifyfailure && $count > 0 && is_array($recip) && count($recip) > 0) {
+ // If we have something useful to report.
+ if ($count > 0) {
$site = get_site();
$subject = get_string('notifyloginfailuressubject', '', format_string($site->fullname));
// Calculate the complete body of notification (start + messages + end)
// Finally, delete all the temp records we have created in cache_flags
$DB->delete_records_select('cache_flags', "flagtype IN ('login_failure_by_ip', 'login_failure_by_info')");
+
+ return true;
}
'contextlevel' => CONTEXT_BLOCK,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW
)
),
</KEYS>
<INDEXES>
<INDEX NAME="course" UNIQUE="false" FIELDS="course" NEXT="criteriatype"/>
- <INDEX NAME="criteriatype" UNIQUE="false" FIELDS="criteriatype" PREVIOUS="course"/>
+ <INDEX NAME="criteriatype" UNIQUE="false" FIELDS="criteriatype" PREVIOUS="course" NEXT="coursecriteriatype"/>
+ <INDEX NAME="coursecriteriatype" UNIQUE="true" FIELDS="course, criteriatype" PREVIOUS="criteriatype"/>
</INDEXES>
</TABLE>
<TABLE NAME="course_completion_criteria" COMMENT="Course completion criteria" PREVIOUS="course_completion_aggr_methd" NEXT="course_completion_crit_compl">
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid" NEXT="course"/>
<INDEX NAME="course" UNIQUE="false" FIELDS="course" PREVIOUS="userid" NEXT="criteriaid"/>
<INDEX NAME="criteriaid" UNIQUE="false" FIELDS="criteriaid" PREVIOUS="course" NEXT="timecompleted"/>
- <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="criteriaid"/>
+ <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="criteriaid" NEXT="useridcoursecriteriaid"/>
+ <INDEX NAME="useridcoursecriteriaid" UNIQUE="true" FIELDS="userid, course, criteriaid" PREVIOUS="timecompleted"/>
</INDEXES>
</TABLE>
<TABLE NAME="course_completion_notify" COMMENT="Course completion notification emails" PREVIOUS="course_completion_crit_compl" NEXT="course_completions">
<INDEXES>
<INDEX NAME="userid" UNIQUE="false" FIELDS="userid" NEXT="course"/>
<INDEX NAME="course" UNIQUE="false" FIELDS="course" PREVIOUS="userid" NEXT="timecompleted"/>
- <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="course"/>
+ <INDEX NAME="timecompleted" UNIQUE="false" FIELDS="timecompleted" PREVIOUS="course" NEXT="useridcourse"/>
+ <INDEX NAME="useridcourse" UNIQUE="true" FIELDS="userid, course" PREVIOUS="timecompleted"/>
</INDEXES>
</TABLE>
<TABLE NAME="enrol" COMMENT="Instances of enrolment plugins used in courses, fields marked as custom have a plugin defined meaning, core does not touch them. Create a new linked table if you need even more custom fields." PREVIOUS="course_completions" NEXT="user_enrolments">
</KEYS>
</TABLE>
</TABLES>
-</XMLDB>
\ No newline at end of file
+</XMLDB>
$logs = array(
array('module'=>'course', 'action'=>'user report', 'mtable'=>'user', 'field'=>$DB->sql_concat('firstname', "' '" , 'lastname')),
array('module'=>'course', 'action'=>'view', 'mtable'=>'course', 'field'=>'fullname'),
+ array('module'=>'course', 'action'=>'view section', 'mtable'=>'course_sections', 'field'=>'COALESCE(name, section)'),
array('module'=>'course', 'action'=>'update', 'mtable'=>'course', 'field'=>'fullname'),
array('module'=>'course', 'action'=>'enrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
array('module'=>'course', 'action'=>'unenrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
upgrade_main_savepoint(true, 2012052100.00);
}
+ if ($oldversion < 2012052500.03) { // fix invalid course_completion_records MDL-27368
+ //first get all instances of duplicate records
+ $sql = 'SELECT userid, course FROM {course_completions} WHERE (deleted IS NULL OR deleted <> 1) GROUP BY userid, course HAVING (count(id) > 1)';
+ $duplicates = $DB->get_recordset_sql($sql, array());
+
+ foreach ($duplicates as $duplicate) {
+ $pointer = 0;
+ //now get all the records for this user/course
+ $sql = 'userid = ? AND course = ? AND (deleted IS NULL OR deleted <> 1)';
+ $completions = $DB->get_records_select('course_completions', $sql,
+ array($duplicate->userid, $duplicate->course), 'timecompleted DESC, timestarted DESC');
+ $needsupdate = false;
+ $origcompletion = null;
+ foreach ($completions as $completion) {
+ $pointer++;
+ if ($pointer === 1) { //keep 1st record but delete all others.
+ $origcompletion = $completion;
+ } else {
+ //we need to keep the "oldest" of all these fields as the valid completion record.
+ $fieldstocheck = array('timecompleted', 'timestarted', 'timeenrolled');
+ foreach ($fieldstocheck as $f) {
+ if ($origcompletion->$f > $completion->$f) {
+ $origcompletion->$f = $completion->$f;
+ $needsupdate = true;
+ }
+ }
+ $DB->delete_records('course_completions', array('id'=>$completion->id));
+ }
+ }
+ if ($needsupdate) {
+ $DB->update_record('course_completions', $origcompletion);
+ }
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052500.03);
+ }
+
+ if ($oldversion < 2012052900.00) {
+ // Clean up all duplicate records in the course_completions table in preparation
+ // for adding a new index there.
+ upgrade_course_completion_remove_duplicates(
+ 'course_completions',
+ array('userid', 'course'),
+ array('timecompleted', 'timestarted', 'timeenrolled')
+ );
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.00);
+ }
+
+ if ($oldversion < 2012052900.01) {
+ // Add indexes to prevent new duplicates in the course_completions table.
+ // Define index useridcourse (unique) to be added to course_completions
+ $table = new xmldb_table('course_completions');
+ $index = new xmldb_index('useridcourse', XMLDB_INDEX_UNIQUE, array('userid', 'course'));
+
+ // Conditionally launch add index useridcourse
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.01);
+ }
+
+ if ($oldversion < 2012052900.02) {
+ // Clean up all duplicate records in the course_completion_crit_compl table in preparation
+ // for adding a new index there.
+ upgrade_course_completion_remove_duplicates(
+ 'course_completion_crit_compl',
+ array('userid', 'course', 'criteriaid'),
+ array('timecompleted')
+ );
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.02);
+ }
+
+ if ($oldversion < 2012052900.03) {
+ // Add indexes to prevent new duplicates in the course_completion_crit_compl table.
+ // Define index useridcoursecriteraid (unique) to be added to course_completion_crit_compl
+ $table = new xmldb_table('course_completion_crit_compl');
+ $index = new xmldb_index('useridcoursecriteraid', XMLDB_INDEX_UNIQUE, array('userid', 'course', 'criteriaid'));
+
+ // Conditionally launch add index useridcoursecriteraid
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.03);
+ }
+
+ if ($oldversion < 2012052900.04) {
+ // Clean up all duplicate records in the course_completion_aggr_methd table in preparation
+ // for adding a new index there.
+ upgrade_course_completion_remove_duplicates(
+ 'course_completion_aggr_methd',
+ array('course', 'criteriatype')
+ );
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.04);
+ }
+
+ if ($oldversion < 2012052900.05) {
+ // Add indexes to prevent new duplicates in the course_completion_aggr_methd table.
+ // Define index coursecriteratype (unique) to be added to course_completion_aggr_methd
+ $table = new xmldb_table('course_completion_aggr_methd');
+ $index = new xmldb_index('coursecriteriatype', XMLDB_INDEX_UNIQUE, array('course', 'criteriatype'));
+
+ // Conditionally launch add index coursecriteratype
+ if (!$dbman->index_exists($table, $index)) {
+ $dbman->add_index($table, $index);
+ }
+
+ // Main savepoint reached
+ upgrade_main_savepoint(true, 2012052900.05);
+ }
+
return true;
-}
+}
\ No newline at end of file
} else {
unset($params['id']);
if ($returnid) {
- $returning = "; SELECT SCOPE_IDENTITY()";
+ $returning = "OUTPUT inserted.id";
}
}
$qms = array_fill(0, count($params), '?');
$qms = implode(',', $qms);
- $sql = "INSERT INTO {" . $table . "} ($fields) VALUES($qms) $returning";
+ $sql = "INSERT INTO {" . $table . "} ($fields) $returning VALUES ($qms)";
list($sql, $params, $type) = $this->fix_sql_params($sql, $params);
$rawsql = $this->emulate_bound_params($sql, $params);
$this->query_start($sql, $params, SQL_QUERY_INSERT);
$result = mssql_query($rawsql, $this->mssql);
- $this->query_end($result);
+ // Expected results are:
+ // - true: insert ok and there isn't returned information.
+ // - false: insert failed and there isn't returned information.
+ // - resource: insert executed, need to look for returned (output)
+ // values to know if the insert was ok or no. Posible values
+ // are false = failed, integer = insert ok, id returned.
+ $end = false;
+ if (is_bool($result)) {
+ $end = $result;
+ } else if (is_resource($result)) {
+ $end = mssql_result($result, 0, 0); // Fetch 1st column from 1st row.
+ }
+ $this->query_end($end); // End the query with the calculated $end.
if ($returning !== "") {
- $row = mssql_fetch_assoc($result);
- $params['id'] = reset($row);
+ $params['id'] = $end;
}
$this->free_result($result);
$this->assertEquals(1e-300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
$id = $DB->insert_record($tablename, array('onetext' => 1e300));
$this->assertEquals(1e300, $DB->get_field($tablename, 'onetext', array('id' => $id)));
+
+ // Test that inserting data violating one unique key leads to error.
+ // Empty the table completely.
+ $this->assertTrue($DB->delete_records($tablename));
+
+ // Add one unique constraint (index).
+ $key = new xmldb_key('testuk', XMLDB_KEY_UNIQUE, array('course', 'oneint'));
+ $dbman->add_key($table, $key);
+
+ // Let's insert one record violating the constraint multiple times.
+ $record = (object)array('course' => 1, 'oneint' => 1);
+ $this->assertTrue($DB->insert_record($tablename, $record, false)); // insert 1st. No problem expected.
+
+ // Re-insert same record, not returning id. dml_exception expected.
+ try {
+ $DB->insert_record($tablename, $record, false);
+ $this->fail("Expecting an exception, none occurred");
+ } catch (exception $e) {
+ $this->assertTrue($e instanceof dml_exception);
+ }
+
+ // Re-insert same record, returning id. dml_exception expected.
+ try {
+ $DB->insert_record($tablename, $record, true);
+ $this->fail("Expecting an exception, none occurred");
+ } catch (exception $e) {
+ $this->assertTrue($e instanceof dml_exception);
+ }
}
public function test_import_record() {
'sin','sinh','arcsin','asin','arcsinh','asinh',
'cos','cosh','arccos','acos','arccosh','acosh',
'tan','tanh','arctan','atan','arctanh','atanh',
- 'sqrt','abs','ln','log','exp','floor','ceil','round');
+ 'sqrt','abs','ln','log','exp','floor','ceil');
var $fc = array( // calc functions emulation
'average'=>array(-1), 'max'=>array(-1), 'min'=>array(-1),
/**
* Copy content of this file to local storage, overriding current file if needed.
*
- * @param int $contextid context ID
- * @param string $component component
- * @param string $filearea file area
- * @param int $itemid item ID
- * @param string $filepath file path
- * @param string $filename file name
- * @return boolean success
+ * @param array|stdClass $filerecord contains contextid, component, filearea,
+ * itemid, filepath, filename and optionally other attributes of the new file
+ * @return bool success
*/
- public function copy_to_storage($contextid, $component, $filearea, $itemid, $filepath, $filename) {
+ public function copy_to_storage($filerecord) {
return false;
}
if ($this->is_directory()) {
$filepath = $this->lf->get_filepath();
$fs = get_file_storage();
- $storedfiles = $fs->get_area_files($this->context->id, $this->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid(), "");
+ $storedfiles = $fs->get_area_files($this->context->id, $this->get_component(), $this->lf->get_filearea(), $this->lf->get_itemid());
foreach ($storedfiles as $file) {
if (strpos($file->get_filepath(), $filepath) === 0) {
$file->delete();
/**
* Copy content of this file to local storage, overriding current file if needed.
*
- * @param int $contextid context ID
- * @param string $component file component
- * @param string $filearea file area
- * @param int $itemid item ID
- * @param string $filepath file path
- * @param string $filename file name
+ * @param array|stdClass $filerecord contains contextid, component, filearea,
+ * itemid, filepath, filename and optionally other attributes of the new file
* @return bool success
*/
- public function copy_to_storage($contextid, $component, $filearea, $itemid, $filepath, $filename) {
+ public function copy_to_storage($filerecord) {
if (!$this->is_readable() or $this->is_directory()) {
return false;
}
+ $filerecord = (array)$filerecord;
$fs = get_file_storage();
- if ($existing = $fs->get_file($contextid, $component, $filearea, $itemid, $filepath, $filename)) {
+ if ($existing = $fs->get_file($filerecord['contextid'], $filerecord['component'], $filerecord['filearea'], $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename'])) {
$existing->delete();
}
- $file_record = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'filepath'=>$filepath, 'filename'=>$filename);
- $fs->create_file_from_storedfile($file_record, $this->lf);
+ $fs->create_file_from_storedfile($filerecord, $this->lf);
return true;
}
if (!empty($options['preview'])) {
// replace the file with its preview
$fs = get_file_storage();
- $stored_file = $fs->get_file_preview($stored_file, $options['preview']);
- if (!$stored_file) {
- // unable to create a preview of the file
- send_header_404();
- die();
+ $preview_file = $fs->get_file_preview($stored_file, $options['preview']);
+ if (!$preview_file) {
+ // unable to create a preview of the file, send its default mime icon instead
+ if ($options['preview'] === 'tinyicon') {
+ $size = 24;
+ } else if ($options['preview'] === 'thumb') {
+ $size = 90;
+ } else {
+ $size = 256;
+ }
+ $fileicon = file_file_icon($stored_file, $size);
+ send_file($CFG->dirroot.'/pix/'.$fileicon.'.png', basename($fileicon).'.png');
} else {
// preview images have fixed cache lifetime and they ignore forced download
// (they are generated by GD and therefore they are considered reasonably safe).
+ $stored_file = $preview_file;
$lifetime = DAYSECS;
$filter = 0;
$forcedownload = false;
}
// fix file name automatically
- if ($filename !== 'f1' and $filename !== 'f2') {
+ if ($filename !== 'f1' and $filename !== 'f2' and $filename !== 'f3') {
$filename = 'f1';
}
redirect($theme->pix_url('u/'.$filename, 'moodle')); // intentionally not cached
}
- if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.png')) {
- if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'/.jpg')) {
- // bad reference - try to prevent future retries as hard as possible!
- if ($user = $DB->get_record('user', array('id'=>$context->instanceid), 'id, picture')) {
- if ($user->picture == 1 or $user->picture > 10) {
- $DB->set_field('user', 'picture', 0, array('id'=>$user->id));
+ if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'.png')) {
+ if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', $filename.'.jpg')) {
+ if ($filename === 'f3') {
+ // f3 512x512px was introduced in 2.3, there might be only the smaller version.
+ if (!$file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.png')) {
+ $file = $fs->get_file($context->id, 'user', 'icon', 0, '/', 'f1.jpg');
}
}
- // no redirect here because it is not cached
- $theme = theme_config::load($themename);
- $imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
- send_file($imagefile, basename($imagefile), 60*60*24*14);
}
}
+ if (!$file) {
+ // bad reference - try to prevent future retries as hard as possible!
+ if ($user = $DB->get_record('user', array('id'=>$context->instanceid), 'id, picture')) {
+ if ($user->picture > 0) {
+ $DB->set_field('user', 'picture', 0, array('id'=>$user->id));
+ }
+ }
+ // no redirect here because it is not cached
+ $theme = theme_config::load($themename);
+ $imagefile = $theme->resolve_image_location('u/'.$filename, 'moodle');
+ send_file($imagefile, basename($imagefile), 60*60*24*14);
+ }
send_stored_file($file, 60*60*24*365, 0, false, array('preview' => $preview)); // enable long caching, there are many images on each page
* Returns all files belonging to given repository
*
* @param int $repositoryid
- * @param string $sort
+ * @param string $sort A fragment of SQL to use for sorting
*/
public function get_external_files($repositoryid, $sort = 'sortorder, itemid, filepath, filename') {
global $DB;
FROM {files} f
LEFT JOIN {files_reference} r
ON f.referencefileid = r.id
- WHERE r.repositoryid = ?
- ORDER BY $sort";
+ WHERE r.repositoryid = ?";
+ if (!empty($sort)) {
+ $sql .= " ORDER BY {$sort}";
+ }
$result = array();
$filerecords = $DB->get_records_sql($sql, array($repositoryid));
* @param string $component component
* @param string $filearea file area
* @param int $itemid item ID or all files if not specified
- * @param string $sort sort fields
+ * @param string $sort A fragment of SQL to use for sorting
* @param bool $includedirs whether or not include directories
* @return array of stored_files indexed by pathanmehash
*/
- public function get_area_files($contextid, $component, $filearea, $itemid = false, $sort="sortorder, itemid, filepath, filename", $includedirs = true) {
+ public function get_area_files($contextid, $component, $filearea, $itemid = false, $sort = "sortorder, itemid, filepath, filename", $includedirs = true) {
global $DB;
$conditions = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea);
WHERE f.contextid = :contextid
AND f.component = :component
AND f.filearea = :filearea
- $itemidsql
- ORDER BY $sort";
+ $itemidsql";
+ if (!empty($sort)) {
+ $sql .= " ORDER BY {$sort}";
+ }
$result = array();
$filerecords = $DB->get_records_sql($sql, $conditions);
* @param int $filepath directory path
* @param bool $recursive include all subdirectories
* @param bool $includedirs include files and directories
- * @param string $sort sort fields
+ * @param string $sort A fragment of SQL to use for sorting
* @return array of stored_files indexed by pathanmehash
*/
public function get_directory_files($contextid, $component, $filearea, $itemid, $filepath, $recursive = false, $includedirs = true, $sort = "filepath, filename") {
return array();
}
+ $orderby = (!empty($sort)) ? " ORDER BY {$sort}" : '';
+
if ($recursive) {
$dirs = $includedirs ? "" : "AND filename <> '.'";
AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
AND f.id <> :dirid
$dirs
- ORDER BY $sort";
+ $orderby";
$params = array('contextid'=>$contextid, 'component'=>$component, 'filearea'=>$filearea, 'itemid'=>$itemid, 'filepath'=>$filepath, 'dirid'=>$directory->get_id());
$files = array();
AND f.itemid = :itemid AND f.filename = '.'
AND ".$DB->sql_substr("f.filepath", 1, $length)." = :filepath
AND f.id <> :dirid
- ORDER BY $sort";
+ $orderby";
$reqlevel = substr_count($filepath, '/') + 1;
$filerecords = $DB->get_records_sql($sql, $params);
foreach ($filerecords as $filerecord) {
ON f.referencefileid = r.id
WHERE f.contextid = :contextid AND f.component = :component AND f.filearea = :filearea AND f.itemid = :itemid
AND f.filepath = :filepath AND f.filename <> '.'
- ORDER BY $sort";
+ $orderby";
$filerecords = $DB->get_records_sql($sql, $params);
foreach ($filerecords as $filerecord) {
$newrecord->timecreated = $filerecord->timecreated;
$newrecord->timemodified = $filerecord->timemodified;
- $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($pathname) : $filerecord->mimetype;
+ $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($pathname, $filerecord->filename) : $filerecord->mimetype;
$newrecord->userid = empty($filerecord->userid) ? null : $filerecord->userid;
$newrecord->source = empty($filerecord->source) ? null : $filerecord->source;
$newrecord->author = empty($filerecord->author) ? null : $filerecord->author;
list($newrecord->contenthash, $newrecord->filesize, $newfile) = $this->add_string_to_pool($content);
$filepathname = $this->path_from_hash($newrecord->contenthash) . '/' . $newrecord->contenthash;
// get mimetype by magic bytes
- $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($filepathname) : $filerecord->mimetype;
+ $newrecord->mimetype = empty($filerecord->mimetype) ? $this->mimetype($filepathname, $filerecord->filename) : $filerecord->mimetype;
$newrecord->pathnamehash = $this->get_pathname_hash($newrecord->contextid, $newrecord->component, $newrecord->filearea, $newrecord->itemid, $newrecord->filepath, $newrecord->filename);
$filerecord->timemodified = $now;
}
+ $transaction = $DB->start_delegated_transaction();
+
// Insert file reference record.
try {
$referencerecord = new stdClass;
$this->create_directory($filerecord->contextid, $filerecord->component, $filerecord->filearea, $filerecord->itemid, $filerecord->filepath, $filerecord->userid);
+ $transaction->allow_commit();
+
// Adding repositoryid and reference to file record to create stored_file instance
$filerecord->repositoryid = $repositoryid;
$filerecord->reference = $reference;
* If file has a known extension, we return the mimetype based on extension.
* Otherwise (when possible) we try to get the mimetype from file contents.
*
- * @param string $pathname
+ * @param string $pathname full path to the file
+ * @param string $filename correct file name with extension, if omitted will be taken from $path
* @return string
*/
- public static function mimetype($pathname) {
- $type = mimeinfo('type', $pathname);
+ public static function mimetype($pathname, $filename = null) {
+ if (empty($filename)) {
+ $filename = $pathname;
+ }
+ $type = mimeinfo('type', $filename);
if ($type === 'document/unknown' && class_exists('finfo') && file_exists($pathname)) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
$type = mimeinfo_from_type('type', $finfo->file($pathname));
// Remove repository info.
$this->repository = null;
+ $transaction = $DB->start_delegated_transaction();
+
// Remove reference info from DB.
$DB->delete_records('files_reference', array('id'=>$this->file_record->referencefileid));
$filerecord->referencefileid = null;
$this->update($filerecord);
+ $transaction->allow_commit();
+
// unset object variable
unset($this->file_record->repositoryid);
unset($this->file_record->reference);
*/
public function delete() {
global $DB;
+
+ $transaction = $DB->start_delegated_transaction();
+
// If other files referring to this file, we need convert them
if ($files = $this->fs->get_references_by_storedfile($this)) {
foreach ($files as $file) {
// Now delete file records in DB
$DB->delete_records('files', array('id'=>$this->file_record->id));
$DB->delete_records('files_reference', array('id'=>$this->file_record->referencefileid));
+
+ $transaction->allow_commit();
+
// moves pool file to trash if content not needed any more
$this->fs->deleted_file_cleanup($this->file_record->contenthash);
return true; // BC only
$previewtinyicon = $fs->get_file_preview($file, 'thumb');
$this->assertInstanceOf('stored_file', $previewtinyicon);
$this->assertEquals('6b9864ae1536a8eeef54e097319175a8be12f07c', $previewtinyicon->get_filename());
+
+ $this->setExpectedException('file_exception');
+ $fs->get_file_preview($file, 'amodewhichdoesntexist');
+ }
+
+ public function test_get_file_preview_nonimage() {
+ $this->resetAfterTest(true);
+ $syscontext = context_system::instance();
+ $filerecord = array(
+ 'contextid' => $syscontext->id,
+ 'component' => 'core',
+ 'filearea' => 'unittest',
+ 'itemid' => 0,
+ 'filepath' => '/textfiles/',
+ 'filename' => 'testtext.txt',
+ );
+
+ $fs = get_file_storage();
+ $fs->create_file_from_string($filerecord, 'text contents');
+ $textfile = $fs->get_file($syscontext->id, $filerecord['component'], $filerecord['filearea'],
+ $filerecord['itemid'], $filerecord['filepath'], $filerecord['filename']);
+
+ $preview = $fs->get_file_preview($textfile, 'thumb');
+ $this->assertFalse($preview);
}
/**
$this->assertEquals($content, $importedfile->get_content());
}
- /**
- * TODO: the tests following this line were added to demonstrate specific Oracle problems in
- * MDL-33172. They need to be improved to properly evalulate the results of the tests. This is
- * tracked in MDL-33326.
- */
private function setup_three_private_files() {
- global $USER, $DB;
$this->resetAfterTest(true);
$generator = $this->getDataGenerator();
$user = $generator->create_user();
+ $this->setUser($user->id);
$usercontext = context_user::instance($user->id);
- $USER = $DB->get_record('user', array('id'=>$user->id));
// create a user private file
$file1 = new stdClass;
$file1->contextid = $usercontext->id;
$fs = get_file_storage();
$userfile1 = $fs->create_file_from_string($file1, 'file1 content');
+ $this->assertInstanceOf('stored_file', $userfile1);
+
$file2 = clone($file1);
$file2->filename = '2.txt';
$userfile2 = $fs->create_file_from_string($file2, 'file2 content');
+ $this->assertInstanceOf('stored_file', $userfile2);
$file3 = clone($file1);
$file3->filename = '3.txt';
$userfile3 = $fs->create_file_from_storedfile($file3, $userfile2);
+ $this->assertInstanceOf('stored_file', $userfile3);
$user->ctxid = $usercontext->id;
return $user;
}
-
public function test_get_area_files() {
$user = $this->setup_three_private_files();
$fs = get_file_storage();
// Get area files with default options.
$areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
+
// Should be the two files we added plus the folder.
$this->assertEquals(4, count($areafiles));
+ // Verify structure.
+ foreach ($areafiles as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
+
// Get area files without a folder.
- $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'sortorder', false);
+ $folderlessfiles = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'sortorder', false);
// Should be the two files without folder.
- $this->assertEquals(3, count($areafiles));
+ $this->assertEquals(3, count($folderlessfiles));
+
+ // Verify structure.
+ foreach ($folderlessfiles as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
// Get area files ordered by id (was breaking on oracle).
- $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'id', false);
+ $filesbyid = $fs->get_area_files($user->ctxid, 'user', 'private', false, 'id', false);
// Should be the two files without folder.
- $this->assertEquals(3, count($areafiles));
+ $this->assertEquals(3, count($filesbyid));
+
+ // Verify structure.
+ foreach ($filesbyid as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
// Test with an itemid with no files
$areafiles = $fs->get_area_files($user->ctxid, 'user', 'private', 666, 'sortorder', false);
- // Should none
- $this->assertEquals(0, count($areafiles));
+ // Should be none.
+ $this->assertEmpty($areafiles);
}
public function test_get_area_tree() {
$user = $this->setup_three_private_files();
$fs = get_file_storage();
+
// Get area files with default options.
- $areafiles = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
- $areafiles = $fs->get_area_tree($user->ctxid, 'user', 'private', 666);
- //TODO: verify result!! MDL-33326
+ $areatree = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
+ $this->assertEmpty($areatree['subdirs']);
+ $this->assertNotEmpty($areatree['files']);
+ $this->assertCount(3, $areatree['files']);
+
+ // Ensure an empty try with a fake itemid.
+ $emptytree = $fs->get_area_tree($user->ctxid, 'user', 'private', 666);
+ $this->assertEmpty($emptytree['subdirs']);
+ $this->assertEmpty($emptytree['files']);
+
+ // Create a subdir.
+ $dir = $fs->create_directory($user->ctxid, 'user', 'private', 0, '/testsubdir/');
+ $this->assertInstanceOf('stored_file', $dir);
+
+ // Add a file to the subdir.
+ $filerecord = array(
+ 'contextid' => $user->ctxid,
+ 'component' => 'user',
+ 'filearea' => 'private',
+ 'itemid' => 0,
+ 'filepath' => '/testsubdir/',
+ 'filename' => 'test-get-area-tree.txt',
+ );
+
+ $directoryfile = $fs->create_file_from_string($filerecord, 'Test content');
+ $this->assertInstanceOf('stored_file', $directoryfile);
+
+ $areatree = $fs->get_area_tree($user->ctxid, 'user', 'private', 0);
+
+ // At the top level there should still be 3 files.
+ $this->assertCount(3, $areatree['files']);
+
+ // There should now be a subdirectory.
+ $this->assertCount(1, $areatree['subdirs']);
+
+ // The test subdir is named testsubdir.
+ $subdir = $areatree['subdirs']['testsubdir'];
+ $this->assertNotEmpty($subdir);
+ // It should have one file we added.
+ $this->assertCount(1, $subdir['files']);
+ // And no subdirs itself.
+ $this->assertCount(0, $subdir['subdirs']);
+
+ // Verify the file is the one we added.
+ $subdirfile = reset($subdir['files']);
+ $this->assertInstanceOf('stored_file', $subdirfile);
+ $this->assertEquals($filerecord['filename'], $subdirfile->get_filename());
}
public function test_get_file_by_id() {
$filebyid = reset($areafiles);
$shouldbesame = $fs->get_file_by_id($filebyid->get_id());
$this->assertEquals($filebyid->get_contenthash(), $shouldbesame->get_contenthash());
+
+ // Test an id which doens't exist.
+ $doesntexist = $fs->get_file_by_id(99999);
+ $this->assertFalse($doesntexist);
}
public function test_get_file_by_hash() {
$filebyhash = reset($areafiles);
$shouldbesame = $fs->get_file_by_hash($filebyhash->get_pathnamehash());
$this->assertEquals($filebyhash->get_id(), $shouldbesame->get_id());
+
+ // Test an hash which doens't exist.
+ $doesntexist = $fs->get_file_by_hash('DOESNTEXIST');
+ $this->assertFalse($doesntexist);
}
public function test_get_references_by_storedfile() {
$testfile = reset($areafiles);
$references = $fs->get_references_by_storedfile($testfile);
- //TODO: verify result!! MDL-33326
+ // TODO MDL-33368 Verify result!!
}
public function test_get_external_files() {
$userrepository = reset($repos);
$this->assertInstanceOf('repository', $userrepository);
- // this should break on oracle
+ // This should break on oracle.
$fs->get_external_files($userrepository->id, 'id');
- //TODO: verify result!! MDL-33326
- }
+ // TODO MDL-33368 Verify result!!
+ }
+
+ public function test_create_directory_contextid_negative() {
+ $fs = get_file_storage();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory(-1, 'core', 'unittest', 0, '/');
+ }
+
+ public function test_create_directory_contextid_invalid() {
+ $fs = get_file_storage();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory('not an int', 'core', 'unittest', 0, '/');
+ }
+
+ public function test_create_directory_component_invalid() {
+ $fs = get_file_storage();
+ $syscontext = context_system::instance();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory($syscontext->id, 'bad/component', 'unittest', 0, '/');
+ }
+
+ public function test_create_directory_filearea_invalid() {
+ $fs = get_file_storage();
+ $syscontext = context_system::instance();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory($syscontext->id, 'core', 'bad-filearea', 0, '/');
+ }
+
+ public function test_create_directory_itemid_negative() {
+ $fs = get_file_storage();
+ $syscontext = context_system::instance();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory($syscontext->id, 'core', 'unittest', -1, '/');
+ }
+
+ public function test_create_directory_itemid_invalid() {
+ $fs = get_file_storage();
+ $syscontext = context_system::instance();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory($syscontext->id, 'core', 'unittest', 'notanint', '/');
+ }
+
+ public function test_create_directory_filepath_invalid() {
+ $fs = get_file_storage();
+ $syscontext = context_system::instance();
+
+ $this->setExpectedException('file_exception');
+ $fs->create_directory($syscontext->id, 'core', 'unittest', 0, '/not-with-trailing/or-leading-slash');
+ }
public function test_get_directory_files() {
$user = $this->setup_three_private_files();
$fs = get_file_storage();
- // This should also break on oracle.
- $fs->create_directory($user->ctxid, 'user', 'private', 0, '/');
- //TODO: verify result!! MDL-33326
+ $dir = $fs->create_directory($user->ctxid, 'user', 'private', 0, '/testsubdir/');
+ $this->assertInstanceOf('stored_file', $dir);
- // Don't recurse with dirs
- $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, true, 'id');
- //TODO: verify result!! MDL-33326
+ // Add a file to the subdir.
+ $filerecord = array(
+ 'contextid' => $user->ctxid,
+ 'component' => 'user',
+ 'filearea' => 'private',
+ 'itemid' => 0,
+ 'filepath' => '/testsubdir/',
+ 'filename' => 'test-get-area-tree.txt',
+ );
- // Don't recurse without dirs
- $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, false, 'id');
- //TODO: verify result!! MDL-33326
+ $directoryfile = $fs->create_file_from_string($filerecord, 'Test content');
+ $this->assertInstanceOf('stored_file', $directoryfile);
- // Recurse with dirs
- $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, true, 'id');
- //TODO: verify result!! MDL-33326
- // Recurse without dirs
- $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, false, 'id');
- //TODO: verify result!! MDL-33326
+ // Don't recurse without dirs
+ $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, false, 'id');
+ // 3 files only.
+ $this->assertCount(3, $files);
+ foreach ($files as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
+
+ // Don't recurse with dirs.
+ $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', false, true, 'id');
+ // 3 files + 1 directory.
+ $this->assertCount(4, $files);
+ foreach ($files as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
+
+ // Recurse with dirs.
+ $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, true, 'id');
+ // 3 files + 1 directory + 1 subdir file.
+ $this->assertCount(5, $files);
+ foreach ($files as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
+
+ // Recurse without dirs.
+ $files = $fs->get_directory_files($user->ctxid, 'user', 'private', 0, '/', true, false, 'id');
+ // 3 files + 1 subdir file.
+ $this->assertCount(4, $files);
+ foreach ($files as $key => $file) {
+ $this->assertInstanceOf('stored_file', $file);
+ $this->assertEquals($key, $file->get_pathnamehash());
+ }
}
public function test_search_references() {
$fs = get_file_storage();
$references = $fs->search_references('testsearch');
- //TODO: verify result!! MDL-33326
+ // TODO MDL-33368 Verify result!!
}
public function test_search_references_count() {
$fs = get_file_storage();
$references = $fs->search_references_count('testsearch');
- //TODO: verify result!! MDL-33326
+ // TODO MDL-33368 Verify result!!
}
public function test_delete_area_files() {
$this->assertEquals(0, count($areafiles));
}
+ public function test_delete_area_files_itemid() {
+ $user = $this->setup_three_private_files();
+ $fs = get_file_storage();
+
+ // Get area files with default options.
+ $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
+ // Should be the two files we added plus the folder.
+ $this->assertEquals(4, count($areafiles));
+ $fs->delete_area_files($user->ctxid, 'user', 'private', 9999);
+
+ $areafiles = $fs->get_area_files($user->ctxid, 'user', 'private');
+ $this->assertEquals(4, count($areafiles));
+ }
+
public function test_delete_area_files_select() {
$user = $this->setup_three_private_files();
$fs = get_file_storage();
// Should be the two files we added plus the folder.
$this->assertEquals(0, count($areafiles));
}
+
+ public function test_create_file_from_url() {
+ $this->resetAfterTest(true);
+
+ $syscontext = context_system::instance();
+ $filerecord = array(
+ 'contextid' => $syscontext->id,
+ 'component' => 'core',
+ 'filearea' => 'unittest',
+ 'itemid' => 0,
+ 'filepath' => '/downloadtest/',
+ );
+ $url = 'http://download.moodle.org/unittest/test.html';
+
+ $fs = get_file_storage();
+
+ // Test creating file without filename.
+ $file1 = $fs->create_file_from_url($filerecord, $url);
+ $this->assertInstanceOf('stored_file', $file1);
+
+ // Set filename.
+ $filerecord['filename'] = 'unit-test-filename.html';
+ $file2 = $fs->create_file_from_url($filerecord, $url);
+ $this->assertInstanceOf('stored_file', $file2);
+
+ // Use temporary file.
+ $filerecord['filename'] = 'unit-test-with-temp-file.html';
+ $file3 = $fs->create_file_from_url($filerecord, $url, null, true);
+ $file3 = $this->assertInstanceOf('stored_file', $file3);
+ }
+
+ public function test_cron() {
+ $this->resetAfterTest(true);
+
+ // Note: this is only testing DB compatibility atm, rather than
+ // that work is done.
+ $fs = get_file_storage();
+
+ $this->expectOutputRegex('/Cleaning up/');
+ $fs->cron();
+ }
+
+ public function test_is_area_empty() {
+ $user = $this->setup_three_private_files();
+ $fs = get_file_storage();
+
+ $this->assertFalse($fs->is_area_empty($user->ctxid, 'user', 'private'));
+
+ // File area with madeup itemid should be empty.
+ $this->assertTrue($fs->is_area_empty($user->ctxid, 'user', 'private', 9999));
+ // Still empty with dirs included.
+ $this->assertTrue($fs->is_area_empty($user->ctxid, 'user', 'private', 9999, false));
+ }
+
+ public function test_move_area_files_to_new_context() {
+ $this->resetAfterTest(true);
+
+ // Create a course with a page resource.
+ $course = $this->getDataGenerator()->create_course();
+ $page1 = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
+ $page1context = context_module::instance($page1->cmid);
+
+ // Add a file to the page.
+ $fs = get_file_storage();
+ $filerecord = array(
+ 'contextid' => $page1context->id,
+ 'component' => 'mod_page',
+ 'filearea' => 'content',
+ 'itemid' => 0,
+ 'filepath' => '/',
+ 'filename' => 'unit-test-file.txt',
+ );
+
+ $originalfile = $fs->create_file_from_string($filerecord, 'Test content');
+ $this->assertInstanceOf('stored_file', $originalfile);
+
+ $pagefiles = $fs->get_area_files($page1context->id, 'mod_page', 'content', 0, 'sortorder', false);
+ // Should be one file in filearea.
+ $this->assertFalse($fs->is_area_empty($page1context->id, 'mod_page', 'content'));
+
+ // Create a new page.
+ $page2 = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
+ $page2context = context_module::instance($page2->cmid);
+
+ // Newly created page area is empty.
+ $this->assertTrue($fs->is_area_empty($page2context->id, 'mod_page', 'content'));
+
+ // Move the files.
+ $fs->move_area_files_to_new_context($page1context->id, $page2context->id, 'mod_page', 'content');
+
+ // Page2 filearea should no longer be empty.
+ $this->assertFalse($fs->is_area_empty($page2context->id, 'mod_page', 'content'));
+
+ // Page1 filearea should now be empty.
+ $this->assertTrue($fs->is_area_empty($page1context->id, 'mod_page', 'content'));
+
+ $page2files = $fs->get_area_files($page2context->id, 'mod_page', 'content', 0, 'sortorder', false);
+ $movedfile = reset($page2files);
+
+ // The two files should have the same content hash.
+ $this->assertEquals($movedfile->get_contenthash(), $originalfile->get_contenthash());
+ }
+
+ public function test_convert_image() {
+ global $CFG;
+
+ $this->resetAfterTest(false);
+
+ $filepath = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+ $syscontext = context_system::instance();
+ $filerecord = array(
+ 'contextid' => $syscontext->id,
+ 'component' => 'core',
+ 'filearea' => 'unittest',
+ 'itemid' => 0,
+ 'filepath' => '/images/',
+ 'filename' => 'testimage.jpg',
+ );
+
+ $fs = get_file_storage();
+ $original = $fs->create_file_from_pathname($filerecord, $filepath);
+
+ $filerecord['filename'] = 'testimage-converted-10x10.jpg';
+ $converted = $fs->convert_image($filerecord, $original, 10, 10, true, 100);
+ $this->assertInstanceOf('stored_file', $converted);
+
+ $filerecord['filename'] = 'testimage-convereted-nosize.jpg';
+ $converted = $fs->convert_image($filerecord, $original);
+ $this->assertInstanceOf('stored_file', $converted);
+ }
+
+ private function generate_file_record() {
+ $syscontext = context_system::instance();
+ $filerecord = new stdClass();
+ $filerecord->contextid = $syscontext->id;
+ $filerecord->component = 'core';
+ $filerecord->filearea = 'phpunit';
+ $filerecord->filepath = '/';
+ $filerecord->filename = 'testfile.txt';
+ $filerecord->itemid = 0;
+
+ return $filerecord;
+ }
+
+ public function test_create_file_from_storedfile_file_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $this->setExpectedException('file_exception');
+ // Create a file from a file id which doesn't exist.
+ $fs->create_file_from_storedfile($filerecord, 9999);
+ }
+
+ public function test_create_file_from_storedfile_contextid_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->contextid = 'invalid';
+
+ $this->setExpectedException('file_exception', 'Invalid contextid');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_component_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->component = 'bad/component';
+
+ $this->setExpectedException('file_exception', 'Invalid component');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_filearea_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->filearea = 'bad-filearea';
+
+ $this->setExpectedException('file_exception', 'Invalid filearea');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_itemid_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->itemid = 'bad-itemid';
+
+ $this->setExpectedException('file_exception', 'Invalid itemid');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_filepath_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->filepath = 'a-/bad/-filepath';
+
+ $this->setExpectedException('file_exception', 'Invalid file path');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_filename_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = '';
+
+ $this->setExpectedException('file_exception', 'Invalid file name');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_timecreated_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->timecreated = 'today';
+
+ $this->setExpectedException('file_exception', 'Invalid file timecreated');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_timemodified_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'invalid.txt';
+ $filerecord->timemodified = 'today';
+
+ $this->setExpectedException('file_exception', 'Invalid file timemodified');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile_duplicate() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+
+ $fs = get_file_storage();
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ // Creating a file validating unique constraint.
+ $this->setExpectedException('stored_file_creation_exception');
+ $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ }
+
+ public function test_create_file_from_storedfile() {
+ $this->resetAfterTest(true);
+
+ $syscontext = context_system::instance();
+
+ $filerecord = new stdClass();
+ $filerecord->contextid = $syscontext->id;
+ $filerecord->component = 'core';
+ $filerecord->filearea = 'phpunit';
+ $filerecord->filepath = '/';
+ $filerecord->filename = 'testfile.txt';
+ $filerecord->itemid = 0;
+
+ $fs = get_file_storage();
+
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ $this->assertInstanceOf('stored_file', $file1);
+
+ $filerecord->filename = 'test-create-file-from-storedfile.txt';
+ $file2 = $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ $this->assertInstanceOf('stored_file', $file2);
+
+ // These will be normalised to current time..
+ $filerecord->timecreated = -100;
+ $filerecord->timemodified= -100;
+ $filerecord->filename = 'test-create-file-from-storedfile-bad-dates.txt';
+
+ $file3 = $fs->create_file_from_storedfile($filerecord, $file1->get_id());
+ $this->assertInstanceOf('stored_file', $file3);
+
+ $this->assertNotEquals($file3->get_timemodified(), $filerecord->timemodified);
+ $this->assertNotEquals($file3->get_timecreated(), $filerecord->timecreated);
+ }
+
+ public function test_create_file_from_string_contextid_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->contextid = 'invalid';
+
+ $this->setExpectedException('file_exception', 'Invalid contextid');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_component_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->component = 'bad/component';
+
+ $this->setExpectedException('file_exception', 'Invalid component');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_filearea_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->filearea = 'bad-filearea';
+
+ $this->setExpectedException('file_exception', 'Invalid filearea');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_itemid_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->itemid = 'bad-itemid';
+
+ $this->setExpectedException('file_exception', 'Invalid itemid');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_filepath_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->filepath = 'a-/bad/-filepath';
+
+ $this->setExpectedException('file_exception', 'Invalid file path');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_filename_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->filename = '';
+
+ $this->setExpectedException('file_exception', 'Invalid file name');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_timecreated_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->timecreated = 'today';
+
+ $this->setExpectedException('file_exception', 'Invalid file timecreated');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_timemodified_invalid() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->timemodified = 'today';
+
+ $this->setExpectedException('file_exception', 'Invalid file timemodified');
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_string_duplicate() {
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $file1 = $fs->create_file_from_string($filerecord, 'text contents');
+
+ // Creating a file validating unique constraint.
+ $this->setExpectedException('stored_file_creation_exception');
+ $file2 = $fs->create_file_from_string($filerecord, 'text contents');
+ }
+
+ public function test_create_file_from_pathname_contextid_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->contextid = 'invalid';
+
+ $this->setExpectedException('file_exception', 'Invalid contextid');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_component_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->component = 'bad/component';
+
+ $this->setExpectedException('file_exception', 'Invalid component');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_filearea_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->filearea = 'bad-filearea';
+
+ $this->setExpectedException('file_exception', 'Invalid filearea');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_itemid_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->itemid = 'bad-itemid';
+
+ $this->setExpectedException('file_exception', 'Invalid itemid');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_filepath_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->filepath = 'a-/bad/-filepath';
+
+ $this->setExpectedException('file_exception', 'Invalid file path');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_filename_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->filename = '';
+
+ $this->setExpectedException('file_exception', 'Invalid file name');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_timecreated_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->timecreated = 'today';
+
+ $this->setExpectedException('file_exception', 'Invalid file timecreated');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_timemodified_invalid() {
+ global $CFG;
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $this->resetAfterTest(true);
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $filerecord->timemodified = 'today';
+
+ $this->setExpectedException('file_exception', 'Invalid file timemodified');
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ }
+
+ public function test_create_file_from_pathname_duplicate_file() {
+ global $CFG;
+ $this->resetAfterTest(true);
+
+ $path = $CFG->dirroot.'/lib/filestorage/tests/fixtures/testimage.jpg';
+
+ $filerecord = $this->generate_file_record();
+ $fs = get_file_storage();
+
+ $file1 = $fs->create_file_from_pathname($filerecord, $path);
+ $this->assertInstanceOf('stored_file', $file1);
+
+ // Creating a file validating unique constraint.
+ $this->setExpectedException('stored_file_creation_exception');
+ $file2 = $fs->create_file_from_pathname($filerecord, $path);
+ }
}
this.maxfiles = options.maxfiles;
this.maxbytes = options.maxbytes;
this.itemid = options.itemid;
+ this.author = options.author;
this.container = this.Y.one('#'+options.containerid);
if (options.filemanager) {
formdata.append('sesskey', M.cfg.sesskey);
formdata.append('repo_id', this.repositoryid);
formdata.append('itemid', this.itemid);
+ if (this.author) {
+ formdata.append('author', this.author);
+ }
if (this.filemanager) { // Filepickers do not have folders
formdata.append('savepath', this.filemanager.currentpath);
}
this.pathbar.removeChild(this.pathnode);
}
// initialize 'select file' panel
- this.selectnode = Y.Node.create(M.form_filemanager.templates.fileselectlayout);
+ this.selectnode = Y.Node.createWithFilesSkin(M.form_filemanager.templates.fileselectlayout);
this.selectnode.generateID();
- Y.one(document.body).appendChild(this.selectnode);
this.selectui = new Y.Panel({
srcNode : this.selectnode,
zIndex : 600000,
header = M.str.moodle.info;
}
if (!this.msg_dlg) {
- var node = Y.Node.create(M.form_filemanager.templates.message);
- this.filemanager.appendChild(node);
+ this.msg_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.message);
+ var nodeid = this.msg_dlg_node.generateID();
this.msg_dlg = new Y.Panel({
- srcNode : node,
+ srcNode : this.msg_dlg_node,
zIndex : 800000,
centered : true,
modal : true,
visible : false,
render : true
});
- this.msg_dlg.plug(Y.Plugin.Drag,{handles:['.yui3-widget-hd']});
- node.one('.fp-msg-butok').on('click', function(e) {
+ this.msg_dlg.plug(Y.Plugin.Drag,{handles:['#'+nodeid+' .yui3-widget-hd']});
+ this.msg_dlg_node.one('.fp-msg-butok').on('click', function(e) {
e.preventDefault();
this.msg_dlg.hide();
}, this);
}
this.msg_dlg.set('headerContent', header);
- this.filemanager.one('.fp-msg').removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type)
- this.filemanager.one('.fp-msg .fp-msg-text').setContent(msg);
+ this.msg_dlg_node.removeClass('fp-msg-info').removeClass('fp-msg-error').addClass('fp-msg-'+type)
+ this.msg_dlg_node.one('.fp-msg-text').setContent(msg);
this.msg_dlg.show();
},
setup_buttons: function() {
});
}
if (!this.mkdir_dialog) {
- var node = Y.Node.create(M.form_filemanager.templates.mkdir);
- this.filemanager.appendChild(node);
+ var node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.mkdir);
this.mkdir_dialog = new Y.Panel({
srcNode : node,
zIndex : 800000,
show_confirm_dialog: function(dialog_options) {
// instead of M.util.show_confirm_dialog(e, dialog_options);
if (!this.confirm_dlg) {
- this.confirm_dlg_node = Y.Node.create(M.form_filemanager.templates.confirmdialog);
+ this.confirm_dlg_node = Y.Node.createWithFilesSkin(M.form_filemanager.templates.confirmdialog);
var node = this.confirm_dlg_node;
node.generateID();
- Y.one(document.body).appendChild(node);
this.confirm_dlg = new Y.Panel({
srcNode : node,
zIndex : 800000,
this.selectui.fileinfo = node;
selectnode.one('.fp-saveas input').set('value', node.fullname);
var foldername = this.get_parent_folder_name(node);
- selectnode.all('.fp-author input').set('value', node.author);
+ selectnode.all('.fp-author input').set('value', node.author ? node.author : '');
selectnode.all('.fp-license select option[selected]').set('selected', false);
selectnode.all('.fp-license select option[value='+node.license+']').set('selected', true);
selectnode.all('.fp-path select option[selected]').set('selected', false);
filemanager: manager,
acceptedtypes: options.accepted_types,
clientid: options.client_id,
+ author: options.author,
maxfiles: options.maxfiles,
maxbytes: options.maxbytes,
itemid: options.itemid,
var dndoptions = {
clientid: options.client_id,
acceptedtypes: options.accepted_types,
+ author: options.author,
maxfiles: -1,
maxbytes: options.maxbytes,
itemid: options.itemid,
$image->height = $imageinfo[1];
$image->type = $imageinfo[2];
+ $t = null;
switch ($image->type) {
case IMAGETYPE_GIF:
if (function_exists('imagecreatefromgif')) {
debugging('GIF not supported on this server');
return false;
}
+ // Guess transparent colour from GIF.
+ $transparent = imagecolortransparent($im);
+ if ($transparent != -1) {
+ $t = imagecolorsforindex($im, $transparent);
+ }
break;
case IMAGETYPE_JPEG:
if (function_exists('imagecreatefromjpeg')) {
if (function_exists('imagecreatetruecolor') and $CFG->gdversion >= 2) {
$im1 = imagecreatetruecolor(100, 100);
$im2 = imagecreatetruecolor(35, 35);
- if ($image->type == IMAGETYPE_PNG and $imagefnc === 'imagepng') {
+ $im3 = imagecreatetruecolor(512, 512);
+ if ($image->type != IMAGETYPE_JPEG and $imagefnc === 'imagepng') {
+ if ($t) {
+ // Transparent GIF hacking...
+ $transparentcolour = imagecolorallocate($im1 , $t['red'] , $t['green'] , $t['blue']);
+ imagecolortransparent($im1 , $transparentcolour);
+ $transparentcolour = imagecolorallocate($im2 , $t['red'] , $t['green'] , $t['blue']);
+ imagecolortransparent($im2 , $transparentcolour);
+ $transparentcolour = imagecolorallocate($im3 , $t['red'] , $t['green'] , $t['blue']);
+ imagecolortransparent($im3 , $transparentcolour);
+ }
+
imagealphablending($im1, false);
$color = imagecolorallocatealpha($im1, 0, 0, 0, 127);
imagefill($im1, 0, 0, $color);
imagesavealpha($im1, true);
+
imagealphablending($im2, false);
$color = imagecolorallocatealpha($im2, 0, 0, 0, 127);
imagefill($im2, 0, 0, $color);
imagesavealpha($im2, true);
+
+ imagealphablending($im3, false);
+ $color = imagecolorallocatealpha($im3, 0, 0, 0, 127);
+ imagefill($im3, 0, 0, $color);
+ imagesavealpha($im3, true);
}
} else {
$im1 = imagecreate(100, 100);
$im2 = imagecreate(35, 35);
+ $im3 = imagecreate(512, 512);
}
$cx = $image->width / 2;
imagecopybicubic($im1, $im, 0, 0, $cx - $half, $cy - $half, 100, 100, $half * 2, $half * 2);
imagecopybicubic($im2, $im, 0, 0, $cx - $half, $cy - $half, 35, 35, $half * 2, $half * 2);
+ imagecopybicubic($im3, $im, 0, 0, $cx - $half, $cy - $half, 512, 512, $half * 2, $half * 2);
$fs = get_file_storage();
$icon['filename'] = 'f2'.$imageext;
$fs->create_file_from_string($icon, $data);
+ ob_start();
+ if (!$imagefnc($im3, NULL, $quality, $filters)) {
+ ob_end_clean();
+ $fs->delete_area_files($context->id, $component, $filearea, $itemid);
+ return false;
+ }
+ $data = ob_get_clean();
+ imagedestroy($im3);
+ $icon['filename'] = 'f3'.$imageext;
+ $fs->create_file_from_string($icon, $data);
+
return $file1->get_id();
}
<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
+
/**
- * Moodle - Modular Object-Oriented Dynamic Learning Environment
- * http://moodle.org
- * Copyright (C) 1999 onwards Martin Dougiamas http://dougiamas.com
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ * Simple implementation of some Google API functions for Moodle.
*
- * @package core
- * @subpackage lib
+ * @package core
* @copyright Dan Poltawski <talktodan@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- *
- * Simple implementation of some Google API functions for Moodle.
*/
defined('MOODLE_INTERNAL') || die();
- /** Include essential file */
require_once($CFG->libdir.'/filelib.php');
+require_once($CFG->libdir.'/oauthlib.php');
/**
- * Base class for google authenticated http requests
- *
- * Most Google API Calls required that requests are sent with an
- * Authorization header + token. This class extends the curl class
- * to aid this
+ * Class for manipulating google documents through the google data api.
*
- * @package moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-abstract class google_auth_request extends curl {
- protected $token = '';
- private $persistantheaders = array();
-
- // Must be overridden with the authorization header name
- public static function get_auth_header_name() {
- throw new coding_exception('get_auth_header_name() method needs to be overridden in each subclass of google_auth_request');
- }
-
- protected function request($url, $options = array()){
- if($this->token){
- // Adds authorisation head to a request so that it can be authentcated
- $this->setHeader('Authorization: '. $this->get_auth_header_name().'"'.$this->token.'"');
- }
-
- foreach($this->persistantheaders as $h){
- $this->setHeader($h);
- }
-
- $ret = parent::request($url, $options);
- // reset headers for next request
- $this->header = array();
- return $ret;
- }
-
- protected function multi($requests, $options = array()) {
- if($this->token){
- // Adds authorisation head to a request so that it can be authentcated
- $this->setHeader('Authorization: '. $this->get_auth_header_name().'"'.$this->token.'"');
- }
-
- foreach($this->persistantheaders as $h){
- $this->setHeader($h);
- }
-
- $ret = parent::multi($requests, $options);
- // reset headers for next request
- $this->header = array();
- return $ret;
- }
-
- public function get_sessiontoken(){
- return $this->token;
- }
-
- public function add_persistant_header($header){
- $this->persistantheaders[] = $header;
- }
-}
-
-/*******
- * The following two classes are usd to implement AuthSub google
- * authtentication, as documented here:
- * http://code.google.com/apis/accounts/docs/AuthSub.html
- *******/
-
-/**
- * Used to uprade a google AuthSubRequest one-time token into
- * a session token which can be used long term.
- *
- * @package moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class google_authsub_request extends google_auth_request {
- const AUTHSESSION_URL = 'https://www.google.com/accounts/AuthSubSessionToken';
-
- /**
- * Constructor. Calls constructor of its parents
- *
- * @param string $authtoken The token to upgrade to a session token
- */
- public function __construct($authtoken){
- parent::__construct();
- $this->token = $authtoken;
- }
-
- /**
- * Requests a long-term session token from google based on the
- *
- * @return string Sub-Auth token
- */
- public function get_session_token(){
- $content = $this->get(google_authsub_request::AUTHSESSION_URL);
-
- if( preg_match('/token=(.*)/i', $content, $matches) ){
- return $matches[1];
- }else{
- throw new moodle_exception('could not upgrade google authtoken to session token');
- }
- }
-
- public static function get_auth_header_name(){
- return 'AuthSub token=';
- }
-}
-
-/**
- * Allows http calls using google subauth authorisation
- *
- * @package moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
- * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class google_authsub extends google_auth_request {
- const LOGINAUTH_URL = 'https://www.google.com/accounts/AuthSubRequest';
- const VERIFY_TOKEN_URL = 'https://www.google.com/accounts/AuthSubTokenInfo';
- const REVOKE_TOKEN_URL = 'https://www.google.com/accounts/AuthSubRevokeToken';
-
- /**
- * Constructor, allows subauth requests using the response from an initial
- * AuthSubRequest or with the subauth long-term token. Note that constructing
- * this object without a valid token will cause an exception to be thrown.
- *
- * @param string $sessiontoken A long-term subauth session token
- * @param string $authtoken A one-time auth token wich is used to upgrade to session token
- * @param mixed @options Options to pass to the base curl object
- */
- public function __construct($sessiontoken = '', $authtoken = '', $options = array()){
- parent::__construct($options);
-
- if( $authtoken ){
- $gauth = new google_authsub_request($authtoken);
- $sessiontoken = $gauth->get_session_token();
- }
-
- $this->token = $sessiontoken;
- if(! $this->valid_token() ){
- throw new moodle_exception('Invalid subauth token');
- }
- }
-
- /**
- * Tests if a subauth token used is valid
- *
- * @return boolean true if token valid
- */
- public function valid_token(){
- $this->get(google_authsub::VERIFY_TOKEN_URL);
-
- if($this->info['http_code'] === 200){
- return true;
- }else{
- return false;
- }
- }
-
- /**
- * Calls googles api to revoke the subauth token
- *
- * @return boolean Returns true if token succesfully revoked
- */
- public function revoke_session_token(){
- $this->get(google_authsub::REVOKE_TOKEN_URL);
-
- if($this->info['http_code'] === 200){
- $this->token = '';
- return true;
- }else{
- return false;
- }
- }
-
- /**
- * Creates a login url for subauth request
- *
- * @param string $returnaddr The address which the user should be redirected to recieve the token
- * @param string $realm The google realm which is access is being requested
- * @return string URL to bounce the user to
- */
- public static function login_url($returnaddr, $realm){
- $uri = google_authsub::LOGINAUTH_URL.'?next='
- .urlencode($returnaddr)
- .'&scope='
- .urlencode($realm)
- .'&session=1&secure=0';
-
- return $uri;
- }
-
- public static function get_auth_header_name(){
- return 'AuthSub token=';
- }
-}
-
-/**
- * Class for manipulating google documents through the google data api
* Docs for this can be found here:
* {@link http://code.google.com/apis/documents/docs/2.0/developers_guide_protocol.html}
*
- * @package moodlecore
+ * @package core
* @subpackage lib
* @copyright Dan Poltawski <talktodan@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class google_docs {
- // need both docs and the spreadsheets realm
+ /** @var string Realm for authentication, need both docs and spreadsheet realm */
const REALM = 'https://docs.google.com/feeds/ https://spreadsheets.google.com/feeds/ https://docs.googleusercontent.com/';
+ /** @var string Document list url */
const DOCUMENTFEED_URL = 'https://docs.google.com/feeds/default/private/full';
- const USER_PREF_NAME = 'google_authsub_sesskey';
+ /** @var string Upload url */
+ const UPLOAD_URL = 'https://docs.google.com/feeds/upload/create-session/default/private/full?convert=false';
- private $google_curl = null;
+ /** @var google_oauth oauth curl class for making authenticated requests */
+ private $googleoauth = null;
/**
* Constructor.
*
- * @param object A google_auth_request object which can be used to do http requests
+ * @param google_oauth $googleoauth oauth curl class for making authenticated requests
*/
- public function __construct($google_curl){
- if(is_a($google_curl, 'google_auth_request')){
- $this->google_curl = $google_curl;
- $this->google_curl->add_persistant_header('GData-Version: 3.0');
- }else{
- throw new moodle_exception('Google Curl Request object not given');
- }
- }
-
- public static function get_sesskey($userid){
- return get_user_preferences(google_docs::USER_PREF_NAME, false, $userid);
- }
-
- public static function set_sesskey($value, $userid){
- return set_user_preference(google_docs::USER_PREF_NAME, $value, $userid);
- }
-
- public static function delete_sesskey($userid){
- return unset_user_preference(google_docs::USER_PREF_NAME, $userid);
+ public function __construct(google_oauth $googleoauth) {
+ $this->googleoauth = $googleoauth;
+ $this->googleoauth->setHeader('GData-Version: 3.0');
}
/**
* @param string $search A search string to do full text search on the documents
* @return mixed Array of files formated for fileapoi
*/
- #FIXME
- public function get_file_list($search = ''){
+ public function get_file_list($search = '') {
global $CFG, $OUTPUT;
- $url = google_docs::DOCUMENTFEED_URL;
+ $url = self::DOCUMENTFEED_URL;
- if($search){
+ if ($search) {
$url.='?q='.urlencode($search);
}
- $content = $this->google_curl->get($url);
+ $content = $this->googleoauth->get($url);
$xml = new SimpleXMLElement($content);
-
$files = array();
- foreach($xml->entry as $gdoc){
+ foreach ($xml->entry as $gdoc) {
$docid = (string) $gdoc->children('http://schemas.google.com/g/2005')->resourceId;
list($type, $docid) = explode(':', $docid);
$title = (string)$gdoc->title;
$source = (string)$gdoc->content[0]->attributes()->src;
break;
+ case 'file':
+ $title = (string)$gdoc->title;
+ $source = (string)$gdoc->content[0]->attributes()->src;
+ break;
}
- if(!empty($source)){
+ if (!empty($source)) {
$files[] = array( 'title' => $title,
'url' => "{$gdoc->link[0]->attributes()->href}",
'source' => $source,
* @param object $file File object
* @return boolean True on success
*/
- public function send_file($file){
- $this->google_curl->setHeader("Content-Length: ". $file->get_filesize());
- $this->google_curl->setHeader("Content-Type: ". $file->get_mimetype());
- $this->google_curl->setHeader("Slug: ". $file->get_filename());
+ public function send_file($file) {
+ // First we create the 'resumable upload request'.
+ $this->googleoauth->setHeader("Content-Length: 0");
+ $this->googleoauth->setHeader("X-Upload-Content-Length: ". $file->get_filesize());
+ $this->googleoauth->setHeader("X-Upload-Content-Type: ". $file->get_mimetype());
+ $this->googleoauth->setHeader("Slug: ". $file->get_filename());
+ $this->googleoauth->post(self::UPLOAD_URL);
+
+ if ($this->googleoauth->info['http_code'] !== 200) {
+ throw new moodle_exception('Cantpostupload');
+ }
+
+ // Now we http PUT the file in the location returned.
+ $location = $this->googleoauth->response['Location'];
+ if (empty($location)) {
+ throw new moodle_exception('Nouploadlocation');
+ }
+
+ // Reset the curl object for actually sending the file.
+ $this->googleoauth->clear_headers();
+ $this->googleoauth->setHeader("Content-Length: ". $file->get_filesize());
+ $this->googleoauth->setHeader("Content-Type: ". $file->get_mimetype());
+
+ // We can't get a filepointer, so have to copy the file..
+ $tmproot = make_temp_directory('googledocsuploads');
+ $tmpfilepath = $tmproot.'/'.$file->get_contenthash();
+ $file->copy_content_to($tmpfilepath);
- $this->google_curl->post(google_docs::DOCUMENTFEED_URL, $file->get_content());
+ // HTTP PUT the file.
+ $this->googleoauth->put($location, array('file'=>$tmpfilepath));
- if($this->google_curl->info['http_code'] === 201){
+ // Remove the temporary file we created..
+ unlink($tmpfilepath);
+
+ if ($this->googleoauth->info['http_code'] === 201) {
return true;
- }else{
+ } else {
return false;
}
}
- public function download_file($url, $fp){
- return $this->google_curl->download(array( array('url'=>$url, 'file' => $fp) ));
+ /**
+ * Downloads a file using authentication
+ *
+ * @param string $url url of file
+ * @param string $path path to save file to
+ * @return array stucture for repository download_file
+ */
+ public function download_file($url, $path) {
+ $content = $this->googleoauth->get($url);
+ file_put_contents($path, $content);
+ return array('path'=>$path, 'url'=>$url);
}
}
/**
- * Class for manipulating picasa through the google data api
+ * Class for manipulating picasa through the google data api.
+ *
* Docs for this can be found here:
* {@link http://code.google.com/apis/picasaweb/developers_guide_protocol.html}
*
- * @package moodlecore
- * @subpackage lib
+ * @package core
* @copyright Dan Poltawski <talktodan@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class google_picasa {
+ /** @var string Realm for authentication */
const REALM = 'http://picasaweb.google.com/data/';
- const USER_PREF_NAME = 'google_authsub_sesskey_picasa';
+ /** @var string Upload url */
const UPLOAD_LOCATION = 'https://picasaweb.google.com/data/feed/api/user/default/albumid/default';
+ /** @var string photo list url */
const ALBUM_PHOTO_LIST = 'https://picasaweb.google.com/data/feed/api/user/default/albumid/';
+ /** @var string search url */
const PHOTO_SEARCH_URL = 'https://picasaweb.google.com/data/feed/api/user/default?kind=photo&q=';
+ /** @var string album list url */
const LIST_ALBUMS_URL = 'https://picasaweb.google.com/data/feed/api/user/default';
+ /** @var string manage files url */
const MANAGE_URL = 'http://picasaweb.google.com/';
- private $google_curl = null;
+ /** @var google_oauth oauth curl class for making authenticated requests */
+ private $googleoauth = null;
+ /** @var string Last album name retrievied */
private $lastalbumname = null;
/**
* Constructor.
*
- * @param object A google_auth_request object which can be used to do http requests
+ * @param google_oauth $googleoauth oauth curl class for making authenticated requests
*/
- public function __construct($google_curl){
- if(is_a($google_curl, 'google_auth_request')){
- $this->google_curl = $google_curl;
- $this->google_curl->add_persistant_header('GData-Version: 2');
- }else{
- throw new moodle_exception('Google Curl Request object not given');
- }
- }
-
- public static function get_sesskey($userid){
- return get_user_preferences(google_picasa::USER_PREF_NAME, false, $userid);
- }
-
- public static function set_sesskey($value, $userid){
- return set_user_preference(google_picasa::USER_PREF_NAME, $value, $userid);
- }
-
- public static function delete_sesskey($userid){
- return unset_user_preference(google_picasa::USER_PREF_NAME, $userid);
+ public function __construct(google_oauth $googleoauth) {
+ $this->googleoauth = $googleoauth;
+ $this->googleoauth->setHeader('GData-Version: 2');
}
/**
* @param object $file File object
* @return boolean True on success
*/
- public function send_file($file){
- $this->google_curl->setHeader("Content-Length: ". $file->get_filesize());
- $this->google_curl->setHeader("Content-Type: ". $file->get_mimetype());
- $this->google_curl->setHeader("Slug: ". $file->get_filename());
+ public function send_file($file) {
+ $this->googleoauth->setHeader("Content-Length: ". $file->get_filesize());
+ $this->googleoauth->setHeader("Content-Type: ". $file->get_mimetype());
+ $this->googleoauth->setHeader("Slug: ". $file->get_filename());
- $this->google_curl->post(google_picasa::UPLOAD_LOCATION, $file->get_content());
+ $this->googleoauth->post(self::UPLOAD_LOCATION, $file->get_content());
- if($this->google_curl->info['http_code'] === 201){
+ if ($this->googleoauth->info['http_code'] === 201) {
return true;
- }else{
+ } else {
return false;
}
}
* @param string $path The path to files (assumed to be albumid)
* @return mixed $files A list of files for the file picker
*/
- public function get_file_list($path = ''){
- if(!$path){
+ public function get_file_list($path = '') {
+ if (!$path) {
return $this->get_albums();
- }else{
+ } else {
return $this->get_album_photos($path);
}
}
* @param int $albumid Photo album to list photos from
* @return mixed $files A list of files for the file picker
*/
- public function get_album_photos($albumid){
- $albumcontent = $this->google_curl->get(google_picasa::ALBUM_PHOTO_LIST.$albumid);
+ public function get_album_photos($albumid) {
+ $albumcontent = $this->googleoauth->get(self::ALBUM_PHOTO_LIST.$albumid);
return $this->get_photo_details($albumcontent);
}
* @param string $query Search terms
* @return mixed $files A list of files for the file picker
*/
- public function do_photo_search($query){
- $content = $this->google_curl->get(google_picasa::PHOTO_SEARCH_URL.htmlentities($query));
+ public function do_photo_search($query) {
+ $content = $this->googleoauth->get(self::PHOTO_SEARCH_URL.htmlentities($query));
return $this->get_photo_details($content);
}
*
* @return mixes $files Array in the format get_listing uses for folders
*/
- public function get_albums(){
- $content = $this->google_curl->get(google_picasa::LIST_ALBUMS_URL);
+ public function get_albums() {
+ $content = $this->googleoauth->get(self::LIST_ALBUMS_URL);
$xml = new SimpleXMLElement($content);
$files = array();
- foreach($xml->entry as $album){
+ foreach ($xml->entry as $album) {
$gphoto = $album->children('http://schemas.google.com/photos/2007');
$mediainfo = $album->children('http://search.yahoo.com/mrss/');
- //hacky...
+ // Hacky...
$thumbnailinfo = $mediainfo->group->thumbnail[0]->attributes();
$files[] = array( 'title' => (string) $album->title,
'size' => (int) $gphoto->bytesUsed,
'path' => (string) $gphoto->id,
'thumbnail' => (string) $thumbnailinfo['url'],
- 'thumbnail_width' => 160, // 160 is the native maximum dimension
+ 'thumbnail_width' => 160, // 160 is the native maximum dimension.
'thumbnail_height' => 160,
'children' => array(),
);
* @param string $rawxml XML from picasa api
* @return mixed $files A list of files for the file picker
*/
- public function get_photo_details($rawxml){
+ public function get_photo_details($rawxml) {
$xml = new SimpleXMLElement($rawxml);
$this->lastalbumname = (string)$xml->title;
$files = array();
- foreach($xml->entry as $photo){
+ foreach ($xml->entry as $photo) {
$gphoto = $photo->children('http://schemas.google.com/photos/2007');
$mediainfo = $photo->children('http://search.yahoo.com/mrss/');
$fullinfo = $mediainfo->group->content->attributes();
- //hacky...
+ // Hacky...
$thumbnailinfo = $mediainfo->group->thumbnail[0]->attributes();
- // Derive the nicest file name we can
+ // Derive the nicest file name we can.
if (!empty($mediainfo->group->description)) {
$title = shorten_text((string)$mediainfo->group->description, 20, false, '');
$title = clean_filename($title).'.jpg';
'size' => (int) $gphoto->size,
'path' => $gphoto->albumid.'/'.$gphoto->id,
'thumbnail' => (string) $thumbnailinfo['url'],
- 'thumbnail_width' => 72, // 72 is the native maximum dimension
+ 'thumbnail_width' => 72, // 72 is the native maximum dimension.
'thumbnail_height' => 72,
'source' => (string) $fullinfo['url'],
'url' => (string) $fullinfo['url']
return $files;
}
-
}
/**
- * Beginings of an implementation of Clientogin authenticaton for google
- * accounts as documented here:
- * {@link http://code.google.com/apis/accounts/docs/AuthForInstalledApps.html#ClientLogin}
+ * OAuth 2.0 client for Google Services
*
- * With this authentication we have to accept a username and password and to post
- * it to google. Retrieving a token for use afterwards.
- *
- * @package moodlecore
- * @subpackage lib
- * @copyright Dan Poltawski <talktodan@gmail.com>
+ * @package core
+ * @copyright 2012 Dan Poltawski
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
-class google_authclient extends google_auth_request {
- const LOGIN_URL = 'https://www.google.com/accounts/ClientLogin';
-
- public function __construct($sessiontoken = '', $username = '', $password = '', $options = array() ){
- parent::__construct($options);
-
- if($username and $password){
- $param = array(
- 'accountType'=>'GOOGLE',
- 'Email'=>$username,
- 'Passwd'=>$password,
- 'service'=>'writely'
- );
-
- $content = $this->post(google_authclient::LOGIN_URL, $param);
-
- if( preg_match('/auth=(.*)/i', $content, $matches) ){
- $sessiontoken = $matches[1];
- }else{
- throw new moodle_exception('could not upgrade authtoken');
- }
-
- }
+class google_oauth extends oauth2_client {
+ /**
+ * Returns the auth url for OAuth 2.0 request
+ * @return string the auth url
+ */
+ protected function auth_url() {
+ return 'https://accounts.google.com/o/oauth2/auth';
+ }
- if($sessiontoken){
- $this->token = $sessiontoken;
- }else{
- throw new moodle_exception('no session token specified');
- }
+ /**
+ * Returns the token url for OAuth 2.0 request
+ * @return string the auth url
+ */
+ protected function token_url() {
+ return 'https://accounts.google.com/o/oauth2/token';
}
- public static function get_auth_header_name(){
- return 'GoogleLogin auth=';
+ /**
+ * Clear any headers in the curl object
+ */
+ public function clear_headers() {
+ $this->header = array();
}
}
set_config('release', $release);
set_config('branch', $branch);
+ if (PHPUNIT_TEST) {
+ // mark as test database as soon as possible
+ set_config('phpunittest', 'na');
+ }
+
// install all plugins types, local, etc.
upgrade_noncore(true);