Merge branch 'MDL-70320-master' of https://github.com/andrewnicols/moodle
authorJake Dallimore <jake@moodle.com>
Thu, 10 Dec 2020 00:12:10 +0000 (08:12 +0800)
committerJake Dallimore <jake@moodle.com>
Thu, 10 Dec 2020 03:56:40 +0000 (11:56 +0800)
750 files changed:
.github/workflows/config-template.php [new file with mode: 0644]
.github/workflows/push.yml [new file with mode: 0644]
.travis.yml
admin/cli/generate_key.php [new file with mode: 0644]
admin/settings/analytics.php
admin/templates/setting_encryptedpassword.mustache [new file with mode: 0644]
admin/tests/behat/behat_admin.php
admin/tool/behat/tests/behat/inplaceeditable.feature [new file with mode: 0644]
admin/tool/behat/tests/behat/keyboard.feature
admin/upgrade.txt
analytics/classes/manager.php
analytics/upgrade.txt
auth/oauth2/login.php
blocks/classes/external/fetch_addable_blocks.php [new file with mode: 0644]
blocks/section_links/block_section_links.php
blocks/section_links/edit_form.php
blocks/section_links/lang/en/block_section_links.php
blocks/section_links/renderer.php
blocks/section_links/settings.php
blocks/section_links/tests/behat/show_section_name.feature [new file with mode: 0644]
blocks/section_links/upgrade.txt [new file with mode: 0644]
blocks/section_links/version.php
blocks/site_main_menu/tests/behat/behat_block_site_main_menu.php
blocks/site_main_menu/tests/behat/edit_activities.feature
blocks/social_activities/tests/behat/behat_block_social_activities.php
blocks/social_activities/tests/behat/edit_activities.feature
cohort/tests/behat/add_cohort.feature
config-dist.php
course/amd/build/local/activitychooser/dialogue.min.js
course/amd/build/local/activitychooser/dialogue.min.js.map
course/amd/build/local/activitychooser/selectors.min.js
course/amd/build/local/activitychooser/selectors.min.js.map
course/amd/src/local/activitychooser/dialogue.js
course/amd/src/local/activitychooser/selectors.js
course/format/topics/tests/behat/edit_delete_sections.feature
course/format/weeks/tests/behat/edit_delete_sections.feature
course/tests/behat/activities_edit_name.feature
course/tests/behat/behat_course.php
customfield/externallib.php
customfield/tests/behat/edit_categories.feature
enrol/cohort/settings.php
enrol/database/cli/sync.php [deleted file]
enrol/database/settings.php
enrol/database/upgrade.txt
enrol/externallib.php
enrol/fee/settings.php
enrol/manual/settings.php
enrol/mnet/settings.php
enrol/paypal/settings.php
enrol/self/settings.php
enrol/tests/externallib_test.php
enrol/upgrade.txt
h5p/classes/player.php
install/lang/ab/langconfig.php [new file with mode: 0644]
install/lang/af/admin.php
install/lang/af/install.php
install/lang/af/langconfig.php
install/lang/af/moodle.php
install/lang/am/install.php
install/lang/am/langconfig.php
install/lang/am/moodle.php
install/lang/an/admin.php
install/lang/an/error.php
install/lang/an/install.php
install/lang/an/langconfig.php
install/lang/an/moodle.php
install/lang/ar/admin.php
install/lang/ar/error.php
install/lang/ar/install.php
install/lang/ar/langconfig.php
install/lang/ar/moodle.php
install/lang/ar_wp/langconfig.php
install/lang/ar_wp/moodle.php [new file with mode: 0644]
install/lang/arn/langconfig.php
install/lang/ast/admin.php
install/lang/ast/error.php
install/lang/ast/install.php
install/lang/ast/langconfig.php
install/lang/ast/moodle.php
install/lang/az/admin.php
install/lang/az/error.php
install/lang/az/install.php
install/lang/az/langconfig.php
install/lang/az/moodle.php
install/lang/ba/langconfig.php
install/lang/bar/admin.php
install/lang/bar/langconfig.php
install/lang/be/langconfig.php
install/lang/be/moodle.php
install/lang/bg/admin.php
install/lang/bg/error.php
install/lang/bg/install.php
install/lang/bg/langconfig.php
install/lang/bg/moodle.php
install/lang/bi/langconfig.php
install/lang/bm/langconfig.php
install/lang/bn/admin.php
install/lang/bn/error.php
install/lang/bn/install.php
install/lang/bn/langconfig.php
install/lang/bn/moodle.php
install/lang/br/langconfig.php
install/lang/bs/admin.php
install/lang/bs/error.php
install/lang/bs/install.php
install/lang/bs/langconfig.php
install/lang/bs/moodle.php
install/lang/ca/admin.php
install/lang/ca/error.php
install/lang/ca/install.php
install/lang/ca/langconfig.php
install/lang/ca/moodle.php
install/lang/ca_valencia/admin.php
install/lang/ca_valencia/error.php
install/lang/ca_valencia/install.php
install/lang/ca_valencia/langconfig.php
install/lang/ca_valencia_racv/langconfig.php
install/lang/ca_wp/langconfig.php
install/lang/ckb/admin.php
install/lang/ckb/error.php
install/lang/ckb/langconfig.php
install/lang/ckb/moodle.php
install/lang/cs/admin.php
install/lang/cs/error.php
install/lang/cs/install.php
install/lang/cs/langconfig.php
install/lang/cs/moodle.php
install/lang/cy/admin.php
install/lang/cy/error.php
install/lang/cy/install.php
install/lang/cy/langconfig.php
install/lang/cy/moodle.php
install/lang/da/admin.php
install/lang/da/error.php
install/lang/da/install.php
install/lang/da/langconfig.php
install/lang/da/moodle.php
install/lang/da_kursus/langconfig.php
install/lang/da_rum/langconfig.php
install/lang/de/admin.php
install/lang/de/error.php
install/lang/de/install.php
install/lang/de/langconfig.php
install/lang/de/moodle.php
install/lang/de_ch/langconfig.php
install/lang/de_comm/langconfig.php
install/lang/de_du/error.php
install/lang/de_du/install.php
install/lang/de_du/langconfig.php
install/lang/de_kids/langconfig.php
install/lang/de_wp/langconfig.php
install/lang/dsb/langconfig.php
install/lang/dv/admin.php
install/lang/dv/error.php
install/lang/dv/install.php
install/lang/dv/langconfig.php
install/lang/dv/moodle.php
install/lang/dz/admin.php
install/lang/dz/error.php
install/lang/dz/install.php
install/lang/dz/langconfig.php
install/lang/dz/moodle.php
install/lang/ee/langconfig.php
install/lang/el/admin.php
install/lang/el/error.php
install/lang/el/install.php
install/lang/el/langconfig.php
install/lang/el/moodle.php
install/lang/el_kids/langconfig.php
install/lang/el_uni/langconfig.php
install/lang/el_wp/admin.php
install/lang/el_wp/error.php
install/lang/el_wp/install.php
install/lang/el_wp/langconfig.php
install/lang/el_wp/moodle.php
install/lang/en/admin.php
install/lang/en/error.php
install/lang/en/install.php
install/lang/en/langconfig.php
install/lang/en/moodle.php
install/lang/en_ar/admin.php
install/lang/en_ar/error.php
install/lang/en_ar/install.php
install/lang/en_ar/langconfig.php
install/lang/en_kids/langconfig.php
install/lang/en_us/admin.php
install/lang/en_us/install.php
install/lang/en_us/langconfig.php
install/lang/en_us_k12/langconfig.php
install/lang/en_us_wp/langconfig.php
install/lang/en_wp/langconfig.php
install/lang/eo/langconfig.php
install/lang/eo/moodle.php
install/lang/es/admin.php
install/lang/es/error.php
install/lang/es/install.php
install/lang/es/langconfig.php
install/lang/es/moodle.php
install/lang/es_co/install.php
install/lang/es_co/langconfig.php
install/lang/es_mx/admin.php
install/lang/es_mx/error.php
install/lang/es_mx/install.php
install/lang/es_mx/langconfig.php
install/lang/es_mx/moodle.php
install/lang/es_mx_kids/langconfig.php
install/lang/es_ve/langconfig.php
install/lang/es_wp/langconfig.php
install/lang/et/admin.php
install/lang/et/error.php
install/lang/et/install.php
install/lang/et/langconfig.php
install/lang/et/moodle.php
install/lang/eu/admin.php
install/lang/eu/error.php
install/lang/eu/install.php
install/lang/eu/langconfig.php
install/lang/eu/moodle.php
install/lang/fa/admin.php
install/lang/fa/error.php
install/lang/fa/install.php
install/lang/fa/langconfig.php
install/lang/fa/moodle.php
install/lang/fi/admin.php
install/lang/fi/error.php
install/lang/fi/install.php
install/lang/fi/langconfig.php
install/lang/fi/moodle.php
install/lang/fi_co/langconfig.php
install/lang/fil/langconfig.php
install/lang/fil/moodle.php
install/lang/fj/admin.php
install/lang/fj/langconfig.php
install/lang/fj/moodle.php
install/lang/fkv/langconfig.php
install/lang/fo/admin.php
install/lang/fo/langconfig.php
install/lang/fo/moodle.php
install/lang/fr/admin.php
install/lang/fr/error.php
install/lang/fr/install.php
install/lang/fr/langconfig.php
install/lang/fr/moodle.php
install/lang/fr_ca/install.php
install/lang/fr_ca/langconfig.php
install/lang/fr_ca/moodle.php
install/lang/fr_incl/langconfig.php
install/lang/fr_wp/langconfig.php
install/lang/ga/error.php
install/lang/ga/langconfig.php
install/lang/ga/moodle.php
install/lang/gd/langconfig.php
install/lang/gd/moodle.php
install/lang/gl/admin.php
install/lang/gl/error.php
install/lang/gl/install.php
install/lang/gl/langconfig.php
install/lang/gl/moodle.php
install/lang/gu/error.php
install/lang/gu/langconfig.php
install/lang/gu/moodle.php
install/lang/ha/langconfig.php
install/lang/hat/admin.php
install/lang/hat/langconfig.php
install/lang/haw/langconfig.php
install/lang/he/admin.php
install/lang/he/error.php
install/lang/he/install.php
install/lang/he/langconfig.php
install/lang/he/moodle.php
install/lang/he_kids/langconfig.php
install/lang/he_wp/admin.php
install/lang/he_wp/langconfig.php
install/lang/hi/admin.php
install/lang/hi/langconfig.php
install/lang/hi/moodle.php
install/lang/hi_kids/langconfig.php
install/lang/hi_wp/langconfig.php
install/lang/hr/admin.php
install/lang/hr/error.php
install/lang/hr/install.php
install/lang/hr/langconfig.php
install/lang/hr/moodle.php
install/lang/hr_schools/langconfig.php
install/lang/hu/admin.php
install/lang/hu/error.php
install/lang/hu/install.php
install/lang/hu/langconfig.php
install/lang/hu/moodle.php
install/lang/hy/admin.php
install/lang/hy/error.php
install/lang/hy/install.php
install/lang/hy/langconfig.php
install/lang/hy/moodle.php
install/lang/id/admin.php
install/lang/id/install.php
install/lang/id/langconfig.php
install/lang/id/moodle.php
install/lang/ig/langconfig.php
install/lang/is/admin.php
install/lang/is/error.php
install/lang/is/install.php
install/lang/is/langconfig.php
install/lang/is/moodle.php
install/lang/it/admin.php
install/lang/it/error.php
install/lang/it/install.php
install/lang/it/langconfig.php
install/lang/it/moodle.php
install/lang/it_wp/langconfig.php
install/lang/ja/admin.php
install/lang/ja/error.php
install/lang/ja/install.php
install/lang/ja/langconfig.php
install/lang/ja/moodle.php
install/lang/ja_kids/langconfig.php
install/lang/ja_wp/langconfig.php
install/lang/ka/admin.php
install/lang/ka/install.php
install/lang/ka/langconfig.php
install/lang/ka/moodle.php
install/lang/kaa/langconfig.php
install/lang/kab/langconfig.php
install/lang/kk/install.php
install/lang/kk/langconfig.php
install/lang/kk/moodle.php
install/lang/kl/langconfig.php
install/lang/kl/moodle.php
install/lang/km/admin.php
install/lang/km/error.php
install/lang/km/install.php
install/lang/km/langconfig.php
install/lang/km/moodle.php
install/lang/kmr/langconfig.php
install/lang/kn/install.php
install/lang/kn/langconfig.php
install/lang/kn/moodle.php
install/lang/ko/admin.php
install/lang/ko/error.php
install/lang/ko/install.php
install/lang/ko/langconfig.php
install/lang/ko/moodle.php
install/lang/ky/langconfig.php
install/lang/ky/moodle.php [new file with mode: 0644]
install/lang/la/langconfig.php
install/lang/la/moodle.php
install/lang/lb/admin.php
install/lang/lb/langconfig.php
install/lang/lo/admin.php
install/lang/lo/install.php
install/lang/lo/langconfig.php
install/lang/lo/moodle.php
install/lang/lt/admin.php
install/lang/lt/error.php
install/lang/lt/install.php
install/lang/lt/langconfig.php
install/lang/lt/moodle.php
install/lang/lt_uni/admin.php
install/lang/lt_uni/error.php
install/lang/lt_uni/install.php
install/lang/lt_uni/langconfig.php
install/lang/lt_uni/moodle.php
install/lang/lv/admin.php
install/lang/lv/error.php
install/lang/lv/install.php
install/lang/lv/langconfig.php
install/lang/lv/moodle.php
install/lang/mg/langconfig.php
install/lang/mh/langconfig.php
install/lang/mi/langconfig.php
install/lang/mi_tn/langconfig.php
install/lang/mi_tn/moodle.php
install/lang/mi_wwow/admin.php
install/lang/mi_wwow/error.php
install/lang/mi_wwow/install.php
install/lang/mi_wwow/langconfig.php
install/lang/mi_wwow/moodle.php
install/lang/mis/langconfig.php
install/lang/mk/admin.php
install/lang/mk/error.php
install/lang/mk/install.php
install/lang/mk/langconfig.php
install/lang/mk/moodle.php
install/lang/ml/langconfig.php
install/lang/ml/moodle.php
install/lang/mn/admin.php
install/lang/mn/error.php
install/lang/mn/install.php
install/lang/mn/langconfig.php
install/lang/mn/moodle.php
install/lang/mn_mong/langconfig.php
install/lang/mr/admin.php
install/lang/mr/error.php
install/lang/mr/install.php
install/lang/mr/langconfig.php
install/lang/mr/moodle.php
install/lang/ms/admin.php
install/lang/ms/install.php
install/lang/ms/langconfig.php
install/lang/ms/moodle.php
install/lang/mwl/langconfig.php
install/lang/my/langconfig.php
install/lang/nb/langconfig.php
install/lang/ne/install.php
install/lang/ne/langconfig.php
install/lang/ne/moodle.php
install/lang/nl/admin.php
install/lang/nl/error.php
install/lang/nl/install.php
install/lang/nl/langconfig.php
install/lang/nl/moodle.php
install/lang/nl_wp/langconfig.php
install/lang/nn/langconfig.php
install/lang/nn/moodle.php
install/lang/no/admin.php
install/lang/no/error.php
install/lang/no/install.php
install/lang/no/langconfig.php
install/lang/no/moodle.php
install/lang/no_gr/langconfig.php
install/lang/no_gr/moodle.php
install/lang/no_wp/langconfig.php
install/lang/oc_es/langconfig.php
install/lang/oc_gsc/admin.php
install/lang/oc_gsc/error.php
install/lang/oc_gsc/install.php
install/lang/oc_gsc/langconfig.php
install/lang/oc_gsc/moodle.php
install/lang/oc_lnc/admin.php
install/lang/oc_lnc/error.php
install/lang/oc_lnc/install.php
install/lang/oc_lnc/langconfig.php
install/lang/oc_lnc/moodle.php
install/lang/om/install.php
install/lang/om/langconfig.php
install/lang/om/moodle.php
install/lang/or/langconfig.php
install/lang/pan/langconfig.php
install/lang/pcm/langconfig.php
install/lang/pl/admin.php
install/lang/pl/error.php
install/lang/pl/install.php
install/lang/pl/langconfig.php
install/lang/pl/moodle.php
install/lang/prs/langconfig.php
install/lang/prs/moodle.php
install/lang/ps/langconfig.php
install/lang/ps/moodle.php
install/lang/pt/admin.php
install/lang/pt/error.php
install/lang/pt/install.php
install/lang/pt/langconfig.php
install/lang/pt/moodle.php
install/lang/pt_br/admin.php
install/lang/pt_br/error.php
install/lang/pt_br/install.php
install/lang/pt_br/langconfig.php
install/lang/pt_br/moodle.php
install/lang/pt_br_wp/langconfig.php
install/lang/rm_surs/admin.php
install/lang/rm_surs/langconfig.php
install/lang/rm_surs/moodle.php
install/lang/ro/admin.php
install/lang/ro/error.php
install/lang/ro/install.php
install/lang/ro/langconfig.php
install/lang/ro/moodle.php
install/lang/ro_wp/admin.php
install/lang/ro_wp/error.php [new file with mode: 0644]
install/lang/ro_wp/install.php [new file with mode: 0644]
install/lang/ro_wp/langconfig.php
install/lang/ro_wp/moodle.php
install/lang/ru/admin.php
install/lang/ru/error.php
install/lang/ru/install.php
install/lang/ru/langconfig.php
install/lang/ru/moodle.php
install/lang/rw/langconfig.php
install/lang/scn/langconfig.php
install/lang/sd_ap/langconfig.php
install/lang/se/error.php
install/lang/se/install.php
install/lang/se/langconfig.php
install/lang/se/moodle.php
install/lang/si/admin.php
install/lang/si/error.php
install/lang/si/install.php
install/lang/si/langconfig.php
install/lang/si/moodle.php
install/lang/sk/admin.php
install/lang/sk/error.php
install/lang/sk/install.php
install/lang/sk/langconfig.php
install/lang/sk/moodle.php
install/lang/sl/admin.php
install/lang/sl/error.php
install/lang/sl/install.php
install/lang/sl/langconfig.php
install/lang/sl/moodle.php
install/lang/sm/install.php
install/lang/sm/langconfig.php
install/lang/sm/moodle.php
install/lang/sma/langconfig.php
install/lang/smj/langconfig.php
install/lang/so/admin.php
install/lang/so/install.php
install/lang/so/langconfig.php
install/lang/so/moodle.php
install/lang/sq/langconfig.php
install/lang/sq/moodle.php
install/lang/sr_cr/admin.php
install/lang/sr_cr/error.php
install/lang/sr_cr/install.php
install/lang/sr_cr/langconfig.php
install/lang/sr_cr/moodle.php
install/lang/sr_lt/admin.php
install/lang/sr_lt/error.php
install/lang/sr_lt/install.php
install/lang/sr_lt/langconfig.php
install/lang/sr_lt/moodle.php
install/lang/sv/admin.php
install/lang/sv/error.php
install/lang/sv/install.php
install/lang/sv/langconfig.php
install/lang/sv/moodle.php
install/lang/sv_fi/install.php
install/lang/sv_fi/langconfig.php
install/lang/sv_fi/moodle.php
install/lang/sw/admin.php
install/lang/sw/langconfig.php
install/lang/sw/moodle.php
install/lang/ta/admin.php
install/lang/ta/error.php
install/lang/ta/install.php
install/lang/ta/langconfig.php
install/lang/ta/moodle.php
install/lang/ta_lk/admin.php
install/lang/ta_lk/error.php
install/lang/ta_lk/install.php
install/lang/ta_lk/langconfig.php
install/lang/ta_lk/moodle.php
install/lang/te/admin.php
install/lang/te/error.php
install/lang/te/install.php
install/lang/te/langconfig.php
install/lang/te/moodle.php
install/lang/tg/admin.php
install/lang/tg/error.php
install/lang/tg/install.php
install/lang/tg/langconfig.php
install/lang/tg/moodle.php
install/lang/th/admin.php
install/lang/th/install.php
install/lang/th/langconfig.php
install/lang/th/moodle.php
install/lang/ti/langconfig.php
install/lang/ti/moodle.php
install/lang/tk/langconfig.php
install/lang/tl/admin.php
install/lang/tl/error.php
install/lang/tl/install.php
install/lang/tl/langconfig.php
install/lang/tl/moodle.php
install/lang/tn/langconfig.php
install/lang/to/install.php
install/lang/to/langconfig.php
install/lang/to/moodle.php
install/lang/tpi/langconfig.php
install/lang/tr/admin.php
install/lang/tr/error.php
install/lang/tr/install.php
install/lang/tr/langconfig.php
install/lang/tr/moodle.php
install/lang/tt/langconfig.php
install/lang/ug_lt/langconfig.php
install/lang/ug_ug/admin.php
install/lang/ug_ug/langconfig.php
install/lang/uk/admin.php
install/lang/uk/error.php
install/lang/uk/install.php
install/lang/uk/langconfig.php
install/lang/uk/moodle.php
install/lang/ur/install.php
install/lang/ur/langconfig.php
install/lang/ur/moodle.php
install/lang/uz/install.php
install/lang/uz/langconfig.php
install/lang/uz/moodle.php
install/lang/vi/admin.php
install/lang/vi/error.php
install/lang/vi/install.php
install/lang/vi/langconfig.php
install/lang/vi/moodle.php
install/lang/wo/langconfig.php
install/lang/xct/langconfig.php
install/lang/zgh/langconfig.php
install/lang/zh_cn/admin.php
install/lang/zh_cn/error.php
install/lang/zh_cn/install.php
install/lang/zh_cn/langconfig.php
install/lang/zh_cn/moodle.php
install/lang/zh_cn_wp/langconfig.php
install/lang/zh_tw/admin.php
install/lang/zh_tw/error.php
install/lang/zh_tw/install.php
install/lang/zh_tw/langconfig.php
install/lang/zh_tw/moodle.php
install/lang/zh_tw_wp/langconfig.php
install/lang/zu/error.php
install/lang/zu/install.php
install/lang/zu/langconfig.php
lang/en/admin.php
lang/en/analytics.php
lang/en/error.php
lang/en/filters.php
lib/adminlib.php
lib/amd/build/addblockmodal.min.js
lib/amd/build/addblockmodal.min.js.map
lib/amd/src/addblockmodal.js
lib/behat/behat_base.php
lib/behat/behat_field_manager.php
lib/behat/classes/behat_session_interface.php [new file with mode: 0644]
lib/behat/classes/behat_session_trait.php [new file with mode: 0644]
lib/behat/classes/partial_named_selector.php
lib/behat/form_field/behat_form_field.php
lib/behat/form_field/behat_form_inplaceeditable.php [new file with mode: 0644]
lib/classes/antivirus/scanner.php
lib/classes/encryption.php [new file with mode: 0644]
lib/classes/session/redis.php
lib/db/services.php
lib/db/upgrade.php
lib/deprecatedlib.php
lib/editor/atto/tests/behat/disablecontrol.feature
lib/editor/textarea/tests/behat/disablecontrol.feature
lib/form/amd/build/encryptedpassword.min.js [new file with mode: 0644]
lib/form/amd/build/encryptedpassword.min.js.map [new file with mode: 0644]
lib/form/amd/src/encryptedpassword.js [new file with mode: 0644]
lib/html2text/Html2Text.php
lib/html2text/readme_moodle.txt
lib/moodlelib.php
lib/myprofilelib.php
lib/navigationlib.php
lib/simplepie/LICENSE.txt
lib/simplepie/README.markdown
lib/simplepie/autoloader.php
lib/simplepie/library/SimplePie.php
lib/simplepie/library/SimplePie/Author.php
lib/simplepie/library/SimplePie/Cache.php
lib/simplepie/library/SimplePie/Cache/Base.php
lib/simplepie/library/SimplePie/Cache/DB.php
lib/simplepie/library/SimplePie/Cache/File.php
lib/simplepie/library/SimplePie/Cache/Memcache.php
lib/simplepie/library/SimplePie/Cache/Memcached.php
lib/simplepie/library/SimplePie/Cache/MySQL.php
lib/simplepie/library/SimplePie/Caption.php
lib/simplepie/library/SimplePie/Category.php
lib/simplepie/library/SimplePie/Content/Type/Sniffer.php
lib/simplepie/library/SimplePie/Copyright.php
lib/simplepie/library/SimplePie/Core.php
lib/simplepie/library/SimplePie/Credit.php
lib/simplepie/library/SimplePie/Decode/HTML/Entities.php
lib/simplepie/library/SimplePie/Enclosure.php
lib/simplepie/library/SimplePie/Exception.php
lib/simplepie/library/SimplePie/File.php
lib/simplepie/library/SimplePie/HTTP/Parser.php
lib/simplepie/library/SimplePie/IRI.php
lib/simplepie/library/SimplePie/Item.php
lib/simplepie/library/SimplePie/Locator.php
lib/simplepie/library/SimplePie/Misc.php
lib/simplepie/library/SimplePie/Net/IPv6.php
lib/simplepie/library/SimplePie/Parse/Date.php
lib/simplepie/library/SimplePie/Parser.php
lib/simplepie/library/SimplePie/Rating.php
lib/simplepie/library/SimplePie/Registry.php
lib/simplepie/library/SimplePie/Restriction.php
lib/simplepie/library/SimplePie/Sanitize.php
lib/simplepie/library/SimplePie/Source.php
lib/simplepie/library/SimplePie/XML/Declaration/Parser.php
lib/simplepie/library/SimplePie/gzdecode.php
lib/simplepie/readme_moodle.txt
lib/table/classes/local/filter/filter.php
lib/table/classes/local/filter/filterset.php
lib/templates/add_block_body.mustache
lib/templates/settings_link_page.mustache
lib/tests/behat/behat_deprecated.php
lib/tests/behat/behat_general.php
lib/tests/encryption_test.php [new file with mode: 0644]
lib/tests/fixtures/testable_encryption.php [new file with mode: 0644]
lib/tests/session_redis_test.php
lib/thirdpartylibs.xml
lib/upgrade.txt
message/amd/build/message_drawer.min.js
message/amd/build/message_drawer.min.js.map
message/amd/src/message_drawer.js
message/classes/api.php
message/templates/message_drawer.mustache
message/templates/message_drawer_view_contacts_header.mustache
message/templates/message_drawer_view_conversation_header.mustache
message/templates/message_drawer_view_overview_header.mustache
message/templates/message_drawer_view_search_header.mustache
message/templates/message_drawer_view_settings_header.mustache
message/tests/api_test.php
message/tests/externallib_test.php
mod/assign/module.js
mod/book/tests/behat/edit_tags.feature
mod/book/tool/print/locallib.php
mod/book/upgrade.txt
mod/forum/classes/local/exporters/post.php
mod/forum/tests/behat/advanced_search.feature
mod/forum/tests/externallib_test.php
mod/forum/upgrade.txt
mod/h5pactivity/classes/local/manager.php
mod/lti/locallib.php
mod/lti/tests/behat/renametool.feature
mod/quiz/tests/behat/behat_mod_quiz.php
mod/quiz/tests/behat/editing_set_marks_no_attempts.feature
payment/classes/external/get_available_gateways.php
payment/gateway/paypal/db/install.php
payment/templates/gateway.mustache
question/tests/backup_test.php
question/type/ddimageortext/amd/build/form.min.js
question/type/ddimageortext/amd/build/form.min.js.map
question/type/ddimageortext/amd/src/form.js
question/type/ddimageortext/styles.css
question/type/essay/renderer.php
question/type/essay/tests/behat/max_file_size.feature
search/classes/manager.php
search/tests/manager_test.php
tag/tests/behat/collections.feature
tag/tests/behat/edit_tag.feature
theme/boost/amd/build/aria.min.js
theme/boost/amd/build/aria.min.js.map
theme/boost/amd/build/loader.min.js
theme/boost/amd/build/loader.min.js.map
theme/boost/amd/src/aria.js
theme/boost/amd/src/loader.js
theme/boost/scss/moodle/drawer.scss
theme/boost/style/moodle.css
theme/boost/templates/admin_setting_tabs.mustache
theme/classic/style/moodle.css
user/action_redir.php
user/amd/build/participantsfilter.min.js
user/amd/build/participantsfilter.min.js.map
user/amd/src/participantsfilter.js
user/filters/lib.php
user/filters/user_filter_forms.php
user/templates/participantsfilter.mustache
user/tests/behat/filter_participants.feature
user/view.php
version.php

diff --git a/.github/workflows/config-template.php b/.github/workflows/config-template.php
new file mode 100644 (file)
index 0000000..dc5f958
--- /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/>.
+
+/**
+ * Template configuraton file for github actions CI/CD.
+ *
+ * @package    core
+ * @copyright  2020 onwards Eloy Lafuente (stronk7) {@link https://stronk7.com}
+ * @license    https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+// This cannot be used out from a github actions workflow, so just exit.
+getenv('GITHUB_WORKFLOW') || die; // phpcs:ignore moodle.Files.MoodleInternal.MoodleInternalGlobalState
+
+unset($CFG);
+global $CFG;
+$CFG = new stdClass();
+
+$CFG->dbtype    = getenv('dbtype');
+$CFG->dblibrary = 'native';
+$CFG->dbhost    = '127.0.0.1';
+$CFG->dbname    = 'test';
+$CFG->dbuser    = 'test';
+$CFG->dbpass    = 'test';
+$CFG->prefix    = 'm_';
+$CFG->dboptions = ['dbcollation' => 'utf8mb4_bin'];
+
+$host = 'localhost';
+$CFG->wwwroot   = "http://{$host}";
+$CFG->dataroot  = realpath(dirname(__DIR__)) . '/moodledata';
+$CFG->admin     = 'admin';
+$CFG->directorypermissions = 0777;
+
+// Debug options - possible to be controlled by flag in future.
+$CFG->debug = (E_ALL | E_STRICT); // DEBUG_DEVELOPER.
+$CFG->debugdisplay = 1;
+$CFG->debugstringids = 1; // Add strings=1 to url to get string ids.
+$CFG->perfdebug = 15;
+$CFG->debugpageinfo = 1;
+$CFG->allowthemechangeonurl = 1;
+$CFG->passwordpolicy = 0;
+$CFG->cronclionly = 0;
+$CFG->pathtophp = getenv('pathtophp');
+
+$CFG->phpunit_dataroot  = realpath(dirname(__DIR__)) . '/phpunitdata';
+$CFG->phpunit_prefix = 't_';
+
+define('TEST_EXTERNAL_FILES_HTTP_URL', 'http://localhost:8080');
+define('TEST_EXTERNAL_FILES_HTTPS_URL', 'http://localhost:8080');
+
+define('TEST_SESSION_REDIS_HOST', 'localhost');
+define('TEST_CACHESTORE_REDIS_TESTSERVERS', 'localhost');
+
+// TODO: add others (solr, mongodb, memcached, ldap...).
+
+// Too much for now: define('PHPUNIT_LONGTEST', true); // Only leaves a few tests out and they are run later by CI.
+
+require_once(__DIR__ . '/lib/setup.php');
diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
new file mode 100644 (file)
index 0000000..f063803
--- /dev/null
@@ -0,0 +1,103 @@
+name: Core
+
+on: [push]
+
+env:
+  php: 7.4
+
+jobs:
+  Grunt:
+    runs-on: ubuntu-18.04
+
+    steps:
+      - name: Checking out code
+        uses: actions/checkout@v2
+
+      - name: Configuring node & npm
+        shell: bash -l {0}
+        run: nvm install
+
+      - name: Installing node stuff
+        run: npm install
+
+      - name: Running grunt
+        run: npx grunt
+
+      - name: Looking for uncommitted changes
+        # Add all files to the git index and then run diff --cached to see all changes.
+        # This ensures that we get the status of all files, including new files.
+        # We ignore npm-shrinkwrap.json to make the tasks immune to npm changes.
+        run: |
+          git add .
+          git reset -- npm-shrinkwrap.json
+          git diff --cached --exit-code
+
+  PHPUnit:
+    runs-on: ${{ matrix.os }}
+    services:
+      exttests:
+        image: moodlehq/moodle-exttests
+        ports:
+          - 8080:80
+      redis:
+        image: redis
+        ports:
+          - 6379:6379
+    strategy:
+      fail-fast: false
+      matrix:
+        include:
+          - os: ubuntu-18.04
+            php: 7.2
+            db: mysqli
+          - os: ubuntu-18.04
+            php: 7.4
+            db: pgsql
+
+    steps:
+      - name: Setting up DB mysql
+        if: ${{ matrix.db == 'mysqli' }}
+        uses: johanmeiring/mysql-action@tmpfs-patch
+        with:
+          collation server: utf8mb4_bin
+          mysql version: 5.7
+          mysql database: test
+          mysql user: test
+          mysql password: test
+          use tmpfs: true
+
+      - name: Setting up DB pgsql
+        if: ${{ matrix.db == 'pgsql' }}
+        uses: m4nu56/postgresql-action@v1
+        with:
+          postgresql version: 9.6
+          postgresql db: test
+          postgresql user: test
+          postgresql password: test
+
+      - name: Configuring git vars
+        uses: rlespinasse/github-slug-action@v3.x
+
+      - name: Setting up PHP ${{ matrix.php }}
+        uses: shivammathur/setup-php@v2
+        with:
+          php-version: ${{ matrix.php }}
+          coverage: none
+
+      - name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
+        uses: actions/checkout@v2
+
+      - name: Setting up PHPUnit
+        env:
+          dbtype: ${{ matrix.db }}
+        run: |
+          echo "pathtophp=$(which php)" >> $GITHUB_ENV # Inject installed pathtophp to env. The template config needs it.
+          cp .github/workflows/config-template.php config.php
+          mkdir ../moodledata
+          sudo locale-gen en_AU.UTF-8
+          php admin/tool/phpunit/cli/init.php --no-composer-self-update
+
+      - name: Running PHPUnit tests
+        env:
+          dbtype: ${{ matrix.db }}
+        run: vendor/bin/phpunit -v
index 7b533fe..89acef8 100644 (file)
@@ -16,31 +16,9 @@ services:
     - mysql
     - docker
 
-php:
-    # We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
-    - 7.4
-    - 7.2
-
 addons:
   postgresql: "9.6"
 
-env:
-    # Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
-    # start first so that the total run time is not too high.
-    #
-    # We only run MySQL on PHP 7.2, so run that first.
-    # CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
-    # Postgres is significantly is pretty reasonable in its run-time.
-
-    # Run CI Tests without running PHPUnit.
-    - DB=none     TASK=CITEST
-
-    # Run unit tests on Postgres
-    - DB=pgsql    TASK=PHPUNIT
-
-    # Perform an upgrade test too.
-    - DB=pgsql    TASK=UPGRADE
-
 jobs:
     # Enable fast finish.
     # This will fail the build if a single job fails (except those in allow_failures).
@@ -48,12 +26,35 @@ jobs:
     fast_finish: true
 
     include:
-          # Run mysql only on highest - it's just too slow
-        - php: 7.4
+        # First all the lowest php ones (7.2)
+        - php: 7.2
+          env: DB=none     TASK=CITEST
+        - php: 7.2
+          env: DB=none     TASK=GRUNT    NVM_VERSION='lts/carbon'
+
+        - if: env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present
+          php: 7.2
+          env: DB=pgsql    TASK=PHPUNIT
+
+        - if: env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all"
+          php: 7.2
+          env: DB=mysqli   TASK=PHPUNIT
+
+        # Then, conditionally, all the highest php ones (7.4)
+        - if: env(MOODLE_PHP) = "all"
+          php: 7.4
+          env: DB=none     TASK=CITEST
+        - if: env(MOODLE_PHP) = "all"
+          php: 7.4
+          env: DB=none     TASK=GRUNT    NVM_VERSION='lts/carbon'
+
+        - if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "pgsql" OR env(MOODLE_DATABASE) = "all" OR env(MOODLE_DATABASE) IS NOT present)
+          php: 7.4
+          env: DB=pgsql    TASK=PHPUNIT
+
+        - if: env(MOODLE_PHP) = "all" AND (env(MOODLE_DATABASE) = "mysqli" OR env(MOODLE_DATABASE) = "all")
+          php: 7.4
           env: DB=mysqli   TASK=PHPUNIT
-          # Run grunt/npm install on highest version too ('node' is an alias for the latest node.js version.)
-        - php: 7.4
-          env: DB=none     TASK=GRUNT   NVM_VERSION='lts/carbon'
 
 cache:
     directories:
@@ -113,7 +114,7 @@ install:
 before_script:
     - phpenv config-rm xdebug.ini
     - >
-      if [ "$TASK" = 'PHPUNIT' -o "$TASK" = 'UPGRADE' ];
+      if [ "$TASK" = 'PHPUNIT' ];
       then
         # Copy generic configuration in place.
         cp config-dist.php config.php ;
@@ -224,32 +225,6 @@ before_script:
         export phpcmd=`which php`;
       fi
 
-    ########################################################################
-    # Upgrade test
-    ########################################################################
-    - >
-      if [ "$TASK" = 'UPGRADE' ];
-      then
-        # We need the official upstream.
-        git remote add upstream https://github.com/moodle/moodle.git;
-
-        # 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;
-
-        # Return to the previous commit
-        git checkout -;
-
-        # Perform the upgrade
-        php admin/cli/upgrade.php --non-interactive --allow-unstable ;
-
-        # The local_ci repository can be used to check upgrade savepoints.
-        git clone https://github.com/moodlehq/moodle-local_ci.git local/ci ;
-      fi
-
 script:
     - >
       if [ "$TASK" = 'PHPUNIT' ];
@@ -275,23 +250,6 @@ script:
         git diff --cached --exit-code ;
       fi
 
-    ########################################################################
-    # Upgrade test
-    ########################################################################
-    - >
-      if [ "$TASK" = 'UPGRADE' ];
-      then
-        cp local/ci/check_upgrade_savepoints/check_upgrade_savepoints.php ./check_upgrade_savepoints.php
-        result=`php check_upgrade_savepoints.php`;
-        # Check if there are problems
-        count=`echo "$result" | grep -P "ERROR|WARN" | wc -l` ;
-        if (($count > 0));
-        then
-          echo "$result"
-          exit 1 ;
-        fi
-      fi
-
 after_script:
     - >
       if [ "$TASK" = 'PHPUNIT' ];
diff --git a/admin/cli/generate_key.php b/admin/cli/generate_key.php
new file mode 100644 (file)
index 0000000..28fd0af
--- /dev/null
@@ -0,0 +1,77 @@
+<?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/>.
+
+/**
+ * Generates a secure key for the current server (presuming it does not already exist).
+ *
+ * @package core_admin
+ * @copyright 2020 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+use \core\encryption;
+
+define('CLI_SCRIPT', true);
+
+require(__DIR__ . '/../../config.php');
+require_once($CFG->libdir . '/clilib.php');
+
+// Get cli options.
+[$options, $unrecognized] = cli_get_params(
+        ['help' => false, 'method' => null],
+        ['h' => 'help']);
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+if ($options['help']) {
+    echo "Generate secure key
+
+This script manually creates a secure key within the secret data root folder (configured in
+config.php as \$CFG->secretdataroot). You must run it using an account with access to write
+to that folder.
+
+In normal use Moodle automatically creates the key; this script is intended when setting up
+a new Moodle system, for cases where the secure folder is not on shared storage and the key
+may be manually installed on multiple servers.
+
+Options:
+-h, --help         Print out this help
+--method <method>  Generate key for specified encryption method instead of default.
+                   * sodium
+                   * openssl-aes-256-ctr
+
+Example:
+php admin/cli/generate_key.php
+";
+    exit;
+}
+
+$method = $options['method'];
+
+if (encryption::key_exists($method)) {
+    echo 'Key already exists: ' . encryption::get_key_file($method) . "\n";
+    exit;
+}
+
+// Creates key with default permissions (no chmod).
+echo "Generating key...\n";
+encryption::create_key($method, false);
+
+echo "\nKey created: " . encryption::get_key_file($method) . "\n\n";
+echo "If the key folder is not shared storage, then key files should be copied to all servers.\n";
index 30b6a22..1bf0cb3 100644 (file)
@@ -144,5 +144,20 @@ if ($hassiteconfig && \core_analytics\manager::is_analytics_enabled()) {
         $settings->add(new admin_setting_configduration('analytics/modeltimelimit', new lang_string('modeltimelimit', 'analytics'),
             new lang_string('modeltimelimitinfo', 'analytics'), 20 * MINSECS));
 
+        $options = array(
+            0    => new lang_string('neverdelete', 'analytics'),
+            1000 => new lang_string('numdays', '', 1000),
+            365  => new lang_string('numdays', '', 365),
+            180  => new lang_string('numdays', '', 180),
+            150  => new lang_string('numdays', '', 150),
+            120  => new lang_string('numdays', '', 120),
+            90   => new lang_string('numdays', '', 90),
+            60   => new lang_string('numdays', '', 60),
+            35   => new lang_string('numdays', '', 35));
+        $settings->add(new admin_setting_configselect('analytics/calclifetime',
+            new lang_string('calclifetime', 'analytics'),
+            new lang_string('configlcalclifetime', 'analytics'), 35, $options));
+
+
     }
 }
diff --git a/admin/templates/setting_encryptedpassword.mustache b/admin/templates/setting_encryptedpassword.mustache
new file mode 100644 (file)
index 0000000..e2a98cf
--- /dev/null
@@ -0,0 +1,64 @@
+{{!
+    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 core_admin/admin_setting_encryptedpassword
+
+    Admin encrypted password template.
+
+    Context variables required for this template:
+    * name - form element name
+    * set - whether it is set or empty
+    * id - element id
+
+    Example context (json):
+    {
+        "name": "test",
+        "id": "test0",
+        "set": true
+    }
+}}
+<div class="core_admin_encryptedpassword" data-encryptedpasswordid="{{ id }}"
+        {{#novalue}}data-novalue="y"{{/novalue}}>
+    {{#set}}
+        <span>{{# str }} encryptedpassword_set, admin {{/ str }}</span>
+    {{/set}}
+    {{^set}}
+        <a href="#" title="{{# str }} encryptedpassword_edit, admin {{/ str }}">
+            <span>{{# str }} novalueclicktoset, form {{/ str }}</span>
+            {{# pix }} t/passwordunmask-edit, core, {{# str }} passwordunmaskedithint, form {{/ str }}{{/ pix }}
+        </a>
+    {{/set}}
+    <input style="display: none" type="password" name="{{name}}" disabled>
+    {{!
+        Using buttons instead of links here allows them to be connected to the label, so the button
+        works if you click the label.
+    }}
+    {{#set}}
+        <button type="button" id="{{id}}" title="{{# str }} encryptedpassword_edit, admin {{/ str }}" class="btn btn-link" data-editbutton>
+            {{# pix }} t/passwordunmask-edit, core, {{/ pix }}
+        </button>
+    {{/set}}
+    <button type="button" style="display: none" title="{{# str }} cancel {{/ str }}" class="btn btn-link" data-cancelbutton>
+        <i class="icon fa fa-times"></i>
+    </button>
+</div>
+
+{{#js}}
+require(['core_form/encryptedpassword'], function(encryptedpassword) {
+    new encryptedpassword.EncryptedPassword("{{ id }}");
+});
+{{/js}}
index 98f5d91..d71af45 100644 (file)
@@ -89,7 +89,7 @@ class behat_admin extends behat_base {
     }
 
     /**
-     * Sets the specified site settings. A table with | config | value | (optional)plugin | is expected.
+     * Sets the specified site settings. A table with | config | value | (optional)plugin | (optional)encrypted | is expected.
      *
      * @Given /^the following config values are set as admin:$/
      * @param TableNode $table
@@ -103,11 +103,20 @@ class behat_admin extends behat_base {
         foreach ($data as $config => $value) {
             // Default plugin value is null.
             $plugin = null;
+            $encrypted = false;
 
             if (is_array($value)) {
                 $plugin = $value[1];
+                if (array_key_exists(2, $value)) {
+                    $encrypted = $value[2] === 'encrypted';
+                }
                 $value = $value[0];
             }
+
+            if ($encrypted) {
+                $value = \core\encryption::encrypt($value);
+            }
+
             set_config($config, $value, $plugin);
         }
     }
diff --git a/admin/tool/behat/tests/behat/inplaceeditable.feature b/admin/tool/behat/tests/behat/inplaceeditable.feature
new file mode 100644 (file)
index 0000000..014c5f5
--- /dev/null
@@ -0,0 +1,30 @@
+@tool_behat
+Feature: Verify that the inplace editable field works as expected
+  In order to use behat step definitions
+  As a test write
+  I need to ensure that the inplace editable works in forms
+
+  Background:
+    Given the following "course" exists:
+      | fullname  | Course 1 |
+      | shortname | C1       |
+    And the following "activities" exist:
+      | activity | course | name                | idnumber |
+      | forum    | C1     | My first forum      | forum1   |
+      | assign   | C1     | My first assignment | assign1  |
+      | quiz     | C1     | My first quiz       | quiz1    |
+    And I log in as "admin"
+    And I am on "Course 1" course homepage with editing mode on
+
+  @javascript
+  Scenario: Using an inplace editable updates the name of an activity
+    When I set the field "Edit title" in the "My first assignment" "activity" to "Coursework submission"
+    Then I should see "Coursework submission"
+    And I should not see "My first assignment"
+    But I should see "My first forum"
+    And I should see "My first quiz"
+    And I set the field "Edit title" in the "Coursework submission" "activity" to "My first assignment"
+    And I should not see "Coursework submission"
+    But I should see "My first assignment"
+    And I should see "My first forum"
+    And I should see "My first quiz"
index ca9a74f..cdcb081 100644 (file)
@@ -28,15 +28,16 @@ Feature: Verify that keyboard steps work as expected
     And I press the shift tab key
     And the focused element is "Username" "field"
 
-  @javascript
-  Scenario: Using the arrow keys allows me to navigate through menus
-    Given the following "users" exist:
-      | username | email                        | firstname | lastname |
-      | saffronr | saffron.rutledge@example.com | Saffron   | Rutledge |
-    And I log in as "saffronr"
-    And I click on "Saffron Rutledge" "link" in the ".usermenu" "css_element"
-    When I press the up key
-    Then the focused element is "Log out" "link"
+#  TODO: Uncomment the following when MDL-66979 is integrated.
+#  @javascript
+#  Scenario: Using the arrow keys allows me to navigate through menus
+#    Given the following "users" exist:
+#      | username | email                        | firstname | lastname |
+#      | saffronr | saffron.rutledge@example.com | Saffron   | Rutledge |
+#    And I log in as "saffronr"
+#    And I click on "Saffron Rutledge" "link" in the ".usermenu" "css_element"
+#    When I press the up key
+#    Then the focused element is "Log out" "link"
 
   @javascript
   Scenario: The escape key can be used to close a dialogue
index d3adb18..c3ab30f 100644 (file)
@@ -1,5 +1,10 @@
 This files describes API changes in /admin/*.
 
+=== 3.11 ===
+
+* New admin setting admin_setting_encryptedpassword allows passwords in admin settings to be
+  encrypted (with the new \core\encryption API) so that even the admin cannot read them.
+
 === 3.9 ===
 
 * The following functions, previously used (exclusively) by upgrade steps are not available anymore because of the upgrade cleanup performed for this version. See MDL-65809 for more info:
index 054a07a..4216bbe 100644 (file)
@@ -300,18 +300,12 @@ class manager {
     }
 
     /**
-     * Returns the enabled time splitting methods.
-     *
-     * @deprecated since Moodle 3.7
-     * @todo MDL-65086 This will be deleted in Moodle 3.11
-     * @see \core_analytics\manager::get_time_splitting_methods_for_evaluation
-     * @return \core_analytics\local\time_splitting\base[]
+     * @deprecated since Moodle 3.7 use get_time_splitting_methods_for_evaluation instead
      */
     public static function get_enabled_time_splitting_methods() {
-        debugging('This function has been deprecated. You can use self::get_time_splitting_methods_for_evaluation if ' .
+        throw new coding_exception(__FUNCTION__ . '() has been removed. You can use self::get_time_splitting_methods_for_evaluation if ' .
             'you want to get the default time splitting methods for evaluation, or you can use self::get_all_time_splittings if ' .
             'you want to get all the time splitting methods available on this site.');
-        return self::get_time_splitting_methods_for_evaluation();
     }
 
     /**
@@ -609,8 +603,8 @@ class manager {
      */
     public static function add_builtin_models() {
 
-        debugging('core_analytics\manager::add_builtin_models() has been deprecated. Core models are now automatically '.
-            'updated according to their declaration in the lib/db/analytics.php file.', DEBUG_DEVELOPER);
+        throw new \coding_exception('core_analytics\manager::add_builtin_models() has been removed. Core models ' .
+                        'are now automatically updated according to their declaration in the lib/db/analytics.php file.');
     }
 
     /**
@@ -694,6 +688,13 @@ class manager {
                     $param + $idsparams);
             }
         }
+
+        // Clean up calculations table.
+        $calclifetime = get_config('analytics', 'calclifetime');
+        if (!empty($calclifetime)) {
+            $lifetime = time() - ($calclifetime * DAYSECS); // Value in days.
+            $DB->delete_records_select('analytics_indicator_calc', 'timecreated < ?', [$lifetime]);
+        }
     }
 
     /**
index 4773d4a..ff24228 100644 (file)
@@ -1,6 +1,14 @@
 This files describes API changes in analytics sub system,
 information provided here is intended especially for developers.
 
+=== 3.11 ===
+* Final deprecation get_enabled_time_splitting_methods. Method has been removed. Use
+  get_time_splitting_methods_for_evaluation instead.
+* Final deprecation add_builtin_models. Method has been removed. The functionality
+  has been replaced with automatic update of models provided by the core moodle component.
+  There is no need to call this method explicitly any more. Instead, adding new models can be achieved
+  by updating the lib/db/analytics.php file and bumping the core version.
+
 === 3.8 ===
 
 * "Time-splitting method" have been replaced by "Analysis interval" for the language strings that are
index 5a9d7e8..9abb2a3 100644 (file)
@@ -27,6 +27,9 @@ require_once('../../config.php');
 $issuerid = required_param('id', PARAM_INT);
 $wantsurl = new moodle_url(optional_param('wantsurl', '', PARAM_URL));
 
+$PAGE->set_context(context_system::instance());
+$PAGE->set_url(new moodle_url('/auth/oauth2/login.php', ['id' => $issuerid]));
+
 require_sesskey();
 
 if (!\auth_oauth2\api::is_enabled()) {
diff --git a/blocks/classes/external/fetch_addable_blocks.php b/blocks/classes/external/fetch_addable_blocks.php
new file mode 100644 (file)
index 0000000..3e14ae5
--- /dev/null
@@ -0,0 +1,118 @@
+<?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 is the external method used for fetching the addable blocks in a given page.
+ *
+ * @package    core_block
+ * @since      Moodle 3.11
+ * @copyright  2020 Mihail Geshoski <mihail@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_block\external;
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir . '/externallib.php');
+
+use external_api;
+use external_function_parameters;
+use external_multiple_structure;
+use external_single_structure;
+use external_value;
+
+/**
+ * This is the external method used for fetching the addable blocks in a given page.
+ *
+ * @copyright  2020 Mihail Geshoski <mihail@moodle.com>
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class fetch_addable_blocks extends external_api {
+
+    /**
+     * Describes the parameters for execute.
+     *
+     * @return external_function_parameters
+     */
+    public static function execute_parameters(): external_function_parameters {
+        return new external_function_parameters(
+            [
+                'pagecontextid' => new external_value(PARAM_INT, 'The context ID of the page.'),
+                'pagetype' => new external_value(PARAM_ALPHAEXT, 'The type of the page.'),
+                'pagelayout' => new external_value(PARAM_ALPHA, 'The layout of the page.')
+            ]
+        );
+    }
+
+    /**
+     * Fetch the addable blocks in a given page.
+     *
+     * @param int $pagecontextid The context ID of the page
+     * @param string $pagetype The type of the page
+     * @param string $pagelayout The layout of the page
+     * @return array The blocks list
+     */
+    public static function execute(int $pagecontextid, string $pagetype, string $pagelayout): array {
+        global $PAGE;
+
+        $params = self::validate_parameters(self::execute_parameters(),
+            [
+                'pagecontextid' => $pagecontextid,
+                'pagetype' => $pagetype,
+                'pagelayout' => $pagelayout
+            ]
+        );
+
+        $context = \context::instance_by_id($params['pagecontextid']);
+        // Validate the context. This will also set the context in $PAGE.
+        self::validate_context($context);
+
+        // We need to manually set the page layout and page type.
+        $PAGE->set_pagelayout($params['pagelayout']);
+        $PAGE->set_pagetype($params['pagetype']);
+        // Firstly, we need to load all currently existing page blocks to later determine which blocks are addable.
+        $PAGE->blocks->load_blocks(false);
+        $PAGE->blocks->create_all_block_instances();
+
+        $addableblocks = $PAGE->blocks->get_addable_blocks();
+
+        return array_map(function($block) {
+            return [
+                'name' => $block->name,
+                'title' => get_string('pluginname', "block_{$block->name}")
+            ];
+        }, $addableblocks);
+    }
+
+    /**
+     * Describes the execute return value.
+     *
+     * @return external_multiple_structure
+     */
+    public static function execute_returns(): external_multiple_structure {
+        return new external_multiple_structure(
+            new external_single_structure(
+                [
+                    'name' => new external_value(PARAM_PLUGIN, 'The name of the block.'),
+                    'title' => new external_value(PARAM_RAW, 'The title of the block.'),
+                ]
+            ),
+            'List of addable blocks in a given page.'
+        );
+    }
+}
index 6c638ea..f7e555e 100644 (file)
@@ -105,6 +105,9 @@ class block_section_links extends block_base {
             }
         }
 
+        // Whether or not section name should be displayed.
+        $showsectionname = !empty($config->showsectionname) ? true : false;
+
         // Prepare an array of sections to create links for.
         $sections = array();
         $canviewhidden = has_capability('moodle/course:update', $context);
@@ -126,13 +129,17 @@ class block_section_links extends block_base {
                     $sections[$i]->highlight = true;
                     $sectiontojumpto = $section->section;
                 }
+                if ($showsectionname) {
+                    $sections[$i]->name = $courseformat->get_section_name($i);
+                }
             }
         }
 
         if (!empty($sections)) {
             // Render the sections.
             $renderer = $this->page->get_renderer('block_section_links');
-            $this->content->text = $renderer->render_section_links($this->page->course, $sections, $sectiontojumpto);
+            $this->content->text = $renderer->render_section_links($this->page->course, $sections,
+                $sectiontojumpto, $showsectionname);
         }
 
         return $this->content;
index 63a3593..3cedaf0 100644 (file)
@@ -82,5 +82,8 @@ class block_section_links_edit_form extends block_edit_form {
             $mform->addHelpButton('config_incby'.$i, 'incby'.$i, 'block_section_links');
         }
 
+        $mform->addElement('selectyesno', 'config_showsectionname', get_string('showsectionname', 'block_section_links'));
+        $mform->setDefault('config_showsectionname', !empty($config->showsectionname) ? 1 : 0);
+        $mform->addHelpButton('config_showsectionname', 'showsectionname', 'block_section_links');
     }
 }
\ No newline at end of file
index b267898..950a0bb 100644 (file)
@@ -34,6 +34,8 @@ $string['numsections2'] = 'Alternative number of sections';
 $string['numsections2_help'] = 'Once the number of sections in the course reaches this number then the Alternative increment by value is used.';
 $string['pluginname'] = 'Section links';
 $string['section_links:addinstance'] = 'Add a new section links block';
+$string['showsectionname'] = 'Display section name';
+$string['showsectionname_help'] = 'Display section name in addition to section number';
 $string['topics'] = 'Topics';
 $string['weeks'] = 'Weeks';
 $string['privacy:metadata'] = 'The Section links block only shows data stored in other locations.';
index 338855b..a1ebe87 100644 (file)
@@ -38,10 +38,12 @@ class block_section_links_renderer extends plugin_renderer_base {
      * @param stdClass $course The course we are rendering for.
      * @param array $sections An array of section objects to render.
      * @param bool|int The section to provide a jump to link for.
+     * @param bool $showsectionname Whether or not section name should be displayed.
      * @return string The HTML to display.
      */
-    public function render_section_links(stdClass $course, array $sections, $jumptosection = false) {
-        $html = html_writer::start_tag('ol', array('class' => 'inline-list'));
+    public function render_section_links(stdClass $course, array $sections, $jumptosection = false, $showsectionname = false) {
+        $olparams = $showsectionname ? ['class' => 'unlist'] : ['class' => 'inline-list'];
+        $html = html_writer::start_tag('ol', $olparams);
         foreach ($sections as $section) {
             $attributes = array();
             if (!$section->visible) {
@@ -49,6 +51,9 @@ class block_section_links_renderer extends plugin_renderer_base {
             }
             $html .= html_writer::start_tag('li');
             $sectiontext = $section->section;
+            if ($showsectionname) {
+                $sectiontext .= ': ' . $section->name;
+            }
             if ($section->highlight) {
                 $sectiontext = html_writer::tag('strong', $sectiontext);
             }
index 2fcb4a4..ef18237 100644 (file)
@@ -48,4 +48,9 @@ if ($ADMIN->fulltree) {
                             get_string('incby'.$i.'_help', 'block_section_links'),
                             $selected[$i][1], $increments));
     }
+
+    $settings->add(new admin_setting_configcheckbox('block_section_links/showsectionname',
+        get_string('showsectionname', 'block_section_links'),
+        get_string('showsectionname_help', 'block_section_links'),
+        0));
 }
\ No newline at end of file
diff --git a/blocks/section_links/tests/behat/show_section_name.feature b/blocks/section_links/tests/behat/show_section_name.feature
new file mode 100644 (file)
index 0000000..8c0b713
--- /dev/null
@@ -0,0 +1,43 @@
+@block @block_section_links
+Feature: The Section links block can be configured to display section name in addition to section number
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname | category | numsections | coursedisplay |
+      | Course 1 | C1        | 0        | 10          | 1             |
+    And the following "activities" exist:
+      | activity | name              | course | idnumber | section |
+      | assign   | First assignment  | C1     | assign1  | 7       |
+    And the following "users" exist:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher   | 1        | teacher1@example.com |
+      | student1 | Student   | 1        | student1@example.com |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+    And I log in as "admin"
+    And I set the following administration settings values:
+      | showsectionname | 1 |
+    And I am on "Course 1" course homepage with editing mode on
+    And I add the "Section links" block
+    And I log out
+
+  Scenario: Student can see section name under the Section links block
+    Given I log in as "student1"
+    When I am on "Course 1" course homepage
+    Then I should see "7: Topic 7" in the "Section links" "block"
+    And I follow "7: Topic 7"
+    And I should see "First assignment"
+
+  Scenario: Teacher can configure existing Section links block to display section number or section name
+    Given I log in as "teacher1"
+    And I am on "Course 1" course homepage with editing mode on
+    When I configure the "Section links" block
+    And I set the following fields to these values:
+      | Display section name | No |
+    And I click on "Save changes" "button"
+    Then I should not see "7: Topic 7" in the "Section links" "block"
+    And I should see "7" in the "Section links" "block"
+    And I follow "7"
+    And I should see "First assignment"
diff --git a/blocks/section_links/upgrade.txt b/blocks/section_links/upgrade.txt
new file mode 100644 (file)
index 0000000..bf4f9a4
--- /dev/null
@@ -0,0 +1,6 @@
+This file describes API changes in the section_links block code.
+
+=== 3.11 ===
+
+* New optional parameter $showsectionname has been added to render_section_links(). Setting this to true will display
+  section name in addition to section number.
index 96451a2..dd45489 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2021052500;        // The current plugin version (Date: YYYYMMDDXX)
+$plugin->version   = 2021052501;        // The current plugin version (Date: YYYYMMDDXX).
 $plugin->requires  = 2021052500;        // Requires this Moodle version
 $plugin->component = 'block_section_links'; // Full name of the plugin (used for diagnostics)
index b80713c..f99f479 100644 (file)
@@ -150,4 +150,17 @@ class behat_block_site_main_menu extends behat_base {
         $xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., $activityname)]";
         $this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
     }
+
+    /**
+     * Return the list of partial named selectors.
+     *
+     * @return array
+     */
+    public static function get_partial_named_selectors(): array {
+        return [
+            new behat_component_named_selector('Activity', [
+                "//*[contains(concat(' ',normalize-space(@class),' '),' block_site_main_menu ')]//li[contains(., %locator%)]"
+            ]),
+        ];
+    }
 }
index 0f6d8c2..51b60ea 100644 (file)
@@ -6,15 +6,16 @@ Feature: Edit activities in main menu block
 
   @javascript
   Scenario: Edit name of acitivity in-place in site main menu block
-    Given I log in as "admin"
+    Given the following "activity" exists:
+      | activity | forum                |
+      | course   | Acceptance test site |
+      | name     | My forum name        |
+      | idnumber | forum                |
+    And I log in as "admin"
     And I am on site homepage
     And I navigate to "Turn editing on" in current page administration
     And I add the "Main menu" block
-    When I add a "Forum" to section "0" and I fill the form with:
-      | Forum name | My forum name |
-    And I click on "Edit title" "link" in the "My forum name" activity in site main menu block
-    And I set the field "New name for activity My forum name" to "New forum name"
-    And I press the enter key
+    When I set the field "Edit title" in the "My forum name" "block_site_main_menu > Activity" to "New forum name"
     Then I should not see "My forum name"
     And I should see "New forum name"
     And I follow "New forum name"
index 167b24d..eb28523 100644 (file)
@@ -158,4 +158,17 @@ class behat_block_social_activities extends behat_base {
         $xpath = "//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., $activityname)]";
         $this->execute('behat_action_menu::i_open_the_action_menu_in', [$xpath, 'xpath_element']);
     }
+
+    /**
+     * Return the list of partial named selectors.
+     *
+     * @return array
+     */
+    public static function get_partial_named_selectors(): array {
+        return [
+            new behat_component_named_selector('Activity', [
+                "//*[contains(concat(' ',normalize-space(@class),' '),' block_social_activities ')]//li[contains(., %locator%)]",
+            ]),
+        ];
+    }
 }
index 984b731..a21e848 100644 (file)
@@ -25,9 +25,7 @@ Feature: Edit activities in social activities block
     And I click on "Add a new Forum" "link" in the "Add an activity or resource" "dialogue"
     And I set the field "Forum name" to "My forum name"
     And I press "Save and return to course"
-    And I click on "Edit title" "link" in the "My forum name" activity in social activities block
-    And I set the field "New name for activity My forum name" to "New forum name"
-    And I press the enter key
+    When I set the field "Edit title" in the "My forum name" "block_social_activities > Activity" to "New forum name"
     Then I should not see "My forum name" in the "Social activities" "block"
     And I should see "New forum name"
     And I follow "New forum name"
@@ -84,4 +82,3 @@ Feature: Edit activities in social activities block
     And I should not see "My forum name" in the "Social activities" "block"
     And I click on "My forum name" "link" in the "Recent activity" "block"
     And I should see "My forum name" in the ".breadcrumb" "css_element"
-    And I log out
index 9bc5469..c422c70 100644 (file)
@@ -62,9 +62,7 @@ Feature: Add cohorts of users
   @javascript
   Scenario: Edit cohort name in-place
     When I follow "Cohorts"
-    And I click on "Edit cohort name" "link" in the "Test cohort name" "table_row"
-    And I set the field "New name for cohort Test cohort name" to "Students cohort"
-    And I press the enter key
+    And I set the field "Edit cohort name" to "Students cohort"
     Then I should not see "Test cohort name"
     And I should see "Students cohort"
     And I follow "Cohorts"
index e35e19b..8933024 100644 (file)
@@ -324,6 +324,9 @@ $CFG->admin = 'admin';
 //      Use the igbinary serializer instead of the php default one. Note that phpredis must be compiled with
 //      igbinary support to make the setting to work. Also, if you change the serializer you have to flush the database!
 //      $CFG->session_redis_serializer_use_igbinary = false; // Optional, default is PHP builtin serializer.
+//      $CFG->session_redis_compressor = 'none'; // Optional, possible values are:
+//                                               // 'gzip' - PHP GZip compression
+//                                               // 'zstd' - PHP Zstandard compression
 //
 // Please be aware that when selecting Memcached for sessions that it is advised to use a dedicated
 // memcache server. The memcached extension does not provide isolated environments for individual uses.
@@ -724,6 +727,22 @@ $CFG->admin = 'admin';
 //
 // $CFG->maxcoursesincategory = 10000;
 //
+// Admin setting encryption
+//
+//      $CFG->secretdataroot = '/var/www/my_secret_folder';
+//
+// Location to store encryption keys. By default this is $CFG->dataroot/secret; set this if
+// you want to use a different location for increased security (e.g. if too many people have access
+// to the main dataroot, or if you want to avoid using shared storage). Your web server user needs
+// read access to this location, and write access unless you manually create the keys.
+//
+//      $CFG->nokeygeneration = false;
+//
+// If you change this to true then the server will give an error if keys don't exist, instead of
+// automatically generating them. This is only needed if you want to ensure that keys are consistent
+// across a cluster when not using shared storage. If you stop the server generating keys, you will
+// need to manually generate them by running 'php admin/cli/generate_key.php'.
+
 //=========================================================================
 // 7. SETTINGS FOR DEVELOPMENT SERVERS - not intended for production use!!!
 //=========================================================================
index d517d5b..8028476 100644 (file)
Binary files a/course/amd/build/local/activitychooser/dialogue.min.js and b/course/amd/build/local/activitychooser/dialogue.min.js differ
index 740fe3f..c782a84 100644 (file)
Binary files a/course/amd/build/local/activitychooser/dialogue.min.js.map and b/course/amd/build/local/activitychooser/dialogue.min.js.map differ
index 45f8f4f..ea395d6 100644 (file)
Binary files a/course/amd/build/local/activitychooser/selectors.min.js and b/course/amd/build/local/activitychooser/selectors.min.js differ
index 13f9e9f..25b6d79 100644 (file)
Binary files a/course/amd/build/local/activitychooser/selectors.min.js.map and b/course/amd/build/local/activitychooser/selectors.min.js.map differ
index a3bde76..a7c7018 100644 (file)
@@ -216,7 +216,6 @@ const registerListenerEvents = (modal, mappedModules, partialFavourite, footerDa
         const firstChooserOption = sectionChooserOptions.querySelector(selectors.regions.chooserOption.container);
 
         toggleFocusableChooserOption(firstChooserOption, true);
-        initTabsKeyboardNavigation(body);
         initChooserOptionsKeyboardNavigation(body, mappedModules, sectionChooserOptions, modal);
 
         return body;
@@ -235,77 +234,6 @@ const registerListenerEvents = (modal, mappedModules, partialFavourite, footerDa
     .catch();
 };
 
-/**
- * Initialise the keyboard navigation controls for the tab list items.
- *
- * @method initTabsKeyboardNavigation
- * @param {HTMLElement} body Our modal that we are working with
- */
-const initTabsKeyboardNavigation = (body) => {
-    // Set up the tab handlers.
-    const favTabNav = body.querySelector(selectors.regions.favouriteTabNav);
-    const recommendedTabNav = body.querySelector(selectors.regions.recommendedTabNav);
-    const defaultTabNav = body.querySelector(selectors.regions.defaultTabNav);
-    const activityTabNav = body.querySelector(selectors.regions.activityTabNav);
-    const resourceTabNav = body.querySelector(selectors.regions.resourceTabNav);
-    const tabNavArray = [favTabNav, recommendedTabNav, defaultTabNav, activityTabNav, resourceTabNav];
-    tabNavArray.forEach((element) => {
-        return element.addEventListener('keydown', (e) => {
-            // The first visible navigation tab link.
-            const firstLink = e.target.parentElement.querySelector(selectors.elements.visibletabs);
-            // The last navigation tab link. It would always be the default activities tab link.
-            const lastLink = e.target.parentElement.lastElementChild;
-
-            if (e.keyCode === arrowRight) {
-                const nextLink = e.target.nextElementSibling;
-                if (nextLink === null) {
-                    e.target.tabIndex = -1;
-                    firstLink.tabIndex = 0;
-                    firstLink.focus();
-                } else if (nextLink.classList.contains('d-none')) {
-                    e.target.tabIndex = -1;
-                    lastLink.tabIndex = 0;
-                    lastLink.focus();
-                } else {
-                    e.target.tabIndex = -1;
-                    nextLink.tabIndex = 0;
-                    nextLink.focus();
-                }
-            }
-            if (e.keyCode === arrowLeft) {
-                const previousLink = e.target.previousElementSibling;
-                if (previousLink === null) {
-                    e.target.tabIndex = -1;
-                    lastLink.tabIndex = 0;
-                    lastLink.focus();
-                } else if (previousLink.classList.contains('d-none')) {
-                    e.target.tabIndex = -1;
-                    firstLink.tabIndex = 0;
-                    firstLink.focus();
-                } else {
-                    e.target.tabIndex = -1;
-                    previousLink.tabIndex = 0;
-                    previousLink.focus();
-                }
-            }
-            if (e.keyCode === home) {
-                e.target.tabIndex = -1;
-                firstLink.tabIndex = 0;
-                firstLink.focus();
-            }
-            if (e.keyCode === end) {
-                e.target.tabIndex = -1;
-                lastLink.tabIndex = 0;
-                lastLink.focus();
-            }
-            if (e.keyCode === space) {
-                e.preventDefault();
-                e.target.click();
-            }
-        });
-    });
-};
-
 /**
  * Initialise the keyboard navigation controls for the chooser options.
  *
index dd20e75..34e9adb 100644 (file)
@@ -52,10 +52,8 @@ export default {
         help: getDataSelector('region', 'help'),
         modules: getDataSelector('region', 'modules'),
         favouriteTabNav: getDataSelector('region', 'favourite-tab-nav'),
-        recommendedTabNav: getDataSelector('region', 'recommended-tab-nav'),
         defaultTabNav: getDataSelector('region', 'default-tab-nav'),
         activityTabNav: getDataSelector('region', 'activity-tab-nav'),
-        resourceTabNav: getDataSelector('region', 'resources-tab-nav'),
         favouriteTab: getDataSelector('region', 'favourites'),
         recommendedTab: getDataSelector('region', 'recommended'),
         defaultTab: getDataSelector('region', 'default'),
index a1e205b..573c7e5 100644 (file)
@@ -53,9 +53,7 @@ Feature: Sections can be edited and deleted in topics format
 
   @javascript
   Scenario: Inline edit section name in topics format
-    When I click on "Edit topic name" "link" in the "li#section-1" "css_element"
-    And I set the field "New name for topic Topic 1" to "Midterm evaluation"
-    And I press the enter key
+    When I set the field "Edit topic name" in the "li#section-1" "css_element" to "Midterm evaluation"
     Then I should not see "Topic 1" in the "region-main" "region"
     And "New name for topic" "field" should not exist
     And I should see "Midterm evaluation" in the "li#section-1" "css_element"
index 5d8ff89..6fdc14a 100644 (file)
@@ -54,9 +54,7 @@ Feature: Sections can be edited and deleted in weeks format
 
   @javascript
   Scenario: Inline edit section name in weeks format
-    When I click on "Edit week name" "link" in the "li#section-1" "css_element"
-    And I set the field "New name for week 1 May - 7 May" to "Midterm evaluation"
-    And I press the enter key
+    When I set the field "Edit week name" in the "li#section-1" "css_element" to "Midterm evaluation"
     Then I should not see "1 May - 7 May" in the "region-main" "region"
     And "New name for week" "field" should not exist
     And I should see "Midterm evaluation" in the "li#section-1" "css_element"
index 7372c17..1821738 100644 (file)
@@ -15,15 +15,16 @@ Feature: Edit activity name in-place
     And the following "course enrolments" exist:
       | user | course | role |
       | teacher1 | C1 | editingteacher |
+    And the following "activity" exists:
+      | course      | C1                     |
+      | activity    | forum                  |
+      | name        | Test forum name        |
+      | description | Test forum description |
+      | idnumber    | forum1                 |
     When I log in as "teacher1"
     And I am on "Course 1" course homepage with editing mode on
-    And I add a "Forum" to section "1" and I fill the form with:
-      | Forum name | Test forum name |
-      | Description | Test forum description |
     # Rename activity
-    And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Test forum name')]" "xpath_element"
-    And I set the field "New name for activity Test forum name" to "Good news"
-    And I press the enter key
+    And I set the field "Edit title" in the "Test forum name" "activity" to "Good news"
     Then I should not see "Test forum name" in the ".course-content" "css_element"
     And "New name for activity Test forum name" "field" should not exist
     And I should see "Good news"
@@ -32,7 +33,7 @@ Feature: Edit activity name in-place
     And I should not see "Test forum name"
     # Cancel renaming
     And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Good news')]" "xpath_element"
-    And I set the field "New name for activity Good news" to "Terrible news"
+    And I type "Terrible news"
     And I press the escape key
     And "New name for activity Good news" "field" should not exist
     And I should see "Good news"
index 26cecd1..d06a8bf 100644 (file)
@@ -852,22 +852,12 @@ class behat_course extends behat_base {
      * @param string $newactivityname
      */
     public function i_change_activity_name_to($activityname, $newactivityname) {
-
-        if (!$this->running_javascript()) {
-            throw new DriverException('Change activity name step is not available with Javascript disabled');
-        }
-
-        $activity = $this->escape($activityname);
-
-        $this->execute('behat_course::i_click_on_in_the_activity',
-            array(get_string('edittitle'), "link", $activity)
-        );
-
-        // Adding chr(10) to save changes.
-        $this->execute('behat_forms::i_set_the_field_to',
-            array('title', $this->escape($newactivityname) . chr(10))
-        );
-
+        $this->execute('behat_forms::i_set_the_field_in_container_to', [
+            get_string('edittitle'),
+            $activityname,
+            'activity',
+            $newactivityname
+        ]);
     }
 
     /**
index 24da2bb..76a2f34 100644 (file)
@@ -118,7 +118,7 @@ class core_customfield_external extends external_api {
                 'component' => new external_value(PARAM_COMPONENT, 'component'),
                 'area' => new external_value(PARAM_ALPHANUMEXT, 'area'),
                 'itemid' => new external_value(PARAM_INT, 'itemid'),
-                'usescategories' => new external_value(PARAM_INT, 'view has categories'),
+                'usescategories' => new external_value(PARAM_BOOL, 'view has categories'),
                 'categories' => new external_multiple_structure(
                     new external_single_structure(
                         array(
index 2b88046..b44a661 100644 (file)
@@ -12,7 +12,6 @@ Feature: Managers can manage categories for course custom fields
     Then I should see "Other fields" in the "#customfield_catlist" "css_element"
     And I navigate to "Reports > Logs" in site administration
     And I press "Get these logs"
-    And I log out
 
   Scenario: Edit a category name for custom course fields
     Given the following "custom field categories" exist:
@@ -20,15 +19,12 @@ Feature: Managers can manage categories for course custom fields
       | Category for test | core_course | course | 0      |
     And I log in as "admin"
     And I navigate to "Courses > Course custom fields" in site administration
-    And I click on "Edit category name" "link" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element"
-    And I set the field "New value for Category for test" to "Good fields"
-    And I press the enter key
+    And I set the field "Edit category name" in the "//div[contains(@class,'categoryinstance') and contains(.,'Category for test')]" "xpath_element" to "Good fields"
     Then I should not see "Category for test" in the "#customfield_catlist" "css_element"
     And "New value for Category for test" "field" should not exist
     And I should see "Good fields" in the "#customfield_catlist" "css_element"
     And I navigate to "Reports > Logs" in site administration
     And I press "Get these logs"
-    And I log out
 
   Scenario: Delete a category for custom course fields
     Given the following "custom field categories" exist:
@@ -46,7 +42,6 @@ Feature: Managers can manage categories for course custom fields
     Then I should not see "Test category" in the "#customfield_catlist" "css_element"
     And I navigate to "Reports > Logs" in site administration
     And I press "Get these logs"
-    And I log out
 
   Scenario: Move field in the course custom fields to another category
     Given the following "custom field categories" exist:
@@ -78,7 +73,6 @@ Feature: Managers can manage categories for course custom fields
     And I press "Move \"Field1\""
     And I follow "After field Field2"
     And "Field1" "text" should appear after "Field2" "text"
-    And I log out
 
   Scenario: Reorder course custom field categories
     Given the following "custom field categories" exist:
@@ -108,4 +102,3 @@ Feature: Managers can manage categories for course custom fields
     And "Field1" "text" should appear after "Category1" "text"
     And "Category2" "text" should appear after "Field1" "text"
     And "Category3" "text" should appear after "Category2" "text"
-    And I log out
index 8c08a74..50cd5dc 100644 (file)
@@ -36,7 +36,7 @@ if ($ADMIN->fulltree) {
         $student = get_archetype_roles('student');
         $student = reset($student);
         $settings->add(new admin_setting_configselect('enrol_cohort/roleid',
-            get_string('defaultrole', 'role'), '', $student->id, $options));
+            get_string('defaultrole', 'role'), '', $student->id ?? null, $options));
 
         $options = array(
             ENROL_EXT_REMOVED_UNENROL        => get_string('extremovedunenrol', 'enrol'),
diff --git a/enrol/database/cli/sync.php b/enrol/database/cli/sync.php
deleted file mode 100644 (file)
index 9a78691..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-<?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/>.
-
-/**
- * CLI sync for full external database synchronisation.
- *
- * Sample cron entry:
- * # 5 minutes past 4am
- * 5 4 * * * $sudo -u www-data /usr/bin/php /var/www/moodle/enrol/database/cli/sync.php
- *
- * Notes:
- *   - it is required to use the web server account when executing PHP CLI scripts
- *   - you need to change the "www-data" to match the apache user account
- *   - use "su" if "sudo" not available
- *
- * @deprecated since Moodle 3.7 MDL-59986 - please do not use this CLI script any more, use scheduled task instead.
- * @todo       MDL-63266 This will be deleted in Moodle 3.11.
- * @package    enrol_database
- * @copyright  2010 Petr Skoda {@link http://skodak.org}
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-
-define('CLI_SCRIPT', true);
-
-require(__DIR__.'/../../../config.php');
-require_once("$CFG->libdir/clilib.php");
-
-// Now get cli options.
-list($options, $unrecognized) = cli_get_params(array('verbose'=>false, 'help'=>false), array('v'=>'verbose', 'h'=>'help'));
-
-if ($unrecognized) {
-    $unrecognized = implode("\n  ", $unrecognized);
-    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
-}
-
-if ($options['help']) {
-    $help =
-"Execute enrol sync with external database.
-The enrol_database plugin must be enabled and properly configured.
-
-Options:
--v, --verbose         Print verbose progress information
--h, --help            Print out this help
-
-Example:
-\$ sudo -u www-data /usr/bin/php enrol/database/cli/sync.php
-
-Sample cron entry:
-# 5 minutes past 4am
-5 4 * * * sudo -u www-data /usr/bin/php /var/www/moodle/enrol/database/cli/sync.php
-";
-
-    echo $help;
-    die;
-}
-
-cli_problem('[ENROL DATABASE] The sync enrolments cron script has been deprecated. Please use the scheduled task instead.');
-
-// Abort execution of the CLI script if the enrol_database\task\sync_enrolments is enabled.
-$task = \core\task\manager::get_scheduled_task('enrol_database\task\sync_enrolments');
-if (!$task->get_disabled()) {
-    cli_error('[ENROL DATABASE] The scheduled task sync_enrolments is enabled, the cron execution has been aborted.');
-}
-
-if (!enrol_is_enabled('database')) {
-    cli_error('enrol_database plugin is disabled, synchronisation stopped', 2);
-}
-
-if (empty($options['verbose'])) {
-    $trace = new null_progress_trace();
-} else {
-    $trace = new text_progress_trace();
-}
-
-/** @var enrol_database_plugin $enrol  */
-$enrol = enrol_get_plugin('database');
-$result = 0;
-
-$result = $result | $enrol->sync_courses($trace);
-$result = $result | $enrol->sync_enrolments($trace);
-
-exit($result);
index 28c7504..92d0833 100644 (file)
@@ -86,7 +86,11 @@ if ($ADMIN->fulltree) {
         $options = get_default_enrol_roles(context_system::instance());
         $student = get_archetype_roles('student');
         $student = reset($student);
-        $settings->add(new admin_setting_configselect('enrol_database/defaultrole', get_string('defaultrole', 'enrol_database'), get_string('defaultrole_desc', 'enrol_database'), $student->id, $options));
+        $settings->add(new admin_setting_configselect('enrol_database/defaultrole',
+            get_string('defaultrole', 'enrol_database'),
+            get_string('defaultrole_desc', 'enrol_database'),
+            $student->id ?? null,
+            $options));
     }
 
     $settings->add(new admin_setting_configcheckbox('enrol_database/ignorehiddencourses', get_string('ignorehiddencourses', 'enrol_database'), get_string('ignorehiddencourses_desc', 'enrol_database'), 0));
index 53c0931..fb5d57c 100644 (file)
@@ -1,5 +1,8 @@
 This files describes API changes in the enrol_database code.
 
+=== 3.11 ===
+* Final deprecation enrol/database/cli/sync.php. Refer below for substitute.
+
 === 3.9 ===
 * Class enrol_database_admin_setting_category has been removed. This class was only used by the database
   enrolment plugin settings and it was replaced by admin_settings_coursecat_select.
index d0fbaa9..5189a3a 100644 (file)
@@ -679,28 +679,34 @@ class core_enrol_external extends external_api {
      */
     public static function get_enrolled_users_parameters() {
         return new external_function_parameters(
-            array(
+            [
                 'courseid' => new external_value(PARAM_INT, 'course id'),
                 'options'  => new external_multiple_structure(
                     new external_single_structure(
-                        array(
+                        [
                             'name'  => new external_value(PARAM_ALPHANUMEXT, 'option name'),
                             'value' => new external_value(PARAM_RAW, 'option value')
-                        )
+                        ]
                     ), 'Option names:
                             * withcapability (string) return only users with this capability. This option requires \'moodle/role:review\' on the course context.
                             * groupid (integer) return only users in this group id. If the course has groups enabled and this param
                                                 isn\'t defined, returns all the viewable users.
                                                 This option requires \'moodle/site:accessallgroups\' on the course context if the
                                                 user doesn\'t belong to the group.
-                            * onlyactive (integer) return only users with active enrolments and matching time restrictions. This option requires \'moodle/course:enrolreview\' on the course context.
+                            * onlyactive (integer) return only users with active enrolments and matching time restrictions.
+                                                This option requires \'moodle/course:enrolreview\' on the course context.
+                                                Please note that this option can\'t
+                                                be used together with onlysuspended (only one can be active).
+                            * onlysuspended (integer) return only suspended users. This option requires
+                                            \'moodle/course:enrolreview\' on the course context. Please note that this option can\'t
+                                                be used together with onlyactive (only one can be active).
                             * userfields (\'string, string, ...\') return only the values of these user fields.
                             * limitfrom (integer) sql limit from.
                             * limitnumber (integer) maximum number of returned users.
                             * sortby (string) sort by id, firstname or lastname. For ordering like the site does, use siteorder.
                             * sortdirection (string) ASC or DESC',
-                            VALUE_DEFAULT, array()),
-            )
+                            VALUE_DEFAULT, []),
+            ]
         );
     }
 
@@ -714,7 +720,7 @@ class core_enrol_external extends external_api {
      *                               }
      * @return array An array of users
      */
-    public static function get_enrolled_users($courseid, $options = array()) {
+    public static function get_enrolled_users($courseid, $options = []) {
         global $CFG, $USER, $DB;
 
         require_once($CFG->dirroot . '/course/lib.php');
@@ -722,67 +728,71 @@ class core_enrol_external extends external_api {
 
         $params = self::validate_parameters(
             self::get_enrolled_users_parameters(),
-            array(
+            [
                 'courseid'=>$courseid,
                 'options'=>$options
-            )
+            ]
         );
         $withcapability = '';
         $groupid        = 0;
         $onlyactive     = false;
-        $userfields     = array();
+        $onlysuspended  = false;
+        $userfields     = [];
         $limitfrom = 0;
         $limitnumber = 0;
         $sortby = 'us.id';
-        $sortparams = array();
+        $sortparams = [];
         $sortdirection = 'ASC';
         foreach ($options as $option) {
             switch ($option['name']) {
-            case 'withcapability':
-                $withcapability = $option['value'];
-                break;
-            case 'groupid':
-                $groupid = (int)$option['value'];
-                break;
-            case 'onlyactive':
-                $onlyactive = !empty($option['value']);
-                break;
-            case 'userfields':
-                $thefields = explode(',', $option['value']);
-                foreach ($thefields as $f) {
-                    $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
-                }
-                break;
-            case 'limitfrom' :
-                $limitfrom = clean_param($option['value'], PARAM_INT);
-                break;
-            case 'limitnumber' :
-                $limitnumber = clean_param($option['value'], PARAM_INT);
-                break;
-            case 'sortby':
-                $sortallowedvalues = array('id', 'firstname', 'lastname', 'siteorder');
-                if (!in_array($option['value'], $sortallowedvalues)) {
-                    throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' . $option['value'] . '),' .
-                        'allowed values are: ' . implode(',', $sortallowedvalues));
-                }
-                if ($option['value'] == 'siteorder') {
-                    list($sortby, $sortparams) = users_order_by_sql('us');
-                } else {
-                    $sortby = 'us.' . $option['value'];
-                }
-                break;
-            case 'sortdirection':
-                $sortdirection = strtoupper($option['value']);
-                $directionallowedvalues = array('ASC', 'DESC');
-                if (!in_array($sortdirection, $directionallowedvalues)) {
-                    throw new invalid_parameter_exception('Invalid value for sortdirection parameter
+                case 'withcapability':
+                    $withcapability = $option['value'];
+                    break;
+                case 'groupid':
+                    $groupid = (int)$option['value'];
+                    break;
+                case 'onlyactive':
+                    $onlyactive = !empty($option['value']);
+                    break;
+                case 'onlysuspended':
+                    $onlysuspended = !empty($option['value']);
+                    break;
+                case 'userfields':
+                    $thefields = explode(',', $option['value']);
+                    foreach ($thefields as $f) {
+                        $userfields[] = clean_param($f, PARAM_ALPHANUMEXT);
+                    }
+                    break;
+                case 'limitfrom' :
+                    $limitfrom = clean_param($option['value'], PARAM_INT);
+                    break;
+                case 'limitnumber' :
+                    $limitnumber = clean_param($option['value'], PARAM_INT);
+                    break;
+                case 'sortby':
+                    $sortallowedvalues = ['id', 'firstname', 'lastname', 'siteorder'];
+                    if (!in_array($option['value'], $sortallowedvalues)) {
+                        throw new invalid_parameter_exception('Invalid value for sortby parameter (value: ' .
+                            $option['value'] . '), allowed values are: ' . implode(',', $sortallowedvalues));
+                    }
+                    if ($option['value'] == 'siteorder') {
+                        list($sortby, $sortparams) = users_order_by_sql('us');
+                    } else {
+                        $sortby = 'us.' . $option['value'];
+                    }
+                    break;
+                case 'sortdirection':
+                    $sortdirection = strtoupper($option['value']);
+                    $directionallowedvalues = ['ASC', 'DESC'];
+                    if (!in_array($sortdirection, $directionallowedvalues)) {
+                        throw new invalid_parameter_exception('Invalid value for sortdirection parameter
                         (value: ' . $sortdirection . '),' . 'allowed values are: ' . implode(',', $directionallowedvalues));
-                }
-                break;
+                    }
+                    break;
             }
         }
 
-        $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
+        $course = $DB->get_record('course', ['id' => $courseid], '*', MUST_EXIST);
         $coursecontext = context_course::instance($courseid, IGNORE_MISSING);
         if ($courseid == SITEID) {
             $context = context_system::instance();
@@ -809,11 +819,12 @@ class core_enrol_external extends external_api {
             require_capability('moodle/site:accessallgroups', $coursecontext);
         }
         // to overwrite this option, you need course:enrolereview permission
-        if ($onlyactive) {
+        if ($onlyactive || $onlysuspended) {
             require_capability('moodle/course:enrolreview', $coursecontext);
         }
 
-        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
+        list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive,
+        $onlysuspended);
         $ctxselect = ', ' . context_helper::get_preload_record_columns_sql('ctx');
         $ctxjoin = "LEFT JOIN {context} ctx ON (ctx.instanceid = u.id AND ctx.contextlevel = :contextlevel)";
         $enrolledparams['contextlevel'] = CONTEXT_USER;
@@ -829,7 +840,7 @@ class core_enrol_external extends external_api {
                 $enrolledparams = array_merge($enrolledparams, $groupparams);
             } else {
                 // User doesn't belong to any group, so he can't see any user. Return an empty array.
-                return array();
+                return [];
             }
         }
         $sql = "SELECT us.*, COALESCE(ul.timeaccess, 0) AS lastcourseaccess
@@ -845,7 +856,7 @@ class core_enrol_external extends external_api {
         $enrolledparams['courseid'] = $courseid;
 
         $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams, $limitfrom, $limitnumber);
-        $users = array();
+        $users = [];
         foreach ($enrolledusers as $user) {
             context_helper::preload_from_record($user);
             if ($userdetails = user_get_user_details($user, $course, $userfields)) {
@@ -865,7 +876,7 @@ class core_enrol_external extends external_api {
     public static function get_enrolled_users_returns() {
         return new external_multiple_structure(
             new external_single_structure(
-                array(
+                [
                     'id'    => new external_value(PARAM_INT, 'ID of the user'),
                     'username'    => new external_value(PARAM_RAW, 'Username policy is defined in Moodle security config', VALUE_OPTIONAL),
                     'firstname'   => new external_value(PARAM_NOTAGS, 'The first name(s) of the user', VALUE_OPTIONAL),
@@ -896,47 +907,47 @@ class core_enrol_external extends external_api {
                     'profileimageurl' => new external_value(PARAM_URL, 'User image profile URL - big version', VALUE_OPTIONAL),
                     'customfields' => new external_multiple_structure(
                         new external_single_structure(
-                            array(
+                            [
                                 'type'  => new external_value(PARAM_ALPHANUMEXT, 'The type of the custom field - text field, checkbox...'),
                                 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
                                 'name' => new external_value(PARAM_RAW, 'The name of the custom field'),
                                 'shortname' => new external_value(PARAM_RAW, 'The shortname of the custom field - to be able to build the field class in the code'),
-                            )
+                            ]
                         ), 'User custom fields (also known as user profil fields)', VALUE_OPTIONAL),
                     'groups' => new external_multiple_structure(
                         new external_single_structure(
-                            array(
+                            [
                                 'id'  => new external_value(PARAM_INT, 'group id'),
                                 'name' => new external_value(PARAM_RAW, 'group name'),
                                 'description' => new external_value(PARAM_RAW, 'group description'),
                                 'descriptionformat' => new external_format_value('description'),
-                            )
+                            ]
                         ), 'user groups', VALUE_OPTIONAL),
                     'roles' => new external_multiple_structure(
                         new external_single_structure(
-                            array(
+                            [
                                 'roleid'       => new external_value(PARAM_INT, 'role id'),
                                 'name'         => new external_value(PARAM_RAW, 'role name'),
                                 'shortname'    => new external_value(PARAM_ALPHANUMEXT, 'role shortname'),
                                 'sortorder'    => new external_value(PARAM_INT, 'role sortorder')
-                            )
+                            ]
                         ), 'user roles', VALUE_OPTIONAL),
                     'preferences' => new external_multiple_structure(
                         new external_single_structure(
-                            array(
+                            [
                                 'name'  => new external_value(PARAM_RAW, 'The name of the preferences'),
                                 'value' => new external_value(PARAM_RAW, 'The value of the custom field'),
-                            )
+                            ]
                     ), 'User preferences', VALUE_OPTIONAL),
                     'enrolledcourses' => new external_multiple_structure(
                         new external_single_structure(
-                            array(
+                            [
                                 'id'  => new external_value(PARAM_INT, 'Id of the course'),
                                 'fullname' => new external_value(PARAM_RAW, 'Fullname of the course'),
                                 'shortname' => new external_value(PARAM_RAW, 'Shortname of the course')
-                            )
+                            ]
                     ), 'Courses where the user is enrolled - limited by which courses the user is able to see', VALUE_OPTIONAL)
-                )
+                ]
             )
         );
     }
index 2f383b8..50d919e 100644 (file)
@@ -71,7 +71,7 @@ if ($ADMIN->fulltree) {
         $student = get_archetype_roles('student');
         $student = reset($student);
         $settings->add(new admin_setting_configselect('enrol_fee/roleid',
-            get_string('defaultrole', 'enrol_fee'), get_string('defaultrole_desc', 'enrol_fee'), $student->id, $options));
+            get_string('defaultrole', 'enrol_fee'), get_string('defaultrole_desc', 'enrol_fee'), $student->id ?? null, $options));
     }
 
     $settings->add(new admin_setting_configduration('enrol_fee/enrolperiod',
index 2056c19..8dcabcc 100644 (file)
@@ -63,7 +63,7 @@ if ($ADMIN->fulltree) {
         $student = get_archetype_roles('student');
         $student = reset($student);
         $settings->add(new admin_setting_configselect('enrol_manual/roleid',
-            get_string('defaultrole', 'role'), '', $student->id, $options));
+            get_string('defaultrole', 'role'), '', $student->id ?? null, $options));
     }
 
     $options = array(2 => get_string('coursestart'), 3 => get_string('today'), 4 => get_string('now', 'enrol_manual'));
index fc7517f..c74c8e1 100644 (file)
@@ -36,6 +36,6 @@ if ($ADMIN->fulltree) {
         $student = reset($student);
         $settings->add(new admin_setting_configselect_with_advanced('enrol_mnet/roleid',
             get_string('defaultrole', 'role'), '',
-            array('value'=>$student->id, 'adv'=>true), $options));
+            array('value' => $student->id ?? null, 'adv' => true), $options));
     }
 }
index 66e0ae4..d9a3a7f 100644 (file)
@@ -66,7 +66,10 @@ if ($ADMIN->fulltree) {
         $student = get_archetype_roles('student');
         $student = reset($student);
         $settings->add(new admin_setting_configselect('enrol_paypal/roleid',
-            get_string('defaultrole', 'enrol_paypal'), get_string('defaultrole_desc', 'enrol_paypal'), $student->id, $options));
+            get_string('defaultrole', 'enrol_paypal'),
+            get_string('defaultrole_desc', 'enrol_paypal'),
+            $student->id ?? null,
+            $options));
     }
 
     $settings->add(new admin_setting_configduration('enrol_paypal/enrolperiod',
index 6375ea2..cee5d7f 100644 (file)
@@ -79,7 +79,10 @@ if ($ADMIN->fulltree) {
         $student = get_archetype_roles('student');
         $student = reset($student);
         $settings->add(new admin_setting_configselect('enrol_self/roleid',
-            get_string('defaultrole', 'enrol_self'), get_string('defaultrole_desc', 'enrol_self'), $student->id, $options));
+            get_string('defaultrole', 'enrol_self'),
+            get_string('defaultrole_desc', 'enrol_self'),
+            $student->id ?? null,
+            $options));
     }
 
     $settings->add(new admin_setting_configduration('enrol_self/enrolperiod',
index a12df0b..c98df46 100644 (file)
@@ -355,6 +355,95 @@ class core_enrol_externallib_testcase extends externallib_advanced_testcase {
         }
     }
 
+    /**
+     * Verify get_enrolled_users() returned users according to their status.
+     */
+    public function test_get_enrolled_users_active_suspended() {
+        global $USER;
+
+        $this->resetAfterTest();
+
+        // Create the course and the users.
+        $course = $this->getDataGenerator()->create_course();
+        $coursecontext = context_course::instance($course->id);
+        $user0 = $this->getDataGenerator()->create_user(['username' => 'user0active']);
+        $user1 = $this->getDataGenerator()->create_user(['username' => 'user1active']);
+        $user2 = $this->getDataGenerator()->create_user(['username' => 'user2active']);
+        $user2su = $this->getDataGenerator()->create_user(['username' => 'user2suspended']); // Suspended user.
+        $user3 = $this->getDataGenerator()->create_user(['username' => 'user3active']);
+        $user3su = $this->getDataGenerator()->create_user(['username' => 'user3suspended']); // Suspended user.
+
+        // Enrol the users in the course.
+        $this->getDataGenerator()->enrol_user($user0->id, $course->id);
+        $this->getDataGenerator()->enrol_user($user1->id, $course->id);
+        $this->getDataGenerator()->enrol_user($user2->id, $course->id);
+        $this->getDataGenerator()->enrol_user($user2su->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+        $this->getDataGenerator()->enrol_user($user3->id, $course->id);
+        $this->getDataGenerator()->enrol_user($user3su->id, $course->id, null, 'manual', 0, 0, ENROL_USER_SUSPENDED);
+
+        // Create a role to add the allowedcaps. Users will have this role assigned.
+        $roleid = $this->getDataGenerator()->create_role();
+        // Allow the specified capabilities.
+        assign_capability('moodle/course:enrolreview', CAP_ALLOW, $roleid, $coursecontext);
+        assign_capability('moodle/user:viewalldetails', CAP_ALLOW, $roleid, $coursecontext);
+
+        // Switch to the user and assign the role.
+        $this->setUser($user0);
+        role_assign($roleid, $USER->id, $coursecontext);
+
+        // Suspended users.
+        $options = [
+            ['name' => 'onlysuspended', 'value' => true],
+            ['name' => 'userfields', 'value' => 'id,username']
+        ];
+        $suspendedusers = core_enrol_external::get_enrolled_users($course->id, $options);
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $suspendedusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $suspendedusers);
+        $this->assertCount(2, $suspendedusers);
+
+        foreach ($suspendedusers as $suspendeduser) {
+            $this->assertStringContainsString('suspended', $suspendeduser['username']);
+        }
+
+        // Active users.
+        $options = [
+            ['name' => 'onlyactive', 'value' => true],
+            ['name' => 'userfields', 'value' => 'id,username']
+        ];
+        $activeusers = core_enrol_external::get_enrolled_users($course->id, $options);
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $activeusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $activeusers);
+        $this->assertCount(4, $activeusers);
+
+        foreach ($activeusers as $activeuser) {
+            $this->assertStringContainsString('active', $activeuser['username']);
+        }
+
+        // All enrolled users.
+        $options = [
+            ['name' => 'userfields', 'value' => 'id,username']
+        ];
+        $allusers = core_enrol_external::get_enrolled_users($course->id, $options);
+
+        // We need to execute the return values cleaning process to simulate the web service server.
+        $allusers = external_api::clean_returnvalue(core_enrol_external::get_enrolled_users_returns(), $allusers);
+        $this->assertCount(6, $allusers);
+
+        // Active and suspended. Test exception is thrown.
+        $options = [
+            ['name' => 'onlyactive', 'value' => true],
+            ['name' => 'onlysuspended', 'value' => true],
+            ['name' => 'userfields', 'value' => 'id,username']
+        ];
+        $this->expectException('coding_exception');
+        $message = 'Coding error detected, it must be fixed by a programmer: Both onlyactive ' .
+                        'and onlysuspended are set, this is probably not what you want!';
+        $this->expectExceptionMessage($message);
+        core_enrol_external::get_enrolled_users($course->id, $options);
+    }
+
     /**
      * Test get_users_courses
      */
index bfec2ff..a882f6e 100644 (file)
@@ -1,6 +1,10 @@
 This files describes API changes in /enrol/* - plugins,
 information provided here is intended especially for developers.
 
+=== 3.11 ===
+
+* Added onlysuspended option to core_enrol_get_enrolled_users webservice to retrieve only suspended users.
+
 === 3.8 ===
 
 * Function enrol_manual_plugin::enrol_cohort now return the number of enrolled cohort users.
index 7cc30a4..dfd6041 100644 (file)
@@ -127,7 +127,8 @@ class player {
             $url,
             $config,
             $this->factory,
-            $this->messages
+            $this->messages,
+            $this->preventredirect
         );
         if ($file) {
             $this->context = \context::instance_by_id($file->get_contextid());
diff --git a/install/lang/ab/langconfig.php b/install/lang/ab/langconfig.php
new file mode 100644 (file)
index 0000000..6c5525d
--- /dev/null
@@ -0,0 +1,32 @@
+<?php
+// This file is part of Moodle - https://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 <https://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'Аԥсуа бызшәа';
index 17e85cf..a5bda25 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index ae359a1..a82a1fc 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 3955288..c10cb66 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 7fae007..8d1aed8 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 07817ea..c2c7725 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 76e3612..80a46c8 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 2e90b4d..75198e9 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 79c0a2d..548e757 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 1d2e18d..79f0ed5 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index b70d682..854d083 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index c6d3436..e800ee3 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 94f4624..7d415c5 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
index 0ff4503..bc06fce 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
@@ -34,11 +33,9 @@ $string['clianswerno'] = 'لا';
 $string['cliansweryes'] = 'نعم';
 $string['cliincorrectvalueerror'] = 'خطأ، القيمة "{$a->value}" غير صحيحة من أجل "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'قيمة غير صحيحة، حاول مرة أخرى';
-$string['clitypevalue'] = 'أدخÙ\84 Ø§Ù\84قيمة';
+$string['clitypevalue'] = 'اÙ\83تب قيمة';
 $string['clitypevaluedefault'] = 'أدخل القيمة أو إضغط مفتاح Enter لاستعمال القيمة الافتراضية ({$a})';
-$string['cliunknowoption'] = 'خيارات غير معروفة
-{$a}
-الرجاء استخدام خيار المساعدة';
+$string['cliunknowoption'] = 'خيارات غير معروفة: {$a} الرجاء استخدام -- خيار المساعدة.';
 $string['cliyesnoprompt'] = 'أدخل y (وتعني نعم) أو n (وتعني لا)';
 $string['environmentrequireinstall'] = 'يجب تنصيبه/تمكينه';
 $string['environmentrequireversion'] = 'يتطلب الإصدار {$a->needed}، وأنت تستعمل الإصدار {$a->current}';
index a06f575..c47e1c4 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
@@ -38,9 +37,9 @@ $string['cannotcreatetempdir'] = 'لا يمكن إنشاء المجلد المؤ
 $string['cannotdownloadcomponents'] = 'تعذر تنزيل المُكونات';
 $string['cannotdownloadzipfile'] = 'لم يتم تحميل الملف المضغوط';
 $string['cannotfindcomponent'] = 'لم يتم العثور على المكون';
-$string['cannotsavemd5file'] = 'لم يتم حفظ ملف  md5';
-$string['cannotsavezipfile'] = 'لم يتم حفظ الملف المضغوط';
-$string['cannotunzipfile'] = 'لم يتم فك الملف المضغوط';
+$string['cannotsavemd5file'] = 'تعذر حفظ ملف md5';
+$string['cannotsavezipfile'] = 'تعذر حفظ الملف المضغوط';
+$string['cannotunzipfile'] = 'تعذر فك الملف المضغوط';
 $string['componentisuptodate'] = 'العنصر محدث';
 $string['dmlexceptiononinstall'] = '<p>حدث خطأ في قاعدة البيانات[{$a->errorcode}].<br />{$a->debuginfo}</p>';
 $string['downloadedfilecheckfailed'] = 'فشل التحقق من الملف الذي تم تنزيله';
index 82d998d..95ec3d7 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
@@ -88,9 +87,9 @@ $string['pathsunsecuredataroot'] = 'موضع مجلد البيانات الرئ
 $string['pathswrongadmindir'] = 'مجلد المشرف غير موجود';
 $string['phpextension'] = 'إمتداد PHP {$a}';
 $string['phpversion'] = 'إصدار PHP';
-$string['phpversionhelp'] = '<p> يتطلب مودل على الاقل وجود PHP بالاصدار 5.6.5 أو 7.1 (الإصدار 7.0.x فيه بعض القيود عند التشغيل).</p>
-<p> انت تستعمل حالياً الإصدار {$a}.</p>
-<p> يجب عليك ترقية PHP أو الانتقال إلى مستضيف آخر لديه إصدار أحدث من PHP.</p>';
+$string['phpversionhelp'] = '<p>يتطلب مودل على الأقل وجود PHP بالإصدار 5.6.5 أو 7.1 (الإصدار 7.0.x فيه بعض القيود عند التشغيل).</p>
+<p>انت تستعمل حالياً الإصدار {$a}.</p>
+<p>يجب عليك ترقية PHP أو الانتقال إلى مستضيف آخر لديه إصدار أحدث من PHP.</p>';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['welcomep20'] = 'أنت تشاهد هذه الصفحة لأنك تمكنت بنجاح من تنصيب وإطلاق
 حزمة <strong>{$a->packname} {$a->packversion}</strong> في حاسبتك. تهانينا!';
index 155594c..3ae9a6d 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://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
@@ -13,7 +12,7 @@
 // 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/>.
+// along with Moodle.  If not, see <https://www.gnu.org/licenses/>.
 
 /**
  * Automatically generated strings for Moodle installer
@@ -31,4 +30,4 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['thisdirection'] = 'rtl';
-$string['thislanguage'] = 'عربÙ\8a';
+$string['thislanguage'] = 'اÙ\84عربÙ\8aØ©';
index 8207932..8bd207d 100644 (file)
@@ -1,6 +1,5 @@
 <?php
-
-// This file is part of Moodle - http://moodle.org/
+// This file is part of Moodle - https://moodle.org/
 //
 // Moodl