Merge branch 'MDL-33105' of https://github.com/ppichet/moodle
authorDan Poltawski <dan@moodle.com>
Tue, 18 Jun 2013 02:35:47 +0000 (10:35 +0800)
committerDan Poltawski <dan@moodle.com>
Tue, 18 Jun 2013 02:35:47 +0000 (10:35 +0800)
369 files changed:
admin/auth_config.php
admin/cli/install.php
admin/cron.php
admin/tool/customlang/renderer.php
admin/tool/uploaduser/db/access.php [new file with mode: 0644]
admin/tool/uploaduser/lang/en/tool_uploaduser.php
admin/tool/uploaduser/picture.php
admin/tool/uploaduser/settings.php
admin/tool/uploaduser/version.php
admin/user/user_bulk_confirm.php
admin/user/user_bulk_delete.php
admin/webservice/protocols.php
auth/cas/auth.php
auth/cas/config.html
auth/ldap/auth.php
auth/ldap/config.html
backup/moodle2/restore_course_task.class.php
backup/moodle2/restore_final_task.class.php
backup/moodle2/restore_root_task.class.php
backup/moodle2/restore_stepslib.php
backup/upgrade.txt
backup/util/dbops/backup_controller_dbops.class.php
backup/util/dbops/restore_controller_dbops.class.php
badges/criteria/award_criteria.php
badges/criteria/award_criteria_course.php
blocks/badges/block_badges.php
blocks/course_overview/renderer.php
blocks/dock.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js
blocks/navigation/yui/src/navigation/js/navigation.js
cache/classes/helper.php
cache/classes/loaders.php
cache/stores/file/addinstanceform.php
cache/stores/memcache/addinstanceform.php
cache/stores/mongodb/addinstanceform.php
cohort/index.php
config-dist.php
course/edit_form.php
course/externallib.php
course/format/lib.php
course/format/social/format.php
course/format/topics/lib.php
course/format/topics/renderer.php
course/format/weeks/lib.php
course/lib.php
course/manage.php
course/moodleform_mod.php
course/renderer.php
course/tests/courselib_test.php
course/tests/externallib_test.php
course/view.php
enrol/manual/lib.php
enrol/manual/settings.php
enrol/manual/tests/lib_test.php
filter/urltolink/filter.php
filter/urltolink/tests/filter_test.php
grade/edit/tree/grade.php
grade/grading/form/guide/lib.php
grade/grading/form/rubric/lib.php
grade/report/grader/ajax_callbacks.php
grade/report/grader/lib.php
index.php
install.php
install/lang/ca_valencia/error.php
install/lang/ca_valencia/install.php
install/lang/it/error.php
install/lang/pt_br/error.php
install/lang/sr_cr/langconfig.php
install/lang/sr_lt/langconfig.php
install/lang/sv/error.php
lang/en/admin.php
lang/en/group.php
lang/en/hub.php
lang/en/install.php
lib/accesslib.php
lib/adminlib.php
lib/authlib.php
lib/blocklib.php
lib/completionlib.php
lib/coursecatlib.php
lib/csslib.php
lib/datalib.php
lib/db/access.php
lib/db/install.xml
lib/db/upgrade.php
lib/deprecatedlib.php
lib/dml/oci_native_moodle_database.php
lib/filterlib.php
lib/form/dateselector.php
lib/form/editor.php
lib/form/hidden.php
lib/form/submit.js [new file with mode: 0644]
lib/form/submit.php
lib/form/yui/dateselector/dateselector.js
lib/formslib.php
lib/jslib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputlib.php
lib/outputrenderers.php
lib/pagelib.php
lib/pluginlib.php
lib/portfolio/exporter.php
lib/rsslib.php
lib/setup.php
lib/statslib.php
lib/tests/accesslib_test.php
lib/tests/completionlib_advanced_test.php [new file with mode: 0644]
lib/tests/completionlib_test.php
lib/tests/datalib_test.php
lib/tests/environment_test.php [new file with mode: 0644]
lib/tests/navigationlib_test.php
lib/tests/weblib_test.php
lib/upgrade.txt
lib/weblib.php
lib/yui/build/moodle-core-blocks/moodle-core-blocks-debug.js
lib/yui/build/moodle-core-blocks/moodle-core-blocks-min.js
lib/yui/build/moodle-core-blocks/moodle-core-blocks.js
lib/yui/dragdrop/dragdrop.js
lib/yui/src/blocks/build.json
lib/yui/src/blocks/js/blockregion.js [new file with mode: 0644]
lib/yui/src/blocks/js/blocks.js
lib/yui/src/blocks/js/manager.js [new file with mode: 0644]
login/index.php
login/signup.php
mod/assign/backup/moodle2/backup_assign_stepslib.php
mod/assign/backup/moodle2/restore_assign_stepslib.php
mod/assign/batchsetallocatedmarkerform.php [new file with mode: 0644]
mod/assign/batchsetmarkingworkflowstateform.php [new file with mode: 0644]
mod/assign/db/access.php
mod/assign/db/install.xml
mod/assign/db/log.php
mod/assign/db/upgrade.php
mod/assign/gradingbatchoperationsform.php
mod/assign/gradingoptionsform.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/mod_form.php
mod/assign/module.js
mod/assign/renderer.php
mod/assign/settings.php
mod/assign/tests/generator/lib.php
mod/assign/tests/locallib_test.php
mod/assign/upgradelib.php
mod/assign/version.php
mod/assignment/lib.php
mod/book/edit.php
mod/data/edit.php
mod/data/export.php
mod/data/field.php
mod/data/lib.php
mod/data/preset.php
mod/data/templates.php
mod/data/view.php
mod/feedback/edit_form.php
mod/feedback/mapcourse.php
mod/forum/lib.php
mod/imscp/locallib.php
mod/lesson/locallib.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/tests/behat/date_availability.feature
mod/quiz/attemptlib.php
mod/quiz/lang/en/quiz.php
mod/quiz/locallib.php
mod/quiz/mod_form.php
mod/quiz/settings.php
mod/quiz/startattempt.php
mod/scorm/db/upgrade.php
mod/scorm/lang/en/scorm.php
mod/scorm/lib.php
mod/scorm/loadSCO.php
mod/scorm/locallib.php
mod/scorm/mod_form.php
mod/scorm/module.js
mod/scorm/report/basic/lang/en/scormreport_basic.php
mod/scorm/settings.php
mod/scorm/styles.css
mod/scorm/version.php
mod/wiki/pagelib.php
mod/wiki/renderer.php
mod/wiki/view.php
notes/delete.php
notes/edit_form.php
question/behaviour/behaviourbase.php
question/behaviour/manualgraded/behaviour.php
question/behaviour/upgrade.txt
question/engine/datalib.php
question/engine/lib.php
question/type/calculated/datasetitems_form.php
question/type/calculated/question.php
question/type/calculated/questiontype.php
question/type/calculated/renderer.php
question/type/calculated/tests/helper.php
question/type/calculated/tests/question_test.php
question/type/calculatedmulti/questiontype.php
question/type/calculatedsimple/edit_calculatedsimple_form.php
question/type/calculatedsimple/questiontype.php
question/type/multichoice/question.php
question/type/multichoice/tests/question_multi_test.php [new file with mode: 0644]
question/type/multichoice/tests/question_single_test.php [moved from question/type/multichoice/tests/question_test.php with 56% similarity]
question/type/questiontypebase.php
report/log/graph.php
report/progress/index.php
report/progress/lib.php
report/progress/textrotate.js
tag/edit_form.php
theme/base/style/admin.css
theme/base/style/core.css
theme/bootstrapbase/config.php
theme/bootstrapbase/layout/columns1.php [new file with mode: 0644]
theme/bootstrapbase/layout/columns2.php [new file with mode: 0644]
theme/bootstrapbase/layout/columns3.php [new file with mode: 0644]
theme/bootstrapbase/layout/embedded.php
theme/bootstrapbase/layout/general.php [deleted file]
theme/bootstrapbase/layout/secure.php [new file with mode: 0644]
theme/bootstrapbase/less/moodle.less
theme/bootstrapbase/less/moodle/admin.less
theme/bootstrapbase/less/moodle/buttons.less
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/expendable.less
theme/bootstrapbase/less/moodle/filemanager.less
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/less/moodle/question.less
theme/bootstrapbase/less/moodle/reports.less [new file with mode: 0644]
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/renderers/core_renderer.php
theme/bootstrapbase/style/moodle.css
theme/clean/config.php
theme/clean/layout/columns1.php [new file with mode: 0644]
theme/clean/layout/columns2.php [new file with mode: 0644]
theme/clean/layout/columns3.php [new file with mode: 0644]
theme/clean/layout/embedded.php [new file with mode: 0644]
theme/clean/layout/general.php [deleted file]
theme/clean/layout/secure.php [new file with mode: 0644]
theme/clean/lib.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/lib.php
theme/formal_white/pix/trend/blueberry/bg_bread.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/blueberry.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/custommenubg.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/gradient-sb.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/gradient_h.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/hgradient.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/body_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/body_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/footer.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/footer_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/footer_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/header.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/header_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/blueberry/roundcorner/header_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/bg_bread.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/custommenubg.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/gradient-sb.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/gradient_h.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/hgradient.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/lemon.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/body_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/body_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/footer.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/footer_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/footer_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/header.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/header_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lemon/roundcorner/header_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/bg_bread.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/custommenubg.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/gradient-sb.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/gradient_h.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/hgradient.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/lime.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/body_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/body_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/footer.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/footer_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/footer_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/header.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/header_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/lime/roundcorner/header_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/mink/bg_bread.jpg [moved from theme/formal_white/pix/bg_bread.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/custommenubg.jpg [moved from theme/formal_white/pix/custommenubg.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/gradient-sb.jpg [moved from theme/formal_white/pix/gradient-sb.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/gradient_h.jpg [moved from theme/formal_white/pix/gradient_h.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/hgradient.jpg [moved from theme/formal_white/pix/hgradient.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/mink.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/body_l.jpg [moved from theme/formal_white/pix/roundcorner/body_l.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/body_r.jpg [moved from theme/formal_white/pix/roundcorner/body_r.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/footer.jpg [moved from theme/formal_white/pix/roundcorner/footer.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/footer_l.jpg [moved from theme/formal_white/pix/roundcorner/footer_l.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/footer_r.jpg [moved from theme/formal_white/pix/roundcorner/footer_r.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/header.jpg [moved from theme/formal_white/pix/roundcorner/header.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/header_l.jpg [moved from theme/formal_white/pix/roundcorner/header_l.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/mink/roundcorner/header_r.jpg [moved from theme/formal_white/pix/roundcorner/header_r.jpg with 100% similarity, mode: 0755]
theme/formal_white/pix/trend/orange/bg_bread.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/custommenubg.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/gradient-sb.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/gradient_h.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/hgradient.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/orange.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/body_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/body_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/footer.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/footer_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/footer_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/header.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/header_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/orange/roundcorner/header_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/bg_bread.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/custommenubg.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/gradient-sb.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/gradient_h.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/hgradient.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/peach.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/body_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/body_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/footer.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/footer_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/footer_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/header.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/header_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/peach/roundcorner/header_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/bg_bread.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/custommenubg.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/gradient-sb.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/gradient_h.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/hgradient.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/body_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/body_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/footer.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/footer_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/footer_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/header.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/header_l.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/roundcorner/header_r.jpg [new file with mode: 0755]
theme/formal_white/pix/trend/silver/silver.jpg [new file with mode: 0755]
theme/formal_white/settings.php
theme/formal_white/style/block.css
theme/formal_white/style/calendar.css
theme/formal_white/style/core.css
theme/formal_white/style/course.css
theme/formal_white/style/formal_white.css
theme/formal_white/style/frame.css
theme/formal_white/style/menu.css
theme/formal_white/style/quiz.css
theme/image.php
theme/jquery.php
theme/sky_high/pix/footer-rtl.jpg [deleted file]
theme/sky_high/pix/footer-rtl.png [new file with mode: 0644]
theme/sky_high/pix/footer.png
theme/sky_high/style/admin.css
theme/sky_high/style/pagelayout.css
theme/sky_high/style/report.css
theme/standard/style/modules.css
theme/upgrade.txt
theme/yui_combo.php
theme/yui_image.php
user/editlib.php
user/files.php
user/index.php
user/profile.php
user/selector/module.js
version.php

index c702711..50bcfc9 100644 (file)
@@ -87,8 +87,8 @@ exit;
 // but some may want a custom one if they are offering
 // other options
 // Note: lockconfig_ fields have special handling.
-function print_auth_lock_options ($auth, $user_fields, $helptext, $retrieveopts, $updateopts) {
-    global $OUTPUT;
+function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts, $updateopts, $customfields = array()) {
+    global $DB, $OUTPUT;
     echo '<tr><td colspan="3">';
     if ($retrieveopts) {
         echo $OUTPUT->heading(get_string('auth_data_mapping', 'auth'));
@@ -107,14 +107,21 @@ function print_auth_lock_options ($auth, $user_fields, $helptext, $retrieveopts,
 
     $pluginconfig = get_config("auth/$auth");
 
-    // helptext is on a field with rowspan
+    // Helptext is on a field with rowspan.
     if (empty($helptext)) {
-                $helptext = '&nbsp;';
+        $helptext = '&nbsp;';
     }
 
-    foreach ($user_fields as $field) {
+    // If we have custom fields then merge them with user fields.
+    if (!empty($customfields)) {
+        $user_fields = array_merge($user_fields, $customfields);
+    }
 
-        // Define some vars we'll work with
+    if (!empty($customfields)) {
+        $customfieldname = $DB->get_records('user_info_field', null, '', 'shortname, name');
+    }
+    foreach ($user_fields as $field) {
+        // Define some vars we'll work with.
         if (!isset($pluginconfig->{"field_map_$field"})) {
             $pluginconfig->{"field_map_$field"} = '';
         }
@@ -128,7 +135,7 @@ function print_auth_lock_options ($auth, $user_fields, $helptext, $retrieveopts,
             $pluginconfig->{"field_lock_$field"} = '';
         }
 
-        // define the fieldname we display to the  user
+        // Define the fieldname we display to the  user.
         $fieldname = $field;
         if ($fieldname === 'lang') {
             $fieldname = get_string('language');
@@ -136,6 +143,10 @@ function print_auth_lock_options ($auth, $user_fields, $helptext, $retrieveopts,
             $fieldname =  get_string($matches[1]) . ' ' . $matches[2];
         } elseif ($fieldname == 'url') {
             $fieldname = get_string('webpage');
+        } elseif (!empty($customfields) && in_array($field, $customfields)) {
+            // If custom field then pick name from database.
+            $fieldshortname = str_replace('profile_field_', '', $fieldname);
+            $fieldname = $customfieldname[$fieldshortname]->name;
         } else {
             $fieldname = get_string($fieldname);
         }
@@ -155,8 +166,6 @@ function print_auth_lock_options ($auth, $user_fields, $helptext, $retrieveopts,
                 echo '<label for="menulockconfig_field_updateremote_'.$field.'">'.get_string('auth_updateremote', 'auth') . '</label>&nbsp;';
                 echo html_writer::select($updateextoptions, "lockconfig_field_updateremote_{$field}", $pluginconfig->{"field_updateremote_$field"}, false);
                 echo '<br />';
-
-
             }
             echo '<label for="menulockconfig_field_lock_'.$field.'">'.get_string('auth_fieldlock', 'auth') . '</label>&nbsp;';
             echo html_writer::select($lockoptions, "lockconfig_field_lock_{$field}", $pluginconfig->{"field_lock_$field"}, false);
@@ -175,5 +184,3 @@ function print_auth_lock_options ($auth, $user_fields, $helptext, $retrieveopts,
         echo '</tr>';
     }
 }
-
-
index a84d556..704be90 100644 (file)
@@ -58,7 +58,8 @@ Options:
 --dbname=NAME         Database name. Default is moodle
 --dbuser=USERNAME     Database user. Default is root
 --dbpass=PASSWORD     Database password. Default is blank
---dbsocket            Use database sockets. Available for some databases only.
+--dbport=NUMBER       Use database port.
+--dbsocket=PATH       Use database socket, 1 means default. Available for some databases only.
 --prefix=STRING       Table prefix for above database tables. Default is mdl_
 --fullname=STRING     The fullname of the site
 --shortname=STRING    The shortname of the site
@@ -150,6 +151,8 @@ $CFG->docroot              = 'http://docs.moodle.org';
 $CFG->running_installer    = true;
 $CFG->early_install_lang   = true;
 $CFG->ostype               = (stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin')) ? 'WINDOWS' : 'UNIX';
+$CFG->developerdebug       = true;
+$CFG->dboptions            = array();
 
 $parts = explode('/', str_replace('\\', '/', dirname(dirname(__FILE__))));
 $CFG->admin                = array_pop($parts);
@@ -204,7 +207,8 @@ list($options, $unrecognized) = cli_get_params(
         'dbname'            => 'moodle',
         'dbuser'            => empty($distro->dbuser) ? 'root' : $distro->dbuser, // let distros set dbuser
         'dbpass'            => '',
-        'dbsocket'          => false,
+        'dbport'            => '',
+        'dbsocket'          => '',
         'prefix'            => 'mdl_',
         'fullname'          => '',
         'shortname'         => '',
@@ -497,6 +501,34 @@ if ($interactive) {
     $CFG->prefix = $options['prefix'];
 }
 
+// ask for db port
+if ($interactive) {
+    cli_separator();
+    cli_heading(get_string('databaseport', 'install'));
+    $prompt = get_string('clitypevaluedefault', 'admin', $options['dbport']);
+    $CFG->dboptions['dbport'] = (int)cli_input($prompt, $options['dbport']);
+
+} else {
+    $CFG->dboptions['dbport'] = (int)$options['dbport'];
+}
+if ($CFG->dboptions['dbport'] <= 0) {
+    $CFG->dboptions['dbport'] = '';
+}
+
+// ask for db socket
+if ($CFG->ostype === 'WINDOWS') {
+    $CFG->dboptions['dbsocket'] = '';
+
+} else if ($interactive and empty($CFG->dboptions['dbport'])) {
+    cli_separator();
+    cli_heading(get_string('databasesocket', 'install'));
+    $prompt = get_string('clitypevaluedefault', 'admin', $options['dbsocket']);
+    $CFG->dboptions['dbsocket'] = cli_input($prompt, $options['dbsocket']);
+
+} else {
+    $CFG->dboptions['dbsocket'] = $options['dbsocket'];
+}
+
 // ask for db user
 if ($interactive) {
     cli_separator();
@@ -525,14 +557,14 @@ if ($interactive) {
 
         $CFG->dbpass = cli_input($prompt, $options['dbpass']);
         if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation
-            $distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']), $distro);
+            $distro = distro_pre_create_db($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']), $distro);
         }
-        $hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']));
+        $hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']));
     } while ($hint_database !== '');
 
 } else {
     $CFG->dbpass = $options['dbpass'];
-    $hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbsocket'=>$options['dbsocket']));
+    $hint_database = install_db_validate($database, $CFG->dbhost, $CFG->dbuser, $CFG->dbpass, $CFG->dbname, $CFG->prefix, array('dbpersist'=>0, 'dbport'=>$CFG->dboptions['dbport'], 'dbsocket'=>$CFG->dboptions['dbsocket']));
     if ($hint_database !== '') {
         cli_error(get_string('dbconnectionerror', 'install'));
     }
index cce8ae3..e411545 100644 (file)
@@ -72,24 +72,10 @@ if (!empty($CFG->cronremotepassword)) {
 }
 
 // send mime type and encoding
-if (check_browser_version('MSIE')) {
-    //ugly IE hack to work around downloading instead of viewing
-    @header('Content-Type: text/html; charset=utf-8');
-    echo "<xmp>"; //<pre> is not good enough for us here
-} else {
-    //send proper plaintext header
-    @header('Content-Type: text/plain; charset=utf-8');
-}
+@header('Content-Type: text/plain; charset=utf-8');
 
 // we do not want html markup in emulated CLI
 @ini_set('html_errors', 'off');
 
 // execute the cron
 cron_run();
-
-// finish the IE hack
-if (check_browser_version('MSIE')) {
-    echo "</xmp>";
-}
-
-
index f96f83b..c733dda 100644 (file)
@@ -53,7 +53,7 @@ class tool_customlang_renderer extends plugin_renderer_base {
         $output = '';
 
         if (empty($translator->strings)) {
-            return $this->heading(get_string('nostringsfound', 'tool_customlang'), 3);
+            return $this->notification(get_string('nostringsfound', 'tool_customlang'));
         }
 
         $table = new html_table();
diff --git a/admin/tool/uploaduser/db/access.php b/admin/tool/uploaduser/db/access.php
new file mode 100644 (file)
index 0000000..7fe1c3f
--- /dev/null
@@ -0,0 +1,39 @@
+<?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/>.
+
+/**
+ * Defines the capabilities used by the user upload admin tool
+ *
+ * @package    tool_uploaduser
+ * @copyright  2013 Dan Poltawski <dan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$capabilities = array(
+
+    // Allows the user to upload user pictures.
+    'tool/uploaduser:uploaduserpictures' => array(
+        'riskbitmask' => RISK_SPAM,
+        'captype' => 'write',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'archetypes' => array(
+            'manager' => CAP_ALLOW
+        ),
+        'clonepermissionsfrom' =>  'moodle/site:uploadusers',
+    ),
+);
index 1c2330a..b8d46f3 100644 (file)
@@ -59,6 +59,7 @@ $string['uploadusers_help'] = 'Users may be uploaded (and optionally enrolled in
 * Required fieldnames are username, password, firstname, lastname, email';
 $string['uploaduserspreview'] = 'Upload users preview';
 $string['uploadusersresult'] = 'Upload users results';
+$string['uploaduser:uploaduserpictures'] = 'Upload user pictures';
 $string['useraccountupdated'] = 'User updated';
 $string['useraccountuptodate'] = 'User up-to-date';
 $string['userdeleted'] = 'User deleted';
index f0f1511..fe3d8e5 100644 (file)
@@ -38,7 +38,7 @@ admin_externalpage_setup('tooluploaduserpictures');
 
 require_login();
 
-require_capability('moodle/site:uploadusers', context_system::instance());
+require_capability('tool/uploaduser:uploaduserpictures', context_system::instance());
 
 $site = get_site();
 
index 0dc16e6..d3b37d2 100644 (file)
@@ -25,7 +25,5 @@
 
 defined('MOODLE_INTERNAL') || die;
 
-if (has_capability('moodle/site:uploadusers', $systemcontext)) {
-    $ADMIN->add('accounts', new admin_externalpage('tooluploaduser', get_string('uploadusers', 'tool_uploaduser'), "$CFG->wwwroot/$CFG->admin/tool/uploaduser/index.php", 'moodle/site:uploadusers'));
-    $ADMIN->add('accounts', new admin_externalpage('tooluploaduserpictures', get_string('uploadpictures','tool_uploaduser'), "$CFG->wwwroot/$CFG->admin/tool/uploaduser/picture.php", 'moodle/site:uploadusers'));
-}
+$ADMIN->add('accounts', new admin_externalpage('tooluploaduser', get_string('uploadusers', 'tool_uploaduser'), "$CFG->wwwroot/$CFG->admin/tool/uploaduser/index.php", 'moodle/site:uploadusers'));
+$ADMIN->add('accounts', new admin_externalpage('tooluploaduserpictures', get_string('uploadpictures','tool_uploaduser'), "$CFG->wwwroot/$CFG->admin/tool/uploaduser/picture.php", 'tool/uploaduser:uploaduserpictures'));
index 6de83e5..5116d1b 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2013050100; // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2013061400; // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2013050100; // Requires this Moodle version
 $plugin->component = 'tool_uploaduser'; // Full name of the plugin (used for diagnostics)
 
index 1483e20..9bfc65b 100644 (file)
@@ -23,6 +23,7 @@ echo $OUTPUT->header();
 //TODO: add support for large number of users
 
 if ($confirm and confirm_sesskey()) {
+    $notifications = '';
     list($in, $params) = $DB->get_in_or_equal($SESSION->bulk_users);
     $rs = $DB->get_recordset_select('user', "id $in", $params, '', 'id, username, secret, confirmed, auth, firstname, lastname');
     foreach ($rs as $user) {
@@ -32,12 +33,19 @@ if ($confirm and confirm_sesskey()) {
         $auth = get_auth_plugin($user->auth);
         $result = $auth->user_confirm($user->username, $user->secret);
         if ($result != AUTH_CONFIRM_OK && $result != AUTH_CONFIRM_ALREADY) {
-            echo $OUTPUT->notification(get_string('usernotconfirmed', '', fullname($user, true)));
+            $notifications .= $OUTPUT->notification(get_string('usernotconfirmed', '', fullname($user, true)));
         }
     }
     $rs->close();
-    redirect($return, get_string('changessaved'));
-
+    echo $OUTPUT->box_start('generalbox', 'notice');
+    if (!empty($notifications)) {
+        echo $notifications;
+    } else {
+        echo $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
+    }
+    $continue = new single_button(new moodle_url($return), get_string('continue'), 'post');
+    echo $OUTPUT->render($continue);
+    echo $OUTPUT->box_end();
 } else {
     list($in, $params) = $DB->get_in_or_equal($SESSION->bulk_users);
     $userlist = $DB->get_records_select_menu('user', "id $in", $params, 'fullname', 'id,'.$DB->sql_fullname().' AS fullname');
index f8ac0c9..4dbb75d 100644 (file)
@@ -23,20 +23,27 @@ echo $OUTPUT->header();
 //TODO: add support for large number of users
 
 if ($confirm and confirm_sesskey()) {
-
+    $notifications = '';
     list($in, $params) = $DB->get_in_or_equal($SESSION->bulk_users);
     $rs = $DB->get_recordset_select('user', "id $in", $params);
     foreach ($rs as $user) {
         if (!is_siteadmin($user) and $USER->id != $user->id and delete_user($user)) {
             unset($SESSION->bulk_users[$user->id]);
         } else {
-            echo $OUTPUT->notification(get_string('deletednot', '', fullname($user, true)));
+            $notifications .= $OUTPUT->notification(get_string('deletednot', '', fullname($user, true)));
         }
     }
     $rs->close();
     session_gc(); // remove stale sessions
-    redirect($return, get_string('changessaved'));
-
+    echo $OUTPUT->box_start('generalbox', 'notice');
+    if (!empty($notifications)) {
+        echo $notifications;
+    } else {
+        echo $OUTPUT->notification(get_string('changessaved'), 'notifysuccess');
+    }
+    $continue = new single_button(new moodle_url($return), get_string('continue'), 'post');
+    echo $OUTPUT->render($continue);
+    echo $OUTPUT->box_end();
 } else {
     list($in, $params) = $DB->get_in_or_equal($SESSION->bulk_users);
     $userlist = $DB->get_records_select_menu('user', "id $in", $params, 'fullname', 'id,'.$DB->sql_fullname().' AS fullname');
index c5cc194..76587f2 100644 (file)
@@ -60,9 +60,6 @@ if (!confirm_sesskey()) {
 }
 
 switch ($action) {
-    case 'uninstall':
-        die('TODO: not implemented yet');
-        break;
 
     case 'disable':
         // remove from enabled list
index 7e8e5d0..95ab725 100644 (file)
@@ -174,7 +174,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
      *
      */
     function connectCAS() {
-        global $PHPCAS_CLIENT;
+        global $CFG, $PHPCAS_CLIENT;
 
         if (!is_object($PHPCAS_CLIENT)) {
             // Make sure phpCAS doesn't try to start a new PHP session when connecting to the CAS server.
@@ -185,6 +185,27 @@ class auth_plugin_cas extends auth_plugin_ldap {
             }
         }
 
+        // If Moodle is configured to use a proxy, phpCAS needs some curl options set.
+        if (!empty($CFG->proxyhost) && !is_proxybypass($this->config->hostname)) {
+            phpCAS::setExtraCurlOption(CURLOPT_PROXY, $CFG->proxyhost);
+            if (!empty($CFG->proxyport)) {
+                phpCAS::setExtraCurlOption(CURLOPT_PROXYPORT, $CFG->proxyport);
+            }
+            if (!empty($CFG->proxytype)) {
+                // Only set CURLOPT_PROXYTYPE if it's something other than the curl-default http
+                if ($CFG->proxytype == 'SOCKS5') {
+                    phpCAS::setExtraCurlOption(CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
+                }
+            }
+            if (!empty($CFG->proxyuser) and !empty($CFG->proxypassword)) {
+                phpCAS::setExtraCurlOption(CURLOPT_PROXYUSERPWD, $CFG->proxyuser.':'.$CFG->proxypassword);
+                if (defined('CURLOPT_PROXYAUTH')) {
+                    // any proxy authentication if PHP 5.1
+                    phpCAS::setExtraCurlOption(CURLOPT_PROXYAUTH, CURLAUTH_BASIC | CURLAUTH_NTLM);
+                }
+            }
+        }
+
         if($this->config->certificate_check && $this->config->certificate_path){
             phpCAS::setCasServerCACert($this->config->certificate_path);
         }else{
index 222845b..ff9c863 100644 (file)
@@ -491,6 +491,6 @@ $help .= get_string('auth_updateremote_expl', 'auth');
 $help .= '<hr />';
 $help .= get_string('auth_updateremote_ldap', 'auth');
 
-print_auth_lock_options($this->authtype, $user_fields, $help, true, true);
+print_auth_lock_options($this->authtype, $user_fields, $help, true, true, $this->get_custom_user_profile_fields());
 ?>
 </table>
index d32f6bd..314e5be 100644 (file)
@@ -598,6 +598,8 @@ class auth_plugin_ldap extends auth_plugin_base {
                 if ($user->firstaccess == 0) {
                     $DB->set_field('user', 'firstaccess', time(), array('id'=>$user->id));
                 }
+                $euser = $DB->get_record('user', array('id' => $user->id));
+                events_trigger('user_updated', $euser);
                 return AUTH_CONFIRM_OK;
             }
         } else {
@@ -770,6 +772,8 @@ class auth_plugin_ldap extends auth_plugin_base {
                         $updateuser->auth = 'nologin';
                         $DB->update_record('user', $updateuser);
                         echo "\t"; print_string('auth_dbsuspenduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)); echo "\n";
+                        $euser = $DB->get_record('user', array('id' => $user->id));
+                        events_trigger('user_updated', $euser);
                     }
                 }
             } else {
@@ -795,6 +799,8 @@ class auth_plugin_ldap extends auth_plugin_base {
                     $updateuser->auth = $this->authtype;
                     $DB->update_record('user', $updateuser);
                     echo "\t"; print_string('auth_dbreviveduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)); echo "\n";
+                    $euser = $DB->get_record('user', array('id' => $user->id));
+                    events_trigger('user_updated', $euser);
                 }
             } else {
                 print_string('nouserentriestorevive', 'auth_ldap');
@@ -908,6 +914,8 @@ class auth_plugin_ldap extends auth_plugin_base {
 
                 $id = $DB->insert_record('user', $user);
                 echo "\t"; print_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)); echo "\n";
+                $euser = $DB->get_record('user', array('id' => $user->id));
+                events_trigger('user_created', $euser);
                 if (!empty($this->config->forcechangepassword)) {
                     set_user_preference('auth_forcepasswordchange', 1, $id);
                 }
@@ -978,6 +986,10 @@ class auth_plugin_ldap extends auth_plugin_base {
                     }
                 }
             }
+            if (!empty($updatekeys)) {
+                $euser = $DB->get_record('user', array('id' => $userid));
+                events_trigger('user_updated', $euser);
+            }
         } else {
             return false;
         }
@@ -1148,11 +1160,19 @@ class auth_plugin_ldap extends auth_plugin_base {
             $user_entry = array_change_key_case($user_entry[0], CASE_LOWER);
 
             foreach ($attrmap as $key => $ldapkeys) {
+                $profilefield = '';
                 // Only process if the moodle field ($key) has changed and we
                 // are set to update LDAP with it
+                $customprofilefield = 'profile_field_' . $key;
                 if (isset($olduser->$key) and isset($newuser->$key)
-                  and $olduser->$key !== $newuser->$key
-                  and !empty($this->config->{'field_updateremote_'. $key})) {
+                    and ($olduser->$key !== $newuser->$key)) {
+                    $profilefield = $key;
+                } else if (isset($olduser->$customprofilefield) && isset($newuser->$customprofilefield)
+                    && $olduser->$customprofilefield !== $newuser->$customprofilefield) {
+                    $profilefield = $customprofilefield;
+                }
+
+                if (!empty($profilefield) && !empty($this->config->{'field_updateremote_' . $key})) {
                     // For ldap values that could be in more than one
                     // ldap key, we will do our best to match
                     // where they came from
@@ -1165,9 +1185,9 @@ class auth_plugin_ldap extends auth_plugin_base {
                         $ambiguous = false;
                     }
 
-                    $nuvalue = textlib::convert($newuser->$key, 'utf-8', $this->config->ldapencoding);
+                    $nuvalue = textlib::convert($newuser->$profilefield, 'utf-8', $this->config->ldapencoding);
                     empty($nuvalue) ? $nuvalue = array() : $nuvalue;
-                    $ouvalue = textlib::convert($olduser->$key, 'utf-8', $this->config->ldapencoding);
+                    $ouvalue = textlib::convert($olduser->$profilefield, 'utf-8', $this->config->ldapencoding);
 
                     foreach ($ldapkeys as $ldapkey) {
                         $ldapkey   = $ldapkey;
@@ -1430,7 +1450,15 @@ class auth_plugin_ldap extends auth_plugin_base {
 
     function ldap_attributes () {
         $moodleattributes = array();
-        foreach ($this->userfields as $field) {
+        // If we have custom fields then merge them with user fields.
+        $customfields = $this->get_custom_user_profile_fields();
+        if (!empty($customfields) && !empty($this->userfields)) {
+            $userfields = array_merge($this->userfields, $customfields);
+        } else {
+            $userfields = $this->userfields;
+        }
+
+        foreach ($userfields as $field) {
             if (!empty($this->config->{"field_map_$field"})) {
                 $moodleattributes[$field] = textlib::strtolower(trim($this->config->{"field_map_$field"}));
                 if (preg_match('/,/', $moodleattributes[$field])) {
index 5140397..f23886a 100644 (file)
@@ -604,6 +604,6 @@ $help .= get_string('auth_updateremote_expl', 'auth');
 $help .= '<hr />';
 $help .= get_string('auth_updateremote_ldap', 'auth');
 
-print_auth_lock_options($this->authtype, $user_fields, $help, true, true);
+print_auth_lock_options($this->authtype, $user_fields, $help, true, true, $this->get_custom_user_profile_fields());
 ?>
 </table>
index 5f231e9..74bfef4 100644 (file)
@@ -73,8 +73,20 @@ class restore_course_task extends restore_task {
 
         $this->add_step(new restore_course_legacy_files_step('legacy_files'));
 
-        // Restore course enrolments (plugins and membership). Conditionally prevented for any IMPORT/HUB operation
-        if ($this->plan->get_mode() != backup::MODE_IMPORT && $this->plan->get_mode() != backup::MODE_HUB) {
+        // Deal with enrolment methods and user enrolments.
+        if ($this->plan->get_mode() == backup::MODE_IMPORT) {
+            // No need to do anything with enrolments.
+
+        } else if (!$this->get_setting_value('users') or $this->plan->get_mode() == backup::MODE_HUB) {
+            if ($this->get_target() == backup::TARGET_CURRENT_ADDING or $this->get_target() == backup::TARGET_EXISTING_ADDING) {
+                // Keep current enrolments unchanged.
+            } else {
+                // If no instances yet add default enrol methods the same way as when creating new course in UI.
+                $this->add_step(new restore_default_enrolments_step('default_enrolments'));
+            }
+
+        } else {
+            // Restore course enrolment data.
             $this->add_step(new restore_enrolments_structure_step('course_enrolments', 'enrolments.xml'));
         }
 
index d336631..f4a2d46 100644 (file)
@@ -143,6 +143,9 @@ class restore_final_task extends restore_task {
         $rules[] = new restore_log_rule('course', 'report stats', 'report/stats/index.php?id={course}', '{course}');
         $rules[] = new restore_log_rule('course', 'view section', 'view.php?id={course}&sectionid={course_section}', '{course_section}');
 
+        // module 'grade' rules
+        $rules[] = new restore_log_rule('grade', 'update', 'report/grader/index.php?id={course}', null);
+
         // module 'user' rules
         $rules[] = new restore_log_rule('user', 'view', 'view.php?id={user}&course={course}', '{user}');
         $rules[] = new restore_log_rule('user', 'change password', 'view.php?id={user}&course={course}', '{user}');
index f95a5b9..a0b90b8 100644 (file)
@@ -115,6 +115,7 @@ class restore_root_task extends restore_task {
         $rootenrolmanual = new restore_users_setting('enrol_migratetomanual', base_setting::IS_BOOLEAN, false);
         $rootenrolmanual->set_ui(new backup_setting_ui_checkbox($rootenrolmanual, get_string('rootenrolmanual', 'backup')));
         $rootenrolmanual->get_ui()->set_changeable(enrol_is_enabled('manual'));
+        $rootenrolmanual->get_ui()->set_changeable($changeable);
         $this->add_setting($rootenrolmanual);
         $users->add_dependency($rootenrolmanual);
 
index 8b02dc1..8797ee5 100644 (file)
@@ -477,6 +477,8 @@ class restore_rebuild_course_cache extends restore_execution_step {
 
         // Rebuild cache now that all sections are in place
         rebuild_course_cache($this->get_courseid());
+        cache_helper::purge_by_event('changesincourse');
+        cache_helper::purge_by_event('changesincoursecat');
     }
 }
 
@@ -1623,6 +1625,29 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
     }
 }
 
+/**
+ * If no instances yet add default enrol methods the same way as when creating new course in UI.
+ */
+class restore_default_enrolments_step extends restore_execution_step {
+    public function define_execution() {
+        global $DB;
+
+        $course = $DB->get_record('course', array('id'=>$this->get_courseid()), '*', MUST_EXIST);
+
+        if ($DB->record_exists('enrol', array('courseid'=>$this->get_courseid(), 'enrol'=>'manual'))) {
+            // Something already added instances, do not add default instances.
+            $plugins = enrol_get_plugins(true);
+            foreach ($plugins as $plugin) {
+                $plugin->restore_sync_course($course);
+            }
+
+        } else {
+            // Looks like a newly created course.
+            enrol_course_updated(true, $course, null);
+        }
+    }
+}
+
 /**
  * This structure steps restores the enrol plugins and their underlying
  * enrolments, performing all the mappings and/or movements required
index 245f545..586ee70 100644 (file)
@@ -1,6 +1,12 @@
 This files describes API changes in /backup/*,
 information provided here is intended especially for developers.
 
+=== 2.6 ===
+
+* The backup_controller_dbops::create_temptable_from_real_table()
+  method is not available anymore. Temp tables must be created
+  inline always.
+
 === 2.5 ===
 
 * New optional param $sortby in backup set_source_table() allows to
index 68c1752..2e8da16 100644 (file)
@@ -103,58 +103,44 @@ abstract class backup_controller_dbops extends backup_dbops {
     }
 
     public static function create_backup_ids_temp_table($backupid) {
-        self::create_temptable_from_real_table($backupid, 'backup_ids_template', 'backup_ids_temp');
+        global $CFG, $DB;
+        $dbman = $DB->get_manager(); // We are going to use database_manager services
+
+        $xmldb_table = new xmldb_table('backup_ids_temp');
+        $xmldb_table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
+        // Set default backupid (not needed but this enforce any missing backupid). That's hackery in action!
+        $xmldb_table->add_field('backupid', XMLDB_TYPE_CHAR, 32, null, XMLDB_NOTNULL, null, $backupid);
+        $xmldb_table->add_field('itemname', XMLDB_TYPE_CHAR, 160, null, XMLDB_NOTNULL, null, null);
+        $xmldb_table->add_field('itemid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null);
+        $xmldb_table->add_field('newitemid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, '0');
+        $xmldb_table->add_field('parentitemid', XMLDB_TYPE_INTEGER, 10, null, null, null, '0');
+        $xmldb_table->add_field('info', XMLDB_TYPE_TEXT, 1333, null, null, null, null);
+        $xmldb_table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $xmldb_table->add_key('backupid_itemname_itemid_uk', XMLDB_KEY_UNIQUE, array('backupid','itemname','itemid'));
+        $xmldb_table->add_index('backupid_parentitemid_ix', null, array('backupid','itemname','parentitemid'));
+        $xmldb_table->add_index('backupid_itemname_newitemid_ix', null, array('backupid','itemname','newitemid'));
+
+        $dbman->create_temp_table($xmldb_table); // And create it
+
     }
 
-    /**
-     * Given one "real" tablename, create one temp table suitable for be used in backup/restore operations
-     */
-    public static function create_temptable_from_real_table($backupid, $realtablename, $temptablename) {
+    public static function create_backup_files_temp_table($backupid) {
         global $CFG, $DB;
         $dbman = $DB->get_manager(); // We are going to use database_manager services
 
-        // As far as xmldb objects use a lot of circular references (prev and next) and we aren't destroying
-        // them at all, that causes one memory leak of about 3M per backup execution, not problematic for
-        // individual backups but critical for automated (multiple) ones.
-        // So we are statically caching the xmldb_table definition here to produce the leak "only" once
-        static $xmldb_tables = array();
-
-        // Not cached, get it
-        if (!isset($xmldb_tables[$realtablename])) {
-            // Note: For now we are going to load the realtablename from core lib/db/install.xml
-            // that way, any change in the "template" will be applied here automatically. If this causes
-            // too much slow, we can always forget about the template and keep maintained the xmldb_table
-            // structure inline - manually - here.
-            // TODO: Right now, loading the whole lib/db/install.xml is "eating" 10M, we should
-            // change our way here in order to decrease that memory usage
-            $templatetablename = $realtablename;
-            $targettablename   = $temptablename;
-            $xmlfile = $CFG->dirroot . '/lib/db/install.xml';
-            $xmldb_file = new xmldb_file($xmlfile);
-            if (!$xmldb_file->fileExists()) {
-                throw new ddl_exception('ddlxmlfileerror', null, 'File does not exist');
-            }
-            $loaded = $xmldb_file->loadXMLStructure();
-            if (!$loaded || !$xmldb_file->isLoaded()) {
-                throw new ddl_exception('ddlxmlfileerror', null, 'not loaded??');
-            }
-            $xmldb_structure = $xmldb_file->getStructure();
-            $xmldb_table = $xmldb_structure->getTable($templatetablename);
-            if (is_null($xmldb_table)) {
-                throw new ddl_exception('ddlunknowntable', null, 'The table ' . $templatetablename . ' is not defined in file ' . $xmlfile);
-            }
-            // Clean prev & next, we are alone
-            $xmldb_table->setNext(null);
-            $xmldb_table->setPrevious(null);
-            // Rename
-            $xmldb_table->setName($targettablename);
-            // Cache it
-            $xmldb_tables[$realtablename] = $xmldb_table;
-        }
-        // Arrived here, we have the table always in static cache, get it
-        $xmldb_table = $xmldb_tables[$realtablename];
+        $xmldb_table = new xmldb_table('backup_files_temp');
+        $xmldb_table->add_field('id', XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
         // Set default backupid (not needed but this enforce any missing backupid). That's hackery in action!
-        $xmldb_table->getField('backupid')->setDefault($backupid);
+        $xmldb_table->add_field('backupid', XMLDB_TYPE_CHAR, 32, null, XMLDB_NOTNULL, null, $backupid);
+        $xmldb_table->add_field('contextid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null);
+        $xmldb_table->add_field('component', XMLDB_TYPE_CHAR, 100, null, XMLDB_NOTNULL, null, null);
+        $xmldb_table->add_field('filearea', XMLDB_TYPE_CHAR, 50, null, XMLDB_NOTNULL, null, null);
+        $xmldb_table->add_field('itemid', XMLDB_TYPE_INTEGER, 10, null, XMLDB_NOTNULL, null, null);
+        $xmldb_table->add_field('info', XMLDB_TYPE_TEXT, 1333, null, null, null, null);
+        $xmldb_table->add_field('newcontextid', XMLDB_TYPE_INTEGER, 10, null, null, null, '0');
+        $xmldb_table->add_field('newitemid', XMLDB_TYPE_INTEGER, 10, null, null, null, '0');
+        $xmldb_table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
+        $xmldb_table->add_index('backupid_contextid_component_filearea_itemid_ix', null, array('backupid','contextid','component','filearea','itemid'));
 
         $dbman->create_temp_table($xmldb_table); // And create it
     }
index 94674e7..b68358e 100644 (file)
@@ -111,8 +111,8 @@ abstract class restore_controller_dbops extends restore_dbops {
             // TODO: If not match, exception, table corresponds to another backup/restore operation
             return true;
         }
-        backup_controller_dbops::create_temptable_from_real_table($restoreid, 'backup_ids_template', 'backup_ids_temp');
-        backup_controller_dbops::create_temptable_from_real_table($restoreid, 'backup_files_template', 'backup_files_temp');
+        backup_controller_dbops::create_backup_ids_temp_table($restoreid);
+        backup_controller_dbops::create_backup_files_temp_table($restoreid);
         return false;
     }
 
index 9a469e0..96526c4 100644 (file)
@@ -168,6 +168,7 @@ abstract class award_criteria {
             if (in_array('grade', $this->optional_params)) {
                 $parameter[] =& $mform->createElement('static', 'mgrade_' . $param['id'], null, get_string('mingrade', 'badges'));
                 $parameter[] =& $mform->createElement('text', 'grade_' . $param['id'], '', array('size' => '5'));
+                $mform->setType('grade_' . $param['id'], PARAM_INT);
             }
 
             if (in_array('bydate', $this->optional_params)) {
index 6912813..c6089a2 100644 (file)
@@ -119,6 +119,7 @@ class award_criteria_course extends award_criteria {
             $parameter[] =& $mform->createElement('text', 'grade_' . $param['course'], '', array('size' => '5'));
             $parameter[] =& $mform->createElement('static', 'complby_' . $param['course'], null, get_string('bydate', 'badges'));
             $parameter[] =& $mform->createElement('date_selector', 'bydate_' . $param['course'], '', array('optional' => true));
+            $mform->setType('grade_' . $param['course'], PARAM_INT);
             $mform->addGroup($parameter, 'param_' . $param['course'], '', array(' '), false);
 
             $mform->disabledIf('bydate_' . $param['course'] . '[day]', 'bydate_' . $param['course'] . '[enabled]', 'notchecked');
index 2968a23..2af1c5d 100644 (file)
@@ -52,7 +52,7 @@ class block_badges extends block_base {
         return array(
                 'admin' => false,
                 'site-index' => true,
-                'course-view' => false,
+                'course-view' => true,
                 'mod' => false,
                 'my' => true
         );
@@ -88,8 +88,16 @@ class block_badges extends block_base {
 
         if (empty($CFG->enablebadges)) {
             $this->content->text .= get_string('badgesdisabled', 'badges');
-        } else if ($badges = badges_get_user_badges($USER->id, null, 0, $this->config->numberofbadges)) {
-            $output = $PAGE->get_renderer('core', 'badges');
+            return $this->content;
+        }
+
+        $courseid = $this->page->course->id;
+        if ($courseid == SITEID) {
+            $courseid = null;
+        }
+
+        if ($badges = badges_get_user_badges($USER->id, $courseid, 0, $this->config->numberofbadges)) {
+            $output = $this->page->get_renderer('core', 'badges');
             $this->content->text = $output->print_badges_list($badges, $USER->id, true);
         } else {
             $this->content->text .= get_string('nothingtodisplay', 'block_badges');
index 1ac4e90..bb29569 100644 (file)
@@ -103,6 +103,9 @@ class block_course_overview_renderer extends plugin_renderer_base {
 
             // No need to pass title through s() here as it will be done automatically by html_writer.
             $attributes = array('title' => $course->fullname);
+            if (empty($course->visible)) {
+                $attributes['class'] = 'dimmed';
+            }
             if ($course->id > 0) {
                 $courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
                 $coursefullname = format_string($course->fullname, true, $course->id);
index bb2fa22..95d0a3e 100644 (file)
@@ -836,8 +836,15 @@ M.core_dock.genericblock.prototype = {
         }
 
         // Must set the image src seperatly of we get an error with XML strict headers
-        var moveto = Y.Node.create('<input type="image" class="moveto customcommand requiresjs" alt="'+M.str.block.addtodock+'" title="'+
-            Y.Escape.html(M.util.get_string('dockblock', 'block', node.one('.header .title h2').getHTML())) +'" />');
+        var moveto = Y.Node.create('<input type="image" class="moveto customcommand requiresjs" />');
+        var header = node.one('.header .title h2');
+        moveto.setAttribute('alt', Y.Escape.html(M.util.get_string('addtodock', 'block')));
+        if (header) {
+            moveto.setAttribute('title', Y.Escape.html(M.util.get_string('dockblock', 'block', header.getHTML())));
+        } else {
+            moveto.setAttribute('title', Y.Escape.html(M.util.get_string('addtodock', 'block')));
+        }
+
         var icon = 't/block_to_dock';
         if (right_to_left()) {
             icon = 't/block_to_dock_rtl';
index 0772f6d..e6bc954 100644 (file)
Binary files a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js and b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js differ
index 30b9e85..b9cd9b2 100644 (file)
Binary files a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js and b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js differ
index 0772f6d..e6bc954 100644 (file)
Binary files a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js and b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js differ
index a6d0ed0..2141a95 100644 (file)
@@ -389,11 +389,15 @@ BRANCH.prototype = {
     },
     /**
      * Attaches required events to the branch structure.
+     *
+     * @chainable
+     * @method wire
+     * @return {BRANCH} This function is chainable, it always returns itself.
      */
     wire : function() {
         this.node = this.node || Y.one('#'+this.get('id'));
         if (!this.node) {
-            return false;
+            return this;
         }
         if (this.get('expandable')) {
             this.node.setAttribute('data-expandable', '1');
index 873dbbe..a6de07a 100644 (file)
@@ -350,6 +350,11 @@ class cache_helper {
      * @param string $definition
      */
     protected static function ensure_ready_for_stats($store, $definition) {
+        // This function is performance-sensitive, so exit as quickly as possible
+        // if we do not need to do anything.
+        if (isset(self::$stats[$definition][$store])) {
+            return;
+        }
         if (!array_key_exists($definition, self::$stats)) {
             self::$stats[$definition] = array(
                 $store => array(
@@ -513,8 +518,9 @@ class cache_helper {
      * @return string
      */
     public static function hash_key($key, cache_definition $definition) {
+        global $CFG;
         if ($definition->uses_simple_keys()) {
-            if (debugging() && preg_match('#[^a-zA-Z0-9_]#', $key)) {
+            if ($CFG->developerdebug && preg_match('#[^a-zA-Z0-9_]#', $key)) {
                 throw new coding_exception('Cache definition '.$definition->get_id().' requires simple keys. Invalid key provided.', $key);
             }
             // We put the key first so that we can be sure the start of the key changes.
index 9f7dc79..6f4e680 100644 (file)
@@ -912,7 +912,8 @@ class cache implements cache_loader {
      * @return bool
      */
     protected function is_in_persist_cache($key) {
-        if (is_array($key)) {
+        // This method of checking if an array was supplied is faster than is_array.
+        if ($key === (array)$key) {
             $key = $key['key'];
         }
         // This could be written as a single line, however it has been split because the ttl check is faster than the instanceof
@@ -933,10 +934,15 @@ class cache implements cache_loader {
      * @return mixed|false The data from the persist cache or false if it wasn't there.
      */
     protected function get_from_persist_cache($key) {
-        if (is_array($key)) {
+        // This method of checking if an array was supplied is faster than is_array.
+        if ($key === (array)$key) {
             $key = $key['key'];
         }
-        if (!$this->persist || !array_key_exists($key, $this->persistcache)) {
+        // This isset check is faster than array_key_exists but will return false
+        // for null values, meaning null values will come from backing store not
+        // the persist cache. We think this okay because null usage should be
+        // very rare (see comment in MDL-39472).
+        if (!$this->persist || !isset($this->persistcache[$key])) {
             $result = false;
         } else {
             $data = $this->persistcache[$key];
@@ -976,7 +982,8 @@ class cache implements cache_loader {
      * @return bool
      */
     protected function set_in_persist_cache($key, $data) {
-        if (is_array($key)) {
+        // This method of checking if an array was supplied is faster than is_array.
+        if ($key === (array)$key) {
             $key = $key['key'];
         }
         $this->persistcache[$key] = $data;
index 18eb3e4..2828c3c 100644 (file)
@@ -27,7 +27,6 @@
  */
 
 require_once($CFG->dirroot.'/cache/forms.php');
-require_once($CFG->dirroot.'/cache/stores/file/lib.php');
 
 /**
  * Form for adding a file instance.
index edd55d7..984966a 100644 (file)
@@ -27,7 +27,6 @@
 defined('MOODLE_INTERNAL') || die();
 
 require_once($CFG->dirroot.'/cache/forms.php');
-require_once($CFG->dirroot.'/cache/stores/memcached/lib.php');
 
 /**
  * Form for adding a memcache instance.
index 1b2b8c7..ada3220 100644 (file)
@@ -35,7 +35,6 @@ defined('MOODLE_INTERNAL') || die();
 
 // Include the necessary evils.
 require_once($CFG->dirroot.'/cache/forms.php');
-require_once($CFG->dirroot.'/cache/stores/mongodb/lib.php');
 
 /**
  * The form to add an instance of the MongoDB store to the system.
index 38ecfe6..3c31556 100644 (file)
@@ -86,6 +86,7 @@ $search .= html_writer::start_tag('div');
 $search .= html_writer::label(get_string('searchcohort', 'cohort'), 'cohort_search_q'); // No : in form labels!
 $search .= html_writer::empty_tag('input', array('id'=>'cohort_search_q', 'type'=>'text', 'name'=>'search', 'value'=>$searchquery));
 $search .= html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('search', 'cohort')));
+$search .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'contextid', 'value'=>$contextid));
 $search .= html_writer::end_tag('div');
 $search .= html_writer::end_tag('form');
 echo $search;
index 8955f58..e74d2eb 100644 (file)
@@ -520,6 +520,10 @@ $CFG->admin = 'admin';
 // Example:
 //   $CFG->forced_plugin_settings = array('pluginname'  => array('settingname' => 'value', 'secondsetting' => 'othervalue'),
 //                                        'otherplugin' => array('mysetting' => 'myvalue', 'thesetting' => 'thevalue'));
+// Module default settings with advanced/locked checkboxes can be set too. To do this, add
+// an extra config with '_adv' or '_locked' as a suffix and set the value to true or false.
+// Example:
+//   $CFG->forced_plugin_settings = array('pluginname'  => array('settingname' => 'value', 'settingname_locked' => true, 'settingname_adv' => true));
 //
 //=========================================================================
 // 9. PHPUNIT SUPPORT
@@ -554,6 +558,11 @@ $CFG->admin = 'admin';
 //=========================================================================
 // 11. BEHAT SUPPORT
 //=========================================================================
+// Behat needs a separate data directory and unique database prefix:
+//
+// $CFG->behat_prefix = 'bht_';
+// $CFG->behat_dataroot = '/home/example/bht_moodledata';
+//
 // Behat uses http://localhost:8000 as default URL to run
 // the acceptance tests, you can override this value.
 // Example:
index 2fc377d..c845331 100644 (file)
@@ -81,7 +81,7 @@ class course_edit_form extends moodleform {
                 $displaylist = coursecat::make_categories_list('moodle/course:create');
                 if (!isset($displaylist[$course->category])) {
                     //always keep current
-                    $displaylist[$course->category] = coursecat::get($course->category)->get_formatted_name();
+                    $displaylist[$course->category] = coursecat::get($course->category, MUST_EXIST, true)->get_formatted_name();
                 }
                 $mform->addElement('select', 'category', get_string('coursecategory'), $displaylist);
                 $mform->addHelpButton('category', 'coursecategory');
@@ -248,7 +248,7 @@ class course_edit_form extends moodleform {
         enrol_course_edit_form($mform, $course, $context);
 
 //--------------------------------------------------------------------------------
-        $mform->addElement('header','groups', get_string('groups', 'group'));
+        $mform->addElement('header','groups', get_string('groupsettingsheader', 'group'));
 
         $choices = array();
         $choices[NOGROUPS] = get_string('groupsnone', 'group');
index c174ce3..75b400c 100644 (file)
@@ -902,9 +902,9 @@ class core_course_external extends external_api {
                                             "users" (int) Include users (default to 0 that is equal to no),
                                             "role_assignments" (int) Include role assignments  (default to 0 that is equal to no),
                                             "comments" (int) Include user comments  (default to 0 that is equal to no),
-                                            "completion_information" (int) Include user course completion information  (default to 0 that is equal to no),
+                                            "userscompletion" (int) Include user course completion information  (default to 0 that is equal to no),
                                             "logs" (int) Include course logs  (default to 0 that is equal to no),
-                                            "histories" (int) Include histories  (default to 0 that is equal to no)'
+                                            "grade_histories" (int) Include histories  (default to 0 that is equal to no)'
                                             ),
                                 'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
                             )
@@ -966,9 +966,9 @@ class core_course_external extends external_api {
             'users' => 0,
             'role_assignments' => 0,
             'comments' => 0,
-            'completion_information' => 0,
+            'userscompletion' => 0,
             'logs' => 0,
-            'histories' => 0
+            'grade_histories' => 0
         );
 
         $backupsettings = array();
index a12f187..5723eff 100644 (file)
@@ -235,7 +235,7 @@ abstract class format_base {
             return null;
         }
         if ($this->course === false) {
-            $this->course = $DB->get_record('course', array('id' => $this->courseid));
+            $this->course = get_course($this->courseid);
             $options = $this->get_format_options();
             foreach ($options as $optionname => $optionvalue) {
                 if (!isset($this->course->$optionname)) {
index b661c22..f154a05 100644 (file)
@@ -2,6 +2,8 @@
       // format.php - course format featuring social forum
       //              included from view.php
 
+    require_once($CFG->dirroot.'/mod/forum/lib.php');
+
     $strgroups  = get_string('groups');
     $strgroupmy = get_string('groupmy');
     $editing    = $PAGE->user_is_editing();
index debe045..71a0452 100644 (file)
@@ -257,6 +257,37 @@ class format_topics extends format_base {
         return $courseformatoptions;
     }
 
+    /**
+     * Adds format options elements to the course/section edit form.
+     *
+     * This function is called from {@link course_edit_form::definition_after_data()}.
+     *
+     * @param MoodleQuickForm $mform form the elements are added to.
+     * @param bool $forsection 'true' if this is a section edit form, 'false' if this is course edit form.
+     * @return array array of references to the added form elements.
+     */
+    public function create_edit_form_elements(&$mform, $forsection = false) {
+        $elements = parent::create_edit_form_elements($mform, $forsection);
+
+        // Increase the number of sections combo box values if the user has increased the number of sections
+        // using the icon on the course page beyond course 'maxsections' or course 'maxsections' has been
+        // reduced below the number of sections already set for the course on the site administration course
+        // defaults page.  This is so that the number of sections is not reduced leaving unintended orphaned
+        // activities / resources.
+        if (!$forsection) {
+            $maxsections = get_config('moodlecourse', 'maxsections');
+            $numsections = $mform->getElementValue('numsections');
+            $numsections = $numsections[0];
+            if ($numsections > $maxsections) {
+                $element = $mform->getElement('numsections');
+                for ($i = $maxsections+1; $i <= $numsections; $i++) {
+                    $element->addOption("$i", $i);
+                }
+            }
+        }
+        return $elements;
+    }
+
     /**
      * Updates format options for a course
      *
index e293a9d..ffc7be6 100644 (file)
@@ -35,6 +35,20 @@ require_once($CFG->dirroot.'/course/format/renderer.php');
  */
 class format_topics_renderer extends format_section_renderer_base {
 
+    /**
+     * Constructor method, calls the parent constructor
+     *
+     * @param moodle_page $page
+     * @param string $target one of rendering target constants
+     */
+    public function __construct(moodle_page $page, $target) {
+        parent::__construct($page, $target);
+
+        // Since format_topics_renderer::section_edit_controls() only displays the 'Set current section' control when editing mode is on
+        // we need to be sure that the link 'Turn editing mode on' is available for a user who does not have any other managing capability.
+        $page->set_other_editing_capability('moodle/course:setcurrentsection');
+    }
+
     /**
      * Generate the starting container html for a list of sections
      * @return string HTML to output.
index 40686d4..d31128b 100644 (file)
@@ -64,7 +64,7 @@ class format_weeks extends format_base {
             // We subtract 24 hours for display purposes.
             $dates->end = ($dates->end - 86400);
 
-            $dateformat = ' '.get_string('strftimedateshort');
+            $dateformat = get_string('strftimedateshort');
             $weekday = userdate($dates->start, $dateformat);
             $endweekday = userdate($dates->end, $dateformat);
             return $weekday.' - '.$endweekday;
@@ -262,6 +262,37 @@ class format_weeks extends format_base {
         return $courseformatoptions;
     }
 
+    /**
+     * Adds format options elements to the course/section edit form.
+     *
+     * This function is called from {@link course_edit_form::definition_after_data()}.
+     *
+     * @param MoodleQuickForm $mform form the elements are added to.
+     * @param bool $forsection 'true' if this is a section edit form, 'false' if this is course edit form.
+     * @return array array of references to the added form elements.
+     */
+    public function create_edit_form_elements(&$mform, $forsection = false) {
+        $elements = parent::create_edit_form_elements($mform, $forsection);
+
+        // Increase the number of sections combo box values if the user has increased the number of sections
+        // using the icon on the course page beyond course 'maxsections' or course 'maxsections' has been
+        // reduced below the number of sections already set for the course on the site administration course
+        // defaults page.  This is so that the number of sections is not reduced leaving unintended orphaned
+        // activities / resources.
+        if (!$forsection) {
+            $maxsections = get_config('moodlecourse', 'maxsections');
+            $numsections = $mform->getElementValue('numsections');
+            $numsections = $numsections[0];
+            if ($numsections > $maxsections) {
+                $element = $mform->getElement('numsections');
+                for ($i = $maxsections+1; $i <= $numsections; $i++) {
+                    $element->addOption("$i", $i);
+                }
+            }
+        }
+        return $elements;
+    }
+
     /**
      * Updates format options for a course
      *
index f1663f7..9f2bb26 100644 (file)
@@ -105,6 +105,9 @@ function make_log_url($module, $url) {
         case 'role':
             $url = '/'.$url;
             break;
+        case 'grade':
+            $url = "/grade/$url";
+            break;
         default:
             $url = "/mod/$module/$url";
             break;
@@ -1578,38 +1581,6 @@ function delete_mod_from_section($modid, $sectionid) {
     return false;
 }
 
-/**
- * Moves a section up or down by 1. CANNOT BE USED DIRECTLY BY AJAX!
- *
- * @param object $course course object
- * @param int $section Section number (not id!!!)
- * @param int $move (-1 or 1)
- * @return boolean true if section moved successfully
- * @todo MDL-33379 remove this function in 2.5
- */
-function move_section($course, $section, $move) {
-    debugging('This function will be removed before 2.5 is released please use move_section_to', DEBUG_DEVELOPER);
-
-/// Moves a whole course section up and down within the course
-    global $USER;
-
-    if (!$move) {
-        return true;
-    }
-
-    $sectiondest = $section + $move;
-
-    // compartibility with course formats using field 'numsections'
-    $courseformatoptions = course_get_format($course)->get_format_options();
-    if (array_key_exists('numsections', $courseformatoptions) &&
-            $sectiondest > $courseformatoptions['numsections'] or $sectiondest < 1) {
-        return false;
-    }
-
-    $retval = move_section_to($course, $section, $sectiondest);
-    return $retval;
-}
-
 /**
  * Moves a section within a course, from a position to another.
  * Be very careful: $section and $destination refer to section number,
index fbc384d..df8c5f4 100644 (file)
@@ -183,6 +183,7 @@ if ((!empty($moveupcat) or !empty($movedowncat)) and confirm_sesskey()) {
     if ($swapcategory and $movecategory) {
         $DB->set_field('course_categories', 'sortorder', $swapcategory->sortorder, array('id' => $movecategory->id));
         $DB->set_field('course_categories', 'sortorder', $movecategory->sortorder, array('id' => $swapcategory->id));
+        cache_helper::purge_by_event('changesincoursecat');
         add_to_log(SITEID, "category", "move", "editcategory.php?id=$movecategory->id", $movecategory->id);
     }
 
index d9345e3..1cf3b8f 100644 (file)
@@ -49,6 +49,12 @@ abstract class moodleform_mod extends moodleform {
     /** a flag indicating whether outcomes are being used*/
     protected $_outcomesused;
 
+    /**
+     * @var bool A flag used to indicate that this module should lock settings
+     *           based on admin settings flags in definition_after_data.
+     */
+    protected $applyadminlockedflags = false;
+
     function moodleform_mod($current, $section, $cm, $course) {
         $this->current   = $current;
         $this->_instance = $current->instance;
@@ -278,6 +284,9 @@ abstract class moodleform_mod extends moodleform {
                 }
             }
         }
+
+        // Freeze admin defaults if required (and not different from default)
+        $this->apply_admin_locked_flags();
     }
 
     // form verification
@@ -864,6 +873,99 @@ abstract class moodleform_mod extends moodleform {
         $mform->setType('buttonar', PARAM_RAW);
         $mform->closeHeaderBefore('buttonar');
     }
+
+    /**
+     * Get the list of admin settings for this module and apply any locked settings.
+     * This cannot happen in apply_admin_defaults because we do not the current values of the settings
+     * in that function because set_data has not been called yet.
+     *
+     * @return void
+     */
+    protected function apply_admin_locked_flags() {
+        global $OUTPUT;
+
+        if (!$this->applyadminlockedflags) {
+            return;
+        }
+
+        $settings = get_config($this->_modname);
+        $mform = $this->_form;
+        $lockedicon = html_writer::tag('span',
+                                       $OUTPUT->pix_icon('t/locked', get_string('locked', 'admin')),
+                                       array('class' => 'action-icon'));
+        $isupdate = !empty($this->_cm);
+
+        foreach ($settings as $name => $value) {
+            if (strpos('_', $name) !== false) {
+                continue;
+            }
+            if ($mform->elementExists($name)) {
+                $element = $mform->getElement($name);
+                $lockedsetting = $name . '_locked';
+                if (!empty($settings->$lockedsetting)) {
+                    // Always lock locked settings for new modules,
+                    // for updates, only lock them if the current value is the same as the default (or there is no current value).
+                    $value = $settings->$name;
+                    if ($isupdate && isset($this->current->$name)) {
+                        $value = $this->current->$name;
+                    }
+                    if ($value == $settings->$name) {
+                        $mform->setConstant($name, $settings->$name);
+                        $element->setLabel($element->getLabel() . $lockedicon);
+                        // Do not use hardfreeze because we need the hidden input to check dependencies.
+                        $element->freeze();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Get the list of admin settings for this module and apply any defaults/advanced/locked settings.
+     *
+     * @param $datetimeoffsets array - If passed, this is an array of fieldnames => times that the
+     *                         default date/time value should be relative to. If not passed, all
+     *                         date/time fields are set relative to the users current midnight.
+     * @return void
+     */
+    public function apply_admin_defaults($datetimeoffsets = array()) {
+        // This flag triggers the settings to be locked in apply_admin_locked_flags().
+        $this->applyadminlockedflags = true;
+
+        $settings = get_config($this->_modname);
+        $mform = $this->_form;
+        $usermidnight = usergetmidnight(time());
+        $isupdate = !empty($this->_cm);
+
+        foreach ($settings as $name => $value) {
+            if (strpos('_', $name) !== false) {
+                continue;
+            }
+            if ($mform->elementExists($name)) {
+                $element = $mform->getElement($name);
+                if (!$isupdate) {
+                    if ($element->getType() == 'date_time_selector') {
+                        $enabledsetting = $name . '_enabled';
+                        if (empty($settings->$enabledsetting)) {
+                            $mform->setDefault($name, 0);
+                        } else {
+                            $relativetime = $usermidnight;
+                            if (isset($datetimeoffsets[$name])) {
+                                $relativetime = $datetimeoffsets[$name];
+                            }
+                            $mform->setDefault($name, $relativetime + $settings->$name);
+                        }
+                    } else {
+                        $mform->setDefault($name, $settings->$name);
+                    }
+                }
+                $advancedsetting = $name . '_adv';
+                if (!empty($settings->$advancedsetting)) {
+                    $mform->setAdvanced($name);
+                }
+            }
+        }
+    }
 }
 
 
index 0e3da60..9bc279d 100644 (file)
@@ -72,11 +72,11 @@ class core_course_renderer extends plugin_renderer_base {
                 $this->page->course->id == SITEID ||
                 !$this->page->user_is_editing() ||
                 !($context = context_course::instance($this->page->course->id)) ||
-                !has_capability('moodle/course:update', $context) ||
+                !has_capability('moodle/course:manageactivities', $context) ||
                 !course_ajax_enabled($this->page->course) ||
                 !($coursenode = $this->page->settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) ||
-                !$coursenode->get('editsettings')) {
-            // too late or we are on site page or we could not find the course settings node
+                !($turneditingnode = $coursenode->get('turneditingonoff'))) {
+            // too late or we are on site page or we could not find the adjacent nodes in course settings menu
             // or we are not allowed to edit
             return;
         }
@@ -97,8 +97,13 @@ class core_course_renderer extends plugin_renderer_base {
             $modchoosertogglestring = get_string('modchooserenable', 'moodle');
             $modchoosertoggleurl->param('modchooser', 'on');
         }
-        $modchoosertoggle = navigation_node::create($modchoosertogglestring, $modchoosertoggleurl, navigation_node::TYPE_SETTING);
-        $coursenode->add_node($modchoosertoggle, 'editsettings');
+        $modchoosertoggle = navigation_node::create($modchoosertogglestring, $modchoosertoggleurl, navigation_node::TYPE_SETTING, null, 'modchoosertoggle');
+
+        // Insert the modchoosertoggle after the settings node 'turneditingonoff' (navigation_node only has function to insert before, so we insert before and then swap).
+        $coursenode->add_node($modchoosertoggle, 'turneditingonoff');
+        $turneditingnode->remove();
+        $coursenode->add_node($turneditingnode, 'modchoosertoggle');
+
         $modchoosertoggle->add_class('modchoosertoggle');
         $modchoosertoggle->add_class('visibleifjs');
         user_preference_allow_ajax_update('usemodchooser', PARAM_BOOL);
@@ -369,9 +374,7 @@ class core_course_renderer extends plugin_renderer_base {
         $activities = array(MOD_CLASS_ACTIVITY => array(), MOD_CLASS_RESOURCE => array());
 
         foreach ($modules as $module) {
-            if (!array_key_exists($module->archetype, $activities)) {
-                // System modules cannot be added by user, do not add to dropdown
-            } else if (isset($module->types)) {
+            if (isset($module->types)) {
                 // This module has a subtype
                 // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!!
                 $subtypes = array();
@@ -381,17 +384,28 @@ class core_course_renderer extends plugin_renderer_base {
                 }
 
                 // Sort module subtypes into the list
+                $activityclass = MOD_CLASS_ACTIVITY;
+                if ($module->archetype == MOD_CLASS_RESOURCE) {
+                    $activityclass = MOD_CLASS_RESOURCE;
+                }
                 if (!empty($module->title)) {
                     // This grouping has a name
-                    $activities[$module->archetype][] = array($module->title => $subtypes);
+                    $activities[$activityclass][] = array($module->title => $subtypes);
                 } else {
                     // This grouping does not have a name
-                    $activities[$module->archetype] = array_merge($activities[$module->archetype], $subtypes);
+                    $activities[$activityclass] = array_merge($activities[$activityclass], $subtypes);
                 }
             } else {
                 // This module has no subtypes
+                $activityclass = MOD_CLASS_ACTIVITY;
+                if ($module->archetype == MOD_ARCHETYPE_RESOURCE) {
+                    $activityclass = MOD_CLASS_RESOURCE;
+                } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) {
+                    // System modules cannot be added by user, do not add to dropdown
+                    continue;
+                }
                 $link = $module->link->out(true, $urlparams);
-                $activities[$module->archetype][$link] = $module->title;
+                $activities[$activityclass][$link] = $module->title;
             }
         }
 
index afd8ca9..d6d9c1d 100644 (file)
@@ -100,6 +100,8 @@ class courselib_testcase extends advanced_testcase {
         $moduleinfo->requireallteammemberssubmit = true;
         $moduleinfo->teamsubmissiongroupingid = true;
         $moduleinfo->blindmarking = true;
+        $moduleinfo->markingworkflow = true;
+        $moduleinfo->markingallocation = true;
         $moduleinfo->assignsubmission_onlinetext_enabled = true;
         $moduleinfo->assignsubmission_file_enabled = true;
         $moduleinfo->assignsubmission_file_maxfiles = 1;
@@ -134,6 +136,8 @@ class courselib_testcase extends advanced_testcase {
         $this->assertEquals($moduleinfo->requireallteammemberssubmit, $dbmodinstance->requireallteammemberssubmit);
         $this->assertEquals($moduleinfo->teamsubmissiongroupingid, $dbmodinstance->teamsubmissiongroupingid);
         $this->assertEquals($moduleinfo->blindmarking, $dbmodinstance->blindmarking);
+        $this->assertEquals($moduleinfo->markingworkflow, $dbmodinstance->markingworkflow);
+        $this->assertEquals($moduleinfo->markingallocation, $dbmodinstance->markingallocation);
         // The goal not being to fully test assign_add_instance() we'll stop here for the assign tests - to avoid too many DB queries.
 
         // Advanced grading.
index 59e0c60..5fdbd41 100644 (file)
@@ -671,7 +671,15 @@ class core_course_external_testcase extends externallib_advanced_testcase {
      * Test update_courses
      */
     public function test_update_courses() {
-        global $DB, $CFG, $USER;
+        global $DB, $CFG, $USER, $COURSE;
+
+        // Get current $COURSE to be able to restore it later (defaults to $SITE). We need this
+        // trick because we are both updating and getting (for testing) course information
+        // in the same request and core_course_external::update_courses()
+        // is overwriting $COURSE all over the time with OLD values, so later
+        // use of get_course() fetches those OLD values instead of the updated ones.
+        // See MDL-39723 for more info.
+        $origcourse = clone($COURSE);
 
         $this->resetAfterTest(true);
 
@@ -724,6 +732,7 @@ class core_course_external_testcase extends externallib_advanced_testcase {
         $courses = array($course1, $course2);
 
         $updatedcoursewarnings = core_course_external::update_courses($courses);
+        $COURSE = $origcourse; // Restore $COURSE. Instead of using the OLD one set by the previous line.
 
         // Check that right number of courses were created.
         $this->assertEquals(0, count($updatedcoursewarnings['warnings']));
index 02ae982..f7f925d 100644 (file)
@@ -4,7 +4,6 @@
 
     require_once('../config.php');
     require_once('lib.php');
-    require_once($CFG->dirroot.'/mod/forum/lib.php');
     require_once($CFG->libdir.'/conditionlib.php');
     require_once($CFG->libdir.'/completionlib.php');
 
 
     $PAGE->set_pagelayout('course');
     $PAGE->set_pagetype('course-view-' . $course->format);
+    $PAGE->set_other_editing_capability('moodle/course:update');
     $PAGE->set_other_editing_capability('moodle/course:manageactivities');
+    $PAGE->set_other_editing_capability('moodle/course:activityvisibility');
+    if (course_format_uses_sections($course->format)) {
+        $PAGE->set_other_editing_capability('moodle/course:sectionvisibility');
+        $PAGE->set_other_editing_capability('moodle/course:movesections');
+    }
 
     // Preload course format renderer before output starts.
     // This is a little hacky but necessary since
             }
         }
 
-        if (has_capability('moodle/course:update', $context)) {
-            if (!empty($section)) {
-                if (!empty($move) and has_capability('moodle/course:movesections', $context) and confirm_sesskey()) {
-                    $destsection = $section + $move;
-                    if (move_section_to($course, $section, $destsection)) {
-                        if ($course->id == SITEID) {
-                            redirect($CFG->wwwroot . '/?redirect=0');
-                        } else {
-                            redirect(course_get_url($course));
-                        }
-                    } else {
-                        echo $OUTPUT->notification('An error occurred while moving a section');
-                    }
+        if (!empty($section) && !empty($move) &&
+                has_capability('moodle/course:movesections', $context) && confirm_sesskey()) {
+            $destsection = $section + $move;
+            if (move_section_to($course, $section, $destsection)) {
+                if ($course->id == SITEID) {
+                    redirect($CFG->wwwroot . '/?redirect=0');
+                } else {
+                    redirect(course_get_url($course));
                 }
+            } else {
+                echo $OUTPUT->notification('An error occurred while moving a section');
             }
         }
     } else {
index ab6f719..10e12e1 100644 (file)
@@ -340,7 +340,7 @@ class enrol_manual_plugin extends enrol_plugin {
             $rs->close();
             unset($instances);
 
-        } else if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
+        } else if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES or $action == ENROL_EXT_REMOVED_SUSPEND) {
             $instances = array();
             $sql = "SELECT ue.*, e.courseid, c.id AS contextid
                       FROM {user_enrolments} ue
@@ -355,10 +355,15 @@ class enrol_manual_plugin extends enrol_plugin {
                     $instances[$ue->enrolid] = $DB->get_record('enrol', array('id'=>$ue->enrolid));
                 }
                 $instance = $instances[$ue->enrolid];
-                // Always remove all manually assigned roles here, this may break enrol_self roles but we do not want hardcoded hacks here.
-                role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
-                $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
-                $trace->output("suspending expired user $ue->userid in course $instance->courseid", 1);
+                if ($action == ENROL_EXT_REMOVED_SUSPENDNOROLES) {
+                    // Remove all manually assigned roles here, this may break enrol_self roles but we do not want hardcoded hacks here.
+                    role_unassign_all(array('userid'=>$ue->userid, 'contextid'=>$ue->contextid, 'component'=>'', 'itemid'=>0), true);
+                    $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
+                    $trace->output("suspending expired user $ue->userid in course $instance->courseid, roles unassigned", 1);
+                } else {
+                    $this->update_user_enrol($instance, $ue->userid, ENROL_USER_SUSPENDED);
+                    $trace->output("suspending expired user $ue->userid in course $instance->courseid, roles kept", 1);
+                }
             }
             $rs->close();
             unset($instances);
index 8905c1f..dbfc766 100644 (file)
@@ -33,6 +33,7 @@ if ($ADMIN->fulltree) {
     //       it describes what should happend when users are not supposed to be enerolled any more.
     $options = array(
         ENROL_EXT_REMOVED_KEEP           => get_string('extremovedkeep', 'enrol'),
+        ENROL_EXT_REMOVED_SUSPEND        => get_string('extremovedsuspend', 'enrol'),
         ENROL_EXT_REMOVED_SUSPENDNOROLES => get_string('extremovedsuspendnoroles', 'enrol'),
         ENROL_EXT_REMOVED_UNENROL        => get_string('extremovedunenrol', 'enrol'),
     );
index 77ffc6b..4f4c6d2 100644 (file)
@@ -304,6 +304,30 @@ class enrol_manual_lib_testcase extends advanced_testcase {
         $this->assertEquals(4, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
         $this->assertEquals(0, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
         $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$managerrole->id)));
+
+
+        $manualplugin->set_config('expiredaction', ENROL_EXT_REMOVED_SUSPEND);
+        $manualplugin->enrol_user($instance1, $user3->id, $studentrole->id, 0, $now-60);
+        $manualplugin->enrol_user($instance3, $user3->id, $teacherrole->id, 0, $now-60*60);
+        $maninstance1 = $DB->get_record('enrol', array('courseid'=>$course1->id, 'enrol'=>'manual'), '*', MUST_EXIST);
+        $maninstance2 = $DB->get_record('enrol', array('courseid'=>$course3->id, 'enrol'=>'manual'), '*', MUST_EXIST);
+
+        $this->assertEquals(6, $DB->count_records('user_enrolments'));
+        $this->assertEquals(7, $DB->count_records('role_assignments'));
+        $this->assertEquals(5, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
+        $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
+        $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user3->id, 'status'=>ENROL_USER_ACTIVE)));
+        $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance2->id, 'userid'=>$user3->id, 'status'=>ENROL_USER_ACTIVE)));
+
+        $manualplugin->sync($trace, null);
+        $this->assertEquals(6, $DB->count_records('user_enrolments'));
+        $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance1->id, 'userid'=>$user3->id)));
+        $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$instance3->id, 'userid'=>$user3->id)));
+        $this->assertEquals(7, $DB->count_records('role_assignments'));
+        $this->assertEquals(5, $DB->count_records('role_assignments', array('roleid'=>$studentrole->id)));
+        $this->assertEquals(1, $DB->count_records('role_assignments', array('roleid'=>$teacherrole->id)));
+        $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance1->id, 'userid'=>$user3->id, 'status'=>ENROL_USER_SUSPENDED)));
+        $this->assertTrue($DB->record_exists('user_enrolments', array('enrolid'=>$maninstance2->id, 'userid'=>$user3->id, 'status'=>ENROL_USER_SUSPENDED)));
     }
 
     public function test_send_expiry_notifications() {
index d7ca920..9d01e8d 100644 (file)
@@ -122,19 +122,25 @@ class filter_urltolink extends moodle_text_filter {
             $unicoderegexp = @preg_match('/\pL/u', 'a'); // This will fail silently, returning false,
         }
 
-        //todo: MDL-21296 - use of unicode modifiers may cause a timeout
-        if ($unicoderegexp) { //We can use unicode modifiers
-            $text = preg_replace('#(?<!=["\'])(((http(s?))://)(((([\pLl0-9]([\pLl0-9]|-)*[\pLl0-9]|[\pLl0-9])\.)+([\pLl]([\pLl0-9]|-)*[\pLl0-9]|[\pLl]))|(([0-9]{1,3}\.){3}[0-9]{1,3}))(:[\pL0-9]*)?(/([\pLl0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-fA-F0-9]{2})*)*(\?([\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#iu',
-                                 '<a href="\\1" class="_blanktarget">\\1</a>', $text);
-            $text = preg_replace('#(?<!=["\']|//)((www\.([\pLl0-9]([\pLl0-9]|-)*[\pLl0-9]|[\pLl0-9])\.)+([\pLl]([\pLl0-9]|-)*[\pLl0-9]|[\pLl])(:[\pL0-9]*)?(/([\pLl0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-fA-F0-9]{2})*)*(\?([\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[\pLl0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#iu',
-                                 '<a href="http://\\1" class="_blanktarget">\\1</a>', $text);
-        } else { //We cannot use unicode modifiers
-            $text = preg_replace('#(?<!=["\'])(((http(s?))://)(((([a-z0-9]([a-z0-9]|-)*[a-z0-9]|[a-z0-9])\.)+([a-z]([a-z0-9]|-)*[a-z0-9]|[a-z]))|(([0-9]{1,3}\.){3}[0-9]{1,3}))(:[a-zA-Z0-9]*)?(/([a-z0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-f0-9]{2})*)*(\?([a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#i',
-                                 '<a href="\\1" class="_blanktarget">\\1</a>', $text);
-            $text = preg_replace('#(?<!=["\']|//)((www\.([a-z0-9]([a-z0-9]|-)*[a-z0-9]|[a-z0-9])\.)+([a-z]([a-z0-9]|-)*[a-z0-9]|[a-z])(:[a-zA-Z0-9]*)?(/([a-z0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-f0-9]{2})*)*(\?([a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)?(\#[a-z0-9\.!$&\'\(\)*+,;=_~:@/?-]*)?)(?<![,.;])#i',
-                                 '<a href="http://\\1" class="_blanktarget">\\1</a>', $text);
+        // TODO MDL-21296 - use of unicode modifiers may cause a timeout
+        $domainsegment = '(?:[\pLl0-9][\pLl0-9-]*[\pLl0-9]|[\pLl0-9])';
+        $numericip = '(?:(?:[0-9]{1,3}\.){3}[0-9]{1,3})';
+        $port = '(?::\d*)';
+        $pathchar = '(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@-]|%[a-f0-9]{2})';
+        $path = "(?:/$pathchar*)*";
+        $querystring = '(?:\?(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
+        $fragment = '(?:\#(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
+
+        $regex = "(?<!=[\"'])(?:http(s)?://|(www\.))((?:$domainsegment\.)+$domainsegment|$numericip)" .
+                "($port?$path$querystring?$fragment?)(?<![]),.;])";
+        if ($unicoderegexp) {
+            $regex = '#' . $regex . '#ui';
+        } else {
+            $regex = '#' . preg_replace(array('\pLl', '\PL'), 'a-z', $regex) . '#i';
         }
 
+        $text = preg_replace($regex, '<a href="http$1://$2$3$4" class="_blanktarget">$0</a>', $text);
+
         if (!empty($ignoretags)) {
             $ignoretags = array_reverse($ignoretags); /// Reversed so "progressive" str_replace() will solve some nesting problems.
             $text = str_replace(array_keys($ignoretags),$ignoretags,$text);
index 95109d1..70fb3f1 100644 (file)
@@ -44,7 +44,7 @@ class filter_urltolink_testcase extends basic_testcase {
             '$1<a href="http://www.$2$3" target="_blank">www.$2$3</a>', $text);
     }
 
-    function test_convert_urls_into_links() {
+    function get_convert_urls_into_links_test_cases() {
         $texts = array (
             //just a url
             'http://moodle.org - URL' => '<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a> - URL',
@@ -57,13 +57,26 @@ class filter_urltolink_testcase extends basic_testcase {
             'URL: https://moodle.org/s/i=1&j=2' => 'URL: <a href="https://moodle.org/s/i=1&j=2" class="_blanktarget">https://moodle.org/s/i=1&j=2</a>',
             //url with port and params
             'URL: http://moodle.org:8080/s/i=1' => 'URL: <a href="http://moodle.org:8080/s/i=1" class="_blanktarget">http://moodle.org:8080/s/i=1</a>',
-            //url in brackets
+            // URL with complex fragment.
+            'Most voted issues: https://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Apopularissues-panel' => 'Most voted issues: <a href="https://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Apopularissues-panel" class="_blanktarget">https://tracker.moodle.org/browse/MDL#selectedTab=com.atlassian.jira.plugin.system.project%3Apopularissues-panel</a>',
+            // Domain with more parts
+            'URL: www.bbc.co.uk.' => 'URL: <a href="http://www.bbc.co.uk" class="_blanktarget">www.bbc.co.uk</a>.',
+            // URL in brackets.
             '(http://moodle.org) - URL' => '(<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a>) - URL',
             '(www.moodle.org) - URL' => '(<a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a>) - URL',
-            //url in square brackets
+            // URL in brackets with a path.
+            '(http://example.com/index.html) - URL' => '(<a href="http://example.com/index.html" class="_blanktarget">http://example.com/index.html</a>) - URL',
+            '(www.example.com/index.html) - URL' => '(<a href="http://www.example.com/index.html" class="_blanktarget">www.example.com/index.html</a>) - URL',
+            // URL in brackets with anchor.
+            '(http://moodle.org/main#anchor) - URL' => '(<a href="http://moodle.org/main#anchor" class="_blanktarget">http://moodle.org/main#anchor</a>) - URL',
+            '(www.moodle.org/main#anchor) - URL' => '(<a href="http://www.moodle.org/main#anchor" class="_blanktarget">www.moodle.org/main#anchor</a>) - URL',
+            // URL in square brackets.
             '[http://moodle.org] - URL' => '[<a href="http://moodle.org" class="_blanktarget">http://moodle.org</a>] - URL',
             '[www.moodle.org] - URL' => '[<a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a>] - URL',
-            //url in brackets with anchor
+            // URL in square brackets with a path.
+            '[http://example.com/index.html] - URL' => '[<a href="http://example.com/index.html" class="_blanktarget">http://example.com/index.html</a>] - URL',
+            '[www.example.com/index.html] - URL' => '[<a href="http://www.example.com/index.html" class="_blanktarget">www.example.com/index.html</a>] - URL',
+            // URL in square brackets with anchor.
             '[http://moodle.org/main#anchor] - URL' => '[<a href="http://moodle.org/main#anchor" class="_blanktarget">http://moodle.org/main#anchor</a>] - URL',
             '[www.moodle.org/main#anchor] - URL' => '[<a href="http://www.moodle.org/main#anchor" class="_blanktarget">www.moodle.org/main#anchor</a>] - URL',
             //brackets within the url
@@ -71,7 +84,8 @@ class filter_urltolink_testcase extends basic_testcase {
             'URL: www.cc.org/url_(withpar)_go/?i=2' => 'URL: <a href="http://www.cc.org/url_(withpar)_go/?i=2" class="_blanktarget">www.cc.org/url_(withpar)_go/?i=2</a>',
             'URL: http://cc.org/url_(with)_(par)_go/?i=2' => 'URL: <a href="http://cc.org/url_(with)_(par)_go/?i=2" class="_blanktarget">http://cc.org/url_(with)_(par)_go/?i=2</a>',
             'URL: www.cc.org/url_(with)_(par)_go/?i=2' => 'URL: <a href="http://www.cc.org/url_(with)_(par)_go/?i=2" class="_blanktarget">www.cc.org/url_(with)_(par)_go/?i=2</a>',
-            'http://en.wikipedia.org/wiki/Slash_(punctuation)'=>'<a href="http://en.wikipedia.org/wiki/Slash_(punctuation)" class="_blanktarget">http://en.wikipedia.org/wiki/Slash_(punctuation)</a>',
+            // URL legitimately ending in a bracket. Commented out as part of MDL-22390. See next tests for work-arounds.
+            // 'http://en.wikipedia.org/wiki/Slash_(punctuation)'=>'<a href="http://en.wikipedia.org/wiki/Slash_(punctuation)" class="_blanktarget">http://en.wikipedia.org/wiki/Slash_(punctuation)</a>',
             'http://en.wikipedia.org/wiki/%28#Parentheses_.28_.29 - URL' => '<a href="http://en.wikipedia.org/wiki/%28#Parentheses_.28_.29" class="_blanktarget">http://en.wikipedia.org/wiki/%28#Parentheses_.28_.29</a> - URL',
             'http://en.wikipedia.org/wiki/(#Parentheses_.28_.29 - URL' => '<a href="http://en.wikipedia.org/wiki/(#Parentheses_.28_.29" class="_blanktarget">http://en.wikipedia.org/wiki/(#Parentheses_.28_.29</a> - URL',
             //escaped brackets in url
@@ -94,8 +108,6 @@ class filter_urltolink_testcase extends basic_testcase {
             'URL: www.moodle.org?u=1.23' => 'URL: <a href="http://www.moodle.org?u=1.23" class="_blanktarget">www.moodle.org?u=1.23</a>',
             //escaped space in url
             'URL: www.moodle.org?u=test+param&' => 'URL: <a href="http://www.moodle.org?u=test+param&" class="_blanktarget">www.moodle.org?u=test+param&</a>',
-            //odd characters in url param
-            'URL: www.moodle.org?param=:)' => 'URL: <a href="http://www.moodle.org?param=:)" class="_blanktarget">www.moodle.org?param=:)</a>',
             //multiple urls
             'URL: http://moodle.org www.moodle.org'
             => 'URL: <a href="http://moodle.org" class="_blanktarget">http://moodle.org</a> <a href="http://www.moodle.org" class="_blanktarget">www.moodle.org</a>',
@@ -151,17 +163,25 @@ class filter_urltolink_testcase extends basic_testcase {
             //'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN http://www.w3.org/TR/html4/strict.dtd">'=>'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN http://www.w3.org/TR/html4/strict.dtd">'
         );
 
-        $testablefilter = new testable_filter_urltolink();
-
+        $data = array();
         foreach ($texts as $text => $correctresult) {
-            $msg = "Testing text: ". str_replace('%', '%%', $text) . ": %s"; // Escape original '%' so sprintf() wont get confused
+            $data[] = array($text, $correctresult);
+        }
+        return $data;
+    }
 
-            $testablefilter->convert_urls_into_links($text);
+    /**
+     * @dataProvider get_convert_urls_into_links_test_cases
+     */
+    function test_convert_urls_into_links($text, $correctresult) {
+        $testablefilter = new testable_filter_urltolink();
+        $testablefilter->convert_urls_into_links($text);
+        $this->assertEquals($correctresult, $text);
+    }
 
-            $this->assertEquals($text, $correctresult, $msg);
-        }
+    function test_convert_urls_into_links_performance() {
+        $testablefilter = new testable_filter_urltolink();
 
-        //performance testing
         $reps = 1000;
         $text = file_get_contents(__DIR__ . '/fixtures/sample.txt');
         $time_start = microtime(true);
index 8850622..9287986 100644 (file)
@@ -200,6 +200,18 @@ if ($mform->is_cancelled()) {
         $data->feedback       = $old_grade_grade->feedback;
         $data->feedbackformat = $old_grade_grade->feedbackformat;
     }
+
+    // Only log a grade override if they actually changed the student grade.
+    if ($data->finalgrade != $old_grade_grade->finalgrade) {
+        $url = '/report/grader/index.php?id=' . $course->id;
+
+        $user = $DB->get_record('user', array('id'=>$data->userid), '*', MUST_EXIST);
+        $fullname = fullname($user);
+
+        $info = "{$grade_item->itemname}: $fullname";
+        add_to_log($course->id, 'grade', 'update', $url, $info);
+    }
+
     // update final grade or feedback
     // when we set override grade the first time, it happens here
     $grade_item->update_final_grade($data->userid, $data->finalgrade, 'editgrade', $data->feedback, $data->feedbackformat);
@@ -213,6 +225,19 @@ if ($mform->is_cancelled()) {
             $data->overridden = 0; // checkbox unticked
         }
         $grade_grade->set_overridden($data->overridden);
+
+        if ($data->overridden == 0 && $data->overridden != $old_grade_grade->overridden) {
+            // Log removing an override.
+            // The addition of an override is logged above.
+            // One or the other will happen but never both.
+            $url = '/report/grader/index.php?id=' . $course->id;
+
+            $user = $DB->get_record('user', array('id'=>$data->userid), '*', MUST_EXIST);
+            $fullname = fullname($user);
+
+            $info = "{$grade_item->itemname}: $fullname";
+            add_to_log($course->id, 'grade', 'update', $url, $info);
+        }
     }
 
     if (has_capability('moodle/grade:manage', $context) or has_capability('moodle/grade:hide', $context)) {
index b6b9ec2..c5292ba 100644 (file)
@@ -501,10 +501,16 @@ class gradingform_guide_controller extends gradingform_controller {
             throw new coding_exception('It is the caller\'s responsibility to make sure that the form is actually defined');
         }
 
-        $output = $this->get_renderer($page);
+        // Check if current user is able to see preview
+        $options = $this->get_options();
+        if (empty($options['alwaysshowdefinition']) && !has_capability('moodle/grade:managegradingforms', $page->context))  {
+            return '';
+        }
+
         $criteria = $this->definition->guide_criteria;
         $comments = $this->definition->guide_comment;
-        $options = $this->get_options();
+        $output = $this->get_renderer($page);
+
         $guide = '';
         $guide .= $output->box($this->get_formatted_description(), 'gradingform_guide-description');
         if (has_capability('moodle/grade:managegradingforms', $page->context)) {
index 7f08a4e..ae4f5d5 100644 (file)
@@ -505,15 +505,19 @@ class gradingform_rubric_controller extends gradingform_controller {
             throw new coding_exception('It is the caller\'s responsibility to make sure that the form is actually defined');
         }
 
-        $output = $this->get_renderer($page);
         $criteria = $this->definition->rubric_criteria;
         $options = $this->get_options();
         $rubric = '';
         if (has_capability('moodle/grade:managegradingforms', $page->context)) {
             $showdescription = true;
         } else {
+            if (empty($options['alwaysshowdefinition']))  {
+                // ensure we don't display unless show rubric option enabled
+                return '';
+            }
             $showdescription = $options['showdescriptionstudent'];
         }
+        $output = $this->get_renderer($page);
         if ($showdescription) {
             $rubric .= $output->box($this->get_formatted_description(), 'gradingform_rubric-description');
         }
index f0c7188..b61f579 100644 (file)
@@ -118,6 +118,14 @@ switch ($action) {
                 echo json_encode($json_object);
                 die();
             } else {
+                $url = '/report/grader/index.php?id=' . $course->id;
+
+                $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+                $fullname = fullname($user);
+
+                $info = "{$grade_item->itemname}: $fullname";
+                add_to_log($course->id, 'grade', 'update', $url, $info);
+
                 $json_object->gradevalue = $finalvalue;
 
                 if ($grade_item->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE)) {
index 0734134..f1dd17e 100644 (file)
@@ -297,6 +297,12 @@ class grade_report_grader extends grade_report {
                         }
                     }
 
+                    $url = '/report/grader/index.php?id=' . $this->course->id;
+                    $fullname = fullname($this->users[$userid]);
+
+                    $info = "{$gradeitem->itemname}: $fullname";
+                    add_to_log($this->course->id, 'grade', 'update', $url, $info);
+
                     $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
 
                     // We can update feedback without reloading the grade item as it doesn't affect grade calculations
index b216a69..ce56de5 100644 (file)
--- a/index.php
+++ b/index.php
@@ -40,6 +40,9 @@
     }
     $PAGE->set_url('/', $urlparams);
     $PAGE->set_course($SITE);
+    $PAGE->set_other_editing_capability('moodle/course:update');
+    $PAGE->set_other_editing_capability('moodle/course:manageactivities');
+    $PAGE->set_other_editing_capability('moodle/course:activityvisibility');
 
     // Prevent caching of this page to stop confusion when changing page after making AJAX changes
     $PAGE->set_cacheable(false);
@@ -89,7 +92,6 @@
     }
 
     $PAGE->set_pagetype('site-index');
-    $PAGE->set_other_editing_capability('moodle/course:manageactivities');
     $PAGE->set_docs_path('');
     $PAGE->set_pagelayout('frontpage');
     $editing = $PAGE->user_is_editing();
 
             echo format_text($summarytext, $section->summaryformat, $summaryformatoptions);
 
-            if ($editing) {
+            if ($editing && has_capability('moodle/course:update', $context)) {
                 $streditsummary = get_string('editsummary');
                 echo "<a title=\"$streditsummary\" ".
                      " href=\"course/editsection.php?id=$section->id\"><img src=\"" . $OUTPUT->pix_url('t/edit') . "\" ".
index 7acf6d5..b340036 100644 (file)
@@ -129,7 +129,12 @@ if (!empty($_POST)) {
     $config->dbpass   = trim($_POST['dbpass']);
     $config->dbname   = trim($_POST['dbname']);
     $config->prefix   = trim($_POST['prefix']);
-    $config->dbsocket = (int)(!empty($_POST['dbsocket']));
+    $config->dbport   = (int)trim($_POST['dbport']);
+    $config->dbsocket = trim($_POST['dbsocket']);
+
+    if ($config->dbport <= 0) {
+        $config->dbport = '';
+    }
 
     $config->admin    = empty($_POST['admin']) ? 'admin' : trim($_POST['admin']);
 
@@ -144,7 +149,8 @@ if (!empty($_POST)) {
     $config->dbpass   = '';
     $config->dbname   = 'moodle';
     $config->prefix   = 'mdl_';
-    $config->dbsocket = 0;
+    $config->dbport   = empty($distro->dbport) ? '' : $distro->dbport;
+    $config->dbsocket = empty($distro->dbsocket) ? '' : $distro->dbsocket;
 
     $config->admin    = 'admin';
 
@@ -169,6 +175,7 @@ $CFG->directorypermissions = isset($distro->directorypermissions) ? $distro->dir
 $CFG->running_installer    = true;
 $CFG->early_install_lang   = true;
 $CFG->ostype               = (stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin')) ? 'WINDOWS' : 'UNIX';
+$CFG->developerdebug       = true;
 
 // Require all needed libs
 require_once($CFG->libdir.'/setuplib.php');
@@ -263,9 +270,9 @@ if ($config->stage == INSTALL_SAVE) {
         $config->stage = INSTALL_DATABASETYPE;
     } else {
         if (function_exists('distro_pre_create_db')) { // Hook for distros needing to do something before DB creation
-            $distro = distro_pre_create_db($database, $config->dbhost, $config->dbuser, $config->dbpass, $config->dbname, $config->prefix, array('dbpersist'=>0, 'dbsocket'=>$config->dbsocket), $distro);
+            $distro = distro_pre_create_db($database, $config->dbhost, $config->dbuser, $config->dbpass, $config->dbname, $config->prefix, array('dbpersist'=>0, 'dbport'=>$config->dbport, 'dbsocket'=>$config->dbsocket), $distro);
         }
-        $hint_database = install_db_validate($database, $config->dbhost, $config->dbuser, $config->dbpass, $config->dbname, $config->prefix, array('dbpersist'=>0, 'dbsocket'=>$config->dbsocket));
+        $hint_database = install_db_validate($database, $config->dbhost, $config->dbuser, $config->dbpass, $config->dbname, $config->prefix, array('dbpersist'=>0, 'dbport'=>$config->dbport, 'dbsocket'=>$config->dbsocket));
 
         if ($hint_database === '') {
             $configphp = install_generate_configphp($database, $CFG);
@@ -405,6 +412,7 @@ if ($config->stage == INSTALL_DATABASE) {
     $strdbuser   = get_string('databaseuser', 'install');
     $strdbpass   = get_string('databasepass', 'install');
     $strprefix   = get_string('dbprefix', 'install');
+    $strdbport   = get_string('databaseport', 'install');
     $strdbsocket = get_string('databasesocket', 'install');
 
     echo '<div class="userinput">';
@@ -432,11 +440,13 @@ if ($config->stage == INSTALL_DATABASE) {
     echo '<input id="id_prefix" name="prefix" type="text" value="'.s($config->prefix).'" size="10" class="forminput" />';
     echo '</div>';
 
+    echo '<div class="formrow"><label for="id_prefix" class="formlabel">'.$strdbport.'</label>';
+    echo '<input id="id_dbport" name="dbport" type="text" value="'.s($config->dbport).'" size="10" class="forminput" />';
+    echo '</div>';
+
     if (!(stristr(PHP_OS, 'win') && !stristr(PHP_OS, 'darwin'))) {
-        $checked = $config->dbsocket ? 'checked="checked' : '';
         echo '<div class="formrow"><label for="id_dbsocket" class="formlabel">'.$strdbsocket.'</label>';
-        echo '<input type="hidden" value="0" name="dbsocket" />';
-        echo '<input type="checkbox" id="id_dbsocket" value="1" name="dbsocket" '.$checked.' class="forminput" />';
+        echo '<input id="id_dbsocket" name="dbsocket" type="text" value="'.s($config->dbsocket).'" size="50" class="forminput" />';
         echo '</div>';
     }
 
index 9df0f04..3301110 100644 (file)
@@ -30,5 +30,5 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['cannotsavemd5file'] = 'No s\'ha pogut alçar el fitxer md5';
-$string['cannotsavezipfile'] = 'No s\'ha pogut alçar el fitxer zip';
+$string['cannotsavemd5file'] = 'No s\'ha pogut guardar el fitxer md5';
+$string['cannotsavezipfile'] = 'No s\'ha pogut guardar el fitxer zip';
index d8be051..ec61cf9 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['langdownloaderror'] = 'Dissortadament l\'idioma "{$a}" no està instal·lat. La instal·lació prosseguirà en anglés.';
+$string['clialreadyconfigured'] = 'El fitxer config.php ja existeix, feu servir dmin/cli/install_database.php si voleu instal·lar este lloc web.';
+$string['clialreadyinstalled'] = 'El fitxer config.php ja existeix, feu servir admin/cli/upgrade.php si voleu actualitzar este lloc web.';
+$string['cliinstallheader'] = 'Programa d\'instal·lació de línia d\'ordes de Moodle {$a}';
+$string['langdownloaderror'] = 'Dissortadament l\'idioma "{$a}" no es pot baixar. La instal·lació prosseguirà en anglés.';
 $string['memorylimithelp'] = '<p>El límit de memòria del PHP del vostre servidor actualment està definit en {$a}.</p>
 
 <p>Això pot causar que Moodle tinga problemes de memòria més avant, especialment si teniu molts mòduls habilitats i/o molts usuaris.</p>
@@ -41,14 +44,20 @@ $string['memorylimithelp'] = '<p>El límit de memòria del PHP del vostre servid
 <li>Si teniu accés al fitxer php.ini, podeu canviar el paràmetre <b>memory_limit</b> a 40 MB. Si no hi teniu accés podeu demanar al vostre administrador que ho faça ell.</li>
 <li>En alguns servidors PHP podeu crear un fitxer .htaccess dins del directori de Moodle amb esta línia:
 <p><blockquote>php_value memory_limit 40M</blockquote></p>
-<p>Tanmateix, en alguns servidors això farà que no funcioni <b>cap</b> pàgina PHP (es visualitzaran errors) en el qual cas hauríeu de suprimir el fitxer .htaccess.</p></li>
+<p>Tanmateix, en alguns servidors això farà que no funcione <b>cap</b> pàgina PHP (es visualitzaran errors) en el qual cas hauríeu de suprimir el fitxer .htaccess.</p></li>
 </ol>';
-$string['pathssubdataroot'] = 'Necessiteu un espai on Moodle puga alçar els fitxers penjats. Este directori hauria de tindre permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que siga accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
-$string['phpversionhelp'] = '<p>Moodle necessita la versió de PHP 4.1.0 o posterior.</p>
+$string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen un URL especial /admin p. ex. per a accedir a un tauler de control o quelcom paregut. Malauradament això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar este problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom ací. Per exemple <em>moodleadmin</em>. Això modificarà els enllaços d\'administració de Moodle.';
+$string['pathssubdataroot'] = 'Necessiteu un espai on Moodle puga guardar els fitxers penjats. Este directori hauria de tindre permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que siga accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
+$string['pathssubwwwroot'] = 'L\'adreça web completa on s\'accedirà a Moodle.
+No és possible accedir a Moodle en diferents adreces.
+Si el vostre lloc té múltiples adreces públiques haureu de configurar redireccions permanents per a totes excepte esta.
+Si el vostre lloc és accessible tant des d\'Internet com des d\'una intranet, utilitzeu ací l\'adreça pública i configureu el DNS de manera que els usuaris de la intranet puguen utilitzar també l\'adreça pública.
+Si l\'adreça no és correcta, canvieu l\'URL en el vostre navegador per reiniciar la instal·lació amb un altre valor.';
+$string['phpversionhelp'] = '<p>Moodle necessita una versió de PHP 4.3.0 o 5.1.0 (les versions 5.0.x tenien uns quants problemes coneguts).</p>
 <p>A hores d\'ara esteu utilitzant la versió {$a}.</p>
-<p>Vos caldrà actualitzar el PHP o traslladar Moodle a un ordinador amb una versió de PHP més recent.</p>';
-$string['welcomep20'] = 'Esteu veient esta pàgina perquè heu instal·lat amb èxit i heu executat el paquet <strong>{$a->packname} {$a->packversion}</strong>. Felicitacions!';
-$string['welcomep30'] = 'Esta versió de <strong>{$a->installername}</strong> inclou les aplicacions necessàries per crear un entorn en el qual funcioni <strong>Moodle</strong>:';
+<p>Vos cal actualitzar el PHP o traslladar Moodle a un ordinador amb una versió de PHP més recent.<br />(Si esteu utilitzant la versió 5.0.x, alternativament també podríeu tornar arrere a la 4.4.x)</p>';
+$string['welcomep20'] = 'Esteu veient esta pàgina perquè heu instal·lat amb èxit i heu executat el paquet <strong>{$a->packname} {$a->packversion}</strong>. Felicitacions.';
+$string['welcomep30'] = 'Esta versió de <strong>{$a->installername}</strong> inclou les aplicacions necessàries per crear un entorn en el qual funcione <strong>Moodle</strong>:';
 $string['welcomep50'] = 'L\'ús de totes les aplicacions d\'este paquet és governat per les seues llicències respectives. El paquet <strong>{$a->installername}</strong> complet és
 <a href="http://www.opensource.org/docs/definition_plain.html">codi font obert</a> i es distribueix
 sota llicència <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>.';
index 267e449..61197a5 100644 (file)
@@ -30,6 +30,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['cannotcreatedboninstall'] = '<p>Non è possibile creare il database </p> <p>Il database non esiste o l\'utente non è autorizzato a crearlo.</p>
+<p>E\' necessario che l\'amministratore del sito  verifichi  la configurazione del database.</p>';
 $string['cannotcreatelangdir'] = 'Non è possibile creare la cartella lang';
 $string['cannotcreatetempdir'] = 'Non è possibile creare la cartella temp';
 $string['cannotdownloadcomponents'] = 'Non è possibile scaricare componenti.';
index 0eb6298..4eac84f 100644 (file)
@@ -30,6 +30,9 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['cannotcreatedboninstall'] = '<p> Não é possível criar o banco de dados. </p>
+<p> O banco de dados especificado não existe e o determinado usuário não tem permissão para criar o banco de dados. </p>
+<p> O administrador do site deve verificar a configuração do banco de dados. </p>';
 $string['cannotcreatelangdir'] = 'Impossível criar diretório lang';
 $string['cannotcreatetempdir'] = 'Impossível criar diretório temp';
 $string['cannotdownloadcomponents'] = 'Impossível fazer download dos componentes';
@@ -39,6 +42,7 @@ $string['cannotsavemd5file'] = 'Impossível salvar arquivo md5';
 $string['cannotsavezipfile'] = 'Impossível salvar arquivo ZIP';
 $string['cannotunzipfile'] = 'Impossível descompactar arquivo ZIP';
 $string['componentisuptodate'] = 'Componente está atualizado';
+$string['dmlexceptiononinstall'] = '<p> Ocorreu um erro no banco de dados [{$a->errorcode}].<br />{$a->debuginfo} </p>';
 $string['downloadedfilecheckfailed'] = 'A verificação do arquivo baixado falhou';
 $string['invalidmd5'] = 'A variável de verificação estava errada - tente novamente';
 $string['missingrequiredfield'] = 'Faltam informações obrigatórias';
index 9e1d4de..1ede2d0 100644 (file)
@@ -30,5 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['parentlanguage'] = 'en';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = 'Српски';
index c11ac67..01b82fc 100644 (file)
@@ -30,5 +30,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['parentlanguage'] = 'en';
 $string['thisdirection'] = 'ltr';
 $string['thislanguage'] = 'Srpski';
index 6757bc2..6db43a4 100644 (file)
@@ -30,6 +30,9 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['cannotcreatedboninstall'] = '<p>Kan inte skapa databasen.</p>
+<p>Den specificerade databasen existerar inte och den givna användaren har inte rättighet att skapa databasen.</p>
+<p>Administratören för webbplatsen bör verifiera databaskonfigurationen.</p>';
 $string['cannotcreatelangdir'] = 'Det går inte att skapa en lang-katalog';
 $string['cannotcreatetempdir'] = 'Det går inte att skapa en temp-katalog';
 $string['cannotdownloadcomponents'] = 'Det går inte att ladda ner komponenter';
@@ -39,6 +42,7 @@ $string['cannotsavemd5file'] = 'Det går inte att spara md5-fil';
 $string['cannotsavezipfile'] = 'Det går inte att spara ZIP-fil';
 $string['cannotunzipfile'] = 'Det går inte att packa upp fil';
 $string['componentisuptodate'] = 'Komponenten är av en aktuell version';
+$string['dmlexceptiononinstall'] = '<p>Ett databasfel har inträffat [{$a->errorcode}].<br />{$a->debuginfo}</p>';
 $string['downloadedfilecheckfailed'] = 'Det gick inte att kontrollera den nedladdade filen';
 $string['invalidmd5'] = 'Kontrollvariabeln var felaktig - försök igen';
 $string['missingrequiredfield'] = 'Det saknas några obligatoriska fält';
index b1c5126..ffea8a9 100644 (file)
@@ -479,6 +479,7 @@ $string['enablecomments'] = 'Enable comments';
 $string['enablecourserequests'] = 'Enable course requests';
 $string['enablecssoptimiser'] = 'Enable CSS optimiser';
 $string['enablecssoptimiser_desc'] = 'When enabled CSS will be run through an optimisation process before being cached. The optimiser processes the CSS removing duplicate rules and styles, as well as white space removable and reformatting. Please note turning this on at the same time as theme designer mode is awful for performance but will help theme designers create optimised CSS.';
+$string['enabled'] = 'Enabled';
 $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.';
@@ -635,7 +636,7 @@ $string['localetext'] = 'Sitewide locale';
 $string['localstringcustomization'] = 'Local string customization';
 $string['location'] = 'Location';
 $string['locationsettings'] = 'Location settings';
-$string['locked'] = 'locked';
+$string['locked'] = 'Locked';
 $string['lockoutduration'] = 'Account lockout duration';
 $string['lockoutduration_desc'] = 'Locked out account is automatically unlocked after this duration.';
 $string['lockoutemailbody'] = 'Your account with username {$a->username} on server \'{$a->sitename}\'
index 3aabdfc..4edb0a0 100644 (file)
@@ -111,6 +111,7 @@ $string['groupnameexists'] = 'The group name \'{$a}\' already exists in this cou
 $string['groupnotamember'] = 'Sorry, you are not a member of that group';
 $string['groups'] = 'Groups';
 $string['groupscount'] = 'Groups ({$a})';
+$string['groupsettingsheader'] = 'Groups';
 $string['groupsgroupings'] = 'Groups &amp; groupings';
 $string['groupsinselectedgrouping'] = 'Groups in:';
 $string['groupsnone'] = 'No groups';
index 6ee12c8..6a91a6b 100644 (file)
@@ -154,7 +154,6 @@ $string['publisheremail_help'] = 'The publisher email address allows the hub adm
 $string['publishername'] = 'Publisher';
 $string['publishername_help'] = 'The publisher is the person or organisation that is the official publisher of the course.  Unless you are publishing it on behalf of someone else, it will usually be you.';
 $string['publishon'] = 'Publish on';
-$string['publishonmoodleorg'] = 'Publish on MOOCH';
 $string['publishonspecifichub'] = 'Publish on another Hub';
 $string['questionsnumber'] = 'Number of questions ({$a})';
 $string['registeredcourses'] = 'Registered courses';
@@ -192,7 +191,6 @@ $string['share'] = 'Share this course for people to download';
 $string['shared'] = 'Shared';
 $string['shareon'] = 'Upload this course to {$a}';
 $string['shareonhub'] = 'Upload this course to a hub';
-$string['shareonmoodleorg'] = 'Upload this course to MOOCH';
 $string['sharepublication_help'] = 'Uploading this course to a community hub server will enable people to download it and install it on their own Moodle sites.';
 $string['siteadmin'] = 'Administrator';
 $string['siteadmin_help'] = 'The full name of the site administrator.';
index e936e0d..f744ec5 100644 (file)
@@ -86,6 +86,7 @@ $string['databasehead'] = 'Database settings';
 $string['databasehost'] = 'Database host';
 $string['databasename'] = 'Database name';
 $string['databasepass'] = 'Database password';
+$string['databaseport'] = 'Database port';
 $string['databasesettings'] = 'Now you need to configure the database where most Moodle data
     will be stored.  This database must already have been created
     and a username and password created to access it.<br />
index f9e4e71..dbb2031 100644 (file)
@@ -572,8 +572,21 @@ function is_siteadmin($user_or_id = null) {
         $userid = $user_or_id;
     }
 
+    // Because this script is called many times (150+ for course page) with
+    // the same parameters, it is worth doing minor optimisations. This static
+    // cache stores the value for a single userid, saving about 2ms from course
+    // page load time without using significant memory. As the static cache
+    // also includes the value it depends on, this cannot break unit tests.
+    static $knownid, $knownresult, $knownsiteadmins;
+    if ($knownid === $userid && $knownsiteadmins === $CFG->siteadmins) {
+        return $knownresult;
+    }
+    $knownid = $userid;
+    $knownsiteadmins = $CFG->siteadmins;
+
     $siteadmins = explode(',', $CFG->siteadmins);
-    return in_array($userid, $siteadmins);
+    $knownresult = in_array($userid, $siteadmins);
+    return $knownresult;
 }
 
 /**
index af6bab7..1956352 100644 (file)
@@ -1506,6 +1506,8 @@ abstract class admin_setting {
     public $nosave = false;
     /** @var bool if set, indicates that a change to this setting requires rebuild course cache */
     public $affectsmodinfo = false;
+    /** @var array of admin_setting_flag - These are extra checkboxes attached to a setting. */
+    private $flags = array();
 
     /**
      * Constructor
@@ -1522,6 +1524,117 @@ abstract class admin_setting {
         $this->defaultsetting = $defaultsetting;
     }
 
+    /**
+     * Generic function to add a flag to this admin setting.
+     *
+     * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
+     * @param bool $default - The default for the flag
+     * @param string $shortname - The shortname for this flag. Used as a suffix for the setting name.
+     * @param string $displayname - The display name for this flag. Used as a label next to the checkbox.
+     */
+    protected function set_flag_options($enabled, $default, $shortname, $displayname) {
+        if (empty($this->flags[$shortname])) {
+            $this->flags[$shortname] = new admin_setting_flag($enabled, $default, $shortname, $displayname);
+        } else {
+            $this->flags[$shortname]->set_options($enabled, $default);
+        }
+    }
+
+    /**
+     * Set the enabled options flag on this admin setting.
+     *
+     * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
+     * @param bool $default - The default for the flag
+     */
+    public function set_enabled_flag_options($enabled, $default) {
+        $this->set_flag_options($enabled, $default, 'enabled', new lang_string('enabled', 'core_admin'));
+    }
+
+    /**
+     * Set the advanced options flag on this admin setting.
+     *
+     * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
+     * @param bool $default - The default for the flag
+     */
+    public function set_advanced_flag_options($enabled, $default) {
+        $this->set_flag_options($enabled, $default, 'adv', new lang_string('advanced'));
+    }
+
+
+    /**
+     * Set the locked options flag on this admin setting.
+     *
+     * @param bool $enabled - One of self::OPTION_ENABLED or self::OPTION_DISABLED
+     * @param bool $default - The default for the flag
+     */
+    public function set_locked_flag_options($enabled, $default) {
+        $this->set_flag_options($enabled, $default, 'locked', new lang_string('locked', 'core_admin'));
+    }
+
+    /**
+     * Get the currently saved value for a setting flag
+     *
+     * @param admin_setting_flag $flag - One of the admin_setting_flag for this admin_setting.
+     * @return bool
+     */
+    public function get_setting_flag_value(admin_setting_flag $flag) {
+        $value = $this->config_read($this->name . '_' . $flag->get_shortname());
+        if (!isset($value)) {
+            $value = $flag->get_default();
+        }
+
+        return !empty($value);
+    }
+
+    /**
+     * Get the list of defaults for the flags on this setting.
+     *
+     * @param array of strings describing the defaults for this setting. This is appended to by this function.
+     */
+    public function get_setting_flag_defaults(& $defaults) {
+        foreach ($this->flags as $flag) {
+            if ($flag->is_enabled() && $flag->get_default()) {
+                $defaults[] = $flag->get_displayname();
+            }
+        }
+    }
+
+    /**
+     * Output the input fields for the advanced and locked flags on this setting.
+     *
+     * @param bool $adv - The current value of the advanced flag.
+     * @param bool $locked - The current value of the locked flag.
+     * @return string $output - The html for the flags.
+     */
+    public function output_setting_flags() {
+        $output = '';
+
+        foreach ($this->flags as $flag) {
+            if ($flag->is_enabled()) {
+                $output .= $flag->output_setting_flag($this);
+            }
+        }
+
+        if (!empty($output)) {
+            return html_writer::tag('span', $output, array('class' => 'adminsettingsflags'));
+        }
+        return $output;
+    }
+
+    /**
+     * Write the values of the flags for this admin setting.
+     *
+     * @param array $data - The data submitted from the form or null to set the default value for new installs.
+     * @return bool - true if successful.
+     */
+    public function write_setting_flags($data) {
+        $result = true;
+        foreach ($this->flags as $flag) {
+            $result = $result && $flag->write_setting_flag($this, $data);
+        }
+        return $result;
+    }
+
     /**
      * Set up $this->name and potentially $this->plugin
      *
@@ -1627,15 +1740,7 @@ abstract class admin_setting {
             rebuild_course_cache(0, true);
         }
 
-        // log change
-        $log = new stdClass();
-        $log->userid       = during_initial_install() ? 0 :$USER->id; // 0 as user id during install
-        $log->timemodified = time();
-        $log->plugin       = $this->plugin;
-        $log->name         = $name;
-        $log->value        = $value;
-        $log->oldvalue     = $oldvalue;
-        $DB->insert_record('config_log', $log);
+        add_to_config_log($name, $oldvalue, $value, $this->plugin);
 
         return true; // BC only
     }
@@ -1746,6 +1851,130 @@ abstract class admin_setting {
     }
 }
 
+/**
+ * An additional option that can be applied to an admin setting.
+ * The currently supported options are 'ADVANCED' and 'LOCKED'.
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class admin_setting_flag {
+    /** @var bool Flag to indicate if this option can be toggled for this setting */
+    private $enabled = false;
+    /** @var bool Flag to indicate if this option defaults to true or false */
+    private $default = false;
+    /** @var string Short string used to create setting name - e.g. 'adv' */
+    private $shortname = '';
+    /** @var string String used as the label for this flag */
+    private $displayname = '';
+    /** @const Checkbox for this flag is displayed in admin page */
+    const ENABLED = true;
+    /** @const Checkbox for this flag is not displayed in admin page */
+    const DISABLED = false;
+
+    /**
+     * Constructor
+     *
+     * @param bool $enabled Can this option can be toggled.
+     *                      Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
+     * @param bool $default The default checked state for this setting option.
+     * @param string $shortname The shortname of this flag. Currently supported flags are 'locked' and 'adv'
+     * @param string $displayname The displayname of this flag. Used as a label for the flag.
+     */
+    public function __construct($enabled, $default, $shortname, $displayname) {
+        $this->shortname = $shortname;
+        $this->displayname = $displayname;
+        $this->set_options($enabled, $default);
+    }
+
+    /**
+     * Update the values of this setting options class
+     *
+     * @param bool $enabled Can this option can be toggled.
+     *                      Should be one of admin_setting_flag::ENABLED or admin_setting_flag::DISABLED.
+     * @param bool $default The default checked state for this setting option.
+     */
+    public function set_options($enabled, $default) {
+        $this->enabled = $enabled;
+        $this->default = $default;
+    }
+
+    /**
+     * Should this option appear in the interface and be toggleable?
+     *
+     * @return bool Is it enabled?
+     */
+    public function is_enabled() {
+        return $this->enabled;
+    }
+
+    /**
+     * Should this option be checked by default?
+     *
+     * @return bool Is it on by default?
+     */
+    public function get_default() {
+        return $this->default;
+    }
+
+    /**
+     * Return the short name for this flag. e.g. 'adv' or 'locked'
+     *
+     * @return string
+     */
+    public function get_shortname() {
+        return $this->shortname;
+    }
+
+    /**
+     * Return the display name for this flag. e.g. 'Advanced' or 'Locked'
+     *
+     * @return string
+     */
+    public function get_displayname() {
+        return $this->displayname;
+    }
+
+    /**
+     * Save the submitted data for this flag - or set it to the default if $data is null.
+     *
+     * @param admin_setting $setting - The admin setting for this flag
+     * @param array $data - The data submitted from the form or null to set the default value for new installs.
+     * @return bool
+     */
+    public function write_setting_flag(admin_setting $setting, $data) {
+        $result = true;
+        if ($this->is_enabled()) {
+            if (!isset($data)) {
+                $value = $this->get_default();
+            } else {
+                $value = !empty($data[$setting->get_full_name() . '_' . $this->get_shortname()]);
+            }
+            $result = $setting->config_write($setting->name . '_' . $this->get_shortname(), $value);
+        }
+
+        return $result;
+
+    }
+
+    /**
+     * Output the checkbox for this setting flag. Should only be called if the flag is enabled.
+     *
+     * @param admin_setting $setting - The admin setting for this flag
+     * @return string - The html for the checkbox.
+     */
+    public function output_setting_flag(admin_setting $setting) {
+        $value = $setting->get_setting_flag_value($this);
+        $output = ' <input type="checkbox" class="form-checkbox" ' .
+                        ' id="' .  $setting->get_id() . '_' . $this->get_shortname() . '" ' .
+                        ' name="' . $setting->get_full_name() .  '_' . $this->get_shortname() . '" ' .
+                        ' value="1" ' . ($value ? 'checked="checked"' : '') . ' />' .
+                        ' <label for="' . $setting->get_id() . '_' . $this->get_shortname() . '">' .
+                        $this->get_displayname() .
+                        ' </label> ';
+        return $output;
+    }
+}
+
 
 /**
  * No setting - just heading and text.
@@ -2060,6 +2289,46 @@ if (is_ie) {
     }
 }
 
+/**
+ * Empty setting used to allow flags (advanced) on settings that can have no sensible default.
+ * Note: Only advanced makes sense right now - locked does not.
+ *
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class admin_setting_configempty extends admin_setting_configtext {
+
+    /**
+     * @param string $name
+     * @param string $visiblename
+     * @param string $description
+     */
+    public function __construct($name, $visiblename, $description) {
+        parent::__construct($name, $visiblename, $description, '', PARAM_RAW);
+    }
+
+    /**
+     * Returns an XHTML string for the hidden field
+     *
+     * @param string $data
+     * @param string $query
+     * @return string XHTML string for the editor
+     */
+    public function output_html($data, $query='') {
+        return format_admin_setting($this,
+                                    $this->visiblename,
+                                    '<div class="form-empty" >' .
+                                    '<input type="hidden"' .
+                                        ' id="'. $this->get_id() .'"' .
+                                        ' name="'. $this->get_full_name() .'"' .
+                                        ' value=""/></div>',
+                                    $this->description,
+                                    true,
+                                    '',
+                                    get_string('none'),
+                                    $query);
+    }
+}
+
 
 /**
  * Path to directory
@@ -4230,73 +4499,8 @@ class admin_setting_configtext_with_advanced extends admin_setting_configtext {
      * @param int $size default field size
      */
     public function __construct($name, $visiblename, $description, $defaultsetting, $paramtype=PARAM_RAW, $size=null) {
-        parent::__construct($name, $visiblename, $description, $defaultsetting, $paramtype, $size);
-    }
-
-    /**
-     * Loads the current setting and returns array
-     *
-     * @return array Returns array value=>xx, __construct=>xx
-     */
-    public function get_setting() {
-        $value = parent::get_setting();
-        $adv = $this->config_read($this->name.'_adv');
-        if (is_null($value) or is_null($adv)) {
-            return NULL;
-        }
-        return array('value' => $value, 'adv' => $adv);
-    }
-
-    /**
-     * Saves the new settings passed in $data
-     *
-     * @todo Add vartype handling to ensure $data is an array
-     * @param array $data
-     * @return mixed string or Array
-     */
-    public function write_setting($data) {
-        $error = parent::write_setting($data['value']);
-        if (!$error) {
-            $value = empty($data['adv']) ? 0 : 1;
-            $this->config_write($this->name.'_adv', $value);
-        }
-        return $error;
-    }
-
-    /**
-     * Return XHTML for the control
-     *
-     * @param array $data Default data array
-     * @param string $query
-     * @return string XHTML to display control
-     */
-    public function output_html($data, $query='') {
-        $default = $this->get_defaultsetting();
-        $defaultinfo = array();
-        if (isset($default['value'])) {
-            if ($default['value'] === '') {
-                $defaultinfo[] = "''";
-            } else {
-                $defaultinfo[] = $default['value'];
-            }
-        }
-        if (!empty($default['adv'])) {
-            $defaultinfo[] = get_string('advanced');
-        }
-        $defaultinfo = implode(', ', $defaultinfo);
-
-        $adv = !empty($data['adv']);
-        $return = '<div class="form-text defaultsnext">' .
-            '<input type="text" size="' . $this->size . '" id="' . $this->get_id() .
-            '" name="' . $this->get_full_name() . '[value]" value="' . s($data['value']) . '" />' .
-            ' <input type="checkbox" class="form-checkbox" id="' .
-            $this->get_id() . '_adv" name="' . $this->get_full_name() .
-            '[adv]" value="1" ' . ($adv ? 'checked="checked"' : '') . ' />' .
-            ' <label for="' . $this->get_id() . '_adv">' .
-            get_string('advanced') . '</label></div>';
-
-        return format_admin_setting($this, $this->visiblename, $return,
-        $this->description, true, '', $defaultinfo, $query);
+        parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $paramtype, $size);
+        $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
     }
 }
 
@@ -4319,90 +4523,10 @@ class admin_setting_configcheckbox_with_advanced extends admin_setting_configche
      * @param string $no value used when not checked
      */
     public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
-        parent::__construct($name, $visiblename, $description, $defaultsetting, $yes, $no);
-    }
-
-    /**
-     * Loads the current setting and returns array
-     *
-     * @return array Returns array value=>xx, adv=>xx
-     */
-    public function get_setting() {
-        $value = parent::get_setting();
-        $adv = $this->config_read($this->name.'_adv');
-        if (is_null($value) or is_null($adv)) {
-            return NULL;
-        }
-        return array('value' => $value, 'adv' => $adv);
-    }
-
-    /**
-     * Sets the value for the setting
-     *
-     * Sets the value for the setting to either the yes or no values
-     * of the object by comparing $data to yes
-     *
-     * @param mixed $data Gets converted to str for comparison against yes value
-     * @return string empty string or error
-     */
-    public function write_setting($data) {
-        $error = parent::write_setting($data['value']);
-        if (!$error) {
-            $value = empty($data['adv']) ? 0 : 1;
-            $this->config_write($this->name.'_adv', $value);
-        }
-        return $error;
+        parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
+        $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
     }
 
-    /**
-     * Returns an XHTML checkbox field and with extra advanced cehckbox
-     *
-     * @param string $data If $data matches yes then checkbox is checked
-     * @param string $query
-     * @return string XHTML field
-     */
-    public function output_html($data, $query='') {
-        $defaults = $this->get_defaultsetting();
-        $defaultinfo = array();
-        if (!is_null($defaults)) {
-            if ((string)$defaults['value'] === $this->yes) {
-                $defaultinfo[] = get_string('checkboxyes', 'admin');
-            } else {
-                $defaultinfo[] = get_string('checkboxno', 'admin');
-            }
-            if (!empty($defaults['adv'])) {
-                $defaultinfo[] = get_string('advanced');
-            }
-        }
-        $defaultinfo = implode(', ', $defaultinfo);
-
-        if ((string)$data['value'] === $this->yes) { // convert to strings before comparison
-            $checked = 'checked="checked"';
-        } else {
-            $checked = '';
-        }
-        if (!empty($data['adv'])) {
-            $advanced = 'checked="checked"';
-        } else {
-            $advanced = '';
-        }
-
-        $fullname    = $this->get_full_name();
-        $novalue     = s($this->no);
-        $yesvalue    = s($this->yes);
-        $id          = $this->get_id();
-        $stradvanced = get_string('advanced');
-        $return = <<<EOT
-<div class="form-checkbox defaultsnext" >
-<input type="hidden" name="{$fullname}[value]" value="$novalue" />
-<input type="checkbox" id="$id" name="{$fullname}[value]" value="$yesvalue" $checked />
-<input type="checkbox" class="form-checkbox" id="{$id}_adv" name="{$fullname}[adv]" value="1" $advanced />
-<label for="{$id}_adv">$stradvanced</label>
-</div>
-EOT;
-        return format_admin_setting($this, $this->visiblename, $return, $this->description,
-        true, '', $defaultinfo, $query);
-    }
 }
 
 
@@ -4425,86 +4549,10 @@ class admin_setting_configcheckbox_with_lock extends admin_setting_configcheckbo
      * @param string $no value used when not checked
      */
     public function __construct($name, $visiblename, $description, $defaultsetting, $yes='1', $no='0') {
-        parent::__construct($name, $visiblename, $description, $defaultsetting, $yes, $no);
-    }
-
-    /**
-     * Loads the current setting and returns array
-     *
-     * @return array Returns array value=>xx, adv=>xx
-     */
-    public function get_setting() {
-        $value = parent::get_setting();
-        $locked = $this->config_read($this->name.'_locked');
-        if (is_null($value) or is_null($locked)) {
-            return NULL;
-        }
-        return array('value' => $value, 'locked' => $locked);
-    }
-
-    /**
-     * Sets the value for the setting
-     *
-     * Sets the value for the setting to either the yes or no values
-     * of the object by comparing $data to yes
-     *
-     * @param mixed $data Gets converted to str for comparison against yes value
-     * @return string empty string or error
-     */
-    public function write_setting($data) {
-        $error = parent::write_setting($data['value']);
-        if (!$error) {
-            $value = empty($data['locked']) ? 0 : 1;
-            $this->config_write($this->name.'_locked', $value);
-        }
-        return $error;
+        parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $yes, $no);
+        $this->set_locked_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['locked']));
     }
 
-    /**
-     * Returns an XHTML checkbox field and with extra locked checkbox
-     *
-     * @param string $data If $data matches yes then checkbox is checked
-     * @param string $query
-     * @return string XHTML field
-     */
-    public function output_html($data, $query='') {
-        $defaults = $this->get_defaultsetting();
-        $defaultinfo = array();
-        if (!is_null($defaults)) {
-            if ((string)$defaults['value'] === $this->yes) {
-                $defaultinfo[] = get_string('checkboxyes', 'admin');
-            } else {
-                $defaultinfo[] = get_string('checkboxno', 'admin');
-            }
-            if (!empty($defaults['locked'])) {
-                $defaultinfo[] = get_string('locked', 'admin');
-            }
-        }
-        $defaultinfo = implode(', ', $defaultinfo);
-
-        $fullname    = $this->get_full_name();
-        $novalue     = s($this->no);
-        $yesvalue    = s($this->yes);
-        $id          = $this->get_id();
-
-        $checkboxparams = array('type'=>'checkbox', 'id'=>$id,'name'=>$fullname.'[value]', 'value'=>$yesvalue);
-        if ((string)$data['value'] === $this->yes) { // convert to strings before comparison
-            $checkboxparams['checked'] = 'checked';
-        }
-
-        $lockcheckboxparams = array('type'=>'checkbox', 'id'=>$id.'_locked','name'=>$fullname.'[locked]', 'value'=>1, 'class'=>'form-checkbox locked-checkbox');
-        if (!empty($data['locked'])) { // convert to strings before comparison
-            $lockcheckboxparams['checked'] = 'checked';
-        }
-
-        $return  = html_writer::start_tag('div', array('class'=>'form-checkbox defaultsnext'));
-        $return .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$fullname.'[value]', 'value'=>$novalue));
-        $return .= html_writer::empty_tag('input', $checkboxparams);
-        $return .= html_writer::empty_tag('input', $lockcheckboxparams);
-        $return .= html_writer::tag('label', get_string('locked', 'admin'), array('for'=>$id.'_locked'));
-        $return .= html_writer::end_tag('div');
-        return format_admin_setting($this, $this->visiblename, $return, $this->description, true, '', $defaultinfo, $query);
-    }
 }
 
 
@@ -4518,79 +4566,10 @@ class admin_setting_configselect_with_advanced extends admin_setting_configselec
      * Calls parent::__construct with specific arguments
      */
     public function __construct($name, $visiblename, $description, $defaultsetting, $choices) {
-        parent::__construct($name, $visiblename, $description, $defaultsetting, $choices);
-    }
-
-    /**
-     * Loads the current setting and returns array
-     *
-     * @return array Returns array value=>xx, adv=>xx
-     */
-    public function get_setting() {
-        $value = parent::get_setting();
-        $adv = $this->config_read($this->name.'_adv');
-        if (is_null($value) or is_null($adv)) {
-            return NULL;
-        }
-        return array('value' => $value, 'adv' => $adv);
-    }
-
-    /**
-     * Saves the new settings passed in $data
-     *
-     * @todo Add vartype handling to ensure $data is an array
-     * @param array $data
-     * @return mixed string or Array
-     */
-    public function write_setting($data) {
-        $error = parent::write_setting($data['value']);
-        if (!$error) {
-            $value = empty($data['adv']) ? 0 : 1;
-            $this->config_write($this->name.'_adv', $value);
-        }
-        return $error;
+        parent::__construct($name, $visiblename, $description, $defaultsetting['value'], $choices);
+        $this->set_advanced_flag_options(admin_setting_flag::ENABLED, !empty($defaultsetting['adv']));
     }
 
-    /**
-     * Return XHTML for the control
-     *
-     * @param array $data Default data array
-     * @param string $query
-     * @return string XHTML to display control
-     */
-    public function output_html($data, $query='') {
-        $default = $this->get_defaultsetting();
-        $current = $this->get_setting();
-
-        list($selecthtml, $warning) = $this->output_select_html($data['value'],
-            $current['value'], $default['value'], '[value]');
-        if (!$selecthtml) {
-            return '';
-        }
-
-        if (!is_null($default) and array_key_exists($default['value'], $this->choices)) {
-            $defaultinfo = array();
-            if (isset($this->choices[$default['value']])) {
-                $defaultinfo[] = $this->choices[$default['value']];
-            }
-            if (!empty($default['adv'])) {
-                $defaultinfo[] = get_string('advanced');
-            }
-            $defaultinfo = implode(', ', $defaultinfo);
-        } else {
-            $defaultinfo = '';
-        }
-
-        $adv = !empty($data['adv']);
-        $return = '<div class="form-select defaultsnext">' . $selecthtml .
-            ' <input type="checkbox" class="form-checkbox" id="' .
-            $this->get_id() . '_adv" name="' . $this->get_full_name() .
-            '[adv]" value="1" ' . ($adv ? 'checked="checked"' : '') . ' />' .
-            ' <label for="' . $this->get_id() . '_adv">' .
-            get_string('advanced') . '</label></div>';
-
-        return format_admin_setting($this, $this->visiblename, $return, $this->description, true, $warning, $defaultinfo, $query);
-    }
 }
 
 
@@ -6429,6 +6408,7 @@ function admin_apply_default_settings($node=NULL, $unconditional=true) {
                     continue;
                 }
                 $setting->write_setting($defaultsetting);
+                $setting->write_setting_flags(null);
             }
         }
 }
@@ -6466,6 +6446,8 @@ function admin_write_settings($formdata) {
             $adminroot->errors[$fullname]->data  = $data[$fullname];
             $adminroot->errors[$fullname]->id    = $setting->get_id();
             $adminroot->errors[$fullname]->error = $error;
+        } else {
+            $setting->write_setting_flags($data);
         }
         if ($setting->post_write_settings($original)) {
             $count++;
@@ -6654,6 +6636,7 @@ function format_admin_setting($setting, $title='', $form='', $description='', $l
     } else {
         $labelfor = '';
     }
+    $form .= $setting->output_setting_flags();
 
     $override = '';
     if (empty($setting->plugin)) {
@@ -6670,12 +6653,18 @@ function format_admin_setting($setting, $title='', $form='', $description='', $l
         $warning = '<div class="form-warning">'.$warning.'</div>';
     }
 
-    if (is_null($defaultinfo)) {
-        $defaultinfo = '';
-    } else {
+    $defaults = array();
+    if (!is_null($defaultinfo)) {
         if ($defaultinfo === '') {
             $defaultinfo = get_string('emptysettingvalue', 'admin');
         }
+        $defaults[] = $defaultinfo;
+    }
+
+    $setting->get_setting_flag_defaults($defaults);
+
+    if (!empty($defaults)) {
+        $defaultinfo = implode(', ', $defaults);
         $defaultinfo = highlight($query, nl2br(s($defaultinfo)));
         $defaultinfo = '<div class="form-defaultinfo">'.get_string('defaultsettinginfo', 'admin', $defaultinfo).'</div>';
     }
@@ -7803,7 +7792,6 @@ class admin_setting_managewebserviceprotocols extends admin_setting {
         $strenable = get_string('enable');
         $strdisable = get_string('disable');
         $strversion = get_string('version');
-        $struninstall = get_string('uninstallplugin', 'admin');
 
         $protocols_available = get_plugin_list('webservice');
         $active_protocols = empty($CFG->webserviceprotocols) ? array() : explode(',', $CFG->webserviceprotocols);
@@ -7819,7 +7807,7 @@ class admin_setting_managewebserviceprotocols extends admin_setting {
         $return .= $OUTPUT->box_start('generalbox webservicesui');
 
         $table = new html_table();
-        $table->head  = array($strprotocol, $strversion, $strenable, $struninstall, $strsettings);
+        $table->head  = array($strprotocol, $strversion, $strenable, $strsettings);
         $table->colclasses = array('leftalign', 'centeralign', 'centeralign', 'centeralign', 'centeralign');
         $table->id = 'webserviceprotocols';
         $table->attributes['class'] = 'admintable generaltable';
@@ -7847,9 +7835,6 @@ class admin_setting_managewebserviceprotocols extends admin_setting {
                 $displayname = "<span class=\"dimmed_text\">$name</span>";
             }
 
-            // delete link
-            $uninstall = "<a href=\"$url&amp;action=uninstall&amp;webservice=$protocol\">$struninstall</a>";
-
             // settings link
             if (file_exists($CFG->dirroot.'/webservice/'.$protocol.'/settings.php')) {
                 $settings = "<a href=\"settings.php?section=webservicesetting$protocol\">$strsettings</a>";
@@ -7858,7 +7843,7 @@ class admin_setting_managewebserviceprotocols extends admin_setting {
             }
 
             // add a row to the table
-            $table->data[] = array($displayname, $version, $hideshow, $uninstall, $settings);
+            $table->data[] = array($displayname, $version, $hideshow, $settings);
         }
         $return .= html_writer::table($table);
         $return .= get_string('configwebserviceplugins', 'webservice');
index f8aa820..fd8057e 100644 (file)
@@ -117,6 +117,12 @@ class auth_plugin_base {
         'address'
     );
 
+    /**
+     * Moodle custom fields to sync with.
+     * @var array()
+     */
+    var $customfields = null;
+
     /**
 
      * This is the primary method that is used by the authenticate_user_login()
@@ -522,6 +528,29 @@ class auth_plugin_base {
         return array();
     }
 
+    /**
+     * Return custom user profile fields.
+     *
+     * @return array list of custom fields.
+     */
+    public function get_custom_user_profile_fields() {
+        global $DB;
+        // If already retrieved then return.
+        if (!is_null($this->customfields)) {
+            return $this->customfields;
+        }
+
+        $this->customfields = array();
+        if ($proffields = $DB->get_records('user_info_field')) {
+            foreach ($proffields as $proffield) {
+                $this->customfields[] = 'profile_field_'.$proffield->shortname;
+            }
+        }
+        unset($proffields);
+
+        return $this->customfields;
+    }
+
 }
 
 /**
index f7ab795..54f08a8 100644 (file)
@@ -341,7 +341,7 @@ class block_manager {
      * output the blocks anyway, so we are not doing wasted effort.)
      *
      * @param string $region a block region that exists on this page.
-     * @param object $output a core_renderer. normally the global $OUTPUT.
+     * @param core_renderer $output a core_renderer. normally the global $OUTPUT.
      * @return boolean Whether there is anything in this region.
      */
     public function region_has_content($region, $output) {
index 389312f..78f9eb8 100644 (file)
@@ -1045,40 +1045,36 @@ class completion_info {
         }
     }
 
+     /**
+     * Return whether or not the course has activities with completion enabled.
+     *
+     * @return boolean true when there is at least one activity with completion enabled.
+     */
+    public function has_activities() {
+        $modinfo = get_fast_modinfo($this->course);
+        foreach ($modinfo->get_cms() as $cm) {
+            if ($cm->completion != COMPLETION_TRACKING_NONE) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Obtains a list of activities for which completion is enabled on the
      * course. The list is ordered by the section order of those activities.
      *
-     * @param array $modinfo For unit testing only, supply the value
-     *   here. Otherwise the method calls get_fast_modinfo
      * @return array Array from $cmid => $cm of all activities with completion enabled,
      *   empty array if none
      */
-    public function get_activities($modinfo=null) {
-        global $DB;
-
-        // Obtain those activities which have completion turned on
-        $withcompletion = $DB->get_records_select('course_modules', 'course='.$this->course->id.
-          ' AND completion<>'.COMPLETION_TRACKING_NONE);
-        if (!$withcompletion) {
-            return array();
-        }
-
-        // Use modinfo to get section order and also add in names
-        if (empty($modinfo)) {
-            $modinfo = get_fast_modinfo($this->course);
-        }
+    public function get_activities() {
+        $modinfo = get_fast_modinfo($this->course);
         $result = array();
-        foreach ($modinfo->sections as $sectioncms) {
-            foreach ($sectioncms as $cmid) {
-                if (array_key_exists($cmid, $withcompletion)) {
-                    $result[$cmid] = $withcompletion[$cmid];
-                    $result[$cmid]->modname = $modinfo->cms[$cmid]->modname;
-                    $result[$cmid]->name    = $modinfo->cms[$cmid]->name;
-                }
+        foreach ($modinfo->get_cms() as $cm) {
+            if ($cm->completion != COMPLETION_TRACKING_NONE) {
+                $result[$cm->id] = $cm;
             }
         }
-
         return $result;
     }
 
index 6cf2ea1..2a5e06d 100644 (file)
@@ -833,7 +833,7 @@ class coursecat implements renderable, cacheable_object, IteratorAggregate {
             $fields[] = 'c.summary';
             $fields[] = 'c.summaryformat';
         } else {
-            $fields[] = $DB->sql_substr('c.summary', 1, 1). ' hassummary';
+            $fields[] = $DB->sql_substr('c.summary', 1, 1). ' as hassummary';
         }
         $sql = "SELECT ". join(',', $fields). ", $ctxselect
                 FROM {course} c
index 8551999..cb6faf3 100644 (file)
@@ -228,7 +228,7 @@ function css_send_ie_css($themename, $rev, $etag, $slasharguments) {
         $css .= "\n@import url($relroot/styles.php?theme=$themename&rev=$rev&type=theme);";
     }
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="styles.php"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
@@ -254,7 +254,7 @@ function css_send_ie_css($themename, $rev, $etag, $slasharguments) {
 function css_send_cached_css($csspath, $etag) {
     $lifetime = 60*60*24*60; // 60 days only - the revision may get incremented quite often
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="styles.php"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($csspath)) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
@@ -312,7 +312,7 @@ function css_send_unmodified($lastmodified, $etag) {
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
     header('Cache-Control: public, max-age='.$lifetime);
     header('Content-Type: text/css; charset=utf-8');
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     if ($lastmodified) {
         header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT');
     }
index 7db9eba..49d8cb5 100644 (file)
@@ -556,6 +556,30 @@ function get_site() {
     }
 }
 
+/**
+ * Gets a course object from database. If the course id corresponds to an
+ * already-loaded $COURSE or $SITE object, then the loaded object will be used,
+ * saving a database query.
+ *
+ * If it reuses an existing object, by default the object will be cloned. This
+ * means you can modify the object safely without affecting other code.
+ *
+ * @param int $courseid Course id
+ * @param bool $clone If true (default), makes a clone of the record
+ * @return stdClass A course object
+ * @throws dml_exception If not found in database
+ */
+function get_course($courseid, $clone = true) {
+    global $DB, $COURSE, $SITE;
+    if (!empty($COURSE->id) && $COURSE->id == $courseid) {
+        return $clone ? clone($COURSE) : $COURSE;
+    } else if (!empty($SITE->id) && $SITE->id == $courseid) {
+        return $clone ? clone($SITE) : $SITE;
+    } else {
+        return $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+    }
+}
+
 /**
  * Returns list of courses, for whole site, or category
  *
@@ -1514,6 +1538,35 @@ function coursemodule_visible_for_user($cm, $userid=0) {
 
 /// LOG FUNCTIONS /////////////////////////////////////////////////////
 
+/**
+ * Add an entry to the config log table.
+ *
+ * These are "action" focussed rather than web server hits,
+ * and provide a way to easily reconstruct changes to Moodle configuration.
+ *
+ * @package core
+ * @category log
+ * @global moodle_database $DB
+ * @global stdClass $USER
+ * @param    string  $name     The name of the configuration change action
+                               For example 'filter_active' when activating or deactivating a filter
+ * @param    string  $oldvalue The config setting's previous value
+ * @param    string  $value    The config setting's new value
+ * @param    string  $plugin   Plugin name, for example a filter name when changing filter configuration
+ * @return void
+ */
+function add_to_config_log($name, $oldvalue, $value, $plugin) {
+    global $USER, $DB;
+
+    $log = new stdClass();
+    $log->userid       = during_initial_install() ? 0 :$USER->id; // 0 as user id during install
+    $log->timemodified = time();
+    $log->name         = $name;
+    $log->oldvalue  = $oldvalue;
+    $log->value     = $value;
+    $log->plugin    = $plugin;
+    $DB->insert_record('config_log', $log);
+}
 
 /**
  * Add an entry to the log table.
index 590c28b..c47725f 100644 (file)
@@ -1886,7 +1886,6 @@ $capabilities = array(
         'contextlevel' => CONTEXT_SYSTEM,
         'archetypes'   => array(
             'manager'       => CAP_ALLOW,
-            'student'       => CAP_PREVENT
         )
     ),
 
@@ -1940,7 +1939,6 @@ $capabilities = array(
             'manager'        => CAP_ALLOW,
             'coursecreator'  => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
-            'student'        => CAP_PREVENT
         )
     ),
 
@@ -1953,7 +1951,6 @@ $capabilities = array(
             'manager'        => CAP_ALLOW,
             'coursecreator'  => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
-            'student'        => CAP_PREVENT
         )
     ),
 
@@ -1966,7 +1963,6 @@ $capabilities = array(
             'manager'        => CAP_ALLOW,
             'coursecreator'  => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
-            'student'        => CAP_PREVENT
         )
     ),
 
@@ -1979,7 +1975,6 @@ $capabilities = array(
             'manager'        => CAP_ALLOW,
             'coursecreator'  => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
-            'student'        => CAP_PREVENT
         )
     ),
 
@@ -1992,7 +1987,6 @@ $capabilities = array(
             'manager'        => CAP_ALLOW,
             'coursecreator'  => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
-            'student'        => CAP_PREVENT
         )
     ),
 
@@ -2006,7 +2000,6 @@ $capabilities = array(
             'coursecreator'  => CAP_ALLOW,
             'teacher'        => CAP_ALLOW,
             'editingteacher' => CAP_ALLOW,
-            'student'        => CAP_PREVENT
         )
     ),
 
index 1b86aee..67660b3 100644 (file)
         <INDEX NAME="typeitem_ix" UNIQUE="false" FIELDS="type, itemid"/>
       </INDEXES>
     </TABLE>
-    <TABLE NAME="backup_ids_template" COMMENT="To store all sort of ids along the backup process. Note this table isn't really used but its temporary counterpart.">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
-        <FIELD NAME="backupid" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="unique id of the backup"/>
-        <FIELD NAME="itemname" TYPE="char" LENGTH="160" NOTNULL="true" SEQUENCE="false" COMMENT="name of the component this id belongs to (usually table names)"/>
-        <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="id of the component (usually table-&amp;gt;id values)"/>
-        <FIELD NAME="newitemid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="new id of the component after restore"/>
-        <FIELD NAME="parentitemid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="other id that can be useful to represent parent-child relations"/>
-        <FIELD NAME="info" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="to store information related with the item, base64(serialize())"/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
-        <KEY NAME="backupid_itemname_itemid_uk" TYPE="unique" FIELDS="backupid, itemname, itemid"/>
-      </KEYS>
-      <INDEXES>
-        <INDEX NAME="backupid_parentitemid_ix" UNIQUE="false" FIELDS="backupid, itemname, parentitemid"/>
-        <INDEX NAME="backupid_itemname_newitemid_ix" UNIQUE="false" FIELDS="backupid, itemname, newitemid"/>
-      </INDEXES>
-    </TABLE>
-    <TABLE NAME="backup_files_template" COMMENT="To store files along the backup process. Note this table isn't really used but its temporary counterpart.">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
-        <FIELD NAME="backupid" TYPE="char" LENGTH="32" NOTNULL="true" SEQUENCE="false" COMMENT="unique backup id this record corresponds to"/>
-        <FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="source contextid of the file"/>
-        <FIELD NAME="component" TYPE="char" LENGTH="100" NOTNULL="true" SEQUENCE="false"/>
-        <FIELD NAME="filearea" TYPE="char" LENGTH="50" NOTNULL="true" SEQUENCE="false"/>
-        <FIELD NAME="itemid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
-        <FIELD NAME="info" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="to store the complete file record (serialized)"/>
-        <FIELD NAME="newcontextid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The new contextid that the file has been restored to."/>
-        <FIELD NAME="newitemid" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="The new itemid the file has been restored to."/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
-      </KEYS>
-      <INDEXES>
-        <INDEX NAME="backupid_contextid_component_filearea_itemid_ix" UNIQUE="false" FIELDS="backupid, contextid, component, filearea, itemid"/>
-      </INDEXES>
-    </TABLE>
     <TABLE NAME="backup_logs" COMMENT="To store all the logs from backup and restore operations (by db logger)">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
         <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
       </KEYS>
     </TABLE>
-    <TABLE NAME="temp_enroled_template" COMMENT="Temporary storage for course enrolments">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
-        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
-        <FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
-        <FIELD NAME="roleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
-      </KEYS>
-      <INDEXES>
-        <INDEX NAME="userid" UNIQUE="false" FIELDS="userid"/>
-        <INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
-        <INDEX NAME="roleid" UNIQUE="false" FIELDS="roleid"/>
-      </INDEXES>
-    </TABLE>
-    <TABLE NAME="temp_log_template" COMMENT="Temporary storage for daily logs">
-      <FIELDS>
-        <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
-        <FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
-        <FIELD NAME="course" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
-        <FIELD NAME="action" TYPE="char" LENGTH="40" NOTNULL="true" SEQUENCE="false"/>
-      </FIELDS>
-      <KEYS>
-        <KEY NAME="primary" TYPE="primary" FIELDS="id"/>
-      </KEYS>
-      <INDEXES>
-        <INDEX NAME="action" UNIQUE="false" FIELDS="action"/>
-        <INDEX NAME="course" UNIQUE="false" FIELDS="course"/>
-        <INDEX NAME="user" UNIQUE="false" FIELDS="userid"/>
-        <INDEX NAME="usercourseaction" UNIQUE="false" FIELDS="userid, course, action"/>
-      </INDEXES>
-    </TABLE>
     <TABLE NAME="badge" COMMENT="Defines badge">
       <FIELDS>
         <FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
index 64ecd3b..c6bafe0 100644 (file)
@@ -2139,6 +2139,9 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2013042300.00);
     }
 
+    // Moodle v2.5.0 release upgrade line.
+    // Put any upgrade step following this.
+
     if ($oldversion < 2013051400.01) {
         // Fix incorrect cc-nc url. Unfortunately the license 'plugins' do
         // not give a mechanism to do this.
@@ -2160,9 +2163,32 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2013051400.01);
     }
 
-    // Moodle v2.5.0 release upgrade line.
-    // Put any upgrade step following this.
+    if ($oldversion < 2013061400.01) {
+        // Clean up old tokens which haven't been deleted.
+        $DB->execute("DELETE FROM {user_private_key} WHERE NOT EXISTS
+                         (SELECT 'x' FROM {user} WHERE deleted = 0 AND id = userid)");
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2013061400.01);
+    }
 
+    if ($oldversion < 2013061700.00) {
+        // MDL-40103: Remove unused template tables from the database.
+        // These are now created inline with xmldb_table.
+
+        $tablestocleanup = array('temp_enroled_template','temp_log_template','backup_files_template','backup_ids_template');
+        $dbman = $DB->get_manager();
+
+        foreach ($tablestocleanup as $table) {
+            $xmltable = new xmldb_table($table);
+            if ($dbman->table_exists($xmltable)) {
+                $dbman->drop_table($xmltable);
+            }
+        }
+
+        // Main savepoint reached.
+        upgrade_main_savepoint(true, 2013061700.00);
+    }
 
     return true;
 }
index 5f72a73..05e9c37 100644 (file)
@@ -2838,24 +2838,10 @@ function show_event($event) {
 }
 
 /**
- * Converts string to lowercase using most compatible function available.
- *
  * @deprecated Use textlib::strtolower($text) instead.
- *
- * @param string $string The string to convert to all lowercase characters.
- * @param string $encoding The encoding on the string.
- * @return string
  */
 function moodle_strtolower($string, $encoding='') {
-
-    debugging('moodle_strtolower() is deprecated. Please use textlib::strtolower() instead.', DEBUG_DEVELOPER);
-
-    //If not specified use utf8
-    if (empty($encoding)) {
-        $encoding = 'UTF-8';
-    }
-    //Use text services
-    return textlib::strtolower($string, $encoding);
+    throw new coding_exception('moodle_strtolower() cannot be used any more. Please use textlib::strtolower() instead.');
 }
 
 /**
@@ -4676,3 +4662,20 @@ function convert_tabrows_to_tree($tabrows, $selected, $inactive, $activated) {
 
     return $subtree;
 }
+
+/**
+ * @deprecated since Moodle 2.3
+ */
+function move_section($course, $section, $move) {
+    throw new coding_exception('move_section() can not be used any more, please see move_section_to().');
+}
+/**
+ * Can handle rotated text. Whether it is safe to use the trickery in textrotate.js.
+ *
+ * @deprecated since 2.5 - do not use, the textrotate.js will work it out automatically
+ * @return bool True for yes, false for no
+ */
+function can_use_rotated_text() {
+    debugging('can_use_rotated_text() is deprecated since Moodle 2.5. JS feature detection is used automatically.', DEBUG_DEVELOPER);
+    return true;
+}
index 96f14fc..f146088 100644 (file)
@@ -51,8 +51,6 @@ class oci_native_moodle_database extends moodle_database {
     private $last_error_reporting;
     /** @var To store unique_session_id. Needed for temp tables unique naming.*/
     private $unique_session_id;
-    /** @var To cache locks support along the connection life.*/
-    private $oci_package_installed = null;
 
     /**
      * Detects if all needed PHP stuff installed.
@@ -127,9 +125,6 @@ class oci_native_moodle_database extends moodle_database {
      * @return string null means everything ok, string means problem found.
      */
     public function diagnose() {
-        if (!$this->oci_package_installed()) {
-            return 'Oracle PL/SQL Moodle support packages are not installed! Database administrator has to execute /lib/dml/oci_native_moodle_package.sql script.';
-        }
         return null;
     }
 
@@ -203,6 +198,19 @@ class oci_native_moodle_database extends moodle_database {
             throw new dml_connection_exception($dberr);
         }
 
+        // Make sure moodle package is installed - now required.
+        if (!$this->oci_package_installed()) {
+            try {
+                $this->attempt_oci_package_install();
+            } catch (Exception $e) {
+                // Ignore problems, only the result counts,
+                // admins have to fix it manually if necessary.
+            }
+            if (!$this->oci_package_installed()) {
+                throw new dml_exception('dbdriverproblem', 'Oracle PL/SQL Moodle support package MOODLELIB is not installed! Database administrator has to execute /lib/dml/oci_native_moodle_package.sql script.');
+            }
+        }
+
         // get unique session id, to be used later for temp tables stuff
         $sql = 'SELECT DBMS_SESSION.UNIQUE_SESSION_ID() FROM DUAL';
         $this->query_start($sql, null, SQL_QUERY_AUX);
@@ -1476,21 +1484,11 @@ class oci_native_moodle_database extends moodle_database {
     }
 
     public function sql_bitor($int1, $int2) {
-        // Use the MOODLELIB package if available
-        if ($this->oci_package_installed()) {
-            return 'MOODLELIB.BITOR(' . $int1 . ', ' . $int2 . ')';
-        }
-        // fallback to PHP bool operations, can break if using placeholders
-        return '((' . $int1 . ') + (' . $int2 . ') - ' . $this->sql_bitand($int1, $int2) . ')';
+        return 'MOODLELIB.BITOR(' . $int1 . ', ' . $int2 . ')';
     }
 
     public function sql_bitxor($int1, $int2) {
-        // Use the MOODLELIB package if available
-        if ($this->oci_package_installed()) {
-            return 'MOODLELIB.BITXOR(' . $int1 . ', ' . $int2 . ')';
-        }
-        // fallback to PHP bool operations, can break if using placeholders
-        return '(' . $this->sql_bitor($int1, $int2) . ' - ' . $this->sql_bitand($int1, $int2) . ')';
+        return 'MOODLELIB.BITXOR(' . $int1 . ', ' . $int2 . ')';
     }
 
     /**
@@ -1703,9 +1701,6 @@ class oci_native_moodle_database extends moodle_database {
      * @return bool
      */
     protected function oci_package_installed() {
-        if (isset($this->oci_package_installed)) { // Use cached value if available.
-            return $this->oci_package_installed;
-        }
         $sql = "SELECT 1
                 FROM user_objects
                 WHERE object_type = 'PACKAGE BODY'
@@ -1718,8 +1713,22 @@ class oci_native_moodle_database extends moodle_database {
         $records = null;
         oci_fetch_all($stmt, $records, 0, -1, OCI_FETCHSTATEMENT_BY_ROW);
         oci_free_statement($stmt);
-        $this->oci_package_installed = isset($records[0]) && reset($records[0]) ? true : false;
-        return $this->oci_package_installed;
+        return isset($records[0]) && reset($records[0]) ? true : false;
+    }
+
+    /**
+     * Try to add required moodle package into oracle server.
+     */
+    protected function attempt_oci_package_install() {
+        $sqls = file_get_contents(__DIR__.'/oci_native_moodle_package.sql');
+        $sqls = preg_split('/^\/$/sm', $sqls);
+        foreach ($sqls as $sql) {
+            $sql = trim($sql);
+            if ($sql === '' or $sql === 'SHOW ERRORS') {
+                continue;
+            }
+            $this->change_database_structure($sql);
+        }
     }
 
     /**
@@ -1729,9 +1738,6 @@ class oci_native_moodle_database extends moodle_database {
      * @return void
      */
     public function get_session_lock($rowid, $timeout) {
-        if (!$this->oci_package_installed()) {
-            return;
-        }
         parent::get_session_lock($rowid, $timeout);
 
         $fullname = $this->dbname.'-'.$this->prefix.'-session-'.$rowid;
@@ -1749,9 +1755,6 @@ class oci_native_moodle_database extends moodle_database {
     }
 
     public function release_session_lock($rowid) {
-        if (!$this->oci_package_installed()) {
-            return;
-        }
         if (!$this->used_for_db_sessions) {
             return;
         }
index a01de83..624cead 100644 (file)
@@ -513,8 +513,8 @@ function filter_get_all_installed() {
     global $CFG;
 
     $filternames = array();
-    foreach (get_list_of_plugins('filter') as $filter) {
-        if (is_readable("$CFG->dirroot/filter/$filter/filter.php")) {
+    foreach (get_plugin_list('filter') as $filter => $fulldir) {
+        if (is_readable("$fulldir/filter.php")) {
             $filternames[$filter] = filter_get_name($filter);
         }
     }
@@ -571,17 +571,22 @@ function filter_set_global_state($filtername, $state, $move = 0) {
     if (isset($on[$filtername])) {
         $filter = $on[$filtername];
         if ($filter->active != $state) {
+            add_to_config_log('filter_active', $filter->active, $state, $filtername);
+
             $filter->active = $state;
             $DB->update_record('filter_active', $filter);
             if ($filter->active == TEXTFILTER_DISABLED) {
                 unset($on[$filtername]);
                 $off = array($filter->filter => $filter) + $off;
             }
+
         }
 
     } else if (isset($off[$filtername])) {
         $filter = $off[$filtername];
         if ($filter->active != $state) {
+            add_to_config_log('filter_active', $filter->active, $state, $filtername);
+
             $filter->active = $state;
             $DB->update_record('filter_active', $filter);
             if ($filter->active != TEXTFILTER_DISABLED) {
@@ -591,6 +596,8 @@ function filter_set_global_state($filtername, $state, $move = 0) {
         }
 
     } else {
+        add_to_config_log('filter_active', '', $state, $filtername);
+
         $filter = new stdClass();
         $filter->filter    = $filtername;
         $filter->contextid = $syscontext->id;
index 1a0e432..f4cb2c5 100644 (file)
@@ -119,12 +119,12 @@ class MoodleQuickForm_date_selector extends MoodleQuickForm_group
         $this->_elements[] = @MoodleQuickForm::createElement('select', 'day', get_string('day', 'form'), $days, $this->getAttributes(), true);
         $this->_elements[] = @MoodleQuickForm::createElement('select', 'month', get_string('month', 'form'), $months, $this->getAttributes(), true);
         $this->_elements[] = @MoodleQuickForm::createElement('select', 'year', get_string('year', 'form'), $years, $this->getAttributes(), true);
+        $this->_elements[] = @MoodleQuickForm::createElement('image', 'calendar', $OUTPUT->pix_url('i/calendar', 'moodle'),
+            array('title' => get_string('calendar', 'calendar'), 'class' => 'visibleifjs'));
         // If optional we add a checkbox which the user can use to turn if on
         if($this->_options['optional']) {
             $this->_elements[] = @MoodleQuickForm::createElement('checkbox', 'enabled', null, get_string('enable'), $this->getAttributes(), true);
         }
-        $this->_elements[] = @MoodleQuickForm::createElement('image', 'calendar', $OUTPUT->pix_url('i/calendar', 'moodle'),
-            array('title' => get_string('calendar', 'calendar'), 'class' => 'visibleifjs'));
         foreach ($this->_elements as $element){
             if (method_exists($element, 'setHiddenLabel')){
                 $element->setHiddenLabel(true);
index f2003d2..f56eb03 100644 (file)
@@ -227,28 +227,10 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
     }
 
     /**
-     * Sets help button for editor
-     *
-     * @param mixed $_helpbuttonargs arguments to create help button
-     * @param string $function name of the callback function
-     * @deprecated since Moodle 2.0. Please do not call this function any more.
-     * @todo MDL-34508 this api will be removed.
-     * @see MoodleQuickForm::addHelpButton()
+     * @deprecated since Moodle 2.0
      */
     function setHelpButton($_helpbuttonargs, $function='_helpbutton') {
-        debugging('setHelpButton() is deprecated, please use $mform->addHelpButton() instead');
-        if (!is_array($_helpbuttonargs)) {
-            $_helpbuttonargs = array($_helpbuttonargs);
-        } else {
-            $_helpbuttonargs = $_helpbuttonargs;
-        }
-        //we do this to to return html instead of printing it
-        //without having to specify it in every call to make a button.
-        if ('_helpbutton' == $function){
-            $defaultargs = array('', '', 'moodle', true, false, '', true);
-            $_helpbuttonargs = $_helpbuttonargs + $defaultargs ;
-        }
-        $this->_helpbutton=call_user_func_array($function, $_helpbuttonargs);
+        throw new coding_exception('setHelpButton() can not be used any more, please see MoodleQuickForm::addHelpButton().');
     }
 
     /**
index b0e78b4..6c2f239 100644 (file)
@@ -54,16 +54,10 @@ class MoodleQuickForm_hidden extends HTML_QuickForm_hidden{
     }
 
     /**
-     * set html for help button
-     *
-     * @param array $helpbuttonargs array of arguments to make a help button
-     * @param string $function function name to call to get html
-     * @deprecated since Moodle 2.0. Please do not call this function any more.
-     * @todo MDL-34508 this api will be removed.
-     * @see MoodleQuickForm::addHelpButton()
+     * @deprecated since Moodle 2.0
      */
     function setHelpButton($helpbuttonargs, $function='helpbutton'){
-        debugging('setHelpButton() is deprecated, please use $mform->addHelpButton() instead');
+        throw new coding_exception('setHelpButton() can not be used any more, please see MoodleQuickForm::addHelpButton().');
     }
 
     /**
diff --git a/lib/form/submit.js b/lib/form/submit.js
new file mode 100644 (file)
index 0000000..6287f16
--- /dev/null
@@ -0,0 +1,9 @@
+M.form_submit = {};
+
+M.form_submit.init = function(Y, options) {
+    Y.on('submit', function(e) {
+        if (!containsErrors) {
+            e.target.one('#'+options.submitid).setAttribute('disabled', 'true');
+        }
+    }, '#'+options.formid);
+};
\ No newline at end of file
index af94e4f..445cfbc 100644 (file)
@@ -38,6 +38,9 @@ require_once("HTML/QuickForm/submit.php");
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class MoodleQuickForm_submit extends HTML_QuickForm_submit {
+    /** @var string Need to store id of form for submission control in JS*/
+    var $_formid = '';
+
     /**
      * constructor
      *
@@ -60,6 +63,7 @@ class MoodleQuickForm_submit extends HTML_QuickForm_submit {
     {
         switch ($event) {
             case 'createElement':
+                $this->_formid = $caller->getAttribute('id');
                 parent::onQuickFormEvent($event, $arg, $caller);
                 if ($caller->isNoSubmitButton($arg[0])){
                     //need this to bypass client validation
@@ -98,4 +102,22 @@ class MoodleQuickForm_submit extends HTML_QuickForm_submit {
         $this->_flagFrozen = true;
     }
 
+    /**
+     * Returns HTML for this form element.
+     *
+     * @return string
+     */
+    function toHtml(){
+        global $PAGE;
+        $options = array(
+            'submitid' => $this->getAttribute('id'),
+            'formid' => $this->_formid,
+        );
+        $str = parent::toHtml();
+        if ($this->getAttribute('onclick') === null) {
+            $module = array('name'=>'form_submit', 'fullpath'=>'/lib/form/submit.js');
+            $PAGE->requires->js_init_call('M.form_submit.init', array($options), true, $module);
+        }
+        return $str;
+    }
 }
index 5c48075..e1394f3 100644 (file)
@@ -166,6 +166,7 @@ YUI.add('moodle-form-dateselector', function(Y) {
             if (!this.enablecheckbox.get('checked')) {
                 this.calendarimage.set('disabled', 'disabled');
                 this.calendarimage.setStyle('cursor', 'default');
+                this.release_calendar();
             } else {
                 this.calendarimage.set('disabled', false);
                 this.calendarimage.setStyle('cursor', 'auto');
index 22362f8..8f12d6a 100644 (file)
@@ -2096,6 +2096,7 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
 //<![CDATA[
 
 var skipClientValidation = false;
+var containsErrors = false;
 
 function qf_errorHandler(element, _qfMsg) {
   div = element.parentNode;
@@ -2204,6 +2205,7 @@ function validate_' . $this->_formName . '(frm) {
   var frm = document.getElementById(\''. $this->_attributes['id'] .'\')
   var first_focus = false;
 ' . $validateJS . ';
+  containsErrors = !ret;
   return ret;
 }
 //]]>
index 1d20bbd..bbfb895 100644 (file)
@@ -36,7 +36,7 @@ function js_send_cached($jspath, $etag, $filename = 'javascript.php') {
 
     $lifetime = 60*60*24*60; // 60 days only - the revision may get incremented quite often
 
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     header('Content-Disposition: inline; filename="'.$filename.'"');
     header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($jspath)) .' GMT');
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
@@ -86,7 +86,7 @@ function js_send_unmodified($lastmodified, $etag) {
     header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
     header('Cache-Control: public, max-age='.$lifetime);
     header('Content-Type: application/javascript; charset=utf-8');
-    header('Etag: '.$etag);
+    header('Etag: "'.$etag.'"');
     if ($lastmodified) {
         header('Last-Modified: '. gmdate('D, d M Y H:i:s', $lastmodified) .' GMT');
     }
index 0d396a4..bc3a8ec 100644 (file)
@@ -3839,18 +3839,19 @@ function get_user_fieldnames() {
  */
 function create_user_record($username, $password, $auth = 'manual') {
     global $CFG, $DB;
-
+    require_once($CFG->dirroot."/user/profile/lib.php");
     //just in case check text case
     $username = trim(textlib::strtolower($username));
 
     $authplugin = get_auth_plugin($auth);
-
+    $customfields = $authplugin->get_custom_user_profile_fields();
     $newuser = new stdClass();
-
     if ($newinfo = $authplugin->get_userinfo($username)) {
         $newinfo = truncate_userinfo($newinfo);
         foreach ($newinfo as $key => $value){
-            $newuser->$key = $value;
+            if (in_array($key, $authplugin->userfields) || (in_array($key, $customfields))) {
+                $newuser->$key = $value;
+            }
         }
     }
 
@@ -3880,6 +3881,10 @@ function create_user_record($username, $password, $auth = 'manual') {
     $newuser->mnethostid = $CFG->mnet_localhost_id;
 
     $newuser->id = $DB->insert_record('user', $newuser);
+
+    // Save user profile data.
+    profile_save_data($newuser);
+
     $user = get_complete_user_data('id', $newuser->id);
     if (!empty($CFG->{'auth_'.$newuser->auth.'_forcechangepassword'})){
         set_user_preference('auth_forcepasswordchange', 1, $user);
@@ -3903,7 +3908,7 @@ function create_user_record($username, $password, $auth = 'manual') {
  */
 function update_user_record($username) {
     global $DB, $CFG;
-
+    require_once($CFG->dirroot."/user/profile/lib.php");
     $username = trim(textlib::strtolower($username)); /// just in case check text case
 
     $oldinfo = $DB->get_record('user', array('username'=>$username, 'mnethostid'=>$CFG->mnet_localhost_id), '*', MUST_EXIST);
@@ -3912,9 +3917,12 @@ function update_user_record($username) {
 
     if ($newinfo = $userauth->get_userinfo($username)) {
         $newinfo = truncate_userinfo($newinfo);
+        $customfields = $userauth->get_custom_user_profile_fields();
+
         foreach ($newinfo as $key => $value){
             $key = strtolower($key);
-            if (!property_exists($oldinfo, $key) or $key === 'username' or $key === 'id'
+            $iscustom = in_array($key, $customfields);
+            if ((!property_exists($oldinfo, $key) && !$iscustom) or $key === 'username' or $key === 'id'
                     or $key === 'auth' or $key === 'mnethostid' or $key === 'deleted') {
                 // unknown or must not be changed
                 continue;
@@ -3932,7 +3940,8 @@ function update_user_record($username) {
                 // nothing_ for this field. Thus it makes sense to let this value
                 // stand in until LDAP is giving a value for this field.
                 if (!(empty($value) && $lockval === 'unlockedifempty')) {
-                    if ((string)$oldinfo->$key !== (string)$value) {
+                    if ($iscustom || (in_array($key, $userauth->userfields) &&
+                            ((string)$oldinfo->$key !== (string)$value))) {
                         $newuser[$key] = (string)$value;
                     }
                 }
@@ -3942,6 +3951,10 @@ function update_user_record($username) {
             $newuser['id'] = $oldinfo->id;
             $newuser['timemodified'] = time();
             $DB->update_record('user', $newuser);
+
+            // Save user profile data.
+            profile_save_data((object) $newuser);
+
             // fetch full user record for the event, the complete user data contains too much info
             // and we want to be consistent with other places that trigger this event
             events_trigger('user_updated', $DB->get_record('user', array('id'=>$oldinfo->id)));
@@ -4078,6 +4091,9 @@ function delete_user(stdClass $user) {
     // unauthorise the user for all services
     $DB->delete_records('external_services_users', array('userid'=>$user->id));
 
+    // Remove users private keys.
+    $DB->delete_records('user_private_key', array('userid' => $user->id));
+
     // force logout - may fail if file based sessions used, sorry
     session_kill_user($user->id);
 
@@ -7563,7 +7579,7 @@ function get_string($identifier, $component = '', $a = NULL, $lazyload = false)
         return new lang_string($identifier, $component, $a);
     }
 
-    if (debugging('', DEBUG_DEVELOPER) && clean_param($identifier, PARAM_STRINGID) === '') {
+    if ($CFG->developerdebug && clean_param($identifier, PARAM_STRINGID) === '') {
         throw new coding_exception('Invalid string identifier. The identifier cannot be empty. Please fix your get_string() call.');
     }
 
@@ -8219,7 +8235,14 @@ function get_plugin_types($fullpaths=true) {
     $cache = cache::make('core', 'plugintypes');
 
     if ($fullpaths) {
-        $cached = $cache->get(1);
+        // First confirm that dirroot and the stored dirroot match.
+        if ($CFG->dirroot === $cache->get('dirroot')) {
+            // They match we can use it.
+            $cached = $cache->get(1);
+        } else {
+            // Oops they didn't match. The moodle directory has been moved on us.
+            $cached = false;
+        }
     } else {
         $cached = $cache->get(0);
     }
@@ -8279,6 +8302,9 @@ function get_plugin_types($fullpaths=true) {
 
         $cache->set(0, $info);
         $cache->set(1, $fullinfo);
+        // We cache the dirroot as well so that we can compare it when we
+        // retrieve full info from the cache.
+        $cache->set('dirroot', $CFG->dirroot);
 
         return ($fullpaths ? $fullinfo : $info);
     }
@@ -8301,7 +8327,9 @@ function is_valid_plugin_name($name) {
 function get_plugin_list($plugintype) {
     global $CFG;
 
-    $cache = cache::make('core', 'pluginlist');
+    // We use the dirroot as an identifier here because if it has changed the whole cache
+    // can be considered invalid.
+    $cache = cache::make('core', 'pluginlist', array('dirroot' => $CFG->dirroot));
     $cached = $cache->get($plugintype);
     if ($cached !== false) {
         return $cached;
@@ -9111,17 +9139,6 @@ function get_browser_version_classes() {
     return $classes;
 }
 
-/**
- * Can handle rotated text. Whether it is safe to use the trickery in textrotate.js.
- *
- * @return bool True for yes, false for no
- */
-function can_use_rotated_text() {
-    return check_browser_version('MSIE', 9) || check_browser_version('Firefox', 2) ||
-            check_browser_version('Chrome', 21) || check_browser_version('Safari', 536.25) ||
-            check_browser_version('Opera', 12) || check_browser_version('Safari iOS', 533);
-}
-
 /**
  * Determine if moodle installation requires update
  *
@@ -10609,8 +10626,8 @@ function get_performance_info() {
     $info['html'] .= '<span class="included">Included '.$info['includecount'].' files</span> ';
     $info['txt']  .= 'includecount: '.$info['includecount'].' ';
 
-    if (!empty($CFG->early_install_lang)) {
-        // We can not track more performance before installation, sorry.
+    if (!empty($CFG->early_install_lang) or empty($PAGE)) {
+        // We can not track more performance before installation or before PAGE init, sorry.
         return $info;
     }
 
@@ -11359,6 +11376,7 @@ class lang_string {
      * @param string $lang The language to use when processing the string.
      */
     public function __construct($identifier, $component = '', $a = null, $lang = null) {
+        global $CFG;
         if (empty($component)) {
             $component = 'moodle';
         }
@@ -11396,7 +11414,7 @@ class lang_string {
             }
         }
 
-        if (debugging(false, DEBUG_DEVELOPER)) {
+        if ($CFG->developerdebug) {
             if (clean_param($this->identifier, PARAM_STRINGID) == '') {
                 throw new coding_exception('Invalid string identifier. Most probably some illegal character is part of the string identifier. Please check your string definition');
             }
index 7e1576b..8046f89 100644 (file)
@@ -899,8 +899,9 @@ class navigation_node_collection implements IteratorAggregate {
         $child = $this->get($key, $type);
         if ($child !== false) {
             foreach ($this->collection as $colkey => $node) {
-                if ($node->key == $key && $node->type == $type) {
+                if ($node->key === $key && $node->type == $type) {
                     unset($this->collection[$colkey]);
+                    $this->collection = array_values($this->collection);
                     break;
                 }
             }
@@ -2447,9 +2448,9 @@ class global_navigation extends navigation_node {
         }
 
         // Badges.
-        if (!empty($CFG->enablebadges) && has_capability('moodle/badges:viewbadges', $this->page->context)) {
-            $url = new moodle_url($CFG->wwwroot . '/badges/view.php',
-                    array('type' => 2, 'id' => $course->id));
+        if (!empty($CFG->enablebadges) && !empty($CFG->badges_allowcoursebadges) &&
+            has_capability('moodle/badges:viewbadges', $this->page->context)) {
+            $url = new moodle_url('/badges/view.php', array('type' => 2, 'id' => $course->id));
 
             $coursenode->add(get_string('coursebadges', 'badges'), null,
                     navigation_node::TYPE_CONTAINER, null, 'coursebadges');
@@ -2498,7 +2499,7 @@ class global_navigation extends navigation_node {
         }
 
         //Badges
-        if (!empty($CFG->enablebadges) && !empty($CFG->badges_allowcoursebadges) && has_capability('moodle/badges:viewbadges', $this->page->context)) {
+        if (!empty($CFG->enablebadges) && has_capability('moodle/badges:viewbadges', $this->page->context)) {
             $url = new moodle_url($CFG->wwwroot . '/badges/view.php', array('type' => 1));
             $coursenode->add(get_string('sitebadges', 'badges'), $url, navigation_node::TYPE_CUSTOM);
         }
@@ -3489,7 +3490,7 @@ class settings_navigation extends navigation_node {
             $coursenode->force_open();
         }
 
-        if (has_capability('moodle/course:update', $coursecontext)) {
+        if ($this->page->user_allowed_editing()) {
             // Add the turn on/off settings
 
             if ($this->page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) {
@@ -3509,8 +3510,10 @@ class settings_navigation extends navigation_node {
                 $editurl->param('edit', 'on');
                 $editstring = get_string('turneditingon');
             }
-            $coursenode->add($editstring, $editurl, self::TYPE_SETTING, null, null, new pix_icon('i/edit', ''));
+            $coursenode->add($editstring, $editurl, self::TYPE_SETTING, null, 'turneditingonoff', new pix_icon('i/edit', ''));
+        }
 
+        if (has_capability('moodle/course:update', $coursecontext)) {
             // Add the course settings link
             $url = new moodle_url('/course/edit.php', array('id'=>$course->id));
             $coursenode->add(get_string('editsettings'), $url, self::TYPE_SETTING, null, 'editsettings', new pix_icon('i/settings', ''));
@@ -3906,10 +3909,11 @@ class settings_navigation extends navigation_node {
                 }
             } else {
                 $canviewusercourse = has_capability('moodle/user:viewdetails', $coursecontext);
-                $canaccessallgroups = has_capability('moodle/site:accessallgroups', $coursecontext);
-                if ((!$canviewusercourse && !$canviewuser) || !can_access_course($course, $user->id)) {
+                $userisenrolled = is_enrolled($coursecontext, $user->id);
+                if ((!$canviewusercourse && !$canviewuser) || !$userisenrolled) {
                     return false;
                 }
+                $canaccessallgroups = has_capability('moodle/site:accessallgroups', $coursecontext);
                 if (!$canaccessallgroups && groups_get_course_groupmode($course) == SEPARATEGROUPS) {
                     // If groups are in use, make sure we can see that group
                     return false;
@@ -4030,23 +4034,6 @@ class settings_navigation extends navigation_node {
             $usersetting->add(get_string('securitykeys', 'webservice'), $url, self::TYPE_SETTING);
         }
 
-        // Repository
-        if (!$currentuser && $usercontext->contextlevel == CONTEXT_USER) {
-            if (!$this->cache->cached('contexthasrepos'.$usercontext->id)) {
-                require_once($CFG->dirroot . '/repository/lib.php');
-                $editabletypes = repository::get_editable_types($usercontext);
-                $haseditabletypes = !empty($editabletypes);
-                unset($editabletypes);
-                $this->cache->set('contexthasrepos'.$usercontext->id, $haseditabletypes);
-            } else {
-                $haseditabletypes = $this->cache->{'contexthasrepos'.$usercontext->id};
-            }
-            if ($haseditabletypes) {
-                $url = new moodle_url('/repository/manage_instances.php', array('contextid'=>$usercontext->id));
-                $usersetting->add(get_string('repositories', 'repository'), $url, self::TYPE_SETTING);
-            }
-        }
-
         // Messaging
         if (($currentuser && has_capability('moodle/user:editownmessageprofile', $systemcontext)) || (!isguestuser($user) && has_capability('moodle/user:editmessageprofile', $usercontext) && !is_primary_admin($user->id))) {
             $url = new moodle_url('/message/edit.php', array('id'=>$user->id));
@@ -4079,7 +4066,7 @@ class settings_navigation extends navigation_node {
             $reportfunction($reporttab, $user, $course);
         }
         $anyreport = has_capability('moodle/user:viewuseractivitiesreport', $usercontext);
-        if ($anyreport || ($course->showreports && $currentuser && $forceforcontext)) {
+        if ($anyreport || ($course->showreports && $currentuser)) {
             // Add grade hardcoded grade report if necessary.
             $gradeaccess = false;
             if (has_capability('moodle/grade:viewall', $coursecontext)) {
@@ -4105,7 +4092,6 @@ class settings_navigation extends navigation_node {
         // Check the number of nodes in the report node... if there are none remove the node
         $reporttab->trim_if_empty();
 
-
         // Login as ...
 &nbs