Merge branch 'MDL-42084-master' of git://github.com/sammarshallou/moodle
authorSam Hemelryk <sam@moodle.com>
Wed, 4 Dec 2013 19:25:35 +0000 (08:25 +1300)
committerSam Hemelryk <sam@moodle.com>
Wed, 4 Dec 2013 19:25:35 +0000 (08:25 +1300)
610 files changed:
.shifter.json
admin/mnet/access_control.php
admin/renderer.php
admin/settings/appearance.php
admin/settings/development.php
admin/settings/plugins.php
admin/tests/behat/behat_admin.php
admin/tests/behat/display_short_names.feature
admin/tool/behat/cli/util.php
admin/tool/behat/lang/en/tool_behat.php
admin/tool/behat/tests/behat/basic_actions.feature
admin/tool/behat/tests/behat/data_generators.feature
admin/tool/behat/tests/behat/manipulate_forms.feature
admin/tool/behat/version.php
admin/tool/capability/locallib.php
admin/tool/capability/renderer.php
admin/tool/customlang/db/upgrade.php
admin/tool/generator/testplan.template.jmx
admin/tool/langimport/lang/en/tool_langimport.php
admin/tool/spamcleaner/index.php
admin/tool/uploadcourse/classes/base_form.php
admin/tool/uploadcourse/classes/step1_form.php
admin/tool/uploadcourse/classes/step2_form.php
admin/tool/uploadcourse/lang/en/tool_uploadcourse.php
admin/tool/uploaduser/index.php
admin/tool/xmldb/actions/check_foreign_keys/check_foreign_keys.class.php
admin/tool/xmldb/lang/en/tool_xmldb.php
auth/cas/db/upgrade.php
auth/db/auth.php
auth/imap/auth.php
auth/ldap/auth.php
auth/ldap/db/upgrade.php
auth/manual/db/upgrade.php
auth/mnet/db/upgrade.php
auth/pop3/auth.php
auth/upgrade.txt
backup/backup.class.php
backup/moodle2/restore_stepslib.php
backup/util/progress/core_backup_progress.class.php
backup/util/ui/base_moodleform.class.php
backup/util/ui/restore_ui_stage.class.php
backup/util/ui/tests/behat/duplicate_activities.feature
badges/cron.php
badges/edit_form.php
badges/tests/badgeslib_test.php
blocks/activity_modules/tests/behat/block_activity_modules.feature [new file with mode: 0644]
blocks/community/db/upgrade.php
blocks/completionstatus/db/upgrade.php
blocks/course_list/block_course_list.php
blocks/course_summary/db/upgrade.php
blocks/html/db/upgrade.php
blocks/mentees/block_mentees.php
blocks/navigation/db/upgrade.php
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
blocks/rss_client/block_rss_client.php
blocks/section_links/db/upgrade.php
blocks/selfcompletion/db/upgrade.php
blocks/settings/db/upgrade.php
blocks/site_main_menu/block_site_main_menu.php
blocks/tags/block_tags.php
blocks/tests/behat/behat_blocks.php
blocks/tests/behat/configure_block_throughout_site.feature
blocks/tests/behat/manage_blocks.feature
blocks/tests/behat/return_block_original_state.feature
blog/index.php
blog/lib.php
blog/locallib.php
blog/tests/bloglib_test.php
blog/upgrade.txt [new file with mode: 0644]
cache/admin.php
cache/classes/definition.php
cache/classes/factory.php
cache/classes/helper.php
cache/classes/loaders.php
cache/locallib.php
cache/stores/memcache/lib.php
cache/stores/memcached/lib.php
calendar/renderer.php
cohort/tests/behat/behat_cohort.php
cohort/tests/behat/upload_cohort_users.feature
composer.json
config-dist.php
course/ajax/management.php
course/classes/management/helper.php
course/classes/management_renderer.php
course/format/lib.php
course/format/renderer.php
course/lib.php
course/management.php
course/renderer.php
course/resources.php
course/tests/behat/activities_visibility_icons.feature
course/tests/behat/behat_course.php
course/tests/behat/category_management.feature
course/tests/behat/category_resort.feature
course/tests/behat/course_category_management_listing.feature
course/tests/behat/course_change_visibility.feature
course/tests/behat/course_controls.feature
course/tests/courselib_test.php
course/tests/management_helper_test.php
course/yui/build/moodle-course-management/moodle-course-management-debug.js
course/yui/build/moodle-course-management/moodle-course-management-min.js
course/yui/build/moodle-course-management/moodle-course-management.js
course/yui/dragdrop/dragdrop.js
course/yui/src/management/js/category.js
course/yui/src/management/js/console.js
course/yui/src/management/js/course.js
course/yui/src/management/js/item.js
course/yui/toolboxes/toolboxes.js
enrol/database/db/upgrade.php
enrol/flatfile/db/upgrade.php
enrol/guest/db/upgrade.php
enrol/imsenterprise/db/upgrade.php
enrol/manual/db/upgrade.php
enrol/mnet/db/upgrade.php
enrol/paypal/db/upgrade.php
enrol/paypal/lib.php
enrol/self/db/upgrade.php
enrol/self/version.php
filter/algebra/thirdpartylibs.xml [new file with mode: 0644]
filter/glossary/filter.php
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js
filter/glossary/yui/src/autolinker/js/autolinker.js
filter/mediaplugin/db/upgrade.php
filter/tex/db/upgrade.php
filter/tex/filter.php
filter/tex/lang/en/filter_tex.php
filter/tex/latex.php
filter/tex/lib.php
filter/tex/pix.php
filter/tex/settings.php
filter/tex/texdebug.php
filter/tex/version.php
grade/grading/form/rubric/db/upgrade.php
grade/report/grader/index.php
grade/report/grader/lib.php
grade/report/lib.php
grade/report/upgrade.txt
group/overview.php
group/tests/behat/create_groups.feature
group/tests/behat/delete_groups.feature [new file with mode: 0644]
group/tests/behat/id_uniqueness.feature
group/tests/behat/update_groups.feature [new file with mode: 0644]
install/lang/hi/admin.php
install/lang/hu/langconfig.php
install/lang/hy/admin.php
install/lang/it/error.php
install/lang/it/install.php
install/lang/lt_uni/admin.php
install/lang/pt_br/admin.php
install/lang/ru/admin.php
install/lang/ru/error.php
install/lang/ru/install.php
install/lang/tr/admin.php
install/lang/tr/error.php
install/lang/tr/install.php
lang/en/admin.php
lang/en/backup.php
lang/en/badges.php
lang/en/blog.php
lang/en/cache.php
lang/en/calendar.php
lang/en/error.php
lang/en/form.php
lang/en/message.php
lang/en/mnet.php
lang/en/moodle.php
lang/en/plugin.php
lang/en/question.php
lang/en/repository.php
lib/accesslib.php
lib/ajax/getsiteadminbranch.php
lib/authlib.php
lib/badgeslib.php
lib/behat/classes/behat_command.php
lib/behat/classes/behat_config_manager.php
lib/behat/classes/behat_selectors.php
lib/behat/classes/util.php
lib/behat/lib.php
lib/boxlib.php
lib/classes/collator.php
lib/classes/event/blog_association_created.php [new file with mode: 0644]
lib/classes/event/blog_entries_viewed.php [new file with mode: 0644]
lib/classes/event/course_module_viewed.php [new file with mode: 0644]
lib/classes/minify.php
lib/classes/php_time_limit.php
lib/classes/plugin_manager.php
lib/classes/plugininfo/base.php
lib/classes/plugininfo/calendartype.php
lib/classes/session/file.php
lib/classes/session/manager.php
lib/classes/user.php
lib/completionlib.php
lib/conditionlib.php
lib/coursecatlib.php
lib/db/messages.php
lib/db/upgrade.php
lib/ddl/sql_generator.php
lib/ddl/tests/ddl_test.php
lib/dml/mssql_native_moodle_database.php
lib/dml/oci_native_moodle_database.php
lib/dml/sqlsrv_native_moodle_database.php
lib/dml/tests/dml_test.php
lib/editor/tinymce/db/upgrade.php
lib/editor/tinymce/plugins/managefiles/manage.php
lib/editor/tinymce/plugins/pdw/readme_moodle.txt
lib/editor/tinymce/plugins/pdw/tinymce/editor_plugin.js
lib/editor/tinymce/plugins/spellchecker/db/upgrade.php
lib/editor/tinymce/settings.php
lib/editor/tinymce/styles.css
lib/editor/tinymce/tiny_mce/3.5.8/themes/advanced/skins/moodle/img/button_bg.png
lib/editor/tinymce/tiny_mce/3.5.8/themes/advanced/skins/moodle/ui.css
lib/editor/tinymce/version.php
lib/editorlib.php
lib/filelib.php
lib/filestorage/mbz_packer.php
lib/filestorage/tests/file_storage_test.php
lib/filestorage/tests/mbz_packer_test.php
lib/filestorage/tests/tgz_packer_test.php
lib/filestorage/tgz_packer.php
lib/flickrlib.php
lib/form/form.js
lib/formslib.php
lib/google/Google_Client.php
lib/google/readme_moodle.txt
lib/grouplib.php
lib/ldaplib.php
lib/messagelib.php
lib/modinfolib.php
lib/moodlelib.php
lib/navigationlib.php
lib/oauthlib.php
lib/outputrenderers.php
lib/outputrequirementslib.php
lib/phpunit/classes/util.php
lib/setup.php
lib/setuplib.php
lib/tablelib.php
lib/testing/classes/util.php
lib/testing/generator/repository_generator.php
lib/tests/behat/behat_deprecated.php [new file with mode: 0644]
lib/tests/behat/behat_general.php
lib/tests/behat/behat_navigation.php
lib/tests/event_course_module_viewed.php [new file with mode: 0644]
lib/tests/filelib_test.php
lib/tests/fixtures/event_fixtures.php
lib/tests/grouplib_test.php
lib/tests/messagelib_test.php
lib/tests/minify_test.php
lib/tests/moodlelib_test.php
lib/tests/setuplib_test.php
lib/upgrade.txt
lib/upgradelib.php
lib/weblib.php
lib/yui/build/moodle-core-actionmenu/moodle-core-actionmenu-debug.js
lib/yui/build/moodle-core-actionmenu/moodle-core-actionmenu-min.js
lib/yui/build/moodle-core-actionmenu/moodle-core-actionmenu.js
lib/yui/build/moodle-core-dock-loader/moodle-core-dock-loader-debug.js
lib/yui/build/moodle-core-dock-loader/moodle-core-dock-loader-min.js
lib/yui/build/moodle-core-dock-loader/moodle-core-dock-loader.js
lib/yui/build/moodle-core-dock/moodle-core-dock-debug.js
lib/yui/build/moodle-core-dock/moodle-core-dock-min.js
lib/yui/build/moodle-core-dock/moodle-core-dock.js
lib/yui/build/moodle-core-maintenancemodetimer/moodle-core-maintenancemodetimer-debug.js [new file with mode: 0644]
lib/yui/build/moodle-core-maintenancemodetimer/moodle-core-maintenancemodetimer-min.js [new file with mode: 0644]
lib/yui/build/moodle-core-maintenancemodetimer/moodle-core-maintenancemodetimer.js [new file with mode: 0644]
lib/yui/dragdrop/dragdrop.js
lib/yui/src/actionmenu/js/actionmenu.js
lib/yui/src/dock/js/block.js
lib/yui/src/dock/js/loader.js
lib/yui/src/maintenancemodetimer/build.json [new file with mode: 0644]
lib/yui/src/maintenancemodetimer/js/maintenancemodetimer.js [new file with mode: 0644]
lib/yui/src/maintenancemodetimer/meta/maintenancemodetimer.json [new file with mode: 0644]
message/defaultoutputs.php
message/index.php
message/lib.php
message/module.js
message/output/email/db/upgrade.php
message/output/jabber/db/upgrade.php
message/output/popup/db/upgrade.php
message/renderer.php
message/tests/behat/block_users.feature
message/tests/behat/display_history.feature
message/tests/behat/manage_contacts.feature
message/tests/behat/search_history.feature
mod/assign/db/upgrade.php
mod/assign/feedback/comments/db/upgrade.php
mod/assign/feedback/comments/locallib.php
mod/assign/feedback/editpdf/classes/pdf.php
mod/assign/feedback/editpdf/db/install.php [new file with mode: 0644]
mod/assign/feedback/editpdf/db/install.xml
mod/assign/feedback/editpdf/db/upgrade.php [new file with mode: 0644]
mod/assign/feedback/editpdf/lang/en/assignfeedback_editpdf.php
mod/assign/feedback/editpdf/pix/cross.png [new file with mode: 0644]
mod/assign/feedback/editpdf/pix/sad.png [new file with mode: 0644]
mod/assign/feedback/editpdf/pix/smile.png [new file with mode: 0644]
mod/assign/feedback/editpdf/pix/tick.png [new file with mode: 0644]
mod/assign/feedback/editpdf/settings.php
mod/assign/feedback/editpdf/styles.css
mod/assign/feedback/editpdf/version.php
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotation.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotationhighlight.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotationline.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotationoval.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotationpen.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotationrectangle.js
mod/assign/feedback/editpdf/yui/src/editor/js/annotationstamp.js
mod/assign/feedback/editpdf/yui/src/editor/js/comment.js
mod/assign/feedback/editpdf/yui/src/editor/js/commentsearch.js
mod/assign/feedback/editpdf/yui/src/editor/js/dropdown.js
mod/assign/feedback/editpdf/yui/src/editor/js/editor.js
mod/assign/feedback/editpdf/yui/src/editor/js/rect.js
mod/assign/feedback/editpdf/yui/src/editor/js/stamppicker.js
mod/assign/feedback/file/db/upgrade.php
mod/assign/feedback/file/locallib.php
mod/assign/lang/en/assign.php
mod/assign/locallib.php
mod/assign/submission/comments/db/upgrade.php
mod/assign/submission/file/db/upgrade.php
mod/assign/submission/file/locallib.php
mod/assign/submission/onlinetext/db/upgrade.php
mod/assign/submission/onlinetext/locallib.php
mod/assignment/db/upgrade.php
mod/assignment/index.php
mod/book/classes/event/course_module_viewed.php
mod/book/db/upgrade.php
mod/book/index.php
mod/book/lang/en/book.php
mod/chat/chat_ajax.php
mod/chat/db/upgrade.php
mod/chat/gui_ajax/index.php
mod/chat/gui_ajax/module.js
mod/chat/gui_ajax/theme/bubble/chat.css
mod/chat/gui_ajax/theme/compact/chat.css
mod/chat/gui_ajax/theme/course_theme/config.php [new file with mode: 0644]
mod/chat/index.php
mod/chat/lang/en/chat.php
mod/choice/classes/event/course_module_viewed.php
mod/choice/db/upgrade.php
mod/choice/index.php
mod/choice/lang/en/choice.php
mod/choice/view.php
mod/data/db/upgrade.php
mod/data/index.php
mod/data/view.php
mod/feedback/classes/event/course_module_viewed.php
mod/feedback/db/upgrade.php
mod/feedback/index.php
mod/feedback/lang/en/feedback.php
mod/feedback/styles.css
mod/feedback/view.php
mod/folder/db/upgrade.php
mod/folder/index.php
mod/folder/renderer.php
mod/folder/tests/generator/lib.php [new file with mode: 0644]
mod/folder/tests/generator_test.php [new file with mode: 0644]
mod/forum/db/upgrade.php
mod/forum/lib.php
mod/forum/tests/behat/edit_post_student.feature
mod/glossary/db/upgrade.php
mod/glossary/index.php
mod/glossary/sql.php
mod/glossary/tests/behat/print_friendly_version.feature
mod/imscp/db/upgrade.php
mod/imscp/index.php
mod/imscp/lib.php
mod/imscp/tests/generator/lib.php [new file with mode: 0644]
mod/imscp/tests/generator_test.php [new file with mode: 0644]
mod/imscp/tests/packages/singlescobasic.zip [new file with mode: 0644]
mod/label/db/upgrade.php
mod/lesson/db/upgrade.php
mod/lesson/index.php
mod/lesson/lib.php
mod/lti/classes/plugininfo/ltisource.php [new file with mode: 0644]
mod/lti/db/subplugins.php [new file with mode: 0644]
mod/lti/db/upgrade.php
mod/lti/grade.php
mod/lti/index.php
mod/lti/lang/en/lti.php
mod/lti/lib.php
mod/lti/mod_form.php
mod/lti/request_tool.php
mod/lti/return.php
mod/lti/service.php
mod/lti/servicelib.php
mod/lti/source/readme.txt [new file with mode: 0644]
mod/lti/view.php
mod/page/classes/event/course_module_viewed.php
mod/page/db/upgrade.php
mod/page/index.php
mod/page/lang/en/page.php
mod/page/view.php
mod/quiz/addrandom.php
mod/quiz/attemptlib.php
mod/quiz/autosave.ajax.php
mod/quiz/comment.php
mod/quiz/db/log.php
mod/quiz/db/upgrade.php
mod/quiz/index.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/mod_form.php
mod/quiz/override_form.php
mod/quiz/overridedelete.php
mod/quiz/overrideedit.php
mod/quiz/overrides.php
mod/quiz/renderer.php
mod/quiz/report/attemptsreport_table.php
mod/quiz/report/default.php
mod/quiz/report/grading/gradingsettings_form.php
mod/quiz/report/grading/report.php
mod/quiz/report/overview/db/upgrade.php
mod/quiz/report/overview/report.php
mod/quiz/report/reportlib.php
mod/quiz/report/responses/responses_table.php
mod/quiz/report/statistics/classes/calculator.php
mod/quiz/report/statistics/db/upgrade.php
mod/quiz/report/statistics/report.php
mod/quiz/report/statistics/statistics_graph.php
mod/quiz/report/statistics/tests/stats_from_steps_walkthrough_test.php
mod/quiz/report/upgrade.txt
mod/quiz/reviewquestion.php
mod/quiz/startattempt.php
mod/quiz/styles.css
mod/quiz/upgrade.txt
mod/quiz/version.php
mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-debug.js
mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave-min.js
mod/quiz/yui/build/moodle-mod_quiz-autosave/moodle-mod_quiz-autosave.js
mod/quiz/yui/src/autosave/js/autosave.js
mod/resource/db/upgrade.php
mod/resource/lang/en/resource.php
mod/scorm/backup/moodle2/restore_scorm_stepslib.php
mod/scorm/datamodels/scorm_12.js.php
mod/scorm/db/upgrade.php
mod/scorm/index.php
mod/scorm/lib.php
mod/scorm/module.js
mod/scorm/report/basic/report.php
mod/scorm/report/interactions/report.php
mod/scorm/report/objectives/report.php
mod/scorm/tests/behat/add_scorm.feature
mod/scorm/tests/generator/lib.php [new file with mode: 0644]
mod/scorm/tests/generator_test.php [new file with mode: 0644]
mod/scorm/thirdpartylibs.xml [new file with mode: 0644]
mod/scorm/version.php
mod/scorm/view.js
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/moodle-mod_scorm-treeview-core.css [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/folder.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/folder@2x.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/item.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/item@2x.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/moodle-mod_scorm-treeview.css [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-debug.js [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-min.js [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable.js [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/moodle-mod_scorm-treeview-core.css [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/folder.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/folder@2x.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/item.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/item@2x.png [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/moodle-mod_scorm-treeview.css [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview-debug.js [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview-min.js [new file with mode: 0644]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview.js [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/moodle-mod_scorm-treeview-core.css [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/skins/sam/folder.png [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/skins/sam/folder@2x.png [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/skins/sam/item.png [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/skins/sam/item@2x.png [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [new file with mode: 0644]
mod/scorm/yui/src/treeview/assets/skins/sam/moodle-mod_scorm-treeview.css [new file with mode: 0644]
mod/scorm/yui/src/treeview/build.json [new file with mode: 0644]
mod/scorm/yui/src/treeview/js/gallery-sm-treeview-debug.js [new file with mode: 0644]
mod/scorm/yui/src/treeview/js/gallery-sm-treeview-sortable-debug.js [new file with mode: 0644]
mod/scorm/yui/src/treeview/js/treeview-sortable.js [new file with mode: 0644]
mod/scorm/yui/src/treeview/js/treeview.js [new file with mode: 0644]
mod/scorm/yui/src/treeview/meta/sm-treeview.json [new file with mode: 0644]
mod/scorm/yui/src/treeview/readme_moodle.txt [new file with mode: 0644]
mod/survey/db/upgrade.php
mod/survey/index.php
mod/survey/lang/en/survey.php
mod/url/db/upgrade.php
mod/url/index.php
mod/url/lang/en/url.php
mod/wiki/db/upgrade.php
mod/wiki/index.php
mod/wiki/tests/behat/page_history.feature
mod/workshop/allocation/random/lang/en/workshopallocation_random.php
mod/workshop/classes/event/course_module_viewed.php
mod/workshop/db/upgrade.php
mod/workshop/form/accumulative/db/upgrade.php
mod/workshop/form/comments/db/upgrade.php
mod/workshop/form/numerrors/db/upgrade.php
mod/workshop/form/rubric/db/upgrade.php
mod/workshop/index.php
mod/workshop/lang/en/workshop.php
mod/workshop/lib.php
mod/workshop/locallib.php
mod/workshop/renderer.php
mod/workshop/view.php
my/indexsys.php
portfolio/boxnet/db/upgrade.php [new file with mode: 0644]
portfolio/boxnet/db/upgradelib.php [new file with mode: 0644]
portfolio/boxnet/lang/en/portfolio_boxnet.php
portfolio/boxnet/lib.php
portfolio/boxnet/version.php
portfolio/flickr/lib.php
portfolio/googledocs/db/upgrade.php
portfolio/picasa/db/upgrade.php
question/behaviour/deferredcbm/behaviourtype.php
question/behaviour/deferredcbm/lang/en/qbehaviour_deferredcbm.php
question/behaviour/manualgraded/db/upgrade.php
question/classes/statistics/questions/calculator.php
question/classes/statistics/responses/analyser.php
question/editlib.php
question/engine/datalib.php
question/engine/lib.php
question/engine/renderer.php
question/engine/upgrade.txt
question/export_form.php
question/import_form.php
question/tests/behat/edit_questions.feature
question/tests/behat/preview_question.feature
question/type/calculated/db/upgrade.php
question/type/description/tests/walkthrough_test.php
question/type/essay/db/upgrade.php
question/type/essay/tests/helper.php
question/type/essay/tests/walkthrough_test.php
question/type/match/db/upgrade.php
question/type/multianswer/db/upgrade.php
question/type/multichoice/db/upgrade.php
question/type/multichoice/styles.css
question/type/numerical/db/upgrade.php
question/type/numerical/lang/en/qtype_numerical.php
question/type/random/lang/en/qtype_random.php
question/type/shortanswer/db/upgrade.php
question/type/shortanswer/question.php
question/type/shortanswer/tests/question_test.php
question/type/truefalse/tests/walkthrough_test.php
report/loglive/lib.php
report/security/locallib.php
repository/boxnet/cli/migrationv1.php [new file with mode: 0644]
repository/boxnet/db/upgrade.php [new file with mode: 0644]
repository/boxnet/db/upgradelib.php [new file with mode: 0644]
repository/boxnet/lang/en/repository_boxnet.php
repository/boxnet/lib.php
repository/boxnet/locallib.php [new file with mode: 0644]
repository/boxnet/migrationv1.php [new file with mode: 0644]
repository/boxnet/tests/generator/lib.php
repository/boxnet/version.php
repository/dropbox/db/upgrade.php
repository/dropbox/lib.php
repository/equella/lib.php
repository/googledocs/db/upgrade.php
repository/lib.php
repository/picasa/db/upgrade.php
repository/recent/lang/en/repository_recent.php
repository/skydrive/lib.php
repository/upgrade.txt
tag/manage.php
theme/afterburner/db/upgrade.php
theme/afterburner/lib.php
theme/anomaly/renderers.php
theme/base/style/admin.css
theme/base/style/core.css
theme/base/style/course.css
theme/base/style/dock.css
theme/base/style/filemanager.css
theme/base/style/question.css
theme/bootstrapbase/config.php
theme/bootstrapbase/layout/popup.php [new file with mode: 0644]
theme/bootstrapbase/less/editor.less
theme/bootstrapbase/less/moodle.less
theme/bootstrapbase/less/moodle/admin.less
theme/bootstrapbase/less/moodle/blocks.less
theme/bootstrapbase/less/moodle/chat.less [new file with mode: 0644]
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/course.less
theme/bootstrapbase/less/moodle/editor.less [new file with mode: 0644]
theme/bootstrapbase/less/moodle/filemanager.less
theme/bootstrapbase/less/moodle/forms.less
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/less/moodle/question.less
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/style/editor.css
theme/bootstrapbase/style/moodle.css
theme/brick/lib.php
theme/formal_white/db/upgrade.php
theme/magazine/lib.php
theme/yui_combo.php
user/editadvanced_form.php
user/editlib.php
user/profilesys.php
user/renderer.php
user/selector/module.js
user/tests/behat/edituserpassword.feature [new file with mode: 0644]
user/tests/editlib_test.php
version.php

index b453cc8..a394425 100644 (file)
@@ -1,4 +1,5 @@
 {
     "coverage": false,
-    "lint": "config"
+    "lint": "config",
+    "clean": true
 }
index 79c744c..375b3fa 100644 (file)
@@ -16,8 +16,6 @@ require_login();
 
 admin_externalpage_setup('ssoaccesscontrol');
 
-echo $OUTPUT->header();
-
 if (!extension_loaded('openssl')) {
     print_error('requiresopenssl', 'mnet');
 }
@@ -65,9 +63,11 @@ if (!empty($action) and confirm_sesskey()) {
 
             if (mnet_update_sso_access_control($idrec->username, $idrec->mnet_host_id, $accessctrl)) {
                 if ($accessctrl == 'allow') {
-                    redirect('access_control.php', get_string('ssl_acl_allow','mnet', array('uset'=>$idrec->username, 'host'=>$mnethosts[$idrec->mnet_host_id])));
-                } elseif ($accessctrl == 'deny') {
-                    redirect('access_control.php', get_string('ssl_acl_deny','mnet', array('user'=>$idrec->username, 'host'=>$mnethosts[$idrec->mnet_host_id])));
+                    redirect('access_control.php', get_string('ssl_acl_allow','mnet', array('user' => $idrec->username,
+                        'host' => $mnethosts[$idrec->mnet_host_id])));
+                } else if ($accessctrl == 'deny') {
+                    redirect('access_control.php', get_string('ssl_acl_deny','mnet', array('user' => $idrec->username,
+                        'host' => $mnethosts[$idrec->mnet_host_id])));
                 }
             }
             break;
@@ -118,6 +118,8 @@ if ($form = data_submitted() and confirm_sesskey()) {
     exit;
 }
 
+echo $OUTPUT->header();
+
 // Explain
 echo $OUTPUT->box(get_string('ssoacldescr','mnet'));
 // Are the needed bits enabled?
index 0f84e00..f86097b 100644 (file)
@@ -1176,13 +1176,14 @@ class core_admin_renderer extends plugin_renderer_base {
             get_string('displayname', 'core_plugin'),
             get_string('source', 'core_plugin'),
             get_string('version', 'core_plugin'),
+            get_string('release', 'core_plugin'),
             get_string('availability', 'core_plugin'),
             get_string('actions', 'core_plugin'),
             get_string('notes','core_plugin'),
         );
-        $table->headspan = array(1, 1, 1, 1, 2, 1);
+        $table->headspan = array(1, 1, 1, 1, 1, 2, 1);
         $table->colclasses = array(
-            'pluginname', 'source', 'version', 'availability', 'settings', 'uninstall', 'notes'
+            'pluginname', 'source', 'version', 'release', 'availability', 'settings', 'uninstall', 'notes'
         );
 
         foreach ($plugininfo as $type => $plugins) {
@@ -1238,6 +1239,7 @@ class core_admin_renderer extends plugin_renderer_base {
                 }
 
                 $version = new html_table_cell($plugin->versiondb);
+                $release = new html_table_cell($plugin->release);
 
                 $isenabled = $plugin->is_enabled();
                 if (is_null($isenabled)) {
@@ -1283,7 +1285,7 @@ class core_admin_renderer extends plugin_renderer_base {
                 $notes = new html_table_cell($requiredby.$updateinfo);
 
                 $row->cells = array(
-                    $pluginname, $source, $version, $availability, $settings, $uninstall, $notes
+                    $pluginname, $source, $version, $release, $availability, $settings, $uninstall, $notes
                 );
                 $table->data[] = $row;
             }
index 1ee3a7a..6505c96 100644 (file)
@@ -2,7 +2,12 @@
 
 // This file defines settingpages and externalpages under the "appearance" category
 
-if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
+$capabilities = array(
+    'moodle/my:configsyspages',
+    'moodle/tag:manage'
+);
+
+if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // speedup for non-admins, add all caps used on this page
 
     $ADMIN->add('appearance', new admin_category('themes', new lang_string('themes')));
     // "themesettings" settingpage
@@ -186,10 +191,12 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configcheckbox('doctonewwindow', new lang_string('doctonewwindow', 'admin'), new lang_string('configdoctonewwindow', 'admin'), 0));
     $ADMIN->add('appearance', $temp);
 
-    $temp = new admin_externalpage('mypage', new lang_string('mypage', 'admin'), $CFG->wwwroot . '/my/indexsys.php');
+    $temp = new admin_externalpage('mypage', new lang_string('mypage', 'admin'), $CFG->wwwroot . '/my/indexsys.php',
+            'moodle/my:configsyspages');
     $ADMIN->add('appearance', $temp);
 
-    $temp = new admin_externalpage('profilepage', new lang_string('myprofile', 'admin'), $CFG->wwwroot . '/user/profilesys.php');
+    $temp = new admin_externalpage('profilepage', new lang_string('myprofile', 'admin'), $CFG->wwwroot . '/user/profilesys.php',
+            'moodle/my:configsyspages');
     $ADMIN->add('appearance', $temp);
 
     // coursecontact is the person responsible for course - usually manages enrolments, receives notification, etc.
@@ -219,7 +226,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $ADMIN->add('appearance', $temp);
 
     // link to tag management interface
-    $ADMIN->add('appearance', new admin_externalpage('managetags', new lang_string('managetags', 'tag'), "$CFG->wwwroot/tag/manage.php"));
+    $ADMIN->add('appearance', new admin_externalpage('managetags', new lang_string('managetags', 'tag'), $CFG->wwwroot.'/tag/manage.php', 'moodle/tag:manage'));
 
     $temp = new admin_settingpage('additionalhtml', new lang_string('additionalhtml', 'admin'));
     $temp->add(new admin_setting_heading('additionalhtml_heading', new lang_string('additionalhtml_heading', 'admin'), new lang_string('additionalhtml_desc', 'admin')));
index b99d519..a1ad6e0 100644 (file)
@@ -27,6 +27,9 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configcheckbox('enabletgzbackups',
             new lang_string('enabletgzbackups', 'admin'),
             new lang_string('enabletgzbackups_desc', 'admin'), 0));
+    $temp->add(new admin_setting_php_extension_enabled('zlibenabled',
+            get_string('zlibenabled', 'admin'),
+            get_string('enabletgzbackups_nozlib', 'admin'), 'zlib'));
 
     $ADMIN->add('experimental', $temp);
 
index 63d39ab..283d02a 100644 (file)
@@ -256,7 +256,10 @@ if ($hassiteconfig) {
 
     // Add common settings page
     $temp = new admin_settingpage('managerepositoriescommon', new lang_string('commonrepositorysettings', 'repository'));
-    $temp->add(new admin_setting_configtext('repositorycacheexpire', new lang_string('cacheexpire', 'repository'), new lang_string('configcacheexpire', 'repository'), 120));
+    $temp->add(new admin_setting_configtext('repositorycacheexpire', new lang_string('cacheexpire', 'repository'), new lang_string('configcacheexpire', 'repository'), 120, PARAM_INT));
+    $temp->add(new admin_setting_configtext('repositorygetfiletimeout', new lang_string('getfiletimeout', 'repository'), new lang_string('configgetfiletimeout', 'repository'), 30, PARAM_INT));
+    $temp->add(new admin_setting_configtext('repositorysyncfiletimeout', new lang_string('syncfiletimeout', 'repository'), new lang_string('configsyncfiletimeout', 'repository'), 1, PARAM_INT));
+    $temp->add(new admin_setting_configtext('repositorysyncimagetimeout', new lang_string('syncimagetimeout', 'repository'), new lang_string('configsyncimagetimeout', 'repository'), 3, PARAM_INT));
     $temp->add(new admin_setting_configcheckbox('repositoryallowexternallinks', new lang_string('allowexternallinks', 'repository'), new lang_string('configallowexternallinks', 'repository'), 1));
     $temp->add(new admin_setting_configcheckbox('legacyfilesinnewcourses', new lang_string('legacyfilesinnewcourses', 'admin'), new lang_string('legacyfilesinnewcourses_help', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('legacyfilesaddallowed', new lang_string('legacyfilesaddallowed', 'admin'), new lang_string('legacyfilesaddallowed_help', 'admin'), 1));
@@ -485,6 +488,16 @@ if ($hassiteconfig) {
     }
 }
 
+// Add Calendar type settings.
+if ($hassiteconfig) {
+    $ADMIN->add('modules', new admin_category('calendartype', new lang_string('calendartypes', 'calendar')));
+    foreach (core_component::get_plugin_list_with_file('calendartype', 'settings.php') as $plugin => $settingspath) {
+        $settings = new admin_settingpage('calendartype_' . $plugin . '_settings', new lang_string('pluginname', 'calendartype_' . $plugin), 'moodle/site:config');
+        include($settingspath);
+        $ADMIN->add('calendartype', $settings);
+    }
+}
+
 /// Add all local plugins - must be always last!
 if ($hassiteconfig) {
     $ADMIN->add('modules', new admin_category('localplugins', new lang_string('localplugins')));
index 10d39eb..13d5f2f 100644 (file)
@@ -125,23 +125,4 @@ class behat_admin extends behat_base {
             $this->getSession()->wait($timeout, $javascript);
         }
     }
-
-    /**
-     * Goes to notification page ensuring site admin navigation is loaded.
-     *
-     * @Given /^I go to notifications page$/
-     * @return Given[]
-     */
-    public function i_go_to_notifications_page() {
-        if ($this->running_javascript()) {
-            return array(
-                new Given('I expand "' . get_string('administrationsite') . '" node'),
-                new Given('I follow "' . get_string('notifications') . '"')
-            );
-        } else {
-            return array(
-                new Given('I follow "' . get_string('administrationsite') . '"')
-            );
-        }
-    }
 }
index 86231b2..76cfda0 100644 (file)
@@ -15,7 +15,8 @@ Feature: Display extended course names
     And I should not see "C_shortname Course fullname"
 
   Scenario: Courses list with extended course names
-    Given I go to notifications page
+    Given I expand "Site administration" node
+    And I expand "Appearance" node
     And I click on "Courses" "link" in the "//div[@id='settingsnav']/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' type_setting ')][contains(., 'Appearance')]" "xpath_element"
     And I check "Display extended course names"
     When I press "Save changes"
index 287a535..28c933a 100644 (file)
@@ -93,21 +93,17 @@ ini_set('log_errors', '1');
 // Getting $CFG data.
 require_once(__DIR__ . '/../../../../config.php');
 
-// CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
-if (empty($CFG->behat_prefix) ||
-       ($CFG->behat_prefix == $CFG->prefix) ||
-       (!empty($CFG->phpunit_prefix) && $CFG->behat_prefix == $CFG->phpunit_prefix)) {
-    behat_error(BEHAT_EXITCODE_CONFIG,
-        'Define $CFG->behat_prefix in config.php with a value different than $CFG->prefix and $CFG->phpunit_prefix');
-}
-
-// CFG->behat_dataroot must be set and with value different than CFG->dataroot and phpunit_dataroot.
-if (empty($CFG->behat_dataroot) ||
-       ($CFG->behat_dataroot == $CFG->dataroot) ||
-       (!empty($CFG->phpunit_dataroot) && $CFG->behat_dataroot == $CFG->phpunit_dataroot)) {
-    behat_error(BEHAT_EXITCODE_CONFIG,
-        'Define $CFG->behat_dataroot in config.php with a value different than $CFG->dataroot and $CFG->phpunit_dataroot');
-}
+// When we use the utilities we don't know how the site
+// will be accessed, so if neither $CFG->behat_switchcompletely or
+// $CFG->behat_wwwroot are set we must think that the site will
+// be accessed using the built-in server which is set by default
+// to localhost:8000. We need to do this to prevent uses of the production
+// wwwroot when the site is being installed / dropped...
+$CFG->behat_wwwroot = behat_get_wwwroot();
+
+// Checking the integrity of the provided $CFG->behat_* vars
+// to prevent conflicts with production and phpunit environments.
+behat_check_config_vars();
 
 // Create behat_dataroot if it doesn't exists.
 if (!file_exists($CFG->behat_dataroot)) {
index a67581d..d8b2b51 100644 (file)
@@ -38,7 +38,7 @@ $string['stepsdefinitionscontains'] = 'Contains';
 $string['stepsdefinitionsfilters'] = 'Steps definitions';
 $string['stepsdefinitionstype'] = 'Type';
 $string['theninfo'] = 'Then. Checkings to ensure the outcomes are the expected ones';
-$string['unknownexceptioninfo'] = 'There was a problem with Selenium or the browser, try to upgrade Selenium to the latest version. Error: ';
+$string['unknownexceptioninfo'] = 'There was a problem with Selenium or your browser. Please ensure you are using the latest version of Selenium. Error:';
 $string['viewsteps'] = 'Filter';
 $string['wheninfo'] = 'When. Actions that provokes an event';
 $string['wrongbehatsetup'] = 'Something is wrong with behat setup, ensure:<ul>
index c5dc276..5b1bd50 100644 (file)
@@ -18,7 +18,7 @@ Feature: Page contents assertions
     When I follow "Overview"
     And I wait until the page is ready
     And I wait "2" seconds
-    And I hover ".region-content .generaltable td span" "css_element"
+    And I hover "#region-main .generaltable td span" "css_element"
     Then I should see "I'm the description"
     And "Grouping" "select" in the "region-main" "region" should be visible
     And "Group" "select" should be visible
@@ -26,8 +26,8 @@ Feature: Page contents assertions
     And "Change password" "link" should not be visible
     And I should see "Filter groups by"
     And I should not see "Filter groupssss by"
-    And I should see "Group members" in the ".region-content table th.c1" "css_element"
-    And I should not see "Group membersssss" in the ".region-content table th.c1" "css_element"
+    And I should see "Group members" in the "#region-main table th.c1" "css_element"
+    And I should not see "Group membersssss" in the "#region-main table th.c1" "css_element"
     And I follow "Groups"
     And the "#groupeditform #showcreateorphangroupform" "css_element" should be enabled
     And the "#groupeditform #showeditgroupsettingsform" "css_element" should be disabled
index 45d1ed6..063e198 100644 (file)
@@ -1,4 +1,4 @@
-@tool @tool_behat
+@tool @tool_behat @_only_local
 Feature: Set up contextual data for tests
   In order to write tests quickly
   As a developer
@@ -143,13 +143,56 @@ Feature: Set up contextual data for tests
       | fullname | shortname |
       | Course 1 | C1 |
     And the following "activities" exists:
-      | activity | name | intro | course | idnumber |
-      | assign   | Test assignment name | Test assignment description | C1 | assign1 |
-      | data     | Test database name | Test database description | C1 | data1 |
+      | activity   | name                   | intro                         | course | idnumber    |
+      | assign     | Test assignment name   | Test assignment description   | C1     | assign1     |
+      | assignment | Test assignment22 name | Test assignment22 description | C1     | assignment1 |
+      | book       | Test book name         | Test book description         | C1     | book1       |
+      | chat       | Test chat name         | Test chat description         | C1     | chat1       |
+      | choice     | Test choice name       | Test choice description       | C1     | choice1     |
+      | data       | Test database name     | Test database description     | C1     | data1       |
+      | feedback   | Test feedback name     | Test feedback description     | C1     | feedback1   |
+      | folder     | Test folder name       | Test folder description       | C1     | folder1     |
+      | forum      | Test forum name        | Test forum description        | C1     | forum1      |
+      | glossary   | Test glossary name     | Test glossary description     | C1     | glossary1   |
+      | imscp      | Test imscp name        | Test imscp description        | C1     | imscp1      |
+      | label      | Test label name        | Test label description        | C1     | label1      |
+      | lesson     | Test lesson name       | Test lesson description       | C1     | lesson1     |
+      | lti        | Test lti name          | Test lti description          | C1     | lti1        |
+      | page       | Test page name         | Test page description         | C1     | page1       |
+      | quiz       | Test quiz name         | Test quiz description         | C1     | quiz1       |
+      | resource   | Test resource name     | Test resource description     | C1     | resource1   |
+      | scorm      | Test scorm name        | Test scorm description        | C1     | scorm1      |
+      | survey     | Test survey name       | Test survey description       | C1     | survey1     |
+      | url        | Test url name          | Test url description          | C1     | url1        |
+      | wiki       | Test wiki name         | Test wiki description         | C1     | wiki1       |
+      | workshop   | Test workshop name     | Test workshop description     | C1     | workshop1   |
     When I log in as "admin"
     And I follow "Course 1"
     Then I should see "Test assignment name"
+    # Assignment 2.2 module type is disabled by default
+    # And I should see "Test assignment22 name"
+    And I should see "Test book name"
+    And I should see "Test chat name"
+    And I should see "Test choice name"
     And I should see "Test database name"
+    # Feedback module type is disabled by default
+    # And I should see "Test feedback name"
+    And I should see "Test folder name"
+    And I should see "Test forum name"
+    And I should see "Test glossary name"
+    And I should see "Test imscp name"
+    # We don't see label name, we see only description:
+    And I should see "Test label description"
+    And I should see "Test lesson name"
+    And I should see "Test lti name"
+    And I should see "Test page name"
+    And I should see "Test quiz name"
+    And I should see "Test resource name"
+    And I should see "Test scorm name"
+    And I should see "Test survey name"
+    And I should see "Test url name"
+    And I should see "Test wiki name"
+    And I should see "Test workshop name"
     And I follow "Test assignment name"
     And I should see "Test assignment description"
 
index 9aa1c88..664bbd6 100644 (file)
@@ -32,5 +32,5 @@ Feature: Forms manipulation
     Then I should see "Close the quiz"
     And I should see "Group mode"
     And I should see "Grouping"
-    And I should not see "Show more..." in the "region-main-box" "region"
+    And I should not see "Show more..." in the "region-main" "region"
     And I should see "Show less..."
index b750aa7..12b96cd 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2013110500;
+$plugin->version   = 2013110501;
 $plugin->requires  = 2013110500; // Requires Moodle 2.5.
 $plugin->component = 'tool_behat';
index 08cd8b3..b27a7ce 100644 (file)
@@ -74,9 +74,15 @@ function tool_capability_calculate_role_data($capability, array $roles) {
     // Put the contexts into a tree structure.
     foreach ($contexts as $conid => $con) {
         $context = context::instance_by_id($conid);
-        $parentcontext = $context->get_parent_context();
-        if ($parentcontext) {
-            $contexts[$parentcontext->id]->children[] = $conid;
+        try {
+            $parentcontext = $context->get_parent_context();
+            if ($parentcontext) { // Will be false if $context is the system context.
+                $contexts[$parentcontext->id]->children[] = $conid;
+            }
+        } catch (dml_missing_record_exception $e) {
+            // Ignore corrupt context tree structure here. Don't let it break
+            // showing the rest of the report.
+            continue;
         }
     }
 
index 586725a..dde7c3e 100644 (file)
@@ -87,7 +87,7 @@ class tool_capability_renderer extends plugin_renderer_base {
         $table->attributes['class'] = 'comparisontable';
         $table->head = array('&nbsp;');
         foreach ($roles as $role) {
-            $url = new moodle_url('/admin/roles/override.php', array('contextid' => $contextid, 'roleid' => $role->id));
+            $url = new moodle_url('/admin/roles/define.php', array('action' => 'view', 'roleid' => $role->id));
             $table->head[] = html_writer::div(html_writer::link($url, $role->localname));
         }
         $table->data = array();
index 63d8fb1..4832c0f 100644 (file)
@@ -42,5 +42,8 @@ function xmldb_tool_customlang_upgrade($oldversion) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index 8d28bbc..ccd8cfb 100644 (file)
             <stringProp name="HTTPSampler.contentEncoding"></stringProp>
             <stringProp name="HTTPSampler.path">${sitepath}/mod/forum/post.php</stringProp>
             <stringProp name="HTTPSampler.method">POST</stringProp>
-            <boolProp name="HTTPSampler.follow_redirects">true</boolProp>
+            <boolProp name="HTTPSampler.follow_redirects">false</boolProp>
             <boolProp name="HTTPSampler.auto_redirects">false</boolProp>
             <boolProp name="HTTPSampler.use_keepalive">true</boolProp>
             <boolProp name="HTTPSampler.DO_MULTIPART_POST">false</boolProp>
index 87dee88..d31ec68 100644 (file)
@@ -38,7 +38,7 @@ $string['nolangupdateneeded'] = 'All your language packs are up to date, no upda
 $string['pluginname'] = 'Language packs';
 $string['purgestringcaches'] = 'Purge string caches';
 $string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="http://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
-$string['uninstall'] = 'Uninstall selected language pack(s)';
+$string['uninstall'] = 'Uninstall selected language pack';
 $string['uninstallconfirm'] = 'You are about to completely uninstall language pack {$a}, are you sure?';
 $string['updatelangs'] = 'Update all installed language packs';
 
index 0835270..7ae6017 100644 (file)
@@ -178,13 +178,47 @@ function search_spammers($keywords) {
     $conditions6 = '( '.implode(' OR ', $keywordfull6).' )';
     $conditions7 = '( '.implode(' OR ', $keywordfull7).' )';
 
-    $sql  = "SELECT * FROM {user} WHERE deleted = 0 AND id <> :userid AND $conditions";  // Exclude oneself
-    $sql2 = "SELECT u.*, p.summary FROM {user} AS u, {post} AS p WHERE $conditions2 AND u.deleted = 0 AND u.id=p.userid AND u.id <> :userid";
-    $sql3 = "SELECT u.*, p.subject as postsubject FROM {user} AS u, {post} AS p WHERE $conditions3 AND u.deleted = 0 AND u.id=p.userid AND u.id <> :userid";
-    $sql4 = "SELECT u.*, c.content FROM {user} AS u, {comments} AS c WHERE $conditions4 AND u.deleted = 0 AND u.id=c.userid AND u.id <> :userid";
-    $sql5 = "SELECT u.*, m.fullmessage FROM {user} AS u, {message} AS m WHERE $conditions5 AND u.deleted = 0 AND u.id=m.useridfrom AND u.id <> :userid";
-    $sql6 = "SELECT u.*, fp.message FROM {user} AS u, {forum_posts} AS fp WHERE $conditions6 AND u.deleted = 0 AND u.id=fp.userid AND u.id <> :userid";
-    $sql7 = "SELECT u.*, fp.subject FROM {user} AS u, {forum_posts} AS fp WHERE $conditions7 AND u.deleted = 0 AND u.id=fp.userid AND u.id <> :userid";
+    $sql  = "SELECT *
+               FROM {user}
+              WHERE deleted = 0
+                    AND id <> :userid
+                    AND $conditions";  // Exclude oneself
+    $sql2 = "SELECT u.*, p.summary
+               FROM {user} u, {post} p
+              WHERE $conditions2
+                    AND u.deleted = 0
+                    AND u.id=p.userid
+                    AND u.id <> :userid";
+    $sql3 = "SELECT u.*, p.subject AS postsubject
+               FROM {user} u, {post} p
+              WHERE $conditions3
+                    AND u.deleted = 0
+                    AND u.id=p.userid
+                    AND u.id <> :userid";
+    $sql4 = "SELECT u.*, c.content
+               FROM {user} u, {comments} c
+               WHERE $conditions4
+                    AND u.deleted = 0
+                    AND u.id=c.userid
+                    AND u.id <> :userid";
+    $sql5 = "SELECT u.*, m.fullmessage
+               FROM {user} u, {message} m
+              WHERE $conditions5
+                    AND u.deleted = 0
+                    AND u.id=m.useridfrom
+                    AND u.id <> :userid";
+    $sql6 = "SELECT u.*, fp.message
+               FROM {user} u, {forum_posts} fp
+              WHERE $conditions6
+                    AND u.deleted = 0
+                    AND u.id=fp.userid
+                    AND u.id <> :userid";
+    $sql7 = "SELECT u.*, fp.subject
+               FROM {user} u, {forum_posts} fp
+              WHERE $conditions7
+                    AND u.deleted = 0
+                    AND u.id=fp.userid
+                    AND u.id <> :userid";
 
     $spamusers_desc = $DB->get_recordset_sql($sql, $params);
     $spamusers_blog = $DB->get_recordset_sql($sql2, $params);
index fc0ddf9..868fe6a 100644 (file)
@@ -61,6 +61,7 @@ class tool_uploadcourse_base_form extends moodleform {
             tool_uploadcourse_processor::MODE_UPDATE_ONLY => get_string('updateonly', 'tool_uploadcourse')
         );
         $mform->addElement('select', 'options[mode]', get_string('mode', 'tool_uploadcourse'), $choices);
+        $mform->addHelpButton('options[mode]', 'mode', 'tool_uploadcourse');
 
         $choices = array(
             tool_uploadcourse_processor::UPDATE_NOTHING => get_string('nochanges', 'tool_uploadcourse'),
@@ -73,21 +74,25 @@ class tool_uploadcourse_base_form extends moodleform {
         $mform->setDefault('options[updatemode]', tool_uploadcourse_processor::UPDATE_NOTHING);
         $mform->disabledIf('options[updatemode]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
         $mform->disabledIf('options[updatemode]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
+        $mform->addHelpButton('options[updatemode]', 'updatemode', 'tool_uploadcourse');
 
         $mform->addElement('selectyesno', 'options[allowdeletes]', get_string('allowdeletes', 'tool_uploadcourse'));
         $mform->setDefault('options[allowdeletes]', 0);
         $mform->disabledIf('options[allowdeletes]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
         $mform->disabledIf('options[allowdeletes]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
+        $mform->addHelpButton('options[allowdeletes]', 'allowdeletes', 'tool_uploadcourse');
 
         $mform->addElement('selectyesno', 'options[allowrenames]', get_string('allowrenames', 'tool_uploadcourse'));
         $mform->setDefault('options[allowrenames]', 0);
         $mform->disabledIf('options[allowrenames]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
         $mform->disabledIf('options[allowrenames]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
+        $mform->addHelpButton('options[allowrenames]', 'allowrenames', 'tool_uploadcourse');
 
         $mform->addElement('selectyesno', 'options[allowresets]', get_string('allowresets', 'tool_uploadcourse'));
         $mform->setDefault('options[allowresets]', 0);
         $mform->disabledIf('options[allowresets]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
         $mform->disabledIf('options[allowresets]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
+        $mform->addHelpButton('options[allowresets]', 'allowresets', 'tool_uploadcourse');
     }
 
 }
index 189ff9e..4d0543b 100644 (file)
@@ -44,8 +44,9 @@ class tool_uploadcourse_step1_form extends tool_uploadcourse_base_form {
 
         $mform->addElement('header', 'generalhdr', get_string('general'));
 
-        $mform->addElement('filepicker', 'coursefile', get_string('file'));
+        $mform->addElement('filepicker', 'coursefile', get_string('coursefile', 'tool_uploadcourse'));
         $mform->addRule('coursefile', null, 'required');
+        $mform->addHelpButton('coursefile', 'coursefile', 'tool_uploadcourse');
 
         $choices = csv_import_reader::get_delimiter_list();
         $mform->addElement('select', 'delimiter_name', get_string('csvdelimiter', 'tool_uploadcourse'), $choices);
@@ -56,14 +57,17 @@ class tool_uploadcourse_step1_form extends tool_uploadcourse_base_form {
         } else {
             $mform->setDefault('delimiter_name', 'comma');
         }
+        $mform->addHelpButton('delimiter_name', 'csvdelimiter', 'tool_uploadcourse');
 
         $choices = core_text::get_encodings();
         $mform->addElement('select', 'encoding', get_string('encoding', 'tool_uploadcourse'), $choices);
         $mform->setDefault('encoding', 'UTF-8');
+        $mform->addHelpButton('encoding', 'encoding', 'tool_uploadcourse');
 
         $choices = array('10' => 10, '20' => 20, '100' => 100, '1000' => 1000, '100000' => 100000);
         $mform->addElement('select', 'previewrows', get_string('rowpreviewnum', 'tool_uploadcourse'), $choices);
         $mform->setType('previewrows', PARAM_INT);
+        $mform->addHelpButton('previewrows', 'rowpreviewnum', 'tool_uploadcourse');
 
         $this->add_import_options();
 
index 32886ef..24f9a9e 100644 (file)
@@ -74,6 +74,7 @@ class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
         $mform->disabledIf('options[reset]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_NEW);
         $mform->disabledIf('options[reset]', 'options[mode]', 'eq', tool_uploadcourse_processor::MODE_CREATE_ALL);
         $mform->disabledIf('options[reset]', 'options[allowresets]', 'eq', 0);
+        $mform->addHelpButton('options[reset]', 'reset', 'tool_uploadcourse');
 
         // Default values.
         $mform->addElement('header', 'defaultheader', get_string('defaultvalues', 'tool_uploadcourse'));
index 999ca70..96b847c 100644 (file)
  */
 
 $string['allowdeletes'] = 'Allow deletes';
+$string['allowdeletes_help'] = 'Whether the delete field is accepted or not.';
 $string['allowrenames'] = 'Allow renames';
+$string['allowrenames_help'] = 'Whether the rename field is accepted or not.';
 $string['allowresets'] = 'Allow resets';
+$string['allowresets_help'] = 'Whether the reset field is accepted or not.';
 $string['cachedef_helper'] = 'Helper caching';
 $string['cannotdeletecoursenotexist'] = 'Cannot delete a course that does not exist';
 $string['cannotgenerateshortnameupdatemode'] = 'Cannot generate a shortname when updates are allowed';
@@ -43,6 +46,8 @@ $string['coursedeleted'] = 'Course deleted';
 $string['coursedeletionnotallowed'] = 'Course deletion is not allowed';
 $string['coursedoesnotexistandcreatenotallowed'] = 'The course does not exist and creating course is not allowed';
 $string['courseexistsanduploadnotallowed'] = 'The course exists and update is not allowed';
+$string['coursefile'] = 'File';
+$string['coursefile_help'] = 'This file must be a CSV file.';
 $string['courseidnumberincremented'] = 'Course ID number incremented {$a->from} -> {$a->to}';
 $string['courseprocess'] = 'Course process';
 $string['courserenamed'] = 'Course renamed';
@@ -65,10 +70,12 @@ $string['createall'] = 'Create all, increment shortname if needed';
 $string['createnew'] = 'Create new courses only, skip existing ones';
 $string['createorupdate'] = 'Create new courses, or update existing ones';
 $string['csvdelimiter'] = 'CSV delimiter';
+$string['csvdelimiter_help'] = 'CSV delimiter of the CSV file.';
 $string['csvfileerror'] = 'There is something wrong with the format of the CSV file. Please check the number of headings and columns match, and that the delimiter and file encoding are correct: {$a}';
 $string['csvline'] = 'Line';
 $string['defaultvalues'] = 'Default course values';
 $string['encoding'] = 'Encoding';
+$string['encoding_help'] = 'Encoding of the CSV file.';
 $string['errorwhilerestoringcourse'] = 'Error while restoring the course';
 $string['errorwhiledeletingcourse'] = 'Error while deleting the course';
 $string['generatedshortnameinvalid'] = 'The generated shortname is invalid';
@@ -87,13 +94,17 @@ $string['invalidshortname'] = 'Invalid shortname';
 $string['missingmandatoryfields'] = 'Missing value for mandatory fields: {$a}';
 $string['missingshortnamenotemplate'] = 'Missing shortname and shortname template not set';
 $string['mode'] = 'Upload mode';
+$string['mode_help'] = 'This allows you to specify if courses can be created and/or updated.';
 $string['nochanges'] = 'No changes';
 $string['pluginname'] = 'Course upload';
 $string['preview'] = 'Preview';
 $string['reset'] = 'Reset course after upload';
+$string['reset_help'] = 'Whether to reset the course after creating/updating it.';
 $string['result'] = 'Result';
 $string['restoreafterimport'] = 'Restore after import';
 $string['rowpreviewnum'] = 'Preview rows';
+$string['rowpreviewnum_help'] = 'Number of rows from the CSV file that will be previewed in the next page. This option exists in
+order to limit the next page size.';
 $string['shortnametemplate'] = 'Template to generate a shortname';
 $string['shortnametemplate_help'] = 'The short name of the course is displayed in the navigation. You may use template syntax here (%f = fullname, %i = idnumber), or enter an initial value that is incremented.';
 $string['templatefile'] = 'Restore from this file after upload';
@@ -101,6 +112,7 @@ $string['templatefile_help'] = 'Select a file to use as a template for the creat
 $string['unknownimportmode'] = 'Unknown import mode';
 $string['updatemissing'] = 'Fill in missing items from CSV data and defaults';
 $string['updatemode'] = 'Update mode';
+$string['updatemode_help'] = 'If you allow courses to be updated, you also have to tell the tool what to update the courses with.';
 $string['updatemodedoessettonothing'] = 'Update mode does not allow anything to be updated';
 $string['updateonly'] = 'Only update existing courses';
 $string['updatewithdataordefaults'] = 'Update with CSV data and defaults';
@@ -111,6 +123,6 @@ $string['uploadcourses_help'] = 'Courses may be uploaded via text file. The form
 * Each line of the file contains one record
 * Each record is a series of data separated by commas (or other delimiters)
 * The first record contains a list of fieldnames defining the format of the rest of the file
-* Required fieldnames are shortname, fullname, summary and category';
+* Required fieldnames are shortname, fullname, and category';
 $string['uploadcoursespreview'] = 'Upload courses preview';
 $string['uploadcoursesresult'] = 'Upload courses results';
index 4480278..a45cb47 100644 (file)
@@ -123,12 +123,11 @@ if (empty($iid)) {
         $content = $mform1->get_file_content('userfile');
 
         $readcount = $cir->load_csv_content($content, $formdata->encoding, $formdata->delimiter_name);
+        $csvloaderror = $cir->get_error();
         unset($content);
 
-        if ($readcount === false) {
-            print_error('csvloaderror', '', $returnurl);
-        } else if ($readcount == 0) {
-            print_error('csvemptyfile', 'error', $returnurl);
+        if (!is_null($csvloaderror)) {
+            print_error('csvloaderror', '', $returnurl, $csvloaderror);
         }
         // test if columns ok
         $filecolumns = uu_validate_user_upload_columns($cir, $STD_FIELDS, $PRF_FIELDS, $returnurl);
@@ -235,10 +234,10 @@ if ($formdata = $mform2->is_cancelled()) {
                     $user->$key['text']   = $value;
                     $user->$key['format'] = FORMAT_MOODLE;
                 } else {
-                    $user->$key = $value;
+                    $user->$key = trim($value);
                 }
             } else {
-                $user->$key = $value;
+                $user->$key = trim($value);
             }
 
             if (in_array($key, $upt->columns)) {
@@ -550,8 +549,6 @@ if ($formdata = $mform2->is_cancelled()) {
                         continue;
                     }
                     if (!property_exists($user, $column) or !property_exists($existinguser, $column)) {
-                        // this should never happen
-                        debugging("Could not find $column on the user objects", DEBUG_DEVELOPER);
                         continue;
                     }
                     if ($updatetype == UU_UPDATE_MISSING) {
@@ -966,7 +963,7 @@ if ($formdata = $mform2->is_cancelled()) {
                     $status = null;
 
                     if (isset($user->{'enrolstatus'.$i})) {
-                        $enrolstatus = trim($user->{'enrolstatus'.$i});
+                        $enrolstatus = $user->{'enrolstatus'.$i};
                         if ($enrolstatus == '') {
                             $status = null;
                         } else if ($enrolstatus === (string)ENROL_USER_ACTIVE) {
@@ -1109,7 +1106,7 @@ while ($linenum <= $previewrows and $fields = $cir->next()) {
     $rowcols = array();
     $rowcols['line'] = $linenum;
     foreach($fields as $key => $field) {
-        $rowcols[$filecolumns[$key]] = s($field);
+        $rowcols[$filecolumns[$key]] = s(trim($field));
     }
     $rowcols['status'] = array();
 
@@ -1135,7 +1132,7 @@ while ($linenum <= $previewrows and $fields = $cir->next()) {
     }
 
     if (isset($rowcols['city'])) {
-        $rowcols['city'] = trim($rowcols['city']);
+        $rowcols['city'] = $rowcols['city'];
     }
     // Check if rowcols have custom profile field with correct data and update error state.
     $noerror = uu_check_custom_profile_data($rowcols) && $noerror;
index 67e886f..128b502 100644 (file)
@@ -53,6 +53,8 @@ class check_foreign_keys extends XMLDBCheckAction {
             'noviolatedforeignkeysfound' => 'tool_xmldb',
             'violatedforeignkeysfound' => 'tool_xmldb',
             'violations' => 'tool_xmldb',
+            'unknowntable' => 'tool_xmldb',
+            'unknownfield' => 'tool_xmldb',
         ));
     }
 
@@ -75,6 +77,19 @@ class check_foreign_keys extends XMLDBCheckAction {
                 }
                 $o.='            <li>' . $this->str['key'] . ': ' . $xmldb_key->readableInfo() . ' ';
 
+                $reftable = $xmldb_key->getRefTable();
+                if (!$dbman->table_exists($reftable)) {
+                    $o.='<font color="red">' . $this->str['unknowntable'] . '</font>';
+                    // Add the missing index to the list
+                    $violation = new stdClass();
+                    $violation->string = 'fkunknowntable';
+                    $violation->table = $xmldb_table;
+                    $violation->key = $xmldb_key;
+                    $violation->reftable = $reftable;
+                    $violatedkeys[] = $violation;
+                    continue;
+                }
+
                 // Work out the SQL to find key violations.
                 $keyfields = $xmldb_key->getFields();
                 $reffields = $xmldb_key->getRefFields();
@@ -82,6 +97,19 @@ class check_foreign_keys extends XMLDBCheckAction {
                 $nullnessconditions = array();
                 $params = array();
                 foreach ($keyfields as $i => $field) {
+                    if (!$dbman->field_exists($reftable, $reffields[$i])) {
+                        $o.='<font color="red">' . $this->str['unknownfield'] . '</font>';
+                        // Add the missing index to the list
+                        $violation = new stdClass();
+                        $violation->string = 'fkunknownfield';
+                        $violation->table = $xmldb_table;
+                        $violation->key = $xmldb_key;
+                        $violation->reftable = $reftable;
+                        $violation->reffield = $reffields[$i];
+                        $violatedkeys[] = $violation;
+                        continue 2;
+                    }
+
                     $joinconditions[] = 't1.' . $field . ' = t2.' . $reffields[$i];
                     $xmldb_field = $xmldb_table->getField($field);
                     $default = $xmldb_field->getDefault();
@@ -97,7 +125,7 @@ class check_foreign_keys extends XMLDBCheckAction {
                 }
                 $nullnessconditions[] = 't2.id IS NULL';
                 $sql = 'SELECT count(1) FROM {' . $xmldb_table->getName() .
-                        '} t1 LEFT JOIN {' . $xmldb_key->getRefTable() . '} t2 ON ' .
+                        '} t1 LEFT JOIN {' . $reftable . '} t2 ON ' .
                         implode(' AND ', $joinconditions) . ' WHERE ' .
                         implode(' AND ', $nullnessconditions);
 
@@ -109,6 +137,7 @@ class check_foreign_keys extends XMLDBCheckAction {
                     $o.='<font color="red">' . $this->str['violations'] . '</font>';
                     // Add the missing index to the list
                     $violation = new stdClass;
+                    $violation->string = 'fkviolationdetails';
                     $violation->table = $xmldb_table;
                     $violation->key = $xmldb_key;
                     $violation->numviolations = $violations;
@@ -145,8 +174,11 @@ class check_foreign_keys extends XMLDBCheckAction {
                 $violation->tablename = $violation->table->getName();
                 $violation->keyname = $violation->key->getName();
 
-                $r.= '            <li>' .get_string('fkviolationdetails', 'tool_xmldb', $violation) .
-                        '<pre>' . s($violation->sql) . '; ' . s($violation->sqlparams) . '</pre></li>';
+                $r.= '            <li>' .get_string($violation->string, 'tool_xmldb', $violation);
+                if (!empty($violation->sql)) {
+                    $r.= '<pre>' . s($violation->sql) . '; ' . s($violation->sqlparams) . '</pre>';
+                }
+                $r.= '</li>';
             }
             $r.= '        </ul>';
         } else {
index 040cf3a..f89293f 100644 (file)
@@ -106,6 +106,8 @@ $string['fieldsusedinindex'] = 'This field is used as index';
 $string['fieldsusedinkey'] = 'This field is used as key.';
 $string['filemodifiedoutfromeditor'] = 'Warning: File locally modified while using the XMLDB Editor. Saving will overwrite local changes.';
 $string['filenotwriteable'] = 'File not writeable';
+$string['fkunknownfield'] = 'Foreign key {$a->keyname} on table {$a->tablename} points to a non-existent field {$a->reffield} in referenced table {$a->reftable}.';
+$string['fkunknowntable'] = 'Foreign key {$a->keyname} on table {$a->tablename} points to a non-existent table {$a->reftable}.';
 $string['fkviolationdetails'] = 'Foreign key {$a->keyname} on table {$a->tablename} is violated by {$a->numviolations} out of {$a->numrows} rows.';
 $string['floatincorrectdecimals'] = 'Incorrect number of decimals for float field';
 $string['floatincorrectlength'] = 'Incorrect length for float field';
@@ -183,6 +185,8 @@ $string['selecttable'] = 'Select table:';
 $string['table'] = 'Table';
 $string['tablenameempty'] = 'The table name cannot be empty';
 $string['tables'] = 'Tables';
+$string['unknownfield'] = 'Refers to an unknown field';
+$string['unknowntable'] = 'Refers to an unknown table';
 $string['unload'] = 'Unload';
 $string['up'] = 'Up';
 $string['view'] = 'View';
index b82fcc2..d4e1414 100644 (file)
@@ -49,5 +49,8 @@ function xmldb_auth_cas_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2013091700, 'auth', 'cas');
     }
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index 333142a..d2087f7 100644 (file)
@@ -664,7 +664,7 @@ class auth_plugin_db extends auth_plugin_base {
      * @return moodle_url
      */
     function change_password_url() {
-        if ($this->is_internal()) {
+        if ($this->is_internal() || empty($this->config->changepasswordurl)) {
             // Standard form.
             return null;
         } else {
index 442f93e..ede7600 100644 (file)
@@ -120,7 +120,11 @@ class auth_plugin_imap extends auth_plugin_base {
      * @return moodle_url
      */
     function change_password_url() {
-        return new moodle_url($this->config->changepasswordurl);
+        if (!empty($this->config->changepasswordurl)) {
+            return new moodle_url($this->config->changepasswordurl);
+        } else {
+            return null;
+        }
     }
 
     /**
index f92c08d..a3fc3a8 100644 (file)
@@ -1603,7 +1603,11 @@ class auth_plugin_ldap extends auth_plugin_base {
      */
     function change_password_url() {
         if (empty($this->config->stdchangepassword)) {
-            return new moodle_url($this->config->changepasswordurl);
+            if (!empty($this->config->changepasswordurl)) {
+                return new moodle_url($this->config->changepasswordurl);
+            } else {
+                return null;
+            }
         } else {
             return null;
         }
index b118fa9..641357b 100644 (file)
@@ -39,5 +39,8 @@ function xmldb_auth_ldap_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2013052100, 'auth', 'ldap');
     }
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index 41bfeb9..0170124 100644 (file)
@@ -44,5 +44,8 @@ function xmldb_auth_manual_upgrade($oldversion) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index b2d49e2..14a8c56 100644 (file)
@@ -44,5 +44,8 @@ function xmldb_auth_mnet_upgrade($oldversion) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index 6b4bdff..5e25aa9 100644 (file)
@@ -120,7 +120,11 @@ class auth_plugin_pop3 extends auth_plugin_base {
      * @return moodle_url
      */
     function change_password_url() {
-        return new moodle_url($this->config->changepasswordurl);
+        if (!empty($this->config->changepasswordurl)) {
+            return new moodle_url($this->config->changepasswordurl);
+        } else {
+            return null;
+        }
     }
 
     /**
index 6085397..8334fed 100644 (file)
@@ -1,6 +1,10 @@
 This files describes API changes in /auth/* - plugins,
 information provided here is intended especially for developers.
 
+=== 2.7 ===
+
+* If you are returning a url in method change_password_url() from config, please make sure it is set before trying to use it.
+
 === 2.6 ===
 
 * can_be_manually_set() - This function was introduced in the base class and returns false by default. If overriden by
index 6794645..82f59f1 100644 (file)
@@ -126,8 +126,8 @@ abstract class backup implements checksumable {
     const OPERATION_RESTORE ='restore';// We are performing one restore
 
     // Version (to keep CFG->backup_version (and release) updated automatically)
-    const VERSION = 2013110500;
-    const RELEASE = '2.6';
+    const VERSION = 2013111800;
+    const RELEASE = '2.7';
 }
 
 /*
index eeb6322..a4e42ef 100644 (file)
@@ -2210,9 +2210,15 @@ class restore_calendarevents_structure_step extends restore_structure_step {
         } else {
             $params['instance'] = 0;
         }
-        $sql = 'SELECT id FROM {event} WHERE name = ? AND courseid = ? AND
-                repeatid = ? AND modulename = ? AND timestart = ? AND timeduration =?
-                AND ' . $DB->sql_compare_text('description', 255) . ' = ' . $DB->sql_compare_text('?', 255);
+        $sql = "SELECT id
+                  FROM {event}
+                 WHERE " . $DB->sql_compare_text('name', 255) . " = " . $DB->sql_compare_text('?', 255) . "
+                   AND courseid = ?
+                   AND repeatid = ?
+                   AND modulename = ?
+                   AND timestart = ?
+                   AND timeduration = ?
+                   AND " . $DB->sql_compare_text('description', 255) . " = " . $DB->sql_compare_text('?', 255);
         $arg = array ($params['name'], $params['courseid'], $params['repeatid'], $params['modulename'], $params['timestart'], $params['timeduration'], $params['description']);
         $result = $DB->record_exists_sql($sql, $arg);
         if (empty($result)) {
index fcdd459..7204e58 100644 (file)
@@ -120,7 +120,6 @@ abstract class core_backup_progress {
         $this->currents[] = 0;
         $this->parentcounts[] = $parentcount;
         $this->update_progress();
-        $lastprogresstime = $this->get_time();
     }
 
     /**
index a252ec3..762ea70 100644 (file)
@@ -73,6 +73,14 @@ abstract class base_moodleform extends moodleform {
      */
     function __construct(base_ui_stage $uistage, $action=null, $customdata=null, $method='post', $target='', $attributes=null, $editable=true) {
         $this->uistage = $uistage;
+        // Add a class to the attributes to prevent the default collapsible behaviour.
+        if (!$attributes) {
+            $attributes = array();
+        }
+        $attributes['class'] = 'unresponsive';
+        if (!isset($attributes['enctype'])) {
+            $attributes['enctype'] = 'application/x-www-form-urlencoded'; // Enforce compatibility with our max_input_vars hack.
+        }
         parent::__construct($action, $customdata, $method, $target, $attributes, $editable);
     }
     /**
index 6275e60..ef559fd 100644 (file)
@@ -846,6 +846,7 @@ class restore_ui_stage_process extends restore_ui_stage {
         $html .= html_writer::start_tag('form', array(
             'action'    => $url->out_omit_querystring(),
             'class'     => 'backup-restore',
+            'enctype'   => 'application/x-www-form-urlencoded', // Enforce compatibility with our max_input_vars hack.
             'method'    => 'post'));
         foreach ($url->params() as $name => $value) {
             $html .= html_writer::empty_tag('input', array(
index 8fe100c..9675a62 100644 (file)
@@ -23,6 +23,7 @@ Feature: Duplicate activities
       | Description | Test database description |
     And I open "Test database name" actions menu
     When I click on "Duplicate" "link" in the "Test database name" activity
+    And I open "Test database name" actions menu
     And I click on "Edit settings" "link" in the "Test database name" activity
     And I fill the moodle form with:
       | Name | Original database name |
index a1dcfcc..a0bee0f 100644 (file)
@@ -116,14 +116,9 @@ function badge_message_cron() {
  * @param object $badge A badge which is notified about.
  */
 function badge_assemble_notification(stdClass $badge) {
-    global $CFG, $DB;
-
-    $admin = get_admin();
-    $userfrom = new stdClass();
-    $userfrom->id = $admin->id;
-    $userfrom->email = !empty($CFG->badges_defaultissuercontact) ? $CFG->badges_defaultissuercontact : $admin->email;
-    $userfrom->firstname = !empty($CFG->badges_defaultissuername) ? $CFG->badges_defaultissuername : $admin->firstname;
-    $userfrom->lastname = !empty($CFG->badges_defaultissuername) ? '' : $admin->lastname;
+    global $DB;
+
+    $userfrom = core_user::get_noreply_user();
     $userfrom->maildisplay = true;
 
     if ($msgs = $DB->get_records_select('badge_issued', 'issuernotified IS NULL AND badgeid = ?', array($badge->id))) {
@@ -147,15 +142,15 @@ function badge_assemble_notification(stdClass $badge) {
         // Create a message object.
         $eventdata = new stdClass();
         $eventdata->component         = 'moodle';
-        $eventdata->name              = 'instantmessage';
+        $eventdata->name              = 'badgecreatornotice';
         $eventdata->userfrom          = $userfrom;
         $eventdata->userto            = $creator;
         $eventdata->notification      = 1;
         $eventdata->subject           = $creatorsubject;
-        $eventdata->fullmessage       = $creatormessage;
+        $eventdata->fullmessage       = format_text_email($creatormessage, FORMAT_HTML);
         $eventdata->fullmessageformat = FORMAT_PLAIN;
-        $eventdata->fullmessagehtml   = format_text($creatormessage, FORMAT_HTML);
-        $eventdata->smallmessage      = '';
+        $eventdata->fullmessagehtml   = $creatormessage;
+        $eventdata->smallmessage      = $creatorsubject;
 
         message_send($eventdata);
     }
index 7ebe2f4..24e52d7 100644 (file)
@@ -225,6 +225,9 @@ class edit_message_form extends moodleform {
 
         $mform->addElement('advcheckbox', 'attachment', get_string('attachment', 'badges'), '', null, array(0, 1));
         $mform->addHelpButton('attachment', 'attachment', 'badges');
+        if (empty($CFG->allowattachments)) {
+            $mform->freeze('attachment');
+        }
 
         $options = array(
                 BADGE_MESSAGE_NEVER   => get_string('never'),
index cc1a0d4..b70d377 100644 (file)
@@ -166,6 +166,7 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
     }
 
     public function test_badge_awards() {
+        $this->preventResetByRollback(); // Messaging is not compatible with transactions.
         $badge = new badge($this->badgeid);
         $user1 = $this->getDataGenerator()->create_user();
 
@@ -225,6 +226,7 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
      * Test badges observer when course module completion event id fired.
      */
     public function test_badges_observer_course_module_criteria_review() {
+        $this->preventResetByRollback(); // Messaging is not compatible with transactions.
         $badge = new badge($this->coursebadge);
         $this->assertFalse($badge->is_issued($this->user->id));
 
@@ -257,6 +259,7 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
      * Test badges observer when course_completed event is fired.
      */
     public function test_badges_observer_course_criteria_review() {
+        $this->preventResetByRollback(); // Messaging is not compatible with transactions.
         $badge = new badge($this->coursebadge);
         $this->assertFalse($badge->is_issued($this->user->id));
 
@@ -282,6 +285,7 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
      * Test badges observer when user_updated event is fired.
      */
     public function test_badges_observer_profile_criteria_review() {
+        $this->preventResetByRollback(); // Messaging is not compatible with transactions.
         $badge = new badge($this->coursebadge);
         $this->assertFalse($badge->is_issued($this->user->id));
 
@@ -304,6 +308,7 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
      * Test badges assertion generated when a badge is issued.
      */
     public function test_badges_assertion() {
+        $this->preventResetByRollback(); // Messaging is not compatible with transactions.
         $badge = new badge($this->coursebadge);
         $this->assertFalse($badge->is_issued($this->user->id));
 
diff --git a/blocks/activity_modules/tests/behat/block_activity_modules.feature b/blocks/activity_modules/tests/behat/block_activity_modules.feature
new file mode 100644 (file)
index 0000000..ba76908
--- /dev/null
@@ -0,0 +1,176 @@
+@block @block_activity_modules @_only_local
+Feature: Block activity modules
+  In order to overview activity modules in a course
+  As a manager
+  I can add activities block in a course or on the frontpage
+
+  Background:
+    Given I log in as "admin"
+    And I expand "Site administration" node
+    And I expand "Plugins" node
+    And I expand "Activity modules" node
+    And I follow "Manage activities"
+    And I click on "//a[@title=\"Show\"]" "xpath_element" in the "Feedback" "table_row"
+    And I click on "//a[@title=\"Show\"]" "xpath_element" in the "Assignment (2.2)" "table_row"
+
+  Scenario: Add activities block on the frontpage
+    And the following "activities" exists:
+      | activity   | name                        | intro                              | course               | idnumber    |
+      | assign     | Frontpage assignment name   | Frontpage assignment description   | Acceptance test site | assign0     |
+      | assignment | Frontpage assignment22 name | Frontpage assignment22 description | Acceptance test site | assignment0 |
+      | book       | Frontpage book name         | Frontpage book description         | Acceptance test site | book0       |
+      | chat       | Frontpage chat name         | Frontpage chat description         | Acceptance test site | chat0       |
+      | choice     | Frontpage choice name       | Frontpage choice description       | Acceptance test site | choice0     |
+      | data       | Frontpage database name     | Frontpage database description     | Acceptance test site | data0       |
+      | feedback   | Frontpage feedback name     | Frontpage feedback description     | Acceptance test site | feedback0   |
+      | forum      | Frontpage forum name        | Frontpage forum description        | Acceptance test site | forum0      |
+      | label      | Frontpage label name        | Frontpage label description        | Acceptance test site | label0      |
+      | lti        | Frontpage lti name          | Frontpage lti description          | Acceptance test site | lti0        |
+      | page       | Frontpage page name         | Frontpage page description         | Acceptance test site | page0       |
+      | quiz       | Frontpage quiz name         | Frontpage quiz description         | Acceptance test site | quiz0       |
+      | resource   | Frontpage resource name     | Frontpage resource description     | Acceptance test site | resource0   |
+      | imscp      | Frontpage imscp name        | Frontpage imscp description        | Acceptance test site | imscp0      |
+      | folder     | Frontpage folder name       | Frontpage folder description       | Acceptance test site | folder0     |
+      | glossary   | Frontpage glossary name     | Frontpage glossary description     | Acceptance test site | glossary0   |
+      | scorm      | Frontpage scorm name        | Frontpage scorm description        | Acceptance test site | scorm0      |
+      | lesson     | Frontpage lesson name       | Frontpage lesson description       | Acceptance test site | lesson0     |
+      | survey     | Frontpage survey name       | Frontpage survey description       | Acceptance test site | survey0     |
+      | url        | Frontpage url name          | Frontpage url description          | Acceptance test site | url0        |
+      | wiki       | Frontpage wiki name         | Frontpage wiki description         | Acceptance test site | wiki0       |
+      | workshop   | Frontpage workshop name     | Frontpage workshop description     | Acceptance test site | workshop0   |
+
+    And I am on homepage
+    When I follow "Turn editing on"
+    And I add the "Activities" block
+    And I click on "Assignments" "link" in the "Activities" "block"
+    Then I should see "Frontpage assignment name"
+    And I am on homepage
+    And I click on "Assignments (2.2)" "link" in the "Activities" "block"
+    And I should see "Frontpage assignment22 name"
+    And I am on homepage
+    And I click on "Chats" "link" in the "Activities" "block"
+    And I should see "Frontpage chat name"
+    And I am on homepage
+    And I click on "Choices" "link" in the "Activities" "block"
+    And I should see "Frontpage choice name"
+    And I am on homepage
+    And I click on "Databases" "link" in the "Activities" "block"
+    And I should see "Frontpage database name"
+    And I am on homepage
+    And I click on "Feedback" "link" in the "Activities" "block"
+    And I should see "Frontpage feedback name"
+    And I am on homepage
+    And I click on "Forums" "link" in the "Activities" "block"
+    And I should see "Frontpage forum name"
+    And I am on homepage
+    And I click on "External Tools" "link" in the "Activities" "block"
+    And I should see "Frontpage lti name"
+    And I am on homepage
+    And I click on "Quizzes" "link" in the "Activities" "block"
+    And I should see "Frontpage quiz name"
+    And I am on homepage
+    And I click on "Glossaries" "link" in the "Activities" "block"
+    And I should see "Frontpage glossary name"
+    And I am on homepage
+    And I click on "SCORM packages" "link" in the "Activities" "block"
+    And I should see "Frontpage scorm name"
+    And I am on homepage
+    And I click on "Lessons" "link" in the "Activities" "block"
+    And I should see "Frontpage lesson name"
+    And I am on homepage
+    And I click on "Wikis" "link" in the "Activities" "block"
+    And I should see "Frontpage wiki name"
+    And I am on homepage
+    And I click on "Workshop" "link" in the "Activities" "block"
+    And I should see "Frontpage workshop name"
+    And I am on homepage
+    And I click on "Resources" "link" in the "Activities" "block"
+    And I should see "Frontpage book name"
+    And I should see "Frontpage page name"
+    And I should see "Frontpage resource name"
+    And I should see "Frontpage imscp name"
+    And I should see "Frontpage folder name"
+    And I should see "Frontpage url name"
+
+  Scenario: Add activities block in a course
+    Given the following "courses" exists:
+      | fullname | shortname | format |
+      | Course 1 | C1        | topics |
+    And the following "activities" exists:
+      | activity   | name                   | intro                         | course | idnumber    |
+      | assign     | Test assignment name   | Test assignment description   | C1     | assign1     |
+      | assignment | Test assignment22 name | Test assignment22 description | C1     | assignment1 |
+      | book       | Test book name         | Test book description         | C1     | book1       |
+      | chat       | Test chat name         | Test chat description         | C1     | chat1       |
+      | choice     | Test choice name       | Test choice description       | C1     | choice1     |
+      | data       | Test database name     | Test database description     | C1     | data1       |
+      | feedback   | Test feedback name     | Test feedback description     | C1     | feedback1   |
+      | folder     | Test folder name       | Test folder description       | C1     | folder1     |
+      | forum      | Test forum name        | Test forum description        | C1     | forum1      |
+      | glossary   | Test glossary name     | Test glossary description     | C1     | glossary1   |
+      | imscp      | Test imscp name        | Test imscp description        | C1     | imscp1      |
+      | label      | Test label name        | Test label description        | C1     | label1      |
+      | lesson     | Test lesson name       | Test lesson description       | C1     | lesson1     |
+      | lti        | Test lti name          | Test lti description          | C1     | lti1        |
+      | page       | Test page name         | Test page description         | C1     | page1       |
+      | quiz       | Test quiz name         | Test quiz description         | C1     | quiz1       |
+      | resource   | Test resource name     | Test resource description     | C1     | resource1   |
+      | scorm      | Test scorm name        | Test scorm description        | C1     | scorm1      |
+      | survey     | Test survey name       | Test survey description       | C1     | survey1     |
+      | url        | Test url name          | Test url description          | C1     | url1        |
+      | wiki       | Test wiki name         | Test wiki description         | C1     | wiki1       |
+      | workshop   | Test workshop name     | Test workshop description     | C1     | workshop1   |
+
+    When I follow "Courses"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add the "Activities" block
+    And I click on "Assignments" "link" in the "Activities" "block"
+    Then I should see "Test assignment name"
+    And I follow "Course 1"
+    And I click on "Assignments (2.2)" "link" in the "Activities" "block"
+    And I should see "Test assignment22 name"
+    And I follow "Course 1"
+    And I click on "Chats" "link" in the "Activities" "block"
+    And I should see "Test chat name"
+    And I follow "Course 1"
+    And I click on "Choices" "link" in the "Activities" "block"
+    And I should see "Test choice name"
+    And I follow "Course 1"
+    And I click on "Databases" "link" in the "Activities" "block"
+    And I should see "Test database name"
+    And I follow "Course 1"
+    And I click on "Feedback" "link" in the "Activities" "block"
+    And I should see "Test feedback name"
+    And I follow "Course 1"
+    And I click on "Forums" "link" in the "Activities" "block"
+    And I should see "Test forum name"
+    And I follow "Course 1"
+    And I click on "External Tools" "link" in the "Activities" "block"
+    And I should see "Test lti name"
+    And I follow "Course 1"
+    And I click on "Quizzes" "link" in the "Activities" "block"
+    And I should see "Test quiz name"
+    And I follow "Course 1"
+    And I click on "Glossaries" "link" in the "Activities" "block"
+    And I should see "Test glossary name"
+    And I follow "Course 1"
+    And I click on "SCORM packages" "link" in the "Activities" "block"
+    And I should see "Test scorm name"
+    And I follow "Course 1"
+    And I click on "Lessons" "link" in the "Activities" "block"
+    And I should see "Test lesson name"
+    And I follow "Course 1"
+    And I click on "Wikis" "link" in the "Activities" "block"
+    And I should see "Test wiki name"
+    And I follow "Course 1"
+    And I click on "Workshop" "link" in the "Activities" "block"
+    And I should see "Test workshop name"
+    And I follow "Course 1"
+    And I click on "Resources" "link" in the "Activities" "block"
+    And I should see "Test book name"
+    And I should see "Test page name"
+    And I should see "Test resource name"
+    And I should see "Test imscp name"
+    And I should see "Test folder name"
+    And I should see "Test url name"
index 39a165d..2e56d5c 100644 (file)
@@ -58,5 +58,8 @@ function xmldb_block_community_upgrade($oldversion) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index 0fc7927..d161a36 100644 (file)
@@ -64,5 +64,8 @@ function xmldb_block_completionstatus_upgrade($oldversion, $block) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
\ No newline at end of file
index aaf6570..d459982 100644 (file)
@@ -35,7 +35,14 @@ class block_course_list extends block_list {
 
         if (empty($CFG->disablemycourses) and isloggedin() and !isguestuser() and
           !(has_capability('moodle/course:update', context_system::instance()) and $adminseesall)) {    // Just print My Courses
-            if ($courses = enrol_get_my_courses(NULL, 'visible DESC, fullname ASC')) {
+            // As this is producing navigation sort order should default to $CFG->navsortmycoursessort instead
+            // of using the default.
+            if (!empty($CFG->navsortmycoursessort)) {
+                $sortorder = 'visible DESC, ' . $CFG->navsortmycoursessort . ' ASC';
+            } else {
+                $sortorder = 'visible DESC, sortorder ASC';
+            }
+            if ($courses = enrol_get_my_courses(NULL, $sortorder)) {
                 foreach ($courses as $course) {
                     $coursecontext = context_course::instance($course->id);
                     $linkcss = $course->visible ? "" : " class=\"dimmed\" ";
index d18e85e..932bf2d 100644 (file)
@@ -69,5 +69,8 @@ function xmldb_block_course_summary_upgrade($oldversion, $block) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
\ No newline at end of file
index 7bf440e..ba0cbe2 100644 (file)
@@ -44,5 +44,8 @@ function xmldb_block_html_upgrade($oldversion) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index aa340af..95c3059 100644 (file)
@@ -46,5 +46,14 @@ class block_mentees extends block_base {
 
         return $this->content;
     }
+
+    /**
+     * Returns true if the block can be docked.
+     * The mentees block can only be docked if it has a non-empty title.
+     * @return bool
+     */
+    public function instance_can_be_docked() {
+        return parent::instance_can_be_docked() && isset($this->config->title) && !empty($this->config->title);
+    }
 }
 
index 8037799..36b093f 100644 (file)
@@ -70,5 +70,8 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
\ No newline at end of file
index d0542ac..b6e6822 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 ce342d8..e474ba8 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 55e4047..368a23d 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 97e8bdc..0748b98 100644 (file)
@@ -402,6 +402,15 @@ Y.extend(TREE, Y.Base, TREE.prototype, {
                 }
                 return val;
             }
+        },
+        /**
+         * The navigation tree block instance.
+         */
+        instance : {
+            value : false,
+            setter : function(val) {
+                return parseInt(val);
+            }
         }
     }
 });
@@ -581,7 +590,7 @@ BRANCH.prototype = {
         } else {
             e.stopPropagation();
         }
-        if (e.type === 'actionkey' && e.action === 'enter' && e.target.test('A')) {
+        if ((e.type === 'actionkey' && e.action === 'enter') || e.target.test('a')) {
             // No ajaxLoad for enter.
             this.node.setAttribute('data-expandable', '0');
             this.node.setAttribute('data-loaded', '1');
@@ -638,6 +647,12 @@ BRANCH.prototype = {
         this.node.setAttribute('data-loaded', '1');
         try {
             var object = Y.JSON.parse(outcome.responseText);
+            if (object.error) {
+                Y.use('moodle-core-notification-ajaxException', function () {
+                    return new M.core.ajaxException(object).show();
+                });
+                return false;
+            }
             if (object.children && object.children.length > 0) {
                 var coursecount = 0;
                 for (var i in object.children) {
@@ -661,9 +676,16 @@ BRANCH.prototype = {
                 return true;
             }
             Y.log('AJAX loading complete but there were no children.', 'note', 'moodle-block_navigation');
-        } catch (ex) {
-            // If we got here then there was an error parsing the result.
-            Y.log('Error parsing AJAX response or adding branches to the navigation tree', 'error', 'moodle-block_navigation');
+        } catch (error) {
+            if (outcome && outcome.status && outcome.status > 0) {
+                // If we got here then there was an error parsing the result.
+                Y.log('Error parsing AJAX response or adding branches to the navigation tree', 'error', 'moodle-block_navigation');
+                Y.use('moodle-core-notification-exception', function () {
+                    return new M.core.exception(error).show();
+                });
+            }
+
+            return false;
         }
         // The branch is empty so class it accordingly
         this.node.replaceClass('branch', 'emptybranch');
index f8c5993..2f49298 100644 (file)
 
             if($this->config->display_description && !empty($description)){
 
-                $description = break_up_long_words($description, 30);
-
                 $formatoptions = new stdClass();
                 $formatoptions->para = false;
 
                 $r.= html_writer::start_tag('div',array('class'=>'description'));
-                    $r.= format_text($description, FORMAT_HTML, $formatoptions, $this->page->course->id);
+                    $description = format_text($description, FORMAT_HTML, $formatoptions, $this->page->course->id);
+                    $description = break_up_long_words($description, 30);
+                    $r.= $description;
                 $r.= html_writer::end_tag('div');
             }
         $r.= html_writer::end_tag('li');
index 3c838d8..42a472c 100644 (file)
@@ -80,5 +80,8 @@ function xmldb_block_section_links_upgrade($oldversion, $block) {
     // Put any upgrade step following this
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
index 962b991..1070048 100644 (file)
@@ -69,5 +69,8 @@ function xmldb_block_selfcompletion_upgrade($oldversion, $block) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
\ No newline at end of file
index 305e513..e06f9bb 100644 (file)
@@ -70,5 +70,8 @@ function xmldb_block_settings_upgrade($oldversion, $block) {
     // Put any upgrade step following this.
 
 
+    // Moodle v2.6.0 release upgrade line.
+    // Put any upgrade step following this.
+
     return true;
 }
\ No newline at end of file
index 7f650c4..762bb64 100644 (file)
@@ -89,6 +89,20 @@ class block_site_main_menu extends block_list {
                 }
                 if (!$ismoving) {
                     $actions = course_get_cm_edit_actions($mod, -1);
+
+                    // Add the action move.
+                    $modcontext = context_module::instance($mod->id);
+                    $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext);
+                    if ($hasmanageactivities) {
+                        $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
+                        $actions['move'] = new action_menu_link_primary(
+                            new moodle_url($baseurl, array('copy' => $mod->id)),
+                            new pix_icon('t/move', get_string('move'), 'moodle', array('class' => 'iconsmall', 'title' => '')),
+                            null,
+                            array('title' => get_string('move'))
+                        );
+                    }
+
                     $editbuttons = html_writer::tag('div',
                         $courserenderer->course_section_cm_edit_actions($actions, $mod, array('donotenhance' => true)),
                         array('class' => 'buttons')
index 6b1a793..d1a0371 100644 (file)
@@ -81,6 +81,7 @@ class block_tags extends block_base {
         }
 
         $this->content = new stdClass;
+        $this->content->text = '';
         $this->content->footer = '';
 
         // Get a list of tags.
index 42fe9a1..36d8be2 100644 (file)
@@ -58,4 +58,43 @@ class behat_blocks extends behat_base {
         return $steps;
     }
 
+    /**
+     * Opens a block's actions menu if it is not already opened.
+     *
+     * @Given /^I open the "(?P<block_name_string>(?:[^"]|\\")*)" blocks action menu$/
+     * @throws DriverException The step is not available when Javascript is disabled
+     * @param string $blockname
+     * @return Given
+     */
+    public function i_open_the_blocks_action_menu($blockname) {
+
+        if (!$this->running_javascript()) {
+            throw new DriverException('Blocks action menu not available when Javascript is disabled');
+        }
+
+        // If it is already opened we do nothing.
+        $blocknode = $this->get_block_node($blockname);
+        $classes = array_flip(explode(' ', $blocknode->getAttribute('class')));
+        if (!empty($classes['action-menu-shown'])) {
+            return;
+        }
+
+        return new Given('I click on "a[role=\'menuitem\']" "css_element" in the "' . $this->escape($blockname) . '" "block"');
+    }
+
+    /**
+     * Returns the DOM node of the block from <div>.
+     *
+     * @throws ElementNotFoundException Thrown by behat_base::find
+     * @param string $blockname The block name
+     * @return NodeElement
+     */
+    protected function get_block_node($blockname) {
+
+        $blockname = $this->getSession()->getSelectorsHandler()->xpathLiteral($blockname);
+        $xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' block ')][contains(., $blockname)]";
+
+        return $this->find('xpath', $xpath);
+    }
+
 }
index af2bc33..3812f69 100644 (file)
@@ -18,7 +18,7 @@ Feature: Add and configure blocks throughout the site
     And I log in as "manager1"
     And I follow "Turn editing on"
     And I add the "Comments" block
-    And I click on "Actions" "link" in the "Comments" "block"
+    And I open the "Comments" blocks action menu
     And I follow "Configure Comments block"
     And I fill the moodle form with:
       | Page contexts | Display throughout the entire site |
@@ -27,11 +27,11 @@ Feature: Add and configure blocks throughout the site
     Then I should see "Comments" in the "Comments" "block"
     And I should see "Save comment" in the "Comments" "block"
     And I am on homepage
-    And I click on "Actions" "link" in the "Comments" "block"
+    And I open the "Comments" blocks action menu
     And I follow "Configure Comments block"
     And I fill the moodle form with:
       | Default weight | -10 (first) |
     And I press "Save changes"
     And I follow "Course 1"
     # The first block matching the pattern should be top-left block
-    And I should see "Comments" in the "//*[@id='region-pre']/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]" "xpath_element"
+    And I should see "Comments" in the "//*[@id='region-pre' or @id='block-region-side-pre']/descendant::div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]" "xpath_element"
index 2c3cb7f..5f1189d 100644 (file)
@@ -42,6 +42,7 @@ Feature: Block appearances
     And I follow "Course 1"
     And I follow "Turn editing on"
     And I add the "Comments" block
+    And I open the "Comments" blocks action menu
     And I follow "Configure Comments block"
     And I fill the moodle form with:
       | Display on page types | Any page |
@@ -52,6 +53,7 @@ Feature: Block appearances
     When I follow "Test survey name"
     Then I should see "Comments" in the "Comments" "block"
     And I follow "Course 1"
+    And I open the "Comments" blocks action menu
     And I follow "Configure Comments block"
     And I fill the moodle form with:
       | Display on page types | Any course page |
@@ -63,6 +65,7 @@ Feature: Block appearances
   @javascript
   Scenario: Block settings can be modified so that a block can be hidden or moved
     When I follow "Test book name"
+    And I open the "Comments" blocks action menu
     And I follow "Configure Comments block"
     And I fill the moodle form with:
       | Visible | No |
@@ -72,9 +75,10 @@ Feature: Block appearances
     Then I should not see "Comments"
     And I expand "Course administration" node
     And I follow "Turn editing on"
+    And I open the "Comments" blocks action menu
     And I follow "Configure Comments block"
     And I fill the moodle form with:
       | Visible | Yes |
       | Region  | Right |
     And I press "Save changes"
-    And I should see "Comments" in the "#region-post" "css_element"
+    And I should see "Comments" in the "//*[@id='region-post' or @id='block-region-side-post']" "xpath_element"
index 8605ccc..af9bce2 100644 (file)
@@ -15,7 +15,7 @@ Feature: The context of a block can always be returned to it's original state.
     And I add the "Tags" block
     Then I should see "Tags" in the "Tags" "block"
     And I click on "Participants" "link" in the "//li[p/span[contains(normalize-space(string(.)), 'Current course')]]" "xpath_element"
-    And I click on "Actions" "link" in the "Tags" "block"
+    And I open the "Tags" blocks action menu
     And I follow "Configure Tags block"
     And I fill the moodle form with:
       | Display on page types | Any page |
@@ -25,7 +25,7 @@ Feature: The context of a block can always be returned to it's original state.
       | Assignment name | Assignment1 |
       | Description | Description |
     And I follow "Assignment1"
-    And I click on "Actions" "link" in the "Tags" "block"
+    And I open the "Tags" blocks action menu
     And I follow "Configure Tags block"
     And I fill the moodle form with:
       | Display on page types | Any assignment module page |
@@ -41,7 +41,7 @@ Feature: The context of a block can always be returned to it's original state.
       | Description | Description |
     And I follow "Assignment2"
     And I should see "Tags" in the "Tags" "block"
-    And I click on "Actions" "link" in the "Tags" "block"
+    And I open the "Tags" blocks action menu
     And I follow "Configure Tags block"
     And I fill the moodle form with:
       | Display on page types | Any page |
index 61ef61d..efa99ea 100644 (file)
@@ -40,7 +40,7 @@ if (empty($CFG->enableblogs)) {
 
 //correct tagid if a text tag is provided as a param
 if (!empty($tag)) {
-    if ($tagrec = $DB->get_record_sql("SELECT * FROM {tag} WHERE ". $DB->sql_like('name', '?', false), array("%$tag%"))) {
+    if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
         $tagid = $tagrec->id;
     } else {
         unset($tagid);
@@ -223,5 +223,13 @@ $bloglisting = new blog_listing($blogheaders['filters']);
 $bloglisting->print_entries();
 
 echo $OUTPUT->footer();
-
-add_to_log($courseid, 'blog', 'view', 'index.php?entryid='.$entryid.'&amp;tagid='.@$tagid.'&amp;tag='.$tag, 'view blog entry');
+$eventparams = array(
+    'other' => array('entryid' => $entryid, 'tagid' => $tagid, 'userid' => $userid, 'modid' => $modid, 'groupid' => $groupid,
+                     'search' => $search, 'fromstart' => $start)
+);
+if (!empty($userid)) {
+    $eventparams['relateduserid'] = $userid;
+}
+$eventparams['other']['courseid'] = ($courseid === SITEID) ? 0 : $courseid;
+$event = \core\event\blog_entries_viewed::create($eventparams);
+$event->trigger();
index c7ee5bd..10317c7 100644 (file)
@@ -880,8 +880,12 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
             $tagrec = $DB->get_record('tag', array('id'=>$tagid));
             $PAGE->navbar->add($tagrec->name, $blogurl);
         } elseif (!empty($tag)) {
-            $blogurl->param('tag', $tag);
-            $PAGE->navbar->add(get_string('tagparam', 'blog', $tag), $blogurl);
+            if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
+                $tagid = $tagrec->id;
+                $headers['filters']['tag'] = $tagid;
+                $blogurl->param('tag', $tag);
+                $PAGE->navbar->add(get_string('tagparam', 'blog', $tag), $blogurl);
+            }
         }
 
         // Append Search info
index a4e4210..c6a1084 100644 (file)
@@ -339,46 +339,62 @@ class blog_entry implements renderable {
     }
 
     /**
-     * function to add all context associations to an entry
-     * @param int entry - data object processed to include all 'entry' fields and extra data from the edit_form object
+     * Function to add all context associations to an entry.
+     * TODO : Remove $action in 2.9 (MDL-41330)
+     *
+     * @param string $action - This does nothing, do not use it. This is present only for Backward compatibility.
      */
-    public function add_associations($action='add') {
-        global $DB, $USER;
+    public function add_associations($action = null) {
+
+        if (!empty($action)) {
+            debugging('blog_entry->add_associations() does not accept any argument', DEBUG_DEVELOPER);
+        }
 
         $this->remove_associations();
 
         if (!empty($this->courseassoc)) {
-            $this->add_association($this->courseassoc, $action);
+            $this->add_association($this->courseassoc);
         }
 
         if (!empty($this->modassoc)) {
-            $this->add_association($this->modassoc, $action);
+            $this->add_association($this->modassoc);
         }
     }
 
     /**
-     * add a single association for a blog entry
-     * @param int contextid - id of context to associate with the blog entry
+     * Add a single association for a blog entry
+     * TODO : Remove $action in 2.9 (MDL-41330)
+     *
+     * @param int $contextid - id of context to associate with the blog entry.
+     * @param string $action - This does nothing, do not use it. This is present only for Backward compatibility.
      */
-    public function add_association($contextid, $action='add') {
-        global $DB, $USER;
+    public function add_association($contextid, $action = null) {
+        global $DB;
+
+        if (!empty($action)) {
+            debugging('blog_entry->add_association() accepts only one argument', DEBUG_DEVELOPER);
+        }
 
         $assocobject = new StdClass;
         $assocobject->contextid = $contextid;
         $assocobject->blogid = $this->id;
-        $DB->insert_record('blog_association', $assocobject);
+        $id = $DB->insert_record('blog_association', $assocobject);
 
+        // Trigger an association created event.
         $context = context::instance_by_id($contextid);
-        $courseid = null;
-
+        $eventparam = array(
+            'objectid' => $id,
+            'other' => array('associateid' => $context->instanceid, 'subject' => $this->subject, 'blogid' => $this->id),
+            'relateduserid' => $this->userid
+        );
         if ($context->contextlevel == CONTEXT_COURSE) {
-            $courseid = $context->instanceid;
-            add_to_log($courseid, 'blog', $action, 'index.php?userid='.$this->userid.'&entryid='.$this->id, $this->subject);
+            $eventparam['other']['associatetype'] = 'course';
+
         } else if ($context->contextlevel == CONTEXT_MODULE) {
-            $cm = $DB->get_record('course_modules', array('id' => $context->instanceid));
-            $modulename = $DB->get_field('modules', 'name', array('id' => $cm->module));
-            add_to_log($cm->course, 'blog', $action, 'index.php?userid='.$this->userid.'&entryid='.$this->id, $this->subject, $cm->id, $this->userid);
+            $eventparam['other']['associatetype'] = 'coursemodule';
         }
+        $event = \core\event\blog_association_created::create($eventparam);
+        $event->trigger();
     }
 
     /**
index 689e3be..47c8a29 100644 (file)
@@ -250,5 +250,137 @@ class core_bloglib_testcase extends advanced_testcase {
         $this->assertEventLegacyLogData($arr, $event);
         $this->assertEventLegacyData($blog, $event);
     }
+
+
+    /**
+     * Tests for event blog_association_created.
+     */
+    public function test_blog_association_created_event() {
+        global $USER;
+
+        $this->setAdminUser();
+        $this->resetAfterTest();
+        $sitecontext = context_system::instance();
+        $coursecontext = context_course::instance($this->courseid);
+        $contextmodule = context_module::instance($this->cmid);
+
+        // Add blog associations with a course.
+        $blog = new blog_entry($this->postid);
+        $sink = $this->redirectEvents();
+        $blog->add_association($coursecontext->id);
+        $events = $sink->get_events();
+        $event = reset($events);
+        $sink->close();
+
+        // Validate event data.
+        $this->assertInstanceOf('\core\event\blog_association_created', $event);
+        $this->assertEquals($sitecontext->id, $event->contextid);
+        $this->assertEquals($blog->id, $event->other['blogid']);
+        $this->assertEquals($this->courseid, $event->other['associateid']);
+        $this->assertEquals('course', $event->other['associatetype']);
+        $this->assertEquals($blog->subject, $event->other['subject']);
+        $this->assertEquals($USER->id, $event->userid);
+        $this->assertEquals($this->userid, $event->relateduserid);
+        $this->assertEquals('blog_association', $event->objecttable);
+        $arr = array(SITEID, 'blog', 'add association', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id,
+                     $blog->subject, 0, $this->userid);
+        $this->assertEventLegacyLogData($arr, $event);
+
+        // Add blog associations with a module.
+        $blog = new blog_entry($this->postid);
+        $sink = $this->redirectEvents();
+        $blog->add_association($contextmodule->id);
+        $events = $sink->get_events();
+        $event = reset($events);
+        $sink->close();
+
+        // Validate event data.
+        $this->assertEquals($blog->id, $event->other['blogid']);
+        $this->assertEquals($this->cmid, $event->other['associateid']);
+        $this->assertEquals('coursemodule', $event->other['associatetype']);
+        $arr = array(SITEID, 'blog', 'add association', 'index.php?userid=' . $this->userid . '&entryid=' . $blog->id,
+                     $blog->subject, $this->cmid, $this->userid);
+        $this->assertEventLegacyLogData($arr, $event);
+    }
+
+    /**
+     * Tests for event blog_association_created validations.
+     */
+    public function test_blog_association_created_event_validations() {
+
+        $this->resetAfterTest();
+
+         // Make sure associatetype validations work.
+        try {
+            \core\event\blog_association_created::create(array(
+                'contextid' => 1,
+                'objectid' => 3,
+                'other' => array('associateid' => 2 , 'blogid' => 3, 'subject' => 'blog subject')));
+        } catch (coding_exception $e) {
+            $this->assertContains('Invalid associatetype', $e->getMessage());
+        }
+        try {
+            \core\event\blog_association_created::create(array(
+                'contextid' => 1,
+                'objectid' => 3,
+                'other' => array('associateid' => 2 , 'blogid' => 3, 'associatetype' => 'random', 'subject' => 'blog subject')));
+        } catch (coding_exception $e) {
+            $this->assertContains('Invalid associatetype', $e->getMessage());
+        }
+        // Make sure associateid validations work.
+        try {
+            \core\event\blog_association_created::create(array(
+                'contextid' => 1,
+                'objectid' => 3,
+                'other' => array('blogid' => 3, 'associatetype' => 'course', 'subject' => 'blog subject')));
+        } catch (coding_exception $e) {
+            $this->assertContains('Associate id must be set', $e->getMessage());
+        }
+        // Make sure blogid validations work.
+        try {
+            \core\event\blog_association_created::create(array(
+                'contextid' => 1,
+                'objectid' => 3,
+                'other' => array('associateid' => 3, 'associatetype' => 'course', 'subject' => 'blog subject')));
+        } catch (coding_exception $e) {
+            $this->assertContains('Blog id must be set', $e->getMessage());
+        }
+        // Make sure blogid validations work.
+        try {
+            \core\event\blog_association_created::create(array(
+                'contextid' => 1,
+                'objectid' => 3,
+                'other' => array('blogid' => 3, 'associateid' => 3, 'associatetype' => 'course')));
+        } catch (coding_exception $e) {
+            $this->assertContains('Subject must be set', $e->getMessage());
+        }
+    }
+
+    /**
+     * Tests for event blog_entries_viewed.
+     */
+    public function test_blog_entries_viewed_event() {
+
+        $this->setAdminUser();
+        $this->resetAfterTest();
+        $other = array('entryid' => $this->postid, 'tagid' => $this->tagid, 'userid' => $this->userid, 'modid' => $this->cmid,
+                       'groupid' => $this->groupid, 'courseid' => $this->courseid, 'search' => 'search', 'fromstart' => 2);
+
+        // Trigger event.
+        $sink = $this->redirectEvents();
+        $eventparams = array('other' => $other);
+        $eventinst = \core\event\blog_entries_viewed::create($eventparams);
+        $eventinst->trigger();
+        $events = $sink->get_events();
+        $event = reset($events);
+        $sink->close();
+
+        // Validate event data.
+        $url = new moodle_url('/blog/index.php', $other);
+        $url2 = new moodle_url('index.php', $other);
+        $this->assertEquals($url, $event->get_url());
+        $arr = array(SITEID, 'blog', 'view', $url2->out(), 'view blog entry');
+        $this->assertEventLegacyLogData($arr, $event);
+    }
 }
 
diff --git a/blog/upgrade.txt b/blog/upgrade.txt
new file mode 100644 (file)
index 0000000..8695b95
--- /dev/null
@@ -0,0 +1,4 @@
+=== 2.7 ===
+
+* blog_entry->add_association() does not accept any params.
+* blog_entry->add_associations() accepts only one param.
\ No newline at end of file
index f3e3acb..c9c35db 100644 (file)
@@ -282,6 +282,7 @@ if (!empty($action) && confirm_sesskey()) {
 
 $PAGE->set_title($title);
 $PAGE->set_heading($SITE->fullname);
+/* @var core_cache_renderer $renderer */
 $renderer = $PAGE->get_renderer('core_cache');
 
 echo $renderer->header();
index 281fa30..4463e0a 100644 (file)
@@ -963,4 +963,31 @@ class cache_definition {
     public function has_required_identifiers() {
         return (count($this->requireidentifiers) > 0);
     }
+
+    /**
+     * Returns the possible sharing options that can be used with this defintion.
+     *
+     * @return int
+     */
+    public function get_sharing_options() {
+        return $this->sharingoptions;
+    }
+
+    /**
+     * Returns the user entered sharing key for this definition.
+     *
+     * @return string
+     */
+    public function get_user_input_sharing_key() {
+        return $this->userinputsharingkey;
+    }
+
+    /**
+     * Returns the user selected sharing option for this definition.
+     *
+     * @return int
+     */
+    public function get_selected_sharing_option() {
+        return $this->selectedsharingoption;
+    }
 }
index 2843dae..f850e69 100644 (file)
@@ -235,14 +235,9 @@ class cache_factory {
      */
     public function create_cache(cache_definition $definition) {
         $class = $definition->get_cache_class();
-        if ($this->is_initialising()) {
-            // Do nothing we just want the dummy store.
-            $stores = array();
-        } else {
-            $stores = cache_helper::get_cache_stores($definition);
-        }
+        $stores = cache_helper::get_stores_suitable_for_definition($definition);
         if (count($stores) === 0) {
-            // Hmm no stores, better provide a dummy store to mimick functionality. The dev will be none the wiser.
+            // Hmm still no stores, better provide a dummy store to mimic functionality. The dev will be none the wiser.
             $stores[] = $this->create_dummy_store($definition);
         }
         $loader = null;
index 96c6601..90076aa 100644 (file)
@@ -143,7 +143,7 @@ class cache_helper {
      *
      * @param array $stores
      * @param cache_definition $definition
-     * @return array
+     * @return cache_store[]
      */
     protected static function initialise_cachestore_instances(array $stores, cache_definition $definition) {
         $return = array();
@@ -382,34 +382,40 @@ class cache_helper {
     /**
      * Record a cache hit in the stats for the given store and definition.
      *
+     * @internal
      * @param string $store
      * @param string $definition
+     * @param int $hits The number of hits to record (by default 1)
      */
-    public static function record_cache_hit($store, $definition) {
+    public static function record_cache_hit($store, $definition, $hits = 1) {
         self::ensure_ready_for_stats($store, $definition);
-        self::$stats[$definition][$store]['hits']++;
+        self::$stats[$definition][$store]['hits'] += $hits;
     }
 
     /**
      * Record a cache miss in the stats for the given store and definition.
      *
+     * @internal
      * @param string $store
      * @param string $definition
+     * @param int $misses The number of misses to record (by default 1)
      */
-    public static function record_cache_miss($store, $definition) {
+    public static function record_cache_miss($store, $definition, $misses = 1) {
         self::ensure_ready_for_stats($store, $definition);
-        self::$stats[$definition][$store]['misses']++;
+        self::$stats[$definition][$store]['misses'] += $misses;
     }
 
     /**
      * Record a cache set in the stats for the given store and definition.
      *
+     * @internal
      * @param string $store
      * @param string $definition
+     * @param int $sets The number of sets to record (by default 1)
      */
-    public static function record_cache_set($store, $definition) {
+    public static function record_cache_set($store, $definition, $sets = 1) {
         self::ensure_ready_for_stats($store, $definition);
-        self::$stats[$definition][$store]['sets']++;
+        self::$stats[$definition][$store]['sets'] += $sets;
     }
 
     /**
@@ -672,4 +678,59 @@ class cache_helper {
             }
         }
     }
+
+    /**
+     * Returns an array of stores that would meet the requirements for every definition.
+     *
+     * These stores would be 100% suitable to map as defaults for cache modes.
+     *
+     * @return array[] An array of stores, keys are the store names.
+     */
+    public static function get_stores_suitable_for_mode_default() {
+        $factory = cache_factory::instance();
+        $config = $factory->create_config_instance();
+        $requirements = 0;
+        foreach ($config->get_definitions() as $definition) {
+            $definition = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
+            $requirements = $requirements | $definition->get_requirements_bin();
+        }
+        $stores = array();
+        foreach ($config->get_all_stores() as $name => $store) {
+            if (!empty($store['features']) && ($store['features'] & $requirements)) {
+                $stores[$name] = $store;
+            }
+        }
+        return $stores;
+    }
+
+    /**
+     * Returns stores suitable for use with a given definition.
+     *
+     * @param cache_definition $definition
+     * @return cache_store[]
+     */
+    public static function get_stores_suitable_for_definition(cache_definition $definition) {
+        $factory = cache_factory::instance();
+        $stores = array();
+        if ($factory->is_initialising() || $factory->stores_disabled()) {
+            // No suitable stores here.
+            return $stores;
+        } else {
+            $stores = self::get_cache_stores($definition);
+            if (count($stores) === 0) {
+                // No suitable stores we found for the definition. We need to come up with a sensible default.
+                // If this has happened we can be sure that the user has mapped custom stores to either the
+                // mode of the definition. The first alternative to try is the system default for the mode.
+                // e.g. the default file store instance for application definitions.
+                $config = $factory->create_config_instance();
+                foreach ($config->get_stores($definition->get_mode()) as $name => $details) {
+                    if (!empty($details['default'])) {
+                        $stores[] = $factory->create_store_from_config($name, $details, $definition);
+                        break;
+                    }
+                }
+            }
+        }
+        return $stores;
+    }
 }
index 10ad620..994aef2 100644 (file)
@@ -463,6 +463,20 @@ class cache implements cache_loader {
             }
         }
 
+        if ($this->perfdebug) {
+            $hits = 0;
+            $misses = 0;
+            foreach ($fullresult as $value) {
+                if ($value === false) {
+                    $misses++;
+                } else {
+                    $hits++;
+                }
+            }
+            cache_helper::record_cache_hit($this->storetype, $this->definition->get_id(), $hits);
+            cache_helper::record_cache_miss($this->storetype, $this->definition->get_id(), $misses);
+        }
+
         // Return the result. Phew!
         return $fullresult;
     }
@@ -633,10 +647,11 @@ class cache implements cache_loader {
                 $this->static_acceleration_set($data[$key]['key'], $value);
             }
         }
-        if ($this->perfdebug) {
-            cache_helper::record_cache_set($this->storetype, $this->definition->get_id());
+        $successfullyset = $this->store->set_many($data);
+        if ($this->perfdebug && $successfullyset) {
+            cache_helper::record_cache_set($this->storetype, $this->definition->get_id(), $successfullyset);
         }
-        return $this->store->set_many($data);
+        return $successfullyset;
     }
 
     /**
@@ -1937,7 +1952,19 @@ class cache_session extends cache {
         if ($hasmissingkeys && $strictness === MUST_EXIST) {
             throw new coding_exception('Requested key did not exist in any cache stores and could not be loaded.');
         }
-
+        if ($this->perfdebug) {
+            $hits = 0;
+            $misses = 0;
+            foreach ($return as $value) {
+                if ($value === false) {
+                    $misses++;
+                } else {
+                    $hits++;
+                }
+            }
+            cache_helper::record_cache_hit($this->storetype, $this->get_definition()->get_id(), $hits);
+            cache_helper::record_cache_miss($this->storetype, $this->get_definition()->get_id(), $misses);
+        }
         return $return;
 
     }
@@ -2011,10 +2038,11 @@ class cache_session extends cache {
                 'value' => $value
             );
         }
-        if ($this->perfdebug) {
-            cache_helper::record_cache_set($this->storetype, $definitionid);
+        $successfullyset = $this->get_store()->set_many($data);
+        if ($this->perfdebug && $successfullyset) {
+            cache_helper::record_cache_set($this->storetype, $definitionid, $successfullyset);
         }
-        return $this->get_store()->set_many($data);
+        return $successfullyset;
     }
 
     /**
index c72c52c..c7948cf 100644 (file)
@@ -778,63 +778,36 @@ abstract class cache_administration_helper extends cache_helper {
      * @return array
      */
     public static function get_definition_summaries() {
-        $instance = cache_config::instance();
-        $definitions = $instance->get_definitions();
-
+        $factory = cache_factory::instance();
+        $config = $factory->create_config_instance();
         $storenames = array();
-        foreach ($instance->get_all_stores() as $key => $store) {
+        foreach ($config->get_all_stores() as $key => $store) {
             if (!empty($store['default'])) {
                 $storenames[$key] = new lang_string('store_'.$key, 'cache');
-            }
-        }
-
-        $modemappings = array();
-        foreach ($instance->get_mode_mappings() as $mapping) {
-            $mode = $mapping['mode'];
-            if (!array_key_exists($mode, $modemappings)) {
-                $modemappings[$mode] = array();
-            }
-            if (array_key_exists($mapping['store'], $storenames)) {
-                $modemappings[$mode][] = $storenames[$mapping['store']];
             } else {
-                $modemappings[$mode][] = $mapping['store'];
+                $storenames[$store['name']] = $store['name'];
             }
         }
-
-        $definitionmappings = array();
-        foreach ($instance->get_definition_mappings() as $mapping) {
-            $definition = $mapping['definition'];
-            if (!array_key_exists($definition, $definitionmappings)) {
-                $definitionmappings[$definition] = array();
-            }
-            if (array_key_exists($mapping['store'], $storenames)) {
-                $definitionmappings[$definition][] = $storenames[$mapping['store']];
-            } else {
-                $definitionmappings[$definition][] = $mapping['store'];
-            }
+        /* @var cache_definition[] $definitions */
+        $definitions = array();
+        foreach ($config->get_definitions() as $key => $definition) {
+            $definitions[$key] = cache_definition::load($definition['component'].'/'.$definition['area'], $definition);
         }
-
-        $return = array();
-
         foreach ($definitions as $id => $definition) {
-
             $mappings = array();
-            if (array_key_exists($id, $definitionmappings)) {
-                $mappings = $definitionmappings[$id];
-            } else if (empty($definition['mappingsonly'])) {
-                $mappings = $modemappings[$definition['mode']];
+            foreach (cache_helper::get_stores_suitable_for_definition($definition) as $store) {
+                $mappings[] = $storenames[$store->my_name()];
             }
-
             $return[$id] = array(
                 'id' => $id,
-                'name' => cache_helper::get_definition_name($definition),
-                'mode' => $definition['mode'],
-                'component' => $definition['component'],
-                'area' => $definition['area'],
+                'name' => $definition->get_name(),
+                'mode' => $definition->get_mode(),
+                'component' => $definition->get_component(),
+                'area' => $definition->get_area(),
                 'mappings' => $mappings,
-                'sharingoptions' => self::get_definition_sharing_options($definition['sharingoptions'], false),
-                'selectedsharingoption' => self::get_definition_sharing_options($definition['selectedsharingoption'], true),
-                'userinputsharingkey' => $definition['userinputsharingkey']
+                'sharingoptions' => self::get_definition_sharing_options($definition->get_sharing_options(), false),
+                'selectedsharingoption' => self::get_definition_sharing_options($definition->get_selected_sharing_option(), true),
+                'userinputsharingkey' => $definition->get_user_input_sharing_key()
             );
         }
         return $return;
@@ -1126,7 +1099,10 @@ abstract class cache_administration_helper extends cache_helper {
      * @return array An array containing sub-arrays, one for each mode.
      */
     public static function get_default_mode_stores() {
+        global $OUTPUT;
         $instance = cache_config::instance();
+        $adequatestores = cache_helper::get_stores_suitable_for_mode_default();
+        $icon = new pix_icon('i/warning', new lang_string('inadequatestoreformapping', 'cache'));
         $storenames = array();
         foreach ($instance->get_all_stores() as $key => $store) {
             if (!empty($store['default'])) {
@@ -1149,6 +1125,9 @@ abstract class cache_administration_helper extends cache_helper {
             } else {
                 $modemappings[$mode][$mapping['store']] = $mapping['store'];
             }
+            if (!array_key_exists($mapping['store'], $adequatestores)) {
+                $modemappings[$mode][$mapping['store']] = $modemappings[$mode][$mapping['store']].' '.$OUTPUT->render($icon);
+            }
         }
         return $modemappings;
     }
index 1569da6..c71f108 100644 (file)
@@ -350,7 +350,12 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
         $lines = explode("\n", $data->servers);
         $servers = array();
         foreach ($lines as $line) {
-            $line = trim($line, ':');
+            // Trim surrounding colons and default whitespace.
+            $line = trim(trim($line), ":");
+            // Skip blank lines.
+            if ($line === '') {
+                continue;
+            }
             $servers[] = explode(':', $line, 3);
         }
         return array(
index 508628e..1bce7aa 100644 (file)
@@ -374,7 +374,12 @@ class cachestore_memcached extends cache_store implements cache_is_configurable
         $lines = explode("\n", $data->servers);
         $servers = array();
         foreach ($lines as $line) {
-            $line = trim($line, ':');
+            // Trim surrounding colons and default whitespace.
+            $line = trim(trim($line), ":");
+            // Skip blank lines.
+            if ($line === '') {
+                continue;
+            }
             $servers[] = explode(':', $line, 3);
         }
         return array(
index fd9b99e..1a87d58 100644 (file)
@@ -309,6 +309,7 @@ class core_calendar_renderer extends plugin_renderer_base {
         global $CFG;
 
         $event = calendar_add_event_metadata($event);
+        $context = $event->context;
 
         $anchor  = html_writer::tag('a', '', array('name'=>'event_'.$event->id));
 
@@ -331,7 +332,7 @@ class core_calendar_renderer extends plugin_renderer_base {
         if (!empty($event->referer)) {
             $table->data[0]->cells[1]->text .= html_writer::tag('div', $event->referer, array('class'=>'referer'));
         } else {
-            $table->data[0]->cells[1]->text .= html_writer::tag('div', $event->name, array('class'=>'name'));
+            $table->data[0]->cells[1]->text .= html_writer::tag('div', format_string($event->name, false, array('context' => $context)), array('class'=>'name'));
         }
         if (!empty($event->courselink)) {
             $table->data[0]->cells[1]->text .= html_writer::tag('div', $event->courselink, array('class'=>'course'));
@@ -355,7 +356,7 @@ class core_calendar_renderer extends plugin_renderer_base {
         $table->data[1]->cells[0] = new html_table_cell('&nbsp;');
         $table->data[1]->cells[0]->attributes['class'] .= 'side';
 
-        $table->data[1]->cells[1] = new html_table_cell($event->description);
+        $table->data[1]->cells[1] = new html_table_cell(format_text($event->description, $event->format, array('context' => $context)));
         $table->data[1]->cells[1]->attributes['class'] .= ' description';
         if (isset($event->cssclass)) {
             $table->data[1]->cells[1]->attributes['class'] .= ' '.$event->cssclass;
index 5349c53..887533b 100644 (file)
@@ -54,7 +54,7 @@ class behat_cohort extends behat_base {
         $userid = $DB->get_field('user', 'id', array('username' => $username));
 
         $steps = array(
-            new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "' . $this->escape($cohortidnumber) . '" table row'),
+            new Given('I click on "' . get_string('assign', 'cohort') . '" "link" in the "' . $this->escape($cohortidnumber) . '" "table_row"'),
             new Given('I select "' . $userid . '" from "' . get_string('potusers', 'cohort') . '"'),
             new Given('I press "' . get_string('add') . '"'),
             new Given('I press "' . get_string('backtocohorts', 'cohort') . '"')
index 47b169a..5e6a5ad 100644 (file)
@@ -32,11 +32,11 @@ Feature: Upload users to a cohort
     And I press "Upload users"
     And I press "Continue"
     And I follow "Cohorts"
-    And I click on "Assign" "link" in the "Cohort 1" table row
+    And I click on "Assign" "link" in the "Cohort 1" "table_row"
     Then the "Current users" select box should contain "Tom Jones (tomjones@example.com)"
     And the "Current users" select box should contain "Bob Jones (bobjones@example.com)"
     And I press "Back to cohorts"
-    And I click on "Assign" "link" in the "Cohort 2" table row
+    And I click on "Assign" "link" in the "Cohort 2" "table_row"
     And the "Current users" select box should contain "Mary Smith (marysmith@example.com)"
     And the "Current users" select box should contain "Alice Smith (alicesmith@example.com)"
     And I am on homepage
index 45ff5a8..1810b79 100644 (file)
@@ -8,6 +8,6 @@
     "require-dev": {
         "phpunit/phpunit": "3.7.*",
         "phpunit/dbUnit": "1.2.*",
-        "moodlehq/behat-extension": "1.26.*"
+        "moodlehq/behat-extension": "1.27.0"
     }
 }
index 08a50a0..cafa530 100644 (file)
@@ -589,10 +589,16 @@ $CFG->admin = 'admin';
 // $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.
+// To set a seperate wwwroot for Behat to use, use $CFG->behat_wwwroot; this is set automatically
+// to http://localhost:8000 as it is the proposed PHP built-in server URL. Instead of that you can,
+// for example, use an alias, add a host to /etc/hosts or add a new virtual host having a URL
+// poiting to your production site and another one poiting to your test site. Note that you need
+// to ensure that this URL is not accessible from the www as the behat test site uses "sugar"
+// credentials (admin/admin) and can be easily hackable.
+//
 // Example:
 //   $CFG->behat_wwwroot = 'http://192.168.1.250:8000';
+//   $CFG->behat_wwwroot = 'http://localhost/moodlesitetesting';
 //
 // You can override default Moodle configuration for Behat and add your own
 // params; here you can add more profiles, use different Mink drivers than Selenium...
@@ -661,6 +667,11 @@ $CFG->admin = 'admin';
 // Example:
 //   $CFG->behat_extraallowedsettings = array('logsql', 'dblogerror');
 //
+// You should explicitly allow the usage of the deprecated behat steps, otherwise an exception will
+// be thrown when using them. The setting is disabled by default.
+// Example:
+//   $CFG->behat_usedeprecated = true;
+//
 //=========================================================================
 // 12. DEVELOPER DATA GENERATOR
 //=========================================================================
index 5574dfd..b3b8a0d 100644 (file)
@@ -140,7 +140,8 @@ switch ($action) {
         $categoryid = required_param('categoryid', PARAM_INT);
         /* @var core_course_management_renderer $renderer */
         $renderer = $PAGE->get_renderer('core_course', 'management');
-        $outcome->html = html_writer::start_tag('ul', array('class' => 'ml'));
+        $outcome->html = html_writer::start_tag('ul',
+            array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoriesof'.$categoryid));
         $coursecat = coursecat::get($categoryid);
         foreach ($coursecat->get_children() as $subcat) {
             $outcome->html .= $renderer->category_listitem($subcat, array(), $subcat->get_children_count());
index 5f21e94..a26144d 100644 (file)
@@ -622,10 +622,6 @@ class helper {
         if (!$category->can_change_visibility()) {
             throw new \moodle_exception('permissiondenied', 'error', '', null, 'coursecat::can_change_visbility');
         }
-        if ((int)$category->get_parent_coursecat()->visible === 0) {
-            // You cannot mark a category visible if its parent is hidden.
-            return false;
-        }
         $category->show();
         return true;
     }
index 87609ea..688e304 100644 (file)
@@ -44,7 +44,19 @@ class core_course_management_renderer extends plugin_renderer_base {
     public function enhance_management_interface() {
         $this->page->requires->yui_module('moodle-course-management', 'M.course.management.init');
         $this->page->requires->strings_for_js(
-            array('show', 'hide', 'expand', 'collapse', 'confirmcoursemove', 'move', 'cancel', 'confirm'),
+            array(
+                'show',
+                'showcategory',
+                'hide',
+                'expand',
+                'expandcategory',
+                'collapse',
+                'collapsecategory',
+                'confirmcoursemove',
+                'move',
+                'cancel',
+                'confirm'
+            ),
             'moodle'
         );
     }
@@ -63,6 +75,8 @@ class core_course_management_renderer extends plugin_renderer_base {
             $html .= $this->heading($heading);
         }
         if ($viewmode !== null) {
+            $html .= html_writer::start_div();
+            $html .= $this->view_mode_selector(\core_course\management\helper::get_management_viewmodes(), $viewmode);
             if ($viewmode === 'courses') {
                 $categories = coursecat::make_categories_list(array('moodle/category:manage', 'moodle/course:create'));
                 $nothing = false;
@@ -73,7 +87,7 @@ class core_course_management_renderer extends plugin_renderer_base {
                 $select = new single_select($this->page->url, 'categoryid', $categories, $categoryid, $nothing);
                 $html .= $this->render($select);
             }
-            $html .= $this->view_mode_selector(\core_course\management\helper::get_management_viewmodes(), $viewmode);
+            $html .= html_writer::end_div();
         }
         $html .= html_writer::end_div();
         return $html;
@@ -183,8 +197,21 @@ class core_course_management_renderer extends plugin_renderer_base {
             'aria-expanded' => $isexpanded ? 'true' : 'false'
         );
         $text = $category->get_formatted_name();
+        if ($category->parent) {
+            $a = new stdClass;
+            $a->category = $text;
+            $a->parentcategory = $category->get_parent_coursecat()->get_formatted_name();
+            $textlabel = get_string('categorysubcategoryof', 'moodle', $a);
+        }
         $courseicon = $this->output->pix_icon('i/course', get_string('courses'));
-        $bcatinput = array('type' => 'checkbox', 'name' => 'bcat[]', 'value' => $category->id, 'class' => 'bulk-action-checkbox');
+        $bcatinput = array(
+            'type' => 'checkbox',
+            'name' => 'bcat[]',
+            'value' => $category->id,
+            'class' => 'bulk-action-checkbox',
+            'aria-label' => get_string('bulkactionselect', 'moodle', $text),
+            'data-action' => 'select'
+        );
 
         if (!$category->can_resort_subcategories() && !$category->has_manage_capability()) {
             // Very very hardcoded here.
@@ -193,14 +220,36 @@ class core_course_management_renderer extends plugin_renderer_base {
 
         $viewcaturl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
         if ($isexpanded) {
-            $icon = $this->output->pix_icon('t/switch_minus', get_string('collapse'), 'moodle', array('class' => 'tree-icon'));
-            $icon = html_writer::link($viewcaturl, $icon, array('class' => 'float-left', 'data-action' => 'collapse'));
+            $icon = $this->output->pix_icon('t/switch_minus', get_string('collapse'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
+            $icon = html_writer::link(
+                $viewcaturl,
+                $icon,
+                array(
+                    'class' => 'float-left',
+                    'data-action' => 'collapse',
+                    'title' => get_string('collapsecategory', 'moodle', $text),
+                    'aria-controls' => 'subcategoryof'.$category->id
+                )
+            );
         } else if ($isexpandable) {
-            $icon = $this->output->pix_icon('t/switch_plus', get_string('expand'), 'moodle', array('class' => 'tree-icon'));
-            $icon = html_writer::link($viewcaturl, $icon, array('class' => 'float-left', 'data-action' => 'expand'));
+            $icon = $this->output->pix_icon('t/switch_plus', get_string('expand'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
+            $icon = html_writer::link(
+                $viewcaturl,
+                $icon,
+                array(
+                    'class' => 'float-left',
+                    'data-action' => 'expand',
+                    'title' => get_string('expandcategory', 'moodle', $text)
+                )
+            );
         } else {
-            $icon = $this->output->pix_icon('i/navigationitem', '', 'moodle', array('class' => 'tree-icon'));
-            $icon = html_writer::link($viewcaturl, $icon, array('class' => 'float-left'));
+            $icon = $this->output->pix_icon(
+                'i/navigationitem',
+                '',
+                'moodle',
+                array('class' => 'tree-icon', 'title' => get_string('showcategory', 'moodle', $text))
+            );
+            $icon = html_writer::span($icon, 'float-left');
         }
         $actions = \core_course\management\helper::get_category_listitem_actions($category);
         $hasactions = !empty($actions) || $category->can_create_course();
@@ -212,10 +261,14 @@ class core_course_management_renderer extends plugin_renderer_base {
         $html .= html_writer::end_div();
         $html .= $icon;
         if ($hasactions) {
-            $html .= html_writer::link($viewcaturl, $text, array('class' => 'float-left categoryname'));
+            $textattributes = array('class' => 'float-left categoryname');
         } else {
-            $html .= html_writer::link($viewcaturl, $text, array('class' => 'float-left categoryname without-actions'));
+            $textattributes = array('class' => 'float-left categoryname without-actions');
+        }
+        if (isset($textlabel)) {
+            $textattributes['aria-label'] = $textlabel;
         }
+        $html .= html_writer::link($viewcaturl, $text, $textattributes);
         $html .= html_writer::start_div('float-right');
         if ($category->idnumber) {
             $html .= html_writer::tag('span', s($category->idnumber), array('class' => 'dimmed idnumber'));
@@ -224,16 +277,18 @@ class core_course_management_renderer extends plugin_renderer_base {
             $html .= $this->category_listitem_actions($category, $actions);
         }
         $countid = 'course-count-'.$category->id;
-        $html .= html_writer::span(get_string('courses'), 'accesshide', array('id' => $countid));
         $html .= html_writer::span(
-            html_writer::span($category->get_courses_count()).$courseicon,
+  &