Merge branch 'MDL-51719-master' of git://github.com/danpoltawski/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 22 Dec 2015 12:07:01 +0000 (13:07 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 22 Dec 2015 12:07:01 +0000 (13:07 +0100)
546 files changed:
.travis.yml
Gruntfile.js
admin/environment.xml
admin/roles/classes/define_role_table_advanced.php
admin/settings/plugins.php
admin/settings/subsystems.php
admin/tool/availabilityconditions/tests/behat/manage_conditions.feature
admin/tool/behat/tests/behat/data_generators.feature
admin/tool/uploaduser/index.php
admin/tool/uploaduser/tests/behat/upload_users.feature [moved from admin/tests/behat/upload_users.feature with 58% similarity]
auth/cas/auth.php
auth/db/tests/db_test.php
auth/email/auth.php
auth/fc/auth.php
auth/fc/fcFPP.php
auth/imap/auth.php
auth/ldap/auth.php
auth/manual/auth.php
auth/mnet/auth.php
auth/nntp/auth.php
auth/nologin/auth.php
auth/none/auth.php
auth/pam/auth.php
auth/pop3/auth.php
auth/radius/auth.php
auth/shibboleth/auth.php
auth/webservice/auth.php
availability/condition/completion/tests/behat/availability_completion.feature
availability/condition/completion/tests/behat/conditional_bug.feature
availability/condition/date/tests/behat/availability_date.feature
availability/condition/grade/tests/behat/availability_grade.feature
availability/condition/group/tests/behat/availability_group.feature
availability/condition/grouping/tests/behat/availability_grouping.feature
availability/condition/profile/tests/behat/availability_profile.feature
availability/tests/behat/display_availability.feature
availability/tests/behat/edit_availability.feature
availability/tests/info_test.php
backup/cc/cc2moodle.php
backup/cc/cc_lib/gral_lib/cssparser.php
backup/cc/entities.class.php
backup/cc/restore_cc.php
backup/util/helper/restore_log_rule.class.php
backup/util/helper/restore_logs_processor.class.php
backup/util/helper/tests/restore_log_rule_test.php [new file with mode: 0644]
backup/util/plan/backup_structure_step.class.php
backup/util/plan/restore_structure_step.class.php
backup/util/settings/tests/settings_test.php
badges/tests/behat/award_badge.feature
blocks/edit_form.php
blocks/glossary_random/block_glossary_random.php
blocks/online_users/tests/generator/lib.php
blocks/recent_activity/tests/behat/structural_changes.feature
blocks/rss_client/editfeed.php
blocks/rss_client/tests/cron_test.php
blog/edit.php
blog/edit_form.php
blog/external_blogs.php
blog/index.php
blog/lib.php
blog/locallib.php
blog/renderer.php
blog/rsslib.php
blog/tests/behat/delete.feature [new file with mode: 0644]
blog/tests/bloglib_test.php
completion/tests/behat/enable_manual_complete_mark.feature
completion/tests/behat/restrict_activity_by_date.feature
completion/tests/behat/restrict_activity_by_grade.feature
completion/tests/behat/restrict_section_availability.feature
completion/tests/behat/teacher_manual_completion.feature
course/edit_form.php
course/lib.php
course/mod.php
course/moodleform_mod.php
course/tests/behat/activities_edit_completion.feature
course/tests/behat/role_renaming.feature [new file with mode: 0644]
course/tests/courselib_test.php
course/tests/externallib_test.php
enrol/database/lib.php
enrol/externallib.php
enrol/guest/classes/external.php [new file with mode: 0644]
enrol/guest/db/services.php [new file with mode: 0644]
enrol/guest/lib.php
enrol/guest/tests/external_test.php [new file with mode: 0644]
enrol/guest/version.php
enrol/self/edit_form.php
enrol/self/lib.php
enrol/upgrade.txt
filter/local_settings_form.php
filter/tex/latex.php
grade/export/lib.php
grade/grading/form/guide/guideeditor.php
grade/grading/form/rubric/rubriceditor.php
grade/lib.php
grade/report/singleview/classes/local/ui/dropdown_attribute.php
grade/report/singleview/classes/local/ui/text_attribute.php
grade/report/singleview/js/singleview.js
install/lang/bg/admin.php
install/lang/he/admin.php
install/lang/lt/install.php
install/lang/pl/moodle.php
install/lang/ro/moodle.php
install/lang/zh_cn/moodle.php
lang/en/admin.php
lang/en/blog.php
lang/en/cache.php
lang/en/edufields.php
lang/en/grades.php
lang/en/hub.php
lang/en/moodle.php
lang/en/plagiarism.php
lang/en/repository.php
lang/en/role.php
lib/accesslib.php
lib/adminlib.php
lib/adodb/adodb-active-record.inc.php
lib/adodb/adodb-active-recordx.inc.php
lib/adodb/adodb-csvlib.inc.php
lib/adodb/adodb-datadict.inc.php
lib/adodb/adodb-error.inc.php
lib/adodb/adodb-errorhandler.inc.php
lib/adodb/adodb-errorpear.inc.php
lib/adodb/adodb-exceptions.inc.php
lib/adodb/adodb-iterator.inc.php
lib/adodb/adodb-lib.inc.php
lib/adodb/adodb-memcache.lib.inc.php
lib/adodb/adodb-pager.inc.php
lib/adodb/adodb-pear.inc.php
lib/adodb/adodb-perf.inc.php
lib/adodb/adodb-php4.inc.php
lib/adodb/adodb-time.inc.php
lib/adodb/adodb-xmlschema.inc.php
lib/adodb/adodb-xmlschema03.inc.php
lib/adodb/adodb.inc.php
lib/adodb/datadict/datadict-access.inc.php
lib/adodb/datadict/datadict-db2.inc.php
lib/adodb/datadict/datadict-firebird.inc.php
lib/adodb/datadict/datadict-generic.inc.php
lib/adodb/datadict/datadict-ibase.inc.php
lib/adodb/datadict/datadict-informix.inc.php
lib/adodb/datadict/datadict-mssql.inc.php
lib/adodb/datadict/datadict-mssqlnative.inc.php
lib/adodb/datadict/datadict-mysql.inc.php
lib/adodb/datadict/datadict-oci8.inc.php
lib/adodb/datadict/datadict-postgres.inc.php
lib/adodb/datadict/datadict-sapdb.inc.php
lib/adodb/datadict/datadict-sqlite.inc.php
lib/adodb/datadict/datadict-sybase.inc.php
lib/adodb/drivers/adodb-access.inc.php
lib/adodb/drivers/adodb-ado.inc.php
lib/adodb/drivers/adodb-ado5.inc.php
lib/adodb/drivers/adodb-ado_access.inc.php
lib/adodb/drivers/adodb-ado_mssql.inc.php
lib/adodb/drivers/adodb-ads.inc.php
lib/adodb/drivers/adodb-borland_ibase.inc.php
lib/adodb/drivers/adodb-csv.inc.php
lib/adodb/drivers/adodb-db2.inc.php
lib/adodb/drivers/adodb-db2oci.inc.php
lib/adodb/drivers/adodb-db2ora.inc.php
lib/adodb/drivers/adodb-fbsql.inc.php
lib/adodb/drivers/adodb-firebird.inc.php
lib/adodb/drivers/adodb-ibase.inc.php
lib/adodb/drivers/adodb-informix.inc.php
lib/adodb/drivers/adodb-informix72.inc.php
lib/adodb/drivers/adodb-ldap.inc.php
lib/adodb/drivers/adodb-mssql.inc.php
lib/adodb/drivers/adodb-mssql_n.inc.php
lib/adodb/drivers/adodb-mssqlnative.inc.php
lib/adodb/drivers/adodb-mssqlpo.inc.php
lib/adodb/drivers/adodb-mysql.inc.php
lib/adodb/drivers/adodb-mysqli.inc.php
lib/adodb/drivers/adodb-mysqlpo.inc.php
lib/adodb/drivers/adodb-mysqlt.inc.php
lib/adodb/drivers/adodb-netezza.inc.php
lib/adodb/drivers/adodb-oci8.inc.php
lib/adodb/drivers/adodb-oci805.inc.php
lib/adodb/drivers/adodb-oci8po.inc.php
lib/adodb/drivers/adodb-oci8quercus.inc.php
lib/adodb/drivers/adodb-odbc.inc.php
lib/adodb/drivers/adodb-odbc_db2.inc.php
lib/adodb/drivers/adodb-odbc_mssql.inc.php
lib/adodb/drivers/adodb-odbc_oracle.inc.php
lib/adodb/drivers/adodb-odbtp.inc.php
lib/adodb/drivers/adodb-odbtp_unicode.inc.php
lib/adodb/drivers/adodb-oracle.inc.php
lib/adodb/drivers/adodb-pdo.inc.php
lib/adodb/drivers/adodb-pdo_mssql.inc.php
lib/adodb/drivers/adodb-pdo_mysql.inc.php
lib/adodb/drivers/adodb-pdo_oci.inc.php
lib/adodb/drivers/adodb-pdo_pgsql.inc.php
lib/adodb/drivers/adodb-pdo_sqlite.inc.php
lib/adodb/drivers/adodb-pdo_sqlsrv.inc.php [new file with mode: 0644]
lib/adodb/drivers/adodb-postgres.inc.php
lib/adodb/drivers/adodb-postgres64.inc.php
lib/adodb/drivers/adodb-postgres7.inc.php
lib/adodb/drivers/adodb-postgres8.inc.php
lib/adodb/drivers/adodb-postgres9.inc.php
lib/adodb/drivers/adodb-proxy.inc.php
lib/adodb/drivers/adodb-sapdb.inc.php
lib/adodb/drivers/adodb-sqlanywhere.inc.php
lib/adodb/drivers/adodb-sqlite.inc.php
lib/adodb/drivers/adodb-sqlite3.inc.php
lib/adodb/drivers/adodb-sqlitepo.inc.php
lib/adodb/drivers/adodb-sybase.inc.php
lib/adodb/drivers/adodb-sybase_ase.inc.php
lib/adodb/drivers/adodb-text.inc.php [new file with mode: 0644]
lib/adodb/drivers/adodb-vfp.inc.php
lib/adodb/license.txt
lib/adodb/perf/perf-db2.inc.php
lib/adodb/perf/perf-informix.inc.php
lib/adodb/perf/perf-mssql.inc.php
lib/adodb/perf/perf-mssqlnative.inc.php
lib/adodb/perf/perf-mysql.inc.php
lib/adodb/perf/perf-oci8.inc.php
lib/adodb/perf/perf-postgres.inc.php
lib/adodb/pivottable.inc.php
lib/adodb/readme_moodle.txt
lib/adodb/rsfilter.inc.php
lib/adodb/toexport.inc.php
lib/adodb/tohtml.inc.php
lib/ajax/service.php
lib/amd/build/form-autocomplete.min.js
lib/amd/build/templates.min.js
lib/amd/src/form-autocomplete.js
lib/amd/src/templates.js
lib/behat/classes/behat_selectors.php
lib/classes/event/course_section_deleted.php [new file with mode: 0644]
lib/classes/plugininfo/calendartype.php
lib/classes/shutdown_manager.php
lib/completionlib.php
lib/componentlib.class.php
lib/db/access.php
lib/db/services.php
lib/deprecatedlib.php
lib/dml/moodle_database.php
lib/dml/moodle_transaction.php
lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-debug.js
lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button-min.js
lib/editor/atto/plugins/rtl/yui/build/moodle-atto_rtl-button/moodle-atto_rtl-button.js
lib/editor/atto/plugins/rtl/yui/src/button/js/button.js
lib/editor/tinymce/plugins/spellchecker/classes/SpellChecker.php
lib/editor/tinymce/plugins/spellchecker/classes/utils/JSON.php
lib/editor/tinymce/plugins/spellchecker/classes/utils/Logger.php
lib/editor/tinymce/plugins/spellchecker/readme_moodle.txt
lib/environmentlib.php
lib/evalmath/evalmath.class.php
lib/evalmath/readme_moodle.txt
lib/externallib.php
lib/filestorage/file_storage.php
lib/filestorage/stored_file.php
lib/filestorage/tests/file_storage_test.php
lib/filestorage/tests/fixtures/testimage.png [new file with mode: 0644]
lib/filterlib.php
lib/form/advcheckbox.php
lib/form/autocomplete.php
lib/form/button.php
lib/form/cancel.php
lib/form/checkbox.php
lib/form/dateselector.php
lib/form/datetimeselector.php
lib/form/duration.php
lib/form/editor.php
lib/form/filemanager.php
lib/form/filepicker.php
lib/form/grading.php
lib/form/group.php
lib/form/header.php
lib/form/hidden.php
lib/form/htmleditor.php
lib/form/listing.php
lib/form/modgrade.php
lib/form/modvisible.php
lib/form/password.php
lib/form/passwordunmask.php
lib/form/questioncategory.php
lib/form/radio.php
lib/form/recaptcha.php
lib/form/searchableselector.php
lib/form/select.php
lib/form/selectgroups.php
lib/form/selectwithlink.php
lib/form/selectyesno.php
lib/form/static.php
lib/form/submit.php
lib/form/submitlink.php
lib/form/tags.php
lib/form/text.php
lib/form/textarea.php
lib/form/url.php
lib/form/warning.php
lib/formslib.php
lib/graphlib.php
lib/horde/framework/Horde/Imap/Client/Socket.php
lib/horde/readme_moodle.txt
lib/installlib.php
lib/jabber/XMPP/XMLStream.php
lib/jabber/readme_moodle.txt
lib/lexer.php
lib/mathslib.php
lib/medialib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputcomponents.php
lib/outputlib.php
lib/outputrenderers.php
lib/password_compat/readme_moodle.txt
lib/password_compat/tests/PasswordHashTest.php
lib/pear/Crypt/CHAP.php
lib/pear/HTML/Common.php
lib/pear/HTML/QuickForm.php
lib/pear/HTML/QuickForm/Renderer.php
lib/pear/HTML/QuickForm/Renderer/Array.php
lib/pear/HTML/QuickForm/Renderer/Default.php
lib/pear/HTML/QuickForm/Renderer/Object.php
lib/pear/HTML/QuickForm/Renderer/Tableless.php
lib/pear/HTML/QuickForm/advcheckbox.php
lib/pear/HTML/QuickForm/autocomplete.php
lib/pear/HTML/QuickForm/button.php
lib/pear/HTML/QuickForm/checkbox.php
lib/pear/HTML/QuickForm/date.php
lib/pear/HTML/QuickForm/element.php
lib/pear/HTML/QuickForm/file.php
lib/pear/HTML/QuickForm/group.php
lib/pear/HTML/QuickForm/header.php
lib/pear/HTML/QuickForm/hidden.php
lib/pear/HTML/QuickForm/hiddenselect.php
lib/pear/HTML/QuickForm/hierselect.php
lib/pear/HTML/QuickForm/html.php
lib/pear/HTML/QuickForm/image.php
lib/pear/HTML/QuickForm/input.php
lib/pear/HTML/QuickForm/link.php
lib/pear/HTML/QuickForm/password.php
lib/pear/HTML/QuickForm/radio.php
lib/pear/HTML/QuickForm/reset.php
lib/pear/HTML/QuickForm/select.php
lib/pear/HTML/QuickForm/static.php
lib/pear/HTML/QuickForm/submit.php
lib/pear/HTML/QuickForm/text.php
lib/pear/HTML/QuickForm/textarea.php
lib/pear/HTML/QuickForm/xbutton.php
lib/pear/PEAR.php
lib/pear/README_MOODLE.txt
lib/phpexcel/PHPExcel/Shared/PCLZip/pclzip.lib.php
lib/phpexcel/PHPExcel/Worksheet/AutoFilter/Column.php
lib/phpexcel/readme_moodle.txt
lib/phpunit/classes/advanced_testcase.php
lib/phpunit/classes/basic_testcase.php
lib/phpunit/classes/database_driver_testcase.php
lib/searchlib.php
lib/setup.php
lib/setuplib.php
lib/tablelib.php
lib/testing/generator/block_generator.php
lib/testing/generator/data_generator.php
lib/testing/tests/generator_test.php
lib/tests/behat/behat_data_generators.php
lib/tests/behat/largeforms.feature [new file with mode: 0644]
lib/tests/completionlib_test.php
lib/tests/externallib_test.php
lib/tests/fixtures/max_input_vars.php [new file with mode: 0644]
lib/tests/fixtures/upload_users_profile.csv [new file with mode: 0644]
lib/tests/moodlelib_test.php
lib/tests/rsslib_test.php
lib/tests/setuplib_test.php
lib/tests/weblib_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/upgradelib.php
lib/weblib.php
message/externallib.php
message/output/airnotifier/classes/manager.php
message/tests/behat/message_participants.feature
message/tests/externallib_test.php
mnet/environment.php
mnet/peer.php
mnet/xmlrpc/client.php
mnet/xmlrpc/xmlparser.php
mod/assign/extensionform.php
mod/assign/feedback/editpdf/fpdi/ASL20.txt [deleted file]
mod/assign/feedback/editpdf/fpdi/LICENSE [new file with mode: 0644]
mod/assign/feedback/editpdf/fpdi/filters/FilterASCII85.php
mod/assign/feedback/editpdf/fpdi/filters/FilterASCII85_FPDI.php [deleted file]
mod/assign/feedback/editpdf/fpdi/filters/FilterASCIIHexDecode.php
mod/assign/feedback/editpdf/fpdi/filters/FilterLZW.php
mod/assign/feedback/editpdf/fpdi/filters/FilterLZW_FPDI.php [deleted file]
mod/assign/feedback/editpdf/fpdi/fpdf_tpl.php
mod/assign/feedback/editpdf/fpdi/fpdi.php
mod/assign/feedback/editpdf/fpdi/fpdi_bridge.php
mod/assign/feedback/editpdf/fpdi/fpdi_pdf_parser.php
mod/assign/feedback/editpdf/fpdi/pdf_context.php
mod/assign/feedback/editpdf/fpdi/pdf_parser.php
mod/assign/feedback/editpdf/fpdi/readme_moodle.txt
mod/assign/feedback/editpdf/thirdpartylibs.xml
mod/assign/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/tests/behat/grant_extension.feature
mod/book/classes/external.php
mod/chat/classes/external.php
mod/choice/classes/external.php
mod/data/export_form.php
mod/data/field/textarea/field.class.php
mod/feedback/tests/behat/show_nonrespondents.feature
mod/forum/db/services.php
mod/forum/externallib.php
mod/forum/search.php
mod/forum/tests/behat/completion_condition_number_discussions.feature
mod/forum/tests/behat/forum_subscriptions_availability.feature
mod/forum/tests/externallib_test.php
mod/forum/tests/lib_test.php
mod/forum/version.php
mod/glossary/classes/external.php [new file with mode: 0644]
mod/glossary/db/services.php [new file with mode: 0644]
mod/glossary/tests/external_test.php [new file with mode: 0644]
mod/glossary/version.php
mod/imscp/classes/external.php
mod/lesson/mod_form.php
mod/lesson/tests/behat/completion_condition_end_reached.feature
mod/lesson/tests/behat/completion_condition_time_spent.feature
mod/lesson/view.php
mod/lti/locallib.php
mod/lti/tests/locallib_test.php
mod/quiz/attemptlib.php
mod/quiz/backup/moodle2/restore_quiz_activity_task.class.php
mod/quiz/locallib.php
mod/quiz/renderer.php
mod/quiz/tests/behat/completion_condition_attempts_used.feature
mod/quiz/tests/behat/completion_condition_passing_grade.feature
mod/quiz/upgrade.txt
mod/scorm/classes/external.php
mod/scorm/datamodels/scorm_12.php
mod/scorm/datamodels/scorm_13.php
mod/scorm/datamodels/scorm_13lib.php
mod/scorm/datamodels/sequencinglib.php
mod/scorm/locallib.php
mod/scorm/report/interactions/classes/report.php
mod/scorm/report/interactions/lang/en/scormreport_interactions.php
mod/scorm/report/interactions/responsessettings_form.php
mod/scorm/report/interactions/version.php
mod/scorm/tests/externallib_test.php
mod/scorm/tests/packages/complexscorm.zip [new file with mode: 0644]
mod/wiki/classes/external.php [new file with mode: 0644]
mod/wiki/db/services.php [new file with mode: 0644]
mod/wiki/diff/diff_nwiki.php
mod/wiki/diff/difflib.php
mod/wiki/editors/wikieditor.php
mod/wiki/editors/wikifiletable.php
mod/wiki/lib.php
mod/wiki/locallib.php
mod/wiki/prettyview.php
mod/wiki/tests/externallib_test.php [new file with mode: 0644]
mod/wiki/tests/lib_test.php [new file with mode: 0644]
mod/wiki/version.php
mod/wiki/view.php
npm-shrinkwrap.json [new file with mode: 0644]
package.json
question/category_class.php
question/editlib.php
question/engine/renderer.php
question/engine/upgrade/upgradelib.php
question/import.php
question/tests/behat/behat_question.php
question/type/calculated/db/upgradelib.php
question/type/calculated/question.php
question/type/calculated/questiontype.php
question/type/calculated/tests/variablesubstituter_test.php
question/type/calculatedmulti/db/upgradelib.php
question/type/calculatedmulti/question.php
question/type/ddimageortext/questionbase.php
question/type/ddimageortext/tests/behat/preview.feature
question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-debug.js
question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd-min.js
question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-dd/moodle-qtype_ddimageortext-dd.js
question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-debug.js
question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form-min.js
question/type/ddimageortext/yui/build/moodle-qtype_ddimageortext-form/moodle-qtype_ddimageortext-form.js
question/type/ddimageortext/yui/src/ddimageortext/js/ddimageortext.js
question/type/ddimageortext/yui/src/form/js/form.js
question/type/ddmarker/tests/behat/preview.feature
question/type/ddwtos/tests/behat/preview.feature
question/type/description/question.php
question/type/essay/question.php
question/type/gapselect/questionbase.php
question/type/match/question.php
question/type/missingtype/question.php
question/type/missingtype/questiontype.php
question/type/multianswer/db/upgrade.php
question/type/multianswer/edit_multianswer_form.php
question/type/multianswer/question.php
question/type/multianswer/questiontype.php
question/type/multichoice/question.php
question/type/numerical/question.php
question/type/randomsamatch/questiontype.php
question/type/shortanswer/question.php
question/type/truefalse/question.php
question/upgrade.txt
report/outline/index.php
report/outline/lang/en/report_outline.php
report/outline/tests/behat/outline.feature
repository/filesystem/lib.php
repository/lib.php
theme/bootstrapbase/README.txt
theme/bootstrapbase/less/README
theme/bootstrapbase/readme_moodle.txt
theme/bootstrapbase/style/editor.css
theme/bootstrapbase/style/moodle.css
theme/clean/classes/core_renderer.php
theme/clean/lang/en/theme_clean.php
theme/clean/layout/columns1.php
theme/clean/layout/columns2.php
theme/clean/layout/columns3.php
theme/clean/layout/secure.php
theme/clean/lib.php
theme/clean/settings.php
theme/clean/style/custom.css
theme/clean/version.php
theme/more/lang/en/theme_more.php
theme/more/lib.php
theme/more/settings.php
theme/more/style/custom.css
theme/more/version.php
theme/upgrade.txt
user/edit_form.php
user/filters/cohort.php
user/filters/courserole.php
user/filters/date.php
user/filters/globalrole.php
user/filters/lib.php
user/filters/profilefield.php
user/filters/select.php
user/filters/simpleselect.php
user/filters/text.php
user/filters/yesno.php
user/message.html
user/messageselect.php
user/profile/field/checkbox/field.class.php
user/profile/field/menu/field.class.php
user/profile/lib.php
user/tests/behat/set_default_homepage.feature
version.php
webservice/amf/testclient/index.php
webservice/upgrade.txt
webservice/xmlrpc/lib.php
webservice/xmlrpc/locallib.php
webservice/xmlrpc/tests/fixtures/array_response.xml [new file with mode: 0644]
webservice/xmlrpc/tests/fixtures/fault_response.xml [new file with mode: 0644]
webservice/xmlrpc/tests/fixtures/value_response.xml [new file with mode: 0644]
webservice/xmlrpc/tests/lib_test.php [new file with mode: 0644]

index c462b85..08d8338 100644 (file)
@@ -12,21 +12,12 @@ notifications:
 language: php
 
 php:
-    # Moodle supports versions 5.4, 5.5, and 5.6 of PHP.
-    # Order by fastest to slowest.
-    # We currently only run the highest and lowest versions to reduce the load on travis-ci.org.
-    - 5.6
+    # We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
+    - 7.0
+    # - 5.6
     # - 5.5
     - 5.4
 
-    # We hope to offer PHP 7 support in the near future.
-    - nightly
-
-services:
-    # Ensure that memcached and mongodb are running for testing of those MUC stores.
-    - memcached
-    - mongodb
-
 env:
     # Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
     # start first so that the total run time is not too high.
@@ -50,29 +41,18 @@ matrix:
     # It will not stop the jobs from running.
     fast_finish: true
 
-    # Always allow failure on nightly.
-    # It's a nightly build and failures can happen.
-    allow_failures:
-        - php: nightly
-
     exclude:
-        # PHP 7 is not yet supported for actual runs.
-        # Exclude it by default - we include it for CITEST only later.
-        - php: nightly
-
         # MySQL - it's just too slow.
-        # Exclude it on all versions except for 5.6.
+        # Exclude it on all versions except for 7.0
+        # - env: DB=mysqli   PHPUNIT=true    INSTALL=false   CITEST=false
+        #   php: 5.6
+        #
         # - env: DB=mysqli   PHPUNIT=true    INSTALL=false   CITEST=false
         #   php: 5.5
 
         - env: DB=mysqli   PHPUNIT=true    INSTALL=false   CITEST=false
           php: 5.4
 
-    include:
-        # Attempt to run the CITEST set on PHP 7.
-        - php: nightly
-          env: DB=none     PHPUNIT=false   INSTALL=false   CITEST=true
-
 cache:
     directories:
       - $HOME/.composer/cache
@@ -86,10 +66,6 @@ install:
     # Typically it should be able to use the Composer cache if any other job has already completed before we started here.
     - travis_retry composer install --prefer-dist --no-interaction
 
-    - echo "extension = memcache.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
-    - echo "extension = memcached.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
-    - echo "extension = mongo.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
-
 before_script:
     - >
       if [ "$INSTALL" = 'true' -o "$PHPUNIT" = 'true' ];
@@ -144,9 +120,6 @@ before_script:
           sed -i \
             -e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
             -e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
-            -e "/require_once/i define('TEST_CACHESTORE_MEMCACHE_TESTSERVERS', '127.0.0.1:11211');" \
-            -e "/require_once/i define('TEST_CACHESTORE_MEMCACHED_TESTSERVERS', '127.0.0.1:11211');" \
-            -e "/require_once/i define('TEST_CACHESTORE_MONGODB_TESTSERVER', 'mongodb://localhost:27017');" \
             config.php ;
 
           # Initialise PHPUnit for Moodle.
index a3b699e..dcc22a8 100644 (file)
@@ -50,6 +50,17 @@ module.exports = function(grunt) {
                     }
                 )
             }
+        },
+        less: {
+            bootstrapbase: {
+                files: {
+                    "theme/bootstrapbase/style/moodle.css": "theme/bootstrapbase/less/moodle.less",
+                    "theme/bootstrapbase/style/editor.css": "theme/bootstrapbase/less/editor.less",
+                },
+                options: {
+                    compress: true
+                }
+           }
         }
     });
 
@@ -208,13 +219,11 @@ module.exports = function(grunt) {
             grunt.task.run('shifter');
         // Are we in an AMD directory?
         } else if (path.basename(cwd) == 'amd') {
-            grunt.task.run('jshint');
-            grunt.task.run('uglify');
+            grunt.task.run('amd');
         } else {
             // Run them all!.
-            grunt.task.run('shifter');
-            grunt.task.run('jshint');
-            grunt.task.run('uglify');
+            grunt.task.run('css');
+            grunt.task.run('js');
         }
     };
 
@@ -222,9 +231,15 @@ module.exports = function(grunt) {
     // Register NPM tasks.
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.loadNpmTasks('grunt-contrib-jshint');
+    grunt.loadNpmTasks('grunt-contrib-less');
 
-    // Register the shifter task.
+    // Register JS tasks.
     grunt.registerTask('shifter', 'Run Shifter against the current directory', tasks.shifter);
+    grunt.registerTask('amd', ['jshint', 'uglify']);
+    grunt.registerTask('js', ['amd', 'shifter']);
+
+    // Register CSS taks.
+    grunt.registerTask('css', ['less:bootstrapbase']);
 
     // Register the startup task.
     grunt.registerTask('startup', 'Run the correct tasks for the current directory', tasks.startup);
index 6847483..4bf5798 100644 (file)
       <VENDOR name="oracle" version="10.2" />
     </DATABASE>
     <PHP version="5.4.4" level="required">
-      <RESTRICT function="restrict_php_version_7" message="unsupportedphpversion7" />
     </PHP>
     <PCREUNICODE level="optional">
       <FEEDBACK>
index 06f565d..d18c144 100644 (file)
@@ -422,6 +422,12 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
         } else {
             // Updating role.
             $DB->update_record('role', $this->role);
+
+            // This will ensure the course contacts cache is purged so name changes get updated in
+            // the UI. It would be better to do this only when we know that fields affected are
+            // updated. But thats getting into the weeds of the coursecat cache and role edits
+            // should not be that frequent, so here is the ugly brutal approach.
+            coursecat::role_assignment_changed($this->role->id, context_system::instance());
         }
 
         // Assignable contexts.
index f5ea9e3..9ed5af8 100644 (file)
@@ -489,10 +489,9 @@ 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);
+    foreach (core_plugin_manager::instance()->get_plugins_of_type('calendartype') as $plugin) {
+        /** @var \core\plugininfo\calendartype $plugin */
+        $plugin->load_settings($ADMIN, 'calendartype', $hassiteconfig);
     }
 }
 
index 1eae0d0..9cae26c 100644 (file)
@@ -34,7 +34,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     // Conditional activities: completion and availability
     $optionalsubsystems->add(new admin_setting_configcheckbox('enablecompletion',
         new lang_string('enablecompletion','completion'),
-        new lang_string('configenablecompletion','completion'), 0));
+        new lang_string('configenablecompletion', 'completion'), 1));
 
     $options = array(
         1 => get_string('completionactivitydefault', 'completion'),
@@ -45,7 +45,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
 
     $optionalsubsystems->add($checkbox = new admin_setting_configcheckbox('enableavailability',
             new lang_string('enableavailability', 'availability'),
-            new lang_string('enableavailability_desc', 'availability'), 0));
+            new lang_string('enableavailability_desc', 'availability'), 1));
     $checkbox->set_affects_modinfo(true);
 
     $optionalsubsystems->add(new admin_setting_configcheckbox('enableplagiarism', new lang_string('enableplagiarism','plagiarism'), new lang_string('configenableplagiarism','plagiarism'), 0));
index 9234fee..65b0b4a 100644 (file)
@@ -8,6 +8,8 @@ Feature: Manage availability conditions
   Scenario: Display list of availability conditions
     # Check the report doesn't show when not enabled.
     Given I log in as "admin"
+    And the following config values are set as admin:
+      | enableavailability | 0 |
     And I expand "Site administration" node
     When I expand "Plugins" node
     Then I should not see "Availability restrictions"
@@ -28,8 +30,6 @@ Feature: Manage availability conditions
     Given the following "courses" exist:
       | fullname | shortname | format |
       | Course 1 | C1        | topics |
-    And the following config values are set as admin:
-      | enableavailability | 1 |
     And I log in as "admin"
     And I am on site homepage
     When I navigate to "Manage restrictions" node in "Site administration > Plugins > Availability restrictions"
index 9853ea5..0f3e3af 100644 (file)
@@ -424,9 +424,9 @@ Feature: Set up contextual data for tests
     And the following "grade categories" exist:
       | fullname         | course |
       | Grade category 1 | C1     |
-     And the following "grade items" exist:
-       | itemname                  | course | outcome | gradecategory    |
-       | Test Outcome Grade Item 1 | C1     | OT1     | Grade category 1 |
+    And the following "grade items" exist:
+      | itemname                  | course | outcome | gradecategory    |
+      | Test Outcome Grade Item 1 | C1     | OT1     | Grade category 1 |
     And the following config values are set as admin:
       | enableoutcomes | 1 |
     When I log in as "admin"
@@ -441,3 +441,15 @@ Feature: Set up contextual data for tests
     And I expand all fieldsets
     And "//div[contains(@class, 'fitem')]/div[contains(@class, 'fitemtitle')]/div[contains(@class, fstaticlabel) and contains(., 'Grade category')]/../../div[contains(@class, 'felement') and contains(., 'Grade category 1')]" "xpath_element" should exist
     And I press "Cancel"
+
+  Scenario: Add a block
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "blocks" exist:
+      | blockname    | contextlevel | reference | pagetypepattern | defaultregion |
+      | online_users | Course       | C1        | course-view-*   | site-pre      |
+    When I log in as "admin"
+    And I am on site homepage
+    And I follow "Course 1"
+    Then I should see "Online users"
index ad36657..e687fe3 100644 (file)
@@ -232,8 +232,8 @@ if ($formdata = $mform2->is_cancelled()) {
                 if (isset($USER->$key) and is_array($USER->$key)) {
                     // this must be some hacky field that is abusing arrays to store content and format
                     $user->$key = array();
-                    $user->$key['text']   = $value;
-                    $user->$key['format'] = FORMAT_MOODLE;
+                    $user->{$key['text']}   = $value;
+                    $user->{$key['format']} = FORMAT_MOODLE;
                 } else {
                     $user->$key = trim($value);
                 }
@@ -1,4 +1,4 @@
-@core @core_admin @_file_upload
+@tool @tool_uploaduser @_file_upload
 Feature: Upload users
   In order to add users to the system
   As an admin
@@ -39,3 +39,25 @@ Feature: Upload users
     And I follow "Groups"
     And I set the field "groups" to "Section 1 (1)"
     And the "members" select box should contain "Tom Jones"
+
+  @javascript
+  Scenario: Upload users with custom profile fields
+    # Create user profile field.
+    Given I log in as "admin"
+    And I navigate to "User profile fields" node in "Site administration > Users > Accounts"
+    And I set the field "datatype" to "Text area"
+    And I set the following fields to these values:
+      | Short name | superfield  |
+      | Name       | Super field |
+    And I click on "Save changes" "button"
+    # Upload users.
+    When I navigate to "Upload users" node in "Site administration > Users > Accounts"
+    And I upload "lib/tests/fixtures/upload_users_profile.csv" file to "File" filemanager
+    And I press "Upload users"
+    And I press "Upload users"
+    # Check that users were created and the superfield is filled.
+    And I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
+    And I follow "Tom Jones"
+    And I should see "Super field"
+    And I should see "The big guy"
+    And I log out
index afa87dd..4439bcb 100644 (file)
@@ -39,13 +39,23 @@ class auth_plugin_cas extends auth_plugin_ldap {
     /**
      * Constructor.
      */
-    function auth_plugin_cas() {
+    public function __construct() {
         $this->authtype = 'cas';
         $this->roleauth = 'auth_cas';
         $this->errorlogtag = '[AUTH CAS] ';
         $this->init_plugin($this->authtype);
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_cas() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     function prevent_local_passwords() {
         return true;
     }
index e619df6..03c186d 100644 (file)
@@ -309,7 +309,7 @@ class auth_db_testcase extends advanced_testcase {
         require_once($CFG->libdir.'/password_compat/lib/password.php');
         set_config('passtype', 'saltedcrypt', 'auth/db');
         $auth->config->passtype = 'saltedcrypt';
-        $user3->pass = password_hash('heslo', PASSWORD_BCRYPT, array('salt' => 'best_salt_ever_moodle_rocks_dont_tell'));
+        $user3->pass = password_hash('heslo', PASSWORD_BCRYPT);
         $DB->update_record('auth_db_users', $user3);
         $this->assertTrue($auth->user_login('u3', 'heslo'));
 
@@ -381,4 +381,22 @@ class auth_db_testcase extends advanced_testcase {
 
         $this->cleanup_auth_database();
     }
+
+    /**
+     * Testing the function _colonscope() from ADOdb.
+     */
+    public function test_adodb_colonscope() {
+        global $CFG;
+        require_once($CFG->libdir.'/adodb/adodb.inc.php');
+        require_once($CFG->libdir.'/adodb/drivers/adodb-odbc.inc.php');
+        require_once($CFG->libdir.'/adodb/drivers/adodb-db2ora.inc.php');
+
+        $this->resetAfterTest(false);
+
+        $sql = "select * from table WHERE column=:1 AND anothercolumn > :0";
+        $arr = array('b', 1);
+        list($sqlout, $arrout) = _colonscope($sql,$arr);
+        $this->assertEquals("select * from table WHERE column=? AND anothercolumn > ?", $sqlout);
+        $this->assertEquals(array(1, 'b'), $arrout);
+    }
 }
index 0a0827d..ffa0e91 100644 (file)
@@ -34,11 +34,21 @@ class auth_plugin_email extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_email() {
+    public function __construct() {
         $this->authtype = 'email';
         $this->config = get_config('auth/email');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_email() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index 75c8bd0..b987992 100644 (file)
@@ -37,11 +37,21 @@ class auth_plugin_fc extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_fc() {
+    public function __construct() {
         $this->authtype = 'fc';
         $this->config = get_config('auth/fc');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_fc() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index c082202..2adc309 100644 (file)
@@ -30,7 +30,7 @@ class fcFPP
     var $_debug = FALSE;    // set to true to see some debug info
 
     // class constructor
-    function fcFPP($host="localhost", $port="3333")
+    public function __construct($host="localhost", $port="3333")
     {
     $this->_hostname = $host;
     $this->_port = $port;
@@ -38,6 +38,12 @@ class fcFPP
     $this->_pwd = "";
     }
 
+    function fcFPP($host="localhost", $port="3333")
+    {
+           debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+           self::__construct($host, $port);
+    }
+
     // open a connection to the FirstClass server
     function open()
     {
index b0d7f9f..3e3e2da 100644 (file)
@@ -35,11 +35,21 @@ class auth_plugin_imap extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_imap() {
+    public function __construct() {
         $this->authtype = 'imap';
         $this->config = get_config('auth/imap');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_imap() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index 96d9bba..9d3a4ad 100644 (file)
@@ -143,13 +143,23 @@ class auth_plugin_ldap extends auth_plugin_base {
     /**
      * Constructor with initialisation.
      */
-    function auth_plugin_ldap() {
+    public function __construct() {
         $this->authtype = 'ldap';
         $this->roleauth = 'auth_ldap';
         $this->errorlogtag = '[AUTH LDAP] ';
         $this->init_plugin($this->authtype);
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_ldap() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index 938aae8..c6df146 100644 (file)
@@ -46,13 +46,23 @@ class auth_plugin_manual extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_manual() {
+    public function __construct() {
         $this->authtype = 'manual';
         $config = get_config(self::COMPONENT_NAME);
         $legacyconfig = get_config(self::LEGACY_COMPONENT_NAME);
         $this->config = (object)array_merge((array)$legacyconfig, (array)$config);
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_manual() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist. (Non-mnet accounts only!)
index f061539..8bd7768 100644 (file)
@@ -35,12 +35,22 @@ class auth_plugin_mnet extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_mnet() {
+    public function __construct() {
         $this->authtype = 'mnet';
         $this->config = get_config('auth_mnet');
         $this->mnet = get_mnet_environment();
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_mnet() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * This function is normally used to determine if the username and password
      * are correct for local logins. Always returns false, as local users do not
index c2ad283..9e8b24c 100644 (file)
@@ -35,11 +35,21 @@ class auth_plugin_nntp extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_nntp() {
+    public function __construct() {
         $this->authtype = 'nntp';
         $this->config = get_config('auth/nntp');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_nntp() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index c3ed391..9a1ec28 100644 (file)
@@ -35,10 +35,20 @@ class auth_plugin_nologin extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_nologin() {
+    public function __construct() {
         $this->authtype = 'nologin';
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_nologin() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Do not allow any login.
      *
index fcfce4c..c002930 100644 (file)
@@ -34,11 +34,21 @@ class auth_plugin_none extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_none() {
+    public function __construct() {
         $this->authtype = 'none';
         $this->config = get_config('auth/none');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_none() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work or don't exist and false
      * if the user exists and the password is wrong.
index fd76a09..b1e2053 100644 (file)
@@ -53,12 +53,22 @@ class auth_plugin_pam extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_pam() {
+    public function __construct() {
         $this->authtype = 'pam';
         $this->config = get_config('auth/pam');
         $this->errormessage = '';
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_pam() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index 5e25aa9..4bfaa0b 100644 (file)
@@ -35,11 +35,21 @@ class auth_plugin_pop3 extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_pop3() {
+    public function __construct() {
         $this->authtype = 'pop3';
         $this->config = get_config('auth/pop3');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_pop3() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index a74369e..24ae5d3 100644 (file)
@@ -38,11 +38,21 @@ class auth_plugin_radius extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_radius() {
+    public function __construct() {
         $this->authtype = 'radius';
         $this->config = get_config('auth/radius');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_radius() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index a4cebd8..be7c25b 100644 (file)
@@ -38,11 +38,21 @@ class auth_plugin_shibboleth extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_shibboleth() {
+    public function __construct() {
         $this->authtype = 'shibboleth';
         $this->config = get_config('auth/shibboleth');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_shibboleth() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index 1fc5694..f027f1c 100644 (file)
@@ -35,11 +35,21 @@ class auth_plugin_webservice extends auth_plugin_base {
     /**
      * Constructor.
      */
-    function auth_plugin_webservice() {
+    public function __construct() {
         $this->authtype = 'webservice';
         $this->config = get_config('auth/webservice');
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function auth_plugin_webservice() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     /**
      * Returns true if the username and password work and false if they are
      * wrong or don't exist.
index 3d95470..507ba1b 100644 (file)
@@ -16,9 +16,6 @@ Feature: availability_completion
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
       | student1 | C1     | student        |
-    And the following config values are set as admin:
-      | enableavailability  | 1 |
-      | enablecompletion | 1 |
 
   @javascript
   Scenario: Test condition
index b7f6fec..402afdd 100644 (file)
@@ -14,9 +14,6 @@ Feature: Confirm that conditions on completion no longer cause a bug
     And the following "course enrolments" exist:
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
-    And the following config values are set as admin:
-      | enableavailability | 1 |
-      | enablecompletion   | 1 |
 
   @javascript
   Scenario: Multiple completion conditions on glossary
index 925781d..161080f 100644 (file)
@@ -16,8 +16,6 @@ Feature: availability_date
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
       | student1 | C1     | student        |
-    And the following config values are set as admin:
-      | enableavailability  | 1 |
 
   @javascript
   Scenario: Test condition
index 967e7c8..9c250e1 100644 (file)
@@ -16,8 +16,6 @@ Feature: availability_grade
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
       | student1 | C1     | student        |
-    And the following config values are set as admin:
-      | enableavailability  | 1 |
 
   @javascript
   Scenario: Test condition
index d3c2b06..31d65d2 100644 (file)
@@ -16,8 +16,6 @@ Feature: availability_group
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
       | student1 | C1     | student        |
-    And the following config values are set as admin:
-      | enableavailability  | 1 |
 
   @javascript
   Scenario: Test condition
index e33b588..3c1ccb1 100644 (file)
@@ -22,8 +22,6 @@ Feature: availability_grouping
     And the following "group members" exist:
       | user     | group |
       | student1 | GI1   |
-    And the following config values are set as admin:
-      | enableavailability  | 1 |
 
   @javascript
   Scenario: Test condition
index ba207a1..2222fb7 100644 (file)
@@ -16,8 +16,6 @@ Feature: availability_profile
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
       | student1 | C1     | student        |
-    And the following config values are set as admin:
-      | enableavailability  | 1 |
 
   @javascript
   Scenario: Test condition
index ea70a05..0daeee2 100644 (file)
@@ -34,8 +34,6 @@ Feature: display_availability
       | user     | course | role           |
       | teacher1 | C1     | editingteacher |
       | student1 | C1     | student        |
-    And the following config values are set as admin:
-      | enableavailability | 1 |
 
   @javascript
   Scenario: Activity availability display
index 0af20b5..08a6f70 100644 (file)
@@ -29,6 +29,8 @@ Feature: edit_availability
       | student1 | C1     | student        |
 
   Scenario: Confirm the 'enable availability' option is working
+    Given the following config values are set as admin:
+      | enableavailability | 0 |
     When I log in as "teacher1"
     And I am on site homepage
     And I follow "Course 1"
@@ -55,9 +57,7 @@ Feature: edit_availability
   @javascript
   Scenario: Edit availability using settings in activity form
     # Set up.
-    Given the following config values are set as admin:
-      | enableavailability | 1 |
-    And I log in as "teacher1"
+    Given I log in as "teacher1"
     And I follow "Course 1"
 
     # Add a Page and check it has None in so far.
@@ -148,9 +148,7 @@ Feature: edit_availability
   @javascript
   Scenario: Edit availability using settings in section form
     # Set up.
-    Given the following config values are set as admin:
-      | enableavailability | 1 |
-    And I log in as "teacher1"
+    Given I log in as "teacher1"
     And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
@@ -170,7 +168,9 @@ Feature: edit_availability
   @javascript
   Scenario: 'Add group/grouping access restriction' button unavailable
     # Button does not exist when conditional access restrictions are turned off.
-    Given I log in as "admin"
+    Given the following config values are set as admin:
+      | enableavailability | 0 |
+    And I log in as "admin"
     And I am on site homepage
     And I follow "Course 1"
     And I turn editing mode on
@@ -181,9 +181,7 @@ Feature: edit_availability
   @javascript
   Scenario: Use the 'Add group/grouping access restriction' button
     # Button should initially be disabled.
-    Given the following config values are set as admin:
-      | enableavailability | 1 |
-    And the following "groupings" exist:
+    Given the following "groupings" exist:
       | name | course | idnumber |
       | GX1  | C1     | GXI1     |
     And I log in as "admin"
index 1477978..d349b9c 100644 (file)
@@ -45,9 +45,10 @@ class info_testcase extends advanced_testcase {
      * Tests the info_module class (is_available, get_full_information).
      */
     public function test_info_module() {
-        global $DB;
+        global $DB, $CFG;
 
         // Create a course and pages.
+        $CFG->enableavailability = 0;
         $this->setAdminUser();
         $this->resetAfterTest();
         $generator = $this->getDataGenerator();
@@ -160,6 +161,7 @@ class info_testcase extends advanced_testcase {
         global $CFG, $DB;
         require_once($CFG->dirroot . '/course/lib.php');
         $this->resetAfterTest();
+        $CFG->enableavailability = 0;
 
         // Create a course and some pages:
         // 0. Invisible due to visible=0.
index 0728dac..3b323ad 100644 (file)
@@ -144,7 +144,7 @@ class cc2moodle {
 
     public function generate_moodle_xml () {
 
-        global $CFG;
+        global $CFG, $OUTPUT;
 
         $cdir = static::$path_to_manifest_folder . DIRECTORY_SEPARATOR . 'course_files';
 
@@ -213,7 +213,7 @@ class cc2moodle {
 
         } else {
             $status = false;
-            notify('The course is empty');
+            echo $OUTPUT->notification('The course is empty');
             static::log_action('The course is empty', false);
         }
 
index 3d5653f..fc2e304 100644 (file)
@@ -18,13 +18,23 @@ class cssparser {
   private $css;
   private $html;
 
-  function cssparser($html = true) {
+  public function __construct($html = true) {
     // Register "destructor"
     core_shutdown_manager::register_function(array(&$this, "finalize"));
     $this->html = ($html != false);
     $this->Clear();
   }
 
+  /**
+   * Old syntax of class constructor. Deprecated in PHP7.
+   *
+   * @deprecated since Moodle 3.1
+   */
+  public function cssparser($html = true) {
+      debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+      self::__construct($html);
+  }
+
   function finalize() {
     unset($this->css);
   }
@@ -258,4 +268,4 @@ class cssparser {
     }
     return $result;
   }
-}
\ No newline at end of file
+}
index dfff6b2..4a8ef06 100644 (file)
@@ -198,7 +198,7 @@ class entities {
     }
 
     public function move_files($files, $destination_folder) {
-        global $CFG;
+        global $CFG, $OUTPUT;
 
         if (!empty($files)) {
 
@@ -220,7 +220,7 @@ class entities {
                 }
 
                 if (!$copy_success) {
-                    notify('WARNING: Cannot copy the file ' . $source . ' to ' . $destination);
+                    echo $OUTPUT->notification('WARNING: Cannot copy the file ' . $source . ' to ' . $destination);
                     cc2moodle::log_action('Cannot copy the file ' . $source . ' to ' . $destination, false);
                 }
             }
index 17d9170..94625fb 100644 (file)
@@ -25,6 +25,7 @@ require_once($CFG->dirroot . '/backup/cc/includes/constants.php');
 require_once($CFG->dirroot . '/backup/cc/cc2moodle.php');
 
 function cc_convert ($dir) {
+    global $OUTPUT;
 
     $manifest_file = $dir . DIRECTORY_SEPARATOR . 'imsmanifest.xml';
     $moodle_file = $dir . DIRECTORY_SEPARATOR . 'moodle.xml';
@@ -39,26 +40,26 @@ function cc_convert ($dir) {
             $detected_requirements = detect_requirements();
 
             if (!$detected_requirements["php5"]) {
-                notify(get_string('cc_import_req_php5', 'imscc'));
+                echo $OUTPUT->notification(get_string('cc_import_req_php5', 'imscc'));
                 return false;
             }
 
             if (!$detected_requirements["dom"]) {
-                notify(get_string('cc_import_req_dom', 'imscc'));
+                echo $OUTPUT->notification(get_string('cc_import_req_dom', 'imscc'));
                 return false;
             }
 
             if (!$detected_requirements["libxml"]) {
-                notify(get_string('cc_import_req_libxml', 'imscc'));
+                echo $OUTPUT->notification(get_string('cc_import_req_libxml', 'imscc'));
                 return false;
             }
 
             if (!$detected_requirements["libxmlminversion"]) {
-                notify(get_string('cc_import_req_libxmlminversion', 'imscc'));
+                echo $OUTPUT->notification(get_string('cc_import_req_libxmlminversion', 'imscc'));
                 return false;
             }
             if (!$detected_requirements["xsl"]) {
-                notify(get_string('cc_import_req_xsl', 'imscc'));
+                echo $OUTPUT->notification(get_string('cc_import_req_xsl', 'imscc'));
                 return false;
             }
 
@@ -76,17 +77,17 @@ function cc_convert ($dir) {
                     if (!$cc2moodle->is_auth()) {
                         return $cc2moodle->generate_moodle_xml();
                     } else {
-                        notify(get_string('cc2moodle_req_auth', 'imscc'));
+                        echo $OUTPUT->notification(get_string('cc2moodle_req_auth', 'imscc'));
                         return false;
                     }
 
                 } else {
-                    notify(get_string('cc2moodle_invalid_schema', 'imscc'));
+                    echo $OUTPUT->notification(get_string('cc2moodle_invalid_schema', 'imscc'));
                     return false;
                 }
 
             } else {
-                notify(get_string('cc2moodle_manifest_dont_load', 'imscc'));
+                echo $OUTPUT->notification(get_string('cc2moodle_manifest_dont_load', 'imscc'));
                 return false;
             }
         }
index bb7d4e3..6e182c0 100644 (file)
@@ -97,7 +97,10 @@ class restore_log_rule implements processable {
         return $this->module . '-' . $this->action;
     }
 
-    public function process($log) {
+    public function process($inputlog) {
+
+        // There might be multiple rules that process this log, we can't alter it in the process of checking it.
+        $log = clone($inputlog);
 
         // Reset the allpairs array
         $this->allpairs = array();
index 585d9b4..bc2c2b6 100644 (file)
@@ -89,11 +89,12 @@ class restore_logs_processor {
             }
             // Arrived here log is empty, no rule was able to perform the conversion, log the problem
             if (empty($newlog)) {
-                self::$task->log('Log module-action "' . $keyname . '" process problem. Not restored', backup::LOG_DEBUG);
+                self::$task->log('Log module-action "' . $keyname . '" process problem. Not restored. ' .
+                    json_encode($log), backup::LOG_DEBUG);
             }
 
         } else { // Action not found log the problem
-            self::$task->log('Log module-action "' . $keyname . '" unknown. Not restored', backup::LOG_DEBUG);
+            self::$task->log('Log module-action "' . $keyname . '" unknown. Not restored. '.json_encode($log), backup::LOG_DEBUG);
             $newlog = false;
 
         }
diff --git a/backup/util/helper/tests/restore_log_rule_test.php b/backup/util/helper/tests/restore_log_rule_test.php
new file mode 100644 (file)
index 0000000..03d016b
--- /dev/null
@@ -0,0 +1,52 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * @package    core_backup
+ * @category   test
+ * @copyright  2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// Include all the needed stuff
+global $CFG;
+require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
+
+
+class backup_restore_log_rule_testcase extends basic_testcase {
+
+    function test_process_keeps_log_unmodified() {
+
+        // Prepare a tiny log entry.
+        $originallog = new stdClass();
+        $originallog->url = 'original';
+        $originallog->info = 'original';
+        $log = clone($originallog);
+
+        // Process it with a tiny log rule, only modifying url and info.
+        $lr = new restore_log_rule('test', 'test', 'changed', 'changed');
+        $result = $lr->process($log);
+
+        // The log has been processed.
+        $this->assertEquals('changed', $result->url);
+        $this->assertEquals('changed', $result->info);
+
+        // But the original log has been kept unmodified by the process() call.
+        $this->assertEquals($originallog, $log);
+    }
+}
index 5d8cb55..e18ada4 100644 (file)
@@ -183,6 +183,10 @@ abstract class backup_structure_step extends backup_step {
      * @return void
      */
     protected function add_subplugin_structure($subplugintype, $element, $multiple, $plugintype = null, $pluginname = null) {
+        global $CFG;
+        // This global declaration is required, because where we do require_once($backupfile);
+        // That file may in turn try to do require_once($CFG->dirroot ...).
+        // That worked in the past, we should keep it working.
 
         // Verify if this is a BC call for an activity backup. See NOTE above for this special case.
         if ($plugintype === null and $pluginname === null) {
index de7b002..b59ac82 100644 (file)
@@ -313,6 +313,10 @@ abstract class restore_structure_step extends restore_step {
      * @return void
      */
     protected function add_subplugin_structure($subplugintype, $element, $plugintype = null, $pluginname = null) {
+        global $CFG;
+        // This global declaration is required, because where we do require_once($backupfile);
+        // That file may in turn try to do require_once($CFG->dirroot ...).
+        // That worked in the past, we should keep it working.
 
         // Verify if this is a BC call for an activity restore. See NOTE above for this special case.
         if ($plugintype === null and $pluginname === null) {
index 201d29e..45bc4ec 100644 (file)
@@ -126,6 +126,9 @@ class backp_settings_testcase extends basic_testcase {
         } catch (exception $e) {
             $this->assertTrue($e instanceof base_setting_exception);
             $this->assertEquals($e->errorcode, 'incorrect_object_passed');
+        } catch (TypeError $e) {
+            // On PHP7+ we get a TypeError raised, lets check we've the right error.
+            $this->assertRegexp('/must be an instance of backup_setting_ui/', $e->getMessage());
         }
         restore_error_handler();
 
@@ -140,6 +143,9 @@ class backp_settings_testcase extends basic_testcase {
         } catch (exception $e) {
             $this->assertTrue($e instanceof base_setting_exception);
             $this->assertEquals($e->errorcode, 'incorrect_object_passed');
+        } catch (TypeError $e) {
+            // On PHP7+ we get a TypeError raised, lets check we've the right error.
+            $this->assertRegexp('/must be an instance of backup_setting_ui/', $e->getMessage());
         }
         restore_error_handler();
 
@@ -302,6 +308,9 @@ class backp_settings_testcase extends basic_testcase {
         } catch (exception $e) {
             $this->assertTrue($e instanceof backup_setting_exception);
             $this->assertEquals($e->errorcode, 'incorrect_object_passed');
+        } catch (TypeError $e) {
+            // On PHP7+ we get a TypeError raised, lets check we've the right error.
+            $this->assertRegexp('/must be an instance of base_setting/', $e->getMessage());
         }
         restore_error_handler();
 
index 4bb0a66..0b68bd7 100644 (file)
@@ -129,8 +129,6 @@ Feature: Award badges
       | user | course | role |
       | teacher1 | C1 | editingteacher |
       | student1 | C1 | student |
-    And the following config values are set as admin:
-      | enablecompletion | 1 |
     And I log in as "teacher1"
     And I follow "Course 1"
     And I follow "Edit settings"
@@ -180,8 +178,6 @@ Feature: Award badges
       | user | course | role |
       | teacher1 | C1 | editingteacher |
       | student1 | C1 | student |
-    And the following config values are set as admin:
-      | enablecompletion | 1 |
     And I log in as "teacher1"
     And I follow "Course 1"
     And I follow "Edit settings"
index ad32113..57c9de8 100644 (file)
@@ -54,7 +54,7 @@ class block_edit_form extends moodleform {
         global $CFG;
         $this->block = $block;
         $this->page = $page;
-        parent::moodleform($actionurl);
+        parent::__construct($actionurl);
     }
 
     function definition() {
index a16d200..6ca3bb5 100644 (file)
@@ -84,14 +84,13 @@ class block_glossary_random extends block_base {
             $limitfrom = 0;
             $limitnum = 1;
 
-            $BROWSE = 'timemodified';
+            $orderby = 'timemodified ASC';
 
             switch ($this->config->type) {
 
                 case BGR_RANDOMLY:
                     $i = rand(1,$numberofentries);
                     $limitfrom = $i-1;
-                    $SORT = 'ASC';
                     break;
 
                 case BGR_NEXTONE:
@@ -104,11 +103,10 @@ class block_glossary_random extends block_base {
                         $i = 1;
                     }
                     $limitfrom = $i-1;
-                    $SORT = 'ASC';
                     break;
 
                 case BGR_NEXTALPHA:
-                    $BROWSE = 'concept';
+                    $orderby = 'concept ASC';
                     if (isset($this->config->previous)) {
                         $i = $this->config->previous + 1;
                     } else {
@@ -118,20 +116,19 @@ class block_glossary_random extends block_base {
                         $i = 1;
                     }
                     $limitfrom = $i-1;
-                    $SORT = 'ASC';
                     break;
 
                 default:  // BGR_LASTMODIFIED
                     $i = $numberofentries;
                     $limitfrom = 0;
-                    $SORT = 'DESC';
+                    $orderby = 'timemodified DESC, id DESC';
                     break;
             }
 
             if ($entry = $DB->get_records_sql("SELECT id, concept, definition, definitionformat, definitiontrust
                                                  FROM {glossary_entries}
                                                 WHERE glossaryid = ? AND approved = 1
-                                             ORDER BY $BROWSE $SORT", array($this->config->glossary), $limitfrom, $limitnum)) {
+                                             ORDER BY $orderby", array($this->config->glossary), $limitfrom, $limitnum)) {
 
                 $entry = reset($entry);
 
index a560fd5..6b721a9 100644 (file)
@@ -36,31 +36,6 @@ defined('MOODLE_INTERNAL') || die();
  */
 class block_online_users_generator extends testing_block_generator {
 
-    /**
-     * Create new block instance
-     * @param array|stdClass $record
-     * @param array $options
-     * @return stdClass activity record with extra cmid field
-     */
-    public function create_instance($record = null, array $options = null) {
-        global $DB, $CFG;
-        require_once("$CFG->dirroot/mod/page/locallib.php");
-
-        $this->instancecount++;
-
-        $record = (object)(array)$record;
-        $options = (array)$options;
-
-        $record = $this->prepare_record($record);
-
-        $id = $DB->insert_record('block_instances', $record);
-        context_block::instance($id);
-
-        $instance = $DB->get_record('block_instances', array('id'=>$id), '*', MUST_EXIST);
-
-        return $instance;
-    }
-
     /**
      * Create (simulated) logged in users and add some of them to groups in a course
      */
index 4340c60..a43dbb7 100644 (file)
@@ -46,9 +46,7 @@ Feature: View structural changes in recent activity block
       | GG3      | G2    |
 
   Scenario: Check that Added module information is displayed respecting view capability
-    Given the following config values are set as admin:
-      | enableavailability | 1 |
-    And I log in as "teacher1"
+    Given I log in as "teacher1"
     And I follow "Course 1"
     And I turn editing mode on
     When I add a "Forum" to section "1" and I fill the form with:
index 77e3097..2b6d92a 100644 (file)
@@ -36,7 +36,7 @@ class feed_edit_form extends moodleform {
     function __construct($actionurl, $isadding, $caneditshared) {
         $this->isadding = $isadding;
         $this->caneditshared = $caneditshared;
-        parent::moodleform($actionurl);
+        parent::__construct($actionurl);
     }
 
     function definition() {
index 9069c28..e1299a5 100644 (file)
@@ -40,7 +40,7 @@ class block_rss_client_cron_testcase extends advanced_testcase {
      * than the current time the attempt is skipped.
      */
     public function test_skip() {
-        global $DB;
+        global $DB, $CFG;
         $this->resetAfterTest();
         // Create a RSS feed record with a skip until time set to the future.
         $record = (object) array(
@@ -57,8 +57,12 @@ class block_rss_client_cron_testcase extends advanced_testcase {
 
         $block = new block_rss_client();
         ob_start();
+
         // Silence SimplePie php notices.
-        @$block->cron();
+        $errorlevel = error_reporting($CFG->debug & ~E_USER_NOTICE);
+        $block->cron();
+        error_reporting($errorlevel);
+
         $cronoutput = ob_get_clean();
         $this->assertContains('skipping until ' . userdate($record->skipuntil), $cronoutput);
         $this->assertContains('0 feeds refreshed (took ', $cronoutput);
@@ -68,7 +72,7 @@ class block_rss_client_cron_testcase extends advanced_testcase {
      * Test that when a feed has an error the skip time is increaed correctly.
      */
     public function test_error() {
-        global $DB;
+        global $DB, $CFG;
         $this->resetAfterTest();
         $time = time();
         // A record that has failed before.
@@ -113,8 +117,12 @@ class block_rss_client_cron_testcase extends advanced_testcase {
         // Run the cron.
         $block = new block_rss_client();
         ob_start();
+
         // Silence SimplePie php notices.
-        @$block->cron();
+        $errorlevel = error_reporting($CFG->debug & ~E_USER_NOTICE);
+        $block->cron();
+        error_reporting($errorlevel);
+
         $cronoutput = ob_get_clean();
         $skiptime1 = $record->skiptime * 2;
         $message1 = 'http://example.com/rss Error: could not load/find the RSS feed - skipping for ' . $skiptime1 . ' seconds.';
index 7ff8333..634c511 100644 (file)
@@ -132,8 +132,12 @@ if ($action === 'delete') {
             redirect($returnurl);
         }
     } else if (blog_user_can_edit_entry($entry)) {
-        $optionsyes = array('entryid'=>$id, 'action'=>'delete', 'confirm'=>1, 'sesskey'=>sesskey(), 'courseid'=>$courseid);
-        $optionsno = array('userid'=>$entry->userid, 'courseid'=>$courseid);
+        $optionsyes = array('entryid' => $id,
+                            'action' => 'delete',
+                            'confirm' => 1,
+                            'sesskey' => sesskey(),
+                            'courseid' => $courseid);
+        $optionsno = array('userid' => $entry->userid, 'courseid' => $courseid);
         $PAGE->set_title("$SITE->shortname: $strblogs");
         $PAGE->set_heading($SITE->fullname);
         echo $OUTPUT->header();
@@ -141,14 +145,15 @@ if ($action === 'delete') {
         // Output edit mode title.
         echo $OUTPUT->heading($strblogs . ': ' . get_string('deleteentry', 'blog'), 2);
 
+        echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog', format_string($entry->subject)),
+                              new moodle_url('edit.php', $optionsyes),
+                              new moodle_url('index.php', $optionsno));
+
+        echo '<br />';
         // Output the entry.
         $entry->prepare_render();
         echo $output->render($entry);
 
-        echo '<br />';
-        echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'),
-                              new moodle_url('edit.php', $optionsyes),
-                              new moodle_url('index.php', $optionsno));
         echo $OUTPUT->footer();
         die;
     }
@@ -181,9 +186,9 @@ if (!empty($entry->id)) {
 }
 
 require_once('edit_form.php');
-$summaryoptions = array('maxfiles'=> 99, 'maxbytes'=>$CFG->maxbytes, 'trusttext'=>true, 'context'=>$sitecontext,
-    'subdirs'=>file_area_contains_subdirs($sitecontext, 'blog', 'post', $entry->id));
-$attachmentoptions = array('subdirs'=>false, 'maxfiles'=> 99, 'maxbytes'=>$CFG->maxbytes);
+$summaryoptions = array('maxfiles' => 99, 'maxbytes' => $CFG->maxbytes, 'trusttext' => true, 'context' => $sitecontext,
+    'subdirs' => file_area_contains_subdirs($sitecontext, 'blog', 'post', $entry->id));
+$attachmentoptions = array('subdirs' => false, 'maxfiles' => 99, 'maxbytes' => $CFG->maxbytes);
 
 $blogeditform = new blog_edit_form(null, compact('entry',
                                                  'summaryoptions',
index 805bf79..773f153 100644 (file)
@@ -151,7 +151,7 @@ class blog_edit_form extends moodleform {
     public function validation($data, $files) {
         global $CFG, $DB, $USER;
 
-        $errors = array();
+        $errors = parent::validation($data, $files);
 
         // Validate course association.
         if (!empty($data['courseassoc'])) {
index 4b0d408..6595848 100644 (file)
@@ -94,7 +94,7 @@ if (!empty($blogs)) {
         $editurl = new moodle_url('/blog/external_blog_edit.php', array('id' => $blog->id));
         $editicon = $OUTPUT->action_icon($editurl, new pix_icon('t/edit', get_string('editexternalblog', 'blog')));
 
-        $deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey'=>sesskey()));
+        $deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey' => sesskey()));
         $deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')));
 
         $table->data[] = new html_table_row(array($blog->name,
index ddbdf45..bc3dd1e 100644 (file)
@@ -40,13 +40,13 @@ $search   = optional_param('search', null, PARAM_RAW);
 
 comment::init();
 
-$url_params = compact('id', 'start', 'tag', 'userid', 'tagid', 'modid', 'entryid', 'groupid', 'courseid', 'search');
-foreach ($url_params as $var => $val) {
+$urlparams = compact('id', 'start', 'tag', 'userid', 'tagid', 'modid', 'entryid', 'groupid', 'courseid', 'search');
+foreach ($urlparams as $var => $val) {
     if (empty($val)) {
-        unset($url_params[$var]);
+        unset($urlparams[$var]);
     }
 }
-$PAGE->set_url('/blog/index.php', $url_params);
+$PAGE->set_url('/blog/index.php', $urlparams);
 
 // Correct tagid if a text tag is provided as a param.
 if (!empty($tag)) {
@@ -63,9 +63,9 @@ if ($entryid and !isset($userid)) {
     $userid = $entry->userid;
 }
 
-if (isset($userid) && !isset($courseid)) {
+if (isset($userid) && empty($courseid)) {
     $context = context_user::instance($userid);
-} else if (isset($courseid) && $courseid != SITEID) {
+} else if (!empty($courseid) && $courseid != SITEID) {
     $context = context_course::instance($courseid);
 } else {
     $context = context_system::instance();
@@ -121,7 +121,7 @@ if (!empty($groupid) && empty($courseid)) {
 
 if (!$userid && has_capability('moodle/blog:view', $sitecontext) && $CFG->bloglevel > BLOG_USER_LEVEL) {
     if ($entryid) {
-        if (!$entryobject = $DB->get_record('post', array('id'=>$entryid))) {
+        if (!$entryobject = $DB->get_record('post', array('id' => $entryid))) {
             print_error('nosuchentry', 'blog');
         }
         $userid = $entryobject->userid;
@@ -148,12 +148,12 @@ if ((empty($courseid) ? true : $courseid == SITEID) && empty($userid)) {
         print_error('cannotviewsiteblog', 'blog');
     }
 
-    $COURSE = $DB->get_record('course', array('format'=>'site'));
+    $COURSE = $DB->get_record('course', array('format' => 'site'));
     $courseid = $COURSE->id;
 }
 
 if (!empty($courseid)) {
-    if (!$course = $DB->get_record('course', array('id'=>$courseid))) {
+    if (!$course = $DB->get_record('course', array('id' => $courseid))) {
         print_error('invalidcourseid');
     }
 
@@ -176,7 +176,7 @@ if (!empty($groupid)) {
         print_error(get_string('invalidgroupid', 'blog'));
     }
 
-    if (!$course = $DB->get_record('course', array('id'=>$group->courseid))) {
+    if (!$course = $DB->get_record('course', array('id' => $group->courseid))) {
         print_error('invalidcourseid');
     }
 
@@ -200,7 +200,7 @@ if (!empty($userid)) {
         print_error('blogdisable', 'blog');
     }
 
-    if (!$user = $DB->get_record('user', array('id'=>$userid))) {
+    if (!$user = $DB->get_record('user', array('id' => $userid))) {
         print_error('invaliduserid');
     }
 
index f99ed31..00a1ffa 100644 (file)
@@ -332,9 +332,9 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
             $userid = $page->context->instanceid;
         }
         // Check the userid var.
-        if (!is_null($userid) && $userid!==$USER->id) {
+        if (!is_null($userid) && $userid !== $USER->id) {
             // Load the user from the userid... it MUST EXIST throw a wobbly if it doesn't!
-            $user = $DB->get_record('user', array('id'=>$userid), '*', MUST_EXIST);
+            $user = $DB->get_record('user', array('id' => $userid), '*', MUST_EXIST);
         } else {
             $user = null;
         }
@@ -350,7 +350,7 @@ function blog_get_all_options(moodle_page $page, stdClass $userid = null) {
         // Get the options for the user.
         if ($user !== null and !isguestuser($user)) {
             // Load for the requested user.
-            $options[CONTEXT_USER+1] = blog_get_options_for_user($user);
+            $options[CONTEXT_USER + 1] = blog_get_options_for_user($user);
         }
         // Load for the current user.
         if (isloggedin() and !isguestuser()) {
@@ -413,7 +413,7 @@ function blog_get_options_for_user(stdClass $user=null) {
         // Not the current user, but we can view and its blogs are enabled for SITE or GLOBAL.
         $options['userentries'] = array(
             'string' => get_string('viewuserentries', 'blog', fullname($user)),
-            'link' => new moodle_url('/blog/index.php', array('userid'=>$user->id))
+            'link' => new moodle_url('/blog/index.php', array('userid' => $user->id))
         );
     } else {
         // It's the current user.
@@ -421,14 +421,14 @@ function blog_get_options_for_user(stdClass $user=null) {
             // We can view our own blogs .... BIG surprise.
             $options['view'] = array(
                 'string' => get_string('blogentries', 'blog'),
-                'link' => new moodle_url('/blog/index.php', array('userid'=>$USER->id))
+                'link' => new moodle_url('/blog/index.php', array('userid' => $USER->id))
             );
         }
         if (has_capability('moodle/blog:create', $sitecontext)) {
             // We can add to our own blog.
             $options['add'] = array(
                 'string' => get_string('addnewentry', 'blog'),
-                'link' => new moodle_url('/blog/edit.php', array('action'=>'add'))
+                'link' => new moodle_url('/blog/edit.php', array('action' => 'add'))
             );
         }
     }
@@ -560,13 +560,13 @@ function blog_get_options_for_module($module, $user=null) {
             $a->type = $modulename;
             $options['moduleview'] = array(
                 'string' => get_string('viewallmodentries', 'blog', $a),
-                'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id))
+                'link' => new moodle_url('/blog/index.php', array('modid' => $module->id))
             );
         }
         // View MY entries about this module.
         $options['moduleviewmine'] = array(
             'string' => get_string('viewmyentriesaboutmodule', 'blog', $modulename),
-            'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id, 'userid'=>$USER->id))
+            'link' => new moodle_url('/blog/index.php', array('modid' => $module->id, 'userid' => $USER->id))
         );
         if (!empty($user) && ($CFG->bloglevel >= BLOG_SITE_LEVEL)) {
             // View the given users entries about this module.
@@ -575,7 +575,7 @@ function blog_get_options_for_module($module, $user=null) {
             $a->user = fullname($user);
             $options['moduleviewuser'] = array(
                 'string' => get_string('blogentriesbyuseraboutmodule', 'blog', $a),
-                'link' => new moodle_url('/blog/index.php', array('modid'=>$module->id, 'userid'=>$user->id))
+                'link' => new moodle_url('/blog/index.php', array('modid' => $module->id, 'userid' => $user->id))
             );
         }
     }
@@ -584,7 +584,7 @@ function blog_get_options_for_module($module, $user=null) {
         // The user can blog about this module.
         $options['moduleadd'] = array(
             'string' => get_string('blogaboutthismodule', 'blog', $modulename),
-            'link' => new moodle_url('/blog/edit.php', array('action'=>'add', 'modid'=>$module->id))
+            'link' => new moodle_url('/blog/edit.php', array('action' => 'add', 'modid' => $module->id))
         );
     }
     // Cache the options.
@@ -673,7 +673,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
 
         $headers['filters']['module'] = $modid;
         // A groupid param may conflict with this coursemod's courseid. Ignore groupid in that case.
-        $courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
+        $courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
         $course = $DB->get_record('course', array('id' => $courseid));
         $cm = $DB->get_record('course_modules', array('id' => $modid));
         $cm->modname = $DB->get_field('modules', 'name', array('id' => $cm->module));
@@ -861,7 +861,7 @@ function blog_get_headers($courseid=null, $groupid=null, $userid=null, $tagid=nu
         if (!empty($tagid)) {
             $headers['filters']['tag'] = $tagid;
             $blogurl->param('tagid', $tagid);
-            $tagrec = $DB->get_record('tag', array('id'=>$tagid));
+            $tagrec = $DB->get_record('tag', array('id' => $tagid));
             $PAGE->navbar->add($tagrec->name, $blogurl);
         } else if (!empty($tag)) {
             if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
@@ -921,7 +921,7 @@ function blog_get_associated_count($courseid, $cmid=null) {
  * @package  core_blog
  * @category comment
  *
- * @param stdClass $comment_param {
+ * @param stdClass $commentparam {
  *              context  => context the context object
  *              courseid => int course id
  *              cm       => stdClass course module object
@@ -930,11 +930,11 @@ function blog_get_associated_count($courseid, $cmid=null) {
  * }
  * @return array
  */
-function blog_comment_permissions($comment_param) {
+function blog_comment_permissions($commentparam) {
     global $DB;
 
     // If blog is public and current user is guest, then don't let him post comments.
-    $blogentry = $DB->get_record('post', array('id' => $comment_param->itemid), 'publishstate', MUST_EXIST);
+    $blogentry = $DB->get_record('post', array('id' => $commentparam->itemid), 'publishstate', MUST_EXIST);
 
     if ($blogentry->publishstate != 'public') {
         if (!isloggedin() || isguestuser()) {
@@ -959,7 +959,7 @@ function blog_comment_permissions($comment_param) {
  * }
  * @return boolean
  */
-function blog_comment_validate($comment_param) {
+function blog_comment_validate($commentparam) {
     global $CFG, $DB, $USER;
 
     // Check if blogs are enabled user can comment.
@@ -968,22 +968,22 @@ function blog_comment_validate($comment_param) {
     }
 
     // Validate comment area.
-    if ($comment_param->commentarea != 'format_blog') {
+    if ($commentparam->commentarea != 'format_blog') {
         throw new comment_exception('invalidcommentarea');
     }
 
-    $blogentry = $DB->get_record('post', array('id' => $comment_param->itemid), '*', MUST_EXIST);
+    $blogentry = $DB->get_record('post', array('id' => $commentparam->itemid), '*', MUST_EXIST);
 
     // Validation for comment deletion.
-    if (!empty($comment_param->commentid)) {
-        if ($record = $DB->get_record('comments', array('id'=>$comment_param->commentid))) {
+    if (!empty($commentparam->commentid)) {
+        if ($record = $DB->get_record('comments', array('id' => $commentparam->commentid))) {
             if ($record->commentarea != 'format_blog') {
                 throw new comment_exception('invalidcommentarea');
             }
-            if ($record->contextid != $comment_param->context->id) {
+            if ($record->contextid != $commentparam->context->id) {
                 throw new comment_exception('invalidcontext');
             }
-            if ($record->itemid != $comment_param->itemid) {
+            if ($record->itemid != $commentparam->itemid) {
                 throw new comment_exception('invalidcommentitemid');
             }
         } else {
@@ -1005,10 +1005,10 @@ function blog_comment_validate($comment_param) {
  */
 function blog_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array(
-        '*'=>get_string('page-x', 'pagetype'),
-        'blog-*'=>get_string('page-blog-x', 'blog'),
-        'blog-index'=>get_string('page-blog-index', 'blog'),
-        'blog-edit'=>get_string('page-blog-edit', 'blog')
+        '*' => get_string('page-x', 'pagetype'),
+        'blog-*' => get_string('page-blog-x', 'blog'),
+        'blog-index' => get_string('page-blog-index', 'blog'),
+        'blog-edit' => get_string('page-blog-edit', 'blog')
     );
 }
 
index 114e38e..7968483 100644 (file)
@@ -112,7 +112,7 @@ class blog_entry implements renderable {
 
         $this->renderable = new StdClass();
 
-        $this->renderable->user = $DB->get_record('user', array('id'=>$this->userid));
+        $this->renderable->user = $DB->get_record('user', array('id' => $this->userid));
 
         // Entry comments.
         if (!empty($CFG->usecomments) and $CFG->blogusecomments) {
@@ -163,7 +163,7 @@ class blog_entry implements renderable {
                     $associations[$key]->contextlevel = $context->contextlevel;
 
                     // Course associations.
-                    if ($context->contextlevel ==  CONTEXT_COURSE) {
+                    if ($context->contextlevel == CONTEXT_COURSE) {
                         // TODO: performance!!!!
                         $instancename = $DB->get_field('course', 'shortname', array('id' => $context->instanceid));
 
@@ -174,7 +174,7 @@ class blog_entry implements renderable {
                     }
 
                     // Mod associations.
-                    if ($context->contextlevel ==  CONTEXT_MODULE) {
+                    if ($context->contextlevel == CONTEXT_MODULE) {
 
                         // Getting the activity type and the activity instance id.
                         $sql = 'SELECT cm.instance, m.name FROM {course_modules} cm
@@ -653,7 +653,7 @@ class blog_listing {
                 $assocexists = $DB->record_exists('blog_association', array());
 
                 // Begin permission sql clause.
-                $permissionsql =  '(p.userid = ? ';
+                $permissionsql = '(p.userid = ? ';
                 $params[] = $userid;
 
                 if ($CFG->bloglevel >= BLOG_SITE_LEVEL) { // Add permission to view site-level entries.
index 832d4b1..1045a89 100644 (file)
@@ -141,10 +141,10 @@ class core_blog_renderer extends plugin_renderer_base {
             if ($officialtags) {
                 $o .= get_string('tags', 'tag') .': '. $this->output->container($officialtags, 'officialblogtags');
                 if ($defaulttags) {
-                    $o .=  ', ';
+                    $o .= ', ';
                 }
             }
-            $o .=  $defaulttags;
+            $o .= $defaulttags;
             $o .= $this->output->container_end();
         }
 
@@ -155,7 +155,7 @@ class core_blog_renderer extends plugin_renderer_base {
             $assocstr = '';
             $coursesarray = array();
             foreach ($entry->renderable->blogassociations as $assocrec) {
-                if ($assocrec->contextlevel ==  CONTEXT_COURSE) {
+                if ($assocrec->contextlevel == CONTEXT_COURSE) {
                     $coursesarray[] = $this->output->action_icon($assocrec->url, $assocrec->icon, null, array(), true);
                 }
             }
@@ -166,7 +166,7 @@ class core_blog_renderer extends plugin_renderer_base {
             // Now show mod association.
             $modulesarray = array();
             foreach ($entry->renderable->blogassociations as $assocrec) {
-                if ($assocrec->contextlevel ==  CONTEXT_MODULE) {
+                if ($assocrec->contextlevel == CONTEXT_MODULE) {
                     $str = get_string('associated', 'blog', $assocrec->type) . ': ';
                     $str .= $this->output->action_icon($assocrec->url, $assocrec->icon, null, array(), true);
                     $modulesarray[] = $str;
index 3f26eb0..cad38d8 100644 (file)
@@ -35,7 +35,7 @@ require_once($CFG->dirroot .'/blog/lib.php');
  * @param int    $tagid        The id of the row in the tag table that identifies the RSS Feed
  * @return string
  */
-function blog_rss_get_url($contextid, $userid, $filtertype, $filterselect=0, $tagid=0) {
+function blog_rss_get_url($contextid, $userid, $filtertype, $filterselect = 0, $tagid = 0) {
     $componentname = 'blog';
 
     $additionalargs = null;
@@ -70,7 +70,7 @@ function blog_rss_get_url($contextid, $userid, $filtertype, $filterselect=0, $ta
  * @param int         $tagid        The id of the row in the tag table that identifies the RSS Feed
  * @param string      $tooltiptext  The tooltip to be displayed with the link
  */
-function blog_rss_print_link($context, $filtertype, $filterselect=0, $tagid=0, $tooltiptext='') {
+function blog_rss_print_link($context, $filtertype, $filterselect = 0, $tagid = 0, $tooltiptext = '') {
     global $CFG, $USER, $OUTPUT;
 
     if (!isloggedin()) {
@@ -93,7 +93,7 @@ function blog_rss_print_link($context, $filtertype, $filterselect=0, $tagid=0, $
  * @param int         $filterselect The id of the item defined by $filtertype
  * @param int         $tagid        The id of the row in the tag table that identifies the RSS Feed
  */
-function blog_rss_add_http_header($context, $title, $filtertype, $filterselect=0, $tagid=0) {
+function blog_rss_add_http_header($context, $title, $filtertype, $filterselect = 0, $tagid = 0) {
     global $PAGE, $USER, $CFG;
 
     if (!isloggedin()) {
@@ -168,7 +168,7 @@ function blog_rss_get_feed($context, $args) {
     $type  = clean_param($args[3], PARAM_ALPHA);
     $id = clean_param($args[4], PARAM_INT);  // Could be groupid / courseid  / userid  depending on $type.
 
-    $tagid=0;
+    $tagid = 0;
     if ($args[5] != 'rss.xml') {
         $tagid = clean_param($args[5], PARAM_INT);
     } else {
@@ -234,10 +234,10 @@ function blog_rss_get_feed($context, $args) {
 
     switch ($type) {
         case 'user':
-            $info = fullname($DB->get_record('user', array('id'=>$id), 'firstname,lastname'));
+            $info = fullname($DB->get_record('user', array('id' => $id), 'firstname,lastname'));
             break;
         case 'course':
-            $info = $DB->get_field('course', 'fullname', array('id'=>$id));
+            $info = $DB->get_field('course', 'fullname', array('id' => $id));
             $info = format_string($info, true, array('context' => context_course::instance($id)));
             break;
         case 'site':
@@ -245,7 +245,7 @@ function blog_rss_get_feed($context, $args) {
             break;
         case 'group':
             $group = groups_get_group($id);
-            $info = $group->name; // TODO: $DB->get_field('groups', 'name', array('id'=>$id)).
+            $info = $group->name; // TODO: $DB->get_field('groups', 'name', array('id' => $id)).
             break;
         default:
             $info = '';
@@ -253,7 +253,7 @@ function blog_rss_get_feed($context, $args) {
     }
 
     if ($tagid) {
-        $info .= ': '.$DB->get_field('tags', 'text', array('id'=>$tagid));
+        $info .= ': '.$DB->get_field('tags', 'text', array('id' => $tagid));
     }
 
     $header = rss_standard_header(get_string($type.'blog', 'blog', $info),
@@ -279,7 +279,7 @@ function blog_rss_get_feed($context, $args) {
  * @param int    $tagid The id of the row in the tag table that identifies the RSS Feed
  * @return string
  */
-function blog_rss_file_name($type, $id, $tagid=0) {
+function blog_rss_file_name($type, $id, $tagid = 0) {
     global $CFG;
 
     if ($tagid) {
@@ -298,7 +298,7 @@ function blog_rss_file_name($type, $id, $tagid=0) {
  * @param string $contents The contents of the RSS Feed file
  * @return bool whether the save was successful or not
  */
-function blog_rss_save_file($type, $id, $tagid=0, $contents='') {
+function blog_rss_save_file($type, $id, $tagid = 0, $contents = '') {
     global $CFG;
 
     $status = true;
diff --git a/blog/tests/behat/delete.feature b/blog/tests/behat/delete.feature
new file mode 100644 (file)
index 0000000..cd1dd5b
--- /dev/null
@@ -0,0 +1,43 @@
+@core @core_blog
+Feature: Delete a blog entry
+  In order to manage my blog entries
+  As a user
+  I need to be able to delete entries I no longer wish to appear
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email |
+      | testuser | Test | User | moodle@example.com |
+    And I log in as "testuser"
+    And I expand "Site pages" node
+    And I follow "Site blogs"
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | Blog post one |
+      | Blog entry body | User 1 blog post content |
+    And I press "Save changes"
+    And I follow "Add a new entry"
+    And I set the following fields to these values:
+      | Entry title | Blog post two |
+      | Blog entry body | User 1 blog post content |
+    And I press "Save changes"
+    And I am on site homepage
+    And I expand "Site pages" node
+    And I follow "Site blogs"
+
+  Scenario: Delete blog post results in post deleted
+    Given I follow "Blog post one"
+    And I follow "Delete"
+    And I should see "Delete the blog entry 'Blog post one'?"
+    When I press "Continue"
+    Then I should not see "Blog post one"
+    And I should see "Blog post two"
+
+  Scenario: Delete confirmation screen works and allows cancel
+    Given I follow "Blog post one"
+    When I follow "Delete"
+    Then I should see "Delete the blog entry 'Blog post one'?"
+    And I press "Cancel"
+    And I should see "Blog post one"
+    And I should see "Blog post two"
+
index a0589c2..73c81f2 100644 (file)
@@ -46,9 +46,9 @@ class core_bloglib_testcase extends advanced_testcase {
         $this->resetAfterTest();
 
         // Create default course.
-        $course = $this->getDataGenerator()->create_course(array('category'=>1, 'shortname'=>'ANON'));
+        $course = $this->getDataGenerator()->create_course(array('category' => 1, 'shortname' => 'ANON'));
         $this->assertNotEmpty($course);
-        $page = $this->getDataGenerator()->create_module('page', array('course'=>$course->id));
+        $page = $this->getDataGenerator()->create_module('page', array('course' => $course->id));
         $this->assertNotEmpty($page);
 
         // Create default group.
@@ -58,7 +58,11 @@ class core_bloglib_testcase extends advanced_testcase {
         $group->id = $DB->insert_record('groups', $group);
 
         // Create default user.
-        $user = $this->getDataGenerator()->create_user(array('username'=>'testuser', 'firstname'=>'Jimmy', 'lastname'=>'Kinnon'));
+        $user = $this->getDataGenerator()->create_user(array(
+                'username' => 'testuser',
+                'firstname' => 'Jimmy',
+                'lastname' => 'Kinnon'
+        ));
 
         // Create default tag.
         $tag = new stdClass();
@@ -91,35 +95,35 @@ class core_bloglib_testcase extends advanced_testcase {
         // Try all the filters at once: Only the entry filter is active.
         $filters = array('site' => $SITE->id, 'course' => $this->courseid, 'module' => $this->cmid,
             'group' => $this->groupid, 'user' => $this->userid, 'tag' => $this->tagid, 'entry' => $this->postid);
-        $blog_listing = new blog_listing($filters);
-        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('module', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('user', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('tag', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('entry', $blog_listing->filters));
+        $bloglisting = new blog_listing($filters);
+        $this->assertFalse(array_key_exists('site', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('course', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('module', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('group', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('user', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('tag', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('entry', $bloglisting->filters));
 
         // Again, but without the entry filter: This time, the tag, user and module filters are active.
         $filters = array('site' => $SITE->id, 'course' => $this->courseid, 'module' => $this->cmid,
             'group' => $this->groupid, 'user' => $this->userid, 'tag' => $this->postid);
-        $blog_listing = new blog_listing($filters);
-        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('module', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('user', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
+        $bloglisting = new blog_listing($filters);
+        $this->assertFalse(array_key_exists('site', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('course', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('group', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('module', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('user', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('tag', $bloglisting->filters));
 
         // We should get the same result by removing the 3 inactive filters: site, course and group.
         $filters = array('module' => $this->cmid, 'user' => $this->userid, 'tag' => $this->tagid);
-        $blog_listing = new blog_listing($filters);
-        $this->assertFalse(array_key_exists('site', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('course', $blog_listing->filters));
-        $this->assertFalse(array_key_exists('group', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('module', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('user', $blog_listing->filters));
-        $this->assertTrue(array_key_exists('tag', $blog_listing->filters));
+        $bloglisting = new blog_listing($filters);
+        $this->assertFalse(array_key_exists('site', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('course', $bloglisting->filters));
+        $this->assertFalse(array_key_exists('group', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('module', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('user', $bloglisting->filters));
+        $this->assertTrue(array_key_exists('tag', $bloglisting->filters));
 
     }
 
index 93ba976..75a11a2 100644 (file)
@@ -17,9 +17,6 @@ Feature: Allow students to manually mark an activity as complete
       | user | course | role |
       | teacher1 | C1 | editingteacher |
       | student1 | C1 | student |
-    And the following config values are set as admin:
-      | enablecompletion | 1 |
-      | enableavailability | 1 |
     And I log in as "teacher1"
     And I am on site homepage
     And I follow "Course 1"
index fc3033d..5d19955 100644 (file)
@@ -16,8 +16,6 @@ Feature: Restrict activity availability through date conditions
       | user | course | role |
       | teacher1 | C1 | editingteacher |
       | student1 | C1 | student |
-    And the following config values are set as admin:
-      | enableavailability | 1 |
     And I log in as "teacher1"
     And I am on site homepage
     And I follow "Course 1"
index 3b0a60f..27fa423 100644 (file)
@@ -17,8 +17,6 @@ Feature: Restrict activity availability through grade conditions
       | user | course | role |
       | teacher1 | C1 | editingteacher |
       | student1 | C1 | student |
-    And the following config values are set as admin:
-      | enableavailability | 1 |
     And I log in as "teacher1"
     #And I am on site homepage
     And I follow "Course 1"
index 436c63d..3a74723 100644 (file)
@@ -16,9 +16,6 @@ Feature: Restrict sections availability through completion or grade conditions
       | user | course | role |
       | teacher1 | C1 | editingteacher |
       | student1 | C1 | student |
-    And the following config values are set as admin:
-      | enablecompletion   | 1 |
-      | enableavailability | 1 |
 
   @javascript
   Scenario: Show section greyed-out to student when completion condition is not satisfied
index 3b8c4d4..0a73901 100644 (file)
@@ -16,11 +16,7 @@ Feature: Allow teachers to manually mark users as complete when configured
       | user     | course | role           |
       | student1 | CC1    | student        |
       | teacher1 | CC1    | editingteacher |
-    And the following config values are set as admin:
-      | enablecompletion | 1 |
     And I log in as "admin"
-    And I set the following administration settings values:
-      | Enable completion tracking | 1 |
     And I am on site homepage
     And I follow "Completion course"
     And completion tracking is "Enabled" in current course
@@ -41,12 +37,9 @@ Feature: Allow teachers to manually mark users as complete when configured
     And I follow "View course report"
     And I should see "Student First"
     And I follow "Click to mark user complete"
-    # Running cron just after clicking sometimes fail, so navigate back
-    # and ensure the student completion is updated before running cron.
-    And I am on site homepage
-    And I follow "Completion course"
-    And I follow "View course report"
-    And "//img[contains(@alt, 'Completed')]" "xpath_element" should exist in the "student1" "table_row"
+    # Running cron just after clicking sometimes fail, as record
+    # should be created before the cron runs.
+    And I wait "1" seconds
     And I trigger cron
     And I am on site homepage
     And I log out
index 6e0ed50..94d260c 100644 (file)
@@ -288,16 +288,19 @@ class course_edit_form extends moodleform {
         $options[0] = get_string('none');
         $mform->addElement('select', 'defaultgroupingid', get_string('defaultgrouping', 'group'), $options);
 
-        // Customizable role names in this course.
-        $mform->addElement('header','rolerenaming', get_string('rolerenaming'));
-        $mform->addHelpButton('rolerenaming', 'rolerenaming');
-
-        if ($roles = get_all_roles()) {
-            $roles = role_fix_names($roles, null, ROLENAME_ORIGINAL);
-            $assignableroles = get_roles_for_contextlevels(CONTEXT_COURSE);
-            foreach ($roles as $role) {
-                $mform->addElement('text', 'role_'.$role->id, get_string('yourwordforx', '', $role->localname));
-                $mform->setType('role_'.$role->id, PARAM_TEXT);
+        if ((empty($course->id) && guess_if_creator_will_have_course_capability('moodle/course:renameroles', $categorycontext))
+                || (!empty($course->id) && has_capability('moodle/course:renameroles', $coursecontext))) {
+            // Customizable role names in this course.
+            $mform->addElement('header', 'rolerenaming', get_string('rolerenaming'));
+            $mform->addHelpButton('rolerenaming', 'rolerenaming');
+
+            if ($roles = get_all_roles()) {
+                $roles = role_fix_names($roles, null, ROLENAME_ORIGINAL);
+                $assignableroles = get_roles_for_contextlevels(CONTEXT_COURSE);
+                foreach ($roles as $role) {
+                    $mform->addElement('text', 'role_' . $role->id, get_string('yourwordforx', '', $role->localname));
+                    $mform->setType('role_' . $role->id, PARAM_TEXT);
+                }
             }
         }
 
index ba830ca..21c4481 100644 (file)
@@ -1842,7 +1842,40 @@ function move_section_to($course, $section, $destination, $ignorenumsections = f
  * @return bool whether section was deleted
  */
 function course_delete_section($course, $section, $forcedeleteifnotempty = true) {
-    return course_get_format($course)->delete_section($section, $forcedeleteifnotempty);
+    global $DB;
+
+    // Prepare variables.
+    $courseid = (is_object($course)) ? $course->id : (int)$course;
+    $sectionnum = (is_object($section)) ? $section->section : (int)$section;
+    $section = $DB->get_record('course_sections', array('course' => $courseid, 'section' => $sectionnum));
+    if (!$section) {
+        // No section exists, can't proceed.
+        return false;
+    }
+    $format = course_get_format($course);
+    $sectionname = $format->get_section_name($section);
+
+    // Delete section.
+    $result = $format->delete_section($section, $forcedeleteifnotempty);
+
+    // Trigger an event for course section deletion.
+    if ($result) {
+        $context = context_course::instance($courseid);
+        $event = \core\event\course_section_deleted::create(
+                array(
+                    'objectid' => $section->id,
+                    'courseid' => $courseid,
+                    'context' => $context,
+                    'other' => array(
+                        'sectionnum' => $section->section,
+                        'sectionname' => $sectionname,
+                    )
+                )
+            );
+        $event->add_record_snapshot('course_sections', $section);
+        $event->trigger();
+    }
+    return $result;
 }
 
 /**
@@ -2486,6 +2519,8 @@ function save_local_role_names($courseid, $data) {
             $rolename->name = $value;
             $DB->insert_record('role_names', $rolename);
         }
+        // This will ensure the course contacts cache is purged..
+        coursecat::role_assignment_changed($roleid, $context);
     }
 }
 
index 3247db4..9c23493 100644 (file)
@@ -106,7 +106,8 @@ if (!empty($add)) {
         $optionsyes = array('confirm'=>1, 'delete'=>$cm->id, 'sesskey'=>sesskey(), 'sr' => $sectionreturn);
 
         $strdeletecheck = get_string('deletecheck', '', $fullmodulename);
-        $strdeletecheckfull = get_string('deletecheckfull', '', "$fullmodulename '$cm->name'");
+        $strparams = (object)array('type' => $fullmodulename, 'name' => $cm->name);
+        $strdeletechecktypename = get_string('deletechecktypename', '', $strparams);
 
         $PAGE->set_pagetype('mod-' . $cm->modname . '-delete');
         $PAGE->set_title($strdeletecheck);
@@ -117,7 +118,7 @@ if (!empty($add)) {
         echo $OUTPUT->box_start('noticebox');
         $formcontinue = new single_button(new moodle_url("$CFG->wwwroot/course/mod.php", $optionsyes), get_string('yes'));
         $formcancel = new single_button($return, get_string('no'), 'get');
-        echo $OUTPUT->confirm($strdeletecheckfull, $formcontinue, $formcancel);
+        echo $OUTPUT->confirm($strdeletechecktypename, $formcontinue, $formcancel);
         echo $OUTPUT->box_end();
         echo $OUTPUT->footer();
 
index 4c8c25f..690dda8 100644 (file)
@@ -58,7 +58,7 @@ abstract class moodleform_mod extends moodleform {
     /** @var object The course format of the current course. */
     protected $courseformat;
 
-    function moodleform_mod($current, $section, $cm, $course) {
+    public function __construct($current, $section, $cm, $course) {
         global $CFG;
 
         $this->current   = $current;
@@ -83,7 +83,17 @@ abstract class moodleform_mod extends moodleform {
         }
         $this->_modname = $matches[1];
         $this->init_features();
-        parent::moodleform('modedit.php');
+        parent::__construct('modedit.php');
+    }
+
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function moodleform_mod($current, $section, $cm, $course) {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct($current, $section, $cm, $course);
     }
 
     protected function init_features() {
index b264ea4..50878cc 100644 (file)
@@ -8,8 +8,6 @@ Feature: Edit completion settings of an activity
     Given the following "courses" exist:
       | fullname | shortname | enablecompletion |
       | Course 1 | C1        | 1                |
-    And the following config values are set as admin:
-      | enablecompletion | 1 |
     And I log in as "admin"
     And I am on site homepage
     And I follow "Course 1"
diff --git a/course/tests/behat/role_renaming.feature b/course/tests/behat/role_renaming.feature
new file mode 100644 (file)
index 0000000..7384c4c
--- /dev/null
@@ -0,0 +1,43 @@
+@core @core_course
+Feature: Rename roles in a course
+  In order to account for course-level differences
+  As a teacher
+  I need to be able to rename roles
+
+  Background:
+    Given the following "users" exist:
+      | username | firstname | lastname | email                |
+      | student1 | Student   | 1        | student1@example.com |
+      | teacher1 | Teacher   | 1        | teacher1@example.com |
+    And the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | student1 | C1     | student        |
+      | teacher1 | C1     | editingteacher |
+
+  Scenario: Teacher can rename roles
+    Given I log in as "teacher1"
+    And I follow "Course 1"
+    And I click on "Edit settings" "link" in the "Administration" "block"
+    And I should see "Role renaming"
+    When I set the following fields to these values:
+      | Your word for 'Teacher' | Lecturer |
+      | Your word for 'Student' | Learner  |
+    And I press "Save and display"
+    And I navigate to "Enrolled users" node in "Course administration > Users"
+    Then I should see "Lecturer" in the "Teacher 1" "table_row"
+    And I should see "Learner" in the "Student 1" "table_row"
+
+  Scenario: Ability to rename roles can be prevented
+    Given I log in as "admin"
+    And I set the following system permissions of "Teacher" role:
+      | capability         | permission |
+      | moodle/course:renameroles | Inherit |
+    And I follow "Log out"
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I click on "Edit settings" "link" in the "Administration" "block"
+    Then I should not see "Role renaming"
+    And I should not see "Your word for 'Teacher'"
index 110b0c4..421b1e4 100644 (file)
@@ -2009,6 +2009,44 @@ class core_course_courselib_testcase extends advanced_testcase {
         $this->assertEventContextNotUsed($event);
     }
 
+    /**
+     * Test that triggering a course_section_deleted event works as expected.
+     */
+    public function test_course_section_deleted_event() {
+        global $USER, $DB;
+        $this->resetAfterTest();
+        $sink = $this->redirectEvents();
+
+        // Create the course with sections.
+        $course = $this->getDataGenerator()->create_course(array('numsections' => 10), array('createsections' => true));
+        $sections = $DB->get_records('course_sections', array('course' => $course->id));
+        $coursecontext = context_course::instance($course->id);
+        $section = array_pop($sections);
+        course_delete_section($course, $section);
+        $events = $sink->get_events();
+        $event = array_pop($events); // Delete section event.
+        $sink->close();
+
+        // Validate event data.
+        $this->assertInstanceOf('\core\event\course_section_deleted', $event);
+        $this->assertEquals('course_sections', $event->objecttable);
+        $this->assertEquals($section->id, $event->objectid);
+        $this->assertEquals($course->id, $event->courseid);
+        $this->assertEquals($coursecontext->id, $event->contextid);
+        $this->assertEquals($section->section, $event->other['sectionnum']);
+        $expecteddesc = "The user with id '{$event->userid}' deleted section number '{$event->other['sectionnum']}' " .
+                "(section name '{$event->other['sectionname']}') for the course with id '{$event->courseid}'";
+        $this->assertEquals($expecteddesc, $event->get_description());
+        $this->assertEquals($section, $event->get_record_snapshot('course_sections', $event->objectid));
+        $this->assertNull($event->get_url());
+
+        // Test legacy data.
+        $sectionnum = $section->section;
+        $expectedlegacydata = array($course->id, "course", "delete section", 'view.php?id=' . $course->id, $sectionnum);
+        $this->assertEventLegacyLogData($expectedlegacydata, $event);
+        $this->assertEventContextNotUsed($event);
+    }
+
     public function test_course_integrity_check() {
         global $DB;
 
index e443b33..c5a6464 100644 (file)
@@ -1041,9 +1041,7 @@ class core_course_externallib_testcase extends externallib_advanced_testcase {
                     $this->assertEquals($course2['forcetheme'], $courseinfo->theme);
                 }
 
-                if (completion_info::is_enabled_for_site()) {
-                    $this->assertEquals($course2['enabledcompletion'], $courseinfo->enablecompletion);
-                }
+                $this->assertEquals($course2['enablecompletion'], $courseinfo->enablecompletion);
             } else if ($course['id'] == $course1['id']) {
                 $this->assertEquals($course1['fullname'], $courseinfo->fullname);
                 $this->assertEquals($course1['shortname'], $courseinfo->shortname);
index c22c65e..d25e14a 100644 (file)
@@ -264,9 +264,9 @@ class enrol_database_plugin extends enrol_plugin {
                   FROM {enrol} e
                   JOIN {course} c ON c.id = e.courseid
                   JOIN {role_assignments} ra ON ra.itemid = e.id
-             LEFT JOIN {user_enrolments} ue ON ue.enrolid = e.id
+             LEFT JOIN {user_enrolments} ue ON ue.enrolid = e.id AND ue.userid = ra.userid
                  WHERE ra.userid = :userid AND e.enrol = 'database'";
-        $rs = $DB->get_recordset_sql($sql, array('userid'=>$user->id));
+        $rs = $DB->get_recordset_sql($sql, array('userid' => $user->id));
         foreach ($rs as $instance) {
             if (!$instance->cvisible and $ignorehidden) {
                 continue;
index 7e64f21..331ee3d 100644 (file)
@@ -385,7 +385,10 @@ class core_enrol_external extends external_api {
                             * onlyactive (integer) return only users with active enrolments and matching time restrictions. This option requires \'moodle/course:enrolreview\' on the course context.
                             * userfields (\'string, string, ...\') return only the values of these user fields.
                             * limitfrom (integer) sql limit from.
-                            * limitnumber (integer) maximum number of returned users.', VALUE_DEFAULT, array()),
+                            * limitnumber (integer) maximum number of returned users.
+                            * sortby (string) sort by id, firstname or lastname. For ordering like the site does, use siteorder.
+                            * sortdirection (string) ASC or DESC',
+                            VALUE_DEFAULT, array()),
             )
         );
     }
@@ -417,6 +420,9 @@ class core_enrol_external extends external_api {
         $userfields     = array();
         $limitfrom = 0;
         $limitnumber = 0;
+        $sortby = 'us.id';
+        $sortparams = array();
+        $sortdirection = 'ASC';
         foreach ($options as $option) {
             switch ($option['name']) {
             case 'withcapability':
@@ -440,6 +446,26 @@ class core_enrol_external extends external_api {
             case 'limitnumber' :
                 $limitnumber = clean_param($option['value'], PARAM_INT);
                 break;
+            case 'sortby':
+                $sortallowedvalues = array('id', 'firstname', 'lastname', 'siteorder');
+                if (!in_array($option['value'], $sortallowedvalues)) {
+                    throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $option['value'] . '),' .
+                        'allowed values are: ' . implode(',', $sortallowedvalues));
+                }
+                if ($option['value'] == 'siteorder') {
+                    list($sortby, $sortparams) = users_order_by_sql('us');
+                } else {
+                    $sortby = 'us.' . $option['value'];
+                }
+                break;
+            case 'sortdirection':
+                $sortdirection = strtoupper($option['value']);
+                $directionallowedvalues = array('ASC', 'DESC');
+                if (!in_array($sortdirection, $directionallowedvalues)) {
+                    throw new invalid_parameter_exception('Invalid value for sortdirection parameter
+                        (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues));
+                }
+                break;
             }
         }
 
@@ -503,7 +529,8 @@ class core_enrol_external extends external_api {
                         FROM {user} u $ctxjoin $groupjoin
                        WHERE u.id IN ($enrolledsql)
                   ) q ON q.id = us.id
-                ORDER BY us.id ASC";
+                ORDER BY $sortby $sortdirection";
+        $enrolledparams = array_merge($enrolledparams, $sortparams);
         $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
         $users = array();
         foreach ($enrolledusers as $user) {
diff --git a/enrol/guest/classes/external.php b/enrol/guest/classes/external.php
new file mode 100644 (file)
index 0000000..a441ef8
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Guest enrolment method external API
+ *
+ * @package    enrol_guest
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.1
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+require_once($CFG->libdir . '/externallib.php');
+require_once($CFG->libdir . '/enrollib.php');
+
+/**
+ * Guest enrolment method external API
+ *
+ * @package    enrol_guest
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.1
+ */
+class enrol_guest_external extends external_api {
+
+    /**
+     * Returns description of get_instance_info() parameters.
+     *
+     * @return external_function_parameters
+     * @since Moodle 3.1
+     */
+    public static function get_instance_info_parameters() {
+        return new external_function_parameters(
+                array('instanceid' => new external_value(PARAM_INT, 'Instance id of guest enrolment plugin.'))
+            );
+    }
+
+    /**
+     * Return guest enrolment instance information.
+     *
+     * @param int $instanceid instance id of guest enrolment plugin.
+     * @return array warnings and instance information.
+     * @since Moodle 3.1
+     */
+    public static function get_instance_info($instanceid) {
+        global $DB;
+
+        $params = self::validate_parameters(self::get_instance_info_parameters(), array('instanceid' => $instanceid));
+        $warnings = array();
+
+        // Retrieve guest enrolment plugin.
+        $enrolplugin = enrol_get_plugin('guest');
+        if (empty($enrolplugin)) {
+            throw new moodle_exception('invaliddata', 'error');
+        }
+
+        require_login(null, false, null, false, true);
+        $enrolinstance = $DB->get_record('enrol', array('id' => $params['instanceid']), '*', MUST_EXIST);
+
+        $course = $DB->get_record('course', array('id' => $enrolinstance->courseid), '*', MUST_EXIST);
+        $context = context_course::instance($course->id);
+        if (!$course->visible and !has_capability('moodle/course:viewhiddencourses', $context)) {
+            throw new moodle_exception('coursehidden');
+        }
+
+        $instanceinfo = $enrolplugin->get_enrol_info($enrolinstance);
+        // Specific instance information.
+        $instanceinfo->passwordrequired = $instanceinfo->requiredparam->passwordrequired;
+
+        unset($instanceinfo->requiredparam);
+
+        $result = array();
+        $result['instanceinfo'] = $instanceinfo;
+        $result['warnings'] = $warnings;
+        return $result;
+    }
+
+    /**
+     * Returns description of get_instance_info() result value.
+     *
+     * @return external_description
+     * @since Moodle 3.1
+     */
+    public static function get_instance_info_returns() {
+        return new external_single_structure(
+            array(
+                'instanceinfo' => new external_single_structure(
+                    array(
+                        'id' => new external_value(PARAM_INT, 'Id of course enrolment instance'),
+                        'courseid' => new external_value(PARAM_INT, 'Id of course'),
+                        'type' => new external_value(PARAM_PLUGIN, 'Type of enrolment plugin'),
+                        'name' => new external_value(PARAM_RAW, 'Name of enrolment plugin'),
+                        'status' => new external_value(PARAM_BOOL, 'Is the enrolment enabled?'),
+                        'passwordrequired' => new external_value(PARAM_BOOL, 'Is a password required?'),
+                    )
+                ),
+                'warnings' => new external_warnings()
+            )
+        );
+    }
+
+}
diff --git a/enrol/guest/db/services.php b/enrol/guest/db/services.php
new file mode 100644 (file)
index 0000000..9127483
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Guest enrolment external functions and service definitions.
+ *
+ * @package    enrol_guest
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.1
+ */
+
+$functions = array(
+
+    'enrol_guest_get_instance_info' => array(
+        'classname'   => 'enrol_guest_external',
+        'methodname'  => 'get_instance_info',
+        'description' => 'Return guest enrolment instance information.',
+        'type'        => 'read'
+    ),
+);
index 7c0bfd2..51e2edb 100644 (file)
@@ -391,4 +391,32 @@ class enrol_guest_plugin extends enrol_plugin {
         $fields['status']          = $this->get_config('status');
         return $fields;
     }
+
+    /**
+     * Return information for enrolment instance containing list of parameters required
+     * for enrolment, name of enrolment plugin etc.
+     *
+     * @param stdClass $instance enrolment instance
+     * @return stdClass instance info.
+     * @since Moodle 3.1
+     */
+    public function get_enrol_info(stdClass $instance) {
+
+        $instanceinfo = new stdClass();
+        $instanceinfo->id = $instance->id;
+        $instanceinfo->courseid = $instance->courseid;
+        $instanceinfo->type = $this->get_name();
+        $instanceinfo->name = $this->get_instance_name($instance);
+        $instanceinfo->status = $instance->status == ENROL_INSTANCE_ENABLED;
+
+        // Specifics enrolment method parameters.
+        $instanceinfo->requiredparam = new stdClass();
+        $instanceinfo->requiredparam->passwordrequired = !empty($instance->password);
+
+        // If the plugin is enabled, return the URL for obtaining more information.
+        if ($instanceinfo->status) {
+            $instanceinfo->wsfunction = 'enrol_guest_get_instance_info';
+        }
+        return $instanceinfo;
+    }
 }
diff --git a/enrol/guest/tests/external_test.php b/enrol/guest/tests/external_test.php
new file mode 100644 (file)
index 0000000..91193af
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Self enrol external PHPunit tests
+ *
+ * @package   enrol_guest
+ * @copyright 2015 Juan Leyva <juan@moodle.com>
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since     Moodle 3.1
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+
+require_once($CFG->dirroot . '/webservice/tests/helpers.php');
+
+/**
+ * Guest enrolment external functions tests
+ *
+ * @package    enrol_guest
+ * @category   external
+ * @copyright  2015 Juan Leyva <juan@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @since      Moodle 3.1
+ */
+class enrol_guest_external_testcase extends externallib_advanced_testcase {
+
+    /**
+     * Test get_instance_info
+     */
+    public function test_get_instance_info() {
+        global $DB;
+
+        $this->resetAfterTest(true);
+
+        // Check if guest enrolment plugin is enabled.
+        $guestplugin = enrol_get_plugin('guest');
+        $this->assertNotEmpty($guestplugin);
+
+        $studentrole = $DB->get_record('role', array('shortname' => 'student'));
+
+        $coursedata = new stdClass();
+        $coursedata->visible = 0;
+        $course = self::getDataGenerator()->create_course($coursedata);
+
+        $student = self::getDataGenerator()->create_user();
+        $this->getDataGenerator()->enrol_user($student->id, $course->id, $studentrole->id, 'manual');
+
+        // Add enrolment methods for course.
+        $instance = $guestplugin->add_instance($course, array('status' => ENROL_INSTANCE_ENABLED,
+                                                                'name' => 'Test instance',
+                                                                'customint6' => 1,
+                                                                'roleid' => $studentrole->id));
+
+        $this->setAdminUser();
+        $result = enrol_guest_external::get_instance_info($instance);
+        $result = external_api::clean_returnvalue(enrol_guest_external::get_instance_info_returns(), $result);
+
+        $this->assertEquals($instance, $result['instanceinfo']['id']);
+        $this->assertEquals($course->id, $result['instanceinfo']['courseid']);
+        $this->assertEquals('guest', $result['instanceinfo']['type']);
+        $this->assertEquals('Test instance', $result['instanceinfo']['name']);
+        $this->assertTrue($result['instanceinfo']['status']);
+        $this->assertFalse($result['instanceinfo']['passwordrequired']);
+
+        $DB->set_field('enrol', 'status', ENROL_INSTANCE_DISABLED, array('id' => $instance));
+
+        $result = enrol_guest_external::get_instance_info($instance);
+        $result = external_api::clean_returnvalue(enrol_guest_external::get_instance_info_returns(), $result);
+        $this->assertEquals($instance, $result['instanceinfo']['id']);
+        $this->assertEquals($course->id, $result['instanceinfo']['courseid']);
+        $this->assertEquals('guest', $result['instanceinfo']['type']);
+        $this->assertEquals('Test instance', $result['instanceinfo']['name']);
+        $this->assertFalse($result['instanceinfo']['status']);
+        $this->assertFalse($result['instanceinfo']['passwordrequired']);
+
+        $DB->set_field('enrol', 'status', ENROL_INSTANCE_ENABLED, array('id' => $instance));
+
+        // Try to retrieve information using a normal user for a hidden course.
+        $user = self::getDataGenerator()->create_user();
+        $this->setUser($user);
+        try {
+            enrol_guest_external::get_instance_info($instance);
+        } catch (moodle_exception $e) {
+            $this->assertEquals('coursehidden', $e->errorcode);
+        }
+
+        // Student user.
+        $DB->set_field('course', 'visible', 1, array('id' => $course->id));
+        $this->setUser($student);
+        $result = enrol_guest_external::get_instance_info($instance);
+        $result = external_api::clean_returnvalue(enrol_guest_external::get_instance_info_returns(), $result);
+
+        $this->assertEquals($instance, $result['instanceinfo']['id']);
+        $this->assertEquals($course->id, $result['instanceinfo']['courseid']);
+        $this->assertEquals('guest', $result['instanceinfo']['type']);
+        $this->assertEquals('Test instance', $result['instanceinfo']['name']);
+        $this->assertTrue($result['instanceinfo']['status']);
+        $this->assertFalse($result['instanceinfo']['passwordrequired']);
+    }
+}
index d916ed6..5076e7b 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2015111600;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2015111601;        // The current plugin version (Date: YYYYMMDDXX)
 $plugin->requires  = 2015111000;        // Requires this Moodle version
 $plugin->component = 'enrol_guest';     // Full name of the plugin (used for diagnostics)
index b035bd3..af10050 100644 (file)
@@ -163,15 +163,17 @@ class enrol_self_edit_form extends moodleform {
         $checkpassword = false;
 
         if ($instance->id) {
-            if ($data['status'] == ENROL_INSTANCE_ENABLED) {
-                if ($instance->password !== $data['password']) {
-                    $checkpassword = true;
-                }
+            // Check the password if we are enabling the plugin again.
+            if (($instance->status == ENROL_INSTANCE_DISABLED) && ($data['status'] == ENROL_INSTANCE_ENABLED)) {
+                $checkpassword = true;
             }
-        } else {
-            if ($data['status'] == ENROL_INSTANCE_ENABLED) {
+
+            // Check the password if the instance is enabled and the password has changed.
+            if (($data['status'] == ENROL_INSTANCE_ENABLED) && ($instance->password !== $data['password'])) {
                 $checkpassword = true;
             }
+        } else {
+            $checkpassword = true;
         }
 
         if ($checkpassword) {
@@ -179,8 +181,8 @@ class enrol_self_edit_form extends moodleform {
             $policy  = $plugin->get_config('usepasswordpolicy');
             if ($require and trim($data['password']) === '') {
                 $errors['password'] = get_string('required');
-            } else if ($policy) {
-                $errmsg = '';//prevent eclipse warning
+            } else if (!empty($data['password']) && $policy) {
+                $errmsg = '';
                 if (!check_password_policy($data['password'], $errmsg)) {
                     $errors['password'] = $errmsg;
                 }
index 7ad82ef..fef3f6f 100644 (file)
@@ -685,6 +685,27 @@ class enrol_self_plugin extends enrol_plugin {
      */
     public function can_hide_show_instance($instance) {
         $context = context_course::instance($instance->courseid);
-        return has_capability('enrol/self:config', $context);
+
+        if (!has_capability('enrol/self:config', $context)) {
+            return false;
+        }
+
+        // If the instance is currently disabled, before it can be enabled,
+        // we must check whether the password meets the password policies.
+        if ($instance->status == ENROL_INSTANCE_DISABLED) {
+            if ($this->get_config('requirepassword')) {
+                if (empty($instance->password)) {
+                    return false;
+                }
+            }
+            // Only check the password if it is set.
+            if (!empty($instance->password) && $this->get_config('usepasswordpolicy')) {
+                if (!check_password_policy($instance->password, $errmsg)) {
+                    return false;
+                }
+            }
+        }
+
+        return true;
     }
 }
index f98bcbb..38a41e1 100644 (file)
@@ -1,6 +1,9 @@
 This files describes API changes in /enrol/* - plugins,
 information provided here is intended especially for developers.
 
+=== 3.1 ===
+* core_enrol_external::get_enrolled_users now supports two additional parameters for ordering: sortby and sortdirection.
+
 === 3.0 ===
 
 * Added new events enrol_instance_created, enrol_instance_updated and
index 1721ffa..fce01a1 100644 (file)
@@ -33,7 +33,7 @@ abstract class filter_local_settings_form extends moodleform {
     public function __construct($submiturl, $filter, $context) {
         $this->filter = $filter;
         $this->context = $context;
-        parent::moodleform($submiturl);
+        parent::__construct($submiturl);
     }
 
     /**
index a1966da..e09f7e9 100644 (file)
@@ -15,7 +15,7 @@
          * external 'helper' binaries.
          * Other platforms could/should be added
          */
-        function latex() {
+        public function __construct() {
             global $CFG;
 
             // construct directory structure
             make_temp_directory('latex');
         }
 
+        /**
+         * Old syntax of class constructor. Deprecated in PHP7.
+         *
+         * @deprecated since Moodle 3.1
+         */
+        public function latex() {
+            debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+            self::__construct();
+        }
+
         /**
          * Accessor function for support_platform field.
          * @return boolean value of supported_platform
 
             // run dvips (.dvi to .ps)
             $pathdvips = escapeshellarg(trim(get_config('filter_tex', 'pathdvips'), " '\""));
-            $command = "$pathdvips -E $dvi -o $ps";
+            $command = "$pathdvips -q -E $dvi -o $ps";
             if ($this->execute($command, $log )) {
                 return false;
             }
index e817943..bf7b981 100644 (file)
@@ -625,11 +625,21 @@ class grade_export_update_buffer {
     /**
      * Constructor - creates the buffer and initialises the time stamp
      */
-    public function grade_export_update_buffer() {
+    public function __construct() {
         $this->update_list = array();
         $this->export_time = time();
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function grade_export_update_buffer() {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct();
+    }
+
     public function flush($buffersize) {
         global $CFG, $DB;
 
index 902834c..a6e43a1 100644 (file)
@@ -53,8 +53,18 @@ class moodlequickform_guideeditor extends HTML_QuickForm_input {
      * @param string $elementlabel
      * @param array $attributes
      */
+    public function __construct($elementname=null, $elementlabel=null, $attributes=null) {
+        parent::__construct($elementname, $elementlabel, $attributes);
+    }
+
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
     public function moodlequickform_guideeditor($elementname=null, $elementlabel=null, $attributes=null) {
-        parent::HTML_QuickForm_input($elementname, $elementlabel, $attributes);
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct($elementname, $elementlabel, $attributes);
     }
 
     /**
index b3cc5bf..d990126 100644 (file)
@@ -60,8 +60,18 @@ class MoodleQuickForm_rubriceditor extends HTML_QuickForm_input {
      * @param string $elementLabel
      * @param array $attributes
      */
-    function MoodleQuickForm_rubriceditor($elementName=null, $elementLabel=null, $attributes=null) {
-        parent::HTML_QuickForm_input($elementName, $elementLabel, $attributes);
+    public function __construct($elementName=null, $elementLabel=null, $attributes=null) {
+        parent::__construct($elementName, $elementLabel, $attributes);
+    }
+
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function MoodleQuickForm_rubriceditor($elementName=null, $elementLabel=null, $attributes=null) {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct($elementName, $elementLabel, $attributes);
     }
 
     /**
index 3a04829..2696dca 100644 (file)
@@ -1085,7 +1085,7 @@ class grade_plugin_return {
      *
      * @param array $params - associative array with return parameters, if null parameter are taken from _GET or _POST
      */
-    public function grade_plugin_return($params = null) {
+    public function __construct($params = null) {
         if (empty($params)) {
             $this->type     = optional_param('gpr_type', null, PARAM_SAFEDIR);
             $this->plugin   = optional_param('gpr_plugin', null, PARAM_PLUGIN);
@@ -1102,6 +1102,16 @@ class grade_plugin_return {
         }
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function grade_plugin_return($params = null) {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct($params);
+    }
+
     /**
      * Returns return parameters as options array suitable for buttons.
      * @return array options
@@ -2033,7 +2043,7 @@ class grade_seq extends grade_structure {
      * @param bool $category_grade_last category grade item is the last child
      * @param bool $nooutcomes Whether or not outcomes should be included
      */
-    public function grade_seq($courseid, $category_grade_last=false, $nooutcomes=false) {
+    public function __construct($courseid, $category_grade_last=false, $nooutcomes=false) {
         global $USER, $CFG;
 
         $this->courseid   = $courseid;
@@ -2049,6 +2059,16 @@ class grade_seq extends grade_structure {
         }
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function grade_seq($courseid, $category_grade_last=false, $nooutcomes=false) {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct($courseid, $category_grade_last, $nooutcomes);
+    }
+
     /**
      * Static recursive helper - makes the grade_item for category the last children
      *
@@ -2185,7 +2205,7 @@ class grade_tree extends grade_structure {
      * @param array $collapsed array of collapsed categories
      * @param bool  $nooutcomes Whether or not outcomes should be included
      */
-    public function grade_tree($courseid, $fillers=true, $category_grade_last=false,
+    public function __construct($courseid, $fillers=true, $category_grade_last=false,
                                $collapsed=null, $nooutcomes=false) {
         global $USER, $CFG, $COURSE, $DB;
 
@@ -2229,6 +2249,17 @@ class grade_tree extends grade_structure {
 
     }
 
+    /**
+     * Old syntax of class constructor. Deprecated in PHP7.
+     *
+     * @deprecated since Moodle 3.1
+     */
+    public function grade_tree($courseid, $fillers=true, $category_grade_last=false,
+                               $collapsed=null, $nooutcomes=false) {
+        debugging('Use of class name as constructor is deprecated', DEBUG_DEVELOPER);
+        self::__construct($courseid, $fillers, $category_grade_last, $collapsed, $nooutcomes);
+    }
+
     /**
      * Static recursive helper - removes items from collapsed categories
      *
index aaaed88..19bc80c 100644 (file)
@@ -83,7 +83,7 @@ class dropdown_attribute extends element {
             'value' => $this->selected
         );
 
-        $attributes = array();
+        $attributes = array('tabindex' => '1');
 
         if (!empty($this->isdisabled)) {
             $attributes['disabled'] = 'DISABLED';
index 2766a9d..0102199 100644 (file)
@@ -85,9 +85,11 @@ class text_attribute extends element {
         $label = '';
         if (preg_match("/^feedback/", $this->name)) {
             $labeltitle = get_string('feedbackfor', 'gradereport_singleview', $this->label);
+            $attributes['tabindex'] = '2';
             $label = html_writer::tag('label', $labeltitle,  array('for' => $this->name, 'class' => 'accesshide'));
         } else if (preg_match("/^finalgrade/", $this->name)) {
             $labeltitle = get_string('gradefor', 'gradereport_singleview', $this->label);
+            $attributes['tabindex'] = '1';
             $label = html_writer::tag('label', $labeltitle,  array('for' => $this->name, 'class' => 'accesshide'));
         }
 
index 0c377b8..7ee45eb 100644 (file)
@@ -1,6 +1,96 @@
 M.gradereport_singleview = {};
 
 M.gradereport_singleview.init = function(Y) {
+    var getColumnIndex = function(cell) {
+        var rowNode = cell.ancestor('tr');
+        if (!rowNode || !cell) {
+            return;
+        }
+        var cells = rowNode.all('td, th');
+        return cells.indexOf(cell);
+    },
+    getNextCell = function(cell) {
+        var n = cell || document.activeElement,
+            next = n.next('td.cell, th.cell');
+        if (!next) {
+            return null;
+        }
+        // Continue on until we find a navigable cell
+        if (!next || !Y.one(next).one('input:not([type="hidden"]):not([disabled="DISABLED"]), select, a')) {
+            return getNextCell(next);
+        }
+        return next;
+    },
+    getPrevCell = function(cell) {
+        var n = cell || document.activeElement,
+            next = n.previous('td.cell, th.cell');
+        if (!next) {
+            return null;
+        }
+        // Continue on until we find a navigable cell
+        if (!Y.one(next).one('input:not([type="hidden"]):not([disabled="DISABLED"]), select, a')) {
+            return getPrevCell(next);
+        }
+        return next;
+    },
+    getAboveCell = function(cell) {
+        var n = cell || document.activeElement,
+            tr = n.ancestor('tr').previous('tr'),
+            columnIndex = getColumnIndex(n),
+            next = null;
+        if (tr) {
+            next = tr.all('td, th').item(columnIndex);
+        } else {
+            return null;
+        }
+        // Continue on until we find a navigable cell
+        if (!Y.one(next).one('input:not([type="hidden"]):not([disabled="DISABLED"]), select, a')) {
+            return getAboveCell(next);
+        }
+        return next;
+    },
+    getBelowCell = function(cell) {
+        var n = cell || document.activeElement,
+            tr = n.ancestor('tr').next('tr'),
+            columnIndex = getColumnIndex(n),
+            next = null;
+        if (tr) {
+            next = tr.all('td, th').item(columnIndex);
+        } else {
+            return null;
+        }
+        // Continue on until we find a navigable cell
+        if (!Y.one(next).one('input:not([type="hidden"]):not([disabled="DISABLED"]), select, a')) {
+            return getBelowCell(next);
+        }
+        return next;
+    };
+
+    // Add ctrl+arrow controls for navigation
+    Y.one(Y.config.doc.body).delegate('key', function(e) {
+        e.preventDefault();
+        e.stopPropagation();
+        var next = null;
+        switch (e.keyCode) {
+            case 37:
+                next = getPrevCell(this.ancestor('td, th'));
+                break;
+            case 38:
+                next = getAboveCell(this.ancestor('td, th'));
+                break;
+            case 39:
+                next = getNextCell(this.ancestor('td, th'));
+                break;
+            case 40:
+                next = getBelowCell(this.ancestor('td, th'));
+                break;
+        }
+        if (next) {
+            Y.one(next).one('input:not([type="hidden"]):not([disabled="DISABLED"]), select, a').focus();
+        }
+        return;
+    }, 'down:37,38,39,40+ctrl', 'table input, table select, table a');
+
     // Make toggle links
     Y.all('.include').each(function(link) {
         var type = link.getAttribute('class').split(" ")[2];
index fb5e988..fc90ba2 100644 (file)
@@ -35,6 +35,7 @@ $string['cliansweryes'] = 'Да';
 $string['cliincorrectvalueerror'] = 'Грешка, некоректна стойност "{$a->value}" за "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Неправилна стойност. Моля опитайте отново';
 $string['clitypevalue'] = 'Тип стойност';
+$string['clitypevaluedefault&