Merge branch 'MDL-56751-master' of git://github.com/jleyva/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Tue, 25 Jul 2017 02:44:05 +0000 (10:44 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Tue, 25 Jul 2017 02:44:05 +0000 (10:44 +0800)
758 files changed:
.eslintignore
.stylelintignore
.stylelintrc
.travis.yml
Gruntfile.js
admin/cli/install.php
admin/cli/install_database.php
admin/cli/upgrade.php
admin/environment.xml
admin/index.php
admin/registration/forms.php
admin/searchareas.php
admin/settings/analytics.php [new file with mode: 0644]
admin/settings/plugins.php
admin/settings/users.php
admin/tool/analytics/amd/build/log_info.min.js [new file with mode: 0644]
admin/tool/analytics/amd/src/log_info.js [new file with mode: 0644]
admin/tool/analytics/classes/output/form/edit_model.php [new file with mode: 0644]
admin/tool/analytics/classes/output/helper.php [new file with mode: 0644]
admin/tool/analytics/classes/output/model_logs.php [new file with mode: 0644]
admin/tool/analytics/classes/output/models_list.php [new file with mode: 0644]
admin/tool/analytics/classes/output/renderer.php [new file with mode: 0644]
admin/tool/analytics/classes/task/predict_models.php [new file with mode: 0644]
admin/tool/analytics/classes/task/train_models.php [new file with mode: 0644]
admin/tool/analytics/cli/enable_model.php [new file with mode: 0644]
admin/tool/analytics/cli/evaluate_model.php [new file with mode: 0644]
admin/tool/analytics/cli/guess_course_start_and_end.php [new file with mode: 0644]
admin/tool/analytics/db/tasks.php [new file with mode: 0644]
admin/tool/analytics/index.php [new file with mode: 0644]
admin/tool/analytics/lang/en/tool_analytics.php [new file with mode: 0644]
admin/tool/analytics/model.php [new file with mode: 0644]
admin/tool/analytics/settings.php [new file with mode: 0644]
admin/tool/analytics/templates/models_list.mustache [new file with mode: 0644]
admin/tool/analytics/version.php [moved from auth/fc/version.php with 69% similarity]
admin/tool/customlang/db/upgrade.php
admin/tool/log/db/upgrade.php
admin/tool/log/store/database/db/upgrade.php
admin/tool/log/store/standard/db/upgrade.php
admin/tool/lp/classes/external.php
admin/tool/lp/db/services.php
admin/tool/lp/tests/behat/behat_tool_lp.php
admin/tool/lp/tests/behat/plan_crud.feature
admin/tool/lp/tests/externallib_test.php
admin/tool/lp/version.php
admin/tool/monitor/db/upgrade.php
admin/tool/oauth2/classes/form/issuer.php
admin/tool/oauth2/lang/en/tool_oauth2.php
admin/tool/uploadcourse/classes/course.php
admin/tool/uploadcourse/classes/step2_form.php
admin/tool/uploadcourse/cli/uploadcourse.php
admin/tool/uploadcourse/tests/course_test.php
admin/tool/xmldb/actions/check_defaults/check_defaults.class.php
analytics/classes/admin_setting_predictor.php [new file with mode: 0644]
analytics/classes/analysable.php [new file with mode: 0644]
analytics/classes/calculable.php [new file with mode: 0644]
analytics/classes/course.php [new file with mode: 0644]
analytics/classes/dataset_manager.php [new file with mode: 0644]
analytics/classes/local/analyser/base.php [new file with mode: 0644]
analytics/classes/local/analyser/by_course.php [new file with mode: 0644]
analytics/classes/local/analyser/sitewide.php [new file with mode: 0644]
analytics/classes/local/indicator/base.php [new file with mode: 0644]
analytics/classes/local/indicator/binary.php [new file with mode: 0644]
analytics/classes/local/indicator/community_of_inquiry_activity.php [new file with mode: 0644]
analytics/classes/local/indicator/discrete.php [new file with mode: 0644]
analytics/classes/local/indicator/linear.php [new file with mode: 0644]
analytics/classes/local/target/base.php [new file with mode: 0644]
analytics/classes/local/target/binary.php [new file with mode: 0644]
analytics/classes/local/target/discrete.php [new file with mode: 0644]
analytics/classes/local/target/linear.php [new file with mode: 0644]
analytics/classes/local/time_splitting/accumulative_parts.php [new file with mode: 0644]
analytics/classes/local/time_splitting/base.php [new file with mode: 0644]
analytics/classes/local/time_splitting/equal_parts.php [new file with mode: 0644]
analytics/classes/manager.php [new file with mode: 0644]
analytics/classes/model.php [new file with mode: 0644]
analytics/classes/prediction.php [new file with mode: 0644]
analytics/classes/prediction_action.php [new file with mode: 0644]
analytics/classes/predictor.php [new file with mode: 0644]
analytics/classes/requirements_exception.php [new file with mode: 0644]
analytics/classes/site.php [new file with mode: 0644]
analytics/tests/course_activities_test.php [new file with mode: 0644]
analytics/tests/course_test.php [new file with mode: 0644]
analytics/tests/fixtures/test_indicator_fullname.php [new file with mode: 0644]
analytics/tests/fixtures/test_indicator_max.php [new file with mode: 0644]
analytics/tests/fixtures/test_indicator_min.php [new file with mode: 0644]
analytics/tests/fixtures/test_indicator_random.php [new file with mode: 0644]
analytics/tests/fixtures/test_static_target_shortname.php [new file with mode: 0644]
analytics/tests/fixtures/test_target_shortname.php [new file with mode: 0644]
analytics/tests/model_test.php [new file with mode: 0644]
analytics/tests/prediction_test.php [new file with mode: 0644]
auth/README.txt [deleted file]
auth/cas/CAS/CAS.php
auth/cas/CAS/CAS/AuthenticationException.php
auth/cas/CAS/CAS/Client.php
auth/cas/CAS/CAS/Languages/ChineseSimplified.php [new file with mode: 0644]
auth/cas/CAS/CAS/Languages/Greek.php
auth/cas/CAS/CAS/Languages/Japanese.php
auth/cas/CAS/CAS/PGTStorage/File.php
auth/cas/CAS/CAS/Request/CurlMultiRequest.php
auth/cas/CAS/CAS/Request/CurlRequest.php
auth/cas/CAS/moodle_readme.txt
auth/cas/db/upgrade.php
auth/cas/thirdpartylibs.xml
auth/fc/Readme.txt [deleted file]
auth/fc/auth.php [deleted file]
auth/fc/db/install.php [deleted file]
auth/fc/fcFPP.php [deleted file]
auth/fc/lang/en/auth_fc.php [deleted file]
auth/fc/settings.php [deleted file]
auth/fc/thirdpartylibs.xml [deleted file]
auth/fc/upgrade.txt [deleted file]
auth/imap/auth.php [deleted file]
auth/imap/db/install.php [deleted file]
auth/imap/db/upgrade.php [deleted file]
auth/imap/lang/en/auth_imap.php [deleted file]
auth/imap/settings.php [deleted file]
auth/imap/upgrade.txt [deleted file]
auth/ldap/db/upgrade.php
auth/manual/db/upgrade.php
auth/mnet/db/upgrade.php
auth/nntp/auth.php [deleted file]
auth/nntp/db/install.php [deleted file]
auth/nntp/db/upgrade.php [deleted file]
auth/nntp/settings.php [deleted file]
auth/nntp/upgrade.txt [deleted file]
auth/oauth2/classes/api.php
auth/oauth2/classes/auth.php
auth/oauth2/tests/api_test.php
auth/pam/auth.php [deleted file]
auth/pam/db/install.php [deleted file]
auth/pam/upgrade.txt [deleted file]
auth/pop3/auth.php [deleted file]
auth/pop3/db/install.php [deleted file]
auth/pop3/db/upgrade.php [deleted file]
auth/pop3/lang/en/auth_pop3.php [deleted file]
auth/pop3/settings.php [deleted file]
auth/pop3/upgrade.txt [deleted file]
auth/pop3/version.php [deleted file]
backup/moodle2/backup_stepslib.php
backup/moodle2/restore_final_task.class.php
backup/moodle2/restore_stepslib.php
backup/moodle2/tests/moodle2_test.php
blocks/badges/db/upgrade.php
blocks/calendar_month/db/upgrade.php
blocks/calendar_upcoming/db/upgrade.php
blocks/comments/tests/behat/behat_block_comments.php
blocks/community/db/upgrade.php
blocks/completionstatus/db/upgrade.php
blocks/course_summary/db/upgrade.php
blocks/html/classes/search/content.php [new file with mode: 0644]
blocks/html/db/upgrade.php
blocks/html/lang/en/block_html.php
blocks/html/lib.php
blocks/html/tests/search_content_test.php [new file with mode: 0644]
blocks/moodleblock.class.php
blocks/navigation/db/upgrade.php
blocks/quiz_results/db/upgrade.php
blocks/recent_activity/db/upgrade.php
blocks/rss_client/db/upgrade.php
blocks/section_links/db/upgrade.php
blocks/selfcompletion/db/upgrade.php
blocks/settings/db/upgrade.php
blocks/upgrade.txt
calendar/amd/build/calendar.min.js [new file with mode: 0644]
calendar/amd/build/calendar_events.min.js [new file with mode: 0644]
calendar/amd/build/calendar_repository.min.js [new file with mode: 0644]
calendar/amd/build/summary_modal.min.js [new file with mode: 0644]
calendar/amd/src/calendar.js [new file with mode: 0644]
calendar/amd/src/calendar_events.js [new file with mode: 0644]
calendar/amd/src/calendar_repository.js [new file with mode: 0644]
calendar/amd/src/summary_modal.js [new file with mode: 0644]
calendar/export_execute.php
calendar/externallib.php
calendar/lib.php
calendar/renderer.php
calendar/templates/event_summary_body.mustache [new file with mode: 0644]
calendar/templates/event_summary_modal.mustache [new file with mode: 0644]
calendar/tests/behat/calendar_import.feature
calendar/tests/container_test.php
calendar/view.php
cohort/externallib.php
cohort/lib.php
cohort/tests/externallib_test.php
completion/classes/api.php
completion/classes/manager.php
completion/tests/api_test.php
course/classes/analytics/indicator/no_teacher.php [new file with mode: 0644]
course/externallib.php
course/lib.php
course/renderer.php
course/templates/defaultactivitycompletion.mustache
course/tests/behat/behat_course.php
course/tests/courselib_test.php
course/tests/externallib_test.php
course/yui/build/moodle-course-management/moodle-course-management-debug.js
course/yui/build/moodle-course-management/moodle-course-management-min.js
course/yui/build/moodle-course-management/moodle-course-management.js
course/yui/src/management/js/category.js
course/yui/src/management/js/console.js
dataformat/html/classes/writer.php
enrol/database/db/upgrade.php
enrol/externallib.php
enrol/flatfile/db/upgrade.php
enrol/guest/db/upgrade.php
enrol/imsenterprise/db/upgrade.php
enrol/manual/ajax.php
enrol/manual/amd/build/form-potential-user-selector.min.js [new file with mode: 0644]
enrol/manual/amd/build/quickenrolment.min.js [new file with mode: 0644]
enrol/manual/amd/src/form-potential-user-selector.js [new file with mode: 0644]
enrol/manual/amd/src/quickenrolment.js [new file with mode: 0644]
enrol/manual/classes/enrol_users_form.php [new file with mode: 0644]
enrol/manual/db/upgrade.php
enrol/manual/lang/en/enrol_manual.php
enrol/manual/lib.php
enrol/manual/templates/form-user-selector-suggestion.mustache [new file with mode: 0644]
enrol/manual/yui/quickenrolment/assets/skins/sam/quickenrolment.css [deleted file]
enrol/manual/yui/quickenrolment/assets/skins/sam/sprite.png [deleted file]
enrol/manual/yui/quickenrolment/quickenrolment.js [deleted file]
enrol/mnet/db/upgrade.php
enrol/paypal/db/upgrade.php
enrol/self/db/upgrade.php
enrol/tests/behat/add_to_group.feature
enrol/tests/behat/behat_enrol.php
enrol/tests/behat/manage_enrolments_from_participants.feature
enrol/tests/enrollib_test.php
enrol/yui/rolemanager/assets/skins/sam/rolemanager.css [deleted file]
enrol/yui/rolemanager/assets/skins/sam/sprite.png [deleted file]
filter/mathjaxloader/db/upgrade.php
filter/mediaplugin/db/upgrade.php
filter/mediaplugin/styles.css
filter/tex/db/upgrade.php
grade/grading/form/rubric/db/upgrade.php
grade/lib.php
grade/report/overview/db/access.php
grade/report/overview/db/upgrade.php [moved from auth/fc/db/upgrade.php with 55% similarity]
grade/report/overview/lib.php
grade/report/overview/version.php
grade/report/user/db/upgrade.php
group/classes/output/user_groups_editable.php [new file with mode: 0644]
group/lib.php
group/tests/behat/behat_groups.php
install.php
install/lang/da/install.php
install/lang/de/install.php
install/lang/fr/install.php
install/lang/ja/install.php
install/lang/pt_br/error.php
lang/en/admin.php
lang/en/analytics.php [new file with mode: 0644]
lang/en/cache.php
lang/en/calendar.php
lang/en/form.php
lang/en/group.php
lang/en/moodle.php
lang/en/plugin.php
lang/en/role.php
lib/amd/build/form-autocomplete.min.js
lib/amd/build/form-cohort-selector.min.js [new file with mode: 0644]
lib/amd/build/inplace_editable.min.js
lib/amd/build/modal.min.js
lib/amd/build/modal_events.min.js
lib/amd/src/form-autocomplete.js
lib/amd/src/form-cohort-selector.js [new file with mode: 0644]
lib/amd/src/inplace_editable.js
lib/amd/src/modal.js
lib/amd/src/modal_events.js
lib/behat/behat_base.php
lib/behat/behat_field_manager.php
lib/behat/form_field/behat_form_autocomplete.php
lib/behat/form_field/behat_form_checkbox.php
lib/behat/form_field/behat_form_field.php
lib/behat/form_field/behat_form_select.php
lib/bennu/iCalendar_components.php
lib/bennu/readme_moodle.txt
lib/blocklib.php
lib/classes/analytics/analyser/courses.php [new file with mode: 0644]
lib/classes/analytics/analyser/site_courses.php [new file with mode: 0644]
lib/classes/analytics/analyser/student_enrolments.php [new file with mode: 0644]
lib/classes/analytics/indicator/any_access_after_end.php [new file with mode: 0644]
lib/classes/analytics/indicator/any_access_before_start.php [new file with mode: 0644]
lib/classes/analytics/indicator/any_write_action.php [new file with mode: 0644]
lib/classes/analytics/indicator/read_actions.php [new file with mode: 0644]
lib/classes/analytics/target/course_dropout.php [new file with mode: 0644]
lib/classes/analytics/target/no_teaching.php [new file with mode: 0644]
lib/classes/analytics/time_splitting/deciles.php [new file with mode: 0644]
lib/classes/analytics/time_splitting/deciles_accum.php [new file with mode: 0644]
lib/classes/analytics/time_splitting/no_splitting.php [new file with mode: 0644]
lib/classes/analytics/time_splitting/quarters.php [new file with mode: 0644]
lib/classes/analytics/time_splitting/quarters_accum.php [new file with mode: 0644]
lib/classes/analytics/time_splitting/single_range.php [new file with mode: 0644]
lib/classes/component.php
lib/classes/event/prediction_action_started.php [new file with mode: 0644]
lib/classes/oauth2/api.php
lib/classes/oauth2/issuer.php
lib/classes/output/icon_system_fontawesome.php
lib/classes/output/inplace_editable.php
lib/classes/plugin_manager.php
lib/classes/plugininfo/mlbackend.php [moved from auth/pam/db/upgrade.php with 50% similarity]
lib/classes/task/build_installed_themes_task.php [new file with mode: 0644]
lib/classes/task/manager.php
lib/classes/task/refresh_mod_calendar_events_task.php
lib/classes/task/search_index_task.php
lib/classes/task/search_optimize_task.php
lib/db/access.php
lib/db/caches.php
lib/db/install.php
lib/db/install.xml
lib/db/messages.php
lib/db/services.php
lib/db/upgrade.php
lib/db/upgradelib.php
lib/ddl/database_manager.php
lib/dml/moodle_database.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/sqlsrv_native_moodle_database.php
lib/editor/atto/db/upgrade.php
lib/editor/atto/plugins/equation/db/upgrade.php
lib/editor/atto/plugins/equation/db/upgradelib.php [deleted file]
lib/editor/atto/plugins/equation/tests/upgradelib_testcase.php [deleted file]
lib/editor/atto/upgrade.txt
lib/editor/tinymce/db/upgrade.php
lib/editor/tinymce/plugins/spellchecker/db/upgrade.php
lib/enrollib.php
lib/external/externallib.php
lib/externallib.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/filestorage/stored_file.php
lib/form/classes/filetypes_util.php
lib/form/cohort.php [new file with mode: 0644]
lib/form/filemanager.js
lib/form/filemanager.php
lib/form/filetypes.php
lib/form/tests/behat/filetypes.feature [new file with mode: 0644]
lib/form/tests/filetypes_util_test.php
lib/form/tests/fixtures/filetypes.php [new file with mode: 0644]
lib/formslib.php
lib/grouplib.php
lib/mlbackend/php/classes/processor.php [new file with mode: 0644]
lib/mlbackend/php/lang/en/mlbackend_php.php [new file with mode: 0644]
lib/mlbackend/php/phpml/LICENSE [new file with mode: 0644]
lib/mlbackend/php/phpml/readme_moodle.txt [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Association/Apriori.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Association/Associator.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Classifier.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/DecisionTree.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/DecisionTree/DecisionTreeLeaf.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Ensemble/AdaBoost.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Ensemble/Bagging.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Ensemble/RandomForest.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/KNearestNeighbors.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Linear/Adaline.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Linear/DecisionStump.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Linear/LogisticRegression.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/Linear/Perceptron.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/MLPClassifier.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/NaiveBayes.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/SVC.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Classification/WeightedClassifier.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/Clusterer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/DBSCAN.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/FuzzyCMeans.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/KMeans.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/KMeans/Cluster.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/KMeans/Point.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Clustering/KMeans/Space.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/CrossValidation/RandomSplit.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/CrossValidation/Split.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/CrossValidation/StratifiedRandomSplit.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/ArrayDataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/CsvDataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/Dataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/Demo/GlassDataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/Demo/IrisDataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/Demo/WineDataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Dataset/FilesDataset.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/DimensionReduction/EigenTransformerBase.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/DimensionReduction/KernelPCA.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/DimensionReduction/LDA.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/DimensionReduction/PCA.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Estimator.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Exception/DatasetException.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Exception/FileException.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Exception/InvalidArgumentException.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Exception/MatrixException.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Exception/NormalizerException.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Exception/SerializeException.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/FeatureExtraction/StopWords.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/FeatureExtraction/StopWords/English.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/FeatureExtraction/StopWords/French.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/FeatureExtraction/StopWords/Polish.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/FeatureExtraction/TfIdfTransformer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/FeatureExtraction/TokenCountVectorizer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/OneVsRest.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/Optimizer/ConjugateGradient.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/Optimizer/GD.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/Optimizer/Optimizer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/Optimizer/StochasticGD.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/Predictable.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Helper/Trainable.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/IncrementalEstimator.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Distance.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Distance/Chebyshev.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Distance/Euclidean.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Distance/Manhattan.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Distance/Minkowski.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Kernel.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Kernel/RBF.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/LinearAlgebra/EigenvalueDecomposition.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/LinearAlgebra/LUDecomposition.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Matrix.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Product.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Set.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Statistic/Correlation.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Statistic/Covariance.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Statistic/Gaussian.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Statistic/Mean.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Math/Statistic/StandardDeviation.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Metric/Accuracy.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Metric/ClassificationReport.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Metric/ConfusionMatrix.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/ModelManager.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/ActivationFunction.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/ActivationFunction/BinaryStep.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/ActivationFunction/Gaussian.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/ActivationFunction/HyperbolicTangent.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/ActivationFunction/Sigmoid.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Layer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Network.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Network/LayeredNetwork.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Network/MultilayerPerceptron.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Node.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Node/Bias.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Node/Input.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Node/Neuron.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Node/Neuron/Synapse.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Training.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Training/Backpropagation.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/NeuralNetwork/Training/Backpropagation/Sigma.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Pipeline.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Imputer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Imputer/Strategy.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Imputer/Strategy/MeanStrategy.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Imputer/Strategy/MedianStrategy.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Imputer/Strategy/MostFrequentStrategy.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Normalizer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Preprocessing/Preprocessor.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Regression/LeastSquares.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Regression/Regression.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Regression/SVR.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/SupportVectorMachine/DataTransformer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/SupportVectorMachine/Kernel.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/SupportVectorMachine/SupportVectorMachine.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/SupportVectorMachine/Type.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Tokenization/Tokenizer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Tokenization/WhitespaceTokenizer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Tokenization/WordTokenizer.php [new file with mode: 0644]
lib/mlbackend/php/phpml/src/Phpml/Transformer.php [new file with mode: 0644]
lib/mlbackend/php/readme_moodle.txt [new file with mode: 0644]
lib/mlbackend/php/thirdpartylibs.xml [new file with mode: 0644]
lib/mlbackend/php/version.php [moved from auth/imap/version.php with 69% similarity]
lib/mlbackend/python/classes/processor.php [new file with mode: 0644]
lib/mlbackend/python/lang/en/mlbackend_python.php [moved from auth/pam/lang/en/auth_pam.php with 53% similarity]
lib/mlbackend/python/version.php [moved from auth/pam/version.php with 68% similarity]
lib/moodlelib.php
lib/outputcomponents.php
lib/outputlib.php
lib/outputrenderers.php
lib/phpminimumversionlib.php [new file with mode: 0644]
lib/phpunit/classes/util.php
lib/requirejs.php
lib/templates/form_autocomplete_selection.mustache
lib/templates/inplace_editable.mustache
lib/testing/generator/block_generator.php
lib/testing/tests/generator_test.php
lib/tests/adhoc_task_test.php
lib/tests/analysers_test.php [new file with mode: 0644]
lib/tests/behat/behat_forms.php
lib/tests/behat/behat_general.php
lib/tests/blocklib_test.php
lib/tests/component_test.php
lib/tests/fixtures/task_fixtures.php
lib/tests/grouplib_test.php
lib/tests/indicators_test.php [new file with mode: 0644]
lib/tests/moodlelib_test.php
lib/tests/time_splittings_test.php [new file with mode: 0644]
lib/tests/upgradelib_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/upgradelib.php
lib/validateurlsyntax.php
media/classes/manager.php
media/player/videojs/settings.php
message/classes/api.php
message/output/email/db/upgrade.php
message/output/jabber/db/upgrade.php
message/output/popup/amd/build/message_popover_controller.min.js
message/output/popup/amd/build/notification_area_control_area.min.js
message/output/popup/amd/build/notification_popover_controller.min.js
message/output/popup/amd/src/message_popover_controller.js
message/output/popup/amd/src/notification_area_control_area.js
message/output/popup/amd/src/notification_popover_controller.js
message/output/popup/classes/api.php
message/output/popup/db/upgrade.php
mod/assign/backup/moodle2/restore_assign_stepslib.php
mod/assign/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/assign/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/assign/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/assign/db/upgrade.php
mod/assign/feedback/comments/db/upgrade.php
mod/assign/feedback/editpdf/db/upgrade.php
mod/assign/feedback/file/db/upgrade.php
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/styles.css
mod/assign/submission/comments/db/upgrade.php
mod/assign/submission/comments/lang/en/assignsubmission_comments.php
mod/assign/submission/comments/lib.php
mod/assign/submission/file/db/upgrade.php
mod/assign/submission/onlinetext/db/upgrade.php
mod/assign/upgrade.txt
mod/assignment/db/upgrade.php
mod/book/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/book/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/book/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/book/db/upgrade.php
mod/book/lang/en/book.php
mod/book/tests/behat/edit_tags.feature
mod/chat/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/chat/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/chat/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/chat/db/upgrade.php
mod/chat/lang/en/chat.php
mod/chat/lib.php
mod/chat/upgrade.txt
mod/choice/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/choice/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/choice/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/choice/db/upgrade.php
mod/choice/lang/en/choice.php
mod/choice/lib.php
mod/choice/upgrade.txt
mod/data/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/data/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/data/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/data/db/upgrade.php
mod/data/field/file/field.class.php
mod/data/field/picture/field.class.php
mod/data/import.php
mod/data/lang/en/data.php
mod/data/lib.php
mod/data/upgrade.txt
mod/feedback/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/feedback/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/feedback/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/feedback/db/upgrade.php
mod/feedback/lang/en/feedback.php
mod/feedback/lib.php
mod/feedback/tests/behat/coursemapping.feature
mod/feedback/upgrade.txt
mod/folder/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/folder/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/folder/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/folder/db/upgrade.php
mod/folder/lang/en/folder.php
mod/forum/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/forum/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/forum/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/forum/db/upgrade.php
mod/forum/lang/en/forum.php
mod/forum/lib.php
mod/forum/mod_form.php
mod/forum/settings.php
mod/forum/tests/behat/edit_tags.feature
mod/glossary/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/glossary/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/glossary/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/glossary/db/upgrade.php
mod/glossary/lang/en/glossary.php
mod/glossary/tests/behat/edit_tags.feature
mod/imscp/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/imscp/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/imscp/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/imscp/db/upgrade.php
mod/imscp/lang/en/imscp.php
mod/label/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/label/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/label/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/label/db/upgrade.php
mod/label/lang/en/label.php
mod/label/mod_form.php
mod/label/tests/generator/lib.php
mod/label/version.php
mod/lesson/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/lesson/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/lesson/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/lesson/continue.php
mod/lesson/db/upgrade.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/tests/behat/lesson_question_attempts.feature
mod/lesson/upgrade.txt
mod/lesson/version.php
mod/lti/classes/analytics/indicator/activity_base.php [moved from auth/nntp/lang/en/auth_nntp.php with 50% similarity]
mod/lti/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/lti/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/lti/db/access.php
mod/lti/db/upgrade.php
mod/lti/db/upgradelib.php [deleted file]
mod/lti/lang/en/lti.php
mod/lti/locallib.php
mod/lti/tests/upgradelib_test.php [deleted file]
mod/lti/upgrade.txt
mod/lti/version.php
mod/page/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/page/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/page/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/page/db/upgrade.php
mod/page/lang/en/page.php
mod/quiz/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/quiz/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/quiz/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/quiz/classes/structure.php
mod/quiz/db/upgrade.php
mod/quiz/lang/en/quiz.php
mod/quiz/lib.php
mod/quiz/report/overview/db/upgrade.php
mod/quiz/report/statistics/db/upgrade.php
mod/quiz/tests/structure_test.php
mod/quiz/upgrade.txt
mod/resource/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/resource/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/resource/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/resource/db/upgrade.php
mod/resource/lang/en/resource.php
mod/scorm/backup/moodle2/backup_scorm_stepslib.php
mod/scorm/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/scorm/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/scorm/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/scorm/db/upgrade.php
mod/scorm/lang/en/scorm.php
mod/scorm/lib.php
mod/scorm/player.php
mod/scorm/upgrade.txt
mod/scorm/view.php
mod/survey/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/survey/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/survey/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/survey/db/upgrade.php
mod/survey/lang/en/survey.php
mod/url/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/url/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/url/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/url/db/upgrade.php
mod/url/lang/en/url.php
mod/wiki/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/wiki/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/wiki/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/wiki/db/upgrade.php
mod/wiki/lang/en/wiki.php
mod/wiki/tests/behat/edit_tags.feature
mod/workshop/classes/analytics/indicator/activity_base.php [new file with mode: 0644]
mod/workshop/classes/analytics/indicator/cognitive_depth.php [new file with mode: 0644]
mod/workshop/classes/analytics/indicator/social_breadth.php [new file with mode: 0644]
mod/workshop/classes/external.php [new file with mode: 0644]
mod/workshop/classes/external/workshop_summary_exporter.php [new file with mode: 0644]
mod/workshop/db/install.xml
mod/workshop/db/services.php [moved from auth/pam/settings.php with 53% similarity]
mod/workshop/db/upgrade.php
mod/workshop/form/accumulative/db/upgrade.php
mod/workshop/form/assessment_form.php
mod/workshop/form/comments/db/upgrade.php
mod/workshop/form/numerrors/db/upgrade.php
mod/workshop/form/rubric/db/upgrade.php
mod/workshop/lang/en/deprecated.txt
mod/workshop/lang/en/workshop.php
mod/workshop/lib.php
mod/workshop/locallib.php
mod/workshop/mod_form.php
mod/workshop/submission_form.php
mod/workshop/tests/behat/file_type_restriction.feature [new file with mode: 0644]
mod/workshop/tests/external_test.php [new file with mode: 0644]
mod/workshop/tests/locallib_test.php
mod/workshop/upgrade.txt
mod/workshop/version.php
my/lib.php
npm-shrinkwrap.json
package.json
phpunit.xml.dist
pix/e/cancel.png [new file with mode: 0644]
pix/e/cancel.svg [new file with mode: 0644]
portfolio/boxnet/db/upgrade.php
portfolio/googledocs/db/upgrade.php
portfolio/picasa/db/upgrade.php
question/behaviour/manualgraded/db/upgrade.php
question/type/calculated/db/upgrade.php
question/type/ddmarker/db/upgrade.php
question/type/essay/db/upgrade.php
question/type/match/db/upgrade.php
question/type/multianswer/db/upgrade.php
question/type/multichoice/db/upgrade.php
question/type/numerical/db/upgrade.php
question/type/random/db/upgrade.php
question/type/randomsamatch/db/upgrade.php
question/type/shortanswer/db/upgrade.php
report/insights/action.php [new file with mode: 0644]
report/insights/classes/output/insight.php [new file with mode: 0644]
report/insights/classes/output/insights_list.php [new file with mode: 0644]
report/insights/classes/output/renderer.php [new file with mode: 0644]
report/insights/insights.php [new file with mode: 0644]
report/insights/lang/en/report_insights.php [new file with mode: 0644]
report/insights/lib.php [new file with mode: 0644]
report/insights/prediction.php [new file with mode: 0644]
report/insights/templates/insight.mustache [new file with mode: 0644]
report/insights/templates/insight_details.mustache [new file with mode: 0644]
report/insights/templates/insights_list.mustache [new file with mode: 0644]
report/insights/version.php [moved from auth/nntp/version.php with 68% similarity]
repository/boxnet/db/upgrade.php
repository/dropbox/db/upgrade.php
repository/googledocs/db/upgrade.php
repository/picasa/db/upgrade.php
search/classes/base.php
search/classes/base_block.php [new file with mode: 0644]
search/classes/engine.php
search/classes/manager.php
search/cli/indexer.php
search/tests/base_block_test.php [new file with mode: 0644]
search/tests/fixtures/mock_block_area.php [new file with mode: 0644]
search/tests/fixtures/mock_search_area.php
search/tests/fixtures/mock_search_engine.php
search/tests/manager_test.php
search/upgrade.txt
tag/tests/behat/edit_tag.feature
tag/tests/behat/flag_tags.feature
theme/boost/classes/output/core_renderer.php
theme/boost/scss/moodle/admin.scss
theme/boost/scss/moodle/blocks.scss
theme/boost/scss/moodle/forms.scss
theme/boost/scss/moodle/user.scss
theme/boost/templates/core/form_autocomplete_selection.mustache
theme/bootstrapbase/less/moodle/bootstrapoverride.less
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/question.less
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/less/moodle/templates.less
theme/bootstrapbase/less/moodle/user.less
theme/bootstrapbase/style/moodle.css
theme/more/db/upgrade.php
theme/upgrade.txt
user/classes/analytics/indicator/user_profile_set.php [new file with mode: 0644]
user/classes/analytics/indicator/user_track_forums.php [new file with mode: 0644]
user/classes/participants_table.php
user/externallib.php
user/index.php
user/lib.php
user/tests/behat/view_participants.feature
version.php

index e62d329..0622612 100644 (file)
@@ -6,7 +6,6 @@ vendor/
 admin/tool/usertours/amd/src/tour.js
 admin/tool/usertours/amd/src/popper.js
 auth/cas/CAS/
-auth/fc/fcFPP.php
 enrol/lti/ims-blti/
 filter/algebra/AlgParser.pm
 filter/tex/mimetex.*
@@ -14,6 +13,7 @@ lib/editor/atto/yui/src/rangy/js/*.*
 lib/editor/tinymce/plugins/pdw/tinymce/
 lib/editor/tinymce/plugins/spellchecker/rpc.php
 lib/editor/tinymce/tiny_mce/
+lib/mlbackend/php/phpml/
 lib/adodb/
 lib/bennu/
 lib/evalmath/
@@ -58,6 +58,7 @@ lib/maxmind/MaxMind/
 lib/ltiprovider/
 lib/amd/src/truncate.js
 lib/fonts/
+lib/validateurlsyntax.php
 media/player/videojs/amd/src/video-lazy.js
 media/player/videojs/amd/src/Youtube-lazy.js
 media/player/videojs/videojs/
index 8c3d147..cfcf702 100644 (file)
@@ -7,7 +7,6 @@ vendor/
 admin/tool/usertours/amd/src/tour.js
 admin/tool/usertours/amd/src/popper.js
 auth/cas/CAS/
-auth/fc/fcFPP.php
 enrol/lti/ims-blti/
 filter/algebra/AlgParser.pm
 filter/tex/mimetex.*
@@ -15,6 +14,7 @@ lib/editor/atto/yui/src/rangy/js/*.*
 lib/editor/tinymce/plugins/pdw/tinymce/
 lib/editor/tinymce/plugins/spellchecker/rpc.php
 lib/editor/tinymce/tiny_mce/
+lib/mlbackend/php/phpml/
 lib/adodb/
 lib/bennu/
 lib/evalmath/
@@ -59,6 +59,7 @@ lib/maxmind/MaxMind/
 lib/ltiprovider/
 lib/amd/src/truncate.js
 lib/fonts/
+lib/validateurlsyntax.php
 media/player/videojs/amd/src/video-lazy.js
 media/player/videojs/amd/src/Youtube-lazy.js
 media/player/videojs/videojs/
index 409123a..ae818b0 100644 (file)
@@ -1,18 +1,22 @@
 {
+    "plugins": [
+        "stylelint-csstree-validator"
+    ],
     "rules": {
+        "csstree/validator": true,
         "at-rule-empty-line-before": [ "always",
-          {"except": [ "blockless-group"], ignore: ["after-comment", "all-nested"]}
+          {"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
         ],
         "at-rule-name-case": "lower",
         "at-rule-name-space-after": "always-single-line",
         "at-rule-no-unknown": null, # Enabled for non-scss in grunt.
         "at-rule-semicolon-newline-after": "always",
+        "at-rule-semicolon-space-before": "never",
         "block-closing-brace-newline-after": "always",
-        "block-closing-brace-newline-before": "always-multi-line",
+        "block-closing-brace-newline-before": "always",
         "block-closing-brace-space-before": "always-single-line",
         "block-no-empty": true,
-        "block-no-single-line": true,
-        "block-opening-brace-newline-after": "always-multi-line",
+        "block-opening-brace-newline-after": "always",
         "block-opening-brace-space-after": "always-single-line",
         "block-opening-brace-space-before": "always",
         "color-hex-case": ["lower", { "severity": "warning" }],
@@ -21,7 +25,6 @@
         "declaration-bang-space-after": "never",
         "declaration-bang-space-before": "always",
         "declaration-block-no-duplicate-properties": true,
-        "declaration-block-no-ignored-properties": true,
         "declaration-block-no-shorthand-property-overrides": true,
         "declaration-block-semicolon-newline-after": "always-multi-line",
         "declaration-block-semicolon-space-after": "always-single-line",
@@ -32,6 +35,7 @@
         "declaration-colon-space-after": "always-single-line",
         "declaration-colon-space-before": "never",
         "declaration-no-important": true,
+        "font-family-no-duplicate-names": true,
         "function-calc-no-unspaced-operator": true,
         "function-comma-newline-after": "always-multi-line",
         "function-comma-space-after": "always-single-line",
@@ -41,7 +45,7 @@
         "function-name-case": "lower",
         "function-parentheses-newline-inside": "always-multi-line",
         "function-parentheses-space-inside": "never-single-line",
-        "function-url-data-uris": never,
+        "function-url-scheme-blacklist": ["data"],
         "function-whitespace-after": "always",
         "indentation": 4,
         "keyframe-declaration-no-important": true,
         "max-line-length": [132, { "severity": "warning" }],
         "media-feature-colon-space-after": "always",
         "media-feature-colon-space-before": "never",
-        "media-feature-no-missing-punctuation": true,
         "media-feature-parentheses-space-inside": "never",
         "media-feature-range-operator-space-after": "always",
         "media-feature-range-operator-space-before": "always",
         "media-query-list-comma-newline-after": "always-multi-line",
         "media-query-list-comma-space-after": "always-single-line",
         "media-query-list-comma-space-before": "never",
-        "no-browser-hacks": null, # Enabled for non-scss in grunt.
         "no-empty-source": true,
         "no-eol-whitespace": true,
         "no-extra-semicolons": [true, { "severity": "warning" }],
         "selector-pseudo-class-parentheses-space-inside": "never",
         "selector-pseudo-element-case": "lower",
         "selector-pseudo-element-no-unknown": true,
-        "selector-root-no-composition": true,
         "selector-type-case": "lower",
         "selector-type-no-unknown": true,
         "string-no-newline": true,
-        "time-no-imperceptible": true,
+        "time-min-milliseconds": 100,
         "unit-blacklist": ["pt"],
         "unit-case": "lower",
         "unit-no-unknown": true,
index d58effa..54198fd 100644 (file)
@@ -14,7 +14,7 @@ language: php
 php:
     # We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
     - 7.1
-    - 5.6
+    - 7.0
 
 addons:
   postgresql: "9.3"
@@ -65,11 +65,7 @@ matrix:
         # Exclude it on all versions except for 7.1
 
         - env: DB=mysqli   TASK=PHPUNIT
-          php: 5.6
-
-        # Moodle 2.7 is not compatible with PHP 7 for the upgrade test.
-        - env: DB=pgsql    TASK=UPGRADE
-          php: 7.1
+          php: 7.0
 
 cache:
     directories:
@@ -77,8 +73,6 @@ cache:
       - $HOME/.npm
 
 install:
-    - sudo apt-get -y install haveged
-    - sudo service haveged start
     - >
         if [ "$DB" = 'mysqli' ];
         then
@@ -233,9 +227,9 @@ before_script:
         # We need the official upstream.
         git remote add upstream https://github.com/moodle/moodle.git;
 
-        # Checkout 27 STABLE branch.
-        git fetch upstream MOODLE_27_STABLE;
-        git checkout MOODLE_27_STABLE;
+        # Checkout 30 STABLE branch (the first version compatible with PHP 7.x)
+        git fetch upstream MOODLE_30_STABLE;
+        git checkout MOODLE_30_STABLE;
 
         # Perform the upgrade
         php admin/cli/install_database.php --agree-license --adminpass=Password --adminemail=admin@example.com --fullname="Upgrade test" --shortname=Upgrade;
index 5f2302e..2026c23 100644 (file)
@@ -194,7 +194,6 @@ module.exports = function(grunt) {
                         rules: {
                             // These rules have to be disabled in .stylelintrc for scss compat.
                             "at-rule-no-unknown": true,
-                            "no-browser-hacks": [true, {"severity": "warning"}]
                         }
                     }
                 },
@@ -211,7 +210,6 @@ module.exports = function(grunt) {
                         rules: {
                             // These rules have to be disabled in .stylelintrc for scss compat.
                             "at-rule-no-unknown": true,
-                            "no-browser-hacks": [true, {"severity": "warning"}]
                         }
                     }
                 }
index 0b6c5ca..240a819 100644 (file)
@@ -146,14 +146,9 @@ define('PHPUNIT_TEST', false);
 
 define('IGNORE_COMPONENT_CACHE', true);
 
-// Check that PHP is of a sufficient version
-if (version_compare(phpversion(), "5.6.5") < 0) {
-    $phpversion = phpversion();
-    // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
-    fwrite(STDERR, "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).\n");
-    fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
-    exit(1);
-}
+// Check that PHP is of a sufficient version as soon as possible.
+require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
+moodle_require_minimum_php_version();
 
 // set up configuration
 global $CFG;
@@ -808,6 +803,12 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
 
 if (!$options['skip-database']) {
     install_cli_database($options, $interactive);
+    // This needs to happen at the end to ensure it occurs after all caches
+    // have been purged for the last time.
+    // This will build a cached version of the current theme for the user
+    // to immediately start browsing the site.
+    require_once($CFG->libdir.'/upgradelib.php');
+    upgrade_themes();
 } else {
     echo get_string('cliskipdatabase', 'install')."\n";
 }
index f41263e..0dd6122 100644 (file)
@@ -62,14 +62,9 @@ Example:
 \$sudo -u www-data /usr/bin/php admin/cli/install_database.php --lang=cs --adminpass=soMePass123 --agree-license
 ";
 
-// Check that PHP is of a sufficient version
-if (version_compare(phpversion(), "5.6.5") < 0) {
-    $phpversion = phpversion();
-    // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
-    fwrite(STDERR, "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).\n");
-    fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
-    exit(1);
-}
+// Check that PHP is of a sufficient version as soon as possible.
+require_once(__DIR__.'/../../lib/phpminimumversionlib.php');
+moodle_require_minimum_php_version();
 
 // Nothing to do if config.php does not exist
 $configfile = __DIR__.'/../../config.php';
@@ -183,5 +178,12 @@ if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
 
 install_cli_database($options, true);
 
+// This needs to happen at the end to ensure it occurs after all caches
+// have been purged for the last time.
+// This will build a cached version of the current theme for the user
+// to immediately start browsing the site.
+require_once($CFG->libdir.'/upgradelib.php');
+upgrade_themes();
+
 echo get_string('cliinstallfinished', 'install')."\n";
 exit(0); // 0 means success
index 6de2e13..6c10b9a 100644 (file)
@@ -187,5 +187,11 @@ upgrade_noncore(true);
 admin_apply_default_settings(NULL, false);
 admin_apply_default_settings(NULL, false);
 
+// This needs to happen at the end to ensure it occurs after all caches
+// have been purged for the last time.
+// This will build a cached version of the current theme for the user
+// to immediately start browsing the site.
+upgrade_themes();
+
 echo get_string('cliupgradefinished', 'admin')."\n";
 exit(0); // 0 means success
index 916c8a7..b8c7f16 100644 (file)
       </CUSTOM_CHECK>
     </CUSTOM_CHECKS>
   </MOODLE>
+  <MOODLE version="3.4" requires="3.0">
+    <UNICODE level="required">
+      <FEEDBACK>
+        <ON_ERROR message="unicoderequired" />
+      </FEEDBACK>
+    </UNICODE>
+    <DATABASE level="required">
+      <VENDOR name="mariadb" version="5.5.31" />
+      <VENDOR name="mysql" version="5.5.31" />
+      <VENDOR name="postgres" version="9.3" />
+      <VENDOR name="mssql" version="10.0" />
+      <VENDOR name="oracle" version="10.2" />
+    </DATABASE>
+    <PHP version="7.0.0" level="required">
+    </PHP>
+    <PCREUNICODE level="optional">
+      <FEEDBACK>
+        <ON_CHECK message="pcreunicodewarning" />
+      </FEEDBACK>
+    </PCREUNICODE>
+    <PHP_EXTENSIONS>
+      <PHP_EXTENSION name="iconv" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="iconvrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="mbstring" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="mbstringrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="curl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="curlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="openssl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="opensslrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="tokenizer" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="tokenizerrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlrpc" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="xmlrpcrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="soap" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="soaprecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="ctype" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ctyperequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zip" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ziprequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zlib" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="gd" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="gdrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="simplexml" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="simplexmlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="spl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="splrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="pcre" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="dom" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xml" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlreader" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="intl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="intlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="json" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="hash" level="required"/>
+      <PHP_EXTENSION name="fileinfo" level="required"/>
+    </PHP_EXTENSIONS>
+    <PHP_SETTINGS>
+      <PHP_SETTING name="memory_limit" value="96M" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="settingmemorylimit" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="file_uploads" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingfileuploads" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="opcache.enable" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="opcacherecommended" />
+        </FEEDBACK>
+      </PHP_SETTING>
+    </PHP_SETTINGS>
+    <CUSTOM_CHECKS>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddbstorageengine" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="quizattemptsupgradedmessage" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="slashargumentswarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="unsupporteddbtablerowformat" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="unoconvwarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="libcurlwarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddbfileformat" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddbfilepertable" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="unsupporteddblargeprefix" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="ishttpswarning" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+      <CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="incompleteunicodesupport" />
+        </FEEDBACK>
+      </CUSTOM_CHECK>
+    </CUSTOM_CHECKS>
+  </MOODLE>
 </COMPATIBILITY_MATRIX>
index 6cf7f45..d0da26b 100644 (file)
@@ -29,14 +29,9 @@ if (!file_exists('../config.php')) {
     die();
 }
 
-// Check that PHP is of a sufficient version as soon as possible
-if (version_compare(phpversion(), '5.6.5') < 0) {
-    $phpversion = phpversion();
-    // do NOT localise - lang strings would not work here and we CAN NOT move it to later place
-    echo "Moodle 3.2 or later requires at least PHP 5.6.5 (currently using version $phpversion).<br />";
-    echo "Please upgrade your server software or install older Moodle version.";
-    die();
-}
+// Check that PHP is of a sufficient version as soon as possible.
+require_once(__DIR__.'/../lib/phpminimumversionlib.php');
+moodle_require_minimum_php_version();
 
 // make sure iconv is available and actually works
 if (!function_exists('iconv')) {
index 6e0b8a9..8142999 100644 (file)
@@ -225,19 +225,25 @@ class site_registration_form extends moodleform {
         $imageurl = get_config('hub', 'site_imageurl_' . $cleanhuburl);
         $privacy = get_config('hub', 'site_privacy_' . $cleanhuburl);
         $address = get_config('hub', 'site_address_' . $cleanhuburl);
+        if ($address === false) {
+            $address = '';
+        }
         $region = get_config('hub', 'site_region_' . $cleanhuburl);
         $country = get_config('hub', 'site_country_' . $cleanhuburl);
-        if ($country === false) {
-            $country = $admin->country;
+        if (empty($country)) {
+            $country = $admin->country ?: $CFG->country;
         }
         $language = get_config('hub', 'site_language_' . $cleanhuburl);
         if ($language === false) {
             $language = explode('_', current_language())[0];
         }
         $geolocation = get_config('hub', 'site_geolocation_' . $cleanhuburl);
+        if ($geolocation === false) {
+            $geolocation = '';
+        }
         $contactable = get_config('hub', 'site_contactable_' . $cleanhuburl);
         $emailalert = get_config('hub', 'site_emailalert_' . $cleanhuburl);
-        $emailalert = ($emailalert === 0) ? 0 : 1;
+        $emailalert = ($emailalert === false || $emailalert) ? 1 : 0;
         $coursesnumber = get_config('hub', 'site_coursesnumber_' . $cleanhuburl);
         $usersnumber = get_config('hub', 'site_usersnumber_' . $cleanhuburl);
         $roleassignmentsnumber = get_config('hub', 'site_roleassignmentsnumber_' . $cleanhuburl);
@@ -311,11 +317,12 @@ class site_registration_form extends moodleform {
         $mform->addElement('hidden', 'regioncode', '-');
         $mform->setType('regioncode', PARAM_ALPHANUMEXT);
 
-        $countries = get_string_manager()->get_list_of_countries();
+        $countries = ['' => ''] + get_string_manager()->get_list_of_countries();
         $mform->addElement('select', 'countrycode', get_string('sitecountry', 'hub'), $countries);
         $mform->setDefault('countrycode', $country);
         $mform->setType('countrycode', PARAM_ALPHANUMEXT);
         $mform->addHelpButton('countrycode', 'sitecountry', 'hub');
+        $mform->addRule('countrycode', $strrequired, 'required', null, 'client');
 
         $mform->addElement('text', 'geolocation', get_string('sitegeolocation', 'hub'),
                 array('class' => 'registration_textfield'));
@@ -333,6 +340,7 @@ class site_registration_form extends moodleform {
         $mform->addElement('text', 'contactphone', get_string('sitephone', 'hub'),
                 array('class' => 'registration_textfield'));
         $mform->setType('contactphone', PARAM_TEXT);
+        $mform->setDefault('contactphone', $contactphone);
         $mform->addHelpButton('contactphone', 'sitephone', 'hub');
         $mform->setForceLtr('contactphone');
 
index dcbc7cb..9ce7af6 100644 (file)
@@ -125,6 +125,9 @@ foreach ($searchareas as $area) {
                     $areasconfig[$areaid]->docsprocessed . ' , ' .
                     $areasconfig[$areaid]->recordsprocessed . ' , ' .
                     $areasconfig[$areaid]->docsignored;
+                if ($areasconfig[$areaid]->partial) {
+                    $laststatus .= ' ' . get_string('searchpartial', 'admin');
+                }
             } else {
                 $laststatus = '';
             }
diff --git a/admin/settings/analytics.php b/admin/settings/analytics.php
new file mode 100644 (file)
index 0000000..247ae74
--- /dev/null
@@ -0,0 +1,87 @@
+<?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/>.
+
+/**
+ * Adds settings links to admin tree.
+ *
+ * @package   core_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+if ($hassiteconfig) {
+    $settings = new admin_settingpage('analyticssettings', new lang_string('analyticssettings', 'analytics'));
+    $ADMIN->add('appearance', $settings);
+
+    if ($ADMIN->fulltree) {
+        // Select the site prediction's processor.
+        $predictionprocessors = \core_analytics\manager::get_all_prediction_processors();
+        $predictors = array();
+        foreach ($predictionprocessors as $fullclassname => $predictor) {
+            $pluginname = substr($fullclassname, 1, strpos($fullclassname, '\\', 1) - 1);
+            $predictors[$fullclassname] = new lang_string('pluginname', $pluginname);
+        }
+        $settings->add(new \core_analytics\admin_setting_predictor('analytics/predictionsprocessor',
+            new lang_string('predictionsprocessor', 'analytics'), new lang_string('predictionsprocessor_help', 'analytics'),
+            '\mlbackend_php\processor', $predictors)
+        );
+
+        // Log store.
+        $logmanager = get_log_manager();
+        $readers = $logmanager->get_readers('core\log\sql_reader');
+        $options = array();
+        $defaultreader = null;
+        foreach ($readers as $plugin => $reader) {
+            if (!$reader->is_logging()) {
+                continue;
+            }
+            if (!isset($defaultreader)) {
+                // The top one as default reader.
+                $defaultreader = $plugin;
+            }
+            $options[$plugin] = $reader->get_name();
+        }
+        $settings->add(new admin_setting_configselect('analytics/logstore',
+            new lang_string('analyticslogstore', 'analytics'), new lang_string('analyticslogstore_help', 'analytics'),
+            $defaultreader, $options));
+
+        // Enable/disable time splitting methods.
+        $alltimesplittings = \core_analytics\manager::get_all_time_splittings();
+
+        $timesplittingoptions = array();
+        $timesplittingdefaults = array('\core\analytics\time_splitting\quarters_accum',
+            '\core\analytics\time_splitting\quarters', '\core\analytics\time_splitting\no_splitting');
+        foreach ($alltimesplittings as $key => $timesplitting) {
+            $timesplittingoptions[$key] = $timesplitting->get_name();
+        }
+        $settings->add(new admin_setting_configmultiselect('analytics/timesplittings',
+            new lang_string('enabledtimesplittings', 'analytics'), new lang_string('enabledtimesplittings_help', 'analytics'),
+            $timesplittingdefaults, $timesplittingoptions)
+        );
+
+        // Predictions processor output dir.
+        $defaultmodeloutputdir = rtrim($CFG->dataroot, '/') . DIRECTORY_SEPARATOR . 'models';
+        if (empty(get_config('analytics', 'modeloutputdir')) && !file_exists($defaultmodeloutputdir) &&
+                is_writable($defaultmodeloutputdir)) {
+            // Automatically create the dir for them so users don't see the invalid value red cross.
+            mkdir($defaultmodeloutputdir, $CFG->directorypermissions, true);
+        }
+        $settings->add(new admin_setting_configdirectory('analytics/modeloutputdir', new lang_string('modeloutputdir', 'analytics'),
+            new lang_string('modeloutputdirinfo', 'analytics'), $defaultmodeloutputdir));
+    }
+}
index e63f190..3bb3c4a 100644 (file)
@@ -557,6 +557,13 @@ 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_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));
 
     $ADMIN->add('searchplugins', $temp);
     $ADMIN->add('searchplugins', new admin_externalpage('searchareas', new lang_string('searchareas', 'admin'),
index 950c2aa..a82d5d6 100644 (file)
@@ -189,6 +189,8 @@ if ($hassiteconfig
                     'phone2'      => new lang_string('phone2'),
                     'department'  => new lang_string('department'),
                     'institution' => new lang_string('institution'),
+                    'city'        => new lang_string('city'),
+                    'country'     => new lang_string('country'),
                 )));
         $setting = new admin_setting_configtext('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'),
             new lang_string('configfullnamedisplay', 'admin'), 'language', PARAM_TEXT, 50);
diff --git a/admin/tool/analytics/amd/build/log_info.min.js b/admin/tool/analytics/amd/build/log_info.min.js
new file mode 100644 (file)
index 0000000..c2715aa
Binary files /dev/null and b/admin/tool/analytics/amd/build/log_info.min.js differ
diff --git a/admin/tool/analytics/amd/src/log_info.js b/admin/tool/analytics/amd/src/log_info.js
new file mode 100644 (file)
index 0000000..b87d56f
--- /dev/null
@@ -0,0 +1,56 @@
+// 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/>.
+
+/**
+ * Shows a dialogue with info about this logs.
+ *
+ * @module     tool_analytics/log_info
+ * @class      log_info
+ * @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
+ */
+define(['jquery', 'core/str', 'core/modal_factory', 'core/notification'], function($, str, ModalFactory, Notification) {
+
+    return /** @alias module:tool_analytics/log_info */ {
+
+        /**
+         * Prepares a modal info for a log's results.
+         *
+         * @method loadInfo
+         * @param {int} id
+         * @param {string[]} info
+         */
+        loadInfo: function(id, info) {
+
+            var link = $('[data-model-log-id="' + id + '"]');
+            str.get_string('loginfo', 'tool_analytics').then(function(langString) {
+
+                var bodyInfo = $("<ul>");
+                info.forEach(function(item) {
+                    bodyInfo.append('<li>' + item + '</li>');
+                });
+                bodyInfo.append("</ul>");
+
+                return ModalFactory.create({
+                    title: langString,
+                    body: bodyInfo.html(),
+                    large: true,
+                }, link);
+
+            }).catch(Notification.exception);
+        }
+    };
+});
diff --git a/admin/tool/analytics/classes/output/form/edit_model.php b/admin/tool/analytics/classes/output/form/edit_model.php
new file mode 100644 (file)
index 0000000..c8f7129
--- /dev/null
@@ -0,0 +1,119 @@
+<?php
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Model edit form.
+ *
+ * @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\form;
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once($CFG->dirroot.'/lib/formslib.php');
+
+/**
+ * Model edit form.
+ *
+ * @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 edit_model extends \moodleform {
+
+    /**
+     * Form definition
+     */
+    public function definition() {
+        global $OUTPUT;
+
+        $mform = $this->_form;
+
+        if ($this->_customdata['model']->get_model_obj()->trained == 1) {
+            $message = get_string('edittrainedwarning', 'tool_analytics');
+            $mform->addElement('html', $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING));
+        }
+
+        $mform->addElement('advcheckbox', 'enabled', get_string('enabled', 'tool_analytics'));
+
+        $indicators = array();
+        foreach ($this->_customdata['indicators'] as $classname => $indicator) {
+            $optionname = \tool_analytics\output\helper::class_to_option($classname);
+            $indicators[$optionname] = $indicator->get_name();
+        }
+        $options = array(
+            'multiple' => true
+        );
+        $mform->addElement('autocomplete', 'indicators', get_string('indicators', 'tool_analytics'), $indicators, $options);
+        $mform->setType('indicators', PARAM_ALPHANUMEXT);
+
+        $timesplittings = array('' => '');
+        foreach ($this->_customdata['timesplittings'] as $classname => $timesplitting) {
+            $optionname = \tool_analytics\output\helper::class_to_option($classname);
+            $timesplittings[$optionname] = $timesplitting->get_name();
+        }
+
+        $mform->addElement('select', 'timesplitting', get_string('timesplittingmethod', 'analytics'), $timesplittings);
+        $mform->addHelpButton('timesplitting', 'timesplittingmethod', 'analytics');
+
+        $mform->addElement('hidden', 'id', $this->_customdata['id']);
+        $mform->setType('id', PARAM_INT);
+
+        $mform->addElement('hidden', 'action', 'edit');
+        $mform->setType('action', PARAM_ALPHANUMEXT);
+
+        $this->add_action_buttons();
+    }
+
+    /**
+     * Form validation
+     *
+     * @param array $data data from the form.
+     * @param array $files files uploaded.
+     *
+     * @return array of errors.
+     */
+    public function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+
+        if (!empty($data['timesplitting'])) {
+            $realtimesplitting = \tool_analytics\output\helper::option_to_class($data['timesplitting']);
+            if (\core_analytics\manager::is_valid($realtimesplitting, '\core_analytics\local\time_splitting\base') === false) {
+                $errors['timesplitting'] = get_string('errorinvalidtimesplitting', 'analytics');
+            }
+        }
+
+        if (empty($data['indicators'])) {
+            $errors['indicators'] = get_string('errornoindicators', 'analytics');
+        } else {
+            foreach ($data['indicators'] as $indicator) {
+                $realindicatorname = \tool_analytics\output\helper::option_to_class($indicator);
+                if (\core_analytics\manager::is_valid($realindicatorname, '\core_analytics\local\indicator\base') === false) {
+                    $errors['indicators'] = get_string('errorinvalidindicator', 'analytics', $realindicatorname);
+                }
+            }
+        }
+
+        if (!empty($data['enabled']) && empty($data['timesplitting'])) {
+            $errors['enabled'] = get_string('errorcantenablenotimesplitting', 'tool_analytics');
+        }
+
+        return $errors;
+    }
+}
diff --git a/admin/tool/analytics/classes/output/helper.php b/admin/tool/analytics/classes/output/helper.php
new file mode 100644 (file)
index 0000000..8d121e2
--- /dev/null
@@ -0,0 +1,61 @@
+<?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/>.
+
+/**
+ * Typical crappy helper class with tiny functions.
+ *
+ * @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();
+
+/**
+ * Helper class with general purpose tiny functions.
+ *
+ * @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 helper {
+
+    /**
+     * Converts a class full name to a select option key
+     *
+     * @param string $class
+     * @return string
+     */
+    public static function class_to_option($class) {
+        // Form field is PARAM_ALPHANUMEXT and we are sending fully qualified class names
+        // as option names, but replacing the backslash for a string that is really unlikely
+        // to ever be part of a class name.
+        return str_replace('\\', '2015102400ouuu', $class);
+    }
+
+    /**
+     * option_to_class
+     *
+     * @param string $option
+     * @return string
+     */
+    public static function option_to_class($option) {
+        // Really unlikely but yeah, I'm a bad booyyy.
+        return str_replace('2015102400ouuu', '\\', $option);
+    }
+}
diff --git a/admin/tool/analytics/classes/output/model_logs.php b/admin/tool/analytics/classes/output/model_logs.php
new file mode 100644 (file)
index 0000000..df59038
--- /dev/null
@@ -0,0 +1,192 @@
+<?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/>.
+
+/**
+ * Model logs table class.
+ *
+ * @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;
+require_once($CFG->libdir . '/tablelib.php');
+
+/**
+ * Model logs table class.
+ *
+ * @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 model_logs extends \table_sql {
+
+    /**
+     * @var \core_analytics\model
+     */
+    protected $model = null;
+
+    /**
+     * Sets up the table_log parameters.
+     *
+     * @param string $uniqueid unique id of form.
+     * @param \core_analytics\model $model
+     */
+    public function __construct($uniqueid, $model) {
+        global $PAGE;
+
+        parent::__construct($uniqueid);
+
+        $this->model = $model;
+
+        $this->set_attribute('class', 'modellog generaltable generalbox');
+        $this->set_attribute('aria-live', 'polite');
+
+        $this->define_columns(array('time', 'version', 'indicators', 'timesplitting', 'accuracy', 'info', 'usermodified'));
+        $this->define_headers(array(
+            get_string('time'),
+            get_string('version'),
+            get_string('indicators', 'tool_analytics'),
+            get_string('timesplittingmethod', 'analytics'),
+            get_string('accuracy', 'tool_analytics'),
+            get_string('info', 'tool_analytics'),
+            get_string('fullnameuser'),
+        ));
+        $this->pageable(true);
+        $this->collapsible(false);
+        $this->sortable(false);
+        $this->is_downloadable(false);
+
+        $this->define_baseurl($PAGE->url);
+    }
+
+    /**
+     * Generate the version column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the version column
+     */
+    public function col_version($log) {
+        $recenttimestr = get_string('strftimerecent', 'core_langconfig');
+        return userdate($log->version, $recenttimestr);
+    }
+
+    /**
+     * Generate the time column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the time column
+     */
+    public function col_time($log) {
+        $recenttimestr = get_string('strftimerecent', 'core_langconfig');
+        return userdate($log->timecreated, $recenttimestr);
+    }
+
+    /**
+     * Generate the indicators column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the indicators column
+     */
+    public function col_indicators($log) {
+        $indicatorclasses = json_decode($log->indicators);
+        $indicators = array();
+        foreach ($indicatorclasses as $indicatorclass) {
+            $indicator = \core_analytics\manager::get_indicator($indicatorclass);
+            if ($indicator) {
+                $indicators[] = $indicator->get_name();
+            } else {
+                debugging('Can\'t load ' . $indicatorclass . ' indicator', DEBUG_DEVELOPER);
+            }
+        }
+        return '<ul><li>' . implode('</li><li>', $indicators) . '</li></ul>';
+    }
+
+    /**
+     * Generate the context column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the context column
+     */
+    public function col_timesplitting($log) {
+        $timesplitting = \core_analytics\manager::get_time_splitting($log->timesplitting);
+        return $timesplitting->get_name();
+    }
+
+    /**
+     * Generate the accuracy column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the accuracy column
+     */
+    public function col_accuracy($log) {
+        return strval(round($log->score * 100, 2)) . '%';
+    }
+
+    /**
+     * Generate the info column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the score column
+     */
+    public function col_info($log) {
+        global $PAGE;
+
+        if (empty($log->info) && empty($log->dir)) {
+            return '';
+        }
+
+        $info = array();
+        if (!empty($log->info)) {
+            $info = json_decode($log->info);
+        }
+        if (!empty($log->dir)) {
+            $info[] = get_string('predictorresultsin', 'tool_analytics', $log->dir);
+        }
+        $PAGE->requires->js_call_amd('tool_analytics/log_info', 'loadInfo', array($log->id, $info));
+        return \html_writer::link('#', get_string('view'), array('data-model-log-id' => $log->id));
+    }
+
+    /**
+     * Generate the usermodified column.
+     *
+     * @param \stdClass $log log data.
+     * @return string HTML for the usermodified column
+     */
+    public function col_usermodified($log) {
+        $user = \core_user::get_user($log->usermodified);
+        return fullname($user);
+    }
+
+    /**
+     * Query the logs table. Store results in the object for use by build_table.
+     *
+     * @param int $pagesize size of page for paginated displayed table.
+     * @param bool $useinitialsbar do you want to use the initials bar.
+     */
+    public function query_db($pagesize, $useinitialsbar = true) {
+        $total = count($this->model->get_logs());
+        $this->pagesize($pagesize, $total);
+        $this->rawdata = $this->model->get_logs($this->get_page_start(), $this->get_page_size());
+
+        // Set initial bars.
+        if ($useinitialsbar) {
+            $this->initialbars($total > $pagesize);
+        }
+    }
+}
diff --git a/admin/tool/analytics/classes/output/models_list.php b/admin/tool/analytics/classes/output/models_list.php
new file mode 100644 (file)
index 0000000..d495554
--- /dev/null
@@ -0,0 +1,159 @@
+<?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/>.
+
+/**
+ * Prediction models list page.
+ *
+ * @package    tool_analytics
+ * @copyright  2016 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();
+
+/**
+ * Shows tool_analytics models list.
+ *
+ * @package    tool_analytics
+ * @copyright  2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class models_list implements \renderable, \templatable {
+
+    /**
+     * models
+     *
+     * @var \core_analytics\model[]
+     */
+    protected $models = array();
+
+    /**
+     * __construct
+     *
+     * @param \core_analytics\model[] $models
+     * @return void
+     */
+    public function __construct($models) {
+        $this->models = $models;
+    }
+
+    /**
+     * Exports the data.
+     *
+     * @param \renderer_base $output
+     * @return \stdClass
+     */
+    public function export_for_template(\renderer_base $output) {
+
+        $data = new \stdClass();
+
+        $data->models = array();
+        foreach ($this->models as $model) {
+            $modeldata = $model->export();
+
+            // Model predictions list.
+            if ($model->uses_insights()) {
+                $predictioncontexts = $model->get_predictions_contexts();
+                if ($predictioncontexts) {
+
+                    foreach ($predictioncontexts as $contextid => $unused) {
+                        // We prepare this to be used as single_select template options.
+                        $context = \context::instance_by_id($contextid);
+                        if (empty($context)) {
+                            // The context may have been deleted.
+                            unset($predictioncontexts[$contextid]);
+                            continue;
+                        }
+
+                        // Special name for system level predictions as showing "System is not visually nice".
+                        if ($contextid == SYSCONTEXTID) {
+                            $contextname = get_string('allpredictions', 'tool_analytics');
+                        } else {
+                            $contextname = shorten_text($context->get_context_name(true, true), 90);
+                        }
+                        $predictioncontexts[$contextid] = $contextname;
+                    }
+                    \core_collator::asort($predictioncontexts);
+
+                    if (!empty($predictioncontexts)) {
+                        $url = new \moodle_url('/report/insights/insights.php', array('modelid' => $model->get_id()));
+                        $singleselect = new \single_select($url, 'contextid', $predictioncontexts);
+                        $modeldata->insights = $singleselect->export_for_template($output);
+                    }
+                }
+
+                if (empty($modeldata->insights)) {
+                    if ($model->any_prediction_obtained()) {
+                        $modeldata->noinsights = get_string('noinsights', 'analytics');
+                    } else {
+                        $modeldata->noinsights = get_string('nopredictionsyet', 'analytics');
+                    }
+                }
+
+            } else {
+                $modeldata->noinsights = get_string('noinsightsmodel', 'analytics');
+            }
+
+            // Actions.
+            $actionsmenu = new \action_menu();
+            $actionsmenu->set_menu_trigger(get_string('actions'));
+            $actionsmenu->set_owner_selector('model-actions-' . $model->get_id());
+            $actionsmenu->set_alignment(\action_menu::TL, \action_menu::BL);
+
+            // Edit model.
+            if (!$model->is_static()) {
+                $url = new \moodle_url('model.php', array('action' => 'edit', 'id' => $model->get_id()));
+                $icon = new \action_menu_link_secondary($url, new \pix_icon('t/edit', get_string('edit')), get_string('edit'));
+                $actionsmenu->add($icon);
+            }
+
+            // Evaluate machine-learning-based models.
+            if ($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);
+            }
+
+            if ($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'));
+                $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'));
+                $actionsmenu->add($icon);
+            }
+
+            $modeldata->actions = $actionsmenu->export_for_template($output);
+
+            $data->models[] = $modeldata;
+        }
+
+        $data->warnings = array(
+            (object)array('message' => get_string('bettercli', 'tool_analytics'), 'closebutton' => true)
+        );
+
+        return $data;
+    }
+}
diff --git a/admin/tool/analytics/classes/output/renderer.php b/admin/tool/analytics/classes/output/renderer.php
new file mode 100644 (file)
index 0000000..2bbfbc9
--- /dev/null
@@ -0,0 +1,208 @@
+<?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/>.
+
+/**
+ * Renderer.
+ *
+ * @package    tool_analytics
+ * @copyright  2016 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();
+
+use plugin_renderer_base;
+use templatable;
+use renderable;
+
+/**
+ * Renderer class.
+ *
+ * @package    tool_analytics
+ * @copyright  2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class renderer extends plugin_renderer_base {
+
+    /**
+     * Defer to template.
+     *
+     * @param \tool_analytics\output\models_list $modelslist
+     * @return string HTML
+     */
+    protected function render_models_list(\tool_analytics\output\models_list $modelslist) {
+        $data = $modelslist->export_for_template($this);
+        return parent::render_from_template('tool_analytics/models_list', $data);
+    }
+
+    /**
+     * Renders a table.
+     *
+     * @param \table_sql $table
+     * @return string HTML
+     */
+    public function render_table(\table_sql $table) {
+
+        ob_start();
+        $table->out(10, true);
+        $output = ob_get_contents();
+        ob_end_clean();
+
+        return $output;
+    }
+
+    /**
+     * Web interface evaluate results.
+     *
+     * @param \stdClass[] $results
+     * @param string[] $logs
+     * @return string HTML
+     */
+    public function render_evaluate_results($results, $logs = array()) {
+        global $OUTPUT;
+
+        $output = '';
+
+        foreach ($results as $timesplittingid => $result) {
+
+            if (!CLI_SCRIPT) {
+                $output .= $OUTPUT->box_start('generalbox m-b-3');
+            }
+
+            // Check that the array key is a string, not all results depend on time splitting methods (e.g. general errors).
+            if (!is_numeric($timesplittingid)) {
+                $timesplitting = \core_analytics\manager::get_time_splitting($timesplittingid);
+                $langstrdata = (object)array('name' => $timesplitting->get_name(), 'id' => $timesplittingid);
+
+                if (CLI_SCRIPT) {
+                    $output .= $OUTPUT->heading(get_string('getpredictionsresultscli', 'tool_analytics', $langstrdata), 3);
+                } else {
+                    $output .= $OUTPUT->heading(get_string('getpredictionsresults', 'tool_analytics', $langstrdata), 3);
+                }
+            }
+
+            if ($result->status == 0) {
+                $output .= $OUTPUT->notification(get_string('goodmodel', 'tool_analytics'),
+                    \core\output\notification::NOTIFY_SUCCESS);
+            } else if ($result->status === \core_analytics\model::NO_DATASET) {
+                $output .= $OUTPUT->notification(get_string('nodatatoevaluate', 'tool_analytics'),
+                    \core\output\notification::NOTIFY_WARNING);
+            }
+
+            if (isset($result->score)) {
+                // Score.
+                $output .= $OUTPUT->heading(get_string('accuracy', 'tool_analytics') . ': ' .
+                    round(floatval($result->score), 4) * 100  . '%', 4);
+            }
+
+            if (!empty($result->info)) {
+                foreach ($result->info as $message) {
+                    $output .= $OUTPUT->notification($message, \core\output\notification::NOTIFY_WARNING);
+                }
+            }
+
+            if (!CLI_SCRIPT) {
+                $output .= $OUTPUT->box_end();
+            }
+        }
+
+        // Info logged during evaluation.
+        if (!empty($logs) && debugging()) {
+            $output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 3);
+            foreach ($logs as $log) {
+                $output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
+            }
+        }
+
+        if (!CLI_SCRIPT) {
+            $output .= $OUTPUT->single_button(new \moodle_url('/admin/tool/analytics/index.php'), get_string('continue'));
+        }
+
+        return $output;
+    }
+
+
+    /**
+     * Web interface training & prediction results.
+     *
+     * @param \stdClass|false $trainresults
+     * @param string[] $trainlogs
+     * @param \stdClass|false $predictresults
+     * @param string[] $predictlogs
+     * @return string HTML
+     */
+    public function render_get_predictions_results($trainresults = false, $trainlogs = array(), $predictresults = false, $predictlogs = array()) {
+        global $OUTPUT;
+
+        $output = '';
+
+        if ($trainresults || (!empty($trainlogs) && debugging())) {
+            $output .= $OUTPUT->heading(get_string('trainingresults', 'tool_analytics'), 3);
+        }
+
+        if ($trainresults) {
+            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) {
+                $output .= $OUTPUT->notification(get_string('nodatatotrain', 'tool_analytics'),
+                    \core\output\notification::NOTIFY_WARNING);
+            } else {
+                $output .= $OUTPUT->notification(get_string('generalerror', 'analytics', $trainresults->status),
+                    \core\output\notification::NOTIFY_ERROR);
+            }
+        }
+
+        if (!empty($trainlogs) && debugging()) {
+            $output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 4);
+            foreach ($trainlogs as $log) {
+                $output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
+            }
+        }
+
+        if ($predictresults || (!empty($predictlogs) && debugging())) {
+            $output .= $OUTPUT->heading(get_string('predictionresults', 'tool_analytics'), 3, 'main m-t-3');
+        }
+
+        if ($predictresults) {
+            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) {
+                $output .= $OUTPUT->notification(get_string('nodatatopredict', 'tool_analytics'),
+                    \core\output\notification::NOTIFY_WARNING);
+            } else {
+                $output .= $OUTPUT->notification(get_string('generalerror', 'analytics', $predictresults->status),
+                    \core\output\notification::NOTIFY_ERROR);
+            }
+        }
+
+        if (!empty($predictlogs) && debugging()) {
+            $output .= $OUTPUT->heading(get_string('extrainfo', 'tool_analytics'), 4);
+            foreach ($predictlogs as $log) {
+                $output .= $OUTPUT->notification($log, \core\output\notification::NOTIFY_WARNING);
+            }
+        }
+
+        if (!CLI_SCRIPT) {
+            $output .= $OUTPUT->single_button(new \moodle_url('/admin/tool/analytics/index.php'), get_string('continue'));
+        }
+
+        return $output;
+    }
+}
diff --git a/admin/tool/analytics/classes/task/predict_models.php b/admin/tool/analytics/classes/task/predict_models.php
new file mode 100644 (file)
index 0000000..83894be
--- /dev/null
@@ -0,0 +1,71 @@
+<?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/>.
+
+/**
+ * Predict system models with new data available.
+ *
+ * @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\task;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Predict system models with new data available.
+ *
+ * @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 predict_models extends \core\task\scheduled_task {
+
+    /**
+     * get_name
+     *
+     * @return string
+     */
+    public function get_name() {
+        return get_string('predictmodels', 'tool_analytics');
+    }
+
+    /**
+     * Executes the prediction task.
+     *
+     * @return void
+     */
+    public function execute() {
+        global $OUTPUT, $PAGE;
+
+        $models = \core_analytics\manager::get_all_models(true, true);
+        if (!$models) {
+            mtrace(get_string('errornoenabledandtrainedmodels', 'tool_analytics'));
+            return;
+        }
+
+        foreach ($models as $model) {
+            $result = $model->predict();
+            if ($result) {
+                echo $OUTPUT->heading(get_string('modelresults', 'tool_analytics', $model->get_target()->get_name()));
+                $renderer = $PAGE->get_renderer('tool_analytics');
+                echo $renderer->render_get_predictions_results(false, array(), $result, $model->get_analyser()->get_logs());
+            }
+        }
+
+    }
+}
diff --git a/admin/tool/analytics/classes/task/train_models.php b/admin/tool/analytics/classes/task/train_models.php
new file mode 100644 (file)
index 0000000..b017e9a
--- /dev/null
@@ -0,0 +1,82 @@
+<?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/>.
+
+/**
+ * Train system models with new data available.
+ *
+ * @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\task;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Train system models with new data available.
+ *
+ * @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 train_models extends \core\task\scheduled_task {
+
+    /**
+     * get_name
+     *
+     * @return string
+     */
+    public function get_name() {
+        return get_string('trainmodels', 'tool_analytics');
+    }
+
+    /**
+     * Executes the prediction task.
+     *
+     * @return void
+     */
+    public function execute() {
+        global $OUTPUT, $PAGE;
+
+        $models = \core_analytics\manager::get_all_models(true);
+        if (!$models) {
+            mtrace(get_string('errornoenabledmodels', 'tool_analytics'));
+            return;
+        }
+
+        foreach ($models as $model) {
+
+            if ($model->is_static()) {
+                // Skip models based on assumptions.
+                continue;
+            }
+
+            if (!$model->get_time_splitting()) {
+                // Can not train if there is no time splitting method selected.
+                continue;
+            }
+
+            $result = $model->train();
+            if ($result) {
+                echo $OUTPUT->heading(get_string('modelresults', 'tool_analytics', $model->get_target()->get_name()));
+
+                $renderer = $PAGE->get_renderer('tool_analytics');
+                echo $renderer->render_get_predictions_results($result, $model->get_analyser()->get_logs());
+            }
+        }
+    }
+}
diff --git a/admin/tool/analytics/cli/enable_model.php b/admin/tool/analytics/cli/enable_model.php
new file mode 100644 (file)
index 0000000..bc1219f
--- /dev/null
@@ -0,0 +1,72 @@
+<?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/>.
+
+/**
+ * Enables the provided model.
+ *
+ * @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
+ */
+
+define('CLI_SCRIPT', true);
+
+require_once(__DIR__ . '/../../../../config.php');
+require_once($CFG->libdir.'/clilib.php');
+
+$help = "Enables the provided model.
+
+Options:
+--modelid           Model id
+--timesplitting     Time splitting method full class name
+-h, --help          Print out this help
+
+Example:
+\$ php admin/tool/analytics/cli/enable_model.php --modelid=1 --timesplitting=\"\\core\\analytics\\time_splitting\\quarters\"
+";
+
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'help'            => false,
+        'modelid'         => false,
+        'timesplitting'   => false
+    ),
+    array(
+        'h' => 'help',
+    )
+);
+
+if ($options['help']) {
+    echo $help;
+    exit(0);
+}
+
+if ($options['modelid'] === false || $options['timesplitting'] === false) {
+    echo $help;
+    exit(0);
+}
+
+// We need admin permissions.
+\core\session\manager::set_user(get_admin());
+
+$model = new \core_analytics\model($options['modelid']);
+
+// Evaluate its suitability to predict accurately.
+$model->enable($options['timesplitting']);
+
+cli_heading(get_string('success'));
+exit(0);
diff --git a/admin/tool/analytics/cli/evaluate_model.php b/admin/tool/analytics/cli/evaluate_model.php
new file mode 100644 (file)
index 0000000..5319f0d
--- /dev/null
@@ -0,0 +1,131 @@
+<?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/>.
+
+/**
+ * Evaluates the provided model.
+ *
+ * @package    tool_analytics
+ * @copyright  2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require_once(__DIR__ . '/../../../../config.php');
+require_once($CFG->libdir.'/clilib.php');
+
+$help = "Evaluates the provided model.
+
+Options:
+--modelid              Model id
+--non-interactive      Not interactive questions
+--timesplitting        Restrict the evaluation to 1 single time splitting method (Optional)
+--filter               Analyser dependant. e.g. A courseid would evaluate the model using a single course (Optional)
+--reuse-prev-analysed  Reuse recently analysed courses instead of analysing the whole site. Set it to false while" .
+    " coding indicators. Defaults to true (Optional)" . "
+-h, --help             Print out this help
+
+Example:
+\$ php admin/tool/analytics/cli/evaluate_model.php --modelid=1 --timesplitting='\\core\\analytics\\time_splitting\\quarters' --filter=123,321
+";
+
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'help'                  => false,
+        'modelid'               => false,
+        'timesplitting'         => false,
+        'reuse-prev-analysed'   => true,
+        'non-interactive'       => false,
+        'filter'                => false
+    ),
+    array(
+        'h' => 'help',
+    )
+);
+
+if ($options['help']) {
+    echo $help;
+    exit(0);
+}
+
+if ($options['modelid'] === false) {
+    echo $help;
+    exit(0);
+}
+
+// Reformat them as an array.
+if ($options['filter'] !== false) {
+    $options['filter'] = explode(',', $options['filter']);
+}
+
+// We need admin permissions.
+\core\session\manager::set_user(get_admin());
+
+$model = new \core_analytics\model($options['modelid']);
+
+mtrace(get_string('analysingsitedata', 'tool_analytics'));
+
+if ($options['reuse-prev-analysed']) {
+    mtrace(get_string('evaluationinbatches', 'tool_analytics'));
+}
+
+$analyseroptions = array(
+    'filter' => $options['filter'],
+    'timesplitting' => $options['timesplitting'],
+    'reuseprevanalysed' => $options['reuse-prev-analysed'],
+);
+// Evaluate its suitability to predict accurately.
+$results = $model->evaluate($analyseroptions);
+
+$renderer = $PAGE->get_renderer('tool_analytics');
+echo $renderer->render_evaluate_results($results, $model->get_analyser()->get_logs());
+
+// Check that we have, at leasa,t 1 valid dataset (not necessarily good) to use.
+foreach ($results as $result) {
+    if ($result->status !== \core_analytics\model::NO_DATASET &&
+            $result->status !== \core_analytics\model::GENERAL_ERROR) {
+        $validdatasets = true;
+    }
+}
+
+if (!empty($validdatasets) && !$model->is_enabled() && $options['non-interactive'] === false) {
+
+    // Select a dataset, train and enable the model.
+    $input = cli_input(get_string('clienablemodel', 'tool_analytics'));
+    while (!\core_analytics\manager::is_valid($input, '\core_analytics\local\time_splitting\base') && $input !== 'none') {
+        mtrace(get_string('errorunexistingtimesplitting', 'analytics'));
+        $input = cli_input(get_string('clienablemodel', 'tool_analytics'));
+    }
+
+    if ($input === 'none') {
+        exit(0);
+    }
+
+    // Refresh the instance to prevent unexpected issues.
+    $model = new \core_analytics\model($modelobj);
+
+    // Set the time splitting method file and enable it.
+    $model->enable($input);
+
+    mtrace(get_string('trainandpredictmodel', 'tool_analytics'));
+
+    // Train the model with the selected time splitting method and start predicting.
+    $model->train();
+    $model->predict();
+}
+
+exit(0);
diff --git a/admin/tool/analytics/cli/guess_course_start_and_end.php b/admin/tool/analytics/cli/guess_course_start_and_end.php
new file mode 100644 (file)
index 0000000..f8273e1
--- /dev/null
@@ -0,0 +1,207 @@
+<?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/>.
+
+/**
+ * Guesses course start and end dates based on activity logs.
+ *
+ * @package    tool_analytics
+ * @copyright  2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require_once(__DIR__ . '/../../../../config.php');
+require_once($CFG->libdir.'/clilib.php');
+
+require_once($CFG->dirroot . '/course/lib.php');
+require_once($CFG->dirroot . '/course/format/weeks/lib.php');
+
+$help = "Guesses course start and end dates based on activity logs.
+
+Options:
+--guessstart           Guess the course start date (default to true)
+--guessend             Guess the course end date (default to true)
+--guessall             Guess all start and end dates, even if they are already set (default to false)
+--update               Update the db or just notify the guess (default to false)
+--filter               Analyser dependant. e.g. A courseid would evaluate the model using a single course (Optional)
+-h, --help             Print out this help
+
+Example:
+\$ php admin/tool/analytics/cli/guess_course_start_and_end_dates.php --update=1 --filter=123,321
+";
+
+// Now get cli options.
+list($options, $unrecognized) = cli_get_params(
+    array(
+        'help'        => false,
+        'guessstart'  => true,
+        'guessend'    => true,
+        'guessall'    => false,
+        'update'      => false,
+        'filter'      => false
+    ),
+    array(
+        'h' => 'help',
+    )
+);
+
+if ($options['help']) {
+    echo $help;
+    exit(0);
+}
+
+if ($options['guessstart'] === false && $options['guessend'] === false && $options['guessall'] === false) {
+    echo $help;
+    exit(0);
+}
+
+// Reformat them as an array.
+if ($options['filter'] !== false) {
+    $options['filter'] = explode(',', clean_param($options['filter'], PARAM_SEQUENCE));
+}
+
+// We need admin permissions.
+\core\session\manager::set_user(get_admin());
+
+$conditions = array('id != 1');
+if (!$options['guessall']) {
+    if ($options['guessstart']) {
+        $conditions[] = '(startdate is null or startdate = 0)';
+    }
+    if ($options['guessend']) {
+        $conditions[] = '(enddate is null or enddate = 0)';
+    }
+}
+
+$coursessql = '';
+$params = null;
+if ($options['filter']) {
+    list($coursessql, $params) = $DB->get_in_or_equal($options['filter'], SQL_PARAMS_NAMED);
+    $conditions[] = 'id ' . $coursessql;
+}
+
+$courses = $DB->get_recordset_select('course', implode(' AND ', $conditions), $params, 'sortorder ASC');
+foreach ($courses as $course) {
+    tool_analytics_calculate_course_dates($course, $options);
+}
+$courses->close();
+
+
+/**
+ * tool_analytics_calculate_course_dates
+ *
+ * @param stdClass $course
+ * @param array $options CLI options
+ * @return void
+ */
+function tool_analytics_calculate_course_dates($course, $options) {
+    global $DB, $OUTPUT;
+
+    $courseman = new \core_analytics\course($course);
+
+    $notification = $course->shortname . ' (id = ' . $course->id . '): ';
+
+    if ($options['guessstart'] || $options['guessall']) {
+
+        $originalstartdate = $course->startdate;
+
+        $guessedstartdate = $courseman->guess_start();
+        if ($guessedstartdate == $originalstartdate) {
+            if (!$guessedstartdate) {
+                $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics');
+            } else {
+                // No need to update.
+                $notification .= PHP_EOL . '  ' . get_string('samestartdate', 'tool_analytics') . ': ' . userdate($guessedstartdate);
+            }
+        } else if (!$guessedstartdate) {
+            $notification .= PHP_EOL . '  ' . get_string('cantguessstartdate', 'tool_analytics');
+        } else {
+            // Update it to something we guess.
+
+            // We set it to $course even if we don't update because may be needed to guess the end one.
+            $course->startdate = $guessedstartdate;
+            $notification .= PHP_EOL . '  ' . get_string('startdate') . ': ' . userdate($guessedstartdate);
+
+            // Two different course updates because week's end date may be recalculated after setting the start date.
+            if ($options['update']) {
+                update_course($course);
+
+                // Refresh course data as end date may have been updated.
+                $course = $DB->get_record('course', array('id' => $course->id));
+                $courseman = new \core_analytics\course($course);
+            }
+        }
+    }
+
+    if ($options['guessend'] || $options['guessall']) {
+
+        $originalenddate = $course->enddate;
+
+        $format = course_get_format($course);
+        $formatoptions = $format->get_format_options();
+
+        if ($course->format === 'weeks' && $formatoptions['automaticenddate']) {
+            // Special treatment for weeks with automatic end date.
+
+            if ($options['update']) {
+                format_weeks::update_end_date($course->id);
+                $course->enddate = $DB->get_field('course', 'enddate', array('id' => $course->id));
+                $notification .= PHP_EOL . '  ' . get_string('weeksenddateautomaticallyset', 'tool_analytics') . ': ' .
+                    userdate($course->enddate);
+            } else {
+                // We can't provide more info without actually updating it in db.
+                $notification .= PHP_EOL . '  ' . get_string('weeksenddatedefault', 'tool_analytics');
+            }
+        } else {
+            $guessedenddate = $courseman->guess_end();
+
+            if ($guessedenddate == $originalenddate) {
+                if (!$guessedenddate) {
+                    $notification .= PHP_EOL . '  ' . get_string('cantguessenddate', 'tool_analytics');
+                } else {
+                    // No need to update.
+                    $notification .= PHP_EOL . '  ' . get_string('sameenddate', 'tool_analytics') . ': ' . userdate($guessedenddate);
+                }
+            } else if (!$guessedenddate) {
+                $notification .= PHP_EOL . '  ' . get_string('cantguessenddate', 'tool_analytics');
+            } else {
+                // Update it to something we guess.
+
+                $course->enddate = $guessedenddate;
+
+                if ($course->enddate > $course->startdate) {
+                    $notification .= PHP_EOL . '  ' . get_string('enddate') . ': ' . userdate($course->enddate);
+                } else {
+                    $notification .= PHP_EOL . '  ' . get_string('errorendbeforestart', 'analytics', userdate($course->enddate));
+                }
+
+                if ($options['update']) {
+                    if ($course->enddate > $course->startdate) {
+                        update_course($course);
+                    }
+                }
+            }
+        }
+
+    }
+
+    mtrace($notification);
+}
+
+mtrace(get_string('success'));
+
+exit(0);
diff --git a/admin/tool/analytics/db/tasks.php b/admin/tool/analytics/db/tasks.php
new file mode 100644 (file)
index 0000000..2faa2d1
--- /dev/null
@@ -0,0 +1,47 @@
+<?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/>.
+
+/**
+ * This file defines tasks performed by the tool.
+ *
+ * @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
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+// List of tasks.
+$tasks = array(
+    array(
+        'classname' => 'tool_analytics\task\train_models',
+        'blocking' => 0,
+        'minute' => '0',
+        'hour' => 'R',
+        'day' => '*',
+        'dayofweek' => '*',
+        'month' => '*'
+    ),
+    array(
+        'classname' => 'tool_analytics\task\predict_models',
+        'blocking' => 0,
+        'minute' => '0',
+        'hour' => 'R',
+        'day' => '*',
+        'dayofweek' => '*',
+        'month' => '*'
+    ),
+);
diff --git a/admin/tool/analytics/index.php b/admin/tool/analytics/index.php
new file mode 100644 (file)
index 0000000..4b01f6f
--- /dev/null
@@ -0,0 +1,37 @@
+<?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/>.
+
+/**
+ * Prediction models tool frontend.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.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('analyticmodels', '', null, '', array('pagelayout' => 'report'));
+
+$models = \core_analytics\manager::get_all_models();
+
+echo $OUTPUT->header();
+
+$templatable = new \tool_analytics\output\models_list($models);
+echo $PAGE->get_renderer('tool_analytics')->render($templatable);
+
+echo $OUTPUT->footer();
diff --git a/admin/tool/analytics/lang/en/tool_analytics.php b/admin/tool/analytics/lang/en/tool_analytics.php
new file mode 100644 (file)
index 0000000..eba2a8f
--- /dev/null
@@ -0,0 +1,76 @@
+<?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 tool_analytics.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['accuracy'] = 'Accuracy';
+$string['allpredictions'] = 'All predictions';
+$string['analysingsitedata'] = 'Analysing the site';
+$string['analyticmodels'] = 'Analytic models';
+$string['bettercli'] = 'Evaluating models and generating predictions may involve heavy processing. It is advised that you run these actions via the command line interface';
+$string['cantguessstartdate'] = 'Can\'t guess the start date';
+$string['cantguessenddate'] = 'Can\'t guess the end date';
+$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['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 the new ones';
+$string['enabled'] = 'Enabled';
+$string['errorcantenablenotimesplitting'] = 'You need to select a time splitting method before enabling the model';
+$string['errornoenabledandtrainedmodels'] = 'There are not enabled and trained models to predict';
+$string['errornoenabledmodels'] = 'There are not enabled models to train';
+$string['errornostaticedit'] = 'Models based on assumptions can not be edited';
+$string['errornostaticevaluated'] = 'Models based on assumptions can not be evaluated, they are always 100% correct according to how they were defined';
+$string['errornostaticlog'] = 'Models based on assumptions can not be evaluated, there is no preformance log';
+$string['evaluate'] = 'Evaluate';
+$string['evaluatemodel'] = 'Evaluate model';
+$string['evaluationinbatches'] = 'The site contents are calculated and stored in batches, during evaluation you can stop the process at any moment, the next time you run it it will continue from the point you stopped it.';
+$string['trainandpredictmodel'] = 'Training model and calculating predictions';
+$string['getpredictionsresultscli'] = 'Results using {$a->name} (id: {$a->id}) course duration splitting';
+$string['getpredictionsresults'] = 'Results using {$a->name} course duration splitting';
+$string['extrainfo'] = 'Info';
+$string['generalerror'] = 'Evaluation error. Status code {$a}';
+$string['getpredictions'] = 'Get predictions';
+$string['goodmodel'] = 'This is a good model and it can be used to predict, enable it to start getting predictions.';
+$string['indicators'] = 'Indicators';
+$string['info'] = 'Info';
+$string['insights'] = 'Insights';
+$string['loginfo'] = 'Log extra info';
+$string['modelresults'] = '{$a} results';
+$string['modelslist'] = 'Models list';
+$string['modeltimesplitting'] = 'Time splitting';
+$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';
+$string['notdefined'] = 'Not yet defined';
+$string['pluginname'] = 'Analytic models';
+$string['predictionresults'] = 'Prediction results';
+$string['predictmodels'] = 'Predict models';
+$string['predictorresultsin'] = 'Predictor logged information in {$a} directory';
+$string['predictionprocessfinished'] = 'Prediction process finished';
+$string['samestartdate'] = 'Current start date is good';
+$string['sameenddate'] = 'Current end date is good';
+$string['target'] = 'Target';
+$string['trainingprocessfinished'] = 'Training process finished';
+$string['trainingresults'] = 'Training results';
+$string['trainmodels'] = 'Train models';
+$string['viewlog'] = 'Log';
+$string['weeksenddateautomaticallyset'] = 'End date automatically set based on start date and the number of sections';
+$string['weeksenddatedefault'] = 'End date would be automatically calculated from the course start date';
diff --git a/admin/tool/analytics/model.php b/admin/tool/analytics/model.php
new file mode 100644 (file)
index 0000000..2c64179
--- /dev/null
@@ -0,0 +1,152 @@
+<?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/>.
+
+/**
+ * Model-related actions.
+ *
+ * @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
+ */
+
+require_once(__DIR__ . '/../../../config.php');
+
+$id = required_param('id', PARAM_INT);
+$action = required_param('action', PARAM_ALPHANUMEXT);
+
+$context = context_system::instance();
+
+require_login();
+
+$model = new \core_analytics\model($id);
+\core_analytics\manager::check_can_manage_models();
+
+$params = array('id' => $id, 'action' => $action);
+$url = new \moodle_url('/admin/tool/analytics/model.php', $params);
+
+switch ($action) {
+
+    case 'edit':
+        $title = get_string('editmodel', 'tool_analytics', $model->get_target()->get_name());
+        break;
+    case 'evaluate':
+        $title = get_string('evaluatemodel', 'tool_analytics');
+        break;
+    case 'getpredictions':
+        $title = get_string('getpredictions', 'tool_analytics');
+        break;
+    case 'log':
+        $title = get_string('viewlog', 'tool_analytics');
+        break;
+    default:
+        throw new moodle_exception('errorunknownaction', 'analytics');
+}
+
+$PAGE->set_context($context);
+$PAGE->set_url($url);
+$PAGE->set_pagelayout('report');
+$PAGE->set_title($title);
+$PAGE->set_heading($title);
+
+switch ($action) {
+
+    case 'edit':
+
+        if ($model->is_static()) {
+            echo $OUTPUT->header();
+            throw new moodle_exception('errornostaticedit', 'tool_analytics');
+        }
+
+        $customdata = array(
+            'id' => $model->get_id(),
+            'model' => $model,
+            'indicators' => $model->get_potential_indicators(),
+            'timesplittings' => \core_analytics\manager::get_enabled_time_splitting_methods()
+        );
+        $mform = new \tool_analytics\output\form\edit_model(null, $customdata);
+
+        if ($mform->is_cancelled()) {
+            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();
+            foreach ($data->indicators as $indicator) {
+                $indicatorclass = \tool_analytics\output\helper::option_to_class($indicator);
+                $indicators[] = \core_analytics\manager::get_indicator($indicatorclass);
+            }
+            $timesplitting = \tool_analytics\output\helper::option_to_class($data->timesplitting);
+            $model->update($data->enabled, $indicators, $timesplitting);
+            redirect(new \moodle_url('/admin/tool/analytics/index.php'));
+        }
+
+        echo $OUTPUT->header();
+
+        $modelobj = $model->get_model_obj();
+
+        $callable = array('\tool_analytics\output\helper', 'class_to_option');
+        $modelobj->indicators = array_map($callable, json_decode($modelobj->indicators));
+        $modelobj->timesplitting = \tool_analytics\output\helper::class_to_option($modelobj->timesplitting);
+        $mform->set_data($modelobj);
+        $mform->display();
+        break;
+
+    case 'evaluate':
+        echo $OUTPUT->header();
+
+        if ($model->is_static()) {
+            throw new moodle_exception('errornostaticevaluate', 'tool_analytics');
+        }
+
+        // Web interface is used by people who can not use CLI nor code stuff, always use
+        // cached stuff as they will change the model through the web interface as well
+        // which invalidates the previously analysed stuff.
+        $results = $model->evaluate(array('reuseprevanalysed' => true));
+        $renderer = $PAGE->get_renderer('tool_analytics');
+        echo $renderer->render_evaluate_results($results, $model->get_analyser()->get_logs());
+        break;
+
+    case 'getpredictions':
+        echo $OUTPUT->header();
+
+        $trainresults = $model->train();
+        $trainlogs = $model->get_analyser()->get_logs();
+
+        // Looks dumb to get a new instance but better be conservative.
+        $model = new \core_analytics\model($model->get_model_obj());
+        $predictresults = $model->predict();
+        $predictlogs = $model->get_analyser()->get_logs();
+
+        $renderer = $PAGE->get_renderer('tool_analytics');
+        echo $renderer->render_get_predictions_results($trainresults, $trainlogs, $predictresults, $predictlogs);
+        break;
+
+    case 'log':
+        echo $OUTPUT->header();
+
+        if ($model->is_static()) {
+            throw new moodle_exception('errornostaticlog', 'tool_analytics');
+        }
+
+        $renderer = $PAGE->get_renderer('tool_analytics');
+        $modellogstable = new \tool_analytics\output\model_logs('model-' . $model->get_id(), $model);
+        echo $renderer->render_table($modellogstable);
+        break;
+}
+
+echo $OUTPUT->footer();
diff --git a/admin/tool/analytics/settings.php b/admin/tool/analytics/settings.php
new file mode 100644 (file)
index 0000000..76a1bde
--- /dev/null
@@ -0,0 +1,28 @@
+<?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/>.
+
+/**
+ * Adds settings links to admin tree.
+ *
+ * @package tool_analytics
+ * @copyright 2016 David Monllao {@link http://www.davidmonllao.com}
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$ADMIN->add('reports', new admin_externalpage('analyticmodels', get_string('analyticmodels', 'tool_analytics'),
+    "$CFG->wwwroot/$CFG->admin/tool/analytics/index.php", 'moodle/analytics:managemodels'));
diff --git a/admin/tool/analytics/templates/models_list.mustache b/admin/tool/analytics/templates/models_list.mustache
new file mode 100644 (file)
index 0000000..f3d4fc8
--- /dev/null
@@ -0,0 +1,109 @@
+{{!
+    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/models_list
+
+    Template for models list.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * none
+
+    Example context (json):
+    {
+        "models": [
+            {
+                "target": "Prevent devs at risk",
+                "enabled": 1,
+                "indicators": [
+                    "Indicator 1",
+                    "Indicator 2",
+                    "Indicator 3",
+                    "Indicator 4"
+                ],
+                "timesplitting": "Quarters",
+                "noinsights": "No insights available yet"
+            }
+        ],
+        "warnings": {
+            "message": "Hey, this is a warning"
+        }
+    }
+}}
+
+{{#warnings}}
+    {{> core/notification_warning}}
+{{/warnings}}
+<div class="box">
+    <table class="generaltable fullwidth">
+        <caption>{{#str}}modelslist, tool_analytics{{/str}}</caption>
+        <thead>
+            <tr>
+                <th scope="col">{{#str}}target, tool_analytics{{/str}}</th>
+                <th scope="col">{{#str}}enabled, tool_analytics{{/str}}</th>
+                <th scope="col">{{#str}}indicators, tool_analytics{{/str}}</th>
+                <th scope="col">{{#str}}modeltimesplitting, tool_analytics{{/str}}</th>
+                <th scope="col">{{#str}}insights, tool_analytics{{/str}}</th>
+                <th scope="col">{{#str}}actions{{/str}}</th>
+            </tr>
+        </thead>
+        <tbody>
+        {{#models}}
+            <tr>
+                <td>{{target}}</td>
+                <td>
+                    {{#enabled}}
+                        {{#pix}}i/checked, core, {{#str}}yes{{/str}}{{/pix}}
+                    {{/enabled}}
+                    {{^enabled}}
+                        {{#str}}no{{/str}}
+                    {{/enabled}}
+                </td>
+                <td>
+                    <ul>
+                    {{#indicators}}
+                        <li>{{.}}</li>
+                    {{/indicators}}
+                    </ul>
+                </td>
+                <td>
+                    {{#timesplitting}}{{timesplitting}}{{/timesplitting}}{{^timesplitting}}{{#str}}notdefined, tool_analytics{{/str}}{{/timesplitting}}
+                </td>
+                <td>
+                    {{! models_list renderer is responsible of sending one or the other}}
+                    {{#insights}}
+                        {{> core/single_select }}
+                    {{/insights}}
+                    {{#noinsights}}
+                        {{.}}
+                    {{/noinsights}}
+                </td>
+                <td>
+                    {{#actions}}
+                        {{> core/action_menu}}
+                    {{/actions}}
+                </td>
+            </tr>
+        {{/models}}
+        </tbody>
+    </table>
+</div>
similarity index 69%
rename from auth/fc/version.php
rename to admin/tool/analytics/version.php
index 386950a..d630777 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Version details
+ * Version details.
  *
- * @package    auth_fc
- * @copyright  1999 onwards Martin Dougiamas (http://dougiamas.com)
+ * @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
  */
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2017051500;        // The current plugin version (Date: YYYYMMDDXX)
-$plugin->requires  = 2017050500;        // Requires this Moodle version
-$plugin->component = 'auth_fc';         // Full name of the plugin (used for diagnostics)
+$plugin->version   = 2017051500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires  = 2017050500; // Requires this Moodle version.
+$plugin->component = 'tool_analytics'; // Full name of the plugin (used for diagnostics).
index d6fa182..afda140 100644 (file)
@@ -29,15 +29,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_tool_customlang_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v2.8.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v2.9.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v3.0.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Moodle v3.1.0 release upgrade line.
     // Put any upgrade step following this.
 
index 3d7f4f9..13befec 100644 (file)
@@ -33,15 +33,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_tool_log_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v2.8.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v2.9.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v3.0.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Moodle v3.1.0 release upgrade line.
     // Put any upgrade step following this.
 
index 789415e..0dbe11a 100644 (file)
@@ -27,15 +27,6 @@ defined('MOODLE_INTERNAL') || die();
 function xmldb_logstore_database_upgrade($oldversion) {
     global $CFG;
 
-    // Moodle v2.8.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v2.9.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v3.0.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Moodle v3.1.0 release upgrade line.
     // Put any upgrade step following this.
 
index 2614e0a..bcd8d1d 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 function xmldb_logstore_standard_upgrade($oldversion) {
-    global $CFG, $DB;
-
-    $dbman = $DB->get_manager();
-
-    // Moodle v2.8.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v2.9.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v3.0.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    if ($oldversion < 2016041200) {
-        // This could take a long time. Unfortunately, no way to know how long, and no way to do progress, so setting for 1 hour.
-        upgrade_set_timeout(3600);
-
-        // Define key contextid (foreign) to be added to logstore_standard_log.
-        $table = new xmldb_table('logstore_standard_log');
-        $key = new xmldb_key('contextid', XMLDB_KEY_FOREIGN, array('contextid'), 'context', array('id'));
-
-        // Launch add key contextid.
-        $dbman->add_key($table, $key);
-
-        // Standard savepoint reached.
-        upgrade_plugin_savepoint(true, 2016041200, 'logstore', 'standard');
-    }
+    global $CFG;
 
     // Moodle v3.1.0 release upgrade line.
     // Put any upgrade step following this.
index 6af0d41..77cf893 100644 (file)
@@ -920,119 +920,6 @@ class external extends external_api {
         ));
     }
 
-    /**
-     * Returns the description of external function parameters.
-     *
-     * @return external_function_parameters
-     */
-    public static function search_cohorts_parameters() {
-        $query = new external_value(
-            PARAM_RAW,
-            'Query string'
-        );
-        $includes = new external_value(
-            PARAM_ALPHA,
-            'What other contexts to fetch the frameworks from. (all, parents, self)',
-            VALUE_DEFAULT,
-            'parents'
-        );
-        $limitfrom = new external_value(
-            PARAM_INT,
-            'limitfrom we are fetching the records from',
-            VALUE_DEFAULT,
-            0
-        );
-        $limitnum = new external_value(
-            PARAM_INT,
-            'Number of records to fetch',
-            VALUE_DEFAULT,
-            25
-        );
-        return new external_function_parameters(array(
-            'query' => $query,
-            'context' => self::get_context_parameters(),
-            'includes' => $includes,
-            'limitfrom' => $limitfrom,
-            'limitnum' => $limitnum
-        ));
-    }
-
-    /**
-     * Search cohorts.
-     * TODO: MDL-52243 Move this function to cohorts/externallib.php
-     *
-     * @param string $query
-     * @param array $context
-     * @param string $includes
-     * @param int $limitfrom
-     * @param int $limitnum
-     * @return array
-     */
-    public static function search_cohorts($query, $context, $includes = 'parents', $limitfrom = 0, $limitnum = 25) {
-        global $DB, $CFG, $PAGE;
-        require_once($CFG->dirroot . '/cohort/lib.php');
-
-        $params = self::validate_parameters(self::search_cohorts_parameters(), array(
-            'query' => $query,
-            'context' => $context,
-            'includes' => $includes,
-            'limitfrom' => $limitfrom,
-            'limitnum' => $limitnum,
-        ));
-        $query = $params['query'];
-        $includes = $params['includes'];
-        $context = self::get_context_from_params($params['context']);
-        $limitfrom = $params['limitfrom'];
-        $limitnum = $params['limitnum'];
-
-        self::validate_context($context);
-        $output = $PAGE->get_renderer('tool_lp');
-
-        $manager = has_capability('moodle/cohort:manage', $context);
-        if (!$manager) {
-            require_capability('moodle/cohort:view', $context);
-        }
-
-        // TODO Make this more efficient.
-        if ($includes == 'self') {
-            $results = cohort_get_cohorts($context->id, $limitfrom, $limitnum, $query);
-            $results = $results['cohorts'];
-        } else if ($includes == 'parents') {
-            $results = cohort_get_cohorts($context->id, $limitfrom, $limitnum, $query);
-            $results = $results['cohorts'];
-            if (!$context instanceof context_system) {
-                $results = array_merge($results, cohort_get_available_cohorts($context, COHORT_ALL, $limitfrom, $limitnum, $query));
-            }
-        } else if ($includes == 'all') {
-            $results = cohort_get_all_cohorts($limitfrom, $limitnum, $query);
-            $results = $results['cohorts'];
-        } else {
-            throw new coding_exception('Invalid parameter value for \'includes\'.');
-        }
-
-        $cohorts = array();
-        foreach ($results as $key => $cohort) {
-            $cohortcontext = context::instance_by_id($cohort->contextid);
-            $exporter = new cohort_summary_exporter($cohort, array('context' => $cohortcontext));
-            $newcohort = $exporter->export($output);
-
-            $cohorts[$key] = $newcohort;
-        }
-
-        return array('cohorts' => $cohorts);
-    }
-
-    /**
-     * Returns description of external function result value.
-     *
-     * @return external_description
-     */
-    public static function search_cohorts_returns() {
-        return new external_single_structure(array(
-            'cohorts' => new external_multiple_structure(cohort_summary_exporter::get_read_structure())
-        ));
-    }
-
     /**
      * Returns description of external function.
      *
index 258f382..b7f9e9e 100644 (file)
@@ -131,10 +131,11 @@ $functions = array(
         'capabilities' => '',
         'ajax'         => true,
     ),
+    // This function was originally in this plugin but has been moved to core.
     'tool_lp_search_cohorts' => array(
-        'classname'    => 'tool_lp\external',
+        'classname'    => 'core_cohort_external',
         'methodname'   => 'search_cohorts',
-        'classpath'    => '',
+        'classpath'    => 'cohort/externallib.php',
         'description'  => 'Search for cohorts.',
         'type'         => 'read',
         'capabilities' => 'moodle/cohort:view',
index a43d857..acd0b19 100644 (file)
@@ -63,16 +63,4 @@ class behat_tool_lp extends behat_base {
         $this->execute('behat_general::i_click_on', [$xpathtarget, 'xpath_element']);
     }
 
-    /**
-     * Select item from autocomplete list.
-     *
-     * @Given /^I click on "([^"]*)" item in the autocomplete list$/
-     *
-     * @param string $item
-     */
-    public function i_click_on_item_in_the_autocomplete_list($item) {
-        $xpathtarget = "//ul[@class='form-autocomplete-suggestions']//li//span//span[contains(.,'" . $item . "')]";
-
-        $this->execute('behat_general::i_click_on', [$xpathtarget, 'xpath_element']);
-    }
 }
index 456e32b..7e9fecc 100644 (file)
@@ -28,8 +28,9 @@ Feature: Manage plearning plan
     And I follow "Home"
     And I navigate to "Competencies > Learning plan templates" in site administration
     And I click on ".template-userplans" "css_element" in the "Science template" "table_row"
-    And I click on ".form-autocomplete-downarrow" "css_element"
+    And I open the autocomplete suggestions list
     And I click on "Admin" item in the autocomplete list
+    And I press key "27" in the field "Select users to create learning plans for"
     When I click on "Create learning plans" "button"
     Then I should see "A learning plan was created"
     And I should see "Admin User" in the "Science template" "table_row"
@@ -54,6 +55,7 @@ Feature: Manage plearning plan
     And I click on ".template-cohorts" "css_element" in the "Science template cohort" "table_row"
     And I click on ".form-autocomplete-downarrow" "css_element"
     And I click on "cohort plan" item in the autocomplete list
+    And I press key "27" in the field "Select cohorts to sync"
     When I click on "Add cohorts" "button"
     Then I should see "2 learning plans were created."
     And I follow "Learning plan templates"
index d523735..138a420 100644 (file)
@@ -461,76 +461,4 @@ class tool_lp_external_testcase extends externallib_advanced_testcase {
         $this->assertEquals('A', $summary->evidence[1]->gradename);
     }
 
-    /**
-     * Search cohorts.
-     */
-    public function test_search_cohorts() {
-        $this->resetAfterTest(true);
-
-        $syscontext = array('contextid' => context_system::instance()->id);
-        $catcontext = array('contextid' => context_coursecat::instance($this->category->id)->id);
-        $othercatcontext = array('contextid' => context_coursecat::instance($this->othercategory->id)->id);
-
-        $cohort1 = $this->getDataGenerator()->create_cohort(array_merge($syscontext, array('name' => 'Cohortsearch 1')));
-        $cohort2 = $this->getDataGenerator()->create_cohort(array_merge($catcontext, array('name' => 'Cohortsearch 2')));
-        $cohort3 = $this->getDataGenerator()->create_cohort(array_merge($othercatcontext, array('name' => 'Cohortsearch 3')));
-
-        // Check for parameter $includes = 'parents'.
-
-        // A user without permission in the system.
-        $this->setUser($this->user);
-        try {
-            $result = external::search_cohorts("Cohortsearch", $syscontext, 'parents');
-            $this->fail('Invalid permissions in system');
-        } catch (required_capability_exception $e) {
-            // All good.
-        }
-
-        // A user without permission in a category.
-        $this->setUser($this->catuser);
-        try {
-            $result = external::search_cohorts("Cohortsearch", $catcontext, 'parents');
-            $this->fail('Invalid permissions in category');
-        } catch (required_capability_exception $e) {
-            // All good.
-        }
-
-        // A user with permissions in the system.
-        $this->setUser($this->creator);
-        $result = external::search_cohorts("Cohortsearch", $syscontext, 'parents');
-        $this->assertEquals(1, count($result['cohorts']));
-        $this->assertEquals('Cohortsearch 1', $result['cohorts'][$cohort1->id]->name);
-
-        // A user with permissions in the category.
-        $this->setUser($this->catcreator);
-        $result = external::search_cohorts("Cohortsearch", $catcontext, 'parents');
-        $this->assertEquals(2, count($result['cohorts']));
-        $cohorts = array();
-        foreach ($result['cohorts'] as $cohort) {
-            $cohorts[] = $cohort->name;
-        }
-        $this->assertTrue(in_array('Cohortsearch 1', $cohorts));
-        $this->assertTrue(in_array('Cohortsearch 2', $cohorts));
-
-        // Check for parameter $includes = 'self'.
-        $this->setUser($this->creator);
-        $result = external::search_cohorts("Cohortsearch", $othercatcontext, 'self');
-        $this->assertEquals(1, count($result['cohorts']));
-        $this->assertEquals('Cohortsearch 3', $result['cohorts'][$cohort3->id]->name);
-
-        // Check for parameter $includes = 'all'.
-        $this->setUser($this->creator);
-        $result = external::search_cohorts("Cohortsearch", $syscontext, 'all');
-        $this->assertEquals(3, count($result['cohorts']));
-
-        // Detect invalid parameter $includes.
-        $this->setUser($this->creator);
-        try {
-            $result = external::search_cohorts("Cohortsearch", $syscontext, 'invalid');
-            $this->fail('Invalid parameter includes');
-        } catch (coding_exception $e) {
-            // All good.
-        }
-    }
-
 }
index 3dadfb7..4c12650 100644 (file)
@@ -25,6 +25,6 @@
 defined('MOODLE_INTERNAL') || die();
 
 
-$plugin->version   = 2017051500; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version   = 2017062700; // The current plugin version (Date: YYYYMMDDXX).
 $plugin->requires  = 2017050500; // Requires this Moodle version.
 $plugin->component = 'tool_lp'; // Full name of the plugin (used for diagnostics).
index 1a47f3a..4d7c475 100644 (file)
@@ -31,34 +31,10 @@ defined('MOODLE_INTERNAL') || die();
  * @return bool always true
  */
 function xmldb_tool_monitor_upgrade($oldversion) {
-    global $DB;
+    global $CFG, $DB;
 
     $dbman = $DB->get_manager();
 
-    if ($oldversion < 2014102000) {
-
-        // Define field lastnotificationsent to be added to tool_monitor_subscriptions.
-        $table = new xmldb_table('tool_monitor_subscriptions');
-        $field = new xmldb_field('lastnotificationsent', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0', 'timecreated');
-
-        // Conditionally launch add field lastnotificationsent.
-        if (!$dbman->field_exists($table, $field)) {
-            $dbman->add_field($table, $field);
-        }
-
-        // Monitor savepoint reached.
-        upgrade_plugin_savepoint(true, 2014102000, 'tool', 'monitor');
-    }
-
-    // Moodle v2.8.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v2.9.0 release upgrade line.
-    // Put any upgrade step following this.
-
-    // Moodle v3.0.0 release upgrade line.
-    // Put any upgrade step following this.
-
     // Moodle v3.1.0 release upgrade line.
     // Put any upgrade step following this.
 
index 3a0b64d..a57b4c2 100644 (file)
@@ -119,6 +119,10 @@ class issuer extends persistent {
         $mform->addElement('checkbox', 'showonloginpage', get_string('issuershowonloginpage', 'tool_oauth2'));
         $mform->addHelpButton('showonloginpage', 'issuershowonloginpage', 'tool_oauth2');
 
+        // Require confirmation email for new accounts.
+        $mform->addElement('advcheckbox', 'requireconfirmation', get_string('issuerrequireconfirmation', 'tool_oauth2'));
+        $mform->addHelpButton('requireconfirmation', 'issuerrequireconfirmation', 'tool_oauth2');
+
         $mform->addElement('hidden', 'sortorder');
         $mform->setType('sortorder', PARAM_INT);
 
index 5cc423c..8c20c6a 100644 (file)
@@ -81,6 +81,8 @@ $string['issuername_help'] = 'Name of the identity issuer. May be displayed on l
 $string['issuername'] = 'Name';
 $string['issuershowonloginpage_help'] = 'If the OAuth 2 authentication plugin is enabled, this login issuer will be listed on the login page to allow users to log in with accounts from this issuer.';
 $string['issuershowonloginpage'] = 'Show on login page';
+$string['issuerrequireconfirmation_help'] = 'Require that all users verify their email address before they can log in with OAuth. This applies to newly created accounts as part of the login process, or when an existing Moodle account is connected to an OAuth login via matching email addresses.';
+$string['issuerrequireconfirmation'] = 'Require email verification';
 $string['issuers'] = 'Issuers';
 $string['loginissuer'] = 'Allow login';
 $string['notconfigured'] = 'Not configured';
index 75500b2..da1592e 100644 (file)
@@ -95,7 +95,7 @@ class tool_uploadcourse_course {
     /** @var array fields allowed as course data. */
     static protected $validfields = array('fullname', 'shortname', 'idnumber', 'category', 'visible', 'startdate', 'enddate',
         'summary', 'format', 'theme', 'lang', 'newsitems', 'showgrades', 'showreports', 'legacyfiles', 'maxbytes',
-        'groupmode', 'groupmodeforce', 'groupmodeforce', 'enablecompletion');
+        'groupmode', 'groupmodeforce', 'enablecompletion');
 
     /** @var array fields required on course creation. */
     static protected $mandatoryfields = array('fullname', 'category');
@@ -676,6 +676,17 @@ class tool_uploadcourse_course {
             return false;
         }
 
+        // TODO MDL-59259 allow to set course format options for the current course format.
+
+        // Special case, 'numsections' is not a course format option any more but still should apply from defaults.
+        if (!$exists || !array_key_exists('numsections', $coursedata)) {
+            if (isset($this->rawdata['numsections']) && is_numeric($this->rawdata['numsections'])) {
+                $coursedata['numsections'] = (int)$this->rawdata['numsections'];
+            } else {
+                $coursedata['numsections'] = get_config('moodlecourse', 'numsections');
+            }
+        }
+
         // Saving data.
         $this->data = $coursedata;
         $this->enrolmentdata = tool_uploadcourse_helper::get_enrolment_data($this->rawdata);
index 4601500..d3c5024 100644 (file)
@@ -166,6 +166,13 @@ class tool_uploadcourse_step2_form extends tool_uploadcourse_base_form {
         $mform->addHelpButton('defaults[groupmodeforce]', 'groupmodeforce', 'group');
         $mform->setDefault('defaults[groupmodeforce]', $courseconfig->groupmodeforce);
 
+        // Completion tracking.
+        if (!empty($CFG->enablecompletion)) {
+            $mform->addElement('selectyesno', 'defaults[enablecompletion]', get_string('enablecompletion', 'completion'));
+            $mform->setDefault('defaults[enablecompletion]', $courseconfig->enablecompletion);
+            $mform->addHelpButton('defaults[enablecompletion]', 'enablecompletion', 'completion');
+        }
+
         // Hidden fields.
         $mform->addElement('hidden', 'importid');
         $mform->setType('importid', PARAM_INT);
index 7d9970f..75c39d8 100644 (file)
@@ -166,6 +166,7 @@ $defaults['groupmode'] = $courseconfig->groupmode;
 $defaults['groupmodeforce'] = $courseconfig->groupmodeforce;
 $defaults['visible'] = $courseconfig->visible;
 $defaults['lang'] =  $courseconfig->lang;
+$defaults['enablecompletion'] = $courseconfig->enablecompletion;
 
 // Course template.
 if (isset($options['templatecourse'])) {
index 3ac9fe0..3356163 100644 (file)
@@ -120,6 +120,36 @@ class tool_uploadcourse_course_testcase extends advanced_testcase {
         $this->assertTrue($DB->record_exists('course', array('shortname' => 'c2')));
     }
 
+    public function test_create_with_sections() {
+        global $DB;
+        $this->resetAfterTest(true);
+        $updatemode = tool_uploadcourse_processor::UPDATE_NOTHING;
+        $defaultnumsections = get_config('moodlecourse', 'numsections');
+
+        // Add new course, make sure default number of sections is created.
+        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
+        $data = array('shortname' => 'newcourse1', 'fullname' => 'New course1', 'format' => 'topics', 'category' => 1);
+        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
+        $this->assertTrue($co->prepare());
+        $co->proceed();
+        $courseid = $DB->get_field('course', 'id', array('shortname' => 'newcourse1'));
+        $this->assertNotEmpty($courseid);
+        $this->assertEquals($defaultnumsections + 1,
+            $DB->count_records('course_sections', ['course' => $courseid]));
+
+        // Add new course specifying number of sections.
+        $mode = tool_uploadcourse_processor::MODE_CREATE_NEW;
+        $data = array('shortname' => 'newcourse2', 'fullname' => 'New course2', 'format' => 'topics', 'category' => 1,
+            'numsections' => 15);
+        $co = new tool_uploadcourse_course($mode, $updatemode, $data);
+        $this->assertTrue($co->prepare());
+        $co->proceed();
+        $courseid = $DB->get_field('course', 'id', array('shortname' => 'newcourse2'));
+        $this->assertNotEmpty($courseid);
+        $this->assertEquals(15 + 1,
+            $DB->count_records('course_sections', ['course' => $courseid]));
+    }
+
     public function test_delete() {
         global $DB;
         $this->resetAfterTest(true);
index 73306ea..c37ab36 100644 (file)
@@ -20,6 +20,8 @@
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
+defined('MOODLE_INTERNAL') || die();
+
 /**
  * This class will check all the default values existing in the DB
  * match those specified in the xml specs
@@ -34,15 +36,15 @@ class check_defaults extends XMLDBCheckAction {
     /**
      * Init method, every subclass will have its own
      */
-    function init() {
+    public function init() {
         $this->introstr = 'confirmcheckdefaults';
         parent::init();
 
-        // Set own core attributes
+        // Set own core attributes.
 
-        // Set own custom attributes
+        // Set own custom attributes.
 
-        // Get needed strings
+        // Get needed strings.
         $this->loadStrings(array(
             'wrongdefaults' => 'tool_xmldb',
             'nowrongdefaultsfound' => 'tool_xmldb',
@@ -52,107 +54,130 @@ class check_defaults extends XMLDBCheckAction {
         ));
     }
 
-    protected function check_table(xmldb_table $xmldb_table, array $metacolumns) {
+    protected function check_table(xmldb_table $xmldbtable, array $metacolumns) {
         $o = '';
-        $wrong_fields = array();
+        $wrongfields = array();
+
+        // Get and process XMLDB fields.
+        if ($xmldbfields = $xmldbtable->getFields()) {
+            $o .= '        <ul>';
+            foreach ($xmldbfields as $xmldbfield) {
 
-        // Get and process XMLDB fields
-        if ($xmldb_fields = $xmldb_table->getFields()) {
-            $o.='        <ul>';
-            foreach ($xmldb_fields as $xmldb_field) {
+                // Get the default value for the field.
+                $xmldbdefault = $xmldbfield->getDefault();
 
-                // Get the default value for the field
-                $xmldbdefault = $xmldb_field->getDefault();
+                // Char fields with not null currently have default '' when actually installed.
+                if ($xmldbdefault === null && $xmldbfield->getType() === XMLDB_TYPE_CHAR &&
+                        $xmldbfield->getNotNull()) {
+                    $xmldbdefault = '';
+                }
+                if ($xmldbdefault !== null) {
+                    $xmldbdefault = (string)$xmldbdefault;
+                }
 
-                // If the metadata for that column doesn't exist or 'id' field found, skip
-                if (!isset($metacolumns[$xmldb_field->getName()]) or $xmldb_field->getName() == 'id') {
+                // If the metadata for that column doesn't exist or 'id' field found, skip.
+                if (!isset($metacolumns[$xmldbfield->getName()]) or $xmldbfield->getName() == 'id') {
                     continue;
                 }
 
-                // To variable for better handling
-                $metacolumn = $metacolumns[$xmldb_field->getName()];
+                // To variable for better handling.
+                $metacolumn = $metacolumns[$xmldbfield->getName()];
 
-                // Going to check this field in DB
-                $o.='            <li>' . $this->str['field'] . ': ' . $xmldb_field->getName() . ' ';
+                // Going to check this field in DB.
+                $o .= '            <li>' . $this->str['field'] . ': ' . $xmldbfield->getName() . ' ';
 
-                // get the value of the physical default (or blank if there isn't one)
-                if ($metacolumn->has_default==1) {
+                // Get the value of the physical default (or blank if there isn't one).
+                if ($metacolumn->has_default == 1) {
                     $physicaldefault = $metacolumn->default_value;
-                }
-                else {
-                    $physicaldefault = '';
+                } else {
+                    $physicaldefault = null;
                 }
 
-                // there *is* a default and it's wrong
-                if ($physicaldefault != $xmldbdefault) {
-                    $info = '('.$this->str['expected']." '$xmldbdefault', ".$this->str['actual'].
-                    " '$physicaldefault')";
-                    $o.='<font color="red">' . $this->str['wrong'] . " $info</font>";
-                    // Add the wrong field to the list
+                // There *is* a default and it's wrong.
+                if ($physicaldefault !== $xmldbdefault) {
+                    $xmldbtext = self::display_default($xmldbdefault);
+                    $physicaltext = self::display_default($physicaldefault);
+                    $info = "({$this->str['expected']} {$xmldbtext}, {$this->str['actual']} {$physicaltext})";
+                    $o .= '<font color="red">' . $this->str['wrong'] . " $info</font>";
+