Merge branch 'MDL-33487' of git://github.com/danpoltawski/moodle
authorSam Hemelryk <sam@moodle.com>
Tue, 5 Jun 2012 22:06:17 +0000 (10:06 +1200)
committerSam Hemelryk <sam@moodle.com>
Tue, 5 Jun 2012 22:06:17 +0000 (10:06 +1200)
91 files changed:
admin/index.php
admin/oauth2callback.php
admin/registration/confirmregistration.php
admin/registration/forms.php
admin/registration/hubselector.php [deleted file]
admin/registration/index.php
admin/registration/register.php
admin/registration/renderer.php
admin/registration/renewregistration.php
admin/renderer.php
admin/settings/server.php
admin/settings/top.php
backup/bb/restore_bb.php
backup/moodle2/restore_stepslib.php
backup/util/helper/backup_general_helper.class.php
course/dndupload.js
course/dnduploadlib.php
course/externallib.php
course/view.php
enrol/externallib.php
files/renderer.php
grade/edit/tree/grade.php
grade/import/csv/index.php
group/externallib.php
install.php
lang/en/admin.php
lang/en/hub.php
lang/en/repository.php
lang/en/webservice.php
lib/completionlib.php
lib/configonlylib.php
lib/cronlib.php
lib/db/access.php
lib/evalmath/evalmath.class.php
lib/externallib.php
lib/filebrowser/file_info.php
lib/filebrowser/file_info_stored.php
lib/filelib.php
lib/filestorage/stored_file.php
lib/form/filemanager.js
lib/messagelib.php
lib/moodlelib.php
lib/oauthlib.php
lib/phpunit/lib.php
lib/rsslib.php
lib/tablelib.php
lib/tests/configonlylib_test.php [new file with mode: 0644]
lib/tests/mathslib_test.php
lib/tests/moodlelib_test.php
lib/webdavlib.php
message/defaultoutputs.php
message/externallib.php
message/lib.php
mod/assign/feedback/comments/locallib.php
mod/assign/feedbackplugin.php
mod/assign/gradingtable.php
mod/assign/locallib.php
mod/book/tool/print/index.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/unsubscribeall.php
mod/quiz/report/grading/report.php
notes/externallib.php
phpunit.xml.dist
portfolio/googledocs/lib.php
portfolio/picasa/lib.php
rating/index.php
repository/dropbox/lang/en/repository_dropbox.php
repository/filepicker.js
repository/googledocs/lib.php
repository/lib.php
repository/picasa/lib.php
repository/recent/lib.php
repository/repository_ajax.php
repository/upload/lib.php
theme/base/style/course.css
theme/base/style/filemanager.css
theme/formal_white/db/upgrade.php
theme/formal_white/lang/en/theme_formal_white.php
theme/formal_white/layout/frontpage.php
theme/formal_white/layout/general.php
theme/formal_white/layout/report.php
theme/formal_white/settings.php
theme/formal_white/style/formal_white.css
theme/formal_white/version.php
user/externallib.php
user/lib.php
version.php
webservice/lib.php
webservice/rest/locallib.php
webservice/rest/server.php

index bf3eea5..d4a7d4e 100644 (file)
@@ -44,11 +44,6 @@ if (!function_exists('iconv')) {
     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);
 
@@ -434,6 +429,10 @@ $availableupdates = $updateschecker->get_update_info('core',
     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) {
@@ -444,4 +443,5 @@ 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);
index 364c002..c032a9c 100644 (file)
@@ -33,6 +33,14 @@ require_once(dirname(dirname(__FILE__)).'/config.php');
 // The authorization code generated by the authorization server.
 $code = required_param('code', PARAM_RAW);
 // The state parameter we've given (used in moodle as a redirect url).
-$state = required_param('state', PARAM_URL);
+$state = required_param('state', PARAM_LOCALURL);
 
-redirect(new moodle_url($state, array('code' => $code)));
+$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');
+}
index 12afb50..e7c8288 100644 (file)
@@ -44,7 +44,7 @@ $hubname = optional_param('hubname', '', PARAM_TEXT);
 $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',
index 48c2cd9..0126722 100644 (file)
@@ -236,6 +236,7 @@ class site_registration_form extends moodleform {
         $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);
@@ -279,9 +280,6 @@ class site_registration_form extends moodleform {
         $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'),
@@ -290,16 +288,6 @@ class site_registration_form extends moodleform {
         $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);
@@ -360,6 +348,20 @@ class site_registration_form extends moodleform {
         //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));
diff --git a/admin/registration/hubselector.php b/admin/registration/hubselector.php
deleted file mode 100644 (file)
index 6bb215f..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-<?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
index 02e5cde..4c841ae 100644 (file)
@@ -22,8 +22,9 @@
  * @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');
@@ -34,7 +35,7 @@ require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.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');
 
@@ -126,13 +127,15 @@ if (empty($cancel) and $unregistration and $confirm and confirm_sesskey()) {
     }
 }
 
-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) {
@@ -142,6 +145,7 @@ if (empty($cancel) and $unregistration and !$confirm) {
         $siteunregistrationform = new site_unregistration_form('',
                         array('huburl' => $huburl, 'hubname' => $hub->hubname));
     }
+
     $siteunregistrationform->display();
 } else {
     $registeredonmoodleorg = false;
@@ -150,8 +154,49 @@ if (empty($cancel) and $unregistration and !$confirm) {
         $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();
index eac6400..7a6bc92 100644 (file)
@@ -27,7 +27,7 @@
  * @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.
  */
@@ -39,15 +39,17 @@ require_once($CFG->dirroot . '/' . $CFG->admin . '/registration/forms.php');
 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();
 
@@ -145,5 +147,12 @@ if (!empty($error)) {
     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();
index fdec5fd..d5ca165 100644 (file)
  */
 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
@@ -42,57 +59,6 @@ class core_register_renderer extends plugin_renderer_base {
         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
      */
index ec9fce2..dd15463 100644 (file)
@@ -39,7 +39,7 @@ $url = optional_param('url', '', PARAM_URL);
 $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();
index 9b689a6..c064ca6 100644 (file)
@@ -242,13 +242,15 @@ class core_admin_renderer extends plugin_renderer_base {
      * @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 = '';
 
@@ -257,9 +259,11 @@ class core_admin_renderer extends plugin_renderer_base {
         $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 ///
@@ -381,6 +385,19 @@ class core_admin_renderer extends plugin_renderer_base {
         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
@@ -512,6 +529,27 @@ class core_admin_renderer extends plugin_renderer_base {
         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')
+                    . '&nbsp;' . $this->help_icon('registration', 'admin') . $registerbutton );
+        }
+
+        return '';
+    }
+
     /**
      * Helper method to render the information about the available Moodle update
      *
index 0188b6d..461f06c 100644 (file)
@@ -219,7 +219,8 @@ $temp->add(new admin_setting_configselect('memcachedpconn', new lang_string('mem
 $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)) {
index 4c1295e..147a4e5 100644 (file)
@@ -10,12 +10,12 @@ $hassiteconfig = has_capability('moodle/site:config', $systemcontext);
 
 $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));
index 3e01adf..962c46b 100644 (file)
@@ -8,7 +8,9 @@ defined('MOODLE_INTERNAL') or die('Direct access to this script is forbidden.');
 require_once($CFG->dirroot.'/backup/bb/xsl_emulate_xslt.inc');
 
 function get_subdirs($directory){
-    $opendirectory = opendir( $directory );
+    if (!$opendirectory = opendir( $directory )) {
+        return array();
+    }
     while(false !== ($filename = readdir($opendirectory))) {
         if (is_dir($directory.$filename) and $filename != ".." and $filename != "."){
             $subdirs[] = $filename;
index d87cdb9..e6fc1d1 100644 (file)
@@ -212,15 +212,18 @@ class restore_gradebook_structure_step extends restore_structure_step {
         $data->itemid = $this->get_new_parentid('grade_item');
 
         $data->userid = $this->get_mappingid('user', $data->userid, NULL);
-        $data->usermodified = $this->get_mappingid('user', $data->usermodified, NULL);
-        $data->locktime     = $this->apply_date_offset($data->locktime);
-        // TODO: Ask, all the rest of locktime/exported... work with time... to be rolled?
-        $data->overridden = $this->apply_date_offset($data->overridden);
-        $data->timecreated  = $this->apply_date_offset($data->timecreated);
-        $data->timemodified = $this->apply_date_offset($data->timemodified);
-
-        $newitemid = $DB->insert_record('grade_grades', $data);
-        //$this->set_mapping('grade_grade', $oldid, $newitemid);
+        if (!is_null($data->userid)) {
+            $data->usermodified = $this->get_mappingid('user', $data->usermodified, NULL);
+            $data->locktime     = $this->apply_date_offset($data->locktime);
+            // TODO: Ask, all the rest of locktime/exported... work with time... to be rolled?
+            $data->overridden = $this->apply_date_offset($data->overridden);
+            $data->timecreated  = $this->apply_date_offset($data->timecreated);
+            $data->timemodified = $this->apply_date_offset($data->timemodified);
+
+            $newitemid = $DB->insert_record('grade_grades', $data);
+        } else {
+            debugging("Mapped user id not found for grade item id '{$data->itemid}'");
+        }
     }
     protected function process_grade_category($data) {
         global $DB;
@@ -1105,7 +1108,7 @@ class restore_section_structure_step extends restore_structure_step {
 
         // 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);
+        $this->set_mapping('course_sectionnumber', $oldsection, $section->section);
 
         // set the new course_section id in the task
         $this->task->set_sectionid($newitemid);
@@ -1126,10 +1129,19 @@ class restore_section_structure_step extends restore_structure_step {
     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() {
@@ -1142,16 +1154,20 @@ class restore_section_structure_step extends restore_structure_step {
 
         $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;
@@ -2571,7 +2587,7 @@ class restore_module_structure_step extends restore_structure_step {
                 'course' => $this->get_courseid(),
                 'section' => 1);
             $data->section = $DB->insert_record('course_sections', $sectionrec); // section 1
-            $this->set_mapping('course_sectionnumber', $oldsection, $sectionrec->section, $restorefiles);
+            $this->set_mapping('course_sectionnumber', $oldsection, 1); // Assign unmatching sections to section 1.
         }
         $data->groupingid= $this->get_mappingid('grouping', $data->groupingid);      // grouping
         if (!$CFG->enablegroupmembersonly) {                                         // observe groupsmemberonly
index ff5dc89..df3c8d9 100644 (file)
@@ -79,7 +79,9 @@ abstract class backup_general_helper extends backup_helper {
             return array();
         }
 
-        $dir = opendir($path);
+        if (!$dir = opendir($path)) {
+            return array();
+        }
         while (false !== ($file = readdir($dir))) {
             if ($file == '.' || $file == '..') { // Skip dots
                 continue;
index 9b7c4e4..4651120 100644 (file)
@@ -53,7 +53,7 @@ M.course_dndupload = {
     // The classes that an element must have to be identified as a course section
     sectionclasses: ['section', 'main'],
     // The ID of the main content area of the page (for adding the 'status' div)
-    pagecontentid: 'page-content',
+    pagecontentid: 'page',
     // The selector identifying the list of modules within a section (note changing this may require
     // changes to the get_mods_element function)
     modslistselector: 'ul.section',
@@ -92,7 +92,9 @@ M.course_dndupload = {
             this.init_events(el);
         }, this);
 
-        this.add_status_div();
+        if (options.showstatus) {
+            this.add_status_div();
+        }
     },
 
     /**
@@ -100,14 +102,18 @@ M.course_dndupload = {
      * is available (or to explain why it is not available)
      */
     add_status_div: function() {
-        var div = document.createElement('div');
-        div.id = 'dndupload-status';
         var coursecontents = document.getElementById(this.pagecontentid);
-        if (coursecontents) {
-            coursecontents.insertBefore(div, coursecontents.firstChild);
+        if (!coursecontents) {
+            return;
         }
-        div = this.Y.one(div);
 
+        var div = document.createElement('div');
+        div.id = 'dndupload-status';
+        div.style.opacity = 0.0;
+        coursecontents.insertBefore(div, coursecontents.firstChild);
+
+        var Y = this.Y;
+        div = Y.one(div);
         var handlefile = (this.handlers.filehandlers.length > 0);
         var handletext = false;
         var handlelink = false;
@@ -134,6 +140,25 @@ M.course_dndupload = {
             $msgident += 'link';
         }
         div.setContent(M.util.get_string($msgident, 'moodle'));
+
+        var fadeanim = new Y.Anim({
+            node: '#dndupload-status',
+            from: {
+                opacity: 0.0,
+                top: '-30px'
+            },
+
+            to: {
+                opacity: 1.0,
+                top: '0px'
+            },
+            duration: 0.5
+        });
+        fadeanim.once('end', function(e) {
+            this.set('reverse', 1);
+            Y.later(3000, this, 'run', null, false);
+        });
+        fadeanim.run();
     },
 
     /**
index c0ed633..1b07746 100644 (file)
@@ -39,6 +39,8 @@ require_once($CFG->dirroot.'/course/lib.php');
 function dndupload_add_to_course($course, $modnames) {
     global $CFG, $PAGE;
 
+    $showstatus = optional_param('editingenabled', false, PARAM_BOOL);
+
     // Get all handlers.
     $handler = new dndupload_handler($course, $modnames);
     $jsdata = $handler->get_js_data();
@@ -65,12 +67,13 @@ function dndupload_add_to_course($course, $modnames) {
             array('upload', 'moodle'),
             array('cancel', 'moodle')
         ),
-        'requires' => array('node', 'event', 'panel', 'json')
+        'requires' => array('node', 'event', 'panel', 'json', 'anim')
     );
     $vars = array(
         array('courseid' => $course->id,
               'maxbytes' => get_max_upload_file_size($CFG->maxbytes, $course->maxbytes),
-              'handlers' => $handler->get_js_data())
+              'handlers' => $handler->get_js_data(),
+              'showstatus' => $showstatus)
     );
 
     $PAGE->requires->js_init_call('M.course_dndupload.init', $vars, true, $jsmodule);
index d02506f..1dfc4c6 100644 (file)
@@ -119,9 +119,10 @@ class core_course_external extends external_api {
                 $sectionvalues = array();
                 $sectionvalues['id'] = $section->id;
                 $sectionvalues['name'] = get_section_name($course, $section);
-                $summary = file_rewrite_pluginfile_urls($section->summary, 'webservice/pluginfile.php', $context->id, 'course', 'section', $section->id);
                 $sectionvalues['visible'] = $section->visible;
-                $sectionvalues['summary'] = format_text($summary, $section->summaryformat);
+                list($sectionvalues['summary'], $sectionvalues['summaryformat']) =
+                        external_format_text($section->summary, $section->summaryformat,
+                                $context->id, 'course', 'section', $section->id);
                 $sectioncontents = array();
 
                 //for each module of the section
@@ -205,6 +206,7 @@ class core_course_external extends external_api {
                     'name' => new external_value(PARAM_TEXT, 'Section name'),
                     'visible' => new external_value(PARAM_INT, 'is the section visible', VALUE_OPTIONAL),
                     'summary' => new external_value(PARAM_RAW, 'Section description'),
+                    'summaryformat' => new external_format_value('summary'),
                     'modules' => new external_multiple_structure(
                             new external_single_structure(
                                 array(
@@ -311,8 +313,8 @@ class core_course_external extends external_api {
             $courseinfo['fullname'] = $course->fullname;
             $courseinfo['shortname'] = $course->shortname;
             $courseinfo['categoryid'] = $course->category;
-            $courseinfo['summary'] = $course->summary;
-            $courseinfo['summaryformat'] = $course->summaryformat;
+            list($courseinfo['summary'], $courseinfo['summaryformat']) =
+                external_format_text($course->summary, $course->summaryformat, $context->id, 'course', 'summary', 0);
             $courseinfo['format'] = $course->format;
             $courseinfo['startdate'] = $course->startdate;
             $courseinfo['numsections'] = $course->numsections;
@@ -367,8 +369,7 @@ class core_course_external extends external_api {
                             'fullname' => new external_value(PARAM_TEXT, 'full name'),
                             'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
                             'summary' => new external_value(PARAM_RAW, 'summary'),
-                            'summaryformat' => new external_value(PARAM_INT,
-                                    'the summary text Moodle format'),
+                            'summaryformat' => new external_format_value('summary'),
                             'format' => new external_value(PARAM_PLUGIN,
                                     'course format: weeks, topics, social, site,..'),
                             'showgrades' => new external_value(PARAM_INT,
@@ -435,8 +436,7 @@ class core_course_external extends external_api {
                             'categoryid' => new external_value(PARAM_INT, 'category id'),
                             'idnumber' => new external_value(PARAM_RAW, 'id number', VALUE_OPTIONAL),
                             'summary' => new external_value(PARAM_RAW, 'summary', VALUE_OPTIONAL),
-                            'summaryformat' => new external_value(PARAM_INT,
-                                    'the summary text Moodle format', VALUE_DEFAULT, FORMAT_MOODLE),
+                            'summaryformat' => new external_format_value('summary', VALUE_DEFAULT),
                             'format' => new external_value(PARAM_PLUGIN,
                                     'course format: weeks, topics, social, site,..',
                                     VALUE_DEFAULT, $courseconfig->format),
@@ -560,6 +560,9 @@ class core_course_external extends external_api {
 
             $course['category'] = $course['categoryid'];
 
+            // Summary format.
+            $course['summaryformat'] = external_validate_format($course['summaryformat']);
+
             //Note: create_course() core function check shortname, idnumber, category
             $course['id'] = create_course((object) $course)->id;
 
@@ -1085,13 +1088,9 @@ class core_course_external extends external_api {
                     $categoryinfo = array();
                     $categoryinfo['id'] = $category->id;
                     $categoryinfo['name'] = $category->name;
-                    $categoryinfo['description'] = file_rewrite_pluginfile_urls($category->description,
-                            'webservice/pluginfile.php', $context->id, 'coursecat', 'description', null);
-                    $options = new stdClass;
-                    $options->noclean = true;
-                    $options->para = false;
-                    $categoryinfo['description'] = format_text($categoryinfo['description'],
-                            $category->descriptionformat, $options);
+                    list($categoryinfo['description'], $categoryinfo['descriptionformat']) =
+                        external_format_text($category->description, $category->descriptionformat,
+                                $context->id, 'coursecat', 'description', null);
                     $categoryinfo['parent'] = $category->parent;
                     $categoryinfo['sortorder'] = $category->sortorder;
                     $categoryinfo['coursecount'] = $category->coursecount;
@@ -1160,6 +1159,7 @@ class core_course_external extends external_api {
                     'name' => new external_value(PARAM_TEXT, 'category name'),
                     'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
                     'description' => new external_value(PARAM_RAW, 'category description'),
+                    'descriptionformat' => new external_format_value('description'),
                     'parent' => new external_value(PARAM_INT, 'parent category id'),
                     'sortorder' => new external_value(PARAM_INT, 'category sorting order'),
                     'coursecount' => new external_value(PARAM_INT, 'number of courses in this category'),
@@ -1193,6 +1193,7 @@ class core_course_external extends external_api {
                                         'the new category idnumber', VALUE_OPTIONAL),
                                 'description' => new external_value(PARAM_RAW,
                                         'the new category description', VALUE_OPTIONAL),
+                                'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
                                 'theme' => new external_value(PARAM_THEME,
                                         'the new category theme. This option must be enabled on moodle',
                                         VALUE_OPTIONAL),
@@ -1257,7 +1258,7 @@ class core_course_external extends external_api {
             if (!empty($category['description'])) {
                 $newcategory->description = $category['description'];
             }
-            $newcategory->descriptionformat = FORMAT_HTML;
+            $newcategory->descriptionformat = external_validate_format($category['descriptionformat']);
             if (isset($category['theme']) and !empty($CFG->allowcategorythemes)) {
                 $newcategory->theme = $category['theme'];
             }
@@ -1308,6 +1309,7 @@ class core_course_external extends external_api {
                             'idnumber' => new external_value(PARAM_RAW, 'category id number', VALUE_OPTIONAL),
                             'parent' => new external_value(PARAM_INT, 'parent category id', VALUE_OPTIONAL),
                             'description' => new external_value(PARAM_RAW, 'category description', VALUE_OPTIONAL),
+                            'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
                             'theme' => new external_value(PARAM_THEME,
                                     'the category theme. This option must be enabled on moodle', VALUE_OPTIONAL),
                         )
@@ -1356,7 +1358,7 @@ class core_course_external extends external_api {
             }
             if (!empty($cat['description'])) {
                 $category->description = $cat['description'];
-                $category->descriptionformat = FORMAT_HTML;
+                $category->descriptionformat = external_validate_format($cat['descriptionformat']);
             }
             if (!empty($cat['theme'])) {
                 $category->theme = $cat['theme'];
index de37981..2d4d347 100644 (file)
@@ -14,6 +14,7 @@
     $hide        = optional_param('hide', 0, PARAM_INT);
     $show        = optional_param('show', 0, PARAM_INT);
     $idnumber    = optional_param('idnumber', '', PARAM_RAW);
+    $sectionid   = optional_param('sectionid', 0, PARAM_INT);
     $section     = optional_param('section', 0, PARAM_INT);
     $move        = optional_param('move', 0, PARAM_INT);
     $marker      = optional_param('marker',-1 , PARAM_INT);
     $course = $DB->get_record('course', $params, '*', MUST_EXIST);
 
     $urlparams = array('id' => $course->id);
+
+    // Sectionid should get priority over section number
+    if ($sectionid) {
+        $section = $DB->get_field('course_sections', 'section', array('id' => $sectionid, 'course' => $course->id), MUST_EXIST);
+    }
     if ($section) {
         $urlparams['section'] = $section;
     }
             if ($course->id == SITEID) {
                 redirect($CFG->wwwroot .'/?redirect=0');
             } else {
-                redirect($PAGE->url);
+                $url = new moodle_url($PAGE->url, array('editingenabled' => 1));
+                redirect($url);
             }
         } else if (($edit == 0) and confirm_sesskey()) {
             $USER->editing = 0;
index 08438e1..0b10031 100644 (file)
@@ -277,7 +277,7 @@ class core_enrol_external extends external_api {
                     'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
                     'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
                     'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
-                    'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
+                    'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
                     'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
                     'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
                     'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
@@ -298,6 +298,7 @@ class core_enrol_external extends external_api {
                                 'id'  => new external_value(PARAM_INT, 'group id'),
                                 'name' => new external_value(PARAM_RAW, 'group name'),
                                 'description' => new external_value(PARAM_RAW, 'group description'),
+                                'descriptionformat' => new external_format_value('description'),
                             )
                         ), 'user groups', VALUE_OPTIONAL),
                     'roles' => new external_multiple_structure(
index 3728a23..2f5f5d4 100644 (file)
@@ -301,10 +301,9 @@ class core_files_renderer extends plugin_renderer_base {
      */
     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);
@@ -382,15 +381,15 @@ class core_files_renderer extends plugin_renderer_base {
             <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>
@@ -401,10 +400,10 @@ class core_files_renderer extends plugin_renderer_base {
         </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);
@@ -515,7 +514,7 @@ class core_files_renderer extends plugin_renderer_base {
 <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" />&nbsp;<span class="{!}fp-repo-name" /span></a></li>
+            <li class="{!}fp-repo"><a href="#"><img class="{!}fp-repo-icon" width="16" height="16" />&nbsp;<span class="{!}fp-repo-name"></span></a></li>
         </ul>
     </div>
     <div class="fp-repo-items">
@@ -523,7 +522,7 @@ class core_files_renderer extends plugin_renderer_base {
             <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>
@@ -534,7 +533,7 @@ class core_files_renderer extends plugin_renderer_base {
                     <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>
@@ -690,12 +689,12 @@ class core_files_renderer extends plugin_renderer_base {
     </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);
@@ -736,7 +735,7 @@ class core_files_renderer extends plugin_renderer_base {
                     <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>
@@ -771,7 +770,7 @@ class core_files_renderer extends plugin_renderer_base {
      */
     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);
     }
 
@@ -817,7 +816,7 @@ class core_files_renderer extends plugin_renderer_base {
     <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);
     }
@@ -860,11 +859,11 @@ class core_files_renderer extends plugin_renderer_base {
                     <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>
@@ -896,7 +895,7 @@ class core_files_renderer extends plugin_renderer_base {
      * 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;
     }
 }
index 0a0c2c5..d44b2ca 100644 (file)
@@ -171,7 +171,7 @@ if ($mform->is_cancelled()) {
 // 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'];
     }
index 11ae292..74b8c56 100644 (file)
@@ -125,7 +125,9 @@ if ($formdata = $mform->get_data()) {
     fwrite($fp,$text);
     fclose($fp);
 
-    $fp = fopen($filename, "r");
+    if (!$fp = fopen($filename, "r")) {
+        print_error('cannotopenfile');
+    }
 
     // --- get header (field names) ---
     $header = explode($csv_delimiter, fgets($fp, GRADE_CSV_LINE_LENGTH));
index 9045afd..080f406 100644 (file)
@@ -52,6 +52,7 @@ class core_group_external extends external_api {
                             'courseid' => new external_value(PARAM_INT, 'id of course'),
                             'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
                             'description' => new external_value(PARAM_RAW, 'group description text'),
+                            'descriptionformat' => new external_format_value('description', VALUE_DEFAULT),
                             'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'),
                         )
                     ), 'List of group object. A group has a courseid, a name, a description and an enrolment key.'
@@ -99,6 +100,9 @@ class core_group_external extends external_api {
             }
             require_capability('moodle/course:managegroups', $context);
 
+            // Validate format.
+            $group->descriptionformat = external_validate_format($group->descriptionformat);
+
             // finally create the group
             $group->id = groups_create_group($group, false);
             $groups[] = (array)$group;
@@ -123,6 +127,7 @@ class core_group_external extends external_api {
                     'courseid' => new external_value(PARAM_INT, 'id of course'),
                     'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
                     'description' => new external_value(PARAM_RAW, 'group description text'),
+                    'descriptionformat' => new external_format_value('description'),
                     'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'),
                 )
             ), 'List of group object. A group has an id, a courseid, a name, a description and an enrolment key.'
@@ -157,7 +162,7 @@ class core_group_external extends external_api {
         $groups = array();
         foreach ($params['groupids'] as $groupid) {
             // validate params
-            $group = groups_get_group($groupid, 'id, courseid, name, description, enrolmentkey', MUST_EXIST);
+            $group = groups_get_group($groupid, 'id, courseid, name, description, descriptionformat, enrolmentkey', MUST_EXIST);
 
             // now security checks
             $context = get_context_instance(CONTEXT_COURSE, $group->courseid);
@@ -171,6 +176,10 @@ class core_group_external extends external_api {
             }
             require_capability('moodle/course:managegroups', $context);
 
+            list($group->description, $group->descriptionformat) =
+                external_format_text($group->description, $group->descriptionformat,
+                        $context->id, 'group', 'description', $group->id);
+
             $groups[] = (array)$group;
         }
 
@@ -191,6 +200,7 @@ class core_group_external extends external_api {
                     'courseid' => new external_value(PARAM_INT, 'id of course'),
                     'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
                     'description' => new external_value(PARAM_RAW, 'group description text'),
+                    'descriptionformat' => new external_format_value('description'),
                     'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'),
                 )
             )
@@ -233,10 +243,14 @@ class core_group_external extends external_api {
         }
         require_capability('moodle/course:managegroups', $context);
 
-        $gs = groups_get_all_groups($params['courseid'], 0, 0, 'g.id, g.courseid, g.name, g.description, g.enrolmentkey');
+        $gs = groups_get_all_groups($params['courseid'], 0, 0,
+            'g.id, g.courseid, g.name, g.description, g.descriptionformat, g.enrolmentkey');
 
         $groups = array();
         foreach ($gs as $group) {
+            list($group->description, $group->descriptionformat) =
+                external_format_text($group->description, $group->descriptionformat,
+                        $context->id, 'group', 'description', $group->id);
             $groups[] = (array)$group;
         }
 
@@ -257,6 +271,7 @@ class core_group_external extends external_api {
                     'courseid' => new external_value(PARAM_INT, 'id of course'),
                     'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
                     'description' => new external_value(PARAM_RAW, 'group description text'),
+                    'descriptionformat' => new external_format_value('description'),
                     'enrolmentkey' => new external_value(PARAM_RAW, 'group enrol secret phrase'),
                 )
             )
@@ -557,7 +572,8 @@ class core_group_external extends external_api {
                         array(
                             'courseid' => new external_value(PARAM_INT, 'id of course'),
                             'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
-                            'description' => new external_value(PARAM_RAW, 'grouping description text')
+                            'description' => new external_value(PARAM_RAW, 'grouping description text'),
+                            'descriptionformat' => new external_format_value('descripiton', VALUE_DEFAULT)
                         )
                     ), 'List of grouping object. A grouping has a courseid, a name and a description.'
                 )
@@ -604,8 +620,7 @@ class core_group_external extends external_api {
             }
             require_capability('moodle/course:managegroups', $context);
 
-            // We must force allways FORMAT_HTML.
-            $grouping->descriptionformat = FORMAT_HTML;
+            $grouping->descriptionformat = external_validate_format($grouping->descriptionformat);
 
             // Finally create the grouping.
             $grouping->id = groups_create_grouping($grouping);
@@ -630,7 +645,8 @@ class core_group_external extends external_api {
                     'id' => new external_value(PARAM_INT, 'grouping record id'),
                     'courseid' => new external_value(PARAM_INT, 'id of course'),
                     'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
-                    'description' => new external_value(PARAM_CLEANHTML, 'grouping description text')
+                    'description' => new external_value(PARAM_RAW, 'grouping description text'),
+                    'descriptionformat' => new external_format_value('description')
                 )
             ), 'List of grouping object. A grouping has an id, a courseid, a name and a description.'
         );
@@ -650,7 +666,8 @@ class core_group_external extends external_api {
                         array(
                             'id' => new external_value(PARAM_INT, 'id of grouping'),
                             'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
-                            'description' => new external_value(PARAM_RAW, 'grouping description text')
+                            'description' => new external_value(PARAM_RAW, 'grouping description text'),
+                            'descriptionformat' => new external_format_value('description', VALUE_DEFAULT)
                         )
                     ), 'List of grouping object. A grouping has a courseid, a name and a description.'
                 )
@@ -705,7 +722,7 @@ class core_group_external extends external_api {
             require_capability('moodle/course:managegroups', $context);
 
             // We must force allways FORMAT_HTML.
-            $grouping->descriptionformat = FORMAT_HTML;
+            $grouping->descriptionformat = external_validate_format($grouping->descriptionformat);
 
             // Finally update the grouping.
             groups_update_grouping($grouping);
@@ -772,12 +789,9 @@ class core_group_external extends external_api {
             }
             require_capability('moodle/course:managegroups', $context);
 
-            $grouping->description = file_rewrite_pluginfile_urls($grouping->description, 'webservice/pluginfile.php', $context->id, 'grouping', 'description', $grouping->id);
-
-            $options = new stdClass;
-            $options->noclean = true;
-            $options->para = false;
-            $grouping->description = format_text($grouping->description, FORMAT_HTML, $options);
+            list($grouping->description, $grouping->descriptionformat) =
+                external_format_text($grouping->description, $grouping->descriptionformat,
+                        $context->id, 'grouping', 'description', $grouping->id);
 
             $groupings[] = (array)$grouping;
         }
@@ -798,7 +812,8 @@ class core_group_external extends external_api {
                     'id' => new external_value(PARAM_INT, 'grouping record id'),
                     'courseid' => new external_value(PARAM_INT, 'id of course'),
                     'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
-                    'description' => new external_value(PARAM_CLEANHTML, 'grouping description text')
+                    'description' => new external_value(PARAM_RAW, 'grouping description text'),
+                    'descriptionformat' => new external_format_value('description')
                 )
             )
         );
@@ -849,13 +864,9 @@ class core_group_external extends external_api {
 
         $groupings = array();
         foreach ($gs as $grouping) {
-            $grouping->description = file_rewrite_pluginfile_urls($grouping->description, 'webservice/pluginfile.php', $context->id, 'grouping', 'description', $grouping->id);
-
-            $options = new stdClass;
-            $options->noclean = true;
-            $options->para = false;
-            $grouping->description = format_text($grouping->description, FORMAT_HTML, $options);
-
+            list($grouping->description, $grouping->descriptionformat) =
+                external_format_text($grouping->description, $grouping->descriptionformat,
+                        $context->id, 'grouping', 'description', $grouping->id);
             $groupings[] = (array)$grouping;
         }
 
@@ -875,7 +886,8 @@ class core_group_external extends external_api {
                     'id' => new external_value(PARAM_INT, 'grouping record id'),
                     'courseid' => new external_value(PARAM_INT, 'id of course'),
                     'name' => new external_value(PARAM_TEXT, 'multilang compatible name, course unique'),
-                    'description' => new external_value(PARAM_CLEANHTML, 'grouping description text')
+                    'description' => new external_value(PARAM_RAW, 'grouping description text'),
+                    'descriptionformat' => new external_format_value('description')
                 )
             )
         );
index 341a147..e50e3bc 100644 (file)
@@ -73,11 +73,6 @@ if (!function_exists('iconv')) {
     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
index 6dbb859..42dbcf3 100644 (file)
@@ -473,7 +473,7 @@ $string['enabledevicedetection'] = 'Enable device detection';
 $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';
@@ -568,6 +568,7 @@ $string['htmleditorsettings'] = 'HTML editor settings';
 $string['htmlsettings'] = 'HTML settings';
 $string['http'] = 'HTTP';
 $string['httpsecurity'] = 'HTTP security';
+$string['hubs'] = 'Hubs';
 $string['change'] = 'change';
 $string['checkboxno'] = 'No';
 $string['checkboxyes'] = 'Yes';
@@ -846,7 +847,15 @@ $string['rcache'] = 'Record cache';
 $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.';
@@ -925,6 +934,7 @@ $string['splrequired'] = 'The SPL PHP extension is now required by Moodle.';
 $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';
@@ -1031,6 +1041,7 @@ $string['usetags'] = 'Enable tags functionality';
 $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';
index 42abfad..4b8cd53 100644 (file)
@@ -118,12 +118,6 @@ $string['licence_link'] = 'licenses';
 $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.';
@@ -165,11 +159,10 @@ $string['registeredcourses'] = 'Registered courses';
 $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.';
@@ -237,7 +230,6 @@ $string['siteversion'] = 'Moodle version';
 $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';
index 42c8658..c0ca916 100644 (file)
@@ -145,6 +145,7 @@ $string['manage'] = 'Manage repositories';
 $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';
index 2b72efe..f92c829 100644 (file)
@@ -122,8 +122,8 @@ $string['mobilewsenabled'] = 'Enabled';
 $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.';
index 2034af1..4df3bc0 100644 (file)
@@ -992,172 +992,72 @@ class completion_info {
      * @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);
     }
 
     /**
index 791d246..031ac61 100644 (file)
  * @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);
@@ -50,15 +55,16 @@ function min_optional_param($name, $default, $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;
@@ -74,6 +80,49 @@ function min_clean_param($value, $type) {
     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.
@@ -112,7 +161,9 @@ function min_enable_zlib_compression() {
 
 /**
  * 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
  */
index f89adbd..b79057d 100644 (file)
@@ -174,9 +174,8 @@ function cron_run() {
 
     // 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');
     }
 
 
@@ -603,16 +602,27 @@ function cron_bc_hack_plugin_functions($plugintype, $plugins) {
  * 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.
@@ -685,10 +695,8 @@ function notify_login_failures() {
     }
     $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)
@@ -710,4 +718,6 @@ function notify_login_failures() {
 
     // 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;
 }
index 76ebc66..173659e 100644 (file)
@@ -1679,6 +1679,7 @@ $capabilities = array(
         'contextlevel' => CONTEXT_BLOCK,
         'archetypes' => array(
             'editingteacher' => CAP_ALLOW,
+            'manager' => CAP_ALLOW
         )
     ),
 
index aa5539f..9d9c7d6 100644 (file)
@@ -107,7 +107,7 @@ class EvalMath {
         '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),
index 9ef3b12..1913f45 100644 (file)
@@ -584,19 +584,242 @@ function external_delete_descriptions($component) {
 }
 
 /**
- * Creates a warnings external_multiple_structure
+ * Standard Moodle web service warnings
  *
- * @return external_multiple_structure
- * @since  Moodle 2.3
+ * @package    core_webservice
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 2.3
+ */
+class external_warnings extends external_multiple_structure {
+
+    /**
+     * Constructor
+     *
+     * @since Moodle 2.3
+     */
+    public function __construct() {
+
+        parent::__construct(
+            new external_single_structure(
+                array(
+                    'item' => new external_value(PARAM_TEXT, 'item', VALUE_OPTIONAL),
+                    'itemid' => new external_value(PARAM_INT, 'item id', VALUE_OPTIONAL),
+                    'warningcode' => new external_value(PARAM_ALPHANUM,
+                            'the warning code can be used by the client app to implement specific behaviour'),
+                    'message' => new external_value(PARAM_TEXT,
+                            'untranslated english message to explain the warning')
+                ), 'warning'),
+            'list of warnings', VALUE_OPTIONAL);
+    }
+}
+
+/**
+ * A pre-filled external_value class for text format.
+ *
+ * Default is FORMAT_HTML
+ * This should be used all the time in external xxx_params()/xxx_returns functions
+ * as it is the standard way to implement text format param/return values.
+ *
+ * @package    core_webservice
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 2.3
  */
-function external_warnings() {
-    return new external_multiple_structure(
-        new external_single_structure(array(
-            'item' => new external_value(PARAM_TEXT, 'item', VALUE_OPTIONAL),
-            'itemid' => new external_value(PARAM_INT, 'item id', VALUE_OPTIONAL),
-            'warningcode' => new external_value(PARAM_ALPHANUM, 'the warning code can be used by
-                the client app to implement specific behaviour'),
-            'message' => new external_value(PARAM_TEXT, 'untranslated english message to explain the warning')
-                ), 'warning'), 'list of warnings', VALUE_OPTIONAL
-    );
+class external_format_value extends external_value {
+
+    /**
+     * Constructor
+     *
+     * @param string $textfieldname Name of the text field
+     * @param int $required if VALUE_REQUIRED then set standard default FORMAT_HTML
+     * @since Moodle 2.3
+     */
+    public function __construct($textfieldname, $required = VALUE_REQUIRED) {
+
+        $default = ($required == VALUE_DEFAULT) ? FORMAT_HTML : null;
+
+        $desc = $textfieldname . ' format (' . FORMAT_HTML . ' = HTML, '
+                . FORMAT_MOODLE . ' = MOODLE, '
+                . FORMAT_PLAIN . ' = PLAIN or '
+                . FORMAT_MARKDOWN . ' = MARKDOWN)';
+
+        parent::__construct($type, $desc='', $required, $default);
+    }
+}
+
+/**
+ * Validate text field format against known FORMAT_XXX
+ *
+ * @param array $format the format to validate
+ * @return the validated format
+ * @throws coding_exception
+ * @since 2.3
+ */
+function external_validate_format($format) {
+    $allowedformats = array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN);
+    if (!in_array($format, $allowedformats)) {
+        throw new moodle_exception('formatnotsupported', 'webservice', '' , null,
+                'The format with value=' . $format . ' is not supported by this Moodle site');
+    }
+    return $format;
+}
+
+/**
+ * Format the text to be returned properly as requested by the either the web service server,
+ * either by an internally call.
+ * The caller can change the format (raw, filter, file, fileurl) with the external_settings singleton
+ * All web service servers must set this singleton when parsing the $_GET and $_POST.
+ *
+ * @param string $text The content that may contain ULRs in need of rewriting.
+ * @param int $textformat The text format, by default FORMAT_HTML.
+ * @param int $contextid This parameter and the next two identify the file area to use.
+ * @param string $component
+ * @param string $filearea helps identify the file area.
+ * @param int $itemid helps identify the file area.
+ * @return array text + textformat
+ * @since Moodle 2.3
+ */
+function external_format_text($text, $textformat, $contextid, $component, $filearea, $itemid) {
+    global $CFG;
+
+    // Get settings (singleton).
+    $settings = external_settings::get_instance();
+
+    if ($settings->get_fileurl()) {
+        $text = file_rewrite_pluginfile_urls($text, $settings->get_file(), $contextid, $component, $filearea, $itemid);
+    }
+
+    if (!$settings->get_raw()) {
+        $textformat = FORMAT_HTML; // Force format to HTML when not raw.
+        $text = format_text($text, $textformat,
+                array('noclean' => true, 'para' => false, 'filter' => $settings->get_filter()));
+    }
+
+    return array($text, $textformat);
+}
+
+/**
+ * Singleton to handle the external settings.
+ *
+ * We use singleton to encapsulate the "logic"
+ *
+ * @package    core_webservice
+ * @copyright  2012 Jerome Mouneyrac
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since Moodle 2.3
+ */
+class external_settings {
+
+    /** @var object the singleton instance */
+    public static $instance = null;
+
+    /** @var boolean Should the external function return raw text or formatted */
+    private $raw = false;
+
+    /** @var boolean Should the external function filter the text */
+    private $filter = false;
+
+    /** @var boolean Should the external function rewrite plugin file url */
+    private $fileurl = true;
+
+    /** @var string In which file should the urls be rewritten */
+    private $file = 'webservice/pluginfile.php';
+
+    /**
+     * Constructor - protected - can not be instanciated
+     */
+    protected function __construct() {
+    }
+
+    /**
+     * Clone - private - can not be cloned
+     */
+    private final function __clone() {
+    }
+
+    /**
+     * Return only one instance
+     *
+     * @return object
+     */
+    public static function get_instance() {
+        if (self::$instance === null) {
+            self::$instance = new external_settings;
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * Set raw
+     *
+     * @param boolean $raw
+     */
+    public function set_raw($raw) {
+        $this->raw = $raw;
+    }
+
+    /**
+     * Get raw
+     *
+     * @return boolean
+     */
+    public function get_raw() {
+        return $this->raw;
+    }
+
+    /**
+     * Set filter
+     *
+     * @param boolean $filter
+     */
+    public function set_filter($filter) {
+        $this->filter = $filter;
+    }
+
+    /**
+     * Get filter
+     *
+     * @return boolean
+     */
+    public function get_filter() {
+        return $this->filter;
+    }
+
+    /**
+     * Set fileurl
+     *
+     * @param boolean $fileurl
+     */
+    public function set_fileurl($fileurl) {
+        $this->fileurl = $fileurl;
+    }
+
+    /**
+     * Get fileurl
+     *
+     * @return boolean
+     */
+    public function get_fileurl() {
+        return $this->fileurl;
+    }
+
+    /**
+     * Set file
+     *
+     * @param string $file
+     */
+    public function set_file($file) {
+        $this->file = $file;
+    }
+
+    /**
+     * Get file
+     *
+     * @return string
+     */
+    public function get_file() {
+        return $this->file;
+    }
 }
index e53640b..2771e04 100644 (file)
@@ -303,15 +303,11 @@ abstract class file_info {
     /**
      * 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;
     }
 
index 2f3ea57..6eb760f 100644 (file)
@@ -519,25 +519,21 @@ class file_info_stored extends file_info {
     /**
      * 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;
     }
index 7aa8841..ef1abdb 100644 (file)
@@ -2535,7 +2535,9 @@ function fulldelete($location) {
         return false;
     }
     if (is_dir($location)) {
-        $currdir = opendir($location);
+        if (!$currdir = opendir($location)) {
+            return false;
+        }
         while (false !== ($file = readdir($currdir))) {
             if ($file <> ".." && $file <> ".") {
                 $fullfile = $location."/".$file;
index c936716..75ab483 100644 (file)
@@ -161,7 +161,7 @@ class stored_file {
                 throw new file_exception('storedfilecannotread', '', $pathname);
             }
         }
-        $mimetype = $this->fs->mimetype($pathname);
+        $mimetype = $this->fs->mimetype($pathname, $this->file_record->filename);
         $this->file_record->mimetype = $mimetype;
 
         $DB->update_record('files', $this->file_record);
index 6627c2a..3b2bd3e 100644 (file)
@@ -100,9 +100,8 @@ M.form_filemanager.init = function(Y, options) {
                 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,
@@ -234,27 +233,27 @@ M.form_filemanager.init = function(Y, options) {
                 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() {
@@ -302,8 +301,7 @@ M.form_filemanager.init = function(Y, options) {
                         });
                     }
                     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,
@@ -679,10 +677,9 @@ M.form_filemanager.init = function(Y, options) {
         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,
@@ -867,7 +864,7 @@ M.form_filemanager.init = function(Y, options) {
             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);
index 0dd6edf..f4674ce 100644 (file)
@@ -389,7 +389,7 @@ function message_get_providers_for_user($userid) {
 
     $systemcontext = get_context_instance(CONTEXT_SYSTEM);
 
-    $providers = $DB->get_records('message_providers', null, 'name');
+    $providers = get_message_providers();
 
     // Remove all the providers we aren't allowed to see now
     foreach ($providers as $providerid => $provider) {
index 23ee2f5..91ff78f 100644 (file)
@@ -1127,15 +1127,39 @@ function fix_utf8($value) {
             // shortcut
             return $value;
         }
-        // lower error reporting because glibc throws bogus notices
+
+        // Lower error reporting because glibc throws bogus notices.
         $olderror = error_reporting();
         if ($olderror & E_NOTICE) {
             error_reporting($olderror ^ E_NOTICE);
         }
-        $result = iconv('UTF-8', 'UTF-8//IGNORE', $value);
+
+        // Note: this duplicates min_fix_utf8() intentionally.
+        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;
 
     } else if (is_array($value)) {
@@ -8005,7 +8029,10 @@ function get_list_of_plugins($directory='mod', $exclude='', $basedir='') {
     }
 
     if (file_exists($basedir) && filetype($basedir) == 'dir') {
-        $dirhandle = opendir($basedir);
+        if (!$dirhandle = opendir($basedir)) {
+            debugging("Directory permission error for plugin ({$directory}). Directory exists but cannot be read.", DEBUG_DEVELOPER);
+            return array();
+        }
         while (false !== ($dir = readdir($dirhandle))) {
             $firstchar = substr($dir, 0, 1);
             if ($firstchar === '.' or $dir === 'CVS' or $dir === '_vti_cnf' or $dir === 'simpletest' or $dir === 'yui' or $dir === 'phpunit' or $dir === $exclude) {
@@ -10201,7 +10228,7 @@ function apd_get_profiling() {
 }
 
 /**
- * Delete directory or only it's content
+ * Delete directory or only its content
  *
  * @param string $dir directory path
  * @param bool $content_only
@@ -10212,7 +10239,9 @@ function remove_dir($dir, $content_only=false) {
         // nothing to do
         return true;
     }
-    $handle = opendir($dir);
+    if (!$handle = opendir($dir)) {
+        return false;
+    }
     $result = true;
     while (false!==($item = readdir($handle))) {
         if($item != '.' && $item != '..') {
index b4aa15b..587ba19 100644 (file)
@@ -368,8 +368,8 @@ abstract class oauth2_client extends curl {
     private $clientid = '';
     /** var string The client secret. */
     private $clientsecret = '';
-    /** var string URL to return to after authenticating */
-    private $returnurl = '';
+    /** var moodle_url URL to return to after authenticating */
+    private $returnurl = null;
     /** var string scope of the authentication request */
     private $scope = '';
     /** var stdClass access token object */
@@ -392,10 +392,10 @@ abstract class oauth2_client extends curl {
      *
      * @param string $clientid
      * @param string $clientsecret
-     * @param string $returnurl
+     * @param moodle_url $returnurl
      * @param string $scope
      */
-    public function __construct($clientid, $clientsecret, $returnurl, $scope) {
+    public function __construct($clientid, $clientsecret, moodle_url $returnurl, $scope) {
         parent::__construct();
         $this->clientid = $clientid;
         $this->clientsecret = $clientsecret;
@@ -425,7 +425,7 @@ abstract class oauth2_client extends curl {
 
         // If we've been passed then authorization code generated by the
         // authorization server try and upgrade the token to an access token.
-        $code = optional_param('code', null, PARAM_RAW);
+        $code = optional_param('oauth2code', null, PARAM_RAW);
         if ($code && $this->upgrade_token($code)) {
             return true;
         }
@@ -456,7 +456,7 @@ abstract class oauth2_client extends curl {
                         array('client_id' => $this->clientid,
                               'response_type' => 'code',
                               'redirect_uri' => $callbackurl->out(false),
-                              'state' => $this->returnurl,
+                              'state' => $this->returnurl->out_as_local_url(false),
                               'scope' => $this->scope,
                           ));
 
index 9cd8585..a700157 100644 (file)
@@ -34,4 +34,5 @@ require_once(__DIR__.'/classes/database_driver_testcase.php');
 require_once(__DIR__.'/classes/arraydataset.php');
 require_once(__DIR__.'/classes/advanced_testcase.php');
 require_once(__DIR__.'/classes/unittestcase.php');
+require_once(__DIR__.'/classes/hint_resultprinter.php'); // Loaded here because phpunit.xml does not support relative links for printerFile
 
index 01ac161..7c33d91 100644 (file)
@@ -110,7 +110,10 @@ function rss_delete_file($componentname, $instance) {
 
     $dirpath = "$CFG->cachedir/rss/$componentname";
     if (is_dir($dirpath)) {
-        $dh  = opendir($dirpath);
+        if (!$dh = opendir($dirpath)) {
+            error_log("Directory permission error. RSS directory store for component '{$componentname}' exists but cannot be opened.", DEBUG_DEVELOPER);
+            return;
+        }
         while (false !== ($filename = readdir($dh))) {
             if ($filename!='.' && $filename!='..') {
                 if (preg_match("/{$instance->id}_/", $filename)) {
index e991bea..b810564 100644 (file)
@@ -131,17 +131,6 @@ class flexible_table {
         );
     }
 
-    /**
-     * Backwards-compatible constructor, so that legacy code subclassing
-     * flexible_table does not break.
-     * @deprecated since Moodle 2.0. Will be removed in Moodle 2.1.
-     */
-    function flexible_table($uniqueid) {
-        debugging('Please update your code to user PHP5-style parent::__construct(...), ' .
-                'not parent::flexible_table(...).');
-        $this->__construct($uniqueid);
-    }
-
     /**
      * Call this to pass the download type. Use :
      *         $download = optional_param('download', '', PARAM_ALPHA);
diff --git a/lib/tests/configonlylib_test.php b/lib/tests/configonlylib_test.php
new file mode 100644 (file)
index 0000000..dc97baa
--- /dev/null
@@ -0,0 +1,144 @@
+<?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/>.
+
+/**
+ * Unit tests for config only library functions-
+ *
+ * @package    core
+ * @category   phpunit
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// Global CFG not used here intentionally to make sure it is not required inside the lib.
+require_once(__DIR__ . '/../configonlylib.php');
+
+
+/**
+ * Unit tests for config only library functions.
+ *
+ * @package    core
+ * @category   phpunit
+ * @copyright  2012 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class core_configonlylib_testcase extends advanced_testcase {
+
+    /**
+     * Test cleaning of invalid utf-8 entities.
+     */
+    public function test_min_fix_utf8() {
+        $this->assertSame('abc', min_fix_utf8('abc'));
+        $this->assertSame("žlutý koníček přeskočil potůček \n\t\r\0", min_fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
+        $this->assertSame('aš', min_fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
+    }
+
+    /**
+     * Test minimalistic parameter cleaning.
+     */
+    public function test_min_clean_param() {
+        $this->assertSame('foo', min_clean_param('foo', 'RAW'));
+        $this->assertSame('aš', min_clean_param('a'.chr(130).'š', 'RAW'));
+
+        $this->assertSame(1, min_clean_param('1', 'INT'));
+        $this->assertSame(1, min_clean_param('1aa', 'INT'));
+
+        $this->assertSame('1abc-d_f', min_clean_param('/.1ačž"b?;c-d{}\\_f.', 'SAFEDIR'));
+        $this->assertSame(1, min_clean_param('1aa', 'INT'));
+
+        $this->assertSame('/a/b/./c5', min_clean_param('/a*?$//b/.../c5', 'SAFEPATH'));
+        $this->assertSame(1, min_clean_param('1aa', 'INT'));
+    }
+
+    /**
+     * Test minimalistic getting of page parameters.
+     */
+    public function test_min_optional_param() {
+        $this->resetAfterTest();
+
+        $_GET['foo'] = 'bar';
+        $_GET['num'] = '1';
+        $_GET['xnum'] = '1aa';
+
+        $_POST['foo'] = 'rebar';
+        $_POST['oof'] = 'rab';
+
+        $this->assertSame('bar', min_optional_param('foo', null, 'RAW'));
+        $this->assertSame(null, min_optional_param('foo2', null, 'RAW'));
+        $this->assertSame('rab', min_optional_param('oof', null, 'RAW'));
+
+        $this->assertSame(1, min_optional_param('num', null, 'INT'));
+        $this->assertSame(1, min_optional_param('xnum', null, 'INT'));
+    }
+
+    /**
+     * Test fail-safe minimalistic slashargument processing.
+     */
+    public function min_get_slash_argument() {
+        global $CFG;
+
+        $this->resetAfterTest();
+        $this->assertEquals('http://www.example.com/moode', $CFG->wwwroot);
+
+        $_SERVER = array();
+        $_SERVER['SERVER_SOFTWARE'] = 'Apache/2.2.22 (Unix)';
+        $_SERVER['QUERY_STRING'] = 'theme=standard&component=core&rev=5&image=u/f1';
+        $_SEREVR['REQUEST_URI'] = '/moodle/theme/image.php?theme=standard&component=core&rev=5&image=u/f1';
+        $_SERVER['SCRIPT_NAME'] = '/moodle/theme/image.php';
+        $this->assertSame('', min_get_slash_argument());
+
+        $_SERVER = array();
+        $_SERVER['SERVER_SOFTWARE'] = 'Apache/2.2.22 (Unix)';
+        $_SERVER['QUERY_STRING'] = '';
+        $_SEREVR['REQUEST_URI'] = '/moodle/theme/image.php/standard/core/5/u/f1';
+        $_SERVER['PATH_INFO'] = '/standard/core/5/u/f1';
+        $_SERVER['SCRIPT_NAME'] = '/moodle/theme/image.php';
+        $_GET = array();
+        $this->assertSame('/standard/core/5/u/f1', min_get_slash_argument());
+
+        // IIS no url rewriting
+        $_SERVER = array();
+        $_SERVER['SERVER_SOFTWARE'] = 'Microsoft-IIS/7.0';
+        $_SERVER['QUERY_STRING'] = '';
+        $_SEREVR['REQUEST_URI'] = '/moodle/theme/image.php/standard/core/5/u/f1';
+        $_SERVER['PATH_INFO'] = '/standard/core/5/u/f1';
+        $_SERVER['SCRIPT_NAME'] = '/moodle/theme/image.php';
+        $_GET = array();
+        $this->assertSame('/standard/core/5/u/f1', min_get_slash_argument());
+
+        // IIS with url rewriting
+        $_SERVER = array();
+        $_SERVER['SERVER_SOFTWARE'] = 'Microsoft-IIS/7.0';
+        $_SERVER['QUERY_STRING'] = 'file=/standard/core/5/u/f1';
+        $_SEREVR['REQUEST_URI'] = '/moodle/theme/image.php/standard/core/5/u/f1';
+        $_SERVER['PATH_INFO'] = '/';
+        $_SERVER['SCRIPT_NAME'] = '/moodle/theme/image.php';
+        $_GET = array();
+        $_GET['file'] = '/standard/core/5/u/f1';
+        $this->assertSame('/standard/core/5/u/f1', min_get_slash_argument());
+
+        $_SERVER = array();
+        $_SERVER['SERVER_SOFTWARE'] = 'Weird server';
+        $_SERVER['QUERY_STRING'] = '';
+        $_SEREVR['REQUEST_URI'] = '/moodle/theme/image.php/standard/core/5/u/f1';
+        $_SERVER['PATH_INFO'] = '/moodle/theme/image.php/standard/core/5/u/f1';
+        $_SERVER['SCRIPT_NAME'] = '/moodle/theme/image.php';
+        $_GET = array();
+        $this->assertSame('/standard/core/5/u/f1', min_get_slash_argument());
+    }
+}
index 4c56eed..1df41fe 100644 (file)
@@ -142,6 +142,9 @@ class mathsslib_testcase extends basic_testcase {
     }
 
     public function test_rounding_function() {
+        // Rounding to the default number of decimal places
+        // The default == 0
+
         $formula = new calc_formula('=round(2.5)');
         $this->assertEquals($formula->evaluate(), 3);
 
@@ -196,6 +199,19 @@ class mathsslib_testcase extends basic_testcase {
         $formula = new calc_formula('=floor(-2.5)');
         $this->assertEquals($formula->evaluate(), -3);
 
+        // Rounding to an explicit number of decimal places
+
+        $formula = new calc_formula('=round(2.5, 1)');
+        $this->assertEquals($formula->evaluate(), 2.5);
+
+        $formula = new calc_formula('=round(2.5, 0)');
+        $this->assertEquals($formula->evaluate(), 3);
+
+        $formula = new calc_formula('=round(1.2345, 2)');
+        $this->assertEquals($formula->evaluate(), 1.23);
+
+        $formula = new calc_formula('=round(123.456, -1)');
+        $this->assertEquals($formula->evaluate(), 120);
     }
 
     public function test_scientific_notation() {
index 6189919..5ce3a2c 100644 (file)
@@ -301,6 +301,7 @@ class moodlelib_testcase extends advanced_testcase {
         $this->assertSame(1.1, fix_utf8(1.1));
         $this->assertSame(true, fix_utf8(true));
         $this->assertSame('', fix_utf8(''));
+        $this->assertSame('abc', fix_utf8('abc'));
         $array = array('do', 're', 'mi');
         $this->assertSame($array, fix_utf8($array));
         $object = new stdClass();
@@ -312,7 +313,7 @@ class moodlelib_testcase extends advanced_testcase {
         $this->assertSame("žlutý koníček přeskočil potůček \n\t\r\0", fix_utf8("žlutý koníček přeskočil potůček \n\t\r\0"));
 
         // invalid utf8 string
-        $this->assertSame('aaabbb', fix_utf8('aaa'.chr(130).'bbb'));
+        $this->assertSame('aš', fix_utf8('a'.chr(130).'š'), 'This fails with buggy iconv() when mbstring extenstion is not available as fallback.');
     }
 
     function test_optional_param() {
index 70bff78..1280a3d 100644 (file)
@@ -946,7 +946,10 @@ EOD;
             if ($result) {
                 // recurse directories
                 if (is_dir($localpath)) {
-                    $dp = opendir($localpath);
+                    if (!$dp = opendir($localpath)) {
+                        $this->_error_log("Could not open localpath for reading");
+                        return false;
+                    }
                     $fl = array();
                     while($filename = readdir($dp)) {
                         if ((is_file($localpath."/".$filename) || is_dir($localpath."/".$filename)) && $filename!="." && $filename != "..") {
index 4d94cc4..d87b9e0 100644 (file)
@@ -34,7 +34,7 @@ require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
 // Fetch processors
 $processors = get_message_processors(true);
 // Fetch message providers
-$providers = $DB->get_records('message_providers', null, 'name');
+$providers = get_message_providers();
 
 if (($form = data_submitted()) && confirm_sesskey()) {
     $preferences = array();
index f39d517..ca28d2d 100644 (file)
@@ -50,7 +50,8 @@ class core_message_external extends external_api {
                     new external_single_structure(
                         array(
                             'touserid' => new external_value(PARAM_INT, 'id of the user to send the private message'),
-                            'text' => new external_value(PARAM_RAW, 'the text of the message - not that you can send anything it will be automatically cleaned to PARAM_TEXT and used againt MOODLE_FORMAT'),
+                            'text' => new external_value(PARAM_RAW, 'the text of the message'),
+                            'textformat' => new external_format_value('text', VALUE_DEFAULT),
                             'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the message. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
                         )
                     )
@@ -111,7 +112,6 @@ class core_message_external extends external_api {
 
         $resultmessages = array();
         foreach ($params['messages'] as $message) {
-            $text = clean_param($message['text'], PARAM_TEXT);
             $resultmsg = array(); //the infos about the success of the operation
 
             //we are going to do some checking
@@ -143,7 +143,8 @@ class core_message_external extends external_api {
             //now we can send the message (at least try)
             if ($success) {
                 //TODO MDL-31118 performance improvement - edit the function so we can pass an array instead one touser object
-                $success = message_post_message($USER, $tousers[$message['touserid']], $text, FORMAT_MOODLE);
+                $success = message_post_message($USER, $tousers[$message['touserid']],
+                        $message['text'], external_validate_format($message['textformat']));
             }
 
             //build the resultmsg
@@ -153,6 +154,9 @@ class core_message_external extends external_api {
             if ($success) {
                 $resultmsg['msgid'] = $success;
             } else {
+                // WARNINGS: for backward compatibility we return this errormessage.
+                //          We should have thrown exceptions as these errors prevent results to be returned.
+                // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
                 $resultmsg['msgid'] = -1;
                 $resultmsg['errormessage'] = $errormessage;
             }
index 3becd45..feb364b 100644 (file)
@@ -2297,6 +2297,36 @@ function get_message_processors($ready = false) {
     return $processors;
 }
 
+/**
+ * Get all message providers, validate their plugin existance and
+ * system configuration
+ *
+ * @return mixed $processors array of objects containing information on message processors
+ */
+function get_message_providers() {
+    global $CFG, $DB;
+    require_once($CFG->libdir . '/pluginlib.php');
+    $pluginman = plugin_manager::instance();
+
+    $providers = $DB->get_records('message_providers', null, 'name');
+
+    // Remove all the providers whose plugins are disabled or don't exist
+    foreach ($providers as $providerid => $provider) {
+        $plugin = $pluginman->get_plugin_info($provider->component);
+        if ($plugin) {
+            if ($plugin->get_status() === plugin_manager::PLUGIN_STATUS_MISSING) {
+                unset($providers[$providerid]);   // Plugins does not exist
+                continue;
+            }
+            if ($plugin->is_enabled() === false) {
+                unset($providers[$providerid]);   // Plugin disabled
+                continue;
+            }
+        }
+    }
+    return $providers;
+}
+
 /**
  * Get an instance of the message_output class for one of the output plugins.
  * @param string $type the message output type. E.g. 'email' or 'jabber'.
index dadd2a8..237a00d 100644 (file)
@@ -53,6 +53,77 @@ class assign_feedback_comments extends assign_feedback_plugin {
         return $DB->get_record('assignfeedback_comments', array('grade'=>$gradeid));
     }
 
+    /**
+     * Get quickgrading form elements as html
+     *
+     * @param int $userid The user id in the table this quickgrading element relates to
+     * @param mixed $grade - The grade data - may be null if there are no grades for this user (yet)
+     * @return mixed - A html string containing the html form elements required for quickgrading
+     */
+    public function get_quickgrading_html($userid, $grade) {
+        $commenttext = '';
+        if ($grade) {
+            $feedbackcomments = $this->get_feedback_comments($grade->id);
+            if ($feedbackcomments) {
+                $commenttext = $feedbackcomments->commenttext;
+            }
+        }
+
+        return html_writer::tag('textarea', $commenttext, array('name'=>'quickgrade_comments_' . $userid,
+                                                                'class'=>'quickgrade'));
+    }
+
+    /**
+     * Has the plugin quickgrading form element been modified in the current form submission?
+     *
+     * @param int $userid The user id in the table this quickgrading element relates to
+     * @param stdClass $grade The grade
+     * @return boolean - true if the quickgrading form element has been modified
+     */
+    public function is_quickgrading_modified($userid, $grade) {
+        $commenttext = '';
+        if ($grade) {
+            $feedbackcomments = $this->get_feedback_comments($grade->id);
+            if ($feedbackcomments) {
+                $commenttext = $feedbackcomments->commenttext;
+            }
+        }
+        return optional_param('quickgrade_comments_' . $userid, '', PARAM_TEXT) != $commenttext;
+    }
+
+
+    /**
+     * Override to indicate a plugin supports quickgrading
+     *
+     * @return boolean - True if the plugin supports quickgrading
+     */
+    public function supports_quickgrading() {
+        return true;
+    }
+
+    /**
+     * Save quickgrading changes
+     *
+     * @param int $userid The user id in the table this quickgrading element relates to
+     * @param stdClass $grade The grade
+     * @return boolean - true if the grade changes were saved correctly
+     */
+    public function save_quickgrading_changes($userid, $grade) {
+        global $DB;
+        $feedbackcomment = $this->get_feedback_comments($grade->id);
+        if ($feedbackcomment) {
+            $feedbackcomment->commenttext = optional_param('quickgrade_comments_' . $userid, '', PARAM_TEXT);
+            return $DB->update_record('assignfeedback_comments', $feedbackcomment);
+        } else {
+            $feedbackcomment = new stdClass();
+            $feedbackcomment->commenttext = optional_param('quickgrade_comments_' . $userid, '', PARAM_TEXT);
+            $feedbackcomment->commentformat = FORMAT_HTML;
+            $feedbackcomment->grade = $grade->id;
+            $feedbackcomment->assignment = $this->assignment->get_instance()->id;
+            return $DB->insert_record('assignfeedback_comments', $feedbackcomment) > 0;
+        }
+    }
+
     /**
      * Get form elements for the grading page
      *
index 198900b..6677e6a 100644 (file)
@@ -81,4 +81,46 @@ abstract class assign_feedback_plugin extends assign_plugin {
         return '';
     }
 
+    /**
+     * Override to indicate a plugin supports quickgrading
+     *
+     * @return boolean - True if the plugin supports quickgrading
+     */
+    public function supports_quickgrading() {
+        return false;
+    }
+
+    /**
+     * Get quickgrading form elements as html
+     *
+     * @param int $userid The user id in the table this quickgrading element relates to
+     * @param mixed $grade grade or null - The grade data. May be null if there are no grades for this user (yet)
+     * @return mixed - A html string containing the html form elements required for quickgrading or false to indicate this plugin does not support quickgrading
+     */
+    public function get_quickgrading_html($userid, $grade) {
+        return false;
+    }
+
+    /**
+     * Has the plugin quickgrading form element been modified in the current form submission?
+     *
+     * @param int $userid The user id in the table this quickgrading element relates to
+     * @param stdClass $grade The grade
+     * @return boolean - true if the quickgrading form element has been modified
+     */
+    public function is_quickgrading_modified($userid, $grade) {
+        return false;
+    }
+
+    /**
+     * Save quickgrading changes
+     *
+     * @param int $userid The user id in the table this quickgrading element relates to
+     * @param stdClass $grade The grade
+     * @return boolean - true if the grade changes were saved correctly
+     */
+    public function save_quickgrading_changes($userid, $grade) {
+        return false;
+    }
+
 }
index 7d2bddc..db4432d 100644 (file)
@@ -253,7 +253,7 @@ class assign_grading_table extends table_sql implements renderable {
             $options = make_grades_menu(-$outcome->scaleid);
 
             $options[0] = get_string('nooutcome', 'grades');
-            if ($this->quickgrading&& !($outcome->grades[$row->userid]->locked)) {
+            if ($this->quickgrading && !($outcome->grades[$row->userid]->locked)) {
                 $select = '<select name="outcome_' . $index . '_' . $row->userid . '" class="quickgrade">';
                 foreach ($options as $optionindex => $optionvalue) {
                     $selected = '';
@@ -519,6 +519,7 @@ class assign_grading_table extends table_sql implements renderable {
     private function format_plugin_summary_with_link(assign_plugin $plugin, stdClass $item, $returnaction, $returnparams) {
         $link = '';
         $showviewlink = false;
+
         $summary = $plugin->view_summary($item, $showviewlink);
         $separator = '';
         if ($showviewlink) {
@@ -550,6 +551,7 @@ class assign_grading_table extends table_sql implements renderable {
     function other_cols($colname, $row){
         if (($pos = strpos($colname, 'assignsubmission_')) !== false) {
             $plugin = $this->assignment->get_submission_plugin_by_type(substr($colname, strlen('assignsubmission_')));
+
             if ($plugin->is_visible() && $plugin->is_enabled()) {
                 if ($row->submissionid) {
                     $submission = new stdClass();
@@ -558,7 +560,6 @@ class assign_grading_table extends table_sql implements renderable {
                     $submission->timemodified = $row->timesubmitted;
                     $submission->assignment = $this->assignment->get_instance()->id;
                     $submission->userid = $row->userid;
-
                     return $this->format_plugin_summary_with_link($plugin, $submission, 'grading', array());
                 }
             }
@@ -567,6 +568,7 @@ class assign_grading_table extends table_sql implements renderable {
         if (($pos = strpos($colname, 'feedback_')) !== false) {
             $plugin = $this->assignment->get_feedback_plugin_by_type(substr($colname, strlen('assignfeedback_')));
             if ($plugin->is_visible() && $plugin->is_enabled()) {
+                $grade = null;
                 if ($row->gradeid) {
                     $grade = new stdClass();
                     $grade->id = $row->gradeid;
@@ -576,7 +578,10 @@ class assign_grading_table extends table_sql implements renderable {
                     $grade->userid = $row->userid;
                     $grade->grade = $row->grade;
                     $grade->mailed = $row->mailed;
-
+                }
+                if ($this->quickgrading && $plugin->supports_quickgrading()) {
+                    return $plugin->get_quickgrading_html($row->userid, $grade);
+                } else if ($grade) {
                     return $this->format_plugin_summary_with_link($plugin, $grade, 'grading', array());
                 }
             }
index 2211bb8..2ab70d6 100644 (file)
@@ -1126,7 +1126,7 @@ class assign {
         // Simple array we'll use for caching modules.
         $modcache = array();
 
-        // Email students about new feedback
+        // Message students about new feedback
         foreach ($submissions as $submission) {
 
             mtrace("Processing assignment submission $submission->id ...");
@@ -2377,7 +2377,7 @@ class assign {
     }
 
     /**
-     * email someone about something (static so it can be called from cron)
+     * Message someone about something (static so it can be called from cron)
      *
      * @param stdClass $userfrom
      * @param stdClass $userto
@@ -2426,7 +2426,7 @@ class assign {
     }
 
     /**
-     * email someone about something
+     * Message someone about something
      *
      * @param stdClass $userfrom
      * @param stdClass $userto
@@ -2440,13 +2440,13 @@ class assign {
     }
 
     /**
-     * Email student upon successful submission
+     * Notify student upon successful submission
      *
      * @global moodle_database $DB
      * @param stdClass $submission
      * @return void
      */
-    private function email_student_submission_receipt(stdClass $submission) {
+    private function notify_student_submission_receipt(stdClass $submission) {
         global $DB;
 
         $adminconfig = $this->get_admin_config();
@@ -2459,13 +2459,13 @@ class assign {
     }
 
     /**
-     * Email graders upon student submissions
+     * Send notifications to graders upon student submissions
      *
      * @global moodle_database $DB
      * @param stdClass $submission
      * @return void
      */
-    private function email_graders(stdClass $submission) {
+    private function notify_graders(stdClass $submission) {
         global $DB;
 
         $late = $this->get_instance()->duedate && ($this->get_instance()->duedate < time());
@@ -2505,8 +2505,8 @@ class assign {
             $submission->status = ASSIGN_SUBMISSION_STATUS_SUBMITTED;
             $this->update_submission($submission);
             $this->add_to_log('submit for grading', $this->format_submission_for_log($submission));
-            $this->email_graders($submission);
-            $this->email_student_submission_receipt($submission);
+            $this->notify_graders($submission);
+            $this->notify_student_submission_receipt($submission);
         }
     }
 
@@ -2531,17 +2531,20 @@ class assign {
 
         $users = array();
         // first check all the last modified values
-        // Using POST is really unfortunate. A better solution needs to be found here. As we are looking for grades students we could
+        $currentgroup = groups_get_activity_group($this->get_course_module(), true);
+        $participants = $this->list_participants($currentgroup, true);
+
         // gets a list of possible users and look for values based upon that.
-        foreach ($_POST as $key => $value) {
-            if (preg_match('#^grademodified_(\d+)$#', $key, $matches)) {
+        foreach ($participants as $userid => $unused) {
+            $modified = optional_param('grademodified_' . $userid, -1, PARAM_INT);
+            if ($modified >= 0) {
                 // gather the userid, updated grade and last modified value
                 $record = new stdClass();
-                $record->userid = (int)$matches[1];
-                $record->grade = required_param('quickgrade_' . $record->userid, PARAM_INT);
-                $record->lastmodified = clean_param($value, PARAM_INT);
-                $record->gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, array($record->userid));
-                $users[$record->userid] = $record;
+                $record->userid = $userid;
+                $record->grade = required_param('quickgrade_' . $userid, PARAM_INT);
+                $record->lastmodified = $modified;
+                $record->gradinginfo = grade_get_grades($this->get_course()->id, 'mod', 'assign', $this->get_instance()->id, array($userid));
+                $users[$userid] = $record;
             }
         }
         if (empty($users)) {
@@ -2561,6 +2564,7 @@ class assign {
         $modifiedusers = array();
         foreach ($currentgrades as $current) {
             $modified = $users[(int)$current->userid];
+            $grade = $this->get_user_grade($userid, false);
 
             // check to see if the outcomes were modified
             if ($CFG->enableoutcomes) {
@@ -2575,6 +2579,20 @@ class assign {
                 }
             }
 
+            // let plugins participate
+            foreach ($this->feedbackplugins as $plugin) {
+                if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->supports_quickgrading()) {
+                    if ($plugin->is_quickgrading_modified($modified->userid, $grade)) {
+                        if ((int)$current->lastmodified > (int)$modified->lastmodified) {
+                            return get_string('errorrecordmodified', 'assign');
+                        } else {
+                            $modifiedusers[$modified->userid] = $modified;
+                            continue;
+                        }
+                    }
+                }
+            }
+
 
             if (($current->grade < 0 || $current->grade === NULL) &&
                 ($modified->grade < 0 || $modified->grade === NULL)) {
@@ -2602,6 +2620,13 @@ class assign {
 
             $this->update_grade($grade);
 
+            // save plugins data
+            foreach ($this->feedbackplugins as $plugin) {
+                if ($plugin->is_visible() && $plugin->is_enabled() && $plugin->supports_quickgrading()) {
+                    $plugin->save_quickgrading_changes($userid, $grade);
+                }
+            }
+
             // save outcomes
             if ($CFG->enableoutcomes) {
                 $data = array();
@@ -2738,8 +2763,8 @@ class assign {
             $this->add_to_log('submit', $this->format_submission_for_log($submission));
 
             if (!$this->get_instance()->submissiondrafts) {
-                $this->email_student_submission_receipt($submission);
-                $this->email_graders($submission);
+                $this->notify_student_submission_receipt($submission);
+                $this->notify_graders($submission);
             }
             return true;
         }
index 5205435..334bd31 100644 (file)
@@ -114,6 +114,7 @@ if ($chapter) {
 } else {
     add_to_log($course->id, 'book', 'print', 'tool/print/index.php?id='.$cm->id, $book->id, $cm->id);
     $allchapters = $DB->get_records('book_chapters', array('bookid'=>$book->id), 'pagenum');
+    $book->intro = file_rewrite_pluginfile_urls($book->intro, 'pluginfile.php', $context->id, 'mod_book', 'intro', null);
 
     // page header
     ?>
index cb084ed..745ed34 100644 (file)
@@ -290,9 +290,9 @@ $string['notrackforum'] = 'Don\'t track unread posts';
 $string['noviewdiscussionspermission'] = 'You do not have the permission to view discussions in this forum';
 $string['nowallsubscribed'] = 'All forums in {$a} are subscribed.';
 $string['nowallunsubscribed'] = 'All forums in {$a} are not subscribed.';
-$string['nownotsubscribed'] = '{$a->name} will NOT receive copies of \'{$a->forum}\' by email.';
+$string['nownotsubscribed'] = '{$a->name} will NOT be notified of new posts in \'{$a->forum}\'';
 $string['nownottracking'] = '{$a->name} is no longer tracking \'{$a->forum}\'.';
-$string['nowsubscribed'] = '{$a->name} will receive copies of \'{$a->forum}\' by email.';
+$string['nowsubscribed'] = '{$a->name} will be notified of new posts in \'{$a->forum}\'';
 $string['nowtracking'] = '{$a->name} is now tracking \'{$a->forum}\'.';
 $string['numposts'] = '{$a} posts';
 $string['olderdiscussions'] = 'Older discussions';
@@ -376,7 +376,7 @@ $string['startedby'] = 'Started by';
 $string['subject'] = 'Subject';
 $string['subscribe'] = 'Subscribe to this forum';
 $string['subscribeall'] = 'Subscribe everyone to this forum';
-$string['subscribeenrolledonly'] = 'Sorry, only enrolled users are allowed to subscribe to receive forum postings by email.';
+$string['subscribeenrolledonly'] = 'Sorry, only enrolled users are allowed to subscribe to forum post notifications.';
 $string['subscribed'] = 'Subscribed';
 $string['subscribenone'] = 'Unsubscribe everyone from this forum';
 $string['subscribers'] = 'Subscribers';
@@ -422,8 +422,8 @@ $string['unreadpostsone'] = '1 unread post';
 $string['unsubscribe'] = 'Unsubscribe from this forum';
 $string['unsubscribeall'] = 'Unsubscribe from all forums';
 $string['unsubscribeallconfirm'] = 'You are subscribed to {$a} forums now. Do you really want to unsubscribe from all forums and disable forum auto-subscribe?';
-$string['unsubscribealldone'] = 'All your forum subscriptions were removed, you might still receive notifications from forums with forced subscription. If you do not want to receive any emails from this server please go to your profile and disable email address there.';
-$string['unsubscribeallempty'] = 'Sorry, you are not subscribed to any forums. If you do not want to receive any emails from this server please go to your profile and disable email address there.';
+$string['unsubscribealldone'] = 'All optional forum subscriptions were removed. You will still receive notifications from forums with forced subscription. To manage forum notifications go to Messaging in My Profile Settings.';
+$string['unsubscribeallempty'] = 'You are not subscribed to any forums. To disable all notifications from this server go to Messaging in My Profile Settings.';
 $string['unsubscribed'] = 'Unsubscribed';
 $string['unsubscribeshort'] = 'Unsubscribe';
 $string['usermarksread'] = 'Manual message read marking';
index 0f55205..0bb2bfc 100644 (file)
@@ -4611,6 +4611,63 @@ function forum_get_subscribed_forums($course) {
     }
 }
 
+/**
+ * Returns an array of forums that the current user is subscribed to and is allowed to unsubscribe from
+ *
+ * @return array An array of unsubscribable forums
+ */
+function forum_get_optional_subscribed_forums() {
+    global $USER, $DB;
+
+    // Get courses that $USER is enrolled in and can see
+    $courses = enrol_get_my_courses();
+    if (empty($courses)) {
+        return array();
+    }
+
+    $courseids = array();
+    foreach($courses as $course) {
+        $courseids[] = $course->id;
+    }
+    list($coursesql, $courseparams) = $DB->get_in_or_equal($courseids, SQL_PARAMS_NAMED, 'c');
+
+    // get all forums from the user's courses that they are subscribed to and which are not set to forced
+    $sql = "SELECT f.id, cm.id as cm, cm.visible
+              FROM {forum} f
+                   JOIN {course_modules} cm ON cm.instance = f.id
+                   JOIN {modules} m ON m.name = :modulename AND m.id = cm.module
+                   LEFT JOIN {forum_subscriptions} fs ON (fs.forum = f.id AND fs.userid = :userid)
+             WHERE f.forcesubscribe <> :forcesubscribe AND fs.id IS NOT NULL
+                   AND cm.course $coursesql";
+    $params = array_merge($courseparams, array('modulename'=>'forum', 'userid'=>$USER->id, 'forcesubscribe'=>FORUM_FORCESUBSCRIBE));
+    if (!$forums = $DB->get_records_sql($sql, $params)) {
+        return array();
+    }
+
+    $unsubscribableforums = array(); // Array to return
+
+    foreach($forums as $forum) {
+
+        if (empty($forum->visible)) {
+            // the forum is hidden
+            $context = context_module::instance($forum->cm);
+            if (!has_capability('moodle/course:viewhiddenactivities', $context)) {
+                // the user can't see the hidden forum
+                continue;
+            }
+        }
+
+        // subscribe.php only requires 'mod/forum:managesubscriptions' when
+        // unsubscribing a user other than yourself so we don't require it here either
+
+        // A check for whether the forum has subscription set to forced is built into the SQL above
+
+        $unsubscribableforums[] = $forum;
+    }
+
+    return $unsubscribableforums;
+}
+
 /**
  * Adds user to the subscriber list
  *
index a425c6b..f66ad26 100644 (file)
@@ -47,15 +47,20 @@ echo $OUTPUT->header();
 echo $OUTPUT->heading($strunsubscribeall);
 
 if (data_submitted() and $confirm and confirm_sesskey()) {
-    $DB->delete_records('forum_subscriptions', array('userid'=>$USER->id));
+    $forums = forum_get_optional_subscribed_forums();
+
+    foreach($forums as $forum) {
+        forum_unsubscribe($USER->id, $forum->id);
+    }
     $DB->set_field('user', 'autosubscribe', 0, array('id'=>$USER->id));
+
     echo $OUTPUT->box(get_string('unsubscribealldone', 'forum'));
     echo $OUTPUT->continue_button($return);
     echo $OUTPUT->footer();
     die;
 
 } else {
-    $a = $DB->count_records('forum_subscriptions', array('userid'=>$USER->id));
+    $a = count(forum_get_optional_subscribed_forums());
 
     if ($a) {
         $msg = get_string('unsubscribeallconfirm', 'forum', $a);
index 1e7e7c0..9fb94bb 100644 (file)
@@ -194,7 +194,7 @@ class quiz_grading_report extends quiz_default_report {
                 SELECT quiza.*, u.firstname, u.lastname, u.idnumber
                 FROM {quiz_attempts} quiza
                 JOIN {user} u ON u.id = quiza.userid
-                WHERE quiza.uniqueid $asql AND quiza.state == ? AND quiza.quiz = ?",
+                WHERE quiza.uniqueid $asql AND quiza.state = ? AND quiza.quiz = ?",
                 $params);
 
         $attempts = array();
index f9a1bf9..fc31e9b 100644 (file)
@@ -53,7 +53,11 @@ class core_notes_external extends external_api {
                             'publishstate' => new external_value(PARAM_ALPHA, '\'personal\', \'course\' or \'site\''),
                             'courseid' => new external_value(PARAM_INT, 'course id of the note (in Moodle a note can only be created into a course, even for site and personal notes)'),
                             'text' => new external_value(PARAM_RAW, 'the text of the message - text or HTML'),
-                            'format' => new external_value(PARAM_ALPHA, '\'text\' or \'html\'', VALUE_DEFAULT, 'text'),
+                            'format' => new external_value(PARAM_ALPHANUMEXT, // For backward compatibility it can not be PARAM_INT, so we don't use external_format_value.
+                                    'text format (' . FORMAT_HTML . ' = HTML, '
+                                    . FORMAT_MOODLE . ' = MOODLE, '
+                                    . FORMAT_PLAIN . ' = PLAIN or '
+                                    . FORMAT_MARKDOWN . ' = MARKDOWN)', VALUE_DEFAULT, FORMAT_HTML),
                             'clientnoteid' => new external_value(PARAM_ALPHANUMEXT, 'your own client id for the note. If this id is provided, the fail message id will be returned to you', VALUE_OPTIONAL),
                         )
                     )
@@ -130,18 +134,19 @@ class core_notes_external extends external_api {
                 $dbnote = new stdClass;
                 $dbnote->courseid = $note['courseid'];
                 $dbnote->userid = $note['userid'];
-                //clean param text and set format accordingly
+                // Need to support 'html' and 'text' format values for backward compatibility.
                 switch (strtolower($note['format'])) {
                     case 'html':
-                        $dbnote->content = clean_param($note['text'], PARAM_CLEANHTML);
-                        $dbnote->format = FORMAT_HTML;
+                        $textformat = FORMAT_HTML;
                         break;
                     case 'text':
+                        $textformat = FORMAT_PLAIN;
                     default:
-                        $dbnote->content = clean_param($note['text'], PARAM_TEXT);
-                        $dbnote->format = FORMAT_PLAIN;
+                        $textformat = external_validate_format($note['format']);
                         break;
                 }
+                $dbnote->content = $note['text'];
+                $dbnote->format = $textformat;
 
                 //get the state ('personal', 'course', 'site')
                 switch ($note['publishstate']) {
@@ -169,6 +174,9 @@ class core_notes_external extends external_api {
 
                 $resultnote['noteid'] = $success;
             } else {
+                // WARNINGS: for backward compatibility we return this errormessage.
+                //          We should have thrown exceptions as these errors prevent results to be returned.
+                // See http://docs.moodle.org/dev/Errors_handling_in_web_services#When_to_send_a_warning_on_the_server_side .
                 $resultnote['noteid'] = -1;
                 $resultnote['errormessage'] = $errormessage;
             }
index 63f8ba9..7b33e94 100644 (file)
@@ -16,7 +16,6 @@
         strict="false"
         verbose="false"
         printerClass="Hint_ResultPrinter"
-        printerFile="lib/phpunit/classes/hint_resultprinter.php"
         >
 
     <php>
index 9820246..02ce159 100644 (file)
@@ -124,7 +124,7 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
         $clientid = $this->get_config('clientid');
         $secret = $this->get_config('secret');
 
-        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_docs::REALM);
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl, google_docs::REALM);
     }
 
     public function instance_sanity_check() {
index d637b54..70200c1 100644 (file)
@@ -124,7 +124,7 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
         $clientid = $this->get_config('clientid');
         $secret = $this->get_config('secret');
 
-        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_picasa::REALM);
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl, google_picasa::REALM);
     }
 
     public function instance_sanity_check() {
index db41d98..ddfc224 100644 (file)
@@ -38,10 +38,16 @@ $popup      = optional_param('popup', 0, PARAM_INT); //==1 if in a popup window?
 list($context, $course, $cm) = get_context_info_array($contextid);
 require_login($course, false, $cm);
 
-$url = new moodle_url('/rating/index.php', array('contextid'=>$contextid,'itemid'=>$itemid,'scaleid'=>$scaleid));
-if ($sort !== 0) {
+$url = new moodle_url('/rating/index.php', array('contextid'=>$contextid,'component'=>$component,'itemid'=>$itemid,'scaleid'=>$scaleid));
+if (!empty($ratingarea)) {
+    $url->param('ratingarea', $ratingarea);
+}
+if (!empty($sort)) {
     $url->param('sort', $sort);
 }
+if (!empty($popup)) {
+    $url->param('popup', $popup);
+}
 $PAGE->set_url($url);
 $PAGE->set_context($context);
 
@@ -84,10 +90,9 @@ if (!$ratings) {
     $msg = get_string('noratings','rating');
     echo html_writer::tag('div', $msg, array('class'=>'mdl-align'));
 } else {
-    $sorturl  = new moodle_url('/index.php', array('contextid' => $contextid, 'itemid' => $itemid, 'scaleid' => $scaleid));
-    if ($popup) {
-        $sorturl->param('popup', $popup);
-    }
+    // To get the sort URL, copy the current URL and remove any previous sort
+    $sorturl = new moodle_url($url);
+    $sorturl->remove_params('sort');
 
     $table = new html_table;
     $table->cellpadding = 3;
index 58f79e1..4cda0af 100644 (file)
@@ -30,5 +30,5 @@ $string['pluginname'] = 'Dropbox';
 $string['apikey'] = 'Dropbox API key';
 $string['dropbox'] = 'Dropbox';
 $string['secret'] = 'Dropbox secret';
-$string['instruction'] = 'You can get your API Key and secret from <a href="http://www.dropbox.com/developers/apps">Dropbox developers</a>';
+$string['instruction'] = 'You can get your API Key and secret from <a href="http://www.dropbox.com/developers/apps">Dropbox developers</a>. When setting up your key please select "Full Dropbox" as the "Access level".';
 $string['dropbox:view'] = 'View a Dropbox folder';
index 3c79232..335f4c9 100644 (file)
@@ -443,6 +443,17 @@ YUI.add('moodle-core_filepicker', function(Y) {
         }
 
     }
+
+    /**
+     * creates a node and adds it to the div with id #filesskin. This is needed for CSS to be able
+     * to overwrite YUI skin styles (instead of using !important that does not work in IE)
+     */
+    Y.Node.createWithFilesSkin = function(node) {
+        if (!Y.one('#filesskin')) {
+            Y.one(document.body).appendChild(Y.Node.create('<div/>').set('id', 'filesskin'));
+        }
+        return Y.one('#filesskin').appendChild(Y.Node.create(node));
+    }
 }, '@VERSION@', {
     requires:['base', 'node', 'yui2-treeview', 'panel', 'cookie', 'datatable', 'datatable-sort']
 });
@@ -692,10 +703,9 @@ M.core_filepicker.init = function(Y, options) {
                 this.selectui.hide();
             }
             if (!this.process_dlg) {
-                this.process_dlg_node = Y.Node.create(M.core_filepicker.templates.processexistingfile);
+                this.process_dlg_node = Y.Node.createWithFilesSkin(M.core_filepicker.templates.processexistingfile);
                 var node = this.process_dlg_node;
                 node.generateID();
-                Y.one(document.body).appendChild(node);
                 this.process_dlg = new Y.Panel({
                     srcNode      : node,
                     headerContent: M.str.repository.fileexistsdialogheader,
@@ -736,9 +746,8 @@ M.core_filepicker.init = function(Y, options) {
                 header = M.str.moodle.info;
             }
             if (!this.msg_dlg) {
-                this.msg_dlg_node = Y.Node.create(M.core_filepicker.templates.message);
+                this.msg_dlg_node = Y.Node.createWithFilesSkin(M.core_filepicker.templates.message);
                 this.msg_dlg_node.generateID();
-                Y.one(document.body).appendChild(this.msg_dlg_node);
 
                 this.msg_dlg = new Y.Panel({
                     srcNode      : this.msg_dlg_node,
@@ -1215,10 +1224,8 @@ M.core_filepicker.init = function(Y, options) {
         },
         render: function() {
             var client_id = this.options.client_id;
-            this.fpnode = Y.Node.create(M.core_filepicker.templates.generallayout).
+            this.fpnode = Y.Node.createWithFilesSkin(M.core_filepicker.templates.generallayout).
                 set('id', 'filepicker-'+client_id);
-            this.selectnode = Y.Node.create(M.core_filepicker.templates.selectlayout);
-            Y.one(document.body).appendChild(this.fpnode);
             this.mainui = new Y.Panel({
                 srcNode      : this.fpnode,
                 headerContent: M.str.repository.filepicker,
@@ -1239,9 +1246,8 @@ M.core_filepicker.init = function(Y, options) {
                 this.mainui.set('y', 0);
             }
             // create panel for selecting a file (initially hidden)
-            this.selectnode = Y.Node.create(M.core_filepicker.templates.selectlayout).
+            this.selectnode = Y.Node.createWithFilesSkin(M.core_filepicker.templates.selectlayout).
                 set('id', 'filepicker-select-'+client_id);
-            Y.one(document.body).appendChild(this.selectnode);
             this.selectui = new Y.Panel({
                 srcNode      : this.selectnode,
                 zIndex       : 600000,
index 6ccb33b..df0f23e 100644 (file)
@@ -39,12 +39,14 @@ class repository_googledocs extends repository {
     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
         parent::__construct($repositoryid, $context, $options);
 
-        $returnurl = new moodle_url('/repository/repository_callback.php',
-            array('callback' => 'yes', 'repo_id' =>$this->id));
+        $returnurl = new moodle_url('/repository/repository_callback.php');
+        $returnurl->param('callback', 'yes');
+        $returnurl->param('repo_id', $this->id);
+        $returnurl->param('sesskey', sesskey());
 
         $clientid = get_config('googledocs', 'clientid');
         $secret = get_config('googledocs', 'secret');
-        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_docs::REALM);
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl, google_docs::REALM);
 
         $this->check_login();
     }
index 3abca8d..5f72baf 100644 (file)
@@ -648,13 +648,14 @@ abstract class repository {
      * This function is used to copy a moodle file to draft area
      *
      * @param string $encoded The metainfo of file, it is base64 encoded php serialized data
-     * @param int $draftitemid itemid
-     * @param string $new_filepath the new path in draft area
-     * @param string $new_filename The intended name of file
+     * @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
+     *      attributes of the new file
+     * @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
+     *      the limit, the file_exception is thrown.
      * @return array The information of file
      */
-    public function copy_to_area($encoded, $draftitemid, $new_filepath, $new_filename) {
-        global $USER, $DB;
+    public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
+        global $USER;
         $fs = get_file_storage();
         $browser = get_file_browser();
 
@@ -662,9 +663,17 @@ abstract class repository {
             throw new coding_exception('Only repository used to browse moodle files can use repository::copy_to_area()');
         }
 
-
         $params = unserialize(base64_decode($encoded));
-        $user_context = get_context_instance(CONTEXT_USER, $USER->id);
+        $user_context = context_user::instance($USER->id);
+
+        $filerecord = (array)$filerecord;
+        // make sure the new file will be created in user draft area
+        $filerecord['component'] = 'user';
+        $filerecord['filearea'] = 'draft';
+        $filerecord['contextid'] = $user_context->id;
+        $draftitemid = $filerecord['itemid'];
+        $new_filepath = $filerecord['filepath'];
+        $new_filename = $filerecord['filename'];
 
         $contextid  = clean_param($params['contextid'], PARAM_INT);
         $fileitemid = clean_param($params['itemid'],    PARAM_INT);
@@ -676,11 +685,15 @@ abstract class repository {
         $context    = get_context_instance_by_id($contextid);
         // the file needs to copied to draft area
         $file_info  = $browser->get_file_info($context, $component, $filearea, $fileitemid, $filepath, $filename);
+        if ($maxbytes !== -1 && $file_info->get_filesize() > $maxbytes) {
+            throw new file_exception('maxbytes');
+        }
 
         if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
             // create new file
             $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
-            $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $unused_filename);
+            $filerecord['filename'] = $unused_filename;
+            $file_info->copy_to_storage($filerecord);
             $event = array();
             $event['event'] = 'fileexists';
             $event['newfile'] = new stdClass;
@@ -690,12 +703,13 @@ abstract class repository {
             $event['existingfile'] = new stdClass;
             $event['existingfile']->filepath = $new_filepath;
             $event['existingfile']->filename = $new_filename;
-            $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $filepath, $filename)->out();;
+            $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
             return $event;
         } else {
-            $file_info->copy_to_storage($user_context->id, 'user', 'draft', $draftitemid, $new_filepath, $new_filename);
+            $file_info->copy_to_storage($filerecord);
             $info = array();
             $info['itemid'] = $draftitemid;
+            $info['file']  = $new_filename;
             $info['title']  = $new_filename;
             $info['contextid'] = $user_context->id;
             $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
@@ -1464,6 +1478,7 @@ abstract class repository {
      * @return int file size in bytes
      */
     public function get_file_size($source) {
+        // TODO MDL-33297 remove this function completely?
         $browser    = get_file_browser();
         $params     = unserialize(base64_decode($source));
         $contextid  = clean_param($params['contextid'], PARAM_INT);
index 9022380..0d0b63c 100644 (file)
@@ -41,12 +41,14 @@ class repository_picasa extends repository {
     public function __construct($repositoryid, $context = SYSCONTEXTID, $options = array()) {
         parent::__construct($repositoryid, $context, $options);
 
-        $returnurl = new moodle_url('/repository/repository_callback.php',
-            array('callback' => 'yes', 'repo_id' =>$this->id));
+        $returnurl = new moodle_url('/repository/repository_callback.php');
+        $returnurl->param('callback', 'yes');
+        $returnurl->param('repo_id', $this->id);
+        $returnurl->param('sesskey', sesskey());
 
         $clientid = get_config('picasa', 'clientid');
         $secret = get_config('picasa', 'secret');
-        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl->out(false), google_picasa::REALM);
+        $this->googleoauth = new google_oauth($clientid, $secret, $returnurl, google_picasa::REALM);
 
         $this->check_login();
     }
index a491015..2c1acf2 100644 (file)
@@ -180,19 +180,28 @@ class repository_recent extends repository {
     /**
      * This function overwrite the default implement to copying file using file_storage
      *
-     * @global object $USER
-     * @global object $DB
      * @param string $encoded The information of file, it is base64 encoded php serialized data
-     * @param string $draftitemid itemid
-     * @param string $new_filename The intended name of file
-     * @param string $new_filepath the new path in draft area
+     * @param stdClass|array $filerecord contains itemid, filepath, filename and optionally other
+     *      attributes of the new file
+     * @param int $maxbytes maximum allowed size of file, -1 if unlimited. If size of file exceeds
+     *      the limit, the file_exception is thrown.
      * @return array The information of file
      */
-    public function copy_to_area($encoded, $draftitemid, $new_filepath, $new_filename) {
-        global $USER, $DB;
+    public function copy_to_area($encoded, $filerecord, $maxbytes = -1) {
+        global $USER;
 
         $user_context = get_context_instance(CONTEXT_USER, $USER->id);
 
+        $filerecord = (array)$filerecord;
+        // make sure the new file will be created in user draft area
+        $filerecord['component'] = 'user'; // make sure
+        $filerecord['filearea'] = 'draft'; // make sure
+        $filerecord['contextid'] = $user_context->id;
+        $filerecord['sortorder'] = 0;
+        $draftitemid = $filerecord['itemid'];
+        $new_filepath = $filerecord['filepath'];
+        $new_filename = $filerecord['filename'];
+
         $fs = get_file_storage();
 
         $params = unserialize(base64_decode($encoded));
@@ -211,21 +220,23 @@ class repository_recent extends repository {
         //
         // To get 'recent' plugin working, we need to use lower level file_stoarge class to bypass the
         // capability check, we will use a better workaround to improve it.
+        // TODO MDL-33297 apply here
         if ($stored_file = $fs->get_file($contextid, $component, $filearea, $fileitemid, $filepath, $filename)) {
             // verify user id
             if ($USER->id != $stored_file->get_userid()) {
                 throw new moodle_exception('errornotyourfile', 'repository');
             }
-            $file_record = array('contextid'=>$user_context->id, 'component'=>'user', 'filearea'=>'draft',
-                'itemid'=>$draftitemid, 'filepath'=>$new_filepath, 'filename'=>$new_filename, 'sortorder'=>0);
+            if ($maxbytes !== -1 && $stored_file->get_filesize() > $maxbytes) {
+                throw new file_exception('maxbytes');
+            }
 
             // test if file already exists
             if (repository::draftfile_exists($draftitemid, $new_filepath, $new_filename)) {
                 // create new file
                 $unused_filename = repository::get_unused_filename($draftitemid, $new_filepath, $new_filename);
-                $file_record['filename'] = $unused_filename;
+                $filerecord['filename'] = $unused_filename;
                 // create a tmp file
-                $fs->create_file_from_storedfile($file_record, $stored_file);
+                $fs->create_file_from_storedfile($filerecord, $stored_file);
                 $event = array();
                 $event['event'] = 'fileexists';
                 $event['newfile'] = new stdClass;
@@ -238,9 +249,10 @@ class repository_recent extends repository {
                 $event['existingfile']->url      = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
                 return $event;
             } else {
-                $fs->create_file_from_storedfile($file_record, $stored_file);
+                $fs->create_file_from_storedfile($filerecord, $stored_file);
                 $info = array();
                 $info['title']  = $new_filename;
+                $info['file']  = $new_filename;
                 $info['itemid'] = $draftitemid;
                 $info['filesize']  = $stored_file->get_filesize();
                 $info['url'] = moodle_url::make_draftfile_url($draftitemid, $new_filepath, $new_filename)->out();;
index aa1e434..240faf3 100644 (file)
@@ -209,30 +209,6 @@ switch ($action) {
             die;
         } else {
             $fs = get_file_storage();
-            // Some repository plugins are hosting moodle internal files, we cannot use get_file
-            // method, so we use copy_to_area method
-            // (local, user, coursefiles, recent)
-            if ($repo->has_moodle_files() && !$usefilereference) {
-                // check filesize against max allowed size
-                $filesize = $repo->get_file_size($source);
-                if (empty($filesize)) {
-                    $filesize = 0;
-                }
-                if (($maxbytes !== -1) && ($filesize > $maxbytes)) {
-                    throw new file_exception('maxbytes');
-                }
-                // If the moodle file is an alias to a file in external repository
-                // we copy this alias instead of create alias to alias
-                // {@link repository::copy_to_area()}.
-                $fileinfo = $repo->copy_to_area($source, $itemid, $saveas_path, $saveas_filename);
-
-                if (!isset($fileinfo['event'])) {
-                    $fileinfo['file'] = $fileinfo['title'];
-                }
-
-                echo json_encode($fileinfo);
-                die;
-            }
 
             // Prepare file record.
             $record = new stdClass();
@@ -240,21 +216,9 @@ switch ($action) {
             $record->filename = $saveas_filename;
             $record->component = 'user';
             $record->filearea = 'draft';
-            if (!is_numeric($itemid)) {
-                $record->itemid = 0;
-            } else {
-                $record->itemid   = $itemid;
-            }
-            if (!empty($file['license'])) {
-                $record->license  = $file['license'];
-            } else {
-                $record->license  = $license;
-            }
-            if (!empty($file['author'])) {
-                $record->author   = $file['author'];
-            } else {
-                $record->author   = $author;
-            }
+            $record->itemid = $itemid;
+            $record->license = $license;
+            $record->author = $author;
 
             if ($record->filepath !== '/') {
                 $record->filepath = trim($record->filepath, '/');
@@ -263,10 +227,9 @@ switch ($action) {
             $usercontext = get_context_instance(CONTEXT_USER, $USER->id);
             $now = time();
             $record->contextid = $usercontext->id;
-            $record->timecreated  = $now;
+            $record->timecreated = $now;
             $record->timemodified = $now;
-            $record->userid       = $USER->id;
-
+            $record->userid = $USER->id;
 
             if ($usefilereference) {
                 $reference = $repo->get_file_reference($source);
@@ -291,21 +254,30 @@ switch ($action) {
                     $event['existingfile']->filepath = $saveas_path;
                     $event['existingfile']->filename = $saveas_filename;
                     $event['existingfile']->url      = moodle_url::make_draftfile_url($itemid, $saveas_path, $saveas_filename)->out();;
-                    echo json_encode($event);
-                    die;
+                } else {
+                    $storedfile = $fs->create_file_from_reference($record, $repo_id, $reference);
+                    $event = array(
+                        'url'=>moodle_url::make_draftfile_url($storedfile->get_itemid(), $storedfile->get_filepath(), $storedfile->get_filename())->out(),
+                        'id'=>$storedfile->get_itemid(),
+                        'file'=>$storedfile->get_filename(),
+                        'icon' => $OUTPUT->pix_url(file_file_icon($storedfile, 32))->out(),
+                    );
                 }
-                $storedfile = $fs->create_file_from_reference($record, $repo_id, $reference);
                 // Repository plugin callback
                 // You can cache reository file in this callback
                 // or complete other tasks.
                 $repo->cache_file_by_reference($reference, $storedfile);
-                $info = array(
-                    'url'=>moodle_url::make_draftfile_url($storedfile->get_itemid(), $storedfile->get_filepath(), $storedfile->get_filename())->out(),
-                    'id'=>$storedfile->get_itemid(),
-                    'file'=>$storedfile->get_filename(),
-                    'icon' => $OUTPUT->pix_url(file_file_icon($storedfile, 32))->out(),
-                );
-                echo json_encode($info);
+                echo json_encode($event);
+                die;
+            } else if ($repo->has_moodle_files()) {
+                // Some repository plugins (local, user, coursefiles, recent) are hosting moodle
+                // internal files, we cannot use get_file method, so we use copy_to_area method
+
+                // If the moodle file is an alias we copy this alias, otherwise we copy the file
+                // {@link repository::copy_to_area()}.
+                $fileinfo = $repo->copy_to_area($source, $record, $maxbytes);
+
+                echo json_encode($fileinfo);
                 die;
             } else {
                 // Download file to moodle.
index fa7eaf3..a307ab6 100644 (file)
@@ -171,7 +171,7 @@ class repository_upload extends repository {
 
         if ($this->mimetypes != '*') {
             // check filetype
-            $filemimetype = file_storage::mimetype($_FILES[$elname]['tmp_name']);
+            $filemimetype = file_storage::mimetype($_FILES[$elname]['tmp_name'], $record->filename);
             if (!in_array($filemimetype, $this->mimetypes)) {
                 throw new moodle_exception('invalidfiletype', 'repository', '', get_mimetype_description(array('filename' => $_FILES[$elname]['name'])));
             }
index df0995e..5a5fc1a 100644 (file)
@@ -159,7 +159,7 @@ input.titleeditor {
 }
 
 /* Course drag and drop upload styles */
-#dndupload-status {width:60%;margin:0 auto;padding:2px;border:1px solid #ddd;text-align:center;background:#ffc}
+#dndupload-status {width:40%;margin:0 30%;padding:6px;border:1px solid #ddd;text-align:center;background:#ffc;position:absolute;z-index:9999;box-shadow:2px 2px 5px 1px #ccc;border-radius:0px 0px 8px 8px;}
 .dndupload-preview {color:#909090;border:1px dashed #909090;}
 .dndupload-progress-outer {width:70px;border:solid black 1px;height:10px;display:inline-block;margin:0;padding:0;overflow:hidden;position:relative;}
 .dndupload-progress-inner {width:0%;height:100%;background-color:green;display:inline-block;margin:0;padding:0;float:left;}
index 5067068..b6ed919 100644 (file)
@@ -2,12 +2,12 @@
  * File Picker and File Manager
  */
 
-.filemanager, .file-picker {font-size:11px;color: #555;letter-spacing: .2px;}
-.filemanager a, .file-picker a {color:#555;}
-.filemanager a:hover, .file-picker a:hover {color:#555;text-decoration: none;}
+.filemanager, .file-picker {font-size:11px;color: #555555;letter-spacing: .2px;}
+.filemanager a, .file-picker a {color:#555555;}
+.filemanager a:hover, .file-picker a:hover {color:#555555;text-decoration: none;}
 .filemanager select, .filemanager input, .filemanagerbutton, .filemanager textarea,
-.file-picker select, .file-picker input, .file-picker button, .file-picker textarea {color:#555; letter-spacing: .2px;}
-.filemanager input[type="text"], .file-picker input[type="text"] {border: 1px solid #BBB;width: 265px;height: 18px;padding: 1px 6px;}
+.file-picker select, .file-picker input, .file-picker button, .file-picker textarea {color:#555555; letter-spacing: .2px;}
+.filemanager input[type="text"], .file-picker input[type="text"] {border: 1px solid #BBBBBB;width: 265px;height: 18px;padding: 1px 6px;}
 .filemanager select, .file-picker select {height: 22px;padding: 2px 1px;}
 .fp-content-center {height: 100%;width: 100%;display:table-cell;vertical-align: middle;}
 
  * Dialogue (File Picker and File Manager)
  */
 .yui3-panel-focused {outline: none;}
-.yui3-panel-content {padding-bottom: 20px!important;background: #F2F2F2!important;border-radius: 8px;border: 1px solid #FFF!important;display: inline-block;-webkit-box-shadow: 5px 5px 20px 0px #666!important;-moz-box-shadow: 5px 5px 20px 0px #666!important;box-shadow: 5px 5px 20px 0px #666!important;}
-.yui3-widget-hd {border-radius: 10px 10px 0px 0px;border-bottom: 1px solid #BBB;padding:5px 5px 5px 5px!important;text-align: center;font-size:12px;letter-spacing: 1px;color:#333!important; text-shadow: 1px 1px 1px #FFF;filter: dropshadow(color=#FFF, offx=1, offy=1);
-background: #CCC!important;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFF', endColorstr='#CCC')!important;background: -webkit-gradient(linear, left top, left bottom, from(#FFF), to(#CCC))!important;background: -moz-linear-gradient(top,  #FFF,  #CCC)!important;}
-.fp-panel-button {background: #FFF;padding: 3px 20px 2px 20px; text-align: center;margin:10px; border-radius: 10px;display: inline-block;-webkit-box-shadow: 2px 2px 3px .1px #999;-moz-box-shadow: 2px 2px 3px .1px #999;box-shadow: 2px 2px 3px .1px #999;}
+#filesskin .yui3-panel-content {padding-bottom: 20px;background: #F2F2F2;border-radius: 8px;border: 1px solid #FFFFFF;display: inline-block;-webkit-box-shadow: 5px 5px 20px 0px #666666;-moz-box-shadow: 5px 5px 20px 0px #666666;box-shadow: 5px 5px 20px 0px #666666;}
+#filesskin .yui3-widget-hd {border-radius: 10px 10px 0px 0px;border-bottom: 1px solid #BBBBBB;padding:5px 5px 5px 5px;text-align: center;font-size:12px;letter-spacing: 1px;color:#333333; text-shadow: 1px 1px 1px #FFFFFF;filter: dropshadow(color=#FFFFFF, offx=1, offy=1);
+background: #CCCCCC;filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#CCCCCC');background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));background: -moz-linear-gradient(top,  #FFFFFF,  #CCCCCC);}
+.fp-panel-button {background: #FFFFFF;padding: 3px 20px 2px 20px; text-align: center;margin:10px; border-radius: 10px;display: inline-block;-webkit-box-shadow: 2px 2px 3px .1px #999999;-moz-box-shadow: 2px 2px 3px .1px #999999;box-shadow: 2px 2px 3px .1px #999999;}
 
 /*
  * File Picker layout
  */
-.file-picker.fp-generallayout {width: 724px;background: #FFF!important;border-radius:10px;border: 1px solid #CCC!important;position: relative;}
-.file-picker .fp-repo-area {width:180px;overflow:auto;display:inline-block;border-right:1px solid #BBB;position:absolute;top:26px;bottom:1px;}
+#filesskin .file-picker.fp-generallayout {width: 724px;background: #FFFFFF;border-radius:10px;border: 1px solid #CCCCCC;position: relative;}
+.file-picker .fp-repo-area {width:180px;overflow:auto;display:inline-block;border-right:1px solid #BBBBBB;position:absolute;top:26px;bottom:1px;}
 .file-picker .fp-repo-items {vertical-align:top;display: inline-block;margin-left: 181px;}
-.file-picker .fp-navbar {background: #F2F2F2;min-height:22px;border-bottom: 1px solid #BBB;padding: 5px 8px;}
-.file-picker .fp-content {background: #FFF;clear: both;overflow:auto;width: 543px;height: 349px;margin-bottom:-14px;}
+.file-picker .fp-navbar {background: #F2F2F2;min-height:22px;border-bottom: 1px solid #BBBBBB;padding: 5px 8px;}
+.file-picker .fp-content {background: #FFFFFF;clear: both;overflow:auto;width: 543px;height: 349px;margin-bottom:-14px;}
 .file-picker .fp-content-loading {height: 100%;width: 100%;display: table;text-align:center;}
 .file-picker .fp-content .fp-object-container {width:98%;height:98%;}
 
@@ -38,23 +38,20 @@ background: #CCC!important;filter: progid:DXImageTransform.Microsoft.gradient(st
 .dir-rtl .file-picker .fp-list {text-align:right;}
 .file-picker .fp-list .fp-repo a{display:block;padding:.5em .7em;}
 .file-picker .fp-list .fp-repo.active {background:#F2F2F2;}
-.file-picker .fp-repo-icon {padding: 0px 7px 0px 5px;}
+.file-picker .fp-list .fp-repo-icon {padding: 0px 7px 0px 5px;}
 
 /*
  * Tools, Path & View on fp-navbar (File Picker and File Manager)
  */
-.fp-toolbar {/*display: table-row;*/display: block;line-height: 22px;float:left;}
+.fp-toolbar {display: table-row;line-height: 22px;float:left;/*display: inline-block;*/}
 .fp-toolbar.empty {display:none;}
 .fp-toolbar .disabled {display:none;}
 .fp-toolbar div {display: inline-block;padding: 0px 2px;padding-right: 10px;}
 .fp-toolbar img {vertical-align: -15%; margin-right: 5px;}
-.file-picker .search-entry {background:#FFF url('[[pix:a/search]]') no-repeat 3px 3px;height:18px;width:230px;border: 1px solid #BBB;padding-left:20px;}
+.fp-toolbar .fp-tb-search {width: 228px;height: 14px;}
+.fp-toolbar .fp-tb-search input {background:#FFFFFF url('[[pix:a/search]]') no-repeat 3px 3px;padding: 2px 6px 1px 20px;width: 200px;height: 16px;border: 1px solid #BBBBBB;}
 
-.file-picker .fp-pathbar {display: table-row;}
-.fp-pathbar .fp-path-folder {background:url('[[pix:theme|fp/path_folder]]') no-repeat 0 0;width:27px;height:12px;margin-left: 4px;}
-.fp-pathbar .fp-path-folder-name {margin-left: 32px;line-height: 20px;}
-
-.fp-viewbar {float:right;width:69px;height:22px;margin-right:8px;}
+.fp-viewbar {float:right;width:69px;height:22px;margin-right:8px;/*display: inline-block;*/}
 .fp-vb-icons {background:url('[[pix:theme|fp/view_icon_active]]') no-repeat 0 0;width:22px;height:22px;display: inline-block;}
 .fp-vb-icons.checked {background:url('[[pix:theme|fp/view_icon_selected]]');}
 .fp-viewbar.disabled .fp-vb-icons {background:url('[[pix:theme|fp/view_icon_inactive]]');}
@@ -64,29 +61,31 @@ background: #CCC!important;filter: progid:DXImageTransform.Microsoft.gradient(st
 .fp-vb-tree {background:url('[[pix:theme|fp/view_tree_active]]') no-repeat 0px 0px;width:23px;height:22px;display: inline-block;margin-left: -4px;}
 .fp-vb-tree.checked {background:url('[[pix:theme|fp/view_tree_selected]]');}
 .fp-viewbar.disabled .fp-vb-tree {background:url('[[pix:theme|fp/view_tree_inactive]]');}
-.file-picker .fp-clear-right {clear: right;}
+.file-picker .fp-clear-left {clear: left;}
+
+.file-picker .fp-pathbar {display: table-row;/*display: inline-block;*/}
+.fp-pathbar.empty {display: none;}
+.fp-pathbar .fp-path-folder {background:url('[[pix:theme|fp/path_folder]]') no-repeat 0 0;width:27px;height:12px;margin-left: 4px;}
+.fp-pathbar .fp-path-folder-name {margin-left: 32px;line-height: 20px;}
 
 /*
  * Icon view (File Picker and File Manager)
  */
 .fp-iconview .fp-file {float: left;text-align: center;position: relative;margin: 10px 10px 35px;}
-.fp-iconview .fp-thumbnail {min-width:110px;min-height:110px;line-height: 110px;text-align: center;border: 1px solid #FFF;}
-.fp-iconview .fp-thumbnail img {border: 1px solid #DDD;padding:3px;vertical-align: middle;-webkit-box-shadow: 1px 1px 2px 0px #CCC;-moz-box-shadow: 1px 1px 2px 0px #CCC;box-shadow: 1px 1px 2px 0px #CCC;}
-.fp-iconview .fp-thumbnail:hover {background: #FFF;border: 1px solid #DDD;-webkit-box-shadow: inset 0px 0px 10px 0px #CCC;-moz-box-shadow: inset 0px 0px 10px 0px #CCC;box-shadow: inset 0px 0px 10px 0px #CCC;}
+.fp-iconview .fp-thumbnail {min-width:110px;min-height:110px;line-height: 110px;text-align: center;border: 1px solid #FFFFFF;display: block;}
+.fp-iconview .fp-thumbnail img {border: 1px solid #DDDDDD;padding:3px;vertical-align: middle;-webkit-box-shadow: 1px 1px 2px 0px #CCCCCC;-moz-box-shadow: 1px 1px 2px 0px #CCCCCC;box-shadow: 1px 1px 2px 0px #CCCCCC;}
+.fp-iconview .fp-thumbnail:hover {background: #FFFFFF;border: 1px solid #DDDDDD;-webkit-box-shadow: inset 0px 0px 10px 0px #CCCCCC;-moz-box-shadow: inset 0px 0px 10px 0px #CCCCCC;box-shadow: inset 0px 0px 10px 0px #CCCCCC;}
 .fp-iconview .fp-filename-field {height:33px;word-wrap:break-word;overflow: hidden;position: absolute;}
 .fp-iconview .fp-filename-field:hover {overflow: visible;z-index: 1000;}
-.fp-iconview .fp-filename-field .fp-filename {background: #FFF;padding-top: 5px;padding-bottom: 12px;min-width:112px;}
+.fp-iconview .fp-filename-field .fp-filename {background: #FFFFFF;padding-top: 5px;padding-bottom: 12px;min-width:112px;}
 
 /*
  * Table view (File Picker only)
  */
-.file-picker .yui3-datatable table {border: 0px solid #BBB;width:100%;}
-.file-picker .yui3-datatable-header {background: #FFF;border-bottom: 1px solid #CCC;border-left: 0 solid #FFF;color: #555;}
-.file-picker .yui3-datatable-columns .yui3-datatable-sorted, .file-picker .yui3-datatable-sortable-column:hover {background-color: #FFF;}
-.file-picker .yui3-datatable-odd .yui3-datatable-cell {background-color: #F6F6F6;border-left: 0px solid #F6F6F6;}
-.file-picker .yui3-datatable-data .yui3-datatable-odd .yui3-datatable-sorted {background-color: #F6F6F6;}
-.file-picker .yui3-datatable-even .yui3-datatable-cell {background-color: #FFF;border-left: 0px solid #FFF;}
-.file-picker .yui3-datatable-data .yui3-datatable-even .yui3-datatable-sorted {background-color: #FFF;}
+.file-picker .yui3-datatable table {border: 0px solid #BBBBBB;width:100%;}
+#filesskin .file-picker .yui3-datatable-header {background: #FFFFFF;border-bottom: 1px solid #CCCCCC;border-left: 0 solid #FFFFFF;color: #555555;}
+#filesskin .file-picker .yui3-datatable-odd .yui3-datatable-cell {background-color: #F6F6F6;border-left: 0px solid #F6F6F6;}
+#filesskin .file-picker .yui3-datatable-even .yui3-datatable-cell {background-color: #FFFFFF;border-left: 0px solid #FFFFFF;}
 
 /*
  * Tree view (File Manager only)
@@ -127,9 +126,9 @@ background: #CCC!important;filter: progid:DXImageTransform.Microsoft.gradient(st
 .filemanager .ygtvlabel,.filemanager .ygtvlabel:link,.filemanager .ygtvlabel:visited,.filemanager .ygtvlabel:hover {margin-left:2px;text-decoration: none;}*/
 a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .ygtvlabel, .ygtvlabel:link, .ygtvlabel:visited, .ygtvlabel:hover {background-color: transparent;cursor: pointer;margin-left: 2px;text-decoration: none;}
-.file-picker .ygtvfocus, .filemanager .ygtvfocus {background-color: #EEE;}
+.file-picker .ygtvfocus, .filemanager .ygtvfocus {background-color: #EEEEEE;}
 
-.fp-filename-icon {margin-top: 10px;display: block;/*top: -10px;position: relative;*/}
+.fp-filename-icon {margin-top: 10px;display: block;position: relative;}
 .fp-icon {float: left;margin-top: -7px;width: 24px;height: 24px;margin-right: 10px;text-align: center;line-height: 24px;}
 .fp-icon img {max-height:24px;max-width:24px;vertical-align: middle;}
 .fp-filename {padding-right: 10px;}
@@ -184,14 +183,14 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
  */
 .file-picker.fp-select {width:420px;}
 .fp-select .fp-select-loading {text-align: center;margin-top: 20px;}
-.fp-select .fp-hr {clear: both;height: 1px; background-color: #FFF;border-bottom: 1px solid #BBB;width: auto; margin: 5px 20px;}
+.fp-select .fp-hr {clear: both;height: 1px; background-color: #FFFFFF;border-bottom: 1px solid #BBBBBB;width: auto; margin: 5px 20px;}
 .fp-select table {margin: 10px 20px;}
 .fp-select-update {float:right;margin-right: 20px;}
 .fp-select .fp-file-update {background:url('[[pix:theme|fp/check]]') no-repeat left center;width:17px;height:17px;}
 .fp-select .fp-file-cancel {background:url('[[pix:theme|fp/cross]]') no-repeat left center;width:17px;height:17px;margin-left: 25px;}
 .fp-select .fp-select-update span {margin-left: 17px;}
-.fp-select .fp-thumbnail {float:left;min-width:110px;min-height:110px;line-height: 110px;text-align: center;margin: 10px 20px 0px 20px;background: #FFF;border: 1px solid #DDD;-webkit-box-shadow: inset 0px 0px 10px 0px #CCC;-moz-box-shadow: inset 0px 0px 10px 0px #CCC;box-shadow: inset 0px 0px 10px 0px #CCC;}
-.fp-select .fp-thumbnail img {border: 1px solid #DDD;padding:3px;vertical-align: middle;margin: 10px;}
+.fp-select .fp-thumbnail {float:left;min-width:110px;min-height:110px;line-height: 110px;text-align: center;margin: 10px 20px 0px 20px;background: #FFFFFF;border: 1px solid #DDDDDD;-webkit-box-shadow: inset 0px 0px 10px 0px #CCCCCC;-moz-box-shadow: inset 0px 0px 10px 0px #CCCCCC;box-shadow: inset 0px 0px 10px 0px #CCCCCC;}
+.fp-select .fp-thumbnail img {border: 1px solid #DDDDDD;padding:3px;vertical-align: middle;margin: 10px;}
 .fp-select .fp-fileinfo {display: inline-block;margin-top: 4px;margin-right: 20px;}
 .file-picker.fp-select .fp-fileinfo {max-width:240px;}
 .fp-select .fp-fileinfo div {padding: 4px 0px;}
@@ -224,12 +223,12 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
  * File Manager layout
  */
 .fp-restrictions{text-align: right;}
-.filemanager .fp-navbar {background: #F2F2F2;border-top: 1px solid #BBB;border-left: 1px solid #BBB;border-right: 1px solid #BBB;}
+.filemanager .fp-navbar {background: #F2F2F2;border-top: 1px solid #BBBBBB;border-left: 1px solid #BBBBBB;border-right: 1px solid #BBBBBB;}
 .filemanager-toolbar{padding: 5px 8px;min-height:22px;}
-.fp-pathbar {border-top: 1px solid #BBB;padding: 5px 8px 1px;min-height: 20px;}
+.fp-pathbar {border-top: 1px solid #BBBBBB;padding: 5px 8px 1px;min-height: 20px;}
 .filemanager .fp-pathbar.empty {display:none;}
 .filepicker-filelist,
-.filemanager-container {background: #FFF;clear: both;overflow:auto;border: 1px solid #BBB;min-height: 140px;position: relative;}
+.filemanager-container {background: #FFFFFF;clear: both;overflow:auto;border: 1px solid #BBBBBB;min-height: 140px;position: relative;}
 /*.filemanager-container ul{margin:0;padding:0;}
 .filemanager-container ul li{white-space:nowrap;list-style-type:none;}
 .filemanager-container ul li a{padding:0}*/
@@ -247,13 +246,10 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*
  * Table view (File Manager only)
  */
-.filemanager .yui3-datatable table {border: 0px solid #BBB;width:100%;}
-.filemanager .yui3-datatable-header {background: #FFF;border-bottom: 1px solid #CCC;border-left: 0 solid #FFF;color: #555;}
-.filemanager .yui3-datatable-columns .yui3-datatable-sorted, .filemanager .yui3-datatable-sortable-column:hover {background-color: #FFF;}
-.filemanager .yui3-datatable-odd .yui3-datatable-cell {background-color: #F6F6F6;border-left: 0px solid #F6F6F6;}
-.filemanager .yui3-datatable-data .yui3-datatable-odd .yui3-datatable-sorted {background-color: #F6F6F6;}
-.filemanager .yui3-datatable-even .yui3-datatable-cell {background-color: #FFF;border-left: 0px solid #FFF;}
-.filemanager .yui3-datatable-data .yui3-datatable-even .yui3-datatable-sorted {background-color: #FFF;}
+.filemanager .yui3-datatable table {border: 0px solid #BBBBBB;width:100%;}
+.filemanager .yui3-datatable-header {background: #FFFFFF!important;border-bottom: 1px solid #CCCCCC!important;border-left: 0 solid #FFFFFF!important;color: #555555!important;}
+.filemanager .yui3-datatable-odd .yui3-datatable-cell {background-color: #F6F6F6!important;border-left: 0px solid #F6F6F6;}
+.filemanager .yui3-datatable-even .yui3-datatable-cell {background-color: #FFFFFF!important;border-left: 0px solid #FFFFFF;}
 
 /*
  * Folder Context Menu (File Manager only)
@@ -261,17 +257,17 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager .fp-contextmenu {display:none;}
 .filemanager .fp-iconview .fp-folder.fp-hascontextmenu .fp-contextmenu {display:block;position:absolute;right:7px;bottom:5px;z-index: 2000;}
 .filemanager .fp-treeview .fp-folder.fp-hascontextmenu .fp-contextmenu,
-.filemanager .fp-tableview .fp-folder.fp-hascontextmenu .fp-contextmenu {/*display: inline;*//*position: relative;left: 14px;margin-right: -20px;top: 6px;background: yellow;*/}
+.filemanager .fp-tableview .fp-folder.fp-hascontextmenu .fp-contextmenu {display: inline;position: absolute;left: 14px;margin-right: -20px;top: 6px;}
 
 /*
  * Drag and drop support (File Manager only)
  */
 .filepicker-filelist .filepicker-container,
-.filemanager.fm-noitems .fm-empty-container {display:block;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #BBB;padding-top:85px;text-align:center;z-index: 3000;}
+.filemanager.fm-noitems .fm-empty-container {display:block;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #BBBBBB;padding-top:85px;text-align:center;z-index: 3000;}
 .filepicker-filelist .dndupload-target,
-.filemanager-container .dndupload-target {background:#FFF;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #fb7979;padding-top:85px;text-align:center;z-index:3000;-webkit-box-shadow:  0px 0px 0px 10px #FFF;-moz-box-shadow: 0px 0px 0px 10px #FFF;box-shadow:  0px 0px 0px 10px #FFF;}
+.filemanager-container .dndupload-target {background:#FFFFFF;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #fb7979;padding-top:85px;text-align:center;z-index:3000;-webkit-box-shadow:  0px 0px 0px 10px #FFFFFF;-moz-box-shadow: 0px 0px 0px 10px #FFFFFF;box-shadow:  0px 0px 0px 10px #FFFFFF;}
 .filepicker-filelist.dndupload-over .dndupload-target,
-.filemanager-container.dndupload-over .dndupload-target {background:#FFF;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #6c8cd3;padding-top:85px;text-align:center;z-index: 3000;}
+.filemanager-container.dndupload-over .dndupload-target {background:#FFFFFF;position:absolute;top:10px;bottom:10px;left:10px;right:10px;border: 2px dashed #6c8cd3;padding-top:85px;text-align:center;z-index: 3000;}
 .dndupload-message {display:none;}
 .dndsupported .dndupload-message {display:inline;}
 .dndupload-target {display:none;}
@@ -310,15 +306,14 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 .filemanager.fp-select .fp-reflist .fp-reflistloading {display:none;}
 .filemanager.fp-select .fp-refcount {max-width: 265px;}
 .filemanager.fp-select .fp-reflist.fp-loading .fp-reflistloading {display:inline;}
-.filemanager.fp-select .fp-reflist .fp-value {background: #FFF;border: 1px solid #BBB;padding: 8px 7px;margin: 0px;max-width: 265px;max-height: 75px;overflow:auto;}
+.filemanager.fp-select .fp-reflist .fp-value {background: #FFFFFF;border: 1px solid #BBBBBB;padding: 8px 7px;margin: 0px;max-width: 265px;max-height: 75px;overflow:auto;}
 .filemanager.fp-select .fp-reflist .fp-value li {padding-bottom: 7px;}
 
 /*
  * Create folder dialogue (File Manager only)
  */
-.filemanager.fp-mkdir-dlg {text-align: center;z-index: 999999}
-.filemanager .fp-mkdir-dlg p {text-align: left;margin: 40px 20px 0px;}
-.filemanager .fp-mkdir-dlg input {margin: 0px 20px 20px;}
+.filemanager.fp-mkdir-dlg {text-align: center;}
+.filemanager.fp-mkdir-dlg .fp-mkdir-dlg-text {text-align: left;margin: 40px 20px 20px;}
 
 /*
  * Confirm dialogue for delete (File Manager only)
index 931fb26..aeb58d2 100644 (file)
@@ -52,5 +52,29 @@ function xmldb_theme_formal_white_upgrade($oldversion) {
     // Moodle v2.2.0 release upgrade line
     // Put any upgrade step following this
 
+    if ($oldversion < 2012051503) {
+        $currentsetting = get_config('theme_formal_white');
+
+        if (isset($currentsetting->displaylogo)) { // useless but safer
+            // Create a new config setting called headercontent and give it the current displaylogo value.
+            set_config('headercontent', $currentsetting->displaylogo, 'theme_formal_white');
+            unset_config('displaylogo', 'theme_formal_white');
+        }
+
+        if (isset($currentsetting->logo)) { // useless but safer
+            // Create a new config setting called headercontent and give it the current displaylogo value.
+            set_config('customlogourl', $currentsetting->logo, 'theme_formal_white');
+            unset_config('logo', 'theme_formal_white');
+        }
+
+        if (isset($currentsetting->frontpagelogo)) { // useless but safer
+            // Create a new config setting called headercontent and give it the current displaylogo value.
+            set_config('frontpagelogourl', $currentsetting->frontpagelogo, 'theme_formal_white');
+            unset_config('frontpagelogo', 'theme_formal_white');
+        }
+
+        upgrade_plugin_savepoint(true, 2012051503, 'theme', 'formal_white');
+    }
+
     return true;
 }
\ No newline at end of file
index a5a2221..cb80bc2 100644 (file)
@@ -58,32 +58,32 @@ $string['choosereadme'] = '
         <p>This, and all other themes included in the Moodle core, are licensed under the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public License</a>.
     </div>
 </div>';
+$string['configtitle'] = 'Formal white theme';
 $string['creditstomoodleorg'] = 'Display credits to moodle.org';
 $string['creditstomoodleorgdesc'] = 'Display the usual small moodle logo at the bottom of the page';
-$string['configtitle'] = 'Formal white theme';
+$string['ctmo_ineverypage'] = 'in every page'; // ctmo == credits to moodle org
 $string['ctmo_no'] = 'never'; // ctmo == credits to moodle org
 $string['ctmo_onfrontpageonly'] = 'in the front page only'; // ctmo == credits to moodle org
-$string['ctmo_ineverypage'] = 'in every page'; // ctmo == credits to moodle org
 $string['customcss'] = 'Custom CSS';
 $string['customcssdesc'] = 'Any CSS you enter here will be added to every page allowing your to easily customise this theme.';
-$string['displaylogo'] = 'Pages header content';
-$string['displaylogodesc'] = 'Choose whether display moodle logo or page heading text in the header.';
+$string['customlogourl'] = 'Custom logo';
+$string['customlogourldesc'] = 'Change the logo for this theme by entering the URL to an image you wish to use (i.e. http://www.yoursite.local/mylogo.png). As a reference the default logo is 200px wide, 50px high and a transparent png will work best.';
+$string['displayheading'] = 'Display page heading';
+$string['displaylogo'] = 'Display logo';
 $string['fontsizereference'] = 'Font size reference';
 $string['fontsizereferencedesc'] = 'This allows you to set the default font size for this theme. It is not recommended to set this higher than 13px as it is known to cause display problems with certain blocks.';
 $string['footnote'] = 'Footnote';
 $string['footnotedesc'] = 'The content from this textarea will be displayed in the footer of every page.';
 $string['framemargin'] = 'Frame margin';
 $string['framemargindesc'] = 'Room between the frame and the edge of the browser window. (This setting will be ignored if "{$a}" is requested).';
-$string['frontpagelogo'] = 'Custom front page logo';
-$string['frontpagelogodesc'] = 'Change the logo that is displayed on the front page of your site by entering the URL to the image you wish to use (i.e. http://www.yoursite.local/myfrontpagelogo.png). This setting overrides the custom logo setting. As a reference the default logo is 300px wide, 80px high and a transparent png will work best.';
+$string['frontpagelogourl'] = 'Custom front page logo';
+$string['frontpagelogourldesc'] = 'Change the logo that is displayed on the front page of your site by entering the URL to the image you wish to use (i.e. http://www.yoursite.local/myfrontpagelogo.png). This setting overrides the custom logo setting. As a reference the default logo is 300px wide, 80px high and a transparent png will work best.';
 $string['headerbgc'] = 'Header background colour';
 $string['headerbgcdesc'] = 'This sets the blocks header background colour for the theme.';
-$string['heading'] = 'Display page heading';
+$string['headercontent'] = 'Header content';
+$string['headercontentdesc'] = 'Choose whether display moodle logo or page heading text in the header.';
 $string['lblockcolumnbgc'] = 'Left column background colour';
 $string['lblockcolumnbgcdesc'] = 'This sets the left column background colour for the theme.';
-$string['logo'] = 'Custom logo';
-$string['logodesc'] = 'Change the logo for this theme by entering the URL to an image you wish to use (i.e. http://www.yoursite.local/mylogo.png). As a reference the default logo is 200px wide, 50px high and a transparent png will work best.';
-$string['moodlelogo'] = 'Display moodle logo';
 $string['noframe'] = 'Formal white 1.9 look';
 $string['noframedesc'] = 'Select this option to require your moodle page to look like moodle 1.*, alias, without the surrounding frame.';
 $string['pluginname'] = 'Formal white';
index 88edd8a..29644e1 100644 (file)
@@ -29,17 +29,17 @@ if ($hascustommenu) {
 }
 
 /************************************************************************************************/
-if (!empty($PAGE->theme->settings->frontpagelogo)) {
-    $logourl = $PAGE->theme->settings->frontpagelogo;
-} else if (!empty($PAGE->theme->settings->logo)) {
-    $logourl = $PAGE->theme->settings->logo;
+if (!empty($PAGE->theme->settings->frontpagelogourl)) {
+    $logourl = $PAGE->theme->settings->frontpagelogourl;
+} else if (!empty($PAGE->theme->settings->customlogourl)) {
+    $logourl = $PAGE->theme->settings->customlogourl;
 } else {
     $logourl = $OUTPUT->pix_url('logo', 'theme');
 }
 
 $hasframe = !isset($PAGE->theme->settings->noframe) || !$PAGE->theme->settings->noframe;
 
-$displaylogo = !isset($PAGE->theme->settings->displaylogo) || $PAGE->theme->settings->displaylogo;
+$displaylogo = !isset($PAGE->theme->settings->headercontent) || $PAGE->theme->settings->headercontent;
 /************************************************************************************************/
 
 echo $OUTPUT->doctype() ?>
index 570ada7..3cebe1c 100644 (file)
@@ -29,15 +29,15 @@ if ($hascustommenu) {
 }
 
 /************************************************************************************************/
-if (!empty($PAGE->theme->settings->logo)) {
-    $logourl = $PAGE->theme->settings->logo;
+if (!empty($PAGE->theme->settings->customlogourl)) {
+    $logourl = $PAGE->theme->settings->customlogourl;
 } else {
     $logourl = $OUTPUT->pix_url('logo_small', 'theme');
 }
 
 $hasframe = !isset($PAGE->theme->settings->noframe) || !$PAGE->theme->settings->noframe;
 
-$displaylogo = !isset($PAGE->theme->settings->displaylogo) || $PAGE->theme->settings->displaylogo;
+$displaylogo = !isset($PAGE->theme->settings->headercontent) || $PAGE->theme->settings->headercontent;
 /************************************************************************************************/
 
 echo $OUTPUT->doctype() ?>
index c3040a3..9bb7ca1 100644 (file)
@@ -24,15 +24,15 @@ if ($hascustommenu) {
 }
 
 /************************************************************************************************/
-if (!empty($PAGE->theme->settings->logo)) {
-    $logourl = $PAGE->theme->settings->logo;
+if (!empty($PAGE->theme->settings->customlogourl)) {
+    $logourl = $PAGE->theme->settings->customlogourl;
 } else {
     $logourl = $OUTPUT->pix_url('logo_small', 'theme');
 }
 
 $hasframe = !isset($PAGE->theme->settings->noframe) || !$PAGE->theme->settings->noframe;
 
-$displaylogo = !isset($PAGE->theme->settings->displaylogo) || $PAGE->theme->settings->displaylogo;
+$displaylogo = !isset($PAGE->theme->settings->headercontent) || $PAGE->theme->settings->headercontent;
 /************************************************************************************************/
 
 echo $OUTPUT->doctype() ?>
index 0c2c8a2..81db472 100644 (file)
@@ -34,26 +34,26 @@ if ($ADMIN->fulltree) {
     $settings->add($setting);
 
     // Display logo or heading
-    $name = 'theme_formal_white/displaylogo';
-    $title = get_string('displaylogo','theme_formal_white');
-    $description = get_string('displaylogodesc', 'theme_formal_white');
+    $name = 'theme_formal_white/headercontent';
+    $title = get_string('headercontent','theme_formal_white');
+    $description = get_string('headercontentdesc', 'theme_formal_white');
     $default = '1';
-    $choices = array(1=>get_string('moodlelogo', 'theme_formal_white'), 0=>get_string('heading', 'theme_formal_white'));
+    $choices = array(1=>get_string('displaylogo', 'theme_formal_white'), 0=>get_string('displayheading', 'theme_formal_white'));
     $setting = new admin_setting_configselect($name, $title, $description, $default, $choices);
     $settings->add($setting);
 
     // Custom site logo setting
-    $name = 'theme_formal_white/logo';
-    $title = get_string('logo','theme_formal_white');
-    $description = get_string('logodesc', 'theme_formal_white');
+    $name = 'theme_formal_white/customlogourl';
+    $title = get_string('customlogourl','theme_formal_white');
+    $description = get_string('customlogourldesc', 'theme_formal_white');
     $default = '';
     $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
     $settings->add($setting);
 
     // Custom front page site logo setting
-    $name = 'theme_formal_white/frontpagelogo';
-    $title = get_string('frontpagelogo','theme_formal_white');
-    $description = get_string('frontpagelogodesc', 'theme_formal_white');
+    $name = 'theme_formal_white/frontpagelogourl';
+    $title = get_string('frontpagelogourl','theme_formal_white');
+    $description = get_string('frontpagelogourldesc', 'theme_formal_white');
     $default = '';
     $setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_URL);
     $settings->add($setting);
index f905a47..2a262c9 100644 (file)
@@ -30,12 +30,13 @@ p {margin:0}
 #page-header{line-height:0;overflow:hidden;}
 
 /* headerlogo */
-#headerlogo {position:relative;margin:0.3em;}
+#headerlogo {position:relative;margin:0;}
   /* if I use: position:absolute; I even need height:105px; in #page-header */
   /* if I use: position:relative; z-index doesn't work*/
 
 /* headermenu */
-.headermenu {position:absolute;text-align:right;line-height:1.7em;font-size:90%;margin:0.3em;right:[[calculated:headermenuright]];top:15px;}
+.headermenu {position:absolute;text-align:right;line-height:1.7em;font-size:90%;margin:0.5em;right:[[calculated:headermenuright]];top:15px;}
+.langmenu {margin-right:0.4em}
 
 #dock {background-color:[[setting:blockcontentbgc]];border-right:1px dashed #000;}
 #dock .dockeditem_container {margin-top: 10px;}
index 1730dc8..4a5829f 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-$plugin->version   = 2012040302; // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2012051503; // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2011081700; // Requires this Moodle version
 $plugin->component = 'theme_formal_white';
 $plugin->maturity  = MATURITY_STABLE;
\ No newline at end of file
index 8916ad0..c1d57bc 100644 (file)
@@ -473,7 +473,7 @@ class core_user_external extends external_api {
                     'timezone'    => new external_value(PARAM_TIMEZONE, 'Timezone code such as Australia/Perth, or 99 for default', VALUE_OPTIONAL),
                     'mailformat'  => new external_value(PARAM_INTEGER, 'Mail format code is 0 for plain text, 1 for HTML etc', VALUE_OPTIONAL),
                     'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
-                    'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
+                    'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
                     'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
                     'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
                     'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
@@ -618,7 +618,7 @@ class core_user_external extends external_api {
                     'firstaccess' => new external_value(PARAM_INT, 'first access to the site (0 if never)', VALUE_OPTIONAL),
                     'lastaccess'  => new external_value(PARAM_INT, 'last access to the site (0 if never)', VALUE_OPTIONAL),
                     'description' => new external_value(PARAM_RAW, 'User profile description', VALUE_OPTIONAL),
-                    'descriptionformat' => new external_value(PARAM_INT, 'User profile description format', VALUE_OPTIONAL),
+                    'descriptionformat' => new external_format_value('description', VALUE_OPTIONAL),
                     'city'        => new external_value(PARAM_NOTAGS, 'Home city of the user', VALUE_OPTIONAL),
                     'url'         => new external_value(PARAM_URL, 'URL of the user', VALUE_OPTIONAL),
                     'country'     => new external_value(PARAM_ALPHA, 'Home country code of the user, such as AU or CZ', VALUE_OPTIONAL),
@@ -639,6 +639,7 @@ class core_user_external extends external_api {
                                 'id'  => new external_value(PARAM_INT, 'group id'),
                                 'name' => new external_value(PARAM_RAW, 'group name'),
                                 'description' => new external_value(PARAM_RAW, 'group description'),
+                                'descriptionformat' => new external_format_value('description'),
                             )
                         ), 'user groups', VALUE_OPTIONAL),
                     'roles' => new external_multiple_structure(
index 040a095..c4f433e 100644 (file)
@@ -171,6 +171,10 @@ function user_get_users_by_id($userids) {
  *
  * Give user record from mdl_user, build an array conntains
  * all user details
+ *
+ * Warning: description file urls are 'webservice/pluginfile.php' is use.
+ *          it can be changed with $CFG->moodlewstextformatlinkstoimagesfile
+ *
  * @param stdClass $user user record from mdl_user
  * @param stdClass $context context object
  * @param stdClass $course moodle course
@@ -319,11 +323,10 @@ function user_get_user_details($user, $course = null, array $userfields = array(
         if (!$cannotviewdescription) {
 
             if (in_array('description', $userfields)) {
-                $user->description = file_rewrite_pluginfile_urls($user->description, 'pluginfile.php', $usercontext->id, 'user', 'profile', null);
-                $userdetails['description'] = $user->description;
-            }
-            if (in_array('descriptionformat', $userfields)) {
-                $userdetails['descriptionformat'] = $user->descriptionformat;
+                // Always return the descriptionformat if description is requested.
+                list($userdetails['description'], $userdetails['descriptionformat']) =
+                        external_format_text($user->description, $user->descriptionformat,
+                                $usercontext->id, 'user', 'profile', null);
             }
         }
     }
@@ -417,11 +420,15 @@ function user_get_user_details($user, $course = null, array $userfields = array(
 
     // If groups are in use and enforced throughout the course, then make sure we can meet in at least one course level group
     if (in_array('groups', $userfields) && !empty($course) && $canaccessallgroups) {
-        $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid, 'g.id, g.name,g.description');
+        $usergroups = groups_get_all_groups($course->id, $user->id, $course->defaultgroupingid,
+                'g.id, g.name,g.description,g.descriptionformat');
         $userdetails['groups'] = array();
         foreach ($usergroups as $group) {
-            $group->description = file_rewrite_pluginfile_urls($group->description, 'pluginfile.php', $context->id, 'group', 'description', $group->id);
-            $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name, 'description'=>$group->description);
+            list($group->description, $group->descriptionformat) =
+                external_format_text($group->description, $group->descriptionformat,
+                        $context->id, 'group', 'description', $group->id);
+            $userdetails['groups'][] = array('id'=>$group->id, 'name'=>$group->name,
+                'description'=>$group->description, 'descriptionformat'=>$group->descriptionformat);
         }
     }
     //list of courses where the user is enrolled
index fd97b59..813b25b 100644 (file)
@@ -30,7 +30,7 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012060100.00;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012060400.00;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
index 7946bd8..4fac2e9 100644 (file)
@@ -960,6 +960,38 @@ abstract class webservice_server implements webservice_server_interface {
         return $user;
 
     }
+
+    /**
+     * Intercept some moodlewssettingXXX $_GET and $_POST parameter
+     * that are related to the web service call and are not the function parameters
+     */
+    protected function set_web_service_call_settings() {
+        global $CFG;
+
+        // Default web service settings.
+        // Must be the same XXX key name as the external_settings::set_XXX function.
+        // Must be the same XXX ws parameter name as 'moodlewssettingXXX'.
+        $externalsettings = array(
+            'raw' => false,
+            'fileurl' => true,
+            'filter' =>  false);
+
+        // Load the external settings with the web service settings.
+        $settings = external_settings::get_instance();
+        foreach ($externalsettings as $name => $default) {
+
+            $wsparamname = 'moodlewssetting' . $name;
+
+            // Retrieve and remove the setting parameter from the request.
+            $value = optional_param($wsparamname, $default, PARAM_BOOL);
+            unset($_GET[$wsparamname]);
+            unset($_POST[$wsparamname]);
+
+            $functioname = 'set_' . $name;
+            $settings->$functioname($value);
+        }
+
+    }
 }
 
 /**
@@ -1336,7 +1368,10 @@ class '.$classname.' {
      */
     protected function parse_request() {
 
-        //Get GET and POST paramters
+        // We are going to clean the POST/GET parameters from the parameters specific to the server.
+        parent::set_web_service_call_settings();
+
+        // Get GET and POST paramters.
         $methodvariables = array_merge($_GET,$_POST);
 
         if ($this->authmethod == WEBSERVICE_AUTHMETHOD_USERNAME) {
index 6dcfd43..abd131c 100644 (file)
@@ -43,10 +43,9 @@ class webservice_rest_server extends webservice_base_server {
      * @param string $authmethod authentication method of the web service (WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN, ...)
      * @param string $restformat Format of the return values: 'xml' or 'json'
      */
-    public function __construct($authmethod, $restformat = 'xml') {
+    public function __construct($authmethod) {
         parent::__construct($authmethod);
         $this->wsname = 'rest';
-        $this->restformat = ($restformat != 'xml' && $restformat != 'json')?'xml':$restformat; //sanity check, we accept only xml or json
     }
 
     /**
@@ -55,11 +54,22 @@ class webservice_rest_server extends webservice_base_server {
      *  1/ user authentication - username+password or token (wsusername, wspassword and wstoken parameters)
      *  2/ function name (wsfunction parameter)
      *  3/ function parameters (all other parameters except those above)
+     *  4/ text format parameters
+     *  5/ return rest format xml/json
      */
     protected function parse_request() {
 
-        //Get GET and POST paramters
-        $methodvariables = array_merge($_GET,$_POST);
+        // Retrieve and clean the POST/GET parameters from the parameters specific to the server.
+        parent::set_web_service_call_settings();
+
+        // Get GET and POST parameters.
+        $methodvariables = array_merge($_GET, $_POST);
+
+        // Retrieve REST format parameter - 'xml' (default) or 'json'.
+        $restformatisset = isset($methodvariables['moodlewsrestformat'])
+                && (($methodvariables['moodlewsrestformat'] == 'xml' || $methodvariables['moodlewsrestformat'] == 'json'));
+        $this->restformat = $restformatisset ? $methodvariables['moodlewsrestformat'] : 'xml';
+        unset($methodvariables['moodlewsrestformat']);
 
         if ($this->authmethod == WEBSERVICE_AUTHMETHOD_USERNAME) {
             $this->username = isset($methodvariables['wsusername']) ? $methodvariables['wsusername'] : null;
index c0f02bc..56d39e2 100644 (file)
@@ -42,16 +42,7 @@ if (!webservice_protocol_is_enabled('rest')) {
     die;
 }
 
-$restformat = optional_param('moodlewsrestformat', 'xml', PARAM_ALPHA);
-//remove the alt from the request
-if(isset($_GET['moodlewsrestformat'])) {
-    unset($_GET['moodlewsrestformat']);
-}
-if(isset($_POST['moodlewsrestformat'])) {
-    unset($_POST['moodlewsrestformat']);
-}
-
-$server = new webservice_rest_server(WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN, $restformat);
+$server = new webservice_rest_server(WEBSERVICE_AUTHMETHOD_PERMANENT_TOKEN);
 $server->run();
 die;