Merge branch 'wip-MDL-60313-master' of git://github.com/marinaglancy/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 19 Oct 2017 20:48:40 +0000 (22:48 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Thu, 19 Oct 2017 20:48:40 +0000 (22:48 +0200)
916 files changed:
.eslintignore
.stylelintignore
admin/index.php
admin/registration/confirmregistration.php
admin/registration/index.php
admin/registration/renderer.php
admin/renderer.php
admin/search.php
admin/settings/analytics.php
admin/settings/courses.php
admin/settings/plugins.php
admin/tool/analytics/amd/build/model.min.js [new file with mode: 0644]
admin/tool/analytics/amd/src/model.js [new file with mode: 0644]
admin/tool/analytics/classes/output/form/edit_model.php
admin/tool/analytics/classes/output/invalid_analysables.php [new file with mode: 0644]
admin/tool/analytics/classes/output/models_list.php
admin/tool/analytics/classes/output/renderer.php
admin/tool/analytics/lang/en/tool_analytics.php
admin/tool/analytics/model.php
admin/tool/analytics/templates/invalid_analysables.mustache [new file with mode: 0644]
admin/tool/analytics/templates/models_list.mustache
admin/tool/httpsreplace/classes/form.php [new file with mode: 0644]
admin/tool/httpsreplace/classes/url_finder.php [new file with mode: 0644]
admin/tool/httpsreplace/cli/url_replace.php [new file with mode: 0644]
admin/tool/httpsreplace/index.php [new file with mode: 0644]
admin/tool/httpsreplace/lang/en/tool_httpsreplace.php [new file with mode: 0644]
admin/tool/httpsreplace/settings.php [new file with mode: 0644]
admin/tool/httpsreplace/tests/behat/httpsreplace.feature [new file with mode: 0644]
admin/tool/httpsreplace/tests/httpsreplace_test.php [new file with mode: 0644]
admin/tool/httpsreplace/tool.php [new file with mode: 0644]
admin/tool/httpsreplace/version.php [new file with mode: 0644]
admin/tool/mobile/classes/api.php
admin/tool/mobile/classes/external.php
admin/tool/mobile/db/services.php
admin/tool/mobile/lang/en/tool_mobile.php
admin/tool/mobile/tests/api_test.php
admin/tool/mobile/upgrade.txt
admin/tool/mobile/version.php
admin/tool/templatelibrary/classes/external.php
admin/tool/uploadcourse/classes/step2_form.php
admin/tool/usertours/amd/build/usertours.min.js
admin/tool/usertours/amd/src/usertours.js
admin/tool/usertours/classes/local/filter/category.php [new file with mode: 0644]
admin/tool/usertours/classes/local/filter/course.php [new file with mode: 0644]
admin/tool/usertours/classes/local/filter/courseformat.php [new file with mode: 0644]
admin/tool/usertours/lang/en/tool_usertours.php
admin/tool/usertours/templates/resettour.mustache [new file with mode: 0644]
admin/tool/usertours/tests/behat/tour_filter.feature
admin/webservice/testclient.php
admin/webservice/testclient_forms.php
analytics/classes/admin_setting_predictor.php
analytics/classes/analysable.php
analytics/classes/calculable.php
analytics/classes/course.php
analytics/classes/dataset_manager.php
analytics/classes/local/analyser/base.php
analytics/classes/local/analyser/by_course.php
analytics/classes/local/analyser/sitewide.php
analytics/classes/local/indicator/base.php
analytics/classes/local/target/base.php
analytics/classes/local/target/discrete.php
analytics/classes/local/target/linear.php
analytics/classes/local/time_splitting/base.php
analytics/classes/manager.php
analytics/classes/model.php
analytics/classes/prediction.php
analytics/classes/predictor.php
analytics/classes/site.php
analytics/tests/dataset_manager_test.php
analytics/tests/fixtures/test_analyser.php [new file with mode: 0644]
analytics/tests/fixtures/test_target_course_level_shortname.php [new file with mode: 0644]
analytics/tests/manager_test.php [new file with mode: 0644]
analytics/tests/model_test.php
analytics/tests/prediction_test.php
auth/cas/CAS/CAS/Autoload.php
auth/cas/CAS/moodle_readme.txt
auth/ldap/classes/admin_setting_special_contexts_configtext.php
backup/backupfilesedit.php
backup/moodle2/restore_activity_task.class.php
backup/moodle2/restore_block_task.class.php
backup/moodle2/restore_course_task.class.php
backup/moodle2/restore_final_task.class.php
backup/moodle2/restore_stepslib.php
backup/moodle2/tests/moodle2_test.php
backup/restorefile.php
backup/util/structure/base_nested_element.class.php
backup/util/ui/renderer.php
badges/award.php
badges/criteria/award_criteria.php
badges/criteria/award_criteria_manual.php
badges/criteria/award_criteria_profile.php
badges/renderer.php
blocks/activity_results/block_activity_results.php
blocks/calendar_month/block_calendar_month.php
blocks/calendar_upcoming/block_calendar_upcoming.php
blocks/glossary_random/block_glossary_random.php
blocks/myoverview/tests/behat/block_myoverview_dashboard.feature
blocks/myoverview/tests/behat/block_myoverview_progress.feature
cache/disabledlib.php
calendar/amd/build/calendar.min.js
calendar/amd/build/calendar_filter.min.js
calendar/amd/build/calendar_threemonth.min.js
calendar/amd/build/calendar_view.min.js [new file with mode: 0644]
calendar/amd/build/crud.min.js [new file with mode: 0644]
calendar/amd/build/drag_drop_data_store.min.js
calendar/amd/build/event_form.min.js
calendar/amd/build/events.min.js
calendar/amd/build/modal_event_form.min.js
calendar/amd/build/month_navigation_drag_drop.min.js
calendar/amd/build/month_view_drag_drop.min.js
calendar/amd/build/repository.min.js
calendar/amd/build/selectors.min.js
calendar/amd/build/summary_modal.min.js
calendar/amd/build/view_manager.min.js
calendar/amd/src/calendar.js
calendar/amd/src/calendar_filter.js
calendar/amd/src/calendar_threemonth.js
calendar/amd/src/calendar_view.js [new file with mode: 0644]
calendar/amd/src/crud.js [new file with mode: 0644]
calendar/amd/src/drag_drop_data_store.js
calendar/amd/src/event_form.js
calendar/amd/src/events.js
calendar/amd/src/modal_event_form.js
calendar/amd/src/month_navigation_drag_drop.js
calendar/amd/src/month_view_drag_drop.js
calendar/amd/src/repository.js
calendar/amd/src/selectors.js
calendar/amd/src/summary_modal.js
calendar/amd/src/view_manager.js
calendar/classes/external/calendar_day_exporter.php [new file with mode: 0644]
calendar/classes/external/calendar_event_exporter.php
calendar/classes/external/calendar_upcoming_exporter.php [new file with mode: 0644]
calendar/classes/external/day_exporter.php
calendar/classes/external/event_exporter.php
calendar/classes/external/event_exporter_base.php
calendar/classes/external/event_icon_exporter.php
calendar/classes/external/event_subscription_exporter.php
calendar/classes/external/footer_options_exporter.php
calendar/classes/external/month_exporter.php
calendar/classes/external/week_day_exporter.php
calendar/classes/local/api.php
calendar/classes/local/event/container.php
calendar/classes/local/event/data_access/event_vault.php
calendar/classes/local/event/data_access/event_vault_interface.php
calendar/classes/local/event/entities/action_event.php
calendar/classes/local/event/entities/event.php
calendar/classes/local/event/entities/event_interface.php
calendar/classes/local/event/entities/repeat_event_collection.php
calendar/classes/local/event/factories/event_abstract_factory.php
calendar/classes/local/event/forms/create.php
calendar/classes/local/event/mappers/create_update_form_mapper.php
calendar/classes/local/event/mappers/event_mapper.php
calendar/classes/local/event/proxies/coursecat_proxy.php [new file with mode: 0644]
calendar/classes/local/event/strategies/raw_event_retrieval_strategy.php
calendar/classes/local/event/strategies/raw_event_retrieval_strategy_interface.php
calendar/event.php
calendar/export.php
calendar/externallib.php
calendar/lib.php
calendar/renderer.php
calendar/templates/calendar_day.mustache [new file with mode: 0644]
calendar/templates/calendar_upcoming.mustache [new file with mode: 0644]
calendar/templates/day_detailed.mustache
calendar/templates/day_navigation.mustache
calendar/templates/event_filter_key.mustache
calendar/templates/event_icon.mustache [new file with mode: 0644]
calendar/templates/event_item.mustache
calendar/templates/event_list.mustache
calendar/templates/event_subscription.mustache
calendar/templates/event_summary_body.mustache
calendar/templates/footer_options.mustache
calendar/templates/header.mustache
calendar/templates/month_detailed.mustache
calendar/templates/month_mini.mustache
calendar/templates/month_navigation.mustache
calendar/templates/upcoming_detailed.mustache [new file with mode: 0644]
calendar/templates/upcoming_mini.mustache [new file with mode: 0644]
calendar/tests/action_event_test.php
calendar/tests/behat/calendar.feature
calendar/tests/behat/category_events.feature [new file with mode: 0644]
calendar/tests/calendar_event_exporter_test.php [new file with mode: 0644]
calendar/tests/container_test.php
calendar/tests/coursecat_proxy_test.php [new file with mode: 0644]
calendar/tests/event_factory_test.php
calendar/tests/event_mapper_test.php
calendar/tests/event_test.php
calendar/tests/externallib_test.php
calendar/tests/helpers.php
calendar/tests/lib_test.php
calendar/tests/raw_event_retrieval_strategy_test.php
calendar/tests/repeat_event_collection_test.php
calendar/tests/rrule_manager_test.php
calendar/view.php
cohort/externallib.php
cohort/lib.php
comment/classes/external.php
completion/classes/external.php
completion/tests/externallib_test.php
composer.json
composer.lock
config-dist.php
course/classes/analytics/indicator/no_student.php [new file with mode: 0644]
course/classes/search/mycourse.php
course/externallib.php
course/format/lib.php
course/format/topics/styles.css
course/format/weeks/styles.css
course/lib.php
course/publish/index.php
course/renderer.php
course/tests/courselib_test.php
course/tests/search_test.php
enrol/cohort/lib.php
enrol/cohort/tests/cohortlib_test.php
enrol/database/lib.php
enrol/database/tests/lib_test.php [new file with mode: 0644]
enrol/editenrolment.php
enrol/editenrolment_form.php
enrol/externallib.php
enrol/flatfile/lib.php
enrol/flatfile/tests/flatfile_test.php
enrol/locallib.php
enrol/lti/lib.php
enrol/lti/tests/lib_test.php
enrol/manual/lib.php
enrol/manual/tests/lib_test.php
enrol/meta/lib.php
enrol/meta/tests/behat/enrol_meta.feature
enrol/meta/tests/plugin_test.php
enrol/paypal/lib.php
enrol/paypal/tests/paypal_test.php
enrol/self/lib.php
enrol/self/tests/behat/self_enrolment.feature
enrol/self/tests/self_test.php
enrol/unenroluser.php
files/converter/googledrive/classes/converter.php
files/externallib.php
filter/classes/external.php [new file with mode: 0644]
filter/mathjaxloader/db/upgrade.php
filter/mathjaxloader/db/upgradelib.php
filter/mathjaxloader/filter.php
filter/mathjaxloader/readme_moodle.txt
filter/mathjaxloader/settings.php
filter/mathjaxloader/tests/filter_test.php [new file with mode: 0644]
filter/mathjaxloader/tests/upgradelib_test.php
filter/mathjaxloader/version.php
filter/tests/external_test.php [new file with mode: 0644]
filter/urltolink/filter.php
group/externallib.php
group/tests/behat/create_groups.feature
index.php
install/lang/et/install.php
install/lang/ja/install.php
install/lang/lt/admin.php
install/lang/lt/install.php
install/lang/mi/langconfig.php
lang/en/admin.php
lang/en/analytics.php
lang/en/calendar.php
lang/en/completion.php
lang/en/deprecated.txt
lang/en/enrol.php
lang/en/hub.php
lang/en/mnet.php
lang/en/moodle.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.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-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-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_mssql2012.inc.php [deleted file]
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-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
lib/adodb/drivers/adodb-vfp.inc.php
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/amd/build/chartjs-lazy.min.js
lib/amd/build/loglevel.min.js
lib/amd/build/mustache.min.js
lib/amd/src/chartjs-lazy.js
lib/amd/src/loglevel.js
lib/amd/src/mustache.js
lib/behat/classes/partial_named_selector.php
lib/behat/form_field/behat_form_select.php
lib/behat/lib.php
lib/bennu/readme_moodle.txt
lib/classes/access/get_user_capability_course_helper.php [new file with mode: 0644]
lib/classes/analytics/analyser/student_enrolments.php
lib/classes/analytics/target/course_dropout.php
lib/classes/analytics/target/no_teaching.php
lib/classes/component.php
lib/classes/event/course_module_completion_updated.php
lib/classes/event/user_info_category_created.php [new file with mode: 0644]
lib/classes/event/user_info_category_deleted.php [new file with mode: 0644]
lib/classes/event/user_info_category_updated.php [new file with mode: 0644]
lib/classes/event/user_info_field_created.php [new file with mode: 0644]
lib/classes/event/user_info_field_deleted.php [new file with mode: 0644]
lib/classes/event/user_info_field_updated.php [new file with mode: 0644]
lib/classes/external/coursecat_summary_exporter.php [new file with mode: 0644]
lib/classes/hub/registration.php
lib/classes/hub/site_registration_form.php
lib/classes/oauth2/client.php
lib/classes/output/icon_system_fontawesome.php
lib/classes/plugin_manager.php
lib/classes/task/analytics_cleanup_task.php [new file with mode: 0644]
lib/classes/task/search_index_task.php
lib/classes/task/search_optimize_task.php
lib/classes/text.php
lib/completionlib.php
lib/coursecatlib.php
lib/db/access.php
lib/db/install.xml
lib/db/services.php
lib/db/tasks.php
lib/db/upgrade.php
lib/dml/moodle_database.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/pgsql_native_moodle_database.php
lib/dml/tests/dml_test.php
lib/enrollib.php
lib/filebrowser/file_info_context_course.php
lib/filebrowser/tests/file_browser_test.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/filestorage/file_system.php
lib/filestorage/tests/file_system_test.php
lib/form/form.js
lib/formslib.php
lib/html2text/Html2Text.php
lib/htmlpurifier/HTMLPurifier.php
lib/htmlpurifier/HTMLPurifier.safe-includes.php
lib/htmlpurifier/HTMLPurifier/AttrDef.php
lib/htmlpurifier/HTMLPurifier/AttrDef/CSS.php
lib/htmlpurifier/HTMLPurifier/AttrDef/CSS/Color.php
lib/htmlpurifier/HTMLPurifier/AttrDef/URI/Host.php
lib/htmlpurifier/HTMLPurifier/AttrTransform/TargetNoopener.php [new file with mode: 0644]
lib/htmlpurifier/HTMLPurifier/ChildDef/List.php
lib/htmlpurifier/HTMLPurifier/Config.php
lib/htmlpurifier/HTMLPurifier/ConfigSchema.php
lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema.ser
lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.AggressivelyRemoveScript.txt [new file with mode: 0644]
lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/Core.LegacyEntityDecoder.txt [new file with mode: 0644]
lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/HTML.TargetNoopener.txt [new file with mode: 0644]
lib/htmlpurifier/HTMLPurifier/ConfigSchema/schema/URI.DefaultScheme.txt
lib/htmlpurifier/HTMLPurifier/DefinitionCache/Serializer.php
lib/htmlpurifier/HTMLPurifier/Encoder.php
lib/htmlpurifier/HTMLPurifier/EntityParser.php
lib/htmlpurifier/HTMLPurifier/Filter/ExtractStyleBlocks.php
lib/htmlpurifier/HTMLPurifier/Generator.php
lib/htmlpurifier/HTMLPurifier/HTMLModule/TargetNoopener.php [new file with mode: 0644]
lib/htmlpurifier/HTMLPurifier/HTMLModuleManager.php
lib/htmlpurifier/HTMLPurifier/Lexer.php
lib/htmlpurifier/HTMLPurifier/Lexer/DOMLex.php
lib/htmlpurifier/HTMLPurifier/Lexer/DirectLex.php
lib/htmlpurifier/HTMLPurifier/Lexer/PH5P.php
lib/htmlpurifier/HTMLPurifier/Strategy/MakeWellFormed.php
lib/htmlpurifier/HTMLPurifier/Token.php
lib/htmlpurifier/HTMLPurifier/URI.php
lib/htmlpurifier/readme_moodle.txt
lib/installlib.php
lib/jquery/jquery-3.1.0.min.js [deleted file]
lib/jquery/jquery-3.2.1.js [moved from lib/jquery/jquery-3.1.0.js with 94% similarity]
lib/jquery/jquery-3.2.1.min.js [new file with mode: 0644]
lib/jquery/plugins.php
lib/markdown/License.md
lib/markdown/Markdown.php
lib/markdown/MarkdownExtra.php
lib/markdown/MarkdownInterface.php
lib/markdown/Readme.md
lib/markdown/readme_moodle.txt
lib/maxmind/GeoIp2/Database/Reader.php
lib/maxmind/GeoIp2/Exception/HttpException.php
lib/maxmind/GeoIp2/Exception/InvalidRequestException.php
lib/maxmind/GeoIp2/Model/AbstractModel.php
lib/maxmind/GeoIp2/Model/AnonymousIp.php
lib/maxmind/GeoIp2/Model/Asn.php [new file with mode: 0644]
lib/maxmind/GeoIp2/Model/City.php
lib/maxmind/GeoIp2/Model/ConnectionType.php
lib/maxmind/GeoIp2/Model/Country.php
lib/maxmind/GeoIp2/Model/Domain.php
lib/maxmind/GeoIp2/Model/Enterprise.php
lib/maxmind/GeoIp2/Model/Insights.php
lib/maxmind/GeoIp2/Model/Isp.php
lib/maxmind/GeoIp2/ProviderInterface.php
lib/maxmind/GeoIp2/Record/AbstractPlaceRecord.php
lib/maxmind/GeoIp2/Record/AbstractRecord.php
lib/maxmind/GeoIp2/Record/City.php
lib/maxmind/GeoIp2/Record/Continent.php
lib/maxmind/GeoIp2/Record/Country.php
lib/maxmind/GeoIp2/Record/Location.php
lib/maxmind/GeoIp2/Record/MaxMind.php
lib/maxmind/GeoIp2/Record/Postal.php
lib/maxmind/GeoIp2/Record/RepresentedCountry.php
lib/maxmind/GeoIp2/Record/Subdivision.php
lib/maxmind/GeoIp2/Record/Traits.php
lib/maxmind/GeoIp2/WebService/Client.php
lib/maxmind/MaxMind/Db/Reader.php
lib/maxmind/readme_moodle.txt [moved from lib/maxmind/README_moodle.txt with 77% similarity]
lib/minify/matthiasmullie-minify/data/js/keywords_before.txt
lib/minify/matthiasmullie-minify/data/js/operators_after.txt
lib/minify/matthiasmullie-minify/src/CSS.php
lib/minify/matthiasmullie-minify/src/JS.php
lib/minify/matthiasmullie-minify/src/Minify.php
lib/minify/matthiasmullie-pathconverter/src/Converter.php
lib/minify/matthiasmullie-pathconverter/src/ConverterInterface.php [new file with mode: 0644]
lib/minify/matthiasmullie-pathconverter/src/NoConverter.php [new file with mode: 0644]
lib/minify/readme_moodle.txt
lib/mlbackend/php/classes/processor.php
lib/mlbackend/python/classes/processor.php
lib/moodlelib.php
lib/mustache/readme_moodle.txt
lib/mustache/src/Mustache/Autoloader.php
lib/mustache/src/Mustache/Cache.php
lib/mustache/src/Mustache/Cache/AbstractCache.php
lib/mustache/src/Mustache/Cache/FilesystemCache.php
lib/mustache/src/Mustache/Cache/NoopCache.php
lib/mustache/src/Mustache/Compiler.php
lib/mustache/src/Mustache/Context.php
lib/mustache/src/Mustache/Engine.php
lib/mustache/src/Mustache/Exception.php
lib/mustache/src/Mustache/Exception/InvalidArgumentException.php
lib/mustache/src/Mustache/Exception/LogicException.php
lib/mustache/src/Mustache/Exception/RuntimeException.php
lib/mustache/src/Mustache/Exception/SyntaxException.php
lib/mustache/src/Mustache/Exception/UnknownFilterException.php
lib/mustache/src/Mustache/Exception/UnknownHelperException.php
lib/mustache/src/Mustache/Exception/UnknownTemplateException.php
lib/mustache/src/Mustache/HelperCollection.php
lib/mustache/src/Mustache/LambdaHelper.php
lib/mustache/src/Mustache/Loader.php
lib/mustache/src/Mustache/Loader/ArrayLoader.php
lib/mustache/src/Mustache/Loader/CascadingLoader.php
lib/mustache/src/Mustache/Loader/FilesystemLoader.php
lib/mustache/src/Mustache/Loader/InlineLoader.php
lib/mustache/src/Mustache/Loader/MutableLoader.php
lib/mustache/src/Mustache/Loader/ProductionFilesystemLoader.php [new file with mode: 0644]
lib/mustache/src/Mustache/Loader/StringLoader.php
lib/mustache/src/Mustache/Logger.php
lib/mustache/src/Mustache/Logger/AbstractLogger.php
lib/mustache/src/Mustache/Logger/StreamLogger.php
lib/mustache/src/Mustache/Parser.php
lib/mustache/src/Mustache/Source.php [new file with mode: 0644]
lib/mustache/src/Mustache/Source/FilesystemSource.php [new file with mode: 0644]
lib/mustache/src/Mustache/Template.php
lib/mustache/src/Mustache/Tokenizer.php
lib/myprofilelib.php
lib/navigationlib.php
lib/outputcomponents.php
lib/pear/HTML/QuickForm/Rule/Compare.php
lib/pear/HTML/QuickForm/date.php
lib/pear/PEAR.php
lib/pear/README_MOODLE.txt
lib/phpmailer/README.md
lib/phpmailer/README_MOODLE.txt
lib/phpmailer/VERSION
lib/phpmailer/changelog.md
lib/phpmailer/language/phpmailer.lang-ba.php [new file with mode: 0644]
lib/phpmailer/language/phpmailer.lang-cs.php [moved from lib/phpmailer/language/phpmailer.lang-cz.php with 95% similarity]
lib/phpmailer/language/phpmailer.lang-da.php [moved from lib/phpmailer/language/phpmailer.lang-dk.php with 100% similarity]
lib/phpmailer/language/phpmailer.lang-fr.php
lib/phpmailer/language/phpmailer.lang-nb.php [new file with mode: 0644]
lib/phpmailer/language/phpmailer.lang-nl.php
lib/phpmailer/language/phpmailer.lang-no.php [deleted file]
lib/phpmailer/language/phpmailer.lang-pt_br.php [moved from lib/phpmailer/language/phpmailer.lang-br.php with 65% similarity]
lib/phpmailer/language/phpmailer.lang-rs.php [moved from lib/phpmailer/language/phpmailer.lang-sr.php with 96% similarity]
lib/phpmailer/language/phpmailer.lang-sv.php [moved from lib/phpmailer/language/phpmailer.lang-se.php with 73% similarity]
lib/phpmailer/language/phpmailer.lang-tr.php
lib/phpmailer/language/phpmailer.lang-zh_cn.php
lib/phpmailer/moodle_phpmailer.php
lib/phpmailer/src/Exception.php [new file with mode: 0644]
lib/phpmailer/src/PHPMailer.php [moved from lib/phpmailer/class.phpmailer.php with 66% similarity]
lib/phpmailer/src/SMTP.php [moved from lib/phpmailer/class.smtp.php with 70% similarity]
lib/phpunit/bootstrap.php
lib/phpunit/classes/base_testcase.php
lib/requirejs/moodle-config.js
lib/requirejs/require.js
lib/requirejs/require.min.js
lib/scssphp/Base/Range.php
lib/scssphp/Block.php
lib/scssphp/Colors.php
lib/scssphp/Compiler.php
lib/scssphp/Compiler/Environment.php
lib/scssphp/Exception/CompilerException.php
lib/scssphp/Exception/ParserException.php
lib/scssphp/Exception/RangeException.php [new file with mode: 0644]
lib/scssphp/Exception/ServerException.php
lib/scssphp/Formatter.php
lib/scssphp/Formatter/Compact.php
lib/scssphp/Formatter/Compressed.php
lib/scssphp/Formatter/Crunched.php
lib/scssphp/Formatter/Debug.php
lib/scssphp/Formatter/Expanded.php
lib/scssphp/Formatter/Nested.php
lib/scssphp/Formatter/OutputBlock.php
lib/scssphp/Node.php
lib/scssphp/Node/Number.php
lib/scssphp/Parser.php
lib/scssphp/Server.php
lib/scssphp/Type.php
lib/scssphp/Util.php
lib/scssphp/Version.php
lib/scssphp/moodle_readme.txt
lib/setuplib.php
lib/simplepie/LICENSE.txt [new file with mode: 0644]
lib/simplepie/autoloader.php
lib/simplepie/library/SimplePie.php
lib/simplepie/library/SimplePie/Category.php
lib/simplepie/library/SimplePie/Content/Type/Sniffer.php
lib/simplepie/library/SimplePie/File.php
lib/simplepie/library/SimplePie/Item.php
lib/simplepie/library/SimplePie/Locator.php
lib/simplepie/library/SimplePie/Misc.php
lib/simplepie/library/SimplePie/Parse/Date.php
lib/simplepie/library/SimplePie/Sanitize.php
lib/simplepie/readme_moodle.txt
lib/spout/readme_moodle.txt
lib/spout/src/Spout/Common/Escaper/ODS.php
lib/spout/src/Spout/Common/Escaper/XLSX.php
lib/spout/src/Spout/Common/Helper/FileSystemHelper.php
lib/spout/src/Spout/Reader/AbstractReader.php
lib/spout/src/Spout/Reader/CSV/Reader.php
lib/spout/src/Spout/Reader/CSV/ReaderOptions.php [new file with mode: 0644]
lib/spout/src/Spout/Reader/CSV/RowIterator.php
lib/spout/src/Spout/Reader/CSV/Sheet.php
lib/spout/src/Spout/Reader/CSV/SheetIterator.php
lib/spout/src/Spout/Reader/Common/ReaderOptions.php [new file with mode: 0644]
lib/spout/src/Spout/Reader/Common/XMLProcessor.php [new file with mode: 0644]
lib/spout/src/Spout/Reader/ODS/Helper/CellValueFormatter.php
lib/spout/src/Spout/Reader/ODS/Helper/SettingsHelper.php [new file with mode: 0644]
lib/spout/src/Spout/Reader/ODS/Reader.php
lib/spout/src/Spout/Reader/ODS/ReaderOptions.php [new file with mode: 0644]
lib/spout/src/Spout/Reader/ODS/RowIterator.php
lib/spout/src/Spout/Reader/ODS/Sheet.php
lib/spout/src/Spout/Reader/ODS/SheetIterator.php
lib/spout/src/Spout/Reader/Wrapper/SimpleXMLElement.php [deleted file]
lib/spout/src/Spout/Reader/Wrapper/XMLReader.php
lib/spout/src/Spout/Reader/XLSX/Helper/CellHelper.php
lib/spout/src/Spout/Reader/XLSX/Helper/CellValueFormatter.php
lib/spout/src/Spout/Reader/XLSX/Helper/DateFormatHelper.php
lib/spout/src/Spout/Reader/XLSX/Helper/SharedStringsHelper.php
lib/spout/src/Spout/Reader/XLSX/Helper/SheetHelper.php
lib/spout/src/Spout/Reader/XLSX/Helper/StyleHelper.php
lib/spout/src/Spout/Reader/XLSX/Reader.php
lib/spout/src/Spout/Reader/XLSX/ReaderOptions.php [new file with mode: 0644]
lib/spout/src/Spout/Reader/XLSX/RowIterator.php
lib/spout/src/Spout/Reader/XLSX/Sheet.php
lib/spout/src/Spout/Reader/XLSX/SheetIterator.php
lib/spout/src/Spout/Writer/AbstractWriter.php
lib/spout/src/Spout/Writer/Common/Helper/AbstractStyleHelper.php
lib/spout/src/Spout/Writer/Common/Helper/CellHelper.php
lib/spout/src/Spout/Writer/Common/Internal/AbstractWorkbook.php
lib/spout/src/Spout/Writer/Common/Sheet.php
lib/spout/src/Spout/Writer/ODS/Helper/FileSystemHelper.php
lib/spout/src/Spout/Writer/ODS/Helper/StyleHelper.php
lib/spout/src/Spout/Writer/ODS/Internal/Workbook.php
lib/spout/src/Spout/Writer/ODS/Internal/Worksheet.php
lib/spout/src/Spout/Writer/ODS/Writer.php
lib/spout/src/Spout/Writer/Style/Style.php
lib/spout/src/Spout/Writer/Style/StyleBuilder.php
lib/spout/src/Spout/Writer/WriterInterface.php
lib/spout/src/Spout/Writer/XLSX/Helper/FileSystemHelper.php
lib/spout/src/Spout/Writer/XLSX/Internal/Workbook.php
lib/spout/src/Spout/Writer/XLSX/Internal/Worksheet.php
lib/tcpdf/CHANGELOG.TXT
lib/tcpdf/README.TXT
lib/tcpdf/composer.json
lib/tcpdf/include/tcpdf_static.php
lib/tcpdf/readme_moodle.txt
lib/tcpdf/tcpdf.php
lib/templates/pix_icon_fontawesome.mustache
lib/testing/generator/data_generator.php
lib/tests/accesslib_test.php
lib/tests/admintree_test.php
lib/tests/behat/behat_data_generators.php
lib/tests/behat/behat_forms.php
lib/tests/completionlib_test.php
lib/tests/coursecatlib_test.php
lib/tests/event_profile_field_test.php [new file with mode: 0644]
lib/tests/filelib_test.php
lib/tests/htmlpurifier_test.php
lib/tests/markdown_test.php
lib/tests/moodlelib_test.php
lib/tests/setuplib_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/upgradelib.php
lib/webdavlib.php
media/player/videojs/amd/build/Youtube-lazy.min.js
media/player/videojs/amd/build/loader.min.js
media/player/videojs/amd/build/video-lazy.min.js
media/player/videojs/amd/build/videojs-flash-lazy.min.js [new file with mode: 0644]
media/player/videojs/amd/src/Youtube-lazy.js
media/player/videojs/amd/src/loader.js
media/player/videojs/amd/src/video-lazy.js
media/player/videojs/amd/src/videojs-flash-lazy.js [new file with mode: 0644]
media/player/videojs/classes/plugin.php
media/player/videojs/readme_moodle.txt
media/player/videojs/styles.css
media/player/videojs/thirdpartylibs.xml
media/player/videojs/videojs/lang/ar.js
media/player/videojs/videojs/lang/de.js
media/player/videojs/videojs/lang/en.js
media/player/videojs/videojs/lang/es.js
media/player/videojs/videojs/lang/fr.js
media/player/videojs/videojs/lang/gl.js [new file with mode: 0644]
media/player/videojs/videojs/lang/nl.js
media/player/videojs/videojs/lang/pt-PT.js [new file with mode: 0644]
media/player/videojs/videojs/lang/sk.js [new file with mode: 0644]
media/player/videojs/videojs/lang/tr.js
media/player/videojs/videojs/lang/vi.js
media/player/videojs/videojs/lang/zh-CN.js
media/player/videojs/videojs/video-js.swf
media/player/vimeo/wsplayer.php [new file with mode: 0644]
message/classes/search/base_message.php
message/classes/search/message_received.php
message/classes/search/message_sent.php
message/externallib.php
message/output/airnotifier/lang/en/message_airnotifier.php
message/tests/api_test.php
message/tests/behat/delete_all_messages.feature
message/tests/search_received_test.php [moved from message/tests/search_test_received.php with 77% similarity]
message/tests/search_sent_test.php [moved from message/tests/search_test_sent.php with 75% similarity]
mod/assign/amd/build/grading_actions.min.js
mod/assign/amd/build/grading_navigation.min.js
mod/assign/amd/build/grading_panel.min.js
mod/assign/amd/src/grading_actions.js
mod/assign/amd/src/grading_navigation.js
mod/assign/amd/src/grading_panel.js
mod/assign/externallib.php
mod/assign/feedback/editpdf/fpdi/LICENSE
mod/assign/feedback/editpdf/fpdi/filters/FilterASCII85.php
mod/assign/feedback/editpdf/fpdi/filters/FilterASCIIHexDecode.php
mod/assign/feedback/editpdf/fpdi/filters/FilterLZW.php
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/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js
mod/assign/feedback/editpdf/yui/src/editor/js/comment.js
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/templates/grading_actions.mustache
mod/assign/tests/lib_test.php
mod/book/classes/search/chapter.php
mod/book/lang/en/book.php
mod/book/lib.php
mod/book/tests/behat/reorganize_chapters.feature [new file with mode: 0644]
mod/book/tests/search_test.php
mod/chat/chatd.php
mod/choice/lang/en/choice.php
mod/choice/lib.php
mod/choice/tests/lib_test.php
mod/data/backup/moodle2/backup_data_stepslib.php
mod/data/backup/moodle2/restore_data_stepslib.php
mod/data/classes/search/entry.php
mod/data/db/tag.php [new file with mode: 0644]
mod/data/edit.php
mod/data/export.php
mod/data/export_form.php
mod/data/import.php
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/locallib.php
mod/data/styles.css
mod/data/templates.php
mod/data/tests/behat/view_entries.feature
mod/data/tests/generator/lib.php
mod/data/tests/generator_test.php
mod/data/tests/lib_test.php
mod/data/tests/search_test.php
mod/data/version.php
mod/feedback/lang/en/feedback.php
mod/feedback/lib.php
mod/feedback/tests/lib_test.php
mod/forum/classes/search/post.php
mod/forum/db/install.xml
mod/forum/db/upgrade.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/tests/search_test.php
mod/forum/version.php
mod/glossary/classes/search/entry.php
mod/glossary/lang/en/glossary.php
mod/glossary/lib.php
mod/glossary/styles.css
mod/glossary/tests/search_test.php
mod/imscp/lang/en/imscp.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lti/locallib.php
mod/quiz/attemptlib.php
mod/quiz/classes/structure.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/quiz/report/overview/report.php
mod/quiz/report/overview/tests/report_test.php
mod/quiz/report/responses/report.php
mod/quiz/report/statistics/tests/statistics_test.php
mod/quiz/tests/behat/editing_section_headings.feature
mod/quiz/tests/structure_test.php
mod/scorm/aicc.php
mod/scorm/lang/en/scorm.php
mod/survey/classes/search/activity.php
mod/survey/graph.php
mod/survey/lib.php
mod/survey/tests/search_test.php [new file with mode: 0644]
mod/wiki/classes/search/collaborative_page.php
mod/wiki/diff/diff_nwiki.php
mod/wiki/diff/difflib.php
mod/wiki/lang/en/wiki.php
mod/wiki/tests/search_test.php
mod/workshop/allocation/random/lib.php
mod/workshop/assessment.php
mod/workshop/classes/external.php
mod/workshop/classes/external/assessment_exporter.php [new file with mode: 0644]
mod/workshop/classes/external/submission_exporter.php [new file with mode: 0644]
mod/workshop/db/services.php
mod/workshop/form/accumulative/lib.php
mod/workshop/form/assessment_form.php
mod/workshop/form/lib.php
mod/workshop/lang/en/workshop.php
mod/workshop/lib.php
mod/workshop/locallib.php
mod/workshop/submission.php
mod/workshop/tests/external_test.php
mod/workshop/tests/lib_test.php
mod/workshop/upgrade.txt
mod/workshop/version.php
notes/externallib.php
phpunit.xml.dist
pix/i/categoryevent.png [new file with mode: 0644]
pix/i/categoryevent.svg [new file with mode: 0644]
pix/i/completion-auto-n-override.png [new file with mode: 0644]
pix/i/completion-auto-n-override.svg [new file with mode: 0644]
pix/i/completion-auto-y-override.png [new file with mode: 0644]
pix/i/completion-auto-y-override.svg [new file with mode: 0644]
pix/i/completion-manual-n-override.png [new file with mode: 0644]
pix/i/completion-manual-n-override.svg [new file with mode: 0644]
pix/i/completion-manual-y-override.png [new file with mode: 0644]
pix/i/completion-manual-y-override.svg [new file with mode: 0644]
pix/i/siteevent.png
pix/i/siteevent.svg
question/classes/external.php
question/classes/statistics/questions/calculator.php
question/type/ddmarker/lang/en/qtype_ddmarker.php
question/type/multianswer/questiontype.php
report/insights/classes/output/insight.php
report/insights/classes/output/insights_list.php
report/insights/lang/en/report_insights.php
report/insights/templates/insight.mustache
report/insights/templates/insight_details.mustache
report/insights/templates/insights_list.mustache
report/progress/amd/build/completion_override.min.js [new file with mode: 0644]
report/progress/amd/src/completion_override.js [new file with mode: 0644]
report/progress/index.php
report/progress/tests/behat/activity_completion_report.feature [new file with mode: 0644]
report/security/lang/en/report_security.php
repository/tests/behat/cancel_add_file.feature
search/classes/base.php
search/classes/base_activity.php
search/classes/base_block.php
search/classes/base_mod.php
search/classes/engine.php
search/classes/manager.php
search/classes/skip_future_documents_iterator.php [new file with mode: 0644]
search/cli/indexer.php
search/engine/solr/classes/engine.php
search/tests/base_activity_test.php
search/tests/base_block_test.php
search/tests/manager_test.php
search/upgrade.txt
tag/classes/external.php
tag/classes/tag.php
tags.txt [deleted file]
theme/boost/lang/en/theme_boost.php
theme/boost/lib.php
theme/boost/scss/moodle/calendar.scss
theme/boost/scss/moodle/modules.scss
theme/boost/settings.php
theme/boost/templates/columns2.mustache
theme/boost/templates/mod_assign/grading_actions.mustache
theme/boost/tests/behat/behat_theme_boost_behat_blocks.php
theme/bootstrapbase/layout/columns2.php
theme/bootstrapbase/less/moodle/admin.less
theme/bootstrapbase/less/moodle/bs4-compat.less
theme/bootstrapbase/less/moodle/calendar.less
theme/bootstrapbase/less/moodle/course.less
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/style/moodle.css
theme/bootstrapbase/templates/report_insights/insight.mustache [deleted file]
theme/bootstrapbase/templates/report_insights/insight_details.mustache [deleted file]
theme/bootstrapbase/templates/report_insights/insights_list.mustache [deleted file]
theme/upgrade.txt
user/amd/build/status_field.min.js
user/amd/build/unified_filter.min.js
user/amd/src/status_field.js
user/amd/src/unified_filter.js
user/classes/search/user.php
user/editlib.php
user/externallib.php
user/lib.php
user/profile/definelib.php
user/profile/field/checkbox/field.class.php
user/profile/field/menu/field.class.php
user/profile/field/upgrade.txt [new file with mode: 0644]
user/profile/lib.php
user/templates/status_field.mustache
user/templates/unified_filter.mustache
user/tests/behat/edit_user_enrolment.feature
user/tests/behat/filter_participants.feature
user/tests/search_test.php
user/tests/userlib_test.php
version.php
webservice/upgrade.txt
webservice/upload.php
webservice/xmlrpc/lib.php

index 0622612..7d19e9c 100644 (file)
@@ -62,6 +62,8 @@ lib/validateurlsyntax.php
 media/player/videojs/amd/src/video-lazy.js
 media/player/videojs/amd/src/Youtube-lazy.js
 media/player/videojs/videojs/
+media/player/videojs/amd/src/videojs-flash-lazy.js
+media/player/videojs/videojs/video-js.swf
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/boost/scss/bootstrap/
index cfcf702..c35c560 100644 (file)
@@ -63,6 +63,8 @@ lib/validateurlsyntax.php
 media/player/videojs/amd/src/video-lazy.js
 media/player/videojs/amd/src/Youtube-lazy.js
 media/player/videojs/videojs/
+media/player/videojs/amd/src/videojs-flash-lazy.js
+media/player/videojs/videojs/video-js.swf
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/boost/scss/bootstrap/
index 88a7d4c..48c7144 100644 (file)
@@ -699,6 +699,7 @@ if (!$cache and moodle_needs_upgrading()) {
 if (during_initial_install()) {
     set_config('rolesactive', 1); // after this, during_initial_install will return false.
     set_config('adminsetuppending', 1);
+    set_config('registrationpending', 1); // Remind to register site after all other setup is finished.
     // we need this redirect to setup proper session
     upgrade_finished("index.php?sessionstarted=1&amp;lang=$CFG->lang");
 }
@@ -814,6 +815,9 @@ if (isset($SESSION->pluginuninstallreturn)) {
     }
 }
 
+// If site registration needs updating, redirect.
+\core\hub\registration::registration_reminder('/admin/index.php');
+
 // Everything should now be set up, and the user is an admin
 
 // Print default admin page with notifications.
@@ -863,9 +867,10 @@ $cachewarnings = cache_helper::warnings();
 // Check if there are events 1 API handlers.
 $eventshandlers = $DB->get_records_sql('SELECT DISTINCT component FROM {events_handlers}');
 $themedesignermode = !empty($CFG->themedesignermode);
+$mobileconfigured = !empty($CFG->enablemobilewebservice);
 
 // Check if a directory with development libraries exists.
-if (is_dir($CFG->dirroot.'/vendor') || is_dir($CFG->dirroot.'/node_modules')) {
+if (empty($CFG->disabledevlibdirscheck) && (is_dir($CFG->dirroot.'/vendor') || is_dir($CFG->dirroot.'/node_modules'))) {
     $devlibdir = true;
 } else {
     $devlibdir = false;
@@ -877,4 +882,5 @@ $output = $PAGE->get_renderer('core', 'admin');
 
 echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
                                        $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
-                                       $registered, $cachewarnings, $eventshandlers, $themedesignermode, $devlibdir);
+                                       $registered, $cachewarnings, $eventshandlers, $themedesignermode, $devlibdir,
+                                       $mobileconfigured);
index 7fe7689..6b20e8d 100644 (file)
@@ -64,8 +64,10 @@ echo $OUTPUT->heading(get_string('registrationconfirmed', 'hub'), 3, 'main');
 echo $OUTPUT->notification(get_string('registrationconfirmedon', 'hub'), 'notifysuccess');
 
 // Display continue button.
-$registrationpage = new moodle_url('/admin/registration/index.php');
-$continuebutton = $OUTPUT->render(new single_button($registrationpage, get_string('continue')));
+$returnurl = !empty($SESSION->registrationredirect) ? clean_param($SESSION->registrationredirect, PARAM_LOCALURL) : null;
+unset($SESSION->registrationredirect);
+$continueurl = new moodle_url($returnurl ?: '/admin/registration/index.php');
+$continuebutton = $OUTPUT->render(new single_button($continueurl, get_string('continue')));
 $continuebutton = html_writer::tag('div', $continuebutton, array('class' => 'mdl-align'));
 echo $continuebutton;
 
index 0adb27b..dee1ba0 100644 (file)
@@ -53,17 +53,25 @@ if ($unregistration && \core\hub\registration::is_registered()) {
     exit;
 }
 
+$isinitialregistration = \core\hub\registration::show_after_install(true);
+if (!$returnurl = optional_param('returnurl', null, PARAM_LOCALURL)) {
+    $returnurl = $isinitialregistration ? '/admin/index.php' : '/admin/registration/index.php';
+}
+
 $siteregistrationform = new \core\hub\site_registration_form();
+$siteregistrationform->set_data(['returnurl' => $returnurl]);
 if ($fromform = $siteregistrationform->get_data()) {
 
     // Save the settings.
     \core\hub\registration::save_site_info($fromform);
 
     if (\core\hub\registration::is_registered()) {
-        \core\hub\registration::update_manual();
-        redirect(new moodle_url('/admin/registration/index.php'));
+        if (\core\hub\registration::update_manual()) {
+            redirect(new moodle_url($returnurl));
+        }
+        redirect(new moodle_url('/admin/registration/index.php', ['returnurl' => $returnurl]));
     } else {
-        \core\hub\registration::register();
+        \core\hub\registration::register($returnurl);
         // This method will redirect away.
     }
 
@@ -80,13 +88,15 @@ if (\core\hub\registration::is_registered()) {
     $lastupdated = \core\hub\registration::get_last_updated();
     if ($lastupdated == 0) {
         $registrationmessage = get_string('pleaserefreshregistrationunknown', 'admin');
+    } else if (\core\hub\registration::get_new_registration_fields()) {
+        $registrationmessage = get_string('pleaserefreshregistrationnewdata', 'admin');
     } else {
         $lastupdated = userdate($lastupdated, get_string('strftimedate', 'langconfig'));
         $registrationmessage = get_string('pleaserefreshregistration', 'admin', $lastupdated);
         $notificationtype = \core\output\notification::NOTIFY_INFO;
     }
     echo $OUTPUT->notification($registrationmessage, $notificationtype);
-} else {
+} else if (!$isinitialregistration) {
     $registrationmessage = get_string('registrationwarning', 'admin');
     echo $OUTPUT->notification($registrationmessage, $notificationtype);
 }
@@ -94,6 +104,8 @@ if (\core\hub\registration::is_registered()) {
 // Heading.
 if (\core\hub\registration::is_registered()) {
     echo $OUTPUT->heading(get_string('updatesite', 'hub', 'Moodle.net'));
+} else if ($isinitialregistration) {
+    echo $OUTPUT->heading(get_string('completeregistration', 'hub'));
 } else {
     echo $OUTPUT->heading(get_string('registerwithmoodleorg', 'admin'));
 }
@@ -107,5 +119,7 @@ if (\core\hub\registration::is_registered()) {
     // Unregister link.
     $unregisterhuburl = new moodle_url("/admin/registration/index.php", ['unregistration' => 1]);
     echo html_writer::div(html_writer::link($unregisterhuburl, get_string('unregister', 'hub')), 'unregister');
+} else if ($isinitialregistration) {
+    echo html_writer::div(html_writer::link(new moodle_url($returnurl), get_string('skipregistration', 'hub')), 'skipregistration');
 }
 echo $OUTPUT->footer();
index 196d680..4832013 100644 (file)
@@ -36,14 +36,6 @@ class core_register_renderer extends plugin_renderer_base {
      * @return string
      */
     public function moodleorg_registration_message() {
-        $moodleorgstatslink = html_writer::link('http://moodle.net/stats',
-                                               get_string('statsmoodleorg', 'admin'),
-                                               array('target' => '_blank'));
-
-        $moodleorgregmsg = get_string('registermoodleorg', 'admin');
-        $items = array(get_string('registermoodleorgli1', 'admin'),
-                       get_string('registermoodleorgli2', 'admin', $moodleorgstatslink));
-        $moodleorgregmsg .= html_writer::alist($items);
-        return $moodleorgregmsg;
+        return format_text(get_string('registermoodlenet', 'admin'), FORMAT_MARKDOWN, ['noclean' => true]);
     }
 }
index 7dd4808..1fd8cb5 100644 (file)
@@ -278,13 +278,14 @@ class core_admin_renderer extends plugin_renderer_base {
      * @param array $eventshandlers Events 1 API handlers.
      * @param bool $themedesignermode Warn about the theme designer mode.
      * @param bool $devlibdir Warn about development libs directory presence.
+     * @param bool $mobileconfigured Whether the mobile web services have been enabled
      *
      * @return string HTML to output.
      */
     public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
             $cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
             $buggyiconvnomb, $registered, array $cachewarnings = array(), $eventshandlers = 0,
-            $themedesignermode = false, $devlibdir = false) {
+            $themedesignermode = false, $devlibdir = false, $mobileconfigured = false) {
         global $CFG;
         $output = '';
 
@@ -303,6 +304,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $output .= $this->cache_warnings($cachewarnings);
         $output .= $this->events_handlers($eventshandlers);
         $output .= $this->registration_warning($registered);
+        $output .= $this->mobile_configuration_warning($mobileconfigured);
 
         //////////////////////////////////////////////////////////////////////////////////////////////////
         ////  IT IS ILLEGAL AND A VIOLATION OF THE GPL TO HIDE, REMOVE OR MODIFY THIS COPYRIGHT NOTICE ///
@@ -830,6 +832,23 @@ class core_admin_renderer extends plugin_renderer_base {
         return $this->registration_warning(\core\hub\registration::is_registered());
     }
 
+    /**
+     * Display a warning about the Mobile Web Services being disabled.
+     *
+     * @param boolean $mobileconfigured true if mobile web services are enabled
+     * @return string HTML to output.
+     */
+    protected function mobile_configuration_warning($mobileconfigured) {
+        $output = '';
+        if (!$mobileconfigured) {
+            $settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
+            $configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
+            $output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . '&nbsp;' . $configurebutton);
+        }
+
+        return $output;
+    }
+
     /**
      * Helper method to render the information about the available Moodle update
      *
index fb38431..dfb6043 100644 (file)
@@ -5,11 +5,22 @@
 require_once('../config.php');
 require_once($CFG->libdir.'/adminlib.php');
 
+redirect_if_major_upgrade_required();
+
 $query = trim(optional_param('query', '', PARAM_NOTAGS));  // Search string
 
 $context = context_system::instance();
 $PAGE->set_context($context);
 
+$hassiteconfig = has_capability('moodle/site:config', $context);
+
+if ($hassiteconfig && moodle_needs_upgrading()) {
+    redirect(new moodle_url('/admin/index.php'));
+}
+
+// If site registration needs updating, redirect.
+\core\hub\registration::registration_reminder('/admin/search.php');
+
 admin_externalpage_setup('search', '', array('query' => $query)); // now hidden page
 
 $adminroot = admin_get_root(); // need all settings here
@@ -55,7 +66,7 @@ if ($errormsg !== '') {
 
 $showsettingslinks = true;
 
-if (has_capability('moodle/site:config', $context)) {
+if ($hassiteconfig) {
     require_once("admin_settings_search_form.php");
     $form = new admin_settings_search_form();
     $form->display();
index e8247c8..b42a252 100644 (file)
@@ -101,5 +101,10 @@ if ($hassiteconfig) {
         // Disable web interface evaluation and get predictions.
         $settings->add(new admin_setting_configcheckbox('analytics/onlycli', new lang_string('onlycli', 'analytics'),
             new lang_string('onlycliinfo', 'analytics'), 1));
+
+        // Training and prediction time limit per model.
+        $settings->add(new admin_setting_configduration('analytics/modeltimelimit', new lang_string('modeltimelimit', 'analytics'),
+            new lang_string('modeltimelimitinfo', 'analytics'), 20 * MINSECS));
+
     }
 }
index 5f83df7..64ef150 100644 (file)
@@ -92,6 +92,9 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
     $temp->add(new admin_setting_configselect('moodlecourse/coursedisplay', new lang_string('coursedisplay'),
         new lang_string('coursedisplay_help'), COURSE_DISPLAY_SINGLEPAGE, $choices));
 
+    $temp->add(new admin_setting_configcheckbox('moodlecourse/courseenddateenabled', get_string('courseenddateenabled'),
+        get_string('courseenddateenabled_desc'), 1));
+
     $temp->add(new admin_setting_configduration('moodlecourse/courseduration', get_string('courseduration'),
         get_string('courseduration_desc'), YEARSECS));
 
index 3bb3c4a..4444ff0 100644 (file)
@@ -557,13 +557,21 @@ if ($hassiteconfig) {
     $temp->add(new admin_setting_heading('searchengineheading', new lang_string('searchengine', 'admin'), ''));
     $temp->add(new admin_setting_configselect('searchengine',
                                 new lang_string('selectsearchengine', 'admin'), '', 'solr', $engines));
-    $temp->add(new admin_setting_heading('searchindexingheading', new lang_string('searchoptions', 'admin'), ''));
+    $temp->add(new admin_setting_heading('searchoptionsheading', new lang_string('searchoptions', 'admin'), ''));
     $temp->add(new admin_setting_configcheckbox('searchindexwhendisabled',
             new lang_string('searchindexwhendisabled', 'admin'), new lang_string('searchindexwhendisabled_desc', 'admin'),
             0));
     $temp->add(new admin_setting_configduration('searchindextime',
             new lang_string('searchindextime', 'admin'), new lang_string('searchindextime_desc', 'admin'),
             600));
+    $options = [
+        0 => new lang_string('searchallavailablecourses_off', 'admin'),
+        1 => new lang_string('searchallavailablecourses_on', 'admin')
+    ];
+    $temp->add(new admin_setting_configselect('searchallavailablecourses',
+            new lang_string('searchallavailablecourses', 'admin'),
+            new lang_string('searchallavailablecourses_desc', 'admin'),
+            0, $options));
 
     $ADMIN->add('searchplugins', $temp);
     $ADMIN->add('searchplugins', new admin_externalpage('searchareas', new lang_string('searchareas', 'admin'),
diff --git a/admin/tool/analytics/amd/build/model.min.js b/admin/tool/analytics/amd/build/model.min.js
new file mode 100644 (file)
index 0000000..e9e2e3c
Binary files /dev/null and b/admin/tool/analytics/amd/build/model.min.js differ
diff --git a/admin/tool/analytics/amd/src/model.js b/admin/tool/analytics/amd/src/model.js
new file mode 100644 (file)
index 0000000..8913431
--- /dev/null
@@ -0,0 +1,94 @@
+// 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/>.
+
+/**
+ * AMD module for model actions confirmation.
+ *
+ * @module     tool_analytics/model
+ * @copyright  2017 David Monllao
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+define(['jquery', 'core/str', 'core/log', 'core/notification', 'core/modal_factory', 'core/modal_events'],
+    function($, Str, log, Notification, ModalFactory, ModalEvents) {
+
+    /**
+     * List of actions that require confirmation and confirmation message.
+     */
+    var actionsList = {
+        clear: {
+            title: {
+                key: 'clearpredictions',
+                component: 'tool_analytics'
+            }, body: {
+                key: 'clearmodelpredictions',
+                component: 'tool_analytics'
+            }
+
+        }
+    };
+
+    /**
+     * Returns the model name.
+     *
+     * @param {Object} actionItem The action item DOM node.
+     * @return {String}
+     */
+    var getModelName = function(actionItem) {
+        return $(actionItem.closest('tr')[0]).find('span.target-name').text();
+    };
+
+    /** @alias module:tool_analytics/model */
+    return {
+
+        /**
+         * Displays a confirm modal window before executing the action.
+         *
+         * @param {String} actionId
+         * @param {String} actionType
+         */
+        confirmAction: function(actionId, actionType) {
+            $('[data-action-id="' + actionId + '"]').on('click', function(ev) {
+                ev.preventDefault();
+
+                var a = $(ev.currentTarget);
+
+                if (typeof actionsList[actionType] === "undefined") {
+                    log.error('Action "' + actionType + '" is not allowed.');
+                    return;
+                }
+
+                var reqStrings = [
+                    actionsList[actionType].title,
+                    actionsList[actionType].body
+                ];
+                reqStrings[1].param = getModelName(a);
+
+                var stringsPromise = Str.get_strings(reqStrings);
+                var modalPromise = ModalFactory.create({type: ModalFactory.types.SAVE_CANCEL});
+
+                $.when(stringsPromise, modalPromise).then(function(strings, modal) {
+                    modal.setTitle(strings[0]);
+                    modal.setBody(strings[1]);
+                    modal.setSaveButtonText(strings[0]);
+                    modal.getRoot().on(ModalEvents.save, function() {
+                        window.location.href = a.attr('href');
+                    });
+                    modal.show();
+                    return modal;
+                }).fail(Notification.exception);
+            });
+        }
+    };
+});
index c8f7129..66270b2 100644 (file)
@@ -45,7 +45,7 @@ class edit_model extends \moodleform {
 
         $mform = $this->_form;
 
-        if ($this->_customdata['model']->get_model_obj()->trained == 1) {
+        if ($this->_customdata['model']->is_trained()) {
             $message = get_string('edittrainedwarning', 'tool_analytics');
             $mform->addElement('html', $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING));
         }
diff --git a/admin/tool/analytics/classes/output/invalid_analysables.php b/admin/tool/analytics/classes/output/invalid_analysables.php
new file mode 100644 (file)
index 0000000..a5bda09
--- /dev/null
@@ -0,0 +1,158 @@
+<?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/>.
+
+/**
+ * Invalid analysables renderable.
+ *
+ * @package    tool_analytics
+ * @copyright  2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_analytics\output;
+
+defined('MOODLE_INTERNAL') || die;
+
+/**
+ * Invalid analysables renderable.
+ *
+ * @package    tool_analytics
+ * @copyright  2017 David Monllao {@link http://www.davidmonllao.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class invalid_analysables implements \renderable, \templatable {
+
+    /**
+     * @var \core_analytics\model
+     */
+    protected $model = null;
+
+    /**
+     * @var int
+     */
+    protected $page = 0;
+
+    /**
+     * @var int
+     */
+    protected $perpage = 0;
+
+    /**
+     * Inits the invalid analysables renderable.
+     *
+     * @param \core_analytics\model $model
+     * @param int $page
+     * @param int $perpage
+     * @return \stdClass
+     */
+    public function __construct(\core_analytics\model $model, $page, $perpage) {
+
+        $this->model = $model;
+        $this->page = $page;
+        $this->perpage = $perpage;
+    }
+
+    /**
+     * Export the data.
+     *
+     * @param \renderer_base $output
+     * @return \stdClass
+     */
+    public function export_for_template(\renderer_base $output) {
+        global $PAGE;
+
+        $offset = $this->page * $this->perpage;
+
+        $analysables = $this->model->get_analyser(['notimesplitting' => true])->get_analysables();
+
+        $skipped = 0;
+        $enoughresults = false;
+        $morepages = false;
+        $results = array();
+        foreach ($analysables as $key => $analysable) {
+
+            $validtraining = $this->model->get_target()->is_valid_analysable($analysable, true);
+            if ($validtraining === true) {
+                if ($this->model->is_static()) {
+                    // We still want to show this analysable if it is not valid to get predictions.
+                    $validtraining = get_string('notrainingbasedassumptions', 'analytics');
+                } else {
+                    // We skip analysables that are valid for training or valid for prediction.
+                    continue;
+                }
+            }
+
+            $validprediction = $this->model->get_target()->is_valid_analysable($analysable, false);
+            if ($validprediction === true) {
+                // We skip analysables that are valid for training or valid for prediction.
+                continue;
+            }
+
+            if ($offset && $skipped < $offset) {
+                $skipped++;
+                continue;
+            }
+
+            // Add a new results if we don't have enough yet.
+            if (!$enoughresults) {
+                $results[$analysable->get_id()] = array($analysable, $validtraining, $validprediction);
+                if ($this->perpage && count($results) === $this->perpage) {
+                    $enoughresults = true;
+                }
+            } else {
+                // Confirmed that we have results we can not fit into this page.
+                $morepages = true;
+                break;
+            }
+
+            unset($analysables[$key]);
+        }
+
+        // Prepare the context object.
+        $data = new \stdClass();
+        $data->modelname = $this->model->get_target()->get_name();
+
+        if ($this->page > 0) {
+            $prev = clone $PAGE->url;
+            $prev->param('page', $this->page - 1);
+            $button = new \single_button($prev, get_string('previouspage', 'tool_analytics'), 'get');
+            $data->prev = $button->export_for_template($output);
+        }
+        if ($morepages) {
+            $next = clone $PAGE->url;
+            $next->param('page', $this->page + 1);
+            $button = new \single_button($next, get_string('nextpage', 'tool_analytics'), 'get');
+            $data->next = $button->export_for_template($output);
+        }
+
+        $data->analysables = [];
+        foreach ($results as list($analysable, $validtraining, $validprediction)) {
+            $obj = new \stdClass();
+            $obj->url = \html_writer::link($analysable->get_context()->get_url(), $analysable->get_name(),
+                array('target' => '_blank'));
+
+            if ($validtraining !== true) {
+                $obj->validtraining = $validtraining;
+            }
+            if ($validprediction !== true) {
+                $obj->validprediction = $validprediction;
+            }
+            $data->analysables[] = $obj;
+        }
+
+        return $data;
+    }
+}
index b05e102..f33980c 100644 (file)
@@ -59,6 +59,7 @@ class models_list implements \renderable, \templatable {
      * @return \stdClass
      */
     public function export_for_template(\renderer_base $output) {
+        global $PAGE;
 
         $data = new \stdClass();
 
@@ -120,11 +121,13 @@ class models_list implements \renderable, \templatable {
                 }
             }
 
+            // Has this model generated predictions?.
+            $predictioncontexts = $model->get_predictions_contexts();
+
             // Model predictions list.
             if (!$model->is_enabled()) {
                 $modeldata->noinsights = get_string('disabledmodel', 'analytics');
             } else if ($model->uses_insights()) {
-                $predictioncontexts = $model->get_predictions_contexts();
                 if ($predictioncontexts) {
 
                     foreach ($predictioncontexts as $contextid => $unused) {
@@ -166,9 +169,39 @@ class models_list implements \renderable, \templatable {
             $actionsmenu->set_owner_selector('model-actions-' . $model->get_id());
             $actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL);
 
+            $urlparams = ['id' => $model->get_id(), 'sesskey' => sesskey()];
+
+            // Get predictions.
+            if (!$onlycli && $modeldata->enabled && !empty($modeldata->timesplitting)) {
+                $urlparams['action'] = 'getpredictions';
+                $url = new \moodle_url('model.php', $urlparams);
+                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/notifications',
+                    get_string('getpredictions', 'tool_analytics')), get_string('getpredictions', 'tool_analytics'));
+                $actionsmenu->add($icon);
+            }
+
+            // Evaluate machine-learning-based models.
+            if (!$onlycli && $model->get_indicators() && !$model->is_static()) {
+                $urlparams['action'] = 'evaluate';
+                $url = new \moodle_url('model.php', $urlparams);
+                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')),
+                    get_string('evaluate', 'tool_analytics'));
+                $actionsmenu->add($icon);
+            }
+
+            // Machine-learning-based models evaluation log.
+            if (!$model->is_static()) {
+                $urlparams['action'] = 'log';
+                $url = new \moodle_url('model.php', $urlparams);
+                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/report', get_string('viewlog', 'tool_analytics')),
+                    get_string('viewlog', 'tool_analytics'));
+                $actionsmenu->add($icon);
+            }
+
             // Edit model.
             if (!$model->is_static()) {
-                $url = new \moodle_url('model.php', array('action' => 'edit', 'id' => $model->get_id()));
+                $urlparams['action'] = 'edit';
+                $url = new \moodle_url('model.php', $urlparams);
                 $icon = new \action_menu_link_secondary($url, new \pix_icon('t/edit', get_string('edit')), get_string('edit'));
                 $actionsmenu->add($icon);
             }
@@ -183,39 +216,39 @@ class models_list implements \renderable, \templatable {
                 $text = get_string('enable');
                 $icontype = 'i/checked';
             }
-            $url = new \moodle_url('model.php', array('action' => $action, 'id' => $model->get_id()));
+            $urlparams['action'] = $action;
+            $url = new \moodle_url('model.php', $urlparams);
             $icon = new \action_menu_link_secondary($url, new \pix_icon($icontype, $text), $text);
             $actionsmenu->add($icon);
 
-            // Evaluate machine-learning-based models.
-            if (!$onlycli && $model->get_indicators() && !$model->is_static()) {
-                $url = new \moodle_url('model.php', array('action' => 'evaluate', 'id' => $model->get_id()));
-                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/calc', get_string('evaluate', 'tool_analytics')),
-                    get_string('evaluate', 'tool_analytics'));
-                $actionsmenu->add($icon);
-            }
-
-            // Get predictions.
-            if (!$onlycli && $modeldata->enabled && !empty($modeldata->timesplitting)) {
-                $url = new \moodle_url('model.php', array('action' => 'getpredictions', 'id' => $model->get_id()));
-                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/notifications',
-                    get_string('getpredictions', 'tool_analytics')), get_string('getpredictions', 'tool_analytics'));
+            // Export training data.
+            if (!$model->is_static() && $model->is_trained()) {
+                $urlparams['action'] = 'export';
+                $url = new \moodle_url('model.php', $urlparams);
+                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/export',
+                    get_string('exporttrainingdata', 'tool_analytics')), get_string('export', 'tool_analytics'));
                 $actionsmenu->add($icon);
             }
 
-            // Machine-learning-based models evaluation log.
-            if (!$model->is_static()) {
-                $url = new \moodle_url('model.php', array('action' => 'log', 'id' => $model->get_id()));
-                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/report', get_string('viewlog', 'tool_analytics')),
-                    get_string('viewlog', 'tool_analytics'));
+            // Invalid analysables.
+            $analyser = $model->get_analyser(['notimesplitting' => true]);
+            if (!$analyser instanceof \core_analytics\local\analyser\sitewide) {
+                $urlparams['action'] = 'invalidanalysables';
+                $url = new \moodle_url('model.php', $urlparams);
+                $pix = new \pix_icon('i/report', get_string('invalidanalysables', 'tool_analytics'));
+                $icon = new \action_menu_link_secondary($url, $pix, get_string('invalidanalysables', 'tool_analytics'));
                 $actionsmenu->add($icon);
             }
 
-            // Export training data.
-            if (!$model->is_static() && $model->is_trained()) {
-                $url = new \moodle_url('model.php', array('action' => 'export', 'id' => $model->get_id()));
-                $icon = new \action_menu_link_secondary($url, new \pix_icon('i/export',
-                    get_string('exporttrainingdata', 'tool_analytics')), get_string('export', 'tool_analytics'));
+            // Clear model.
+            if (!empty($predictioncontexts)) {
+                $actionid = 'clear-' . $model->get_id();
+                $PAGE->requires->js_call_amd('tool_analytics/model', 'confirmAction', [$actionid, 'clear']);
+                $urlparams['action'] = 'clear';
+                $url = new \moodle_url('model.php', $urlparams);
+                $icon = new \action_menu_link_secondary($url, new \pix_icon('e/cleanup_messy_code',
+                    get_string('clearpredictions', 'tool_analytics')), get_string('clearpredictions', 'tool_analytics'),
+                    ['data-action-id' => $actionid]);
                 $actionsmenu->add($icon);
             }
 
index 32bdcfc..4201482 100644 (file)
@@ -159,11 +159,12 @@ class renderer extends plugin_renderer_base {
             if ($trainresults->status == 0) {
                 $output .= $OUTPUT->notification(get_string('trainingprocessfinished', 'tool_analytics'),
                     \core\output\notification::NOTIFY_SUCCESS);
-            } else if ($trainresults->status === \core_analytics\model::NO_DATASET) {
+            } else if ($trainresults->status === \core_analytics\model::NO_DATASET ||
+                    $trainresults->status === \core_analytics\model::NOT_ENOUGH_DATA) {
                 $output .= $OUTPUT->notification(get_string('nodatatotrain', 'tool_analytics'),
                     \core\output\notification::NOTIFY_WARNING);
             } else {
-                $output .= $OUTPUT->notification(get_string('generalerror', 'analytics', $trainresults->status),
+                $output .= $OUTPUT->notification(get_string('generalerror', 'tool_analytics', $trainresults->status),
                     \core\output\notification::NOTIFY_ERROR);
             }
         }
@@ -183,11 +184,12 @@ class renderer extends plugin_renderer_base {
             if ($predictresults->status == 0) {
                 $output .= $OUTPUT->notification(get_string('predictionprocessfinished', 'tool_analytics'),
                     \core\output\notification::NOTIFY_SUCCESS);
-            } else if ($predictresults->status === \core_analytics\model::NO_DATASET) {
+            } else if ($predictresults->status === \core_analytics\model::NO_DATASET ||
+                    $predictresults->status === \core_analytics\model::NOT_ENOUGH_DATA) {
                 $output .= $OUTPUT->notification(get_string('nodatatopredict', 'tool_analytics'),
                     \core\output\notification::NOTIFY_WARNING);
             } else {
-                $output .= $OUTPUT->notification(get_string('generalerror', 'analytics', $predictresults->status),
+                $output .= $OUTPUT->notification(get_string('generalerror', 'tool_analytics', $predictresults->status),
                     \core\output\notification::NOTIFY_ERROR);
             }
         }
@@ -205,4 +207,15 @@ class renderer extends plugin_renderer_base {
 
         return $output;
     }
+
+    /**
+     * Defer to template.
+     *
+     * @param \tool_analytics\output\invalid_analysables $invalidanalysables
+     * @return string HTML
+     */
+    protected function render_invalid_analysables(\tool_analytics\output\invalid_analysables $invalidanalysables) {
+        $data = $invalidanalysables->export_for_template($this);
+        return parent::render_from_template('tool_analytics/invalid_analysables', $data);
+    }
 }
index df38a14..6891ec2 100644 (file)
 $string['accuracy'] = 'Accuracy';
 $string['allpredictions'] = 'All predictions';
 $string['analysingsitedata'] = 'Analysing the site';
-$string['analyticmodels'] = 'Analytic models';
+$string['analyticmodels'] = 'Analytics models';
 $string['bettercli'] = 'Evaluating models and generating predictions may involve heavy processing. It is recommended to run these actions from the command line.';
 $string['cantguessstartdate'] = 'Can\'t guess the start date';
 $string['cantguessenddate'] = 'Can\'t guess the end date';
+$string['clearpredictions'] = 'Clear predictions';
+$string['clearmodelpredictions'] = 'Are you sure you want to clear all "{$a}" predictions?';
 $string['clienablemodel'] = 'You can enable the model by selecting a time-splitting method by its ID. Note that you can also enable it later using the web interface (\'none\' to exit).';
-$string['clievaluationandpredictions'] = 'A cron task iterates through enabled models and gets predictions. Models evaluation via command line is disabled. You can allow these processes to be executed manually via web interface by enabling <a href="{$a}">\'onlycli\' analytics setting</a>';
+$string['clievaluationandpredictions'] = 'A scheduled task iterates through enabled models and gets predictions. Models evaluation via the web interface is disabled. You can allow these processes to be executed manually via the web interface by disabling the <a href="{$a}">\'onlycli\'</a> analytics setting.';
 $string['editmodel'] = 'Edit "{$a}" model';
 $string['edittrainedwarning'] = 'This model has already been trained. Note that changing its indicators or its time-splitting method will delete its previous predictions and start generating new predictions.';
 $string['enabled'] = 'Enabled';
@@ -57,10 +59,16 @@ $string['goodmodel'] = 'This is a good model for using to obtain predictions. En
 $string['indicators'] = 'Indicators';
 $string['info'] = 'Info';
 $string['insights'] = 'Insights';
+$string['invalidanalysables'] = 'Invalid site elements';
+$string['invalidanalysablesinfo'] = 'This pages lists this site analysable elements that can not be used by this prediction model. The listed elements can not be used neither to train the prediction model nor the prediction model can get predictions for them.';
+$string['invalidanalysablestable'] = 'Invalid site analysable elements table';
+$string['invalidprediction'] = 'Invalid to get predictions';
+$string['invalidtraining'] = 'Invalid to train the model';
 $string['loginfo'] = 'Log extra info';
+$string['modelinvalidanalysables'] = 'Invalid analysable elements for "{$a}" model';
 $string['modelresults'] = '{$a} results';
-$string['modelslist'] = 'Models list';
 $string['modeltimesplitting'] = 'Time splitting';
+$string['nextpage'] = 'Next page';
 $string['nodatatoevaluate'] = 'There is no data to evaluate the model';
 $string['nodatatopredict'] = 'No new elements to get predictions for';
 $string['nodatatotrain'] = 'There is no new data that can be used for training';
@@ -70,6 +78,7 @@ $string['predictionresults'] = 'Prediction results';
 $string['predictmodels'] = 'Predict models';
 $string['predictorresultsin'] = 'Predictor logged information in {$a} directory';
 $string['predictionprocessfinished'] = 'Prediction process finished';
+$string['previouspage'] = 'Previous page';
 $string['samestartdate'] = 'Current start date is good';
 $string['sameenddate'] = 'Current end date is good';
 $string['target'] = 'Target';
index 6d64c42..58f1129 100644 (file)
@@ -60,7 +60,12 @@ switch ($action) {
     case 'export':
         $title = get_string('export', 'tool_analytics');
         break;
-
+    case 'clear':
+        $title = get_string('clearpredictions', 'tool_analytics');
+        break;
+    case 'invalidanalysables':
+        $title = get_string('invalidanalysables', 'tool_analytics');
+        break;
     default:
         throw new moodle_exception('errorunknownaction', 'analytics');
 }
@@ -80,14 +85,21 @@ if ($onlycli === false) {
 switch ($action) {
 
     case 'enable':
+        confirm_sesskey();
+
         $model->enable();
         redirect(new \moodle_url('/admin/tool/analytics/index.php'));
+        break;
 
     case 'disable':
+        confirm_sesskey();
+
         $model->update(0, false, false);
         redirect(new \moodle_url('/admin/tool/analytics/index.php'));
+        break;
 
     case 'edit':
+        confirm_sesskey();
 
         if ($model->is_static()) {
             echo $OUTPUT->header();
@@ -106,7 +118,6 @@ switch ($action) {
             redirect(new \moodle_url('/admin/tool/analytics/index.php'));
 
         } else if ($data = $mform->get_data()) {
-            confirm_sesskey();
 
             // Converting option names to class names.
             $indicators = array();
@@ -131,6 +142,8 @@ switch ($action) {
         break;
 
     case 'evaluate':
+        confirm_sesskey();
+
         echo $OUTPUT->header();
 
         if ($model->is_static()) {
@@ -150,6 +163,8 @@ switch ($action) {
         break;
 
     case 'getpredictions':
+        confirm_sesskey();
+
         echo $OUTPUT->header();
 
         if ($onlycli) {
@@ -200,6 +215,27 @@ switch ($action) {
         $filename = 'training-data.' . $model->get_id() . '.' . time() . '.csv';
         send_file($file, $filename, null, 0, false, true);
         break;
+
+    case 'clear':
+        confirm_sesskey();
+
+        $model->clear();
+        redirect(new \moodle_url('/admin/tool/analytics/index.php'));
+        break;
+
+    case 'invalidanalysables':
+
+        echo $OUTPUT->header();
+
+        $page = optional_param('page', 0, PARAM_INT);
+        // No option in the UI to change this, only for url hackers ;).
+        $perpage = optional_param('perpage', 10, PARAM_INT);
+
+        $renderable = new \tool_analytics\output\invalid_analysables($model, $page, $perpage);
+        $renderer = $PAGE->get_renderer('tool_analytics');
+        echo $renderer->render($renderable);
+
+        break;
 }
 
 echo $OUTPUT->footer();
diff --git a/admin/tool/analytics/templates/invalid_analysables.mustache b/admin/tool/analytics/templates/invalid_analysables.mustache
new file mode 100644 (file)
index 0000000..c97dd6b
--- /dev/null
@@ -0,0 +1,78 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_analytics/invalid_analysables
+
+    Template for invalid analysables.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * none
+
+    Example context (json):
+    {
+        "modelname": "Not engaging courses",
+        "analysables": [
+            {
+                "url": "<a href=\"#\">Maths</a>",
+                "validtraining": "Ongoing course",
+                "validprediction": "Not enough students activity"
+            }, {
+                "url": "<a href=\"#\">Psichology</a>",
+                "validtraining": "No students",
+                "validprediction": "No students"
+            }
+        ]
+    }
+}}
+
+<div class="box">
+    <h3>{{#str}}modelinvalidanalysables, tool_analytics, {{modelname}}{{/str}}</h3>
+    <div>{{#str}}invalidanalysablesinfo, tool_analytics{{/str}}</div>
+    <div class="m-t-2 m-b-1">
+        <span>{{#prev}}{{> core/single_button}}{{/prev}}</span>
+        <span>{{#next}}{{> core/single_button}}{{/next}}</span>
+    </div>
+    <table class="generaltable fullwidth">
+        <caption class="accesshide">{{#str}}invalidanalysablestable, tool_analytics{{/str}}</caption>
+        <thead>
+            <tr>
+                <th scope="col">{{#str}}name{{/str}}</th>
+                <th scope="col">{{#str}}invalidtraining, tool_analytics{{/str}}</th>
+                <th scope="col">{{#str}}invalidprediction, tool_analytics{{/str}}</th>
+            </tr>
+        </thead>
+        <tbody>
+        {{#analysables}}
+            <tr>
+                <td>{{{url}}}</td>
+                <td>{{validtraining}}</td>
+                <td>{{validprediction}}</td>
+            </tr>
+        {{/analysables}}
+        </tbody>
+    </table>
+    <div class="m-t-1 m-b-2">
+        <span>{{#prev}}{{> core/single_button}}{{/prev}}</span>
+        <span>{{#next}}{{> core/single_button}}{{/next}}</span>
+    </div>
+</div>
index 9330c54..8eb6211 100644 (file)
 
 <div class="box">
     <table class="generaltable fullwidth">
-        <caption>{{#str}}modelslist, tool_analytics{{/str}}</caption>
+        <caption>{{#str}}analyticmodels, tool_analytics{{/str}}</caption>
         <thead>
             <tr>
                 <th scope="col">{{#str}}target, tool_analytics{{/str}}</th>
         {{#models}}
             <tr>
                 <td>
-                    {{target}}
+                    <span class="target-name">{{target}}</span>
                     {{#targethelp}}
                         {{>core/help_icon}}
                     {{/targethelp}}
diff --git a/admin/tool/httpsreplace/classes/form.php b/admin/tool/httpsreplace/classes/form.php
new file mode 100644 (file)
index 0000000..cd83473
--- /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/>.
+
+/**
+ * Site wide http -> https search-replace form.
+ *
+ * @package    tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_httpsreplace;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once("$CFG->libdir/formslib.php");
+
+/**
+ * Site wide http -> https search-replace form.
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class form extends \moodleform {
+
+    /**
+     * Define the form.
+     */
+    public function definition() {
+        $mform = $this->_form;
+
+        $mform->addElement('header', 'confirmhdr', get_string('confirm'));
+        $mform->setExpanded('confirmhdr', true);
+        $mform->addElement('checkbox', 'sure', get_string('disclaimer', 'tool_httpsreplace'));
+        $mform->addRule('sure', get_string('required'), 'required', null, 'client');
+        $mform->disable_form_change_checker();
+
+        $this->add_action_buttons(false, get_string('doit', 'tool_httpsreplace'));
+    }
+}
diff --git a/admin/tool/httpsreplace/classes/url_finder.php b/admin/tool/httpsreplace/classes/url_finder.php
new file mode 100644 (file)
index 0000000..af9fc9b
--- /dev/null
@@ -0,0 +1,261 @@
+<?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/>.
+
+/**
+ * url_finder class definition.
+ *
+ * @package    tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_httpsreplace;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Examines DB for non-https src or data links
+ *
+ * @package tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class url_finder {
+
+    /**
+     * Returns a hash of what hosts are referred to over http and would need to be changed.
+     *
+     * @param progress_bar $progress Progress bar keeping track of this process.
+     * @return array Hash of domains with number of references as the value.
+     */
+    public function http_link_stats($progress = null) {
+        return $this->process(false, $progress);
+    }
+
+    /**
+     * Changes all resources referred to over http to https.
+     *
+     * @param progress_bar $progress Progress bar keeping track of this process.
+     * @return bool True upon success
+     */
+    public function upgrade_http_links($progress = null) {
+        return $this->process(true, $progress);
+    }
+
+    /**
+     * Replace http domains with https equivalent, with two types of exceptions
+     * for less straightforward swaps.
+     *
+     * @param string $table
+     * @param string $column
+     * @param string $domain
+     * @param string $search search string that has prefix, protocol, domain name and one extra character,
+     *      example1: src="http://host.com/
+     *      example2: DATA="HTTP://MYDOMAIN.EDU"
+     *      example3: src="HTTP://hello.world?
+     * @return void
+     */
+    protected function domain_swap($table, $column, $domain, $search) {
+        global $DB;
+
+        $renames = json_decode(get_config('tool_httpsreplace', 'renames'), true);
+
+        if (isset($renames[$domain])) {
+            $replace = preg_replace('|http://'.preg_quote($domain).'|i', 'https://' . $renames[$domain], $search);
+        } else {
+            $replace = preg_replace('|http://|i', 'https://', $search);
+        }
+        $DB->set_debug(true);
+        $DB->replace_all_text($table, $column, $search, $replace);
+        $DB->set_debug(false);
+    }
+
+    /**
+     * Returns SQL to be used to match embedded http links in the given column
+     *
+     * @param string $columnname name of the column (ready to be used in the SQL query)
+     * @return array
+     */
+    protected function get_select_search_in_column($columnname) {
+        global $DB;
+
+        if ($DB->sql_regex_supported()) {
+            // Database supports regex, use it for better match.
+            $select = $columnname . ' ' . $DB->sql_regex() . ' ?';
+            $params = ["(src|data)\ *=\ *[\\\"\']http://"];
+        } else {
+            // Databases without regex support should use case-insensitive LIKE.
+            // This will have false positive matches and more results than we need, we'll have to filter them in php.
+            $select = $DB->sql_like($columnname, '?', false);
+            $params = ['%=%http://%'];
+        }
+
+        return [$select, $params];
+    }
+
+    /**
+     * Originally forked from core function db_search().
+     * @param bool $replacing Whether or not to replace the found urls.
+     * @param progress_bar $progress Progress bar keeping track of this process.
+     * @return bool|array If $replacing, return true on success. If not, return hash of http urls to number of times used.
+     */
+    protected function process($replacing = false, $progress = null) {
+        global $DB, $CFG;
+
+        require_once($CFG->libdir.'/filelib.php');
+
+        // TODO: block_instances have HTML content as base64, need to decode then
+        // search, currently just skipped. See MDL-60024.
+        $skiptables = array(
+            'block_instances',
+            'config',
+            'config_log',
+            'config_plugins',
+            'events_queue',
+            'files',
+            'filter_config',
+            'grade_grades_history',
+            'grade_items_history',
+            'log',
+            'logstore_standard_log',
+            'repository_instance_config',
+            'sessions',
+            'upgrade_log',
+            'grade_categories_history',
+            '',
+        );
+
+        // Turn off time limits.
+        \core_php_time_limit::raise();
+        if (!$tables = $DB->get_tables() ) {    // No tables yet at all.
+            return false;
+        }
+
+        $urls = array();
+
+        $numberoftables = count($tables);
+        $tablenumber = 0;
+        foreach ($tables as $table) {
+            if ($progress) {
+                $progress->update($tablenumber, $numberoftables, get_string('searching', 'tool_httpsreplace', $table));
+                $tablenumber++;
+            }
+            if (in_array($table, $skiptables)) {
+                continue;
+            }
+            if ($columns = $DB->get_columns($table)) {
+                foreach ($columns as $column) {
+
+                    // Only convert columns that are either text or long varchar.
+                    if ($column->meta_type == 'X' || ($column->meta_type == 'C' && $column->max_length > 255)) {
+                        $columnname = $column->name;
+                        $columnnamequoted = $DB->get_manager()->generator->getEncQuoted($columnname);
+                        list($select, $params) = $this->get_select_search_in_column($columnnamequoted);
+                        $rs = $DB->get_recordset_select($table, $select, $params, '', $columnnamequoted);
+
+                        $found = array();
+                        foreach ($rs as $record) {
+                            // Regex to match src=http://etc. and data=http://etc.urls.
+                            // Standard warning on expecting regex to perfectly parse HTML
+                            // read http://stackoverflow.com/a/1732454 for more info.
+                            $regex = '#((src|data)\ *=\ *[\'\"])(http://)([^\s()<>]+(?:\([\w\d]+\)|([^[:punct:]\s]|/)))[\'\"]#i';
+                            preg_match_all($regex, $record->$columnname, $match);
+                            foreach ($match[0] as $i => $fullmatch) {
+                                if (strpos($fullmatch, $CFG->wwwroot) !== false) {
+                                    continue;
+                                }
+                                $prefix = $match[1][$i];
+                                $protocol = $match[3][$i];
+                                $url = $protocol . $match[4][$i];
+                                $host = \core_text::strtolower(parse_url($url, PHP_URL_HOST));
+                                if (empty($host)) {
+                                    continue;
+                                }
+                                if ($replacing) {
+                                    // For replace string use: prefix, protocol, host and one extra character.
+                                    $found[$prefix . substr($url, 0, strlen($host) + 8)] = $host;
+                                } else {
+                                    $entry["table"] = $table;
+                                    $entry["columnname"] = $columnname;
+                                    $entry["url"] = $url;
+                                    $entry["host"] = $host;
+                                    $entry["raw"] = $record->$columnname;
+                                    $entry["ssl"] = '';
+                                    $urls[] = $entry;
+                                }
+                            }
+                        }
+                        $rs->close();
+
+                        if ($replacing) {
+                            foreach ($found as $search => $domain) {
+                                $this->domain_swap($table, $column, $domain, $search);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if ($replacing) {
+            rebuild_course_cache(0, true);
+            purge_all_caches();
+            return true;
+        }
+
+        $domains = array_map(function ($i) {
+            return $i['host'];
+        }, $urls);
+
+        $uniquedomains = array_unique($domains);
+
+        $sslfailures = array();
+
+        foreach ($uniquedomains as $domain) {
+            if (!$this->check_domain_availability("https://$domain/")) {
+                $sslfailures[] = $domain;
+            }
+        }
+
+        $results = array();
+        foreach ($urls as $url) {
+            $host = $url['host'];
+            foreach ($sslfailures as $badhost) {
+                if ($host == $badhost) {
+                    if (!isset($results[$host])) {
+                        $results[$host] = 1;
+                    } else {
+                        $results[$host]++;
+                    }
+                }
+            }
+        }
+        return $results;
+    }
+
+    /**
+     * Check if url is available (GET request returns 200)
+     *
+     * @param string $url
+     * @return bool
+     */
+    protected function check_domain_availability($url) {
+        $curl = new \curl();
+        $curl->head($url);
+        $info = $curl->get_info();
+        return !empty($info['http_code']) && $info['http_code'] == 200;
+    }
+}
diff --git a/admin/tool/httpsreplace/cli/url_replace.php b/admin/tool/httpsreplace/cli/url_replace.php
new file mode 100644 (file)
index 0000000..b8e4116
--- /dev/null
@@ -0,0 +1,93 @@
+<?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/>.
+
+/**
+ * url_replace cli script. Examines DB for non-https src or data links, and lists broken ones or replaces all links.
+ *
+ * @package    tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+require(__DIR__ . '/../../../../config.php');
+require_once($CFG->libdir.'/clilib.php');
+
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'help' => false,
+        'list' => false,
+        'replace' => false,
+        'confirm' => false,
+    ),
+    array(
+        'h' => 'help',
+        'l' => 'list',
+        'r' => 'replace',
+    )
+);
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized), 2);
+}
+if ($options['help'] || (!$options['list'] && !$options['replace'])) {
+    $help = "Examines DB for non-https src or data links, and lists broken links or replaces all links.
+Options:
+-h, --help            Print out this help
+-l, --list            List of http (not https) urls on a site in the DB that would become broken.
+-r, --replace         List of http (not https) urls on a site in the DB that would become broken.
+--confirm             Replaces http urls with https across a site's content.
+Example:
+\$ sudo -u www-data /usr/bin/php admin/tool/httpsreplace/cli/url_replace.php --list \n";
+    echo $help;
+    exit(0);
+}
+
+if (!$DB->replace_all_text_supported()) {
+    echo $OUTPUT->notification(get_string('notimplemented', 'tool_httpsreplace'));
+    exit(1);
+}
+
+if (!is_https()) {
+    echo $OUTPUT->notification(get_string('httpwarning', 'tool_httpsreplace'), 'warning');
+    echo "\n";
+}
+
+if ($options['replace']) {
+
+    if ($options['confirm']) {
+
+        $urlfinder = new \tool_httpsreplace\url_finder();
+        $urlfinder->upgrade_http_links();
+    } else {
+        echo "Once this is tool run, changes made can't be reverted. \n" .
+             "A complete backup should be made before running this script. \n\n" .
+             "There is a low risk that the wrong content will be replaced, introducing problems. \n" .
+             "If you are sure you want to continue, add --confirm\n\n";
+    }
+
+} else {
+
+    $urlfinder = new \tool_httpsreplace\url_finder();
+    $results = $urlfinder->http_link_stats();
+    asort($results);
+    $fp = fopen('php://stdout', 'w');
+    fputcsv($fp, ['clientsite', 'httpdomain', 'urlcount']);
+    foreach ($results as $domain => $count) {
+        fputcsv($fp, [$SITE->shortname, $domain, $count]);
+    }
+    fclose($fp);
+}
diff --git a/admin/tool/httpsreplace/index.php b/admin/tool/httpsreplace/index.php
new file mode 100644 (file)
index 0000000..a3cec32
--- /dev/null
@@ -0,0 +1,59 @@
+<?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/>.
+
+/**
+ * Search and replace http -> https throughout all texts in the whole database
+ *
+ * @package    tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+require_once($CFG->libdir . '/adminlib.php');
+
+admin_externalpage_setup('toolhttpsreplace');
+
+$context = context_system::instance();
+
+require_login();
+require_capability('moodle/site:config', $context);
+
+$PAGE->set_context($context);
+$PAGE->set_url(new moodle_url('/admin/tool/httpsreplace/index.php'));
+$PAGE->set_title(get_string('pageheader', 'tool_httpsreplace'));
+$PAGE->set_pagelayout('admin');
+
+echo $OUTPUT->header();
+
+echo $OUTPUT->heading(get_string('pageheader', 'tool_httpsreplace'));
+
+if (!$DB->replace_all_text_supported()) {
+    echo $OUTPUT->notification(get_string('notimplemented', 'tool_httpsreplace'));
+    echo $OUTPUT->footer();
+    die;
+}
+
+if (!is_https()) {
+    echo $OUTPUT->notification(get_string('httpwarning', 'tool_httpsreplace'), 'warning');
+}
+
+echo '<p>'.get_string('domainexplain', 'tool_httpsreplace').'</p>';
+echo '<p>'.page_doc_link(get_string('doclink', 'tool_httpsreplace')).'</p>';
+
+echo $OUTPUT->continue_button(new moodle_url('/admin/tool/httpsreplace/tool.php'));
+
+echo $OUTPUT->footer();
diff --git a/admin/tool/httpsreplace/lang/en/tool_httpsreplace.php b/admin/tool/httpsreplace/lang/en/tool_httpsreplace.php
new file mode 100644 (file)
index 0000000..98baf99
--- /dev/null
@@ -0,0 +1,43 @@
+<?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/>.
+
+/**
+ * Strings for component 'tool_httpsreplace'
+ *
+ * @package    tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['complete'] = 'Completed';
+$string['count'] = 'Number of embedded content items';
+$string['disclaimer'] = 'I understand the risks of this operation';
+$string['doclink'] = 'HTTPS conversion tool';
+$string['doit'] = 'Perform conversion';
+$string['domain'] = 'Problematic domain';
+$string['domainexplain'] = 'When a site is moved from HTTP to HTTPS, all embeded HTTP content will stop working. This tool allows you to automatically convert HTTP content to HTTPS.
+
+Before performing the conversion, content will be scanned to find any URLs which may not work after conversion. You may want to check each one has HTTPS available, or find alternative resources.';
+$string['domainexplainhelp'] = 'These domains are found in your content, but do not appear to support HTTPS content. After switching to HTTPS, the content included from these sites will no longer display within Moodle for users with secure modern browsers. It is possible that these sites are temporarily or permanently unavailable and will not work with either security setting. Proceed only after reviewing these results and determining if this externally-hosted content is non-essential. Note: This content would no longer work upon switching to HTTPS anyway.';
+$string['httpwarning'] = 'This instance is still running on HTTP. You can still run this tool and external content will be changed to HTTPS, but internal content will remain on HTTP. You will need to run this script again after switching to HTTPS to convert internal content.';
+$string['notimplemented'] = 'Sorry, this feature is not implemented in your database driver.';
+$string['oktoprocede'] = 'The scan finds no issues with your content. You can proceed to upgrade any HTTP content to use HTTPS.';
+$string['pageheader'] = 'Upgrade externally-hosted content URLs to HTTPS';
+$string['pluginname'] = 'HTTPS conversion tool';
+$string['replacing'] = 'Replacing HTTP content with HTTPS...';
+$string['searching'] = 'Searching {$a}';
+$string['takeabackupwarning'] = 'Warning: After running this tool, changes cannot be reverted. It is recommended that a site backup is made before proceeding, as there is a small risk of wrong content being replaced.';
+$string['toolintro'] = 'If you are planning on converting your site to HTTPS, you can use the <a href="{$a}">HTTPS conversion tool</a> to convert your embedded content to HTTPS.';
diff --git a/admin/tool/httpsreplace/settings.php b/admin/tool/httpsreplace/settings.php
new file mode 100644 (file)
index 0000000..bf5c259
--- /dev/null
@@ -0,0 +1,41 @@
+<?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/>.
+
+/**
+ * Link to http -> https replace script.
+ *
+ * @package tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die;
+
+if ($hassiteconfig) {
+
+    $pluginname = get_string('pluginname', 'tool_httpsreplace');
+    $url = $CFG->wwwroot.'/'.$CFG->admin.'/tool/httpsreplace/index.php';
+    $ADMIN->add('security', new admin_externalpage('toolhttpsreplace', $pluginname, $url, 'moodle/site:config', true));
+
+    $httpsreplaceurl = $CFG->wwwroot.'/'.$CFG->admin.'/tool/httpsreplace/index.php';
+    $ADMIN->locate('httpsecurity')->add(
+        new admin_setting_heading(
+            'tool_httpsreplaceheader',
+            new lang_string('pluginname', 'tool_httpsreplace'),
+            new lang_string('toolintro', 'tool_httpsreplace', $httpsreplaceurl)
+        )
+    );
+}
diff --git a/admin/tool/httpsreplace/tests/behat/httpsreplace.feature b/admin/tool/httpsreplace/tests/behat/httpsreplace.feature
new file mode 100644 (file)
index 0000000..82bbf59
--- /dev/null
@@ -0,0 +1,29 @@
+@tool @tool_httpsreplace
+Feature: View the httpsreplace report
+  In order to switch to https
+  As an admin
+  I need to be able to automatically replace http links
+
+  Background: Create some http links
+    Given I am on site homepage
+    And the following "courses" exist:
+      | fullname | shortname | category | summary                                                                                                     |
+      | Course 1 | C1        | 0        | <img src="http://intentionally.unavailable/test.png"> <img src="http://download.moodle.org/unittest/test.jpg"> |
+    And I log in as "admin"
+
+  @javascript
+  Scenario: Go to the HTTPS replace report screen. Make sure broken domains are reported.
+    When I navigate to "HTTP security" node in "Site administration > Security"
+    And I follow "HTTPS conversion tool"
+    And I press "Continue"
+    Then I should see "intentionally.unavailable"
+
+  @javascript
+  Scenario: Use the find and replace tool.
+    When I navigate to "HTTP security" node in "Site administration > Security"
+    And I follow "HTTPS conversion tool"
+    And I press "Continue"
+    And I set the field "I understand the risks of this operation" to "1"
+    And I press "Perform replacement"
+    Then I should see "intentionally.unavailable"
+    And I should see "download.moodle.org"
diff --git a/admin/tool/httpsreplace/tests/httpsreplace_test.php b/admin/tool/httpsreplace/tests/httpsreplace_test.php
new file mode 100644 (file)
index 0000000..c10ea2f
--- /dev/null
@@ -0,0 +1,413 @@
+<?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/>.
+
+/**
+ * HTTPS find and replace Tests
+ *
+ * @package   tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace tool_httpsreplace\tests;
+
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Tests the httpsreplace tool.
+ *
+ * @package   tool_httpsreplace
+ * @copyright Copyright (c) 2016 Blackboard Inc. (http://www.blackboard.com)
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class httpsreplace_test extends \advanced_testcase {
+
+    /**
+     * Data provider for test_upgrade_http_links
+     */
+    public function upgrade_http_links_provider() {
+        global $CFG;
+        // Get the http url, since the default test wwwroot is https.
+        $wwwroothttp = preg_replace('/^https:/', 'http:', $CFG->wwwroot);
+        return [
+            "Test image from another site should be replaced" => [
+                "content" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', false) . '">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<img src="' . $this->getExternalTestFileUrl('/test.jpg', true) . '">',
+            ],
+            "Test object from another site should be replaced" => [
+                "content" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<object data="' . $this->getExternalTestFileUrl('/test.swf', true) . '">',
+            ],
+            "Test image from a site with international name should be replaced" => [
+                "content" => '<img src="http://中国互联网络信息中心.中国/logosy/201706/W01.png">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<img src="https://中国互联网络信息中心.中国/logosy/201706/W01.png">',
+            ],
+            "Link that is from this site should be replaced" => [
+                "content" => '<img src="' . $wwwroothttp . '/logo.png">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<img src="' . $CFG->wwwroot . '/logo.png">',
+            ],
+            "Link that is from this site, https new so doesn't need replacing" => [
+                "content" => '<img src="' . $CFG->wwwroot . '/logo.png">',
+                "outputregex" => '/^$/',
+                "expectedcontent" => '<img src="' . $CFG->wwwroot . '/logo.png">',
+            ],
+            "Unavailable image should be replaced" => [
+                "content" => '<img src="http://intentionally.unavailable/link1.jpg">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<img src="https://intentionally.unavailable/link1.jpg">',
+            ],
+            "Https content that has an http url as a param should not be replaced" => [
+                "content" => '<img src="https://anothersite.com?param=http://asdf.com">',
+                "outputregex" => '/^$/',
+                "expectedcontent" => '<img src="https://anothersite.com?param=http://asdf.com">',
+            ],
+            "Search for params should be case insensitive" => [
+                "content" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', false) . '">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<object DATA="' . $this->getExternalTestFileUrl('/test.swf', true) . '">',
+            ],
+            "URL should be case insensitive" => [
+                "content" => '<object data="HTTP://some.site/path?query">',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<object data="https://some.site/path?query">',
+            ],
+            "More params should not interfere" => [
+                "content" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', false) .
+                    '" width="1”><p style="font-size: \'20px\'"></p>',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<img alt="A picture" src="' . $this->getExternalTestFileUrl('/test.png', true) .
+                    '" width="1”><p style="font-size: \'20px\'"></p>',
+            ],
+            "Broken URL should not be changed" => [
+                "content" => '<img src="broken.' . $this->getExternalTestFileUrl('/test.png', false) . '">',
+                "outputregex" => '/^$/',
+                "expectedcontent" => '<img src="broken.' . $this->getExternalTestFileUrl('/test.png', false) . '">',
+            ],
+            "Link URL should not be changed" => [
+                "content" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '">' .
+                    $this->getExternalTestFileUrl('/test.png', false) . '</a>',
+                "outputregex" => '/^$/',
+                "expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '">' .
+                    $this->getExternalTestFileUrl('/test.png', false) . '</a>',
+            ],
+            "Test image from another site should be replaced but link should not" => [
+                "content" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
+                    $this->getExternalTestFileUrl('/test.jpg', false) . '"></a>',
+                "outputregex" => '/UPDATE/',
+                "expectedcontent" => '<a href="' . $this->getExternalTestFileUrl('/test.png', false) . '"><img src="' .
+                    $this->getExternalTestFileUrl('/test.jpg', true) . '"></a>',
+            ],
+        ];
+    }
+
+    /**
+     * Test upgrade_http_links
+     * @param string $content Example content that we'll attempt to replace.
+     * @param string $ouputregex Regex for what output we expect.
+     * @param string $expectedcontent What content we are expecting afterwards.
+     * @dataProvider upgrade_http_links_provider
+     */
+    public function test_upgrade_http_links($content, $ouputregex, $expectedcontent) {
+        global $DB;
+
+        $this->resetAfterTest();
+        $this->expectOutputRegex($ouputregex);
+
+        $finder = new tool_httpreplace_url_finder_test();
+
+        $generator = $this->getDataGenerator();
+        $course = $generator->create_course((object) [
+            'summary'