Compare commits
382 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0fae900b58 | |||
| 202cd371a1 | |||
| e60107a0d3 | |||
| 1c6dcd21f9 | |||
| 0be2c46692 | |||
| 4027a6f9fb | |||
| 2fc493dd9f | |||
| 25f8ff2446 | |||
| 4287b7acd9 | |||
| a18d42a1bb | |||
| baabc32443 | |||
| 05d383cdff | |||
| d6087552d0 | |||
| 27c9eb38a0 | |||
| ea697ca8a0 | |||
| 5ba62ce7ae | |||
| e851069e97 | |||
| c231b4ff1b | |||
| 72f985e956 | |||
| 8284e13413 | |||
| 0919443d33 | |||
| cdca553678 | |||
| aeef022c1c | |||
| 2d3d946eef | |||
| fc4a4e6450 | |||
| abff12eda1 | |||
| 2570c08460 | |||
| b19ed507d1 | |||
| e5f40a62d4 | |||
| e3356e2a5a | |||
| 353b25f991 | |||
| f91555d94e | |||
| 8cba18bd0d | |||
| 5022583eec | |||
| c6abd93efb | |||
| 9893e93761 | |||
| af4fae4f5b | |||
| 1bfc8f2097 | |||
| aa7d3faddb | |||
| 05e3716ffe | |||
| f6c5e15bdf | |||
| 9ba9723826 | |||
| 716c223db5 | |||
| 8c6dbf8561 | |||
| fd13110bd4 | |||
| 2a5c62ab88 | |||
| bad9e0a1bc | |||
| b71d30097e | |||
| 1852ad42b5 | |||
| 3a0b800be7 | |||
| 9e7a6d1c79 | |||
| 7553895409 | |||
| 80a06b2966 | |||
| e9e77f32e9 | |||
| c3097aab8c | |||
| 290a7cffea | |||
| 92b235d31b | |||
| 9ea97cc350 | |||
| 62ed5dfd27 | |||
| dcabe38876 | |||
| 3c05e673a3 | |||
| 1fd4f4b11b | |||
| f5645cf4a8 | |||
| 4555270cfc | |||
| a49c1483aa | |||
| 7601dd8b7b | |||
| a50c324721 | |||
| 1885fd9a2f | |||
| 655cae8cc4 | |||
| aacd3761aa | |||
| ff437575bc | |||
| c57bb0107c | |||
| f057226154 | |||
| b946c528b0 | |||
| e835233465 | |||
| 724c4fa373 | |||
| 1bb6bd7381 | |||
| 1cd3788793 | |||
| 1d23929fa9 | |||
| 586168df7c | |||
| e52133c631 | |||
| baca8dd626 | |||
| f0817b2e97 | |||
| 1397ce352a | |||
| 33e98afe3c | |||
| c11c5d26cd | |||
| 6703d67439 | |||
| 277c0ffc0d | |||
| 6436f1532d | |||
| 95a95a80b0 | |||
| ebe39a84db | |||
| 5c261335c7 | |||
| 6b4edc0068 | |||
| 3fc4c17115 | |||
| 4a0793d898 | |||
| 91178b70f5 | |||
| 04bb96886d | |||
| 1eeb10cf08 | |||
| 201e5c1103 | |||
| 1635a0f1b0 | |||
| 3ca56cb7f1 | |||
| 62cfa26cb9 | |||
| b890f223e4 | |||
| e2eb63f1d9 | |||
| fc5eba83d2 | |||
| 51a25fac44 | |||
| 181e8f7686 | |||
| f5f3457173 | |||
| 58f411d2f1 | |||
| c90054e98e | |||
| 8412495f5e | |||
| 2382d6188e | |||
| 3f5d3f8952 | |||
| 7278c5f5b4 | |||
| 0d08af8de6 | |||
| 8585a70700 | |||
| 62d0d76fe1 | |||
| 710fa8ed7a | |||
| 64efaed528 | |||
| 9de063d19b | |||
| dd651bfe75 | |||
| a3984be80b | |||
| 926a143dd6 | |||
| c5a99daa0c | |||
| 1ceb4e2691 | |||
| d46f7f29ce | |||
| 8d2296ef33 | |||
| b961e519cf | |||
| 7995a6a7c9 | |||
| fc1adc914c | |||
| 5003c32dd2 | |||
| 3bb68aefc0 | |||
| 8304ad73a7 | |||
| 146441bf58 | |||
| e3264a1ebc | |||
| 960a32b2ae | |||
| 0082649a28 | |||
| 6e9ff0e536 | |||
| 0e23d91ec3 | |||
| a9cc05c9fd | |||
| 06d446aec1 | |||
| bef92dfbdc | |||
| 63a788899f | |||
| f5f57ba477 | |||
| 13a1d1d661 | |||
| 223cdb0ed9 | |||
| c3f0e5ddaa | |||
| 77d822898a | |||
| 95b47d2432 | |||
| b7c2924b68 | |||
| 73d25ec0c6 | |||
| d418ca209e | |||
| a1d646d621 | |||
| e431f3a4d6 | |||
| 415c9de634 | |||
| 86cc29f021 | |||
| 7dc9c54ff6 | |||
| 4200e6ee16 | |||
| 8ce95fe759 | |||
| b60518501f | |||
| 3178dd5bb2 | |||
| e8bbcdae2c | |||
| 0b6625e736 | |||
| 079a2e0061 | |||
| c0786c11c0 | |||
| 6458658400 | |||
| c3c22e7219 | |||
| d38a0b2100 | |||
| 2cde600dd2 | |||
| ce4622ec99 | |||
| 8c455b4ad6 | |||
| fd5559e3d4 | |||
| acc02e0631 | |||
| e6ff8205f9 | |||
| c5c621dfce | |||
| 6df8e613be | |||
| 484516b450 | |||
| 8d68d6c050 | |||
| 4a1e1081a5 | |||
| 72342d4c08 | |||
| 6f91919237 | |||
| 467d99b7bb | |||
| 2580e7d399 | |||
| 89e2da51c9 | |||
| 7ab289879a | |||
| a15668409e | |||
| 8c2b43f133 | |||
| cdf532cf84 | |||
| 2f794ccb3d | |||
| 3130c83f02 | |||
| fcedef4566 | |||
| d13319f328 | |||
| f244de5a77 | |||
| 98c8165f6a | |||
| 4ccd18f6be | |||
| e99051aabd | |||
| 0e6bc44970 | |||
| 49af8b6508 | |||
| e2e6e1407f | |||
| a47f28ee75 | |||
| 2f15514fa4 | |||
| 831f0cf6ce | |||
| cb2fa7a92d | |||
| 1517a26b7e | |||
| 41bd934db1 | |||
| 162dfaaf85 | |||
| e8cc15ecaa | |||
| 31b6436f90 | |||
| 5a81c72bac | |||
| f291f78cab | |||
| bfddf75448 | |||
| fce1784938 | |||
| 846b0c890c | |||
| 345c4a6a3c | |||
| 6c82a06f49 | |||
| f71d5a9b52 | |||
| fe269e1bac | |||
| 31db9d0c57 | |||
| 20437979e6 | |||
| a9b0d53459 | |||
| 8d36719bc3 | |||
| f6ec6e9dce | |||
| cafd97276a | |||
| 8e20336b30 | |||
| 2c3c32e29e | |||
| 3fced488b3 | |||
| 44c94ffad4 | |||
| b8604c273c | |||
| ea5d5ea519 | |||
| c7f1203480 | |||
| d57345bf06 | |||
| 589ca9aec6 | |||
| ebaec57bb2 | |||
| 0888a32602 | |||
| 326296c482 | |||
| b93cb20e48 | |||
| d7d375ed14 | |||
| 44d77d0848 | |||
| 5169dd0f8b | |||
| 002ed2d867 | |||
| 0ebbecff73 | |||
| 941203b502 | |||
| 9f876fe558 | |||
| ebeb9a87fc | |||
| bac3842abc | |||
| 4efc9efd9b | |||
| 1278c93a06 | |||
| b7334e05db | |||
| e900f15c57 | |||
| 2b4711fdcd | |||
| 16d81dabab | |||
| e844d6d366 | |||
| 28c1597e5a | |||
| 8c08aeb863 | |||
| 1914fe6604 | |||
| b0cc1c096a | |||
| 61737d06c5 | |||
| 45b117f8e7 | |||
| db37e1eb58 | |||
| feb10fbea9 | |||
| d2306d35c6 | |||
| ddff113f3b | |||
| b9a36a1562 | |||
| 5dd03dc296 | |||
| 5563c74c95 | |||
| 7aacb04321 | |||
| 073901d019 | |||
| cd7ec775ae | |||
| 3419329a12 | |||
| 7821816fdd | |||
| 93f6ce8bfe | |||
| 584c42e14d | |||
| a252f3ca77 | |||
| fecc3e0fa1 | |||
| 2756ebfc7c | |||
| a279eba2f1 | |||
| 5160aa199e | |||
| f2a4f26708 | |||
| 21ebba9e39 | |||
| 23e26675ff | |||
| a2b88160d7 | |||
| edc5b03aa1 | |||
| 36c92bc955 | |||
| 0004ba1d1b | |||
| bdb6fb7baf | |||
| d92966f83e | |||
| 70fdaa51aa | |||
| 16e2822e90 | |||
| 9842833fc1 | |||
| 69395127e0 | |||
| c1bc2d4dd2 | |||
| a4a9984650 | |||
| 0b0874b063 | |||
| 9c3af6a9ae | |||
| cf6901bb9c | |||
| 37da5b7176 | |||
| f829545013 | |||
| b79f853484 | |||
| d851bb1ad3 | |||
| 720007a54c | |||
| 5d7411d864 | |||
| 7e4ef00e6d | |||
| 6299d39bf2 | |||
| b56a5e0dfb | |||
| 6be9700e32 | |||
| 4369ac81a7 | |||
| 4f5795037e | |||
| b3e9ba1785 | |||
| fc88017acf | |||
| 4f0c9f4f4b | |||
| 74bde5fb35 | |||
| 58bef2f34e | |||
| f4965f1c72 | |||
| f5666cffda | |||
| ebd0c7fe8c | |||
| 73a7a74d92 | |||
| ae60dd25f6 | |||
| 029e6e7d89 | |||
| e8719fd65a | |||
| c499c7079f | |||
| 66c35154b8 | |||
| b11dbf60c0 | |||
| 4400c34168 | |||
| 365fff0ff2 | |||
| 0386f27ba1 | |||
| a493821bcc | |||
| d3d62a087b | |||
| 45730b9a07 | |||
| a73cddb9f9 | |||
| 83bb155b67 | |||
| 8f8cea4f03 | |||
| f95c68c141 | |||
| f5ec0df5d5 | |||
| 539b6b6c85 | |||
| 28226981fc | |||
| fa558bdbdc | |||
| f5babd9a75 | |||
| f8a081f660 | |||
| a0115a8578 | |||
| 1d8744377f | |||
| 7d9c52b6bd | |||
| 21aba2fb63 | |||
| d5f6993327 | |||
| 9f6fcd1e47 | |||
| 9c4637c086 | |||
| a5fb38a57c | |||
| 72773d10f6 | |||
| e926de79f3 | |||
| 1037818475 | |||
| 93a6761b9e | |||
| 13bc06e37d | |||
| e961a93ee8 | |||
| 6cec3844dc | |||
| 3c44c156e6 | |||
| cd685999fa | |||
| 56dc60887c | |||
| 76bb28ab0b | |||
| f28a05b21c | |||
| c7f189da0f | |||
| 69d187f94b | |||
| 644d3a5b3f | |||
| 963379d7a8 | |||
| 366e1fae05 | |||
| a8e796311e | |||
| dcb19eebc2 | |||
| 5ed130b575 | |||
| 587c9406a3 | |||
| f2a95bf7fa | |||
| 914e611bd1 | |||
| e6eb08a448 | |||
| 4269b654b6 | |||
| f52cc16d34 | |||
| 5aae7cc4aa | |||
| ad87801d2d | |||
| 46cb0bc324 | |||
| 77e664ce4a | |||
| ac754da8f2 | |||
| 492a8726e2 | |||
| a7d6f79bdd | |||
| 1bde415012 | |||
| 940006d39f | |||
| fd14e16617 |
@@ -66,7 +66,7 @@ jobs:
|
||||
steps:
|
||||
- name: Setting up DB mysql
|
||||
if: ${{ matrix.db == 'mysqli' }}
|
||||
uses: johanmeiring/mysql-action@tmpfs-patch
|
||||
uses: moodlehq/mysql-action@v1
|
||||
with:
|
||||
collation server: utf8mb4_bin
|
||||
mysql version: 5.7
|
||||
@@ -74,6 +74,8 @@ jobs:
|
||||
mysql user: test
|
||||
mysql password: test
|
||||
use tmpfs: true
|
||||
tmpfs size: '1024M'
|
||||
extra conf: --skip-log-bin
|
||||
|
||||
- name: Setting up DB pgsql
|
||||
if: ${{ matrix.db == 'pgsql' }}
|
||||
|
||||
+3
-1
@@ -81,7 +81,8 @@ install:
|
||||
sudo service mysql stop
|
||||
sudo mv /var/lib/mysql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/mysql /var/lib/mysql
|
||||
sudo service mysql restart
|
||||
echo -e "[mysqld]\nskip-log-bin" | sudo tee -a /etc/mysql/my.cnf
|
||||
sudo service mysql start
|
||||
fi
|
||||
- >
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
@@ -92,6 +93,7 @@ install:
|
||||
sudo mv /var/lib/postgresql /mnt/ramdisk
|
||||
sudo ln -s /mnt/ramdisk/postgresql /var/lib/postgresql
|
||||
sudo service postgresql start 9.6
|
||||
sh -c 'until pg_isready -p 5432; do echo "Waiting for the DB to be up..."; sleep 2; done'
|
||||
fi
|
||||
- >
|
||||
if [ "$TASK" = 'PHPUNIT' ];
|
||||
|
||||
+53
-35
@@ -1,48 +1,66 @@
|
||||
MOODLE TRADEMARKS POLICY
|
||||
========================
|
||||
|
||||
The word "Moodle" is trademarked in many countries around the world. The word
|
||||
was originally coined as an acronym: Modular Object-Oriented Dynamic Learning
|
||||
Environment. The trademark is owned by Martin Dougiamas, Founder and Director
|
||||
of Moodle.
|
||||
The Moodle Trademark
|
||||
--------------------
|
||||
|
||||
The law obligates trademark owners to police their marks and prevent the use of
|
||||
confusingly similar names by third parties. Through this policy we’d like to
|
||||
make it clear how Moodle-related projects, organisations, and people can use
|
||||
the Moodle trademark. We’d also like to be clear about how use of the word is
|
||||
restricted when used to promote commercial Moodle services. We do this to
|
||||
protect the very business model that allows us to continue developing Moodle
|
||||
for you.
|
||||
The brand and word "Moodle" has trade mark protection in many countries around
|
||||
the world. Various Moodle™ trade marks are owned by either Moodle Pty Ltd or
|
||||
one of its associated entities. The law obligates trade mark owners to police
|
||||
their trade marks and prevent the use of confusingly similar names by
|
||||
third parties.
|
||||
|
||||
Allowed uses
|
||||
------------
|
||||
We have created a more concise and thorough set of Trademark Guidelines
|
||||
(https://moodle.com/wp-content/uploads/2023/02/Moodle-Trademark-Guidelines-2023-4.pdf)
|
||||
to help you understand how to comply with Moodle's trade mark requirements.
|
||||
The Trademark Guidelines will also assist our Moodle Certified Partners and the
|
||||
community to understand some of the principles that inform Moodle's stance
|
||||
whenever potential infringement has been detected by us or our community.
|
||||
|
||||
The following uses don’t require any permission at all:
|
||||
We need to be clear about use of the word "Moodle" and how we restrict its use
|
||||
when promoting commercial Moodle™ branded services. The proper use of
|
||||
trade marks reliably assures consumers about the quality of the associated
|
||||
products or services and where they have been derived from. Because the
|
||||
Moodle LMS is made available under the open source ‘GNU General Public License'
|
||||
that permits you to modify the copyrighted software, the distribution of such
|
||||
modified software in combination with Moodle trade marks can potentially
|
||||
mislead others in the community. To be clear, the GNU GPL does not include an
|
||||
implied right or licence to use Moodle's trade marks.
|
||||
|
||||
* Referring to the software or the Moodle project.
|
||||
* Describing your own Moodle implementation (including within corporate
|
||||
settings).
|
||||
We do all this to protect the very business model that allows us to continue
|
||||
developing various Moodle software solutions for you.
|
||||
|
||||
Allowed uses of "Moodle"
|
||||
------------------------
|
||||
|
||||
The following uses don't require any permission at all:
|
||||
|
||||
* Referring to the software or the Moodle project as the "Moodle™ software"
|
||||
or the "Moodle™ project"
|
||||
* Describing your own implementation of the Moodle™ software platform
|
||||
(including within corporate settings).
|
||||
* Describing a Moodle-based community hub.
|
||||
* Describing some software you’ve made that integrates with Moodle
|
||||
(eg a Moodle integration feature on another system).
|
||||
* Describing certain software you've made that integrates with Moodle™
|
||||
branded software (e.g. a Moodle™ integration feature on another system).
|
||||
|
||||
Restricted uses
|
||||
---------------
|
||||
Restricted uses of "Moodle"
|
||||
---------------------------
|
||||
|
||||
The following uses are generally prohibited without explicit and direct
|
||||
permission being granted to you by Moodle Pty Ltd. We do this to protect the
|
||||
Moodle project from software and sites which could confuse people. Please
|
||||
contact us to ask for permission in writing.
|
||||
Moodle™ project from software and sites which could confuse people. If in
|
||||
doubt, reach out for clarification at <trademarks@moodle.com>
|
||||
|
||||
* You can’t use "Moodle" in the name of your software (including Mobile apps)
|
||||
* You can’t use "Moodle" in your company name
|
||||
* You can’t use "Moodle" in your domain name
|
||||
* You can’t use "Moodle" in advertising-related keywords (such as Adsense)
|
||||
* You can’t use "Moodle" to describe services around Moodle (such as hosting,
|
||||
training, support, consulting, course creation services, theme development,
|
||||
customisation, installation, integration and certification). This applies
|
||||
even if you do not charge for the services. Note that usually only Moodle
|
||||
Partners have this permission.
|
||||
|
||||
For information about the Moodle Partner Certification Mark as well as for how
|
||||
to contact us, please see <https://moodle.com/trademarks/>.
|
||||
* You can't use the word "Moodle" or any Moodle logos for commercial purposes
|
||||
without prior written permission from Moodle HQ.
|
||||
* You can't use "Moodle" in the name of your software (including Mobile apps).
|
||||
* You can't use "Moodle" in your company name.
|
||||
* You can't use "Moodle" in your domain name.
|
||||
* You can't use "Moodle" in advertising-related keywords (such as Adsense).
|
||||
* You can't use "Moodle" to describe services around Moodle
|
||||
(such as hosting, training, support, consulting, course creation services,
|
||||
theme development, customisation, installation, integration, analytics
|
||||
and certification) that cause consumers to be confused that you are
|
||||
associated with Moodle HQ if you are not.
|
||||
This applies even if you do not charge for the services.
|
||||
Note that usually only Moodle Partners have this permission.
|
||||
|
||||
@@ -3924,4 +3924,191 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.2" requires="3.11.8">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="10.6.7" />
|
||||
<VENDOR name="mysql" version="8.0" />
|
||||
<VENDOR name="postgres" version="13" />
|
||||
<VENDOR name="mssql" version="14.0" />
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="mbstringrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="opensslrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="intlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
<PHP_EXTENSION name="fileinfo" level="required"/>
|
||||
<PHP_EXTENSION name="sodium" level="required"/>
|
||||
<PHP_EXTENSION name="exif" level="optional"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_libcurl_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="libcurlwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_format" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfileformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_file_per_table" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbfilepertable" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_large_prefix" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddblargeprefix" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_is_https" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="ishttpswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mysql_incomplete_unicode_support" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="incompleteunicodesupport" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_sixtyfour_bits" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="sixtyfourbitsrequired" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_max_input_vars" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_admin_dir_usage" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="iscustomadminwarnings" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
+10
-19
@@ -31,29 +31,20 @@
|
||||
|
||||
if (!empty($hide) and confirm_sesskey()) {
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
|
||||
$class::enable_plugin($hide, false);
|
||||
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
if ($class::enable_plugin($hide, false)) {
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
}
|
||||
redirect(new moodle_url('/admin/modules.php'));
|
||||
}
|
||||
|
||||
if (!empty($show) and confirm_sesskey()) {
|
||||
$canenablemodule = true;
|
||||
$modulename = $show;
|
||||
|
||||
// Invoking a callback function that enables plugins to force additional actions (e.g. displaying notifications,
|
||||
// modals, etc.) and also specify through its returned value (bool) whether the process of enabling the plugin
|
||||
// should continue after these actions or not.
|
||||
if (component_callback_exists("mod_{$modulename}", 'pre_enable_plugin_actions')) {
|
||||
$canenablemodule = component_callback("mod_{$modulename}", 'pre_enable_plugin_actions');
|
||||
}
|
||||
|
||||
if ($canenablemodule) {
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
|
||||
$class::enable_plugin($show, true);
|
||||
admin_get_root(true, false); // Settings not required - only pages.
|
||||
redirect(new moodle_url('/admin/modules.php'));
|
||||
if (!empty($show) && confirm_sesskey()) {
|
||||
$class = \core_plugin_manager::resolve_plugininfo_class('mod');
|
||||
if ($class::enable_plugin($show, true)) {
|
||||
// Settings not required - only pages.
|
||||
admin_get_root(true, false);
|
||||
}
|
||||
redirect(new moodle_url('/admin/modules.php'));
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
@@ -34,7 +34,7 @@ class adminpresets_admin_setting_configselect extends adminpresets_setting {
|
||||
*/
|
||||
protected function set_value($value) {
|
||||
// When we intantiate the class we need the choices.
|
||||
if (empty($this->settindata->choices) && method_exists($this->settingdata, 'load_choices')) {
|
||||
if (empty($this->settingdata->choices) && method_exists($this->settingdata, 'load_choices')) {
|
||||
$this->settingdata->load_choices();
|
||||
}
|
||||
|
||||
|
||||
+17
-29
@@ -24,6 +24,7 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
use core_question\local\bank\question_version_status;
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
@@ -42,36 +43,23 @@ $qtypes = question_bank::get_all_qtypes();
|
||||
$pluginmanager = core_plugin_manager::instance();
|
||||
|
||||
// Get some data we will need - question counts and which types are needed.
|
||||
$hiddenstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_HIDDEN;
|
||||
$draftstatus = \core_question\local\bank\question_version_status::QUESTION_STATUS_DRAFT;
|
||||
// The second JOIN on question_versions (qv2) is to get the latest version of each question.
|
||||
// (Using this sort of JOIN is a known trick for doing this in the fastest possible way.)
|
||||
$counts = $DB->get_records_sql("
|
||||
SELECT q.qtype,
|
||||
COUNT(qv.id) AS numquestions,
|
||||
SUM(CASE WHEN qv.status = :hiddenstatus THEN 1 ELSE 0 END) AS numhidden,
|
||||
SUM(CASE WHEN qv.status = :draftstatus THEN 1 ELSE 0 END) AS numdraft
|
||||
FROM {question} q
|
||||
JOIN {question_versions} qv ON q.id = qv.questionid
|
||||
LEFT JOIN {question_versions} qv2 ON qv.questionbankentryid = qv2.questionbankentryid AND qv.version < qv2.version
|
||||
WHERE qv2.questionbankentryid IS NULL
|
||||
GROUP BY q.qtype
|
||||
", [
|
||||
'hiddenstatus' => question_version_status::QUESTION_STATUS_HIDDEN,
|
||||
'draftstatus' => question_version_status::QUESTION_STATUS_DRAFT,
|
||||
]);
|
||||
|
||||
$sql = "SELECT result.qtype,
|
||||
SUM(result.numquestions) AS numquestions,
|
||||
SUM(result.numhidden) AS numhidden,
|
||||
SUM(result.numdraft) AS numdraft
|
||||
FROM (SELECT data.qtype,
|
||||
data.versionid,
|
||||
COUNT(data.numquestions) AS numquestions,
|
||||
(SELECT COUNT(qv.id)
|
||||
FROM {question_versions} qv
|
||||
WHERE qv.id = data.versionid
|
||||
AND qv.status = :hiddenstatus) AS numhidden,
|
||||
(SELECT COUNT(qv.id)
|
||||
FROM {question_versions} qv
|
||||
WHERE qv.id = data.versionid
|
||||
AND qv.status = :draftstatus) AS numdraft
|
||||
FROM (SELECT q.qtype, qv.id AS versionid, 1 AS numquestions
|
||||
FROM {question} q
|
||||
JOIN {question_versions} qv ON qv.questionid = q.id
|
||||
JOIN {question_bank_entries} qbe ON qbe.id = qv.questionbankentryid
|
||||
AND qv.version = (SELECT MAX(v.version)
|
||||
FROM {question_versions} v
|
||||
JOIN {question_bank_entries} be ON be.id = v.questionbankentryid
|
||||
WHERE be.id = qbe.id)) data
|
||||
GROUP BY data.qtype, data.versionid) result
|
||||
GROUP BY result.qtype";
|
||||
|
||||
$counts = $DB->get_records_sql($sql, ['hiddenstatus' => $hiddenstatus, 'draftstatus' => $draftstatus]);
|
||||
$needed = [];
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
if (!isset($counts[$qtypename])) {
|
||||
|
||||
@@ -477,7 +477,8 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp->add(new admin_setting_heading('automatedsettings', new lang_string('automatedsettings','backup'), new lang_string('recyclebin_desc', 'backup')));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_users', new lang_string('generalusers', 'backup'), new lang_string('configgeneralusers', 'backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_role_assignments', new lang_string('generalroleassignments','backup'), new lang_string('configgeneralroleassignments','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_activities', new lang_string('generalactivities','backup'), new lang_string('configgeneralactivities','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_activities', new lang_string('generalactivities', 'backup'),
|
||||
new lang_string('backupautoactivitiesdescription', 'backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_blocks', new lang_string('generalblocks','backup'), new lang_string('configgeneralblocks','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox(
|
||||
'backup/backup_auto_files',
|
||||
|
||||
@@ -35,9 +35,7 @@ Feature: Allowing multiple accounts to have the same email address
|
||||
| username | firstname | lastname | email |
|
||||
| s1 | John | Doe | s1@example.com |
|
||||
| s2 | Jane | Doe | s2@example.com |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on "Edit" "link" in the "Jane Doe" "table_row"
|
||||
When I am on the "s2" "user > editing" page logged in as "admin"
|
||||
And I set the field "Email address" to "<email>"
|
||||
And I press "Update profile"
|
||||
Then I should <expect> "This email address is already registered."
|
||||
|
||||
@@ -11,8 +11,11 @@ Feature: I can add a new preset with current settings
|
||||
And I set the field "Name" to "Starter"
|
||||
And I set the field "Description" to "Non-core starter preset"
|
||||
When I click on "Create preset" "button"
|
||||
Then I should see "Moodle with all of the most popular features" in the "Starter" "table_row"
|
||||
And I should see "Starter" in the "Non-core starter preset" "table_row"
|
||||
Then the following should exist in the "Site admin presets table" table:
|
||||
| Name | Description |
|
||||
| Starter | Moodle with all of the most popular features, including Assignment, Feedback, Forum, H5P, Quiz and Completion tracking. |
|
||||
| Full | All the Starter features plus External (LTI) tool, SCORM, Workshop, Analytics, Badges, Competencies, Learning plans and lots more. |
|
||||
| Starter | Non-core starter preset |
|
||||
|
||||
Scenario: Export current settings
|
||||
Given I click on "Create preset" "button"
|
||||
|
||||
@@ -30,10 +30,9 @@ Feature: Verify that all form fields values can be get and set
|
||||
| student2 | G2 |
|
||||
| student3 | G2 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | idnumber | name | intro | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | Test this one | collaborative | 0 |
|
||||
And I log in as "admin"
|
||||
And I am on the "Course 1" "reset" page
|
||||
| activity | course | idnumber | name | firstpagetitle | wikimode | visible |
|
||||
| wiki | C1 | wiki1 | Test this one | Test this one | collaborative | 0 |
|
||||
And I am on the "Course 1" "reset" page logged in as admin
|
||||
# Select (multi-select) - Checking "the select box should contain".
|
||||
And I expand all fieldsets
|
||||
And the "Unenrol users" select box should contain "No roles"
|
||||
@@ -60,16 +59,14 @@ Feature: Verify that all form fields values can be get and set
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" ticked.
|
||||
And I set the field "Force format" to "1"
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value "1"
|
||||
And the field "Force format" does not match value ""
|
||||
# Checkbox - Checking "I set the field" and "The field matches value" unticked.
|
||||
And I set the field "Force format" to ""
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the field "Force format" matches value ""
|
||||
And the field "Force format" does not match value "1"
|
||||
@@ -77,8 +74,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | 1 |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | 1 |
|
||||
@@ -88,8 +84,7 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I set the following fields to these values:
|
||||
| Force format | |
|
||||
And I press "Save and return to course"
|
||||
And I am on the "Test this one" "wiki activity" page
|
||||
And I navigate to "Settings" in current page administration
|
||||
And I am on the "Test this one" "wiki activity editing" page
|
||||
And I expand all fieldsets
|
||||
And the following fields match these values:
|
||||
| Force format | |
|
||||
@@ -142,10 +137,11 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I navigate to "Settings" in current page administration
|
||||
And the field "Course ID number" matches value "Course id number"
|
||||
|
||||
Scenario: with JS disabled all form fields getters and setters works as expected
|
||||
|
||||
@javascript
|
||||
Scenario: with JS enabled all form fields getters and setters works as expected
|
||||
Given the following "activities" exist:
|
||||
| activity | course | name |
|
||||
| lesson | C1 | Test lesson |
|
||||
Then I am on the "Course 1" "groups" page
|
||||
# Select (multi-select & AJAX) - Checking "I set the field" and "select box should contain".
|
||||
And I set the field "groups" to "Group 2"
|
||||
@@ -157,11 +153,8 @@ Feature: Verify that all form fields values can be get and set
|
||||
And the "members" select box should contain "Student 2 (s2@example.com)"
|
||||
And the "members" select box should not contain "Student 3 (s3@example.com)"
|
||||
# Checkbox (AJAX) - Checking "I set the field" and "I set the following fields to these values".
|
||||
And I am on "Course 1" course homepage
|
||||
And I add a "Lesson" to section "1"
|
||||
And I am on the "Test lesson" "lesson activity editing" page
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson |
|
||||
| Description | Test lesson description |
|
||||
| available[enabled] | 1 |
|
||||
And I set the field "deadline[enabled]" to "1"
|
||||
# Checkbox (AJAX) - Checking "the field matches value" before saving.
|
||||
|
||||
@@ -48,12 +48,7 @@ class accessibility {
|
||||
public static function is_accessibility_enabled(): bool {
|
||||
global $CFG;
|
||||
|
||||
if (isset($CFG->enableaccessibilitytools)) {
|
||||
return $CFG->enableaccessibilitytools;
|
||||
}
|
||||
|
||||
// Enabled by default.
|
||||
return true;
|
||||
return !empty($CFG->enableaccessibilitytools);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -274,7 +274,7 @@ $string['requesttypedelete'] = 'Delete all of my personal data';
|
||||
$string['requesttypedeleteshort'] = 'Delete';
|
||||
$string['requesttypeexport'] = 'Export all of my personal data';
|
||||
$string['requesttypeexportshort'] = 'Export';
|
||||
$string['requesttypeothers'] = 'General inquiry';
|
||||
$string['requesttypeothers'] = 'General enquiry';
|
||||
$string['requesttypeothersshort'] = 'Message';
|
||||
$string['requireallenddatesforuserdeletion'] = 'Consider courses without end date as active';
|
||||
$string['requireallenddatesforuserdeletion_desc'] = 'When calculating user expiry, several factors are considered:
|
||||
|
||||
@@ -20,7 +20,7 @@ Feature: Contact the privacy officer
|
||||
And I click on "Send" "button" in the "Contact the privacy officer" "dialogue"
|
||||
Then I should see "Your request has been submitted to the privacy officer"
|
||||
And I click on "Data requests" "link"
|
||||
And I should see "Hello DPO!" in the "General inquiry" "table_row"
|
||||
And I should see "Hello DPO!" in the "General enquiry" "table_row"
|
||||
|
||||
Scenario: Contacting the privacy officer when not enabled
|
||||
When I log in as "student1"
|
||||
|
||||
+1
-1
@@ -5,6 +5,6 @@ define("tool_langimport/search",["exports","core/pending","core/utils"],(functio
|
||||
* @module tool_langimport/search
|
||||
* @copyright 2021 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};const SELECTORS_AVAILABLE_LANG_SELECT="select",SELECTORS_AVAILABLE_LANG_SEARCH='[data-action="search"]';var _default={init:form=>{const availableLangsElement=form.querySelector(SELECTORS_AVAILABLE_LANG_SELECT),availableLangsFilter=event=>{const pendingPromise=new _pending.default("tool_langimport/search:filter");availableLangsElement.querySelectorAll("option").forEach((option=>{option.remove()}));const searchTerm=event.target.value.toLowerCase(),availableLanguages=JSON.parse(availableLangsElement.dataset.availableLanguages),filteredLanguages=Object.keys(availableLanguages).reduce(((matches,langcode)=>(availableLanguages[langcode].toLowerCase().includes(searchTerm)&&(matches[langcode]=availableLanguages[langcode]),matches)),[]);Object.entries(filteredLanguages).forEach((_ref=>{let[langcode,langname]=_ref;const option=document.createElement("option");option.value=langcode,option.innerText=langname,availableLangsElement.append(option)})),pendingPromise.resolve()},availableLanguages={};availableLangsElement.querySelectorAll("option").forEach((option=>{availableLanguages[option.value]=option.text})),availableLangsElement.dataset.availableLanguages=JSON.stringify(availableLanguages);const availableLangsSearch=form.querySelector(SELECTORS_AVAILABLE_LANG_SEARCH);availableLangsSearch.addEventListener("keydown",(event=>{"Enter"===event.key&&event.preventDefault()})),availableLangsSearch.addEventListener("keyup",(event=>{const pendingPromise=new _pending.default("tool_langimport/search:keyup");(0,_utils.debounce)(availableLangsFilter,250)(event),setTimeout((()=>{pendingPromise.resolve()}),250)}))}};return _exports.default=_default,_exports.default}));
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};const SELECTORS_AVAILABLE_LANG_SELECT="select",SELECTORS_AVAILABLE_LANG_SEARCH='[data-action="search"]';_exports.init=form=>{const availableLangsElement=form.querySelector(SELECTORS_AVAILABLE_LANG_SELECT),availableLanguages={};availableLangsElement.querySelectorAll("option").forEach((option=>{availableLanguages[option.value]=option.text})),availableLangsElement.dataset.availableLanguages=JSON.stringify(availableLanguages);const availableLangsSearch=form.querySelector(SELECTORS_AVAILABLE_LANG_SEARCH);availableLangsSearch.addEventListener("keydown",(event=>{"Enter"===event.key&&event.preventDefault()}));const availableLangsSearchDebounce=(0,_utils.debounce)((event=>{const pendingPromise=new _pending.default("tool_langimport/search:filter");availableLangsElement.querySelectorAll("option").forEach((option=>{option.remove()}));const searchTerm=event.target.value.toLowerCase(),availableLanguages=JSON.parse(availableLangsElement.dataset.availableLanguages),filteredLanguages=Object.keys(availableLanguages).reduce(((matches,langcode)=>(availableLanguages[langcode].toLowerCase().includes(searchTerm)&&(matches[langcode]=availableLanguages[langcode]),matches)),[]);Object.entries(filteredLanguages).forEach((_ref=>{let[langcode,langname]=_ref;const option=document.createElement("option");option.value=langcode,option.innerText=langname,availableLangsElement.append(option)})),pendingPromise.resolve()}),250);availableLangsSearch.addEventListener("keyup",(event=>{const pendingPromise=new _pending.default("tool_langimport/search:keyup");availableLangsSearchDebounce(event),setTimeout((()=>{pendingPromise.resolve()}),250)}))}}));
|
||||
|
||||
//# sourceMappingURL=search.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -36,7 +36,7 @@ const DEBOUNCE_TIMER = 250;
|
||||
*
|
||||
* @param {Element} form
|
||||
*/
|
||||
const init = (form) => {
|
||||
export const init = form => {
|
||||
const availableLangsElement = form.querySelector(SELECTORS.AVAILABLE_LANG_SELECT);
|
||||
|
||||
const availableLangsFilter = (event) => {
|
||||
@@ -84,16 +84,13 @@ const init = (form) => {
|
||||
});
|
||||
|
||||
// Debounce the event listener to allow the user to finish typing.
|
||||
const availableLangsSearchDebounce = debounce(availableLangsFilter, DEBOUNCE_TIMER);
|
||||
availableLangsSearch.addEventListener('keyup', (event) => {
|
||||
const pendingPromise = new Pending('tool_langimport/search:keyup');
|
||||
|
||||
debounce(availableLangsFilter, DEBOUNCE_TIMER)(event);
|
||||
availableLangsSearchDebounce(event);
|
||||
setTimeout(() => {
|
||||
pendingPromise.resolve();
|
||||
}, DEBOUNCE_TIMER);
|
||||
});
|
||||
};
|
||||
|
||||
export default {
|
||||
init: init,
|
||||
};
|
||||
|
||||
@@ -33,3 +33,26 @@ Feature: Licence manager
|
||||
And "This is the site default licence" "icon" should exist in the "cc" "table_row"
|
||||
And "Enable licence" "icon" should not exist in the "cc" "table_row"
|
||||
And "This is the site default licence" "icon" should not exist in the "public" "table_row"
|
||||
|
||||
@javascript @_file_upload
|
||||
Scenario Outline: User licence preference is remembered depending of setting value
|
||||
Given the following config values are set as admin:
|
||||
| sitedefaultlicense | cc |
|
||||
| rememberuserlicensepref | <rememberuserlicensepref> |
|
||||
And I log in as "admin"
|
||||
And I follow "Private files" in the user menu
|
||||
And I follow "Add..."
|
||||
And I follow "Upload a file"
|
||||
And the field with xpath "//select[@name='license']" matches value "Creative Commons"
|
||||
And I click on "Close" "button" in the "File picker" "dialogue"
|
||||
When I upload "lib/tests/fixtures/empty.txt" file to "Files" filemanager as:
|
||||
| Save as | empty_copy.txt |
|
||||
| license | Public domain |
|
||||
And I press "Save changes"
|
||||
And I follow "Add..."
|
||||
Then the field with xpath "//select[@name='license']" matches value "<expectedlicence>"
|
||||
|
||||
Examples:
|
||||
| rememberuserlicensepref | expectedlicence |
|
||||
| 0 | Creative Commons |
|
||||
| 1 | Public domain |
|
||||
|
||||
@@ -33,8 +33,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests log writing.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_log_writing(bool $jsonformat) {
|
||||
global $DB, $CFG;
|
||||
@@ -252,9 +251,9 @@ class store_test extends \advanced_testcase {
|
||||
* Returns different JSON format settings so the test can be run with JSON format either on or
|
||||
* off.
|
||||
*
|
||||
* @return [bool] Array of true/false
|
||||
* @return bool[] Array of true/false
|
||||
*/
|
||||
public static function test_log_writing_provider(): array {
|
||||
public static function log_writing_provider(): array {
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
@@ -311,17 +310,16 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_database');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_database');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,20 +217,19 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive',
|
||||
'report_outline' => '/report/outline',
|
||||
'report_participation' => '/report/participation',
|
||||
'report_stats' => '/report/stats'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_legacy');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
'outline' => 'report_outline',
|
||||
'participation' => 'report_participation',
|
||||
'stats' => 'report_stats'
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_legacy');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -38,8 +38,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests log writing.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_log_writing(bool $jsonformat) {
|
||||
global $DB;
|
||||
@@ -223,9 +222,9 @@ class store_test extends \advanced_testcase {
|
||||
* Returns different JSON format settings so the test can be run with JSON format either on or
|
||||
* off.
|
||||
*
|
||||
* @return [bool] Array of true/false
|
||||
* @return bool[] Array of true/false
|
||||
*/
|
||||
public static function test_log_writing_provider(): array {
|
||||
public static function log_writing_provider(): array {
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
@@ -239,20 +238,19 @@ class store_test extends \advanced_testcase {
|
||||
$logmanager = get_log_manager();
|
||||
$allreports = \core_component::get_plugin_list('report');
|
||||
|
||||
$supportedreports = array(
|
||||
'report_log' => '/report/log',
|
||||
'report_loglive' => '/report/loglive',
|
||||
'report_outline' => '/report/outline',
|
||||
'report_participation' => '/report/participation',
|
||||
'report_stats' => '/report/stats'
|
||||
);
|
||||
|
||||
// Make sure all supported reports are installed.
|
||||
$expectedreports = array_keys(array_intersect_key($allreports, $supportedreports));
|
||||
$reports = $logmanager->get_supported_reports('logstore_standard');
|
||||
$reports = array_keys($reports);
|
||||
$expectedreports = array_intersect_key([
|
||||
'log' => 'report_log',
|
||||
'loglive' => 'report_loglive',
|
||||
'outline' => 'report_outline',
|
||||
'participation' => 'report_participation',
|
||||
'stats' => 'report_stats'
|
||||
], $allreports);
|
||||
|
||||
$supportedreports = $logmanager->get_supported_reports('logstore_standard');
|
||||
|
||||
foreach ($expectedreports as $expectedreport) {
|
||||
$this->assertContains($expectedreport, $reports);
|
||||
$this->assertArrayHasKey($expectedreport, $supportedreports);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +366,7 @@ class store_test extends \advanced_testcase {
|
||||
* Tests the decode_other function can cope with both JSON and PHP serialized format.
|
||||
*
|
||||
* @param mixed $value Value to encode and decode
|
||||
* @dataProvider test_decode_other_provider
|
||||
* @dataProvider decode_other_provider
|
||||
*/
|
||||
public function test_decode_other($value) {
|
||||
$this->assertEquals($value, \logstore_standard\log\store::decode_other(serialize($value)));
|
||||
@@ -387,7 +385,7 @@ class store_test extends \advanced_testcase {
|
||||
*
|
||||
* @return array Array of parameters
|
||||
*/
|
||||
public function test_decode_other_provider(): array {
|
||||
public function decode_other_provider(): array {
|
||||
return [
|
||||
[['info' => 'd2819896', 'logurl' => 'discuss.php?d=2819896']],
|
||||
[null],
|
||||
@@ -400,8 +398,7 @@ class store_test extends \advanced_testcase {
|
||||
* Checks that backup and restore of log data works correctly.
|
||||
*
|
||||
* @param bool $jsonformat True to test with JSON format
|
||||
* @dataProvider test_log_writing_provider
|
||||
* @throws moodle_exception
|
||||
* @dataProvider log_writing_provider
|
||||
*/
|
||||
public function test_backup_restore(bool $jsonformat) {
|
||||
global $DB;
|
||||
|
||||
@@ -229,7 +229,6 @@ class page_helper {
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading(fullname($user));
|
||||
|
||||
if (!empty($plan)) {
|
||||
$PAGE->navbar->add($title, $planurl);
|
||||
@@ -303,7 +302,6 @@ class page_helper {
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading(fullname($user));
|
||||
|
||||
if (!empty($evidence)) {
|
||||
$PAGE->navbar->add($title, $evidenceurl);
|
||||
|
||||
@@ -59,22 +59,26 @@ class api_test extends \externallib_advanced_testcase {
|
||||
*/
|
||||
public function test_get_potential_config_issues() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
|
||||
$this->resetAfterTest(true);
|
||||
$this->setAdminUser();
|
||||
|
||||
$CFG->userquota = '73289234723498234723423489273423497234234';
|
||||
// Set non-SSL wwwroot, to avoid spurious certificate checking.
|
||||
$CFG->wwwroot = 'http://www.example.com';
|
||||
$CFG->debugdisplay = 1;
|
||||
|
||||
set_config('debugauthdb', 1, 'auth_db');
|
||||
set_config('debugdb', 1, 'enrol_database');
|
||||
$expectedissues = array('adodbdebugwarning', 'displayerrorswarning');
|
||||
|
||||
// Get potential issues, obtain their keys for comparison.
|
||||
$issues = api::get_potential_config_issues();
|
||||
$this->assertCount(count($expectedissues), $issues);
|
||||
foreach ($issues as $issue) {
|
||||
$this->assertTrue(in_array($issue[0], $expectedissues));
|
||||
}
|
||||
$issuekeys = array_column($issues, 0);
|
||||
|
||||
$this->assertEqualsCanonicalizing([
|
||||
'nohttpsformobilewarning',
|
||||
'adodbdebugwarning',
|
||||
'displayerrorswarning',
|
||||
], $issuekeys);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -108,7 +108,7 @@ class issuer extends persistent {
|
||||
$mform->addHelpButton('clientsecret', 'issuerclientsecret', 'tool_oauth2');
|
||||
|
||||
// Use basic authentication.
|
||||
$mform->addElement('checkbox', 'basicauth', get_string('usebasicauth', 'tool_oauth2'));
|
||||
$mform->addElement('advcheckbox', 'basicauth', get_string('usebasicauth', 'tool_oauth2'));
|
||||
$mform->addHelpButton('basicauth', 'usebasicauth', 'tool_oauth2');
|
||||
|
||||
// Base Url.
|
||||
@@ -244,7 +244,6 @@ class issuer extends persistent {
|
||||
* @return array of additional errors, or overridden errors.
|
||||
*/
|
||||
protected function extra_validation($data, $files, array &$errors) {
|
||||
$errors = [];
|
||||
if ($data->showonloginpage != \core\oauth2\issuer::SERVICEONLY) {
|
||||
if (!strlen(trim($data->loginscopes))) {
|
||||
$errors['loginscopes'] = get_string('required');
|
||||
|
||||
@@ -218,9 +218,13 @@ Feature: Basic OAuth2 functionality
|
||||
| Name | Invalid custom service |
|
||||
| Client ID | thisistheclientid |
|
||||
| Client secret | supersecret |
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
| Service base URL | http://dc.imsglobal.org/ |
|
||||
When I press "Save changes"
|
||||
Then I should see "Could not discover end points for identity issuer: Invalid custom service"
|
||||
Then I should see "For security reasons only https connections are allowed, sorry"
|
||||
And I set the following fields to these values:
|
||||
| Service base URL | https://dc.imsglobal.org/ |
|
||||
And I press "Save changes"
|
||||
And I should see "Could not discover end points for identity issuer: Invalid custom service"
|
||||
And I should see "URL: https://dc.imsglobal.org/.well-known/openid-configuration"
|
||||
And "Allow services" "icon" should exist in the "Invalid custom service" "table_row"
|
||||
And "Do not allow login" "icon" should exist in the "Invalid custom service" "table_row"
|
||||
@@ -358,3 +362,21 @@ Feature: Basic OAuth2 functionality
|
||||
And I navigate to "Server > OAuth 2 services" in site administration
|
||||
And "Allow login" "icon" should exist in the "Empty custom service" "table_row"
|
||||
And "Do not allow services" "icon" should exist in the "Empty custom service" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Changes to "Authenticate token requests via HTTP headers" are saved
|
||||
Given I press "Custom"
|
||||
And I set the following fields to these values:
|
||||
| Name | Custom service |
|
||||
| Client ID | thisistheclientid |
|
||||
| Client secret | supersecret |
|
||||
And I press "Save changes"
|
||||
When I click on "Edit" "link" in the "Custom service" "table_row"
|
||||
And I click on "Authenticate token requests via HTTP headers" "checkbox"
|
||||
And I press "Save changes"
|
||||
And I click on "Edit" "link" in the "Custom service" "table_row"
|
||||
And the field "Authenticate token requests via HTTP headers" matches value "1"
|
||||
And I click on "Authenticate token requests via HTTP headers" "checkbox"
|
||||
And I press "Save changes"
|
||||
And I click on "Edit" "link" in the "Custom service" "table_row"
|
||||
Then the field "Authenticate token requests via HTTP headers" matches value ""
|
||||
|
||||
@@ -462,7 +462,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I am on site homepage
|
||||
And I change window size to "large"
|
||||
And I follow "Log in"
|
||||
When I press "Log in as a guest"
|
||||
When I press "Access as a guest"
|
||||
Then I should see "If you continue browsing this website, you agree to our policies"
|
||||
# Confirm when navigating, the pop-up policies are displayed.
|
||||
When I am on the "My courses" page
|
||||
@@ -626,7 +626,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I am on site homepage
|
||||
And I follow "Log in"
|
||||
# First log in as a guest
|
||||
And I press "Log in as a guest"
|
||||
And I press "Access as a guest"
|
||||
# Now sign up
|
||||
And I follow "Log in"
|
||||
When I click on "Create new account" "link"
|
||||
|
||||
@@ -133,6 +133,16 @@ class course_bin extends base_bin {
|
||||
\backup::MODE_AUTOMATED,
|
||||
$user->id
|
||||
);
|
||||
|
||||
// When "backup_auto_activities" setting is disabled, activities can't be restored from recycle bin.
|
||||
$plan = $controller->get_plan();
|
||||
$activitiessettings = $plan->get_setting('activities');
|
||||
$settingsvalue = $activitiessettings->get_value();
|
||||
if (empty($settingsvalue)) {
|
||||
$controller->destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
$controller->execute_plan();
|
||||
|
||||
// We don't need the forced setting anymore, hence unsetting it.
|
||||
|
||||
@@ -242,6 +242,29 @@ class course_bin_test extends \advanced_testcase {
|
||||
$this->assertEquals(true, $attemptobj->is_finished());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the activity is NOT stored in bin when
|
||||
* in Automated backup setup settings "backup_auto_activities" is disabled.
|
||||
*
|
||||
* @dataProvider recycle_bin_settings_provider
|
||||
* @covers ::store_item
|
||||
*/
|
||||
public function test_coursemodule_restore_with_activity_setting_disabled() {
|
||||
|
||||
// Set the configuration to not include activities in the automated backup.
|
||||
set_config('backup_auto_activities', false, 'backup');
|
||||
|
||||
// Delete the course module.
|
||||
course_delete_module($this->quiz->cmid);
|
||||
|
||||
// Now, run the course module deletion adhoc task.
|
||||
\phpunit_util::run_all_adhoc_tasks();
|
||||
|
||||
// Check there is no items in the recycle bin.
|
||||
$recyclebin = new \tool_recyclebin\course_bin($this->course->id);
|
||||
$this->assertEquals(0, count($recyclebin->get_items()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that user data is not restored when module is restored.
|
||||
*
|
||||
|
||||
@@ -38,15 +38,6 @@ use core\check\result;
|
||||
*/
|
||||
class adhocqueue extends check {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
$this->id = 'adhocqueue';
|
||||
$this->name = get_string('checkadhocqueue', 'tool_task');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return result
|
||||
* @return result
|
||||
|
||||
@@ -38,17 +38,14 @@ use core\check\result;
|
||||
class cronrunning extends check {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* A link the running tasks report
|
||||
*
|
||||
* @return action_link|null
|
||||
*/
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
$this->id = 'cronrunning';
|
||||
$this->name = get_string('checkcronrunning', 'tool_task');
|
||||
if (empty($CFG->cronclionly)) {
|
||||
$this->actionlink = new \action_link(
|
||||
new \moodle_url('/admin/cron.php'),
|
||||
get_string('cron', 'admin'));
|
||||
}
|
||||
public function get_action_link(): ?\action_link {
|
||||
return new \action_link(
|
||||
new \moodle_url('/admin/tool/task/runningtasks.php'),
|
||||
get_string('runningtasks', 'tool_task'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -39,15 +39,13 @@ use core\check\result;
|
||||
class maxfaildelay extends check {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
* Links to the task log report
|
||||
*
|
||||
* @return \action_link|null
|
||||
*/
|
||||
public function __construct() {
|
||||
global $CFG;
|
||||
$this->id = 'cronfaildelay';
|
||||
$this->name = get_string('checkmaxfaildelay', 'tool_task');
|
||||
$this->actionlink = new \action_link(
|
||||
new \moodle_url('/admin/tool/task/scheduledtasks.php'),
|
||||
get_string('scheduledtasks', 'tool_task'));
|
||||
public function get_action_link(): ?\action_link {
|
||||
$url = new \moodle_url('/admin/tasklogs.php');
|
||||
return new \action_link($url, get_string('tasklogs', 'tool_task'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -125,12 +125,10 @@ Feature: Upload users
|
||||
And I should see "Users created: 4"
|
||||
And I press "Continue"
|
||||
# Boost check.
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on ".icon[title=Edit]" "css_element" in the "jonest@example.com" "table_row"
|
||||
And I am on the "jonest@example.com" "user > editing" page
|
||||
And I should see "Boost"
|
||||
# Classic check.
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on ".icon[title=Edit]" "css_element" in the "reznor@example.com" "table_row"
|
||||
And I am on the "reznor@example.com" "user > editing" page
|
||||
And I should see "Classic"
|
||||
|
||||
@javascript
|
||||
|
||||
@@ -152,14 +152,11 @@ Feature: Apply tour filters to a tour
|
||||
| fullname | shortname | format | enablecompletion |
|
||||
| Course 1 | C1 | topics | 1 |
|
||||
| Course 2 | C2 | topics | 1 |
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | firstpagetitle | wikimode |
|
||||
| wiki | C1 | Test wiki name | First page | collaborative |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Wiki" to section "1" and I fill the form with:
|
||||
| Wiki name | Test wiki name |
|
||||
| Description | Test wiki description |
|
||||
| First page name | First page |
|
||||
| Wiki mode | Collaborative wiki |
|
||||
And I am on "Course 2" course homepage
|
||||
And I am on "Course 2" 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 |
|
||||
| Forum type | Standard forum for general use |
|
||||
|
||||
@@ -277,13 +277,13 @@ class condition extends \core_availability\condition {
|
||||
if (!isset($sectionprevious[$othercm->section])) {
|
||||
$sectionprevious[$othercm->section] = $lastcmid;
|
||||
}
|
||||
if ($lastcmid) {
|
||||
$this->modfastprevious[$othercm->id] = $lastcmid;
|
||||
}
|
||||
// Load previous to all cms with completion.
|
||||
if ($othercm->completion == COMPLETION_TRACKING_NONE) {
|
||||
continue;
|
||||
}
|
||||
if ($lastcmid) {
|
||||
$this->modfastprevious[$othercm->id] = $lastcmid;
|
||||
}
|
||||
$lastcmid = $othercm->id;
|
||||
}
|
||||
// Fill empty sections index.
|
||||
|
||||
@@ -380,7 +380,7 @@ class condition_test extends \advanced_testcase {
|
||||
/**
|
||||
* Tests the is_available and get_description functions for previous activity option.
|
||||
*
|
||||
* @dataProvider test_previous_activity_data
|
||||
* @dataProvider previous_activity_data
|
||||
* @param int $grade the current assign grade (0 for none)
|
||||
* @param int $condition true for complete, false for incomplete
|
||||
* @param string $mark activity to mark as complete
|
||||
@@ -469,7 +469,7 @@ class condition_test extends \advanced_testcase {
|
||||
$this->assertMatchesRegularExpression($description, $information);
|
||||
}
|
||||
|
||||
public function test_previous_activity_data(): array {
|
||||
public function previous_activity_data(): array {
|
||||
// Assign grade, condition, activity to complete, activity to test, result, resultnot, description.
|
||||
return [
|
||||
'Missing previous activity complete' => [
|
||||
@@ -561,7 +561,7 @@ class condition_test extends \advanced_testcase {
|
||||
* Tests the is_available and get_description functions for
|
||||
* previous activity option in course sections.
|
||||
*
|
||||
* @dataProvider test_section_previous_activity_data
|
||||
* @dataProvider section_previous_activity_data
|
||||
* @param int $condition condition value
|
||||
* @param bool $mark if Page 1 must be mark as completed
|
||||
* @param string $section section to add the availability
|
||||
@@ -634,7 +634,7 @@ class condition_test extends \advanced_testcase {
|
||||
|
||||
}
|
||||
|
||||
public function test_section_previous_activity_data(): array {
|
||||
public function section_previous_activity_data(): array {
|
||||
return [
|
||||
// Condition, Activity completion, section to test, result, resultnot, description.
|
||||
'Completion complete Section with no previous activity' => [
|
||||
|
||||
@@ -197,7 +197,12 @@ class condition extends \core_availability\condition {
|
||||
$this->customfield);
|
||||
}
|
||||
} else {
|
||||
$translatedfieldname = \core_user\fields::get_display_name($this->standardfield);
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (array_key_exists($this->standardfield, $standardfields)) {
|
||||
$translatedfieldname = $standardfields[$this->standardfield];
|
||||
} else {
|
||||
$translatedfieldname = get_string('missing', 'availability_profile', $this->standardfield);
|
||||
}
|
||||
}
|
||||
$a = new \stdClass();
|
||||
// Not safe to call format_string here; use the special function to call it later.
|
||||
@@ -321,6 +326,27 @@ class condition extends \core_availability\condition {
|
||||
return $fieldconditionmet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of standard user profile fields used by the condition
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public static function get_standard_profile_fields(): array {
|
||||
return [
|
||||
'firstname' => \core_user\fields::get_display_name('firstname'),
|
||||
'lastname' => \core_user\fields::get_display_name('lastname'),
|
||||
'email' => \core_user\fields::get_display_name('email'),
|
||||
'city' => \core_user\fields::get_display_name('city'),
|
||||
'country' => \core_user\fields::get_display_name('country'),
|
||||
'idnumber' => \core_user\fields::get_display_name('idnumber'),
|
||||
'institution' => \core_user\fields::get_display_name('institution'),
|
||||
'department' => \core_user\fields::get_display_name('department'),
|
||||
'phone1' => \core_user\fields::get_display_name('phone1'),
|
||||
'phone2' => \core_user\fields::get_display_name('phone2'),
|
||||
'address' => \core_user\fields::get_display_name('address'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets data about custom profile fields. Cached statically in current
|
||||
* request.
|
||||
@@ -472,6 +498,11 @@ class condition extends \core_availability\condition {
|
||||
$valuefield = 'data';
|
||||
$default = $customfield->defaultdata;
|
||||
} else {
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (!array_key_exists($this->standardfield, $standardfields)) {
|
||||
// If the field isn't found, nobody matches.
|
||||
return [];
|
||||
}
|
||||
$values = $DB->get_records_select('user', 'id ' . $sql, $params,
|
||||
'', 'id, '. $this->standardfield);
|
||||
$valuefield = $this->standardfield;
|
||||
@@ -595,6 +626,11 @@ class condition extends \core_availability\condition {
|
||||
$where = "(ud.data IS NOT NULL AND $condition)";
|
||||
}
|
||||
} else {
|
||||
$standardfields = self::get_standard_profile_fields();
|
||||
if (!array_key_exists($this->standardfield, $standardfields)) {
|
||||
// If the field isn't found, nobody matches.
|
||||
return ['SELECT id FROM {user} WHERE 0 = 1', []];
|
||||
}
|
||||
$tablesql = "JOIN {user} u ON u.id = userids.id";
|
||||
list ($where, $mainparams) = $this->get_condition_sql(
|
||||
'u.' . $this->standardfield);
|
||||
|
||||
@@ -42,20 +42,9 @@ class frontend extends \core_availability\frontend {
|
||||
|
||||
protected function get_javascript_init_params($course, \cm_info $cm = null,
|
||||
\section_info $section = null) {
|
||||
|
||||
// Standard user fields.
|
||||
$standardfields = array(
|
||||
'firstname' => \core_user\fields::get_display_name('firstname'),
|
||||
'lastname' => \core_user\fields::get_display_name('lastname'),
|
||||
'email' => \core_user\fields::get_display_name('email'),
|
||||
'city' => \core_user\fields::get_display_name('city'),
|
||||
'country' => \core_user\fields::get_display_name('country'),
|
||||
'idnumber' => \core_user\fields::get_display_name('idnumber'),
|
||||
'institution' => \core_user\fields::get_display_name('institution'),
|
||||
'department' => \core_user\fields::get_display_name('department'),
|
||||
'phone1' => \core_user\fields::get_display_name('phone1'),
|
||||
'phone2' => \core_user\fields::get_display_name('phone2'),
|
||||
'address' => \core_user\fields::get_display_name('address')
|
||||
);
|
||||
$standardfields = condition::get_standard_profile_fields();
|
||||
\core_collator::asort($standardfields);
|
||||
|
||||
// Custom fields.
|
||||
|
||||
@@ -39,7 +39,7 @@ $string['requires_notendswith'] = 'Your <strong>{$a->field}</strong> does not en
|
||||
$string['requires_notisequalto'] = 'Your <strong>{$a->field}</strong> is not <strong>{$a->value}</strong>';
|
||||
$string['requires_notstartswith'] = 'Your <strong>{$a->field}</strong> does not start with <strong>{$a->value}</strong>';
|
||||
$string['requires_startswith'] = 'Your <strong>{$a->field}</strong> starts with <strong>{$a->value}</strong>';
|
||||
$string['missing'] = '(Missing custom field: {$a})';
|
||||
$string['missing'] = '(Missing field: {$a})';
|
||||
$string['title'] = 'User profile';
|
||||
$string['op_contains'] = 'contains';
|
||||
$string['op_doesnotcontain'] = 'doesn\'t contain';
|
||||
|
||||
@@ -65,11 +65,8 @@ Feature: availability_profile
|
||||
Given the following "custom profile fields" exist:
|
||||
| datatype | shortname | name |
|
||||
| text | superfield | Super field |
|
||||
And I log in as "admin"
|
||||
|
||||
# Set field value for user.
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on ".icon[title=Edit]" "css_element" in the "s@example.com" "table_row"
|
||||
And I am on the "s@example.com" "user > editing" page logged in as "admin"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Super field" to "Bananaman"
|
||||
And I click on "Update profile" "button"
|
||||
|
||||
@@ -55,7 +55,7 @@ Feature: display_availability
|
||||
And I set the field "x[month]" to "March"
|
||||
And I press "Save and return to course"
|
||||
|
||||
# Add a Page with 2 restrictions - one is set to hide from students if failed.
|
||||
# Add a Page with 2 restrictions - one is set to Hide on course page if failed.
|
||||
And I add a "Page" to section "2"
|
||||
And I set the following fields to these values:
|
||||
| Name | Page 2 |
|
||||
|
||||
@@ -546,9 +546,11 @@ class backup_course_structure_step extends backup_structure_step {
|
||||
backup_helper::is_sqlparam('course'),
|
||||
backup::VAR_PARENTID));
|
||||
|
||||
// Section level settings are dealt with in backup_section_structure_step.
|
||||
// We only need to deal with course level (sectionid = 0) here.
|
||||
$courseformatoption->set_source_sql('SELECT id, format, sectionid, name, value
|
||||
FROM {course_format_options}
|
||||
WHERE courseid = ?', [ backup::VAR_PARENTID ]);
|
||||
WHERE courseid = ? AND sectionid = 0', [ backup::VAR_PARENTID ]);
|
||||
|
||||
$handler = core_course\customfield\course_handler::create();
|
||||
$fieldsforbackup = $handler->get_instance_data_for_backup($this->task->get_courseid());
|
||||
|
||||
@@ -246,16 +246,6 @@ abstract class restore_activity_task extends restore_task {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a commment area, return the itemname that contains the itemid mappings
|
||||
*
|
||||
* By default both are the same (commentarea = itemname), so return it. If some
|
||||
* module uses a different approach, this method can be overriden in its taks
|
||||
*/
|
||||
public function get_comment_mapping_itemname($commentarea) {
|
||||
return $commentarea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define (add) particular steps that each activity can have
|
||||
*/
|
||||
|
||||
@@ -767,6 +767,7 @@ class restore_decode_interlinks extends restore_execution_step {
|
||||
|
||||
protected function define_execution() {
|
||||
// Get the decoder (from the plan)
|
||||
/** @var restore_decode_processor $decoder */
|
||||
$decoder = $this->task->get_decoder();
|
||||
restore_decode_processor::register_link_decoders($decoder); // Add decoder contents and rules
|
||||
// And launch it, everything will be processed
|
||||
@@ -1952,6 +1953,10 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
// Course record ready, update it
|
||||
$DB->update_record('course', $data);
|
||||
|
||||
// Apply any course format options that may be saved against the course
|
||||
// entity in earlier-version backups.
|
||||
course_get_format($data)->update_course_format_options($data);
|
||||
|
||||
// Role name aliases
|
||||
restore_dbops::set_course_role_names($this->get_restoreid(), $this->get_courseid());
|
||||
}
|
||||
@@ -1989,8 +1994,14 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
public function process_course_format_option(array $data) : void {
|
||||
global $DB;
|
||||
|
||||
if ($data['sectionid']) {
|
||||
// Ignore section-level format options saved course-level in earlier-version backups.
|
||||
return;
|
||||
}
|
||||
|
||||
$courseid = $this->get_courseid();
|
||||
$record = $DB->get_record('course_format_options', [ 'courseid' => $courseid, 'name' => $data['name'] ], 'id');
|
||||
$record = $DB->get_record('course_format_options', [ 'courseid' => $courseid, 'name' => $data['name'],
|
||||
'format' => $data['format'], 'sectionid' => 0 ], 'id');
|
||||
if ($record !== false) {
|
||||
$DB->update_record('course_format_options', (object) [ 'id' => $record->id, 'value' => $data['value'] ]);
|
||||
} else {
|
||||
@@ -5458,17 +5469,22 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
$this->log('processing file aliases queue', backup::LOG_DEBUG);
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
// Load the queue.
|
||||
$aliascount = $DB->count_records('backup_ids_temp',
|
||||
['backupid' => $this->get_restoreid(), 'itemname' => 'file_aliases_queue']);
|
||||
$rs = $DB->get_recordset('backup_ids_temp',
|
||||
array('backupid' => $this->get_restoreid(), 'itemname' => 'file_aliases_queue'),
|
||||
['backupid' => $this->get_restoreid(), 'itemname' => 'file_aliases_queue'],
|
||||
'', 'info');
|
||||
|
||||
$this->log('processing file aliases queue. ' . $aliascount . ' entries.', backup::LOG_DEBUG);
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress('Processing file aliases queue', $aliascount);
|
||||
|
||||
// Iterate over aliases in the queue.
|
||||
foreach ($rs as $record) {
|
||||
$progress->increment_progress();
|
||||
$info = backup_controller_dbops::decode_backup_temp_info($record->info);
|
||||
|
||||
// Try to pick a repository instance that should serve the alias.
|
||||
@@ -5593,6 +5609,7 @@ class restore_process_file_aliases_queue extends restore_execution_step {
|
||||
}
|
||||
}
|
||||
}
|
||||
$progress->end_progress();
|
||||
$rs->close();
|
||||
}
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ class restore_decode_processor {
|
||||
*/
|
||||
public function execute() {
|
||||
// Iterate over all contents, visiting them
|
||||
/** @var restore_decode_content $content */
|
||||
foreach ($this->contents as $content) {
|
||||
$content->process($this);
|
||||
}
|
||||
|
||||
@@ -201,9 +201,16 @@ class restore_plan extends base_plan implements loggable {
|
||||
*/
|
||||
public function execute_after_restore() {
|
||||
// Simply iterate over each task in the plan and delegate to them the execution
|
||||
$progress = $this->get_progress();
|
||||
$progress->start_progress($this->get_name() .
|
||||
': executing execute_after_restore for all tasks', count($this->tasks));
|
||||
|
||||
/** @var base_task $task */
|
||||
foreach ($this->tasks as $task) {
|
||||
$task->execute_after_restore();
|
||||
$progress->increment_progress();
|
||||
}
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -95,6 +95,19 @@ abstract class restore_task extends base_task {
|
||||
return $this->plan->get_info()->original_system_contextid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a commment area, return the itemname that contains the itemid mappings
|
||||
*
|
||||
* By default, both are the same (commentarea = itemname), so return it. If some
|
||||
* plugins use a different approach, this method can be overriden in its task.
|
||||
*
|
||||
* @param string $commentarea area defined for this comment
|
||||
* @return string itemname that contains the related itemid mapping
|
||||
*/
|
||||
public function get_comment_mapping_itemname($commentarea) {
|
||||
return $commentarea;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the task has been executed, launch its after_restore()
|
||||
* method if available
|
||||
|
||||
@@ -171,9 +171,7 @@ class block_accessreview extends block_base {
|
||||
* @return bool
|
||||
*/
|
||||
public function can_block_be_added(moodle_page $page): bool {
|
||||
global $CFG;
|
||||
|
||||
return $CFG->enableaccessibilitytools;
|
||||
return accessibility::is_accessibility_enabled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -51,7 +51,9 @@ function block_accessreview_get_fontawesome_icon_map() {
|
||||
/**
|
||||
* Define preferences which may be set via the core_user_set_user_preferences external function.
|
||||
*
|
||||
* @return array
|
||||
* @uses core_user::is_current_user
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
function block_accessreview_user_preferences(): array {
|
||||
return [
|
||||
@@ -60,6 +62,7 @@ function block_accessreview_user_preferences(): array {
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => 0,
|
||||
'choices' => [0, 1],
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -74,9 +74,11 @@ define('BLOCK_MYOVERVIEW_DISPLAY_CATEGORIES_OFF', 'off');
|
||||
/**
|
||||
* Get the current user preferences that are available
|
||||
*
|
||||
* @return mixed Array representing current options along with defaults
|
||||
* @uses core_user::is_current_user
|
||||
*
|
||||
* @return array[] Array representing current options along with defaults
|
||||
*/
|
||||
function block_myoverview_user_preferences() {
|
||||
function block_myoverview_user_preferences(): array {
|
||||
$preferences['block_myoverview_user_grouping_preference'] = array(
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => BLOCK_MYOVERVIEW_GROUPING_ALL,
|
||||
@@ -90,13 +92,15 @@ function block_myoverview_user_preferences() {
|
||||
BLOCK_MYOVERVIEW_GROUPING_FAVOURITES,
|
||||
BLOCK_MYOVERVIEW_GROUPING_HIDDEN,
|
||||
BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD,
|
||||
)
|
||||
),
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
$preferences['block_myoverview_user_grouping_customfieldvalue_preference'] = [
|
||||
'null' => NULL_ALLOWED,
|
||||
'default' => null,
|
||||
'type' => PARAM_RAW,
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
];
|
||||
|
||||
$preferences['block_myoverview_user_sort_preference'] = array(
|
||||
@@ -107,8 +111,10 @@ function block_myoverview_user_preferences() {
|
||||
BLOCK_MYOVERVIEW_SORTING_TITLE,
|
||||
BLOCK_MYOVERVIEW_SORTING_LASTACCESSED,
|
||||
BLOCK_MYOVERVIEW_SORTING_SHORTNAME
|
||||
)
|
||||
),
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
$preferences['block_myoverview_user_view_preference'] = array(
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => BLOCK_MYOVERVIEW_VIEW_CARD,
|
||||
@@ -117,7 +123,8 @@ function block_myoverview_user_preferences() {
|
||||
BLOCK_MYOVERVIEW_VIEW_CARD,
|
||||
BLOCK_MYOVERVIEW_VIEW_LIST,
|
||||
BLOCK_MYOVERVIEW_VIEW_SUMMARY
|
||||
)
|
||||
),
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
$preferences['/^block_myoverview_hidden_course_(\d)+$/'] = array(
|
||||
@@ -125,7 +132,8 @@ function block_myoverview_user_preferences() {
|
||||
'choices' => array(0, 1),
|
||||
'type' => PARAM_INT,
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => 'none'
|
||||
'default' => 0,
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
$preferences['block_myoverview_user_paging_preference'] = array(
|
||||
@@ -138,7 +146,8 @@ function block_myoverview_user_preferences() {
|
||||
BLOCK_MYOVERVIEW_PAGING_48,
|
||||
BLOCK_MYOVERVIEW_PAGING_96,
|
||||
BLOCK_MYOVERVIEW_PAGING_ALL
|
||||
)
|
||||
),
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
return $preferences;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<div id="block-myoverview-{{uniqid}}" class="block-myoverview block-cards" data-region="myoverview" role="navigation">
|
||||
<hr class="mt-0"/>
|
||||
|
||||
<div data-region="filter" class="d-flex align-items-center my-2" aria-label="{{#str}} aria:controls, block_myoverview {{/str}}">
|
||||
<div role="search" data-region="filter" class="d-flex align-items-center my-2" aria-label="{{#str}} aria:controls, block_myoverview {{/str}}">
|
||||
<div class="row no-gutters">
|
||||
{{> block_myoverview/nav-grouping-selector }}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
|
||||
<div class="card-deck dashboard-card-deck one-row" data-region="items-list" role="list">
|
||||
{{#items}}
|
||||
<a class="card dashboard-card mb-1" href="{{{viewurl}}}" title="{{{name}}}">
|
||||
<a class="card dashboard-card mb-1" href="{{{viewurl}}}" title="{{{name}}}" role="listitem">
|
||||
<div class="card-body p-2 m-1">
|
||||
<div class="d-flex text-truncate">
|
||||
<div class="d-flex align-self-center activityiconcontainer {{purpose}}">
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ Feature: The recently accessed items block allows users to easily access their m
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| assign | Test assignment name | Test assignment description | C1 | assign1 |
|
||||
| book | Test book name | Test book description | C1 | book1 |
|
||||
| book | Test book name | | C1 | book1 |
|
||||
| choice | Test choice name | Test choice description | C1 | choice1 |
|
||||
| data | Test database name | Test database description | C1 | data1 |
|
||||
And I change window size to "large"
|
||||
|
||||
@@ -92,8 +92,11 @@ class renderer extends \plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function format_published_date($timestamp) {
|
||||
return strftime(get_string('strftimerecentfull', 'langconfig'), $timestamp);
|
||||
return date('j F Y, g:i a', $timestamp);
|
||||
if (empty($timestamp)) {
|
||||
return '';
|
||||
} else {
|
||||
return strftime(get_string('strftimerecentfull', 'langconfig'), $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -57,8 +57,8 @@ Feature: Edit activities in main menu block
|
||||
And I click on "Edit settings" "link" in the "My forum name" activity in site main menu block
|
||||
And I expand all fieldsets
|
||||
And the "Availability" select box should contain "Show on course page"
|
||||
And the "Availability" select box should contain "Hide from students"
|
||||
And the field "Availability" matches value "Make available but not shown on course page"
|
||||
And the "Availability" select box should contain "Hide on course page"
|
||||
And the field "Availability" matches value "Make available but don't show on course page"
|
||||
And I press "Save and return to course"
|
||||
And "My forum name" activity in site main menu block should be available but hidden from course page
|
||||
And I turn editing mode off
|
||||
|
||||
@@ -67,8 +67,8 @@ Feature: Edit activities in social activities block
|
||||
And I click on "Edit settings" "link" in the "My forum name" activity in social activities block
|
||||
And I expand all fieldsets
|
||||
And the "Availability" select box should contain "Show on course page"
|
||||
And the "Availability" select box should contain "Hide from students"
|
||||
And the field "Availability" matches value "Make available but not shown on course page"
|
||||
And the "Availability" select box should contain "Hide on course page"
|
||||
And the field "Availability" matches value "Make available but don't show on course page"
|
||||
And I press "Save and return to course"
|
||||
And "My forum name" activity in social activities block should be available but hidden from course page
|
||||
And I turn editing mode off
|
||||
|
||||
@@ -15,16 +15,13 @@ Feature: Block appearances
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "activities" exist:
|
||||
| activity | name | description | course | idnumber | section | template |
|
||||
| survey | Test survey name | | C1 | survey1 | 1 | 4 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 | |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I click on "Test book name" "link" in the "region-main" "region"
|
||||
And I set the following fields to these values:
|
||||
| Chapter title | Book title |
|
||||
| Content | Book content test test |
|
||||
And I press "Save changes"
|
||||
| activity | name | course | idnumber | section | template |
|
||||
| survey | Test survey name | C1 | survey1 | 1 | 4 |
|
||||
| book | Test book name | C1 | book1 | 1 | |
|
||||
And the following "mod_book > chapter" exists:
|
||||
| book | Test book name |
|
||||
| title | Book title |
|
||||
| content | Book content test test |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I turn editing mode on
|
||||
And I add the "Comments" block
|
||||
|
||||
@@ -17,17 +17,11 @@ Feature: Block region moving
|
||||
And the following "activities" exist:
|
||||
| activity | course | name | template |
|
||||
| survey | C1 | Test survey name | 4 |
|
||||
And I log in as "admin"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add a "Book" to section "1" and I fill the form with:
|
||||
| Name | Test book name |
|
||||
| Description | Test book description |
|
||||
And I follow "Test book name"
|
||||
And I set the following fields to these values:
|
||||
| Chapter title | Book title |
|
||||
| Content | Book content test test |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
| book | C1 | Test book name | |
|
||||
And the following "mod_book > chapter" exists:
|
||||
| book | Test book name |
|
||||
| title | Book title |
|
||||
| content | Book content test test |
|
||||
And I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage with editing mode on
|
||||
And I add the "Comments" block
|
||||
|
||||
+10
-5
@@ -43,14 +43,17 @@ define('BLOCK_TIMELINE_ACTIVITIES_LIMIT_DEFAULT', 5);
|
||||
/**
|
||||
* Returns the name of the user preferences as well as the details this plugin uses.
|
||||
*
|
||||
* @return array
|
||||
* @uses core_user::is_current_user
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
function block_timeline_user_preferences() {
|
||||
function block_timeline_user_preferences(): array {
|
||||
$preferences['block_timeline_user_sort_preference'] = array(
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => BLOCK_TIMELINE_SORT_BY_DATES,
|
||||
'type' => PARAM_ALPHA,
|
||||
'choices' => array(BLOCK_TIMELINE_SORT_BY_DATES, BLOCK_TIMELINE_SORT_BY_COURSES)
|
||||
'choices' => array(BLOCK_TIMELINE_SORT_BY_DATES, BLOCK_TIMELINE_SORT_BY_COURSES),
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
$preferences['block_timeline_user_filter_preference'] = array(
|
||||
@@ -64,13 +67,15 @@ function block_timeline_user_preferences() {
|
||||
BLOCK_TIMELINE_FILTER_BY_30_DAYS,
|
||||
BLOCK_TIMELINE_FILTER_BY_3_MONTHS,
|
||||
BLOCK_TIMELINE_FILTER_BY_6_MONTHS
|
||||
)
|
||||
),
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
$preferences['block_timeline_user_limit_preference'] = array(
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => BLOCK_TIMELINE_ACTIVITIES_LIMIT_DEFAULT,
|
||||
'type' => PARAM_INT
|
||||
'type' => PARAM_INT,
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
);
|
||||
|
||||
return $preferences;
|
||||
|
||||
Vendored
+1
-1
@@ -52,7 +52,7 @@ $PAGE->set_primary_active_tab('siteadminnode');
|
||||
$PAGE->navbar->add(get_string('cacheconfig', 'cache'), new moodle_url('/cache/admin.php'));
|
||||
|
||||
// Handle page actions in admin helper class.
|
||||
if (!empty($action) && confirm_sesskey()) {
|
||||
if (!empty($action)) {
|
||||
$forminfo = $adminhelper->perform_cache_actions($action, $forminfo);
|
||||
}
|
||||
|
||||
|
||||
+14
-8
@@ -66,14 +66,14 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
// Edit mappings.
|
||||
$actions[] = $OUTPUT->action_link(
|
||||
new \moodle_url('/cache/admin.php', array('action' => 'editdefinitionmapping',
|
||||
'definition' => $definitionsummary['id'], 'sesskey' => sesskey())),
|
||||
'definition' => $definitionsummary['id'])),
|
||||
get_string('editmappings', 'cache')
|
||||
);
|
||||
// Edit sharing.
|
||||
if (count($definitionsummary['sharingoptions']) > 1) {
|
||||
$actions[] = $OUTPUT->action_link(
|
||||
new \moodle_url('/cache/admin.php', array('action' => 'editdefinitionsharing',
|
||||
'definition' => $definitionsummary['id'], 'sesskey' => sesskey())),
|
||||
'definition' => $definitionsummary['id'])),
|
||||
get_string('editsharing', 'cache')
|
||||
);
|
||||
}
|
||||
@@ -100,21 +100,22 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
global $OUTPUT;
|
||||
$actions = array();
|
||||
if (has_capability('moodle/site:config', \context_system::instance())) {
|
||||
$baseurl = new \moodle_url('/cache/admin.php', array('store' => $name, 'sesskey' => sesskey()));
|
||||
$baseurl = new \moodle_url('/cache/admin.php', array('store' => $name));
|
||||
if (empty($storedetails['default'])) {
|
||||
// Edit store.
|
||||
$actions[] = $OUTPUT->action_link(
|
||||
new \moodle_url($baseurl, array('action' => 'editstore', 'plugin' => $storedetails['plugin'])),
|
||||
get_string('editstore', 'cache')
|
||||
);
|
||||
|
||||
// Delete store.
|
||||
$actions[] = $OUTPUT->action_link(
|
||||
new \moodle_url($baseurl, array('action' => 'deletestore')),
|
||||
get_string('deletestore', 'cache')
|
||||
);
|
||||
}
|
||||
|
||||
// Purge store.
|
||||
$actions[] = $OUTPUT->action_link(
|
||||
new \moodle_url($baseurl, array('action' => 'purgestore')),
|
||||
new \moodle_url($baseurl, array('action' => 'purgestore', 'sesskey' => sesskey())),
|
||||
get_string('purge', 'cache')
|
||||
);
|
||||
}
|
||||
@@ -135,7 +136,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
if (has_capability('moodle/site:config', \context_system::instance())) {
|
||||
if (!empty($plugindetails['canaddinstance'])) {
|
||||
$url = new \moodle_url('/cache/admin.php',
|
||||
array('action' => 'addstore', 'plugin' => $name, 'sesskey' => sesskey()));
|
||||
array('action' => 'addstore', 'plugin' => $name));
|
||||
$actions[] = $OUTPUT->action_link(
|
||||
$url,
|
||||
get_string('addinstance', 'cache')
|
||||
@@ -429,6 +430,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
public function action_rescan_definition() {
|
||||
global $PAGE;
|
||||
|
||||
require_sesskey();
|
||||
\cache_config_writer::update_definitions();
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
@@ -537,6 +539,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
} else {
|
||||
require_sesskey();
|
||||
$writer = \cache_config_writer::instance();
|
||||
$writer->delete_store_instance($store);
|
||||
redirect($PAGE->url, get_string('deletestoresuccess', 'cache'), 5);
|
||||
@@ -657,6 +660,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
public function action_purgedefinition() {
|
||||
global $PAGE;
|
||||
|
||||
require_sesskey();
|
||||
$id = required_param('definition', PARAM_SAFEPATH);
|
||||
list($component, $area) = explode('/', $id, 2);
|
||||
$factory = cache_factory::instance();
|
||||
@@ -688,6 +692,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
public function action_purge() {
|
||||
global $PAGE;
|
||||
|
||||
require_sesskey();
|
||||
$store = required_param('store', PARAM_TEXT);
|
||||
cache_helper::purge_store($store);
|
||||
$message = get_string('purgexstoresuccess', 'cache', ['store' => $store]);
|
||||
@@ -758,6 +763,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
} else {
|
||||
require_sesskey();
|
||||
$writer = cache_config_writer::instance();
|
||||
$writer->delete_lock_instance($lock);
|
||||
redirect($PAGE->url, get_string('deletelocksuccess', 'cache'), 5);
|
||||
@@ -790,7 +796,7 @@ class administration_display_helper extends \core_cache\administration_helper {
|
||||
$applicationstore = join(', ', $defaultmodestores[cache_store::MODE_APPLICATION]);
|
||||
$sessionstore = join(', ', $defaultmodestores[cache_store::MODE_SESSION]);
|
||||
$requeststore = join(', ', $defaultmodestores[cache_store::MODE_REQUEST]);
|
||||
$editurl = new \moodle_url('/cache/admin.php', array('action' => 'editmodemappings', 'sesskey' => sesskey()));
|
||||
$editurl = new \moodle_url('/cache/admin.php', array('action' => 'editmodemappings'));
|
||||
$html .= $renderer->mode_mappings($applicationstore, $sessionstore, $requeststore, $editurl);
|
||||
|
||||
return $html;
|
||||
|
||||
Vendored
+2
-2
@@ -353,7 +353,7 @@ class renderer extends \plugin_renderer_base {
|
||||
foreach ($locks as $lock) {
|
||||
$actions = array();
|
||||
if ($lock['uses'] === 0 && !$lock['default']) {
|
||||
$url = new moodle_url('/cache/admin.php', array('lock' => $lock['name'], 'action' => 'deletelock', 'sesskey' => sesskey()));
|
||||
$url = new moodle_url('/cache/admin.php', array('lock' => $lock['name'], 'action' => 'deletelock'));
|
||||
$actions[] = html_writer::link($url, get_string('delete', 'cache'));
|
||||
}
|
||||
$table->data[] = new html_table_row(array(
|
||||
@@ -378,7 +378,7 @@ class renderer extends \plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function additional_lock_actions() : string {
|
||||
$url = new moodle_url('/cache/admin.php', array('action' => 'newlockinstance', 'sesskey' => sesskey()));
|
||||
$url = new moodle_url('/cache/admin.php', array('action' => 'newlockinstance'));
|
||||
$select = new single_select($url, 'lock', cache_factory::get_administration_display_helper()->get_addable_lock_options());
|
||||
$select->label = get_string('addnewlockinstance', 'cache');
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace MongoDB\Exception;
|
||||
use MongoDB\Driver\Exception\InvalidArgumentException as DriverInvalidArgumentException;
|
||||
use function array_pop;
|
||||
use function count;
|
||||
use function get_debug_type;
|
||||
use function gettype;
|
||||
use function implode;
|
||||
use function is_array;
|
||||
use function sprintf;
|
||||
@@ -56,6 +56,6 @@ class InvalidArgumentException extends DriverInvalidArgumentException implements
|
||||
$expectedType = $typeString;
|
||||
}
|
||||
|
||||
return new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, get_debug_type($value)));
|
||||
return new static(sprintf('Expected %s to have type "%s" but found "%s"', $name, $expectedType, gettype($value)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
namespace MongoDB\Exception;
|
||||
|
||||
use function get_debug_type;
|
||||
use function gettype;
|
||||
use function sprintf;
|
||||
|
||||
class ResumeTokenException extends RuntimeException
|
||||
@@ -30,7 +30,7 @@ class ResumeTokenException extends RuntimeException
|
||||
*/
|
||||
public static function invalidType($value)
|
||||
{
|
||||
return new static(sprintf('Expected resume token to have type "array or object" but found "%s"', get_debug_type($value)));
|
||||
return new static(sprintf('Expected resume token to have type "array or object" but found "%s"', gettype($value)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+4
@@ -10,3 +10,7 @@ Import procedure:
|
||||
- Check the minim php driver version in https://docs.mongodb.com/drivers/php#compatibility and change the value in the "are_requirements_met" method if necessary.
|
||||
|
||||
This version (1.8.0) requires PHP mongodb extension >= 1.8.0
|
||||
|
||||
Local changes:
|
||||
- Replaced 4 occurrences of get_debug_type() by gettype() to keep PHP 7.4 compatibility. Note this
|
||||
has not been applied to 4.2dev and up because, there, it's safe to use get_debug_type().
|
||||
|
||||
@@ -2795,7 +2795,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function test_get_calendar_event_by_id_prevent_read_other_users_events_data_provider(): array {
|
||||
public function get_calendar_event_by_id_prevent_read_other_users_events_data_provider(): array {
|
||||
$syscontext = \context_system::instance();
|
||||
$managerrole = 'manager';
|
||||
return [
|
||||
@@ -2810,7 +2810,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
* Prevent user from reading other user's event.
|
||||
*
|
||||
* @covers \core_calendar_external::get_calendar_event_by_id
|
||||
* @dataProvider test_get_calendar_event_by_id_prevent_read_other_users_events_data_provider
|
||||
* @dataProvider get_calendar_event_by_id_prevent_read_other_users_events_data_provider
|
||||
*
|
||||
* @param bool $isadminevent Is admin's event
|
||||
* @param bool $isadmin Is current user admin user
|
||||
@@ -2866,7 +2866,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function test_edit_or_delete_other_users_events_data_provider(): array {
|
||||
public function edit_or_delete_other_users_events_data_provider(): array {
|
||||
$syscontext = \context_system::instance();
|
||||
$managerrole = 'manager';
|
||||
return [
|
||||
@@ -2880,7 +2880,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test the behavior of deleting other users' user events.
|
||||
*
|
||||
* @dataProvider test_edit_or_delete_other_users_events_data_provider
|
||||
* @dataProvider edit_or_delete_other_users_events_data_provider
|
||||
* @covers \core_calendar_external::delete_calendar_events
|
||||
* @param bool $isadmin Whether the current user is admin.
|
||||
* @param bool $isadminevent Whether it's an admin event or not.
|
||||
@@ -2927,7 +2927,7 @@ class externallib_test extends externallib_advanced_testcase {
|
||||
/**
|
||||
* Test the behavior of editing other users' user events
|
||||
*
|
||||
* @dataProvider test_edit_or_delete_other_users_events_data_provider
|
||||
* @dataProvider edit_or_delete_other_users_events_data_provider
|
||||
* @covers \core_calendar_external::submit_create_update_form
|
||||
* @param bool $isadmin Whether the current user is admin.
|
||||
* @param bool $isadminevent Whether it's an admin event or not.
|
||||
|
||||
@@ -49,7 +49,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test proxying.
|
||||
*
|
||||
* @dataProvider test_proxy_testcases()
|
||||
* @dataProvider proxy_testcases
|
||||
* @param int $id Object ID.
|
||||
* @param string $member Object member to retrieve.
|
||||
* @param mixed $expected Expected value of member.
|
||||
@@ -65,7 +65,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test setting values with a base class.
|
||||
*
|
||||
* @dataProvider test_proxy_testcases()
|
||||
* @dataProvider proxy_testcases
|
||||
* @param int $id Object ID.
|
||||
* @param string $member Object member to retrieve.
|
||||
* @param mixed $storedvalue Value as would be stored externally.
|
||||
@@ -86,7 +86,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test getting a non existant member.
|
||||
*
|
||||
* @dataProvider test_get_set_testcases()
|
||||
* @dataProvider get_set_testcases
|
||||
* @param int $id ID of the object being proxied.
|
||||
*/
|
||||
public function test_get_invalid_member($id) {
|
||||
@@ -101,7 +101,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test get proxied instance.
|
||||
*
|
||||
* @dataProvider test_get_set_testcases()
|
||||
* @dataProvider get_set_testcases
|
||||
* @param int $id Object ID.
|
||||
*/
|
||||
public function test_get_proxied_instance($id) {
|
||||
@@ -115,7 +115,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test cases for proxying test.
|
||||
*/
|
||||
public function test_proxy_testcases() {
|
||||
public function proxy_testcases() {
|
||||
return [
|
||||
'Object 1 member 1' => [
|
||||
1,
|
||||
@@ -153,7 +153,7 @@ class std_proxy_test extends \advanced_testcase {
|
||||
/**
|
||||
* Test cases for getting and setting tests.
|
||||
*/
|
||||
public function test_get_set_testcases() {
|
||||
public function get_set_testcases() {
|
||||
return [
|
||||
'Object 1' => [1],
|
||||
'Object 2' => [5]
|
||||
|
||||
@@ -63,9 +63,11 @@ class cohortidnumber extends \core\output\inplace_editable {
|
||||
$cohortcontext = \context::instance_by_id($cohort->contextid);
|
||||
\external_api::validate_context($cohortcontext);
|
||||
require_capability('moodle/cohort:manage', $cohortcontext);
|
||||
$record = (object)array('id' => $cohort->id, 'idnumber' => $newvalue, 'contextid' => $cohort->contextid);
|
||||
cohort_update_cohort($record);
|
||||
$cohort->idnumber = $newvalue;
|
||||
if ($newvalue == '' || !$DB->record_exists_select('cohort', 'idnumber = ? AND id != ?', [$newvalue, $cohort->id])) {
|
||||
$record = (object) ['id' => $cohort->id, 'idnumber' => $newvalue, 'contextid' => $cohort->contextid];
|
||||
cohort_update_cohort($record);
|
||||
$cohort->idnumber = $newvalue;
|
||||
}
|
||||
return new static($cohort);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,17 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Data provider.
|
||||
*
|
||||
* @package core_competency
|
||||
* @copyright 2018 Frédéric Massart
|
||||
* @author Frédéric Massart <fred@branchup.tech>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace core_competency\privacy;
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
use context;
|
||||
use context_course;
|
||||
@@ -584,9 +574,16 @@ class provider implements
|
||||
/**
|
||||
* Export all user data for the specified user, in the specified contexts.
|
||||
*
|
||||
* We skip the enabled check for competencies, as there could be historical data. This avoids exceptions thrown from
|
||||
* the {@see api::require_enabled} method, which is called at various points during export via the competency API
|
||||
*
|
||||
* @param approved_contextlist $contextlist The approved contexts to export information for.
|
||||
*/
|
||||
public static function export_user_data(approved_contextlist $contextlist) {
|
||||
|
||||
// Export even if competencies are not currently enabled.
|
||||
api::skip_enabled();
|
||||
|
||||
$user = $contextlist->get_user();
|
||||
$userid = $user->id;
|
||||
|
||||
|
||||
@@ -339,6 +339,7 @@ class core_completion_external extends external_api {
|
||||
)
|
||||
]
|
||||
),
|
||||
'Completion status details',
|
||||
VALUE_DEFAULT,
|
||||
[]
|
||||
),
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
@core @core_completion
|
||||
Feature: Students will be shown relevant completion state based on grade item visibility.
|
||||
In order to understand completion states of course modules
|
||||
As a student
|
||||
I need to see relevant completion information for various combination of activity passgrade settings
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category | enablecompletion |
|
||||
| Course 1 | C1 | 0 | 1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | Frist | teacher1@example.com |
|
||||
| student1 | Student | First | student1@example.com |
|
||||
| student2 | Student | Second | student2@example.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And the following "activity" exists:
|
||||
| activity | assign |
|
||||
| course | C1 |
|
||||
| name | Test assignment name |
|
||||
| intro | Submit your online text |
|
||||
| assignsubmission_onlinetext_enabled | 1 |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| completion | 2 |
|
||||
| completionpassgrade | 1 |
|
||||
| completionusegrade | 1 |
|
||||
| gradepass | 50 |
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And "Student First" user has not completed "Test assignment name" activity
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "todo"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "todo"
|
||||
And I log out
|
||||
|
||||
Scenario: Passing grade and receive a grade completions for visible grade item (passgrade completion enabled)
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "21" to the user "Student First" for the grade item "Test assignment name"
|
||||
And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Student First" user has completed "Test assignment name" activity
|
||||
And "Student Second" user has completed "Test assignment name" activity
|
||||
And I log out
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "failed"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student2
|
||||
Then the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
|
||||
Scenario: Passing grade and receive a grade completions for hidden grade item (passgrade completion enabled)
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
And I hide the grade item "Test assignment name"
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "21" to the user "Student First" for the grade item "Test assignment name"
|
||||
And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Student First" user has not completed "Test assignment name" activity
|
||||
And "Student Second" user has completed "Test assignment name" activity
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "todo"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student2
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And the "Receive a passing grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
|
||||
Scenario: Receive a grade completion for visible grade item (passgrade completion disabled)
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| completionpassgrade | 0 |
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "todo"
|
||||
And I should not see "Receive a passing grade"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "21" to the user "Student First" for the grade item "Test assignment name"
|
||||
And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Student First" user has completed "Test assignment name" activity
|
||||
And "Student Second" user has completed "Test assignment name" activity
|
||||
And I log out
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
# Once MDL-75582 is fixed "failed" should be changed to "done"
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "failed"
|
||||
And I should not see "Receive a passing grade"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student2
|
||||
Then the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
|
||||
Scenario: Receive a grade completion for hidden grade item (passgrade completion disabled)
|
||||
Given I am on the "Test assignment name" Activity page logged in as teacher1
|
||||
When I navigate to "Settings" in current page administration
|
||||
And I set the following fields to these values:
|
||||
| completionpassgrade | 0 |
|
||||
And I press "Save and display"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student1
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "todo"
|
||||
And I should not see "Receive a passing grade"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as teacher1
|
||||
And I navigate to "Setup > Gradebook setup" in the course gradebook
|
||||
And I hide the grade item "Test assignment name"
|
||||
And I navigate to "View > Grader report" in the course gradebook
|
||||
And I turn editing mode on
|
||||
And I give the grade "21" to the user "Student First" for the grade item "Test assignment name"
|
||||
And I give the grade "50" to the user "Student Second" for the grade item "Test assignment name"
|
||||
And I press "Save changes"
|
||||
And I am on "Course 1" course homepage
|
||||
And "Student First" user has completed "Test assignment name" activity
|
||||
And "Student Second" user has completed "Test assignment name" activity
|
||||
And I log out
|
||||
When I am on the "Course 1" course page logged in as student1
|
||||
Then the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
And I should not see "Receive a passing grade"
|
||||
And I log out
|
||||
And I am on the "Course 1" course page logged in as student2
|
||||
And the "Receive a grade" completion condition of "Test assignment name" is displayed as "done"
|
||||
+1
-1
@@ -6,6 +6,6 @@ define("core_contentbank/selectors",["exports"],(function(_exports){Object.defin
|
||||
* @copyright 2020 Sara Arjona <sara@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
const getDataSelector=(name,value)=>"[data-".concat(name,'="').concat(value,'"]');var _default={regions:{cbcontentname:getDataSelector("region","cb-content-name"),contentbank:getDataSelector("region","contentbank"),filearea:getDataSelector("region","filearea")},actions:{search:getDataSelector("action","searchcontent"),clearSearch:getDataSelector("action","clearsearch"),viewgrid:getDataSelector("action","viewgrid"),viewlist:getDataSelector("action","viewlist"),sortname:getDataSelector("action","sortname"),sortuses:getDataSelector("action","sortuses"),sortdate:getDataSelector("action","sortdate"),sortsize:getDataSelector("action","sortsize"),sorttype:getDataSelector("action","sorttype"),sortauthor:getDataSelector("action","sortauthor")},elements:{listitem:".cb-listitem",heading:".cb-heading",cell:".cb-column",cbnavbarbreadcrumb:".cb-navbar-breadbrumb",cbnavbartotalsearch:".cb-navbar-totalsearch",searchinput:"#searchinput",sortbutton:".cb-btnsort"}};return _exports.default=_default,_exports.default}));
|
||||
const getDataSelector=(name,value)=>"[data-".concat(name,'="').concat(value,'"]');var _default={regions:{cbcontentname:getDataSelector("region","cb-content-name"),contentbank:getDataSelector("region","contentbank"),filearea:getDataSelector("region","filearea")},actions:{search:getDataSelector("action","searchcontent"),clearSearch:getDataSelector("action","clearsearch"),viewgrid:getDataSelector("action","viewgrid"),viewlist:getDataSelector("action","viewlist"),sortname:getDataSelector("action","sortname"),sortuses:getDataSelector("action","sortuses"),sortdate:getDataSelector("action","sortdate"),sortsize:getDataSelector("action","sortsize"),sorttype:getDataSelector("action","sorttype"),sortauthor:getDataSelector("action","sortauthor")},elements:{listitem:".cb-listitem",heading:".cb-heading",cell:".cb-column",cbnavbarbreadcrumb:".cb-navbar-breadbrumb",cbnavbartotalsearch:".cb-navbar-totalsearch",searchinput:'[role="searchbox"]',sortbutton:".cb-btnsort"}};return _exports.default=_default,_exports.default}));
|
||||
|
||||
//# sourceMappingURL=selectors.min.js.map
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the contentbank interface.\n *\n * @module core_contentbank/selectors\n * @copyright 2020 Sara Arjona <sara@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n *\n * @method getDataSelector\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n regions: {\n cbcontentname: getDataSelector('region', 'cb-content-name'),\n contentbank: getDataSelector('region', 'contentbank'),\n filearea: getDataSelector('region', 'filearea')\n },\n actions: {\n search: getDataSelector('action', 'searchcontent'),\n clearSearch: getDataSelector('action', 'clearsearch'),\n viewgrid: getDataSelector('action', 'viewgrid'),\n viewlist: getDataSelector('action', 'viewlist'),\n sortname: getDataSelector('action', 'sortname'),\n sortuses: getDataSelector('action', 'sortuses'),\n sortdate: getDataSelector('action', 'sortdate'),\n sortsize: getDataSelector('action', 'sortsize'),\n sorttype: getDataSelector('action', 'sorttype'),\n sortauthor: getDataSelector('action', 'sortauthor'),\n },\n elements: {\n listitem: '.cb-listitem',\n heading: '.cb-heading',\n cell: '.cb-column',\n cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',\n cbnavbartotalsearch: '.cb-navbar-totalsearch',\n searchinput: '#searchinput',\n sortbutton: '.cb-btnsort'\n },\n};\n"],"names":["getDataSelector","name","value","regions","cbcontentname","contentbank","filearea","actions","search","clearSearch","viewgrid","viewlist","sortname","sortuses","sortdate","sortsize","sorttype","sortauthor","elements","listitem","heading","cell","cbnavbarbreadcrumb","cbnavbartotalsearch","searchinput","sortbutton"],"mappings":";;;;;;;;MA+BMA,gBAAkB,CAACC,KAAMC,wBACXD,kBAASC,yBAGd,CACXC,QAAS,CACLC,cAAeJ,gBAAgB,SAAU,mBACzCK,YAAaL,gBAAgB,SAAU,eACvCM,SAAUN,gBAAgB,SAAU,aAExCO,QAAS,CACLC,OAAQR,gBAAgB,SAAU,iBAClCS,YAAaT,gBAAgB,SAAU,eACvCU,SAAUV,gBAAgB,SAAU,YACpCW,SAAUX,gBAAgB,SAAU,YACpCY,SAAUZ,gBAAgB,SAAU,YACpCa,SAAUb,gBAAgB,SAAU,YACpCc,SAAUd,gBAAgB,SAAU,YACpCe,SAAUf,gBAAgB,SAAU,YACpCgB,SAAUhB,gBAAgB,SAAU,YACpCiB,WAAYjB,gBAAgB,SAAU,eAE1CkB,SAAU,CACNC,SAAU,eACVC,QAAS,cACTC,KAAM,aACNC,mBAAoB,wBACpBC,oBAAqB,yBACrBC,YAAa,eACbC,WAAY"}
|
||||
{"version":3,"file":"selectors.min.js","sources":["../src/selectors.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see <http://www.gnu.org/licenses/>.\n\n/**\n * Define all of the selectors we will be using on the contentbank interface.\n *\n * @module core_contentbank/selectors\n * @copyright 2020 Sara Arjona <sara@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\n/**\n * A small helper function to build queryable data selectors.\n *\n * @method getDataSelector\n * @param {String} name\n * @param {String} value\n * @return {string}\n */\nconst getDataSelector = (name, value) => {\n return `[data-${name}=\"${value}\"]`;\n};\n\nexport default {\n regions: {\n cbcontentname: getDataSelector('region', 'cb-content-name'),\n contentbank: getDataSelector('region', 'contentbank'),\n filearea: getDataSelector('region', 'filearea')\n },\n actions: {\n search: getDataSelector('action', 'searchcontent'),\n clearSearch: getDataSelector('action', 'clearsearch'),\n viewgrid: getDataSelector('action', 'viewgrid'),\n viewlist: getDataSelector('action', 'viewlist'),\n sortname: getDataSelector('action', 'sortname'),\n sortuses: getDataSelector('action', 'sortuses'),\n sortdate: getDataSelector('action', 'sortdate'),\n sortsize: getDataSelector('action', 'sortsize'),\n sorttype: getDataSelector('action', 'sorttype'),\n sortauthor: getDataSelector('action', 'sortauthor'),\n },\n elements: {\n listitem: '.cb-listitem',\n heading: '.cb-heading',\n cell: '.cb-column',\n cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',\n cbnavbartotalsearch: '.cb-navbar-totalsearch',\n searchinput: '[role=\"searchbox\"]',\n sortbutton: '.cb-btnsort'\n },\n};\n"],"names":["getDataSelector","name","value","regions","cbcontentname","contentbank","filearea","actions","search","clearSearch","viewgrid","viewlist","sortname","sortuses","sortdate","sortsize","sorttype","sortauthor","elements","listitem","heading","cell","cbnavbarbreadcrumb","cbnavbartotalsearch","searchinput","sortbutton"],"mappings":";;;;;;;;MA+BMA,gBAAkB,CAACC,KAAMC,wBACXD,kBAASC,yBAGd,CACXC,QAAS,CACLC,cAAeJ,gBAAgB,SAAU,mBACzCK,YAAaL,gBAAgB,SAAU,eACvCM,SAAUN,gBAAgB,SAAU,aAExCO,QAAS,CACLC,OAAQR,gBAAgB,SAAU,iBAClCS,YAAaT,gBAAgB,SAAU,eACvCU,SAAUV,gBAAgB,SAAU,YACpCW,SAAUX,gBAAgB,SAAU,YACpCY,SAAUZ,gBAAgB,SAAU,YACpCa,SAAUb,gBAAgB,SAAU,YACpCc,SAAUd,gBAAgB,SAAU,YACpCe,SAAUf,gBAAgB,SAAU,YACpCgB,SAAUhB,gBAAgB,SAAU,YACpCiB,WAAYjB,gBAAgB,SAAU,eAE1CkB,SAAU,CACNC,SAAU,eACVC,QAAS,cACTC,KAAM,aACNC,mBAAoB,wBACpBC,oBAAqB,yBACrBC,YAAa,qBACbC,WAAY"}
|
||||
@@ -57,7 +57,7 @@ export default {
|
||||
cell: '.cb-column',
|
||||
cbnavbarbreadcrumb: '.cb-navbar-breadbrumb',
|
||||
cbnavbartotalsearch: '.cb-navbar-totalsearch',
|
||||
searchinput: '#searchinput',
|
||||
searchinput: '[role="searchbox"]',
|
||||
sortbutton: '.cb-btnsort'
|
||||
},
|
||||
};
|
||||
|
||||
+6
-3
@@ -27,15 +27,18 @@ use \core_contentbank\content;
|
||||
/**
|
||||
* Get the current user preferences that are available
|
||||
*
|
||||
* @return Array preferences configuration
|
||||
* @uses core_user::is_current_user
|
||||
*
|
||||
* @return array[] preferences configuration
|
||||
*/
|
||||
function core_contentbank_user_preferences() {
|
||||
function core_contentbank_user_preferences(): array {
|
||||
return [
|
||||
'core_contentbank_view_list' => [
|
||||
'choices' => array(0, 1),
|
||||
'type' => PARAM_INT,
|
||||
'null' => NULL_NOT_ALLOWED,
|
||||
'default' => 'none'
|
||||
'default' => 0,
|
||||
'permissioncallback' => [core_user::class, 'is_current_user'],
|
||||
],
|
||||
'core_contentbank_visibility' => [
|
||||
'choices' => [content::VISIBILITY_UNLISTED, content::VISIBILITY_PUBLIC],
|
||||
|
||||
@@ -26,6 +26,8 @@ namespace core_course\management;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
|
||||
/**
|
||||
* Course and category management interface helper class.
|
||||
*
|
||||
|
||||
@@ -483,6 +483,7 @@ class core_course_external extends external_api {
|
||||
'dataid' => new external_value(PARAM_NOTAGS, 'cm data id', VALUE_OPTIONAL),
|
||||
)
|
||||
),
|
||||
'Course dates',
|
||||
VALUE_DEFAULT,
|
||||
[]
|
||||
),
|
||||
@@ -514,7 +515,7 @@ class core_course_external extends external_api {
|
||||
VALUE_OPTIONAL
|
||||
),
|
||||
)
|
||||
), VALUE_DEFAULT, array()
|
||||
), 'Course contents', VALUE_DEFAULT, array()
|
||||
),
|
||||
'contentsinfo' => new external_single_structure(
|
||||
array(
|
||||
@@ -1305,7 +1306,7 @@ class core_course_external extends external_api {
|
||||
'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
|
||||
)
|
||||
)
|
||||
), VALUE_DEFAULT, array()
|
||||
), 'Course duplication options', VALUE_DEFAULT, array()
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -1532,7 +1533,7 @@ class core_course_external extends external_api {
|
||||
'value' => new external_value(PARAM_RAW, 'the value for the option 1 (yes) or 0 (no)'
|
||||
)
|
||||
)
|
||||
), VALUE_DEFAULT, array()
|
||||
), 'Course import options', VALUE_DEFAULT, array()
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -158,7 +158,10 @@ export default class Component extends BaseComponent {
|
||||
*/
|
||||
_sectionTogglers(event) {
|
||||
const sectionlink = event.target.closest(this.selectors.TOGGLER);
|
||||
const isChevron = event.target.closest(this.selectors.COLLAPSE);
|
||||
const closestCollapse = event.target.closest(this.selectors.COLLAPSE);
|
||||
// Assume that chevron is the only collapse toggler in a section heading;
|
||||
// I think this is the most efficient way to verify at the moment.
|
||||
const isChevron = closestCollapse?.closest(this.selectors.SECTION_ITEM);
|
||||
|
||||
if (sectionlink || isChevron) {
|
||||
|
||||
|
||||
@@ -295,6 +295,9 @@ export default class {
|
||||
*/
|
||||
async sectionIndexCollapsed(stateManager, sectionIds, collapsed) {
|
||||
const collapsedIds = this._updateStateSectionPreference(stateManager, 'indexcollapsed', sectionIds, collapsed);
|
||||
if (!collapsedIds) {
|
||||
return;
|
||||
}
|
||||
const course = stateManager.get('course');
|
||||
await this._callEditWebservice('section_index_collapsed', course.id, collapsedIds);
|
||||
}
|
||||
@@ -308,6 +311,9 @@ export default class {
|
||||
*/
|
||||
async sectionContentCollapsed(stateManager, sectionIds, collapsed) {
|
||||
const collapsedIds = this._updateStateSectionPreference(stateManager, 'contentcollapsed', sectionIds, collapsed);
|
||||
if (!collapsedIds) {
|
||||
return;
|
||||
}
|
||||
const course = stateManager.get('course');
|
||||
await this._callEditWebservice('section_content_collapsed', course.id, collapsedIds);
|
||||
}
|
||||
@@ -319,7 +325,7 @@ export default class {
|
||||
* @param {string} preferenceName the preference name
|
||||
* @param {array} sectionIds the affected section ids
|
||||
* @param {boolean} preferenceValue the new preferenceValue value
|
||||
* @return {array} the list of all sections with that preference set to true
|
||||
* @return {Number[]|null} sections ids with the preference value true or null if no update is required
|
||||
*/
|
||||
_updateStateSectionPreference(stateManager, preferenceName, sectionIds, preferenceValue) {
|
||||
stateManager.setReadOnly(false);
|
||||
@@ -328,7 +334,7 @@ export default class {
|
||||
sectionIds.forEach(sectionId => {
|
||||
const section = stateManager.get('section', sectionId);
|
||||
if (section === undefined) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
const newValue = preferenceValue ?? section[preferenceName];
|
||||
if (section[preferenceName] != newValue) {
|
||||
@@ -338,7 +344,7 @@ export default class {
|
||||
});
|
||||
stateManager.setReadOnly(true);
|
||||
if (affectedSections.size == 0) {
|
||||
return [];
|
||||
return null;
|
||||
}
|
||||
// Get all collapsed section ids.
|
||||
const collapsedSectionIds = [];
|
||||
|
||||
@@ -225,6 +225,18 @@ abstract class base {
|
||||
self::$instances = array();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reset the current user for all courses.
|
||||
*
|
||||
* The course format cache resets every time the course cache resets but
|
||||
* also when the user changes their language, all course editors
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function session_cache_reset_all(): void {
|
||||
$statecache = cache::make('core', 'courseeditorstate');
|
||||
$statecache->purge();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the current user course format cache.
|
||||
|
||||
@@ -102,12 +102,15 @@ class cmname implements named_templatable, renderable {
|
||||
'url' => $mod->url,
|
||||
'icon' => $mod->get_icon_url(),
|
||||
'modname' => $mod->modname,
|
||||
'pluginname' => get_string('pluginname', 'mod_' . $mod->modname),
|
||||
'textclasses' => $displayoptions['textclasses'] ?? '',
|
||||
'purpose' => plugin_supports('mod', $mod->modname, FEATURE_MOD_PURPOSE, MOD_PURPOSE_OTHER),
|
||||
'activityname' => $this->get_title_data($output),
|
||||
];
|
||||
|
||||
if ($this->format->show_editor()) {
|
||||
$data['pluginname'] = get_string('pluginname', 'mod_' . $mod->modname);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
@@ -76,3 +76,13 @@ Feature: Activity navigation in a single activity course
|
||||
Given I log in as "student2"
|
||||
When I am on "Course 1" course homepage
|
||||
Then I should see "You cannot enrol yourself in this course"
|
||||
|
||||
Scenario: The single activity course format supports multilang course names
|
||||
Given the "multilang" filter is "on"
|
||||
And the "multilang" filter applies to "content and headings"
|
||||
When I am on the "Course 1" "course editing" page logged in as "teacher1"
|
||||
And I expand all fieldsets
|
||||
And I set the field "Course full name" in the "General" "fieldset" to "<span lang=\"de\" class=\"multilang\">Kurs</span><span lang=\"en\" class=\"multilang\">Course</span> 1"
|
||||
And I click on "Save and display" "button"
|
||||
Then I should see "Course 1" in the ".page-header-headings" "css_element"
|
||||
And I should not see "KursCourse 1" in the ".page-header-headings" "css_element"
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
{{/ core_courseformat/local/content/cm/cmname }}
|
||||
{{/cmname}}
|
||||
{{#afterlink}}
|
||||
<div class="afterlink">
|
||||
<div class="afterlink d-flex align-items-center ml-3">
|
||||
{{{afterlink}}}
|
||||
</div>
|
||||
{{/afterlink}}
|
||||
|
||||
@@ -50,9 +50,11 @@
|
||||
<img src="{{{icon}}}" class="activityicon " alt="{{{modname}}} icon">
|
||||
</div>
|
||||
<div class="media-body align-self-center">
|
||||
{{#pluginname}}
|
||||
<div class="text-uppercase small">
|
||||
{{{pluginname}}}
|
||||
</div>
|
||||
{{/pluginname}}
|
||||
<div class="activityname">
|
||||
{{#activityname}}
|
||||
{{$ core/inplace_editable }}
|
||||
|
||||
@@ -18,7 +18,7 @@ Feature: Course content collapsed user preferences
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Activity sample 1 | Test assignment description | C1 | sample1 | 1 |
|
||||
| book | Activity sample 2 | Test book description | C1 | sample2 | 2 |
|
||||
| book | Activity sample 2 | | C1 | sample2 | 2 |
|
||||
| choice | Activity sample 3 | Test choice description | C1 | sample3 | 3 |
|
||||
| assign | Activity sample 4 | Test assignment description | C1 | sample1 | 4 |
|
||||
| assign | Activity sample 5 | Test assignment description | C1 | sample1 | 5 |
|
||||
|
||||
@@ -18,7 +18,7 @@ Feature: Course index depending on role
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Activity sample 1 | Test assignment description | C1 | sample1 | 1 |
|
||||
| book | Activity sample 2 | Test book description | C1 | sample2 | 2 |
|
||||
| book | Activity sample 2 | | C1 | sample2 | 2 |
|
||||
| choice | Activity sample 3 | Test choice description | C1 | sample3 | 3 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
@@ -129,10 +129,9 @@ Feature: Course index depending on role
|
||||
@javascript
|
||||
Scenario: Course index toggling
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| book | Second activity in section 1 | Test book description | C1 | sample4 | 1 |
|
||||
And I log in as "teacher1"
|
||||
When I am on "Course 1" course homepage
|
||||
| activity | name | course | idnumber | section |
|
||||
| book | Second activity in section 1 | C1 | sample4 | 1 |
|
||||
When I am on the "Course 1" course page logged in as teacher1
|
||||
# Sections should be opened by default.
|
||||
Then I should see "Topic 1" in the "courseindex-content" "region"
|
||||
And I should see "Activity sample 1" in the "courseindex-content" "region"
|
||||
@@ -298,3 +297,14 @@ Feature: Course index depending on role
|
||||
| large | be | Close | not be | Open | be |
|
||||
| tablet | not be | Open | not be | Open | not be |
|
||||
| mobile | not be | Open | not be | Open | not be |
|
||||
|
||||
@javascript
|
||||
Scenario: Course index is refreshed when we change role.
|
||||
When I am on the "C1" "Course" page logged in as "teacher1"
|
||||
And I turn editing mode on
|
||||
And I hide section "1"
|
||||
And I turn editing mode off
|
||||
And I should see "Topic 1" in the "courseindex-content" "region"
|
||||
And I follow "Switch role to..." in the user menu
|
||||
And I press "Student"
|
||||
Then I should not see "Topic 1" in the "courseindex-content" "region"
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Verify that courseindex is usable with the keyboard
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Activity sample 1 | Test assignment description | C1 | sample1 | 1 |
|
||||
| book | Activity sample 2 | Test book description | C1 | sample2 | 2 |
|
||||
| book | Activity sample 2 | | C1 | sample2 | 2 |
|
||||
| choice | Activity sample 3 | Test choice description | C1 | sample3 | 3 |
|
||||
Given I am on the "C1" "Course" page logged in as "admin"
|
||||
And I change window size to "large"
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
@core @core_course @core_courseformat
|
||||
Feature: The course index language should change according to user preferences.
|
||||
As a user in a course
|
||||
I should see the same language in the course index and the course content when I switch languages.
|
||||
|
||||
Background:
|
||||
Given remote langimport tests are enabled
|
||||
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" exists:
|
||||
| fullname | Course 1 |
|
||||
| shortname | C1 |
|
||||
| category | 0 |
|
||||
| enablecompletion | 1 |
|
||||
| numsections | 4 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
And the following "language pack" exists:
|
||||
| language | fr |
|
||||
And I change window size to "large"
|
||||
|
||||
@javascript
|
||||
Scenario Outline: Course index is refreshed when we change language.
|
||||
Given I am on the "C1" "Course" page logged in as "<user>"
|
||||
When I follow "Language" in the user menu
|
||||
Then I should see "Language selector" user submenu
|
||||
And I follow "Français (fr)"
|
||||
Then I should see "Généralités" in the "courseindex-content" "region"
|
||||
Examples:
|
||||
| user |
|
||||
| student1 |
|
||||
| teacher1 |
|
||||
@@ -14,7 +14,7 @@ Feature: Move activity using keyboard
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Activity sample 1 | Test assignment description | C1 | sample1 | 1 |
|
||||
| book | Activity sample 2 | Test book description | C1 | sample2 | 2 |
|
||||
| book | Activity sample 2 | | C1 | sample2 | 2 |
|
||||
| choice | Activity sample 3 | Test choice description | C1 | sample3 | 3 |
|
||||
| choice | Other sample 3 | Test choice description | C1 | sample31 | 3 |
|
||||
And I log in as "admin"
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Move a section using keyboard
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Activity sample 1 | Test assignment description | C1 | sample1 | 1 |
|
||||
| book | Activity sample 2 | Test book description | C1 | sample2 | 2 |
|
||||
| book | Activity sample 2 | | C1 | sample2 | 2 |
|
||||
| choice | Activity sample 3 | Test choice description | C1 | sample3 | 3 |
|
||||
| choice | Other sample 3 | Test choice description | C1 | sample31 | 3 |
|
||||
And I log in as "admin"
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Sections can be edited and deleted in topics format
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Test assignment name | Test assignment description | C1 | assign1 | 0 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 |
|
||||
| book | Test book name | | C1 | book1 | 1 |
|
||||
| chat | Test chat name | Test chat description | C1 | chat1 | 4 |
|
||||
| choice | Test choice name | Test choice description | C1 | choice1 | 5 |
|
||||
And the following "course enrolments" exist:
|
||||
|
||||
@@ -14,7 +14,7 @@ Feature: Sections can be edited and deleted in weeks format
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | section |
|
||||
| assign | Test assignment name | Test assignment description | C1 | assign1 | 0 |
|
||||
| book | Test book name | Test book description | C1 | book1 | 1 |
|
||||
| book | Test book name | | C1 | book1 | 1 |
|
||||
| chat | Test chat name | Test chat description | C1 | chat1 | 4 |
|
||||
| choice | Test choice name | Test choice description | C1 | choice1 | 5 |
|
||||
And the following "course enrolments" exist:
|
||||
|
||||
@@ -57,8 +57,8 @@ Feature: Toggle activities visibility from the course page
|
||||
And I click on "Edit settings" "link" in the "Test forum name" activity
|
||||
And I expand all fieldsets
|
||||
And the "Availability" select box should contain "Show on course page"
|
||||
And the "Availability" select box should not contain "Make available but not shown on course page"
|
||||
And the field "Availability" matches value "Hide from students"
|
||||
And the "Availability" select box should not contain "Make available but don't show on course page"
|
||||
And the field "Availability" matches value "Hide on course page"
|
||||
And I press "Save and return to course"
|
||||
And "Test forum name" activity should be hidden
|
||||
And I turn editing mode off
|
||||
@@ -100,10 +100,10 @@ Feature: Toggle activities visibility from the course page
|
||||
And I open "Test forum name" actions menu
|
||||
And I click on "Edit settings" "link" in the "Test forum name" activity
|
||||
And I expand all fieldsets
|
||||
And the "Availability" select box should contain "Hide from students"
|
||||
And the "Availability" select box should contain "Make available but not shown on course page"
|
||||
And the "Availability" select box should contain "Hide on course page"
|
||||
And the "Availability" select box should contain "Make available but don't show on course page"
|
||||
And the "Availability" select box should not contain "Show on course page"
|
||||
And I set the field "Availability" to "Make available but not shown on course page"
|
||||
And I set the field "Availability" to "Make available but don't show on course page"
|
||||
And I press "Save and return to course"
|
||||
And "Test forum name" activity should be available but hidden from course page
|
||||
And I turn editing mode off
|
||||
@@ -142,8 +142,8 @@ Feature: Toggle activities visibility from the course page
|
||||
And I click on "Edit settings" "link" in the "Test assignment name" activity
|
||||
And I expand all fieldsets
|
||||
And the "Availability" select box should contain "Show on course page"
|
||||
And the "Availability" select box should contain "Hide from students"
|
||||
And the field "Availability" matches value "Make available but not shown on course page"
|
||||
And the "Availability" select box should contain "Hide on course page"
|
||||
And the field "Availability" matches value "Make available but don't show on course page"
|
||||
And I press "Save and return to course"
|
||||
And "Test assignment name" activity should be available but hidden from course page
|
||||
And I turn editing mode off
|
||||
|
||||
@@ -22,8 +22,8 @@ Feature: Collapse course sections
|
||||
| activity | name | intro | course | idnumber | section | completion |
|
||||
| assign | Assignment 1 | Test assignment description1 | C1 | assign1 | 1 | 1 |
|
||||
| assign | Assignment 2 | Test assignment description2 | C1 | assign2 | 2 | 1 |
|
||||
| book | Book 2 | Test book description2 | C1 | book2 | 2 | 1 |
|
||||
| book | Book 3 | Test book description3 | C1 | book3 | 3 | 1 |
|
||||
| book | Book 2 | | C1 | book2 | 2 | 1 |
|
||||
| book | Book 3 | | C1 | book3 | 3 | 1 |
|
||||
| forum | Forum 4 | Test forum description4 | C1 | forum4 | 4 | 1 |
|
||||
| forum | Forum 5 | Test forum description5 | C1 | forum5 | 5 | 1 |
|
||||
And the following "course enrolments" exist:
|
||||
@@ -58,8 +58,7 @@ Feature: Collapse course sections
|
||||
|
||||
@javascript
|
||||
Scenario: Expand/collapse sections for Topics format.
|
||||
Given I log in as "student1"
|
||||
And I am on "Course 1" course homepage
|
||||
Given I am on the "Course 1" course page logged in as student1
|
||||
And "[data-toggle=collapse]" "css_element" should exist in the "region-main" "region"
|
||||
And I should see "Assignment 1" in the "region-main" "region"
|
||||
And I should see "Assignment 2" in the "region-main" "region"
|
||||
@@ -97,8 +96,7 @@ Feature: Collapse course sections
|
||||
|
||||
@javascript
|
||||
Scenario: Expand/collapse sections for Weeks format.
|
||||
Given I log in as "teacher1"
|
||||
And I am on "Course 1" course homepage
|
||||
Given I am on the "Course 1" course page logged in as teacher1
|
||||
When I navigate to "Settings" in current page administration
|
||||
And I expand all fieldsets
|
||||
And I set the following fields to these values:
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
@core @core_course
|
||||
Feature: Teacher can change the course format
|
||||
In order to change course format
|
||||
As a teacher
|
||||
I should be able to edit a course
|
||||
|
||||
@javascript
|
||||
Scenario: Teacher can change the course format
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com |
|
||||
# Course format is initially set to Topics format
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | format | startdate |
|
||||
| Course 1 | C1 | topics | ## 1 day ago ## |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
# Confirm that course format is Topics
|
||||
When I am on the "Course 1" course page logged in as teacher1
|
||||
Then I should see "Topic 1"
|
||||
And I am on the "Course 1" "course editing" page
|
||||
And I expand all fieldsets
|
||||
# Fields that appear for Topics format exist
|
||||
# Also confirm contents of Hidden sections and Course layout select box
|
||||
And I should see "Hidden sections"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are shown as not available"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are completely invisible"
|
||||
# Hidden sections default value is 1 (Hidden sections are completely invisible)
|
||||
And the field "Hidden sections" matches value "1"
|
||||
And I should see "Course layout"
|
||||
And the "Course layout" select box should contain "Show all sections on one page"
|
||||
And the "Course layout" select box should contain "Show one section per page"
|
||||
# Course layout default value is 0 (Show all sections on one page)
|
||||
And the field "Course layout" matches value "0"
|
||||
# Set course format to Single activity format
|
||||
And I set the field "Format" to "Single activity format"
|
||||
And I expand all fieldsets
|
||||
# Confirm that fields that appear for Single activity format appears
|
||||
And I should see "Type of activity"
|
||||
And I set the field "Type of activity" to "Glossary"
|
||||
And I press "Save and display"
|
||||
And I set the field "Name" to "Glossary 1"
|
||||
And I press "Save and display"
|
||||
# Confirm that course page displays single activity of type Glossary
|
||||
And I should see "Browse the glossary using this index"
|
||||
And I should not see "Topic 1"
|
||||
And I am on the "Course 1" "course editing" page
|
||||
And I expand all fieldsets
|
||||
# Set course format to Weekly format
|
||||
And I set the field "Format" to "Weekly format"
|
||||
And I expand all fieldsets
|
||||
# Confirm that fields that appear for Weekly format appears
|
||||
# Also confirm contents of Hidden sections and Course layout select box
|
||||
And I should see "Hidden sections"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are shown as not available"
|
||||
And the "Hidden sections" select box should contain "Hidden sections are completely invisible"
|
||||
# Hidden sections default value is 1 (Hidden sections are completely invisible)
|
||||
And the field "Hidden sections" matches value "1"
|
||||
And I should see "Course layout"
|
||||
And the "Course layout" select box should contain "Show all sections on one page"
|
||||
And the "Course layout" select box should contain "Show one section per page"
|
||||
# Course layout default value is 0 (Show all sections on one page)
|
||||
And the field "Course layout" matches value "0"
|
||||
And I press "Save and display"
|
||||
# Confirm that course page displays weekly sections
|
||||
And I should see "This week"
|
||||
And I should not see "Browse the glossary using this index"
|
||||
And I am on the "Course 1" "course editing" page
|
||||
And I expand all fieldsets
|
||||
# Set course format to Social format
|
||||
And I set the field "Format" to "Social format"
|
||||
# Confirm that fields that appear for Social format appears
|
||||
And I expand all fieldsets
|
||||
And I should see "Number of discussions"
|
||||
And the field "Number of discussions" matches value "10"
|
||||
And I press "Save and display"
|
||||
# Confirm that course page displays a forum
|
||||
And I should see "There are no discussion topics yet in this forum"
|
||||
And I should not see "This week"
|
||||
@@ -21,7 +21,7 @@ Feature: Show/hide course sections
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test hidden forum 11 name |
|
||||
| Description | Test hidden forum 11 description |
|
||||
| Availability | Hide from students |
|
||||
| Availability | Hide on course page |
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test hidden forum 12 name |
|
||||
| Description | Test hidden forum 12 description |
|
||||
@@ -29,7 +29,7 @@ Feature: Show/hide course sections
|
||||
And I add a "Forum" to section "2" and I fill the form with:
|
||||
| Forum name | Test hidden forum 21 name |
|
||||
| Description | Test hidden forum 21 description |
|
||||
| Availability | Hide from students |
|
||||
| Availability | Hide on course page |
|
||||
And I add a "Forum" to section "2" and I fill the form with:
|
||||
| Forum name | Test hidden forum 22 name |
|
||||
| Description | Test hidden forum 22 description |
|
||||
@@ -37,7 +37,7 @@ Feature: Show/hide course sections
|
||||
And I add a "Forum" to section "3" and I fill the form with:
|
||||
| Forum name | Test hidden forum 31 name |
|
||||
| Description | Test hidden forum 31 description |
|
||||
| Availability | Hide from students |
|
||||
| Availability | Hide on course page |
|
||||
And I add a "Forum" to section "3" and I fill the form with:
|
||||
| Forum name | Test hidden forum 32 name |
|
||||
| Description | Test hidden forum 32 description |
|
||||
|
||||
@@ -21,6 +21,11 @@ namespace core_course\reportbuilder\datasource;
|
||||
use core_customfield_generator;
|
||||
use core_reportbuilder_testcase;
|
||||
use core_reportbuilder_generator;
|
||||
use core_reportbuilder\local\filters\boolean_select;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\filters\select;
|
||||
use core_reportbuilder\local\filters\text;
|
||||
use core_reportbuilder\local\helpers\user_filter_manager;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -38,9 +43,9 @@ require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
|
||||
class courses_test extends core_reportbuilder_testcase {
|
||||
|
||||
/**
|
||||
* Test courses datasource
|
||||
* Test default datasource
|
||||
*/
|
||||
public function test_courses_datasource(): void {
|
||||
public function test_datasource_default(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Test subject.
|
||||
@@ -54,20 +59,92 @@ class courses_test extends core_reportbuilder_testcase {
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Courses', 'source' => courses::class]);
|
||||
$report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 1]);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
$this->assertCount(1, $content);
|
||||
|
||||
$contentrow = array_values(reset($content));
|
||||
$contentrow = array_values($content[0]);
|
||||
|
||||
$this->assertEquals([
|
||||
'My cats', // Category name.
|
||||
'C101', // Course shortname.
|
||||
'All about cats', // Course fullname.
|
||||
'CAT101', // Course ID number.
|
||||
$category->get_formatted_name(),
|
||||
$course->shortname,
|
||||
$course->fullname,
|
||||
$course->idnumber,
|
||||
], $contentrow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test datasource columns that aren't added by default
|
||||
*/
|
||||
public function test_datasource_non_default_columns(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$category = $this->getDataGenerator()->create_category([
|
||||
'name' => 'Animals',
|
||||
'idnumber' => 'CAT101',
|
||||
'description' => 'Category description',
|
||||
]);
|
||||
$course = $this->getDataGenerator()->create_course([
|
||||
'category' => $category->id,
|
||||
'fullname' => 'Cats',
|
||||
'summary' => 'Course description',
|
||||
]);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]);
|
||||
|
||||
// Category.
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:path']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:idnumber']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course_category:description']);
|
||||
|
||||
// Course.
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:coursefullnamewithlink']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseshortnamewithlink']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:courseidnumberewithlink']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:summary']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:format']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:startdate']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enddate']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:visible']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmode']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:groupmodeforce']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:lang']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:calendartype']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:theme']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:enablecompletion']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:downloadcontent']);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
$this->assertCount(1, $content);
|
||||
|
||||
$courserow = array_values($content[0]);
|
||||
|
||||
// Category.
|
||||
$this->assertEquals($category->get_nested_name(false), $courserow[0]);
|
||||
$this->assertEquals($category->idnumber, $courserow[1]);
|
||||
$this->assertEquals(format_text($category->description, $category->descriptionformat), $courserow[2]);
|
||||
|
||||
// Course.
|
||||
$this->assertStringContainsString($course->fullname, $courserow[3]);
|
||||
$this->assertStringContainsString($course->shortname, $courserow[4]);
|
||||
$this->assertStringContainsString($course->idnumber, $courserow[5]);
|
||||
$this->assertEquals(format_text($course->summary, $course->summaryformat), $courserow[6]);
|
||||
$this->assertEquals('Topics format', $courserow[7]);
|
||||
$this->assertEquals(userdate($course->startdate), $courserow[8]);
|
||||
$this->assertEmpty($courserow[9]);
|
||||
$this->assertEquals('Yes', $courserow[10]);
|
||||
$this->assertEquals('No groups', $courserow[11]);
|
||||
$this->assertEquals('No', $courserow[12]);
|
||||
$this->assertEmpty($courserow[13]);
|
||||
$this->assertEmpty($courserow[14]);
|
||||
$this->assertEmpty($courserow[15]);
|
||||
$this->assertEquals('No', $courserow[16]);
|
||||
$this->assertEmpty($courserow[17]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests courses datasource using multilang filters
|
||||
*/
|
||||
@@ -106,6 +183,181 @@ class courses_test extends core_reportbuilder_testcase {
|
||||
], $contentrow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for {@see test_datasource_filters}
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public function datasource_filters_provider(): array {
|
||||
return [
|
||||
// Category.
|
||||
'Filter category' => ['course_category:name', [
|
||||
'course_category:name_operator' => select::EQUAL_TO,
|
||||
'course_category:name_value' => -1,
|
||||
], false],
|
||||
'Filter category idnumber' => ['course_category:idnumber', [
|
||||
'course_category:idnumber_operator' => text::IS_EQUAL_TO,
|
||||
'course_category:idnumber_value' => 'CAT101',
|
||||
], true],
|
||||
'Filter category idnumber (no match)' => ['course_category:idnumber', [
|
||||
'course_category:idnumber_operator' => text::CONTAINS,
|
||||
'course_category:idnumber_value' => 'FRUIT',
|
||||
], false],
|
||||
|
||||
// Course.
|
||||
'Filter course' => ['course:courseselector', [
|
||||
'course:courseselector_values' => [-1],
|
||||
], false],
|
||||
'Filter course fullname' => ['course:fullname', [
|
||||
'course:fullname_operator' => text::IS_EQUAL_TO,
|
||||
'course:fullname_value' => 'Equine',
|
||||
], true],
|
||||
'Filter course fullname (no match)' => ['course:fullname', [
|
||||
'course:fullname_operator' => text::IS_EQUAL_TO,
|
||||
'course:fullname_value' => 'Foxes',
|
||||
], false],
|
||||
'Filter course shortname' => ['course:shortname', [
|
||||
'course:shortname_operator' => text::IS_EQUAL_TO,
|
||||
'course:shortname_value' => 'EQ101',
|
||||
], true],
|
||||
'Filter course shortname (no match)' => ['course:shortname', [
|
||||
'course:shortname_operator' => text::IS_EQUAL_TO,
|
||||
'course:shortname_value' => 'FX101',
|
||||
], false],
|
||||
'Filter course idnumber' => ['course:idnumber', [
|
||||
'course:idnumber_operator' => text::IS_EQUAL_TO,
|
||||
'course:idnumber_value' => 'E-101AB',
|
||||
], true],
|
||||
'Filter course idnumber (no match)' => ['course:idnumber', [
|
||||
'course:idnumber_operator' => text::IS_EQUAL_TO,
|
||||
'course:idnumber_value' => 'F-101XT',
|
||||
], false],
|
||||
'Filter course format' => ['course:format', [
|
||||
'course:format_operator' => select::EQUAL_TO,
|
||||
'course:format_value' => 'topics',
|
||||
], true],
|
||||
'Filter course format (no match)' => ['course:format', [
|
||||
'course:format_operator' => select::EQUAL_TO,
|
||||
'course:format_value' => 'weekly',
|
||||
], false],
|
||||
'Filter course startdate' => ['course:startdate', [
|
||||
'course:startdate_operator' => date::DATE_RANGE,
|
||||
'course:startdate_from' => 1622502000,
|
||||
], true],
|
||||
'Filter course startdate (no match)' => ['course:startdate', [
|
||||
'course:startdate_operator' => date::DATE_RANGE,
|
||||
'course:startdate_to' => 1622502000,
|
||||
], false],
|
||||
'Filter course enddate' => ['course:enddate', [
|
||||
'course:enddate_operator' => date::DATE_EMPTY,
|
||||
], true],
|
||||
'Filter course enddate (no match)' => ['course:enddate', [
|
||||
'course:enddate_operator' => date::DATE_NOT_EMPTY,
|
||||
], false],
|
||||
'Filter course visible' => ['course:visible', [
|
||||
'course:visible_operator' => boolean_select::CHECKED,
|
||||
], true],
|
||||
'Filter course visible (no match)' => ['course:visible', [
|
||||
'course:visible_operator' => boolean_select::NOT_CHECKED,
|
||||
], false],
|
||||
'Filter course groupmode' => ['course:groupmode', [
|
||||
'course:groupmode_operator' => select::EQUAL_TO,
|
||||
'course:groupmode_value' => 0, // No groups.
|
||||
], true],
|
||||
'Filter course groupmode (no match)' => ['course:groupmode', [
|
||||
'course:groupmode_operator' => select::EQUAL_TO,
|
||||
'course:groupmode_value' => 1, // Separate groups.
|
||||
], false],
|
||||
'Filter course groupmodeforce' => ['course:groupmodeforce', [
|
||||
'course:groupmodeforce_operator' => boolean_select::NOT_CHECKED,
|
||||
], true],
|
||||
'Filter course groupmodeforce (no match)' => ['course:groupmodeforce', [
|
||||
'course:groupmodeforce_operator' => boolean_select::CHECKED,
|
||||
], false],
|
||||
'Filter course lang' => ['course:lang', [
|
||||
'course:lang_operator' => select::EQUAL_TO,
|
||||
'course:lang_value' => 'en',
|
||||
], true],
|
||||
'Filter course lang (no match)' => ['course:lang', [
|
||||
'course:lang_operator' => select::EQUAL_TO,
|
||||
'course:lang_value' => 'de',
|
||||
], false],
|
||||
'Filter course calendartype' => ['course:calendartype', [
|
||||
'course:calendartype_operator' => select::EQUAL_TO,
|
||||
'course:calendartype_value' => 'gregorian',
|
||||
], true],
|
||||
'Filter course calendartype (no match)' => ['course:calendartype', [
|
||||
'course:calendartype_operator' => select::EQUAL_TO,
|
||||
'course:calendartype_value' => 'hijri',
|
||||
], false],
|
||||
'Filter course theme' => ['course:theme', [
|
||||
'course:theme_operator' => select::EQUAL_TO,
|
||||
'course:theme_value' => 'boost',
|
||||
], true],
|
||||
'Filter course theme (no match)' => ['course:theme', [
|
||||
'course:theme_operator' => select::EQUAL_TO,
|
||||
'course:theme_value' => 'classic',
|
||||
], false],
|
||||
'Filter course enablecompletion' => ['course:enablecompletion', [
|
||||
'course:enablecompletion_operator' => boolean_select::NOT_CHECKED,
|
||||
], true],
|
||||
'Filter course enablecompletion (no match)' => ['course:enablecompletion', [
|
||||
'course:enablecompletion_operator' => boolean_select::CHECKED,
|
||||
], false],
|
||||
'Filter course downloadcontent' => ['course:downloadcontent', [
|
||||
'course:downloadcontent_operator' => boolean_select::CHECKED,
|
||||
], true],
|
||||
'Filter course downloadcontent (no match)' => ['course:downloadcontent', [
|
||||
'course:downloadcontent_operator' => boolean_select::NOT_CHECKED,
|
||||
], false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test datasource filters
|
||||
*
|
||||
* @param string $filtername
|
||||
* @param array $filtervalues
|
||||
* @param bool $expectmatch
|
||||
*
|
||||
* @dataProvider datasource_filters_provider
|
||||
*/
|
||||
public function test_datasource_filters(string $filtername, array $filtervalues, bool $expectmatch): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$category = $this->getDataGenerator()->create_category(['name' => 'Animals', 'idnumber' => 'CAT101']);
|
||||
$course = $this->getDataGenerator()->create_course([
|
||||
'category' => $category->id,
|
||||
'fullname' => 'Equine',
|
||||
'shortname' => 'EQ101',
|
||||
'idnumber' => 'E-101AB',
|
||||
'lang' => 'en',
|
||||
'calendartype' => 'gregorian',
|
||||
'theme' => 'boost',
|
||||
'downloadcontent' => 1,
|
||||
]);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
|
||||
// Create report containing single column, and given filter.
|
||||
$report = $generator->create_report(['name' => 'Tasks', 'source' => courses::class, 'default' => 0]);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
|
||||
|
||||
// Add filter, set it's values.
|
||||
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
|
||||
user_filter_manager::set($report->get('id'), $filtervalues);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
|
||||
if ($expectmatch) {
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertEquals($course->fullname, reset($content[0]));
|
||||
} else {
|
||||
$this->assertEmpty($content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stress test datasource
|
||||
*
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user