Compare commits
391 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f810374a0e | |||
| 6c73be6e8e | |||
| 5a7599385f | |||
| eae457d10d | |||
| 56eb910aed | |||
| 11dcef291d | |||
| 42cbafd610 | |||
| fb1752711e | |||
| 99eb359503 | |||
| 6f344ff877 | |||
| 68c20d41fe | |||
| 4272fc3f28 | |||
| 1bd5dfe090 | |||
| f8d0e86350 | |||
| e092c75d15 | |||
| 90b3f5fc26 | |||
| c77bef3ad7 | |||
| 260eef0a72 | |||
| af0fe95d84 | |||
| ee0c928f10 | |||
| d1796d1f0e | |||
| ac2acd0072 | |||
| 155abc6945 | |||
| cf0b182dee | |||
| f863084cc9 | |||
| 2ddad8ce7a | |||
| 8d45a9f2a2 | |||
| 4b0a34f08a | |||
| 3a7f291d38 | |||
| bbfc6312a8 | |||
| fe8d759b17 | |||
| 983921ecff | |||
| f72244a8c2 | |||
| d09f737c7d | |||
| b654282b18 | |||
| bdb5a4ba40 | |||
| 419d7f40c3 | |||
| 7be05aae41 | |||
| 04261e8722 | |||
| a53121b74a | |||
| 6814c42260 | |||
| 658953e34f | |||
| c2c03f203f | |||
| 9a1a58e593 | |||
| 0f63155d58 | |||
| 25e00b5e1f | |||
| b2bc3b9e7e | |||
| 38ed732727 | |||
| 463f16617e | |||
| 260924aeb8 | |||
| d7a1ef5dfa | |||
| b38413afe4 | |||
| 05ab53734b | |||
| 708732ed72 | |||
| 121d6fb20a | |||
| e4acb387bb | |||
| ff74bb2682 | |||
| 17fb4afaab | |||
| 0cb2fd1a7f | |||
| 60541d90e5 | |||
| 4b26df011f | |||
| fbecc7132d | |||
| bbea6e1d31 | |||
| 9e3ca2a866 | |||
| 40ee4ab3fa | |||
| d40fc8708a | |||
| 2a60bc604f | |||
| e8237560d3 | |||
| 258783a754 | |||
| 81de0469c1 | |||
| 638cbfac93 | |||
| 85c70539df | |||
| 5b442418ad | |||
| 9c641bf38e | |||
| f9797aca63 | |||
| d4b1ecbed4 | |||
| d140771110 | |||
| 762df4050c | |||
| bee2d552b7 | |||
| f172248f20 | |||
| db71e79e05 | |||
| 05c9ce4bd8 | |||
| ade9f7177a | |||
| 05846ae405 | |||
| e186ad572d | |||
| 9f636a3de3 | |||
| d79ad5de6a | |||
| b7c8f7f723 | |||
| 46192ca77e | |||
| d68ea95f26 | |||
| 85af2e6a7c | |||
| 4ac4b93064 | |||
| 136aef1fe6 | |||
| 79ea6a2d22 | |||
| e2f5104676 | |||
| bc133f6fc3 | |||
| bea6119692 | |||
| b04fcb4527 | |||
| b4278ca6b0 | |||
| d20c47f89c | |||
| d29433ddc6 | |||
| 0a494aa9f6 | |||
| a418e9e53a | |||
| 3f10ec31b5 | |||
| 488a653e50 | |||
| 7fa08a0b35 | |||
| 6a89731462 | |||
| fd8b7fc730 | |||
| 006eaeef08 | |||
| 2862cce2a9 | |||
| e3d76202cd | |||
| 6441cca4d1 | |||
| 04892e4707 | |||
| 17282deeea | |||
| c2e8975523 | |||
| c5e3ce289e | |||
| 83e442cc69 | |||
| b8f0f87b5f | |||
| 539e5db429 | |||
| 4c3523d987 | |||
| a0951e25b3 | |||
| 70a95b8eae | |||
| 5705496179 | |||
| e77912a7c5 | |||
| fb13f6dd01 | |||
| fbeef47a58 | |||
| 8fa5a3008d | |||
| 2c94380acf | |||
| 8cd66034e4 | |||
| 0bb3a2f20a | |||
| 96f06326f8 | |||
| 8b6d43705e | |||
| eb0575859b | |||
| a6ce3c0758 | |||
| a9bfc2075b | |||
| 6a1644abff | |||
| 1bbc0425e3 | |||
| cb18237b5c | |||
| c898074fd8 | |||
| 14b5d0694f | |||
| 54d0894ec3 | |||
| 0b326e9e72 | |||
| eae154a081 | |||
| 42022a1d26 | |||
| c59c0f906b | |||
| e82f1d43c8 | |||
| 6ff6327a6b | |||
| 4b34028221 | |||
| edbbe29706 | |||
| fc35bc5876 | |||
| 6c5f358ca2 | |||
| 895189107f | |||
| d8c4a57ce8 | |||
| 3d5c60ad26 | |||
| a2cfa93011 | |||
| e40f4e4d83 | |||
| 1f0f185176 | |||
| d5d2c59161 | |||
| c2c357dfb2 | |||
| fccf80c3a3 | |||
| ee26c16e90 | |||
| 26c5ffd356 | |||
| d38211efc6 | |||
| dd844035ac | |||
| 778b8f51b1 | |||
| 4d28563eeb | |||
| 89f3fced22 | |||
| 1ed0cb2562 | |||
| 7e1589b2ee | |||
| bc5d145dfb | |||
| 5aaba2850f | |||
| 3116b46192 | |||
| 3a1aed3578 | |||
| a2544fd5ca | |||
| ebab82c9f3 | |||
| 40e56b3adc | |||
| 0a360e1eb2 | |||
| 59aa25852c | |||
| ba60319c94 | |||
| ad836b6d4c | |||
| 72d7395c96 | |||
| d376741b93 | |||
| ca991dbe29 | |||
| 3a7594c71a | |||
| 9f88fb2125 | |||
| f29c4e36a4 | |||
| a87db5a60d | |||
| 07bbe2fa5e | |||
| 1c11297195 | |||
| 5f59e2a61e | |||
| 7e4119de7e | |||
| c30c1ca9cd | |||
| f50c83ac37 | |||
| c54b573bd0 | |||
| 1f5e140ae9 | |||
| f65d067dec | |||
| dbe914883c | |||
| 783dc4cdb2 | |||
| 26e91219e8 | |||
| 15526541b3 | |||
| c78364eb73 | |||
| 0c9bc880c1 | |||
| 93f282a345 | |||
| 7d4ba18a65 | |||
| e78cbaa6c4 | |||
| 9b401dfc29 | |||
| 3e179325e9 | |||
| 60727a7cdf | |||
| 4d59c788ee | |||
| d5993fffd4 | |||
| 136bd2c4c4 | |||
| b2d8615725 | |||
| 4e880779f9 | |||
| e5efe8b6d1 | |||
| da4a2d6191 | |||
| 84ec153634 | |||
| b69c42db5d | |||
| 55d5f7756d | |||
| b262a67c89 | |||
| 05492ddbb3 | |||
| 185856927d | |||
| 935c2509f1 | |||
| a502fbcd1e | |||
| 061186c215 | |||
| eac49ffa4c | |||
| db82329f6c | |||
| 875ad48c9d | |||
| c627e1a4de | |||
| 3b0165ec67 | |||
| 96bfaf67fd | |||
| fc4354c7e3 | |||
| b5c49b8ac9 | |||
| 2721a7cdc3 | |||
| ab79a0e972 | |||
| 275af6c114 | |||
| dcc8300ef4 | |||
| af62e9773c | |||
| 0ac35f9248 | |||
| a028969791 | |||
| 7bc41babf8 | |||
| 4e08cbd42e | |||
| d3427d45fa | |||
| 67a690d176 | |||
| 81d72254b5 | |||
| b2e58aed7b | |||
| 5ca36b0731 | |||
| b105ec5188 | |||
| a85f7c200b | |||
| f09f15e0be | |||
| e35be12fb7 | |||
| 2f1a67685f | |||
| d3bc17fe56 | |||
| adfd93a303 | |||
| 82f9838f28 | |||
| a18057fd06 | |||
| dbc285e49e | |||
| 31b409d920 | |||
| 501c58729f | |||
| 3cc283a25e | |||
| 188b5021fb | |||
| be7a698223 | |||
| 60a1c97289 | |||
| 92afaa484f | |||
| 9fdb460330 | |||
| ccfc156b43 | |||
| 10f10ee269 | |||
| 47bf3467a2 | |||
| 04d7b13fc4 | |||
| a3e7f7fd14 | |||
| 745b504426 | |||
| 89913c7eeb | |||
| eb658e33c3 | |||
| 03e68d81b4 | |||
| ae80f632bf | |||
| e2079313e2 | |||
| b4bade5ca9 | |||
| 10883ef268 | |||
| 19e1e834a7 | |||
| f30b0eee9b | |||
| 0ad939f062 | |||
| e8f534c4f4 | |||
| 7e22a9c2c7 | |||
| c542a77f11 | |||
| db52a8bc31 | |||
| 4800afbc3e | |||
| 990b740ec1 | |||
| b1d436a281 | |||
| 8bf31f2277 | |||
| 97fc41ebcb | |||
| bac3ffbe79 | |||
| dc7dd96189 | |||
| 67c567062e | |||
| b7ee271c8b | |||
| 81cdd8db81 | |||
| 90d7b45f5f | |||
| 632d4faeec | |||
| aac3b19bff | |||
| a65a8fc40a | |||
| c0bedfd833 | |||
| b72551c475 | |||
| 437967f78e | |||
| e05747e353 | |||
| 4865c40790 | |||
| d63fd0365a | |||
| f054958593 | |||
| 7ee0ee6206 | |||
| cf715c550a | |||
| 440a27c5de | |||
| 2130e4ff8b | |||
| 676626064c | |||
| 655ac0b6a6 | |||
| 28233e5b3d | |||
| e001508f68 | |||
| 9b96653fc5 | |||
| 920ddcb70f | |||
| 82d1033f43 | |||
| 6856da7f09 | |||
| 150d134fa2 | |||
| d30fa9918f | |||
| 343ad024c0 | |||
| 4f8778cfc7 | |||
| b770c56b6d | |||
| 156953f115 | |||
| 07a6698d01 | |||
| 1ec619db69 | |||
| 9f5f8d4a0a | |||
| 810f134cdc | |||
| 7b1a0a0e65 | |||
| 447530591d | |||
| 34223e32ef | |||
| ac3cda51f0 | |||
| f25ac24adf | |||
| c3ba14a052 | |||
| bd844a184c | |||
| c968b1236f | |||
| ff2d542295 | |||
| bf68987951 | |||
| e2049d770c | |||
| 021bdd0e4b | |||
| 9bb59ad004 | |||
| fd1035ecf0 | |||
| 0602fdc0cb | |||
| 1294e309dc | |||
| 596bc2c2bf | |||
| 09568062fd | |||
| b205b758e8 | |||
| 55077e45bb | |||
| 9c4f0d31f2 | |||
| c220ad62dd | |||
| ffc8c116fd | |||
| 8679a15604 | |||
| 9995038273 | |||
| 70ee7b1beb | |||
| 5cc2ab26eb | |||
| cf0446155b | |||
| 87c42699d9 | |||
| 97bcb22dba | |||
| ecd82700a7 | |||
| daa598b1b4 | |||
| 13eb20d8d1 | |||
| d0a9c57c0b | |||
| 21b11cdb3d | |||
| d4b2c50163 | |||
| bd50ac1876 | |||
| da4204c491 | |||
| 780b99229c | |||
| bebde352fe | |||
| 1adf99597e | |||
| 70c1b02809 | |||
| 335c9c920d | |||
| b1ad4fb830 | |||
| 2b5073a222 | |||
| 731b150241 | |||
| 228ee621e6 | |||
| 16f65ba275 | |||
| 165918258d | |||
| 3392a198d7 | |||
| 7cba44007c | |||
| 0004f31e2e | |||
| 83865c7979 | |||
| b43222dc67 | |||
| e857efcf28 | |||
| e7ab69fa26 | |||
| f4743bbb8d | |||
| d1b63c5e18 | |||
| cf5065ed71 | |||
| bf380e2d46 | |||
| 4b40f8273d | |||
| c0f2ff773f | |||
| 2ef18bce0d | |||
| 536780ce38 |
@@ -1,7 +0,0 @@
|
||||
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
|
||||
|
||||
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
|
||||
|
||||
See CONTRIBUTING.md guidelines for how to contribute patches for Moodle. Thank you.
|
||||
|
||||
--
|
||||
@@ -1,6 +0,0 @@
|
||||
> [!IMPORTANT]
|
||||
> PLEASE DO NOT PUBLISH SECURITY FINDINGS PUBLICLY.
|
||||
|
||||
If you discover a potential security issue, please report it via our [Security Submission Form](https://moodle.org/security/report).
|
||||
|
||||
For more information about our security processes and responsible disclosure policy, see the [Security Procedures documentation](https://moodledev.io/general/development/process/security).
|
||||
@@ -1 +0,0 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1231.24 314.44" preserveAspectRatio="xMinYMid meet"><defs><style>.cls-1{fill:#f48020;}.cls-2,.cls-3{fill:#383738;stroke:#4a4a4c;}.cls-2{stroke-width:2.37px;}.cls-3{stroke-width:2.38px;}.cls-4{fill:#585858;}</style></defs><title>Moodle_Logo_UseonBlack_RGB</title><path class="cls-1" d="M1086.3,235.34a53.42,53.42,0,0,0,16.71,29q13.26,12.27,29.48,12.27,11.29,0,24.56-5.89,16.23-6.88,16.22-16.22l58-.49q-12.29,29-41.76,45.2-27.52,15.23-60.43,15.24-42.25,0-70-26.29t-27.75-68.54q0-43.73,27.75-69.51t72-25.8q48.15,0,75.17,31.94,25.07,29.47,25.06,79.1Zm89.91-33.91q-3.43-17.69-14.73-29-12.8-12.28-29.49-12.29-17.21,0-28.74,11.79t-15.47,29.48Z"/><path class="cls-1" d="M965.45,308.54V0h55V308.54Z"/><path class="cls-1" d="M892.69,308.54V290.36q-7.38,9.83-25.06,15.72a92.31,92.31,0,0,1-30,5.41q-39.31,0-63.13-27T750.7,217.65q0-39.3,23.34-65.84t62.15-26.53q43.71,0,56.5,23.58V0h53.55V308.54Zm0-102.68q0-14.75-14-28.26t-28.74-13.51q-21.12,0-33.41,17.2-10.8,15.24-10.8,37.33,0,21.63,10.8,36.85,12.29,17.71,33.41,17.69,12.78,0,27.76-12t15-24.81Z"/><path class="cls-1" d="M647,313.45q-41.77,0-69-26.53t-27.27-68.3q0-41.73,27.27-68.28t69-26.53q41.75,0,69.27,26.53t27.52,68.28q0,41.79-27.52,68.3T647,313.45ZM647,168q-19.89,0-30.58,15.07t-10.68,35.79q0,20.73,9.94,35.05,11.43,16.31,31.32,16.28t31.32-16.28q10.44-14.31,10.44-35.05t-9.94-35Q667.42,168,647,168Z"/><path class="cls-1" d="M448.07,313.45q-41.76,0-69-26.53t-27.27-68.3q0-41.73,27.27-68.28t69-26.53q41.74,0,69.28,26.53t27.5,68.28q0,41.79-27.5,68.3T448.07,313.45Zm0-145.43q-19.89,0-30.59,15.07t-10.69,35.79q0,20.73,9.94,35.05,11.43,16.31,31.34,16.28t31.32-16.28q10.42-14.31,10.44-35.05t-9.94-35Q468.45,168,448.07,168Z"/><path class="cls-1" d="M288.89,309.11V201q0-33.9-28-33.9t-28,33.9V309.11h-55V201q0-33.9-27.52-33.9-28,0-28,33.9V309.11h-55V194.65q0-35.37,24.56-53.54,21.61-16.22,58.46-16.22,37.35,0,55,19.16,15.23-19.16,55.51-19.16,36.86,0,58.45,16.22,24.57,18.16,24.57,53.54V309.11Z"/><path class="cls-2" d="M.76,145.76"/><path class="cls-3" d="M1.73,145.32"/><path class="cls-4" d="M173.86,116.85l55.08-40.1-.7-2.44C135,83.92,80.42,96.44,0,144.13l.73,2.38,21-.67c15.17.52,30.85,1.26,46,1.32-1,24.09.83,32.65.83,32.65,51.92,17.58,101.22,1.53,127.14-43.9A248.72,248.72,0,0,0,173.86,116.85Z"/><path class="cls-4" d="M113.78,110c-.3-1.08-2.23-1.48-4.28-.9a4.73,4.73,0,0,0-3.14,2.19c-18.53,5-49.16,13.72-70.73,21l-1.33.45c-16.68,5.61-24.73,8.49-25.22,12.55-2.29,18.44-.87,42.18-.86,42.48l.19,6.4c-9.74,27.56.06,49.6,8.38,69.77.06-24.92,1.07-45.22-6-71-.2-3.82-1.49-30.36.61-47.34.34-2.75,11.65-6.56,23.63-10.59l1.33-.44c22-7.42,53.57-16.39,71.9-21.29a6.75,6.75,0,0,0,2.29-.25C112.64,112.43,114.08,111.09,113.78,110Z"/></svg>
|
||||
|
Before Width: | Height: | Size: 2.7 KiB |
@@ -1,31 +0,0 @@
|
||||
name: 'Close Pull Requests'
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: opened
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
close:
|
||||
# Avoid forks to run this job
|
||||
if: github.repository_owner == 'moodle'
|
||||
name: Close Pull Requests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: dessant/repo-lockdown@v4
|
||||
with:
|
||||
process-only: prs
|
||||
close-pr: true
|
||||
skip-closed-pr-comment: true
|
||||
pr-comment: >
|
||||
**Please, don't open pull requests via GitHub.**
|
||||
|
||||
|
||||
This repository (moodle.git) at GitHub is just a mirror of the official Moodle repository.
|
||||
|
||||
|
||||
For how to contribute patches for Moodle see
|
||||
[CONTRIBUTING.md](https://github.com/moodle/moodle/blob/main/CONTRIBUTING.md).
|
||||
|
||||
|
||||
Closing this pull request.
|
||||
@@ -1,143 +0,0 @@
|
||||
name: One by One Testing
|
||||
# Run all the individual unit tests one by one, with
|
||||
# fully independent PHPUnit executions. Useful to
|
||||
# detect issues with some tests that are using stuff
|
||||
# that has been made available by others, but is not
|
||||
# available when running individually.
|
||||
#
|
||||
# Note that we aren't using PHPUnit's own isolation
|
||||
# here but completely separated runs, one for each
|
||||
# test.
|
||||
#
|
||||
# The workflow will fail reporting all the tests
|
||||
# that have failed (and will pass if no failure is
|
||||
# detected, of course).
|
||||
#
|
||||
# It's only executed via workflow dispatch (automated
|
||||
# or manual), not by push/tag. And acceptd configuration
|
||||
# of phpunit, specially useful to run it with PHPUnit's
|
||||
# own isolation or any other option.
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
phpunit_extra_options:
|
||||
description: Additional options to apply to PHPUnit
|
||||
required: false
|
||||
default: ''
|
||||
|
||||
env:
|
||||
chunks: 7
|
||||
|
||||
jobs:
|
||||
collect:
|
||||
name: Collect individual unit tests
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{steps.individual-tests.outputs.matrix }}
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Looking for all individual tests
|
||||
id: individual-tests
|
||||
run: |
|
||||
count=0 # Number of individual tests found.
|
||||
while read -r testfile; do # For each test file.
|
||||
while read -r testname; do # For each unit test in a file.
|
||||
count=$((count + 1))
|
||||
# Sent it to the correct chunk file.
|
||||
chunk=$(((($count % $chunks)) + 1))
|
||||
echo "$testname $testfile" >> ./chunk_$chunk.txt
|
||||
done < <(grep "function test_" "${testfile}" | sed -r "s/^.*function (test_[a-zA-Z0-9_]+).*/\1/")
|
||||
done < <(find . -name "*_test.php")
|
||||
# Generate the matrix to run tests.
|
||||
echo "matrix=$(ls -1 chunk_*.txt | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
|
||||
echo "$count individual tests collected in $chunks files"
|
||||
|
||||
- name: Upload individual tests files
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: individual_tests
|
||||
path: chunk_*.txt
|
||||
retention-days: 1
|
||||
|
||||
test:
|
||||
name: Run tests
|
||||
needs: collect
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
exttests:
|
||||
image: moodlehq/moodle-exttests
|
||||
ports:
|
||||
- 8080:80
|
||||
redis:
|
||||
image: redis
|
||||
ports:
|
||||
- 6379:6379
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
file: ${{ fromJson(needs.collect.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- name: Setting up DB pgsql
|
||||
uses: m4nu56/postgresql-action@v1
|
||||
with:
|
||||
postgresql version: 13
|
||||
postgresql db: test
|
||||
postgresql user: test
|
||||
postgresql password: test
|
||||
|
||||
- name: Setting up PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: 8.3
|
||||
ini-values: max_input_vars=5000
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download individual test files
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: individual_tests # Make all the chunk files available for the next steps.
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
dbtype: pgsql
|
||||
run: |
|
||||
echo "pathtophp=$(which php)" >> $GITHUB_ENV
|
||||
cp .github/workflows/config-template.php config.php
|
||||
mkdir ../moodledata
|
||||
sudo locale-gen en_AU.UTF-8
|
||||
php admin/tool/phpunit/cli/init.php --no-composer-self-update
|
||||
|
||||
- name: Run PHPUnit test (one by one)
|
||||
env:
|
||||
dbtype: pgsql
|
||||
run: |
|
||||
status=0
|
||||
count=0
|
||||
while read -r line; do # For each line in the chunk file
|
||||
count=$((count + 1))
|
||||
filter="${line% *}"
|
||||
file="${line#* }"
|
||||
# Run the individual unit test and report problems if needed to.
|
||||
if ! php vendor/bin/phpunit \
|
||||
--fail-on-empty-test-suite \
|
||||
--fail-on-warning \
|
||||
--fail-on-risky \
|
||||
--filter "$filter" ${{ inputs.phpunit_extra_options }} \
|
||||
"$file" >/dev/null 2>&1; then
|
||||
if [ $status -eq 0 ]; then
|
||||
echo "Problems found, list of PHPUnit commands failing:"
|
||||
fi
|
||||
echo "vendor/bin/phpunit --filter '${filter}' ${{ inputs.phpunit_extra_options }} $file"
|
||||
status=$((status + 1))
|
||||
fi
|
||||
done < ${{ matrix.file }}
|
||||
echo "Finished: $count individual tests executed, $status tests failed"
|
||||
exit $status
|
||||
@@ -3,7 +3,7 @@ name: Core
|
||||
on:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
- master
|
||||
- MOODLE_[0-9]+_STABLE
|
||||
tags-ignore:
|
||||
- v[0-9]+.[0-9]+.[0-9]+*
|
||||
@@ -15,7 +15,7 @@ on:
|
||||
default: ''
|
||||
|
||||
env:
|
||||
php: 8.3
|
||||
php: 8.2
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
@@ -23,10 +23,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
@@ -62,12 +62,12 @@ jobs:
|
||||
include:
|
||||
# MySQL builds always run with the lowest PHP supported version.
|
||||
- os: ubuntu-22.04
|
||||
php: 8.1
|
||||
php: 8.0
|
||||
extensions:
|
||||
db: mysqli
|
||||
# PostgreSQL builds always run with the highest PHP supported version.
|
||||
- os: ubuntu-22.04
|
||||
php: 8.3
|
||||
php: 8.2
|
||||
db: pgsql
|
||||
|
||||
steps:
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
coverage: none
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setting up PHPUnit
|
||||
env:
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
name: Web Installer Testing
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
InstallationTest:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-latest]
|
||||
php: [8.1, 8.3]
|
||||
steps:
|
||||
- name: Construct repository URL
|
||||
run: echo "REPOSITORY_URL=${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
|
||||
- uses: moodlehq/moodle-webinstaller-test@main
|
||||
with:
|
||||
repository: ${{ env.REPOSITORY_URL }}
|
||||
branch: ${{ github.ref_name }}
|
||||
php: ${{ matrix.php }}
|
||||
@@ -8,7 +8,7 @@ on:
|
||||
required: false
|
||||
default: ''
|
||||
env:
|
||||
php: 8.3
|
||||
php: 8.2
|
||||
|
||||
jobs:
|
||||
Grunt:
|
||||
@@ -21,10 +21,10 @@ jobs:
|
||||
git config --global core.eol lf
|
||||
|
||||
- name: Checking out code
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Configuring node & npm
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
@@ -51,7 +51,7 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
php: 8.3
|
||||
php: 8.2
|
||||
# Ideally we should use mysql/mariadb, but they are 4x slower without tweaks and configuration
|
||||
# so let's run only postgres (1.5h vs 6h) only, If some day we want to improve the mysql runs,
|
||||
# this is the place to enable them.
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium, zip
|
||||
- os: windows-latest
|
||||
php: 8.1
|
||||
php: 8.0
|
||||
db: pgsql
|
||||
extensions: exif, fileinfo, gd, intl, pgsql, mysql, redis, soap, sodium
|
||||
|
||||
@@ -117,7 +117,7 @@ jobs:
|
||||
git config --global core.eol lf
|
||||
|
||||
- name: Checking out code from ${{ env.GITHUB_REF_SLUG }}
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
# Needs to be done after php is available, git configured and Moodle checkout has happened.
|
||||
- name: Setting up moodle-exttests service
|
||||
|
||||
@@ -26,9 +26,6 @@
|
||||
/.patches/
|
||||
/.idea/
|
||||
.phpstorm.*
|
||||
!/.phpstorm.meta.php/
|
||||
/.phpstorm.meta.php/*
|
||||
!/.phpstorm.meta.php/di.php
|
||||
/nbproject/
|
||||
CVS
|
||||
.DS_Store
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function to generate the destination for the minification task
|
||||
* Function to generate the destination for the uglify task
|
||||
* (e.g. build/file.min.js). This function will be passed to
|
||||
* the rename property of files array when building dynamically:
|
||||
* http://gruntjs.com/configuring-tasks#building-the-files-object-dynamically
|
||||
@@ -60,6 +60,7 @@ module.exports = grunt => {
|
||||
grunt.registerTask('js', ['amd', 'yui']);
|
||||
|
||||
// Register NPM tasks.
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
grunt.loadNpmTasks('grunt-rollup');
|
||||
|
||||
@@ -103,7 +104,6 @@ module.exports = grunt => {
|
||||
// The queue runner will run the next `size` items in the queue.
|
||||
const runQueue = (size = 1) => {
|
||||
queue.splice(0, size).forEach(resolve => {
|
||||
grunt.log.debug(`Item resolved. Kicking off next one.`);
|
||||
resolve();
|
||||
});
|
||||
};
|
||||
@@ -113,17 +113,15 @@ module.exports = grunt => {
|
||||
|
||||
// The options hook is run in parallel.
|
||||
// We can return an unresolved Promise which is queued for later resolution.
|
||||
options: async(options) => {
|
||||
options: async() => {
|
||||
return new Promise(resolve => {
|
||||
queue.push(resolve);
|
||||
startQueue();
|
||||
return options;
|
||||
});
|
||||
},
|
||||
|
||||
// When an item in the queue completes, start the next item in the queue.
|
||||
generateBundle: (options, bundle) => {
|
||||
grunt.log.debug(`Finished output phase for ${Object.keys(bundle).join(', ')}`);
|
||||
buildEnd: () => {
|
||||
runQueue();
|
||||
},
|
||||
};
|
||||
@@ -157,6 +155,16 @@ module.exports = grunt => {
|
||||
],
|
||||
presets: [
|
||||
['@babel/preset-env', {
|
||||
targets: {
|
||||
browsers: [
|
||||
">0.3%",
|
||||
"last 2 versions",
|
||||
"not ie >= 0",
|
||||
"not op_mini all",
|
||||
"not Opera > 0",
|
||||
"not dead"
|
||||
]
|
||||
},
|
||||
modules: false,
|
||||
useBuiltIns: false
|
||||
}]
|
||||
|
||||
+12
-28
@@ -20,33 +20,17 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
module.exports = (grunt) => {
|
||||
const path = require('path');
|
||||
|
||||
grunt.registerTask('jsdoc', 'Generate JavaScript documentation using jsdoc', function() {
|
||||
const done = this.async();
|
||||
const configuration = path.resolve('.grunt/jsdoc/jsdoc.conf.js');
|
||||
|
||||
grunt.util.spawn({
|
||||
cmd: 'jsdoc',
|
||||
args: [
|
||||
'--configure',
|
||||
configuration,
|
||||
]
|
||||
}, function(error, result, code) {
|
||||
if (result.stdout) {
|
||||
grunt.log.write(result.stdout);
|
||||
}
|
||||
|
||||
if (result.stderr) {
|
||||
grunt.log.error(result.stderr);
|
||||
}
|
||||
if (error) {
|
||||
grunt.fail.fatal(`JSDoc failed with error code ${code}`);
|
||||
} else {
|
||||
grunt.log.write('JSDoc completed successfully'.green);
|
||||
}
|
||||
done();
|
||||
});
|
||||
module.exports = grunt => {
|
||||
// Project configuration.
|
||||
grunt.config.merge({
|
||||
jsdoc: {
|
||||
dist: {
|
||||
options: {
|
||||
configure: ".grunt/jsdoc/jsdoc.conf.js",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks('grunt-jsdoc');
|
||||
};
|
||||
|
||||
@@ -29,7 +29,6 @@ module.exports = grunt => {
|
||||
// Use a fully-qualified path.
|
||||
src: files,
|
||||
options: {
|
||||
quietDeprecationWarnings: true,
|
||||
configOverrides: {
|
||||
rules: {
|
||||
// These rules have to be disabled in .stylelintrc for scss compat.
|
||||
@@ -46,10 +45,7 @@ module.exports = grunt => {
|
||||
return {
|
||||
stylelint: {
|
||||
scss: {
|
||||
options: {
|
||||
quietDeprecationWarnings: true,
|
||||
customSyntax: 'postcss-scss',
|
||||
},
|
||||
options: {syntax: 'scss'},
|
||||
src: files,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Helper file for PhpStorm, and other IDEs, to provide better code completion.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2024 Andrew Lyons <andrew@nicols.co.uk>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace PHPSTORM_META;
|
||||
|
||||
// Assume that anything returned by \core\di::get('...') is an instance of the first argument.
|
||||
override(\core\di::get(0), map([
|
||||
'' => '@',
|
||||
]));
|
||||
|
||||
// Assume that anything returned by \Psr\Container\ContainerInterface::get('...') is an instance of the first argument.
|
||||
override(\Psr\Container\ContainerInterface::get(0), map([
|
||||
'' => '@',
|
||||
]));
|
||||
|
||||
// Assume that anything returned by \DI\Container::get('...') is an instance of the first argument.
|
||||
override(\DI\Container::get(0), map([
|
||||
'' => '@',
|
||||
]));
|
||||
+4
-16
@@ -1,14 +1,9 @@
|
||||
{
|
||||
"customSyntax": "postcss-scss",
|
||||
"plugins": [
|
||||
"stylelint-csstree-validator"
|
||||
],
|
||||
"rules": {
|
||||
"csstree/validator": {
|
||||
"syntaxExtensions": [
|
||||
"sass"
|
||||
]
|
||||
},
|
||||
"csstree/validator": true,
|
||||
"at-rule-empty-line-before": [ "always",
|
||||
{"except": [ "blockless-after-blockless"], ignore: ["after-comment", "inside-block"]}
|
||||
],
|
||||
@@ -50,7 +45,7 @@
|
||||
"function-name-case": "lower",
|
||||
"function-parentheses-newline-inside": "always-multi-line",
|
||||
"function-parentheses-space-inside": "never-single-line",
|
||||
"function-url-scheme-disallowed-list": ["data"],
|
||||
"function-url-scheme-blacklist": ["data"],
|
||||
"function-whitespace-after": "always",
|
||||
"indentation": 4,
|
||||
"keyframe-declaration-no-important": true,
|
||||
@@ -89,19 +84,12 @@
|
||||
"selector-type-no-unknown": true,
|
||||
"string-no-newline": true,
|
||||
"time-min-milliseconds": 100,
|
||||
"unit-disallowed-list": ["pt"],
|
||||
"unit-blacklist": ["pt"],
|
||||
"unit-case": "lower",
|
||||
"unit-no-unknown": true,
|
||||
"value-keyword-case": ["lower", {"ignoreKeywords": ["/(@|$)/"]}],
|
||||
"value-list-comma-newline-after": "always-multi-line",
|
||||
"value-list-comma-space-after": "always-single-line",
|
||||
"value-list-comma-space-before": "never",
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["**/yui/**/*.css"],
|
||||
"rules": {
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
# Contributing to Moodle
|
||||
|
||||
[Moodle][1] is made by people like you. We are members of a big worldwide community of developers, designers, teachers, testers, translators and many more. We work in universities, schools, companies and other places. You are very welcome to join us and contribute to the project.
|
||||
|
||||
There are many ways that you can contribute to Moodle, not just through development. See our [community contribution guide][2] for some of the many ways that you can help.
|
||||
|
||||
## Github
|
||||
|
||||
> [!NOTE]
|
||||
> Please do not open pull requests via Github.
|
||||
|
||||
All issues should be reported via, and patched provided to the [Moodle Tracker][3].
|
||||
|
||||
The Moodle [Github][4] repository is a clone of the official Moodle repository, whcih can be found at https://git.moodle.org.
|
||||
|
||||
## Moodle core bug fixes and new features
|
||||
|
||||
Over the years, Moodle has developed a mature process for reporting, reviewing, and accepting patches. This is fully documented in our [documentation on development processes][6], but in summary:
|
||||
|
||||
- Every bug fix or new feature must have a tracker issue.
|
||||
- You publish the branch implementing the fix or new feature in your public clone of the moodle.git repository (typically on Github).
|
||||
- Your patch is peer-reviewed, discussed, integrated, tested and then released as a part of one of our weekly releases.
|
||||
- New features are developed on the `main` branch. Bug fixes are also backported to currently supported maintenance (stable) branches.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Please do not publish security issues, or patches releating to them publicly.
|
||||
> See our [Responsible Disclosure Policy][5] for more information.
|
||||
|
||||
|
||||
## Moodle plugins
|
||||
|
||||
Moodle has a framework for additional plugins to extend its functionality. We
|
||||
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
|
||||
register and maintain your plugin. Plugins hosted in the plugins directory can
|
||||
be easily installed and updated via the Moodle administration interface.
|
||||
|
||||
* You are expected to have a public source code repository with your plugin
|
||||
code.
|
||||
* After registering your plugin in the plugins directory it is reviewed before
|
||||
being published.
|
||||
* You are expected to continuously release updated versions of the plugin via
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://moodledev.io/general/community/plugincontribution>.
|
||||
|
||||
[1]: https://moodle.org
|
||||
[2]: https://moodledev.io/general/community/contribute
|
||||
[3]: https://tracker.moodle.org
|
||||
[4]: https://github.com/moodle/moodle
|
||||
[5]: https://moodledev.io/general/development/process/security
|
||||
[6]: https://moodledev.io/general/development/process
|
||||
@@ -0,0 +1,56 @@
|
||||
CONTRIBUTING TO MOODLE
|
||||
======================
|
||||
|
||||
Moodle is made by people like you. We are members of a big worldwide community
|
||||
of developers, designers, teachers, testers, translators and other users. We
|
||||
work in universities, schools, companies and other places. You are very welcome
|
||||
to join us and contribute to the project.
|
||||
|
||||
See <https://moodledev.io/general/community/contribute> for the many ways you
|
||||
can help, not only with coding.
|
||||
|
||||
Moodle is open to community contributions to core, though all code must go
|
||||
through peer-review, automated behaviour testing, continuous integration and
|
||||
human post-integration checks.
|
||||
|
||||
Pull requests
|
||||
-------------
|
||||
|
||||
Please do not open pull requests via Github. The repository there is just a
|
||||
mirror of the official repository at <https://git.moodle.org>. Issues are
|
||||
reported and patches provided via <https://tracker.moodle.org>. See below for
|
||||
more information.
|
||||
|
||||
Moodle core bug fixes and new features
|
||||
--------------------------------------
|
||||
|
||||
During the years of intensive development, a mature process of including
|
||||
submitted patches has evolved.
|
||||
|
||||
* Every bug fix or new feature must have a tracker issue.
|
||||
* You publish the branch implementing the fix or new feature in your public
|
||||
clone of the moodle.git repository (typically on Github).
|
||||
* Your patch is peer-reviewed, discussed, integrated, tested and then released
|
||||
as a part of moodle.git.
|
||||
* New features are developed on the master branch. Bug fixes are also
|
||||
backported to currently supported maintenance (stable) branches.
|
||||
|
||||
For further details, see <https://moodledev.io/general/development/process>.
|
||||
|
||||
Moodle plugins
|
||||
--------------
|
||||
|
||||
Moodle has a framework for additional plugins to extend its functionality. We
|
||||
have a Moodle plugins directory <https://moodle.org/plugins/> where you can
|
||||
register and maintain your plugin. Plugins hosted in the plugins directory can
|
||||
be easily installed and updated via the Moodle administration interface.
|
||||
|
||||
* You are expected to have a public source code repository with your plugin
|
||||
code.
|
||||
* After registering your plugin in the plugins directory it is reviewed before
|
||||
being published.
|
||||
* You are expected to continuously release updated versions of the plugin via
|
||||
the plugins directory. We do not pull from your code repository; you must do
|
||||
it explicitly.
|
||||
|
||||
For further details, see <https://moodledev.io/general/community/plugincontribution>.
|
||||
@@ -0,0 +1,7 @@
|
||||
*** PLEASE DO NOT OPEN PULL REQUESTS VIA GITHUB ***
|
||||
|
||||
The moodle.git repository at Github is just a mirror of the official repository. We do not accept pull requests at Github.
|
||||
|
||||
See CONTRIBUTING.txt guidelines for how to contribute patches for Moodle. Thank you.
|
||||
|
||||
--
|
||||
@@ -1,48 +0,0 @@
|
||||
# Moodle
|
||||
|
||||
<p align="center"><a href="https://moodle.org" target="_blank" title="Moodle Website">
|
||||
<img src="https://raw.githubusercontent.com/moodle/moodle/main/.github/moodlelogo.svg" alt="The Moodle Logo">
|
||||
</a></p>
|
||||
|
||||
[Moodle][1] is the World's Open Source Learning Platform, widely used around the world by countless universities, schools, companies, and all manner of organisations and individuals.
|
||||
|
||||
Moodle is designed to allow educators, administrators and learners to create personalised learning environments with a single robust, secure and integrated system.
|
||||
|
||||
## Documentation
|
||||
|
||||
- Read our [User documentation][3]
|
||||
- Discover our [developer documentation][5]
|
||||
- Take a look at our [demo site][4]
|
||||
|
||||
## Community
|
||||
|
||||
[moodle.org][1] is the central hub for the Moodle Community, with spaces for educators, administrators and developers to meet and work together.
|
||||
|
||||
You may also be interested in:
|
||||
|
||||
- attending a [Moodle Moot][6]
|
||||
- our regular series of [developer meetings][7]
|
||||
- the [Moodle User Association][8]
|
||||
|
||||
## Installation and hosting
|
||||
|
||||
Moodle is Free, and Open Source software. You can easily [download Moodle][9] and run it on your own web server, however you may prefer to work with one of our experienced [Moodle Partners][10].
|
||||
|
||||
Moodle also offers hosting through both [MoodleCloud][11], and our [partner network][10].
|
||||
|
||||
## License
|
||||
|
||||
Moodle is provided freely as open source software, under version 3 of the GNU General Public License. For more information on our license see
|
||||
|
||||
[1]: https://moodle.org
|
||||
[2]: https://moodle.com
|
||||
[3]: https://docs.moodle.org/
|
||||
[4]: https://sandbox.moodledemo.net/
|
||||
[5]: https://moodledev.io
|
||||
[6]: https://moodle.com/events/mootglobal/
|
||||
[7]: https://moodledev.io/general/community/meetings
|
||||
[8]: https://moodleassociation.org/
|
||||
[9]: https://download.moodle.org
|
||||
[10]: https://moodle.com/partners
|
||||
[11]: https://moodle.com/cloud
|
||||
[12]: https://moodledev.io/general/license
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
.-..-.
|
||||
_____ | || |
|
||||
/____/-.---_ .---. .---. .-.| || | .---.
|
||||
| | _ _ |/ _ \/ _ \/ _ || |/ __ \
|
||||
* | | | | | || |_| || |_| || |_| || || |___/
|
||||
|_| |_| |_|\_____/\_____/\_____||_|\_____)
|
||||
|
||||
Moodle - the world's open source learning platform
|
||||
|
||||
Moodle <https://moodle.org> is a learning platform designed to provide
|
||||
educators, administrators and learners with a single robust, secure and
|
||||
integrated system to create personalised learning environments.
|
||||
|
||||
You can download Moodle <https://download.moodle.org> and run it on your own
|
||||
web server, ask one of our Moodle Partners <https://moodle.com/partners/> to
|
||||
assist you, or have a MoodleCloud site <https://moodle.com/cloud/> set up for
|
||||
you.
|
||||
|
||||
Moodle is widely used around the world by universities, schools, companies and
|
||||
all manner of organisations and individuals.
|
||||
|
||||
Moodle is provided freely as open source software, under the GNU General Public
|
||||
License <https://moodledev.io/general/license>.
|
||||
|
||||
Moodle is written in PHP and JavaScript and uses an SQL database for storing
|
||||
the data.
|
||||
|
||||
See <https://docs.moodle.org> for details of Moodle's many features.
|
||||
-10
@@ -1,10 +0,0 @@
|
||||
define("core_admin/bulk_user_actions",["exports","core_reportbuilder/local/selectors","core_table/local/dynamic/events","core_form/changechecker","core/custom_interaction_events","jquery"],(function(_exports,reportSelectors,tableEvents,FormChangeChecker,CustomEvents,_jquery){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}function _interopRequireWildcard(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}return newObj.default=obj,cache&&cache.set(obj,newObj),newObj}
|
||||
/**
|
||||
* Add bulk actions to the users list report
|
||||
*
|
||||
* @module core_admin/bulk_user_actions
|
||||
* @copyright 2024 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,reportSelectors=_interopRequireWildcard(reportSelectors),tableEvents=_interopRequireWildcard(tableEvents),FormChangeChecker=_interopRequireWildcard(FormChangeChecker),CustomEvents=_interopRequireWildcard(CustomEvents),_jquery=(obj=_jquery)&&obj.__esModule?obj:{default:obj};const Selectors_bulkActionsForm="form#user-bulk-action-form",Selectors_userReportWrapper='[data-region="report-user-list-wrapper"]',Selectors_checkbox='input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',Selectors_masterCheckbox='input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',Selectors_checkedRows='[data-togglegroup="report-select-all"][data-toggle="slave"]:checked';_exports.init=()=>{var _userBulkForm$closest;const userBulkForm=document.querySelector(Selectors_bulkActionsForm),userReport=null==userBulkForm||null===(_userBulkForm$closest=userBulkForm.closest(Selectors_userReportWrapper))||void 0===_userBulkForm$closest?void 0:_userBulkForm$closest.querySelector(reportSelectors.regions.report);if(!userBulkForm||!userReport)return;const actionSelect=userBulkForm.querySelector("select");CustomEvents.define(actionSelect,[CustomEvents.events.accessibleChange]),(0,_jquery.default)(actionSelect).on(CustomEvents.events.accessibleChange,(event=>{if(event.target.value&&"0"!=="".concat(event.target.value)){const e=new Event("submit",{cancelable:!0});userBulkForm.dispatchEvent(e),e.defaultPrevented||(FormChangeChecker.markFormSubmitted(userBulkForm),userBulkForm.submit())}}));const updateUserIds=()=>{const selectedUsers=[...userReport.querySelectorAll(Selectors_checkedRows)],selectedUserIds=selectedUsers.map((check=>parseInt(check.value)));userBulkForm.querySelector('[name="userids"]').value=selectedUserIds.join(","),actionSelect.disabled=0===selectedUsers.length,actionSelect.disabled&&(actionSelect.value="0");const selectedUsersNames=selectedUsers.map((check=>document.querySelector('label[for="'.concat(check.id,'"]')).textContent));userBulkForm.data={userids:selectedUserIds,usernames:selectedUsersNames}};updateUserIds(),document.addEventListener("change",(event=>{(event.target.matches(Selectors_checkbox)||event.target.matches(Selectors_masterCheckbox))&&userReport.contains(event.target)&&updateUserIds()})),document.addEventListener(tableEvents.tableContentRefreshed,(event=>{userReport.contains(event.target)&&updateUserIds()}))}}));
|
||||
|
||||
//# sourceMappingURL=bulk_user_actions.min.js.map
|
||||
File diff suppressed because one or more lines are too long
@@ -1,10 +0,0 @@
|
||||
define("core_admin/themeselector/preview_modal",["exports","core/modal_events","core/modal_cancel","core/modal_save_cancel","core/notification","core/templates","core/str"],(function(_exports,_modal_events,_modal_cancel,_modal_save_cancel,_notification,_templates,_str){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}
|
||||
/**
|
||||
* Modal for theme previews.
|
||||
*
|
||||
* @module core_admin/themeselector/preview_modal
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_modal_events=_interopRequireDefault(_modal_events),_modal_cancel=_interopRequireDefault(_modal_cancel),_modal_save_cancel=_interopRequireDefault(_modal_save_cancel),_notification=_interopRequireDefault(_notification),_templates=_interopRequireDefault(_templates);const SELECTORS_THEMES_CONTAINER="themelist",SELECTORS_PREVIEW='[data-action="preview"]';_exports.init=()=>{registerListenerEvents()};const registerListenerEvents=()=>{document.addEventListener("click",(e=>{const preview=e.target.closest(SELECTORS_PREVIEW);preview&&buildModal(preview).catch(_notification.default.exception)}))},buildModal=async element=>{let description=await(0,_str.getString)("choosereadme","theme_"+element.getAttribute("data-choose"));const themesContainer=document.getElementById(SELECTORS_THEMES_CONTAINER),definedInConfig=parseInt(themesContainer.dataset.definedinconfig),data={name:element.getAttribute("data-name"),image:element.getAttribute("data-image"),description:description.replace(/<[^>]+>/g," "),current:element.getAttribute("data-current"),actionurl:element.getAttribute("data-actionurl"),choose:element.getAttribute("data-choose"),sesskey:element.getAttribute("data-sesskey"),definedinconfig:definedInConfig};let modalTemplate=_modal_save_cancel.default;(data.current||data.definedinconfig)&&(modalTemplate=_modal_cancel.default);const modal=await modalTemplate.create({title:data.name,body:_templates.default.render("core_admin/themeselector/theme_preview_modal",data),large:!0,buttons:{save:(0,_str.getString)("selecttheme","moodle"),cancel:(0,_str.getString)("closebuttontitle","moodle")},show:!0});modal.getRoot().on(_modal_events.default.save,(()=>{modal.getRoot().find("form").submit()}))}}));
|
||||
|
||||
//# sourceMappingURL=preview_modal.min.js.map
|
||||
@@ -1 +0,0 @@
|
||||
{"version":3,"file":"preview_modal.min.js","sources":["../../src/themeselector/preview_modal.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 * Modal for theme previews.\n *\n * @module core_admin/themeselector/preview_modal\n * @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport ModalEvents from 'core/modal_events';\nimport ModalCancel from 'core/modal_cancel';\nimport ModalSaveCancel from 'core/modal_save_cancel';\nimport Notification from 'core/notification';\nimport Templates from 'core/templates';\nimport {getString} from 'core/str';\n\nconst SELECTORS = {\n THEMES_CONTAINER: 'themelist',\n PREVIEW: '[data-action=\"preview\"]',\n};\n\n/**\n * Entrypoint of the js.\n *\n * @method init\n */\nexport const init = () => {\n registerListenerEvents();\n};\n\n/**\n * Register theme related event listeners.\n *\n * @method registerListenerEvents\n */\nconst registerListenerEvents = () => {\n document.addEventListener('click', (e) => {\n const preview = e.target.closest(SELECTORS.PREVIEW);\n if (preview) {\n buildModal(preview).catch(Notification.exception);\n }\n });\n};\n\n/**\n * Build the modal with the provided data.\n *\n * @method buildModal\n * @param {object} element\n */\nconst buildModal = async(element) => {\n\n // This string can be long. We will fetch it with JS as opposed to passing it as an attribute.\n let description = await getString('choosereadme', 'theme_' + element.getAttribute('data-choose'));\n\n const themesContainer = document.getElementById(SELECTORS.THEMES_CONTAINER);\n const definedInConfig = parseInt(themesContainer.dataset.definedinconfig);\n // Prepare data for modal.\n const data = {\n name: element.getAttribute('data-name'),\n image: element.getAttribute('data-image'),\n description: description.replace(/<[^>]+>/g, ' '), // Strip out HTML tags.\n current: element.getAttribute('data-current'),\n actionurl: element.getAttribute('data-actionurl'),\n choose: element.getAttribute('data-choose'),\n sesskey: element.getAttribute('data-sesskey'),\n definedinconfig: definedInConfig,\n };\n\n // Determine which modal template we should use.\n let modalTemplate = ModalSaveCancel;\n if (data.current || data.definedinconfig) {\n modalTemplate = ModalCancel;\n }\n\n const modal = await modalTemplate.create({\n title: data.name,\n body: Templates.render('core_admin/themeselector/theme_preview_modal', data),\n large: true,\n buttons: {\n 'save': getString('selecttheme', 'moodle'),\n 'cancel': getString('closebuttontitle', 'moodle'),\n },\n show: true,\n });\n\n modal.getRoot().on(ModalEvents.save, () => {\n modal.getRoot().find('form').submit();\n });\n};\n"],"names":["SELECTORS","registerListenerEvents","document","addEventListener","e","preview","target","closest","buildModal","catch","Notification","exception","async","description","element","getAttribute","themesContainer","getElementById","definedInConfig","parseInt","dataset","definedinconfig","data","name","image","replace","current","actionurl","choose","sesskey","modalTemplate","ModalSaveCancel","ModalCancel","modal","create","title","body","Templates","render","large","buttons","show","getRoot","on","ModalEvents","save","find","submit"],"mappings":";;;;;;;gWA8BMA,2BACgB,YADhBA,kBAEO,wCAQO,KAChBC,gCAQEA,uBAAyB,KAC3BC,SAASC,iBAAiB,SAAUC,UAC1BC,QAAUD,EAAEE,OAAOC,QAAQP,mBAC7BK,SACAG,WAAWH,SAASI,MAAMC,sBAAaC,eAW7CH,WAAaI,MAAAA,cAGXC,kBAAoB,kBAAU,eAAgB,SAAWC,QAAQC,aAAa,sBAE5EC,gBAAkBd,SAASe,eAAejB,4BAC1CkB,gBAAkBC,SAASH,gBAAgBI,QAAQC,iBAEnDC,KAAO,CACTC,KAAMT,QAAQC,aAAa,aAC3BS,MAAOV,QAAQC,aAAa,cAC5BF,YAAaA,YAAYY,QAAQ,WAAY,KAC7CC,QAASZ,QAAQC,aAAa,gBAC9BY,UAAWb,QAAQC,aAAa,kBAChCa,OAAQd,QAAQC,aAAa,eAC7Bc,QAASf,QAAQC,aAAa,gBAC9BM,gBAAiBH,qBAIjBY,cAAgBC,4BAChBT,KAAKI,SAAWJ,KAAKD,mBACrBS,cAAgBE,6BAGdC,YAAcH,cAAcI,OAAO,CACrCC,MAAOb,KAAKC,KACZa,KAAMC,mBAAUC,OAAO,+CAAgDhB,MACvEiB,OAAO,EACPC,QAAS,OACG,kBAAU,cAAe,kBACvB,kBAAU,mBAAoB,WAE5CC,MAAM,IAGVR,MAAMS,UAAUC,GAAGC,sBAAYC,MAAM,KACjCZ,MAAMS,UAAUI,KAAK,QAAQC"}
|
||||
@@ -1,97 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Add bulk actions to the users list report
|
||||
*
|
||||
* @module core_admin/bulk_user_actions
|
||||
* @copyright 2024 Marina Glancy
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import * as reportSelectors from 'core_reportbuilder/local/selectors';
|
||||
import * as tableEvents from 'core_table/local/dynamic/events';
|
||||
import * as FormChangeChecker from 'core_form/changechecker';
|
||||
import * as CustomEvents from 'core/custom_interaction_events';
|
||||
import jQuery from 'jquery';
|
||||
|
||||
const Selectors = {
|
||||
bulkActionsForm: 'form#user-bulk-action-form',
|
||||
userReportWrapper: '[data-region="report-user-list-wrapper"]',
|
||||
checkbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="slave"]',
|
||||
masterCheckbox: 'input[type="checkbox"][data-togglegroup="report-select-all"][data-toggle="master"]',
|
||||
checkedRows: '[data-togglegroup="report-select-all"][data-toggle="slave"]:checked',
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialise module
|
||||
*/
|
||||
export const init = () => {
|
||||
|
||||
const userBulkForm = document.querySelector(Selectors.bulkActionsForm);
|
||||
const userReport = userBulkForm?.closest(Selectors.userReportWrapper)?.querySelector(reportSelectors.regions.report);
|
||||
if (!userBulkForm || !userReport) {
|
||||
return;
|
||||
}
|
||||
const actionSelect = userBulkForm.querySelector('select');
|
||||
CustomEvents.define(actionSelect, [CustomEvents.events.accessibleChange]);
|
||||
|
||||
jQuery(actionSelect).on(CustomEvents.events.accessibleChange, event => {
|
||||
if (event.target.value && `${event.target.value}` !== "0") {
|
||||
const e = new Event('submit', {cancelable: true});
|
||||
userBulkForm.dispatchEvent(e);
|
||||
if (!e.defaultPrevented) {
|
||||
FormChangeChecker.markFormSubmitted(userBulkForm);
|
||||
userBulkForm.submit();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Every time the checkboxes in the report are changed, update the list of users in the form values
|
||||
// and enable/disable the action select.
|
||||
const updateUserIds = () => {
|
||||
const selectedUsers = [...userReport.querySelectorAll(Selectors.checkedRows)];
|
||||
const selectedUserIds = selectedUsers.map(check => parseInt(check.value));
|
||||
userBulkForm.querySelector('[name="userids"]').value = selectedUserIds.join(',');
|
||||
|
||||
// Disable the action selector if nothing selected, and reset the current selection.
|
||||
actionSelect.disabled = selectedUsers.length === 0;
|
||||
if (actionSelect.disabled) {
|
||||
actionSelect.value = "0";
|
||||
}
|
||||
|
||||
const selectedUsersNames = selectedUsers.map(check => document.querySelector(`label[for="${check.id}"]`).textContent);
|
||||
// Add the user ids and names to the form data attributes so they can be available from the
|
||||
// other JS modules that listen to the form submit event.
|
||||
userBulkForm.data = {userids: selectedUserIds, usernames: selectedUsersNames};
|
||||
};
|
||||
|
||||
updateUserIds();
|
||||
|
||||
document.addEventListener('change', event => {
|
||||
// When checkboxes are checked next to individual users or the master toggle (Select all/none).
|
||||
if ((event.target.matches(Selectors.checkbox) || event.target.matches(Selectors.masterCheckbox))
|
||||
&& userReport.contains(event.target)) {
|
||||
updateUserIds();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener(tableEvents.tableContentRefreshed, event => {
|
||||
// When the report contents is updated (i.e. page is changed, filters applied, etc).
|
||||
if (userReport.contains(event.target)) {
|
||||
updateUserIds();
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -1,104 +0,0 @@
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Modal for theme previews.
|
||||
*
|
||||
* @module core_admin/themeselector/preview_modal
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
import ModalEvents from 'core/modal_events';
|
||||
import ModalCancel from 'core/modal_cancel';
|
||||
import ModalSaveCancel from 'core/modal_save_cancel';
|
||||
import Notification from 'core/notification';
|
||||
import Templates from 'core/templates';
|
||||
import {getString} from 'core/str';
|
||||
|
||||
const SELECTORS = {
|
||||
THEMES_CONTAINER: 'themelist',
|
||||
PREVIEW: '[data-action="preview"]',
|
||||
};
|
||||
|
||||
/**
|
||||
* Entrypoint of the js.
|
||||
*
|
||||
* @method init
|
||||
*/
|
||||
export const init = () => {
|
||||
registerListenerEvents();
|
||||
};
|
||||
|
||||
/**
|
||||
* Register theme related event listeners.
|
||||
*
|
||||
* @method registerListenerEvents
|
||||
*/
|
||||
const registerListenerEvents = () => {
|
||||
document.addEventListener('click', (e) => {
|
||||
const preview = e.target.closest(SELECTORS.PREVIEW);
|
||||
if (preview) {
|
||||
buildModal(preview).catch(Notification.exception);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Build the modal with the provided data.
|
||||
*
|
||||
* @method buildModal
|
||||
* @param {object} element
|
||||
*/
|
||||
const buildModal = async(element) => {
|
||||
|
||||
// This string can be long. We will fetch it with JS as opposed to passing it as an attribute.
|
||||
let description = await getString('choosereadme', 'theme_' + element.getAttribute('data-choose'));
|
||||
|
||||
const themesContainer = document.getElementById(SELECTORS.THEMES_CONTAINER);
|
||||
const definedInConfig = parseInt(themesContainer.dataset.definedinconfig);
|
||||
// Prepare data for modal.
|
||||
const data = {
|
||||
name: element.getAttribute('data-name'),
|
||||
image: element.getAttribute('data-image'),
|
||||
description: description.replace(/<[^>]+>/g, ' '), // Strip out HTML tags.
|
||||
current: element.getAttribute('data-current'),
|
||||
actionurl: element.getAttribute('data-actionurl'),
|
||||
choose: element.getAttribute('data-choose'),
|
||||
sesskey: element.getAttribute('data-sesskey'),
|
||||
definedinconfig: definedInConfig,
|
||||
};
|
||||
|
||||
// Determine which modal template we should use.
|
||||
let modalTemplate = ModalSaveCancel;
|
||||
if (data.current || data.definedinconfig) {
|
||||
modalTemplate = ModalCancel;
|
||||
}
|
||||
|
||||
const modal = await modalTemplate.create({
|
||||
title: data.name,
|
||||
body: Templates.render('core_admin/themeselector/theme_preview_modal', data),
|
||||
large: true,
|
||||
buttons: {
|
||||
'save': getString('selecttheme', 'moodle'),
|
||||
'cancel': getString('closebuttontitle', 'moodle'),
|
||||
},
|
||||
show: true,
|
||||
});
|
||||
|
||||
modal.getRoot().on(ModalEvents.save, () => {
|
||||
modal.getRoot().find('form').submit();
|
||||
});
|
||||
};
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_admin\output;
|
||||
|
||||
use moodle_url;
|
||||
use renderable;
|
||||
use renderer_base;
|
||||
use stdClass;
|
||||
use templatable;
|
||||
|
||||
/**
|
||||
* Theme selector renderable.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license https://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class theme_selector implements renderable, templatable {
|
||||
|
||||
/** @var array $themedata Theme data to pass to the template. */
|
||||
private $themedata = null;
|
||||
|
||||
/** @var bool Whether $CFG->theme is defined in config.php. */
|
||||
private $definedinconfig;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $themedata Theme data used for template.
|
||||
* @param bool $definedinconfig Whether $CFG->theme is defined in config.php.
|
||||
*/
|
||||
public function __construct(array $themedata, bool $definedinconfig = false) {
|
||||
$this->themedata = $themedata;
|
||||
$this->definedinconfig = $definedinconfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export this data so it can be used as the context for a mustache template.
|
||||
*
|
||||
* @param renderer_base $output Renderer base.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function export_for_template(renderer_base $output): stdClass {
|
||||
|
||||
$data = new stdClass();
|
||||
// Theme data used to populate cards and modal.
|
||||
$data->themes = $this->themedata;
|
||||
// Reset theme caches button.
|
||||
$reseturl = new moodle_url('/admin/themeselector.php', ['sesskey' => sesskey(), 'reset' => 1]);
|
||||
$resetbutton = new \single_button($reseturl, get_string('themeresetcaches', 'admin'), 'post',
|
||||
\single_button::BUTTON_SECONDARY);
|
||||
$data->resetbutton = $resetbutton->export_for_template($output);
|
||||
$data->definedinconfig = $this->definedinconfig;
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class provider implements \core_privacy\local\metadata\null_provider {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_reason(): string {
|
||||
public static function get_reason() : string {
|
||||
return 'privacy:metadata';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,14 +46,12 @@ class task_log extends base {
|
||||
protected const FAILED = 1;
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return string[]
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_tables(): array {
|
||||
return [
|
||||
'task_log',
|
||||
];
|
||||
protected function get_default_table_aliases(): array {
|
||||
return ['task_log' => 'tl'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_admin\reportbuilder\local\filters;
|
||||
|
||||
use core\context\system;
|
||||
use core_course_category;
|
||||
use MoodleQuickForm;
|
||||
use core_reportbuilder\local\filters\base;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
|
||||
/**
|
||||
* Course role report filter (by role, category, course)
|
||||
*
|
||||
* The provided filter field SQL must refer/return an expression for the user ID (e.g. "{$user}.id")
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class courserole extends base {
|
||||
|
||||
/**
|
||||
* Setup form
|
||||
*
|
||||
* @param MoodleQuickForm $mform
|
||||
*/
|
||||
public function setup_form(MoodleQuickForm $mform): void {
|
||||
$elements = [];
|
||||
|
||||
// Role.
|
||||
$elements['role'] = $mform->createElement('select', "{$this->name}_role", get_string('rolefullname', 'core_role'),
|
||||
[0 => get_string('anyrole', 'core_filters')] + get_default_enrol_roles(system::instance()));
|
||||
|
||||
// Category.
|
||||
$elements['category'] = $mform->createElement('select', "{$this->name}_category", get_string('category'),
|
||||
[0 => get_string('anycategory', 'core_filters')] + core_course_category::make_categories_list());
|
||||
|
||||
// Course.
|
||||
$elements['course'] = $mform->createElement('text', "{$this->name}_course", get_string('shortnamecourse'));
|
||||
$mform->setType("{$this->name}_course", PARAM_RAW_TRIMMED);
|
||||
|
||||
$mform->addGroup($elements, "{$this->name}_group", $this->get_header(), '', false)
|
||||
->setHiddenLabel(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return filter SQL
|
||||
*
|
||||
* @param array $values
|
||||
* @return array
|
||||
*/
|
||||
public function get_sql_filter(array $values): array {
|
||||
[$fieldsql, $params] = $this->filter->get_field_sql_and_params();
|
||||
|
||||
[$contextalias, $rolealias, $coursealias] = database::generate_aliases(3);
|
||||
[$roleparam, $categoryparam, $courseparam] = database::generate_param_names(3);
|
||||
|
||||
// Role.
|
||||
$role = (int) ($values["{$this->name}_role"] ?? 0);
|
||||
if ($role > 0) {
|
||||
$selects[] = "{$rolealias}.roleid = :{$roleparam}";
|
||||
$params[$roleparam] = $role;
|
||||
}
|
||||
|
||||
// Category.
|
||||
$category = (int) ($values["{$this->name}_category"] ?? 0);
|
||||
if ($category > 0) {
|
||||
$selects[] = "{$coursealias}.category = :{$categoryparam}";
|
||||
$params[$categoryparam] = $category;
|
||||
}
|
||||
|
||||
// Course.
|
||||
$course = trim($values["{$this->name}_course"] ?? '');
|
||||
if ($course !== '') {
|
||||
$selects[] = "{$coursealias}.shortname = :{$courseparam}";
|
||||
$params[$courseparam] = $course;
|
||||
}
|
||||
|
||||
// Filter values are not set.
|
||||
if (empty($selects)) {
|
||||
return ['', []];
|
||||
}
|
||||
|
||||
return ["{$fieldsql} IN (
|
||||
SELECT {$rolealias}.userid
|
||||
FROM {role_assignments} {$rolealias}
|
||||
JOIN {context} {$contextalias} ON {$contextalias}.id = {$rolealias}.contextid AND {$contextalias}.contextlevel = 50
|
||||
JOIN {course} {$coursealias} ON {$coursealias}.id = {$contextalias}.instanceid
|
||||
WHERE " . implode(' AND ', $selects) . "
|
||||
)", $params];
|
||||
}
|
||||
}
|
||||
@@ -1,417 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core_admin\reportbuilder\local\systemreports;
|
||||
|
||||
use core_admin\reportbuilder\local\filters\courserole;
|
||||
use core\context\system;
|
||||
use core_cohort\reportbuilder\local\entities\cohort;
|
||||
use core_cohort\reportbuilder\local\entities\cohort_member;
|
||||
use core_reportbuilder\local\entities\user;
|
||||
use core_reportbuilder\local\filters\boolean_select;
|
||||
use core_reportbuilder\local\helpers\database;
|
||||
use core_reportbuilder\local\helpers\user_profile_fields;
|
||||
use core_reportbuilder\local\report\action;
|
||||
use core_reportbuilder\local\report\filter;
|
||||
use core_reportbuilder\system_report;
|
||||
use core_role\reportbuilder\local\entities\role;
|
||||
use core_user\fields;
|
||||
use lang_string;
|
||||
use moodle_url;
|
||||
use pix_icon;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/authlib.php');
|
||||
require_once($CFG->libdir.'/enrollib.php');
|
||||
require_once($CFG->dirroot.'/user/lib.php');
|
||||
|
||||
/**
|
||||
* Browse users system report class implementation
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 David Carrillo <davidmc@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class users extends system_report {
|
||||
|
||||
/**
|
||||
* Initialise report, we need to set the main table, load our entities and set columns/filters
|
||||
*/
|
||||
protected function initialise(): void {
|
||||
global $CFG;
|
||||
|
||||
// Our main entity, it contains all of the column definitions that we need.
|
||||
$entityuser = new user();
|
||||
$entityuseralias = $entityuser->get_table_alias('user');
|
||||
|
||||
$this->set_main_table('user', $entityuseralias);
|
||||
$this->add_entity($entityuser);
|
||||
|
||||
// Any columns required by actions should be defined here to ensure they're always available.
|
||||
$fullnamefields = array_map(fn($field) => "{$entityuseralias}.{$field}", fields::get_name_fields());
|
||||
$this->add_base_fields("{$entityuseralias}.id, {$entityuseralias}.confirmed, {$entityuseralias}.mnethostid,
|
||||
{$entityuseralias}.suspended, {$entityuseralias}.username, " . implode(', ', $fullnamefields));
|
||||
|
||||
if ($this->get_parameter('withcheckboxes', false, PARAM_BOOL)) {
|
||||
$canviewfullnames = has_capability('moodle/site:viewfullnames', \context_system::instance());
|
||||
$this->set_checkbox_toggleall(static function(\stdClass $row) use ($canviewfullnames): array {
|
||||
return [$row->id, fullname($row, $canviewfullnames)];
|
||||
});
|
||||
}
|
||||
|
||||
$paramguest = database::generate_param_name();
|
||||
$this->add_base_condition_sql("{$entityuseralias}.deleted <> 1 AND {$entityuseralias}.id <> :{$paramguest}",
|
||||
[$paramguest => $CFG->siteguest]);
|
||||
|
||||
$entitycohortmember = new cohort_member();
|
||||
$entitycohortmemberalias = $entitycohortmember->get_table_alias('cohort_members');
|
||||
$this->add_entity($entitycohortmember
|
||||
->add_joins($entitycohortmember->get_joins())
|
||||
->add_join("LEFT JOIN {cohort_members} {$entitycohortmemberalias}
|
||||
ON {$entityuseralias}.id = {$entitycohortmemberalias}.userid")
|
||||
);
|
||||
|
||||
$entitycohort = new cohort();
|
||||
$entitycohortalias = $entitycohort->get_table_alias('cohort');
|
||||
$this->add_entity($entitycohort
|
||||
->add_joins($entitycohort->get_joins())
|
||||
->add_joins($entitycohortmember->get_joins())
|
||||
->add_join("LEFT JOIN {cohort} {$entitycohortalias}
|
||||
ON {$entitycohortalias}.id = {$entitycohortmemberalias}.cohortid")
|
||||
);
|
||||
|
||||
// Join the role entity (Needed for the system role filter).
|
||||
$roleentity = new role();
|
||||
$role = $roleentity->get_table_alias('role');
|
||||
$this->add_entity($roleentity
|
||||
->add_join("LEFT JOIN (
|
||||
SELECT DISTINCT r0.id, ras.userid
|
||||
FROM {role} r0
|
||||
JOIN {role_assignments} ras ON ras.roleid = r0.id
|
||||
WHERE ras.contextid = ".SYSCONTEXTID."
|
||||
) {$role} ON {$role}.userid = {$entityuseralias}.id")
|
||||
);
|
||||
|
||||
// Now we can call our helper methods to add the content we want to include in the report.
|
||||
$this->add_columns();
|
||||
$this->add_filters();
|
||||
$this->add_actions();
|
||||
|
||||
// Set if report can be downloaded.
|
||||
$this->set_downloadable(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates access to view this report
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function can_view(): bool {
|
||||
return has_any_capability(['moodle/user:update', 'moodle/user:delete'], system::instance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the columns we want to display in the report
|
||||
*
|
||||
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
|
||||
* unique identifier
|
||||
*/
|
||||
public function add_columns(): void {
|
||||
$entityuser = $this->get_entity('user');
|
||||
$entityuseralias = $entityuser->get_table_alias('user');
|
||||
|
||||
$this->add_column($entityuser->get_column('fullnamewithpicturelink'));
|
||||
|
||||
// Include identity field columns.
|
||||
$identitycolumns = $entityuser->get_identity_columns($this->get_context());
|
||||
foreach ($identitycolumns as $identitycolumn) {
|
||||
$this->add_column($identitycolumn);
|
||||
}
|
||||
|
||||
// Add "Last access" column.
|
||||
$this->add_column(($entityuser->get_column('lastaccess'))
|
||||
->set_callback(static function ($value, \stdClass $row): string {
|
||||
if ($row->lastaccess) {
|
||||
return format_time(time() - $row->lastaccess);
|
||||
}
|
||||
return get_string('never');
|
||||
})
|
||||
);
|
||||
|
||||
if ($column = $this->get_column('user:fullnamewithpicturelink')) {
|
||||
$column
|
||||
->add_fields("{$entityuseralias}.suspended, {$entityuseralias}.confirmed")
|
||||
->add_callback(static function(string $fullname, \stdClass $row): string {
|
||||
if ($row->suspended) {
|
||||
$fullname .= ' ' . \html_writer::tag('span', get_string('suspended', 'moodle'),
|
||||
['class' => 'badge badge-secondary ml-1']);
|
||||
}
|
||||
if (!$row->confirmed) {
|
||||
$fullname .= ' ' . \html_writer::tag('span', get_string('confirmationpending', 'admin'),
|
||||
['class' => 'badge badge-danger ml-1']);
|
||||
}
|
||||
return $fullname;
|
||||
});
|
||||
}
|
||||
|
||||
$this->set_initial_sort_column('user:fullnamewithpicturelink', SORT_ASC);
|
||||
$this->set_default_no_results_notice(new lang_string('nousersfound', 'moodle'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the filters we want to display in the report
|
||||
*
|
||||
* They are all provided by the entities we previously added in the {@see initialise} method, referencing each by their
|
||||
* unique identifier
|
||||
*/
|
||||
protected function add_filters(): void {
|
||||
$entityuser = $this->get_entity('user');
|
||||
$entityuseralias = $entityuser->get_table_alias('user');
|
||||
|
||||
$filters = [
|
||||
'user:fullname',
|
||||
'user:firstname',
|
||||
'user:lastname',
|
||||
'user:username',
|
||||
'user:idnumber',
|
||||
'user:email',
|
||||
'user:department',
|
||||
'user:institution',
|
||||
'user:city',
|
||||
'user:country',
|
||||
'user:confirmed',
|
||||
'user:suspended',
|
||||
'user:timecreated',
|
||||
'user:lastaccess',
|
||||
'user:timemodified',
|
||||
'user:auth',
|
||||
'user:lastip',
|
||||
'cohort:idnumber',
|
||||
'role:name',
|
||||
];
|
||||
$this->add_filters_from_entities($filters);
|
||||
|
||||
// Enrolled in any course filter.
|
||||
$ue = database::generate_alias();
|
||||
[$now1, $now2] = database::generate_param_names(2);
|
||||
$now = time();
|
||||
$sql = "CASE WHEN ({$entityuseralias}.id IN (
|
||||
SELECT userid FROM {user_enrolments} {$ue}
|
||||
WHERE {$ue}.status = " . ENROL_USER_ACTIVE . "
|
||||
AND ({$ue}.timestart = 0 OR {$ue}.timestart < :{$now1})
|
||||
AND ({$ue}.timeend = 0 OR {$ue}.timeend > :{$now2})
|
||||
)) THEN 1 ELSE 0 END";
|
||||
|
||||
$this->add_filter((new filter(
|
||||
boolean_select::class,
|
||||
'enrolledinanycourse',
|
||||
new lang_string('anycourses', 'filters'),
|
||||
$this->get_entity('user')->get_entity_name(),
|
||||
))
|
||||
->set_field_sql($sql, [
|
||||
$now1 => $now,
|
||||
$now2 => $now,
|
||||
])
|
||||
);
|
||||
|
||||
// Course role filter.
|
||||
$this->add_filter((new filter(
|
||||
courserole::class,
|
||||
'courserole',
|
||||
new lang_string('courserole', 'filters'),
|
||||
$this->get_entity('user')->get_entity_name(),
|
||||
))
|
||||
->set_field_sql("{$entityuseralias}.id")
|
||||
);
|
||||
|
||||
// Add user profile fields filters.
|
||||
$userprofilefields = new user_profile_fields($entityuseralias . '.id', $entityuser->get_entity_name());
|
||||
foreach ($userprofilefields->get_filters() as $filter) {
|
||||
$this->add_filter($filter);
|
||||
}
|
||||
|
||||
// Set options for system role filter.
|
||||
if ($filter = $this->get_filter('role:name')) {
|
||||
$filter
|
||||
->set_header(new lang_string('globalrole', 'role'))
|
||||
->set_options(get_assignable_roles(system::instance()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the system report actions. An extra column will be appended to each row, containing all actions added here
|
||||
*
|
||||
* Note the use of ":id" placeholder which will be substituted according to actual values in the row
|
||||
*/
|
||||
protected function add_actions(): void {
|
||||
global $DB, $USER;
|
||||
|
||||
$contextsystem = system::instance();
|
||||
|
||||
// Action to edit users.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/user/editadvanced.php', ['id' => ':id', 'course' => get_site()->id]),
|
||||
new pix_icon('t/edit', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('edit', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && (is_siteadmin($USER) || !is_siteadmin($row));
|
||||
}));
|
||||
|
||||
// Action to suspend users (non mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['suspend' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/show', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('suspenduser', 'admin'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended && !is_mnet_remote_user($row) &&
|
||||
!($row->id == $USER->id || is_siteadmin($row));
|
||||
}));
|
||||
|
||||
// Action to unsuspend users (non mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['unsuspend' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/hide', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('unsuspenduser', 'admin'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && $row->suspended && !is_mnet_remote_user($row) &&
|
||||
!($row->id == $USER->id || is_siteadmin($row));
|
||||
}));
|
||||
|
||||
// Action to unlock users (non mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['unlock' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/unlock', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('unlockaccount', 'admin'),
|
||||
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && !is_mnet_remote_user($row) &&
|
||||
login_is_lockedout($row);
|
||||
}));
|
||||
|
||||
// Action to suspend users (mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'deny']),
|
||||
new pix_icon('t/show', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('denyaccess', 'mnet'),
|
||||
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
|
||||
if (!$accessctrl = $DB->get_field(table: 'mnet_sso_access_control', return: 'accessctrl',
|
||||
conditions: ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]
|
||||
)) {
|
||||
$accessctrl = 'allow';
|
||||
}
|
||||
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
|
||||
is_mnet_remote_user($row) && $accessctrl == 'allow';
|
||||
}));
|
||||
|
||||
// Action to unsuspend users (mnet remote users).
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['acl' => ':id', 'sesskey' => sesskey(), 'accessctrl' => 'allow']),
|
||||
new pix_icon('t/hide', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('allowaccess', 'mnet'),
|
||||
))->add_callback(static function(\stdclass $row) use ($DB, $contextsystem): bool {
|
||||
if (!$accessctrl = $DB->get_field(table: 'mnet_sso_access_control', return: 'accessctrl',
|
||||
conditions: ['username' => $row->username, 'mnet_host_id' => $row->mnethostid]
|
||||
)) {
|
||||
$accessctrl = 'allow';
|
||||
}
|
||||
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->suspended &&
|
||||
is_mnet_remote_user($row) && $accessctrl == 'deny';
|
||||
}));
|
||||
|
||||
// Action to delete users.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['delete' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/delete', ''),
|
||||
[
|
||||
'class' => 'text-danger',
|
||||
'data-modal' => 'confirmation',
|
||||
'data-modal-title-str' => json_encode(['deleteuser', 'admin']),
|
||||
'data-modal-content-str' => ':deletestr',
|
||||
'data-modal-yes-button-str' => json_encode(['delete', 'core']),
|
||||
'data-modal-destination' => ':deleteurl',
|
||||
|
||||
],
|
||||
false,
|
||||
new lang_string('delete', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row) use ($USER, $contextsystem): bool {
|
||||
|
||||
// Populate deletion modal attributes.
|
||||
$row->deletestr = json_encode([
|
||||
'deletecheckfull',
|
||||
'moodle',
|
||||
fullname($row, true),
|
||||
]);
|
||||
|
||||
$row->deleteurl = (new moodle_url('/admin/user.php', [
|
||||
'delete' => $row->id,
|
||||
'confirm' => md5($row->id),
|
||||
'sesskey' => sesskey(),
|
||||
]))->out(false);
|
||||
|
||||
return has_capability('moodle/user:delete', $contextsystem) &&
|
||||
!is_mnet_remote_user($row) && $row->id != $USER->id && !is_siteadmin($row);
|
||||
}));
|
||||
|
||||
$this->add_action_divider();
|
||||
|
||||
// Action to confirm users.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['confirmuser' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/check', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('confirmaccount', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row) use ($contextsystem): bool {
|
||||
return has_capability('moodle/user:update', $contextsystem) && !$row->confirmed;
|
||||
}));
|
||||
|
||||
// Action to resend email.
|
||||
$this->add_action((new action(
|
||||
new moodle_url('/admin/user.php', ['resendemail' => ':id', 'sesskey' => sesskey()]),
|
||||
new pix_icon('t/email', ''),
|
||||
[],
|
||||
false,
|
||||
new lang_string('resendemail', 'moodle'),
|
||||
))->add_callback(static function(\stdclass $row): bool {
|
||||
return !$row->confirmed && !is_mnet_remote_user($row);
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Row class
|
||||
*
|
||||
* @param \stdClass $row
|
||||
* @return string
|
||||
*/
|
||||
public function get_row_class(\stdClass $row): string {
|
||||
return $row->suspended ? 'text-muted' : '';
|
||||
}
|
||||
}
|
||||
@@ -91,7 +91,7 @@ class hook_list_table extends flexible_table {
|
||||
*/
|
||||
public function out(): void {
|
||||
// All hook consumers referenced from the db/hooks.php files.
|
||||
$hookmanager = \core\di::get(\core\hook\manager::class);
|
||||
$hookmanager = \core\hook\manager::get_instance();
|
||||
$allhooks = (array)$hookmanager->get_all_callbacks();
|
||||
|
||||
// Add any unused hooks.
|
||||
@@ -154,7 +154,11 @@ class hook_list_table extends flexible_table {
|
||||
return '';
|
||||
}
|
||||
|
||||
$deprecates = \core\hook\manager::get_replaced_callbacks($row->classname);
|
||||
$rc = new \ReflectionClass($row->classname);
|
||||
if (!$rc->implementsInterface(\core\hook\deprecated_callback_replacement::class)) {
|
||||
return '';
|
||||
}
|
||||
$deprecates = call_user_func([$row->classname, 'get_deprecated_plugin_callbacks']);
|
||||
if (count($deprecates) === 0) {
|
||||
return '';
|
||||
}
|
||||
@@ -269,7 +273,7 @@ class hook_list_table extends flexible_table {
|
||||
if (is_array($tag)) {
|
||||
return $this->get_tag(...$tag);
|
||||
}
|
||||
return $this->get_tag($tag, 'badge bg-info text-white');
|
||||
return $this->get_tag($tag, 'badge badge-info');
|
||||
}, $tags);
|
||||
|
||||
return implode("\n", $taglist);
|
||||
|
||||
@@ -500,15 +500,4 @@ abstract class plugin_management_table extends flexible_table implements dynamic
|
||||
protected function supports_ordering(): bool {
|
||||
return $this->plugininfoclass::plugintype_supports_ordering();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user has the capability to access this table.
|
||||
*
|
||||
* Default implementation for plugin management tables is to require 'moodle/site:config' capability
|
||||
*
|
||||
* @return bool Return true if capability check passed.
|
||||
*/
|
||||
public function has_capability(): bool {
|
||||
return has_capability('moodle/site:config', $this->get_context());
|
||||
}
|
||||
}
|
||||
|
||||
+7
-23
@@ -33,7 +33,6 @@ require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
list($options, $unrecognized) = cli_get_params(array(
|
||||
'courseid' => false,
|
||||
'courseshortname' => '',
|
||||
'cmid' => false,
|
||||
'destination' => '',
|
||||
'help' => false,
|
||||
), array('h' => 'help'));
|
||||
@@ -43,14 +42,13 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] || !($options['courseid'] || $options['courseshortname'] || $options['cmid'])) {
|
||||
if ($options['help'] || !($options['courseid'] || $options['courseshortname'])) {
|
||||
$help = <<<EOL
|
||||
Perform backup of the given course or course module.
|
||||
Perform backup of the given course.
|
||||
|
||||
Options:
|
||||
--courseid=INTEGER Course ID for backup.
|
||||
--courseshortname=STRING Course shortname for backup. This option is ignored if courseid is set.
|
||||
--cmid=INTEGER Course module ID for backup. This option is ignored if courseid or courseshortname is set.
|
||||
--courseshortname=STRING Course shortname for backup.
|
||||
--destination=STRING Path where to store backup file. If not set the backup
|
||||
will be stored within the course backup file area.
|
||||
-h, --help Print out this help.
|
||||
@@ -78,26 +76,16 @@ if (!empty($dir)) {
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the course or course module exists.
|
||||
// Check that the course exists.
|
||||
if ($options['courseid']) {
|
||||
$course = $DB->get_record('course', array('id' => $options['courseid']), '*', MUST_EXIST);
|
||||
} else if ($options['courseshortname']) {
|
||||
$course = $DB->get_record('course', array('shortname' => $options['courseshortname']), '*', MUST_EXIST);
|
||||
} else if ($options['cmid']) {
|
||||
$cm = $DB->get_record('course_modules', ['id' => $options['cmid']], '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
cli_heading('Performing backup...');
|
||||
if (!empty($course)) {
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
|
||||
} else if (!empty($cm)) {
|
||||
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
}
|
||||
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $course->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_YES, backup::MODE_GENERAL, $admin->id);
|
||||
// Set the default filename.
|
||||
$format = $bc->get_format();
|
||||
$type = $bc->get_type();
|
||||
@@ -125,11 +113,7 @@ if (!empty($dir)) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!empty($course)) {
|
||||
mtrace("Backup completed, the new file is listed in the backup area of the given course");
|
||||
} else {
|
||||
mtrace("Backup completed, the new file is listed in the backup area of the given module");
|
||||
}
|
||||
mtrace("Backup completed, the new file is listed in the backup area of the given course");
|
||||
}
|
||||
$bc->destroy();
|
||||
exit(0);
|
||||
@@ -1,132 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This script allows to import a course from CLI.
|
||||
*
|
||||
* @package core
|
||||
* @subpackage cli
|
||||
* @author Tomo Tsuyuki <tomotsuyuki@catalyst-au.net>
|
||||
* @copyright 2023 Catalyst IT
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', 1);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/backup_includes.php');
|
||||
require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
|
||||
|
||||
list($options, $unrecognized) = cli_get_params([
|
||||
'srccourseid' => '',
|
||||
'srccmid' => '',
|
||||
'dstcourseid' => '',
|
||||
'showdebugging' => false,
|
||||
'help' => false,
|
||||
], [
|
||||
's' => 'showdebugging',
|
||||
'h' => 'help',
|
||||
]);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] ||
|
||||
!(($options['srccourseid'] && $options['dstcourseid'])
|
||||
|| ($options['srccmid'] && $options['dstcourseid']))) {
|
||||
$help = <<<EOL
|
||||
Import course or course module into provided course.
|
||||
|
||||
Options:
|
||||
--srccourseid=INT Source course ID to backup.
|
||||
--srccmid=INT Source course module ID to backup.
|
||||
--dstcourseid=INT Destination course ID to restore.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example1: (Import from a course into another course)
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/import.php --srccourseid=12 --dstcourseid=13\n
|
||||
|
||||
Example2: (Import from a course module into a course)
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/import.php --srccmid=21 --dstcourseid=11\n
|
||||
EOL;
|
||||
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($options['showdebugging']) {
|
||||
set_debugging(DEBUG_DEVELOPER, true);
|
||||
}
|
||||
|
||||
if (!$admin = get_admin()) {
|
||||
throw new \moodle_exception('noadmins');
|
||||
}
|
||||
|
||||
if (!empty($options['srccourseid']) && !empty($options['dstcourseid'])) {
|
||||
// Import from course into course.
|
||||
if (!$srccourse = $DB->get_record('course', ['id' => $options['srccourseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
if (!$dstcourse = $DB->get_record('course', ['id' => $options['dstcourseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
|
||||
cli_heading(get_string('importfromcoursetocourse', 'backup', (object)$options));
|
||||
$bc = new backup_controller(backup::TYPE_1COURSE, $srccourse->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->id);
|
||||
$backupid = $bc->get_backupid();
|
||||
$bc->execute_plan();
|
||||
$bc->destroy();
|
||||
cli_heading(get_string('backupthenrestore', 'backup'));
|
||||
|
||||
$rc = new restore_controller($backupid, $dstcourse->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_SAMESITE, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
cli_heading(get_string('restoredcourseid', 'backup', $dstcourse->id));
|
||||
} else if (!empty($options['srccmid']) && !empty($options['dstcourseid'])) {
|
||||
// Import from course module into course.
|
||||
if (!$cm = $DB->get_record('course_modules', ['id' => $options['srccmid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcoursemoduleid', 'error', '', $options['srccmid']);
|
||||
}
|
||||
if (!$course = $DB->get_record('course', ['id' => $options['dstcourseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
|
||||
cli_heading(get_string('importfromccmidtocourse', 'backup', (object)$options));
|
||||
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $cm->id, backup::FORMAT_MOODLE,
|
||||
backup::INTERACTIVE_NO, backup::MODE_IMPORT, $admin->id);
|
||||
$backupid = $bc->get_backupid();
|
||||
$bc->execute_plan();
|
||||
$bc->destroy();
|
||||
cli_heading(get_string('backupthenrestore', 'backup'));
|
||||
|
||||
$rc = new restore_controller($backupid, $course->id, backup::INTERACTIVE_NO,
|
||||
backup::MODE_SAMESITE, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
cli_heading(get_string('restoredcourseid', 'backup', $course->id));
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
}
|
||||
|
||||
exit(0);
|
||||
@@ -177,7 +177,6 @@ $CFG->admin = array_pop($parts);
|
||||
ini_set('include_path', $CFG->libdir.'/pear' . PATH_SEPARATOR . ini_get('include_path'));
|
||||
|
||||
require_once($CFG->libdir.'/classes/component.php');
|
||||
|
||||
require_once($CFG->libdir.'/classes/text.php');
|
||||
require_once($CFG->libdir.'/classes/string_manager.php');
|
||||
require_once($CFG->libdir.'/classes/string_manager_install.php');
|
||||
@@ -193,8 +192,13 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
require_once($CFG->dirroot.'/cache/lib.php');
|
||||
|
||||
// Register our classloader.
|
||||
\core_component::register_autoloader();
|
||||
// Register our classloader, in theory somebody might want to replace it to load other hacked core classes.
|
||||
// Required because the database checks below lead to session interaction which is going to lead us to requiring autoloaded classes.
|
||||
if (defined('COMPONENT_CLASSLOADER')) {
|
||||
spl_autoload_register(COMPONENT_CLASSLOADER);
|
||||
} else {
|
||||
spl_autoload_register('core_component::classloader');
|
||||
}
|
||||
|
||||
require($CFG->dirroot.'/version.php');
|
||||
$CFG->target_release = $release;
|
||||
|
||||
@@ -31,7 +31,6 @@ require_once($CFG->libdir.'/clilib.php');
|
||||
$longoptions = [
|
||||
'help' => false,
|
||||
'muc' => false,
|
||||
'courses' => false,
|
||||
'theme' => false,
|
||||
'lang' => false,
|
||||
'js' => false,
|
||||
@@ -56,8 +55,6 @@ all caches will be purged.
|
||||
Options:
|
||||
-h, --help Print out this help
|
||||
--muc Purge all MUC caches (includes lang cache)
|
||||
--courses Purge all course caches (or only those specified by a comma-separated list).
|
||||
e.g. --courses=4,67,145
|
||||
--theme Purge theme cache
|
||||
--lang Purge language string cache
|
||||
--js Purge JavaScript cache
|
||||
|
||||
@@ -32,13 +32,11 @@ require_once($CFG->dirroot . "/backup/util/includes/restore_includes.php");
|
||||
list($options, $unrecognized) = cli_get_params([
|
||||
'file' => '',
|
||||
'categoryid' => '',
|
||||
'courseid' => '',
|
||||
'showdebugging' => false,
|
||||
'help' => false,
|
||||
], [
|
||||
'f' => 'file',
|
||||
'c' => 'categoryid',
|
||||
'C' => 'courseid',
|
||||
's' => 'showdebugging',
|
||||
'h' => 'help',
|
||||
]);
|
||||
@@ -48,17 +46,15 @@ if ($unrecognized) {
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
if ($options['help'] || !($options['file']) || !($options['categoryid'] || $options['courseid'])) {
|
||||
if ($options['help'] || !($options['file']) || !($options['categoryid'])) {
|
||||
$help = <<<EOL
|
||||
Restore backup into provided category or course.
|
||||
If courseid is set, course module/s will be added into the course.
|
||||
Restore backup into provided category.
|
||||
|
||||
Options:
|
||||
-f, --file=STRING Path to the backup file.
|
||||
-c, --categoryid=INT ID of the course category to restore to.
|
||||
-C, --courseid=INT ID of the course to restore to. This option is ignored if categoryid is set.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
-f, --file=STRING Path to the backup file.
|
||||
-c, --categoryid=INT ID of the category to restore too.
|
||||
-s, --showdebugging Show developer level debugging information
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example:
|
||||
\$sudo -u www-data /usr/bin/php admin/cli/restore_backup.php --file=/path/to/backup/file.mbz --categoryid=1\n
|
||||
@@ -80,16 +76,8 @@ if (!file_exists($options['file'])) {
|
||||
throw new \moodle_exception('filenotfound');
|
||||
}
|
||||
|
||||
if ($options['categoryid']) {
|
||||
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcategoryid');
|
||||
}
|
||||
} else if ($options['courseid']) {
|
||||
if (!$course = $DB->get_record('course', ['id' => $options['courseid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcourseid');
|
||||
}
|
||||
} else {
|
||||
throw new \moodle_exception('invalidoption');
|
||||
if (!$category = $DB->get_record('course_categories', ['id' => $options['categoryid']], 'id')) {
|
||||
throw new \moodle_exception('invalidcategoryid');
|
||||
}
|
||||
|
||||
$backupdir = restore_controller::get_tempdir_name(SITEID, $USER->id);
|
||||
@@ -104,29 +92,13 @@ try {
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoringcourse', 'backup'),
|
||||
get_string('restoringcourseshortname', 'backup'));
|
||||
|
||||
if (!empty($course)) {
|
||||
$courseid = $course->id;
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_EXISTING_ADDING);
|
||||
} else {
|
||||
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
|
||||
}
|
||||
$courseid = restore_dbops::create_new_course($fullname, $shortname, $category->id);
|
||||
|
||||
$rc = new restore_controller($backupdir, $courseid, backup::INTERACTIVE_NO,
|
||||
backup::MODE_GENERAL, $admin->id, backup::TARGET_NEW_COURSE);
|
||||
$rc->execute_precheck();
|
||||
$rc->execute_plan();
|
||||
$rc->destroy();
|
||||
|
||||
// Rename course name if the backup is from course module and restore to category.
|
||||
if (empty($course)) {
|
||||
$course = get_course($courseid);
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names(0, get_string('restoretonewcourse', 'backup'),
|
||||
get_string('newcourse'));
|
||||
$course->fullname = $fullname;
|
||||
$course->shortname = $shortname;
|
||||
$course->visible = 1;
|
||||
$DB->update_record('course', $course);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
cli_heading(get_string('cleaningtempdata'));
|
||||
fulldelete($path);
|
||||
|
||||
@@ -189,7 +189,11 @@ if ($disable = $options['disable']) {
|
||||
}
|
||||
|
||||
$task->set_lock($lock);
|
||||
$cronlock->release();
|
||||
if (!$task->is_blocking()) {
|
||||
$cronlock->release();
|
||||
} else {
|
||||
$task->set_cron_lock($cronlock);
|
||||
}
|
||||
|
||||
\core\cron::run_inner_scheduled_task($task);
|
||||
}
|
||||
|
||||
@@ -3923,8 +3923,6 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_xmlrpc_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.2" requires="3.11.8">
|
||||
@@ -3941,7 +3939,6 @@
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_83" message="unsupportedphpversion83" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -4115,8 +4112,6 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.3" requires="3.11.8">
|
||||
@@ -4133,7 +4128,6 @@
|
||||
<VENDOR name="oracle" version="19" />
|
||||
</DATABASE>
|
||||
<PHP version="8.0.0" level="required">
|
||||
<RESTRICT function="restrict_php_version_83" message="unsupportedphpversion83" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -4309,8 +4303,6 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.4" requires="4.1.2">
|
||||
@@ -4502,205 +4494,6 @@
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="4.5" requires="4.1.2">
|
||||
<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.1.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_CHECK file="lib/upgradelib.php" function="check_mod_assignment" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_db_prefix_length" level="required">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_oracle_usage" level="optional">
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_async_backup" level="recommended">
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ require_once($CFG->libdir . '/tablelib.php');
|
||||
admin_externalpage_setup('hooksoverview');
|
||||
require_capability('moodle/site:config', \core\context\system::instance());
|
||||
|
||||
$hookmanager = \core\di::get(\core\hook\manager::class);
|
||||
$hookmanager = \core\hook\manager::get_instance();
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('hooksoverview', 'core_admin'));
|
||||
|
||||
@@ -301,12 +301,14 @@ class helper {
|
||||
// Set Activity chooser tabs to the default value ("Starred, Recommended, All, Activities, Resources").
|
||||
static::add_item($presetid, 'activitychoosertabmode', '3');
|
||||
|
||||
// Modules: Enable database, external tool (lti), IMS content package (imscp), lesson, SCORM, wiki, workshop.
|
||||
// Modules: Enable chat, database, external tool (lti), IMS content package (imscp), lesson, SCORM, survey, wiki, workshop.
|
||||
static::add_plugin($presetid, 'mod', 'chat', true);
|
||||
static::add_plugin($presetid, 'mod', 'data', true);
|
||||
static::add_plugin($presetid, 'mod', 'lti', true);
|
||||
static::add_plugin($presetid, 'mod', 'imscp', true);
|
||||
static::add_plugin($presetid, 'mod', 'lesson', true);
|
||||
static::add_plugin($presetid, 'mod', 'scorm', true);
|
||||
static::add_plugin($presetid, 'mod', 'survey', true);
|
||||
static::add_plugin($presetid, 'mod', 'wiki', true);
|
||||
static::add_plugin($presetid, 'mod', 'workshop', true);
|
||||
|
||||
|
||||
@@ -761,8 +761,8 @@ class manager {
|
||||
public function delete_preset(int $presetid): void {
|
||||
global $DB;
|
||||
|
||||
// Check the preset exists (cannot delete the pre-installed core "Starter" and "Full" presets).
|
||||
$preset = $DB->get_record('adminpresets', ['id' => $presetid, 'iscore' => self::NONCORE_PRESET]);
|
||||
// Check the preset exists.
|
||||
$preset = $DB->get_record('adminpresets', ['id' => $presetid]);
|
||||
if (!$preset) {
|
||||
throw new moodle_exception('errordeleting', 'core_adminpresets');
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ class provider implements
|
||||
* @param collection $collection A list of information about this component
|
||||
* @return collection The collection object filled out with information about this component.
|
||||
*/
|
||||
public static function get_metadata(collection $collection): collection {
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
// These tables are really data about site configuration and not user data.
|
||||
|
||||
// The adminpresets includes information about which user performed a configuration change using the admin_presets
|
||||
@@ -74,7 +74,7 @@ class provider implements
|
||||
* @param int $userid The user to search.
|
||||
* @return contextlist $contextlist The contextlist containing the list of contexts used in this plugin.
|
||||
*/
|
||||
public static function get_contexts_for_userid(int $userid): contextlist {
|
||||
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||
return new contextlist();
|
||||
}
|
||||
|
||||
|
||||
@@ -227,6 +227,7 @@ class core_adminpresets_generator extends \component_generator_base {
|
||||
public function access_protected($object, string $property) {
|
||||
$reflection = new ReflectionClass($object);
|
||||
$property = $reflection->getProperty($property);
|
||||
$property->setAccessible(true);
|
||||
return $property->getValue($object);
|
||||
}
|
||||
|
||||
@@ -243,6 +244,7 @@ class core_adminpresets_generator extends \component_generator_base {
|
||||
|
||||
// Set method accessibility.
|
||||
$method = new ReflectionMethod(manager::class, 'get_setting');
|
||||
$method->setAccessible(true);
|
||||
|
||||
// Get the proper adminpresets_setting instance.
|
||||
$settingpage = $adminroot->locate($category);
|
||||
|
||||
@@ -344,7 +344,7 @@ class helper_test extends \advanced_testcase {
|
||||
],
|
||||
'plugins' => [
|
||||
'assign' => 1,
|
||||
'book' => 1,
|
||||
'chat' => 1,
|
||||
'data' => 1,
|
||||
'lesson' => 1,
|
||||
],
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace core_adminpresets;
|
||||
|
||||
use moodle_exception;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
@@ -29,14 +28,6 @@ use stdClass;
|
||||
* @coversDefaultClass \core_adminpresets\manager
|
||||
*/
|
||||
class manager_test extends \advanced_testcase {
|
||||
/**
|
||||
* Include required libraries.
|
||||
*/
|
||||
public static function setUpBeforeClass(): void {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of protected get_site_settings method.
|
||||
*
|
||||
@@ -608,28 +599,10 @@ class manager_test extends \advanced_testcase {
|
||||
|
||||
$manager = new manager();
|
||||
|
||||
$this->expectException(moodle_exception::class);
|
||||
$this->expectExceptionMessage('Error deleting from database');
|
||||
$this->expectException(\moodle_exception::class);
|
||||
$manager->delete_preset($unexistingid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test trying to delete the core/pre-defined presets
|
||||
*
|
||||
* @covers ::delete_preset
|
||||
*/
|
||||
public function test_delete_preset_core(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$starterpreset = $DB->get_record('adminpresets', ['iscore' => manager::STARTER_PRESET]);
|
||||
|
||||
$this->expectException(moodle_exception::class);
|
||||
$this->expectExceptionMessage('Error deleting from database');
|
||||
(new manager())->delete_preset($starterpreset->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the behaviour of delete_preset() method.
|
||||
*
|
||||
|
||||
@@ -36,7 +36,7 @@ class privacy_provider_test extends provider_testcase {
|
||||
* Test for provider::get_metadata().
|
||||
* @covers ::get_metadata
|
||||
*/
|
||||
public function test_get_metadata(): void {
|
||||
public function test_get_metadata() {
|
||||
$collection = new collection('core_adminpresets');
|
||||
$newcollection = provider::get_metadata($collection);
|
||||
$itemcollection = $newcollection->get_collection();
|
||||
@@ -49,7 +49,7 @@ class privacy_provider_test extends provider_testcase {
|
||||
* Test for provider::get_contexts_for_userid() doesn't return any context.
|
||||
* @covers ::get_contexts_for_userid
|
||||
*/
|
||||
public function test_get_contexts_for_userid(): void {
|
||||
public function test_get_contexts_for_userid() {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -67,7 +67,7 @@ class privacy_provider_test extends provider_testcase {
|
||||
* Test for provider::get_users_in_context() doesn't return any user.
|
||||
* @covers ::get_users_in_context
|
||||
*/
|
||||
public function test_get_users_in_context(): void {
|
||||
public function test_get_users_in_context() {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -88,7 +88,7 @@ class privacy_provider_test extends provider_testcase {
|
||||
* Test for provider::export_user_data().
|
||||
* @covers ::export_user_data
|
||||
*/
|
||||
public function test_export_user_data(): void {
|
||||
public function test_export_user_data() {
|
||||
global $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -121,7 +121,7 @@ class privacy_provider_test extends provider_testcase {
|
||||
* Test for provider::delete_data_for_all_users_in_context().
|
||||
* @covers ::delete_data_for_all_users_in_context
|
||||
*/
|
||||
public function test_delete_data_for_all_users_in_context(): void {
|
||||
public function test_delete_data_for_all_users_in_context() {
|
||||
global $DB, $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -146,7 +146,7 @@ class privacy_provider_test extends provider_testcase {
|
||||
* Test for provider::delete_data_for_user().
|
||||
* @covers ::delete_data_for_user
|
||||
*/
|
||||
public function test_delete_data_for_user(): void {
|
||||
public function test_delete_data_for_user() {
|
||||
global $DB, $USER;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
+32
-50
@@ -617,7 +617,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @param bool $croninfrequent
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function cron_infrequent_warning(bool $croninfrequent): string {
|
||||
public function cron_infrequent_warning(bool $croninfrequent) : string {
|
||||
global $CFG;
|
||||
|
||||
if (!$croninfrequent) {
|
||||
@@ -874,8 +874,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
protected function mobile_configuration_warning($mobileconfigured) {
|
||||
$output = '';
|
||||
if (!$mobileconfigured) {
|
||||
$settingslink = new moodle_url('/admin/search.php', ['query' => 'enablemobilewebservice']);
|
||||
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'), 'get');
|
||||
$settingslink = new moodle_url('/admin/settings.php', ['section' => 'mobilesettings']);
|
||||
$configurebutton = $this->single_button($settingslink, get_string('enablemobilewebservice', 'admin'));
|
||||
$output .= $this->warning(get_string('mobilenotconfiguredwarning', 'admin') . ' ' . $configurebutton);
|
||||
}
|
||||
|
||||
@@ -1111,11 +1111,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
if ($isstandard = $plugin->is_standard()) {
|
||||
$row->attributes['class'] .= ' standard';
|
||||
$sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'),
|
||||
'sourcetext badge bg-secondary text-dark');
|
||||
$sourcelabel = html_writer::span(get_string('sourcestd', 'core_plugin'), 'sourcetext badge badge-secondary');
|
||||
} else {
|
||||
$row->attributes['class'] .= ' extension';
|
||||
$sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext badge bg-info text-white');
|
||||
$sourcelabel = html_writer::span(get_string('sourceext', 'core_plugin'), 'sourcetext badge badge-info');
|
||||
}
|
||||
|
||||
$coredependency = $plugin->is_core_dependency_satisfied($version);
|
||||
@@ -1129,19 +1128,19 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$statusclass = 'statustext badge ';
|
||||
switch ($statuscode) {
|
||||
case core_plugin_manager::PLUGIN_STATUS_NEW:
|
||||
$statusclass .= $dependenciesok ? 'bg-success text-white' : 'bg-warning text-dark';
|
||||
$statusclass .= $dependenciesok ? 'badge-success' : 'badge-warning';
|
||||
break;
|
||||
case core_plugin_manager::PLUGIN_STATUS_UPGRADE:
|
||||
$statusclass .= $dependenciesok ? 'bg-info text-white' : 'bg-warning text-dark';
|
||||
$statusclass .= $dependenciesok ? 'badge-info' : 'badge-warning';
|
||||
break;
|
||||
case core_plugin_manager::PLUGIN_STATUS_MISSING:
|
||||
case core_plugin_manager::PLUGIN_STATUS_DOWNGRADE:
|
||||
case core_plugin_manager::PLUGIN_STATUS_DELETE:
|
||||
$statusclass .= 'bg-danger text-white';
|
||||
$statusclass .= 'badge-danger';
|
||||
break;
|
||||
case core_plugin_manager::PLUGIN_STATUS_NODB:
|
||||
case core_plugin_manager::PLUGIN_STATUS_UPTODATE:
|
||||
$statusclass .= $dependenciesok ? 'bg-light text-dark' : 'bg-warning text-dark';
|
||||
$statusclass .= $dependenciesok ? 'badge-light' : 'badge-warning';
|
||||
break;
|
||||
}
|
||||
$status = html_writer::span(get_string('status_' . $statuscode, 'core_plugin'), $statusclass);
|
||||
@@ -1264,11 +1263,11 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 0)),
|
||||
get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge bg-light text-dark'),
|
||||
get_string('plugincheckattention', 'core_plugin')).' '.html_writer::span($sumattention, 'badge badge-light'),
|
||||
'btn btn-link mr-1');
|
||||
|
||||
$out .= html_writer::div(html_writer::link(new moodle_url($this->page->url, array('showallplugins' => 1)),
|
||||
get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge bg-light text-dark'),
|
||||
get_string('plugincheckall', 'core_plugin')).' '.html_writer::span($sumtotal, 'badge badge-light'),
|
||||
'btn btn-link mr-1');
|
||||
|
||||
$out .= $this->output->container_end(); // End of .actions container.
|
||||
@@ -1421,9 +1420,9 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$supportedmoodles = array();
|
||||
foreach ($plugin->version->supportedmoodles as $moodle) {
|
||||
if ($CFG->branch == str_replace('.', '', $moodle->release)) {
|
||||
$supportedmoodles[] = html_writer::span($moodle->release, 'badge bg-success text-white');
|
||||
$supportedmoodles[] = html_writer::span($moodle->release, 'badge badge-success');
|
||||
} else {
|
||||
$supportedmoodles[] = html_writer::span($moodle->release, 'badge bg-light text-dark');
|
||||
$supportedmoodles[] = html_writer::span($moodle->release, 'badge badge-light');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1529,7 +1528,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$label = '';
|
||||
} else {
|
||||
$class = 'requires-failed';
|
||||
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge bg-danger text-white');
|
||||
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-danger');
|
||||
}
|
||||
|
||||
if ($branch != null && !$plugin->is_core_compatible_satisfied($branch)) {
|
||||
@@ -1558,10 +1557,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
} else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_MISSING) {
|
||||
if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) {
|
||||
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'),
|
||||
'badge bg-warning text-dark');
|
||||
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'),
|
||||
'badge bg-warning text-dark');
|
||||
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge badge-warning');
|
||||
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'badge badge-warning');
|
||||
$class = 'requires-failed requires-missing requires-available';
|
||||
$actions[] = html_writer::link(
|
||||
new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $reqname)),
|
||||
@@ -1569,25 +1566,24 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
);
|
||||
|
||||
} else {
|
||||
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge bg-danger text-white');
|
||||
$label = html_writer::span(get_string('dependencymissing', 'core_plugin'), 'badge badge-danger');
|
||||
$label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'),
|
||||
'badge bg-danger text-white');
|
||||
'badge badge-danger');
|
||||
$class = 'requires-failed requires-missing requires-unavailable';
|
||||
}
|
||||
$displayuploadlink = true;
|
||||
|
||||
} else if ($reqinfo->status == $pluginman::REQUIREMENT_STATUS_OUTDATED) {
|
||||
if ($reqinfo->availability == $pluginman::REQUIREMENT_AVAILABLE) {
|
||||
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge bg-warning text-dark');
|
||||
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'),
|
||||
'badge bg-warning text-dark');
|
||||
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-warning');
|
||||
$label .= ' '.html_writer::span(get_string('dependencyavailable', 'core_plugin'), 'badge badge-warning');
|
||||
$class = 'requires-failed requires-outdated requires-available';
|
||||
$displayupdateslink = true;
|
||||
|
||||
} else {
|
||||
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge bg-danger text-white');
|
||||
$label = html_writer::span(get_string('dependencyfails', 'core_plugin'), 'badge badge-danger');
|
||||
$label .= ' '.html_writer::span(get_string('dependencyunavailable', 'core_plugin'),
|
||||
'badge bg-danger text-white');
|
||||
'badge badge-danger');
|
||||
$class = 'requires-failed requires-outdated requires-unavailable';
|
||||
}
|
||||
$displayuploadlink = true;
|
||||
@@ -1697,7 +1693,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
new moodle_url($this->page->url, array('contribonly' => 0, 'updatesonly' => 1)),
|
||||
get_string('overviewupdatable', 'core_plugin'),
|
||||
array('title' => get_string('filterupdatesonly', 'core_plugin'))
|
||||
).' '.html_writer::span($numupdatable, 'badge bg-info text-white number number-updatable');
|
||||
).' '.html_writer::span($numupdatable, 'badge badge-info number number-updatable');
|
||||
} else {
|
||||
// No updates, or the notifications disabled.
|
||||
$infoupdatable = '';
|
||||
@@ -1872,13 +1868,13 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$source = '';
|
||||
} else {
|
||||
$row->attributes['class'] .= ' extension';
|
||||
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge bg-info text-white');
|
||||
$source = html_writer::div(get_string('sourceext', 'core_plugin'), 'source badge badge-info');
|
||||
}
|
||||
|
||||
if ($status === core_plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge bg-danger text-white');
|
||||
$msg = html_writer::div(get_string('status_missing', 'core_plugin'), 'statusmsg badge badge-danger');
|
||||
} else if ($status === core_plugin_manager::PLUGIN_STATUS_NEW) {
|
||||
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge bg-success text-white');
|
||||
$msg = html_writer::div(get_string('status_new', 'core_plugin'), 'statusmsg badge badge-success');
|
||||
} else {
|
||||
$msg = '';
|
||||
}
|
||||
@@ -2055,10 +2051,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
// We are checking installed & enabled things
|
||||
if ($environment_result->getLevel() == 'required') {
|
||||
$stringtouse = 'environmentrequirecustomcheck';
|
||||
} else if ($environment_result->getLevel() == 'optional') {
|
||||
$stringtouse = 'environmentrecommendcustomcheck';
|
||||
} else {
|
||||
$stringtouse = 'environmentshouldfixcustomcheck';
|
||||
$stringtouse = 'environmentrecommendcustomcheck';
|
||||
}
|
||||
|
||||
} else if ($environment_result->getPart() == 'php_setting') {
|
||||
@@ -2089,8 +2083,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
if ($status) { //Handle ok result (ok)
|
||||
$status = get_string('statusok');
|
||||
} else {
|
||||
// Handle check result (warning).
|
||||
if (in_array($environment_result->getLevel(), ['optional', 'recommended'])) {
|
||||
if ($environment_result->getLevel() == 'optional') {//Handle check result (warning)
|
||||
$status = get_string('check');
|
||||
$warningline = true;
|
||||
} else { //Handle error result (error)
|
||||
@@ -2120,13 +2113,13 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
// Format error or warning line
|
||||
if ($errorline) {
|
||||
$messagetype = 'error';
|
||||
$statusclass = 'bg-danger text-white';
|
||||
$statusclass = 'badge-danger';
|
||||
} else if ($warningline) {
|
||||
$messagetype = 'warn';
|
||||
$statusclass = 'bg-warning text-dark';
|
||||
$statusclass = 'badge-warning';
|
||||
} else {
|
||||
$messagetype = 'ok';
|
||||
$statusclass = 'bg-success text-white';
|
||||
$statusclass = 'badge-success';
|
||||
}
|
||||
$status = html_writer::span($status, 'badge ' . $statusclass);
|
||||
// Here we'll store all the feedback found
|
||||
@@ -2210,7 +2203,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$out = format_text(get_string('registerwithmoodleorginfo', 'core_hub'), FORMAT_MARKDOWN);
|
||||
|
||||
$out .= html_writer::link(
|
||||
MOODLE_PRODUCTURL.'/solutions/moodle-app/',
|
||||
new moodle_url('/admin/settings.php', ['section' => 'moodleservices']),
|
||||
$this->output->pix_icon('i/info', '').' '.get_string('registerwithmoodleorginfoapp', 'core_hub'),
|
||||
['class' => 'btn btn-link', 'role' => 'opener', 'target' => '_href']
|
||||
);
|
||||
@@ -2260,15 +2253,4 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
return $this->warning($xmlrpcwarning);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the theme selector list.
|
||||
*
|
||||
* @param core_admin\output\theme_selector $themeselector
|
||||
* @return string HTML
|
||||
*/
|
||||
public function theme_selector_list(core_admin\output\theme_selector $themeselector): string {
|
||||
$renderable = $themeselector->export_for_template($this);
|
||||
return $this->render_from_template('core_admin/themeselector/theme_selector', $renderable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,19 +38,6 @@ if (!is_siteadmin()) {
|
||||
}
|
||||
|
||||
$admisselector = new core_role_admins_existing_selector();
|
||||
|
||||
if (array_key_exists('siteadmins', $CFG->config_php_settings)) {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('manageadmins', 'core_role'), 3);
|
||||
echo $OUTPUT->notification(get_string('siteadministratorsconfigphp', 'core_role'), \core\output\notification::NOTIFY_INFO);
|
||||
echo $OUTPUT->box_start();
|
||||
echo $OUTPUT->paragraph(get_string('existingadmins', 'core_role'));
|
||||
$admisselector->display();
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
}
|
||||
|
||||
$potentialadmisselector = new core_role_admins_potential_selector();
|
||||
|
||||
if ($addusersaction) {
|
||||
|
||||
@@ -99,7 +99,7 @@ abstract class core_role_allow_role_page {
|
||||
* @param int $fromroleid
|
||||
* @param int $targetroleid
|
||||
*/
|
||||
abstract protected function set_allow($fromroleid, $targetroleid);
|
||||
protected abstract function set_allow($fromroleid, $targetroleid);
|
||||
|
||||
/**
|
||||
* Load the current allows from the database.
|
||||
@@ -183,11 +183,11 @@ abstract class core_role_allow_role_page {
|
||||
* Snippet of text displayed above the table, telling the admin what to do.
|
||||
* @return string
|
||||
*/
|
||||
abstract public function get_intro_text();
|
||||
public abstract function get_intro_text();
|
||||
|
||||
/**
|
||||
* Returns the allow class respective event class name.
|
||||
* @return string
|
||||
*/
|
||||
abstract protected function get_eventclass();
|
||||
protected abstract function get_eventclass();
|
||||
}
|
||||
|
||||
@@ -142,12 +142,12 @@ abstract class core_role_capability_table_base {
|
||||
/**
|
||||
* For subclasses to override, output header cells, after the initial capability one.
|
||||
*/
|
||||
abstract protected function add_header_cells();
|
||||
protected abstract function add_header_cells();
|
||||
|
||||
/**
|
||||
* For subclasses to override, return the number of cells that add_header_cells/add_row_cells output.
|
||||
*/
|
||||
abstract protected function num_extra_columns();
|
||||
protected abstract function num_extra_columns();
|
||||
|
||||
/**
|
||||
* For subclasses to override. Allows certain capabilties
|
||||
@@ -191,5 +191,5 @@ abstract class core_role_capability_table_base {
|
||||
* @param stdClass $capability the capability this row relates to.
|
||||
* @return string html of row cells
|
||||
*/
|
||||
abstract protected function add_row_cells($capability);
|
||||
protected abstract function add_row_cells($capability);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected function load_parent_permissions();
|
||||
protected abstract function load_parent_permissions();
|
||||
|
||||
/**
|
||||
* Update $this->permissions based on submitted data, while making a list of
|
||||
@@ -156,7 +156,7 @@ abstract class core_role_capability_table_with_risks extends core_role_capabilit
|
||||
return $rowclasses;
|
||||
}
|
||||
|
||||
abstract protected function add_permission_cells($capability);
|
||||
protected abstract function add_permission_cells($capability);
|
||||
|
||||
protected function add_row_cells($capability) {
|
||||
$cells = $this->add_permission_cells($capability);
|
||||
|
||||
@@ -645,7 +645,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
protected function print_field($name, $caption, $field, $helpicon = null) {
|
||||
global $OUTPUT;
|
||||
// Attempt to generate HTML like formslib.
|
||||
echo '<div class="fitem row mb-3">';
|
||||
echo '<div class="fitem row form-group">';
|
||||
echo '<div class="fitemtitle col-md-3">';
|
||||
if ($name) {
|
||||
echo '<label for="' . $name . '">';
|
||||
@@ -663,7 +663,7 @@ class core_role_define_role_table_advanced extends core_role_capability_table_wi
|
||||
} else {
|
||||
$extraclass = '';
|
||||
}
|
||||
echo '<div class="felement col-md-9 d-flex flex-wrap align-items-center' . $extraclass . '">';
|
||||
echo '<div class="felement col-md-9 form-inline' . $extraclass . '">';
|
||||
echo $field;
|
||||
if (isset($this->errors[$name])) {
|
||||
echo $OUTPUT->error_text($this->errors[$name]);
|
||||
|
||||
@@ -53,7 +53,7 @@ class provider implements
|
||||
* @param collection $collection An object for storing metadata.
|
||||
* @return collection The metadata.
|
||||
*/
|
||||
public static function get_metadata(collection $collection): collection {
|
||||
public static function get_metadata(collection $collection) : collection {
|
||||
$rolecapabilities = [
|
||||
'roleid' => 'privacy:metadata:role_capabilities:roleid',
|
||||
'capability' => 'privacy:metadata:role_capabilities:capability',
|
||||
@@ -100,7 +100,7 @@ class provider implements
|
||||
* @param int $userid The user ID.
|
||||
* @return contextlist The list of context IDs.
|
||||
*/
|
||||
public static function get_contexts_for_userid(int $userid): contextlist {
|
||||
public static function get_contexts_for_userid(int $userid) : contextlist {
|
||||
global $DB;
|
||||
|
||||
$contextlist = new contextlist();
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_role\reportbuilder\datasource;
|
||||
|
||||
use core\reportbuilder\local\entities\context;
|
||||
use core_reportbuilder\datasource;
|
||||
use core_reportbuilder\local\entities\user;
|
||||
use core_role\reportbuilder\local\entities\{role, role_assignment};
|
||||
|
||||
/**
|
||||
* Roles datasource
|
||||
*
|
||||
* @package core_role
|
||||
* @copyright 2024 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class roles extends datasource {
|
||||
|
||||
/**
|
||||
* Return user friendly name of the report source
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name(): string {
|
||||
return get_string('roles', 'core_role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise report
|
||||
*/
|
||||
protected function initialise(): void {
|
||||
$contextentity = new context();
|
||||
$contextalias = $contextentity->get_table_alias('context');
|
||||
|
||||
$roleentity = new role();
|
||||
$rolealias = $roleentity->get_table_alias('role');
|
||||
|
||||
// Role table.
|
||||
$this->add_entity($roleentity->set_table_alias('context', $contextalias));
|
||||
$this->set_main_table('role', $rolealias);
|
||||
|
||||
// Join role assignments.
|
||||
$roleassignmententity = new role_assignment();
|
||||
$roleassignmentalias = $roleassignmententity->get_table_alias('role_assignments');
|
||||
$this->add_entity($roleassignmententity);
|
||||
$this->add_join("JOIN {role_assignments} {$roleassignmentalias} ON {$roleassignmentalias}.roleid = {$rolealias}.id");
|
||||
|
||||
// Join context.
|
||||
$this->add_entity($contextentity);
|
||||
$this->add_join("LEFT JOIN {context} {$contextalias} ON {$contextalias}.id = {$roleassignmentalias}.contextid");
|
||||
|
||||
// Join user.
|
||||
$userentity = new user();
|
||||
$useralias = $userentity->get_table_alias('user');
|
||||
$this->add_entity($userentity
|
||||
->add_join("LEFT JOIN {user} {$useralias} ON {$useralias}.id = {$roleassignmentalias}.userid"));
|
||||
|
||||
$this->add_all_from_entities();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the columns that will be added to the report upon creation
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_default_columns(): array {
|
||||
return [
|
||||
'context:link',
|
||||
'role:originalname',
|
||||
'user:fullnamewithlink',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the column sorting that will be added to the report upon creation
|
||||
*
|
||||
* @return int[]
|
||||
*/
|
||||
public function get_default_column_sorting(): array {
|
||||
return [
|
||||
'context:link' => SORT_ASC,
|
||||
'role:originalname' => SORT_ASC,
|
||||
'user:fullnamewithlink' => SORT_ASC,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the filters that will be added to the report upon creation
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_default_filters(): array {
|
||||
return [
|
||||
'context:level',
|
||||
'role:name',
|
||||
'user:fullname',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the conditions that will be added to the report upon creation
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_default_conditions(): array {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -14,8 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_role\reportbuilder\local\entities;
|
||||
|
||||
use context;
|
||||
@@ -36,14 +34,14 @@ use core_reportbuilder\local\report\{column, filter};
|
||||
class role extends base {
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses
|
||||
* Database tables that this entity uses and their default aliases
|
||||
*
|
||||
* @return string[]
|
||||
* @return array
|
||||
*/
|
||||
protected function get_default_tables(): array {
|
||||
protected function get_default_table_aliases(): array {
|
||||
return [
|
||||
'context',
|
||||
'role',
|
||||
'context' => 'rctx',
|
||||
'role' => 'r',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -99,13 +97,7 @@ class role extends base {
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.name, {$rolealias}.shortname, {$rolealias}.id, {$contextalias}.id AS contextid")
|
||||
->add_fields(context_helper::get_preload_record_columns_sql($contextalias))
|
||||
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
|
||||
->set_is_sortable(true, [
|
||||
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
|
||||
THEN {$rolealias}.shortname
|
||||
ELSE {$rolealias}.name
|
||||
END",
|
||||
])
|
||||
->set_is_sortable(true, ["CASE WHEN {$rolealias}.name = '' THEN {$rolealias}.shortname ELSE {$rolealias}.name END"])
|
||||
->set_callback(static function($name, stdClass $role): string {
|
||||
if ($name === null) {
|
||||
return '';
|
||||
@@ -117,30 +109,6 @@ class role extends base {
|
||||
return role_get_name($role, $context, ROLENAME_BOTH);
|
||||
});
|
||||
|
||||
// Original name column.
|
||||
$columns[] = (new column(
|
||||
'originalname',
|
||||
new lang_string('roleoriginalname', 'core_role'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_fields("{$rolealias}.name, {$rolealias}.shortname")
|
||||
// The sorting is on name, unless empty (determined by single space - thanks Oracle) then we use shortname.
|
||||
->set_is_sortable(true, [
|
||||
"CASE WHEN " . $DB->sql_concat("{$rolealias}.name", "' '") . " = ' '
|
||||
THEN {$rolealias}.shortname
|
||||
ELSE {$rolealias}.name
|
||||
END",
|
||||
])
|
||||
->set_callback(static function($name, stdClass $role): string {
|
||||
if ($name === null) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return role_get_name($role, null, ROLENAME_ORIGINAL);
|
||||
});
|
||||
|
||||
// Short name column.
|
||||
$columns[] = (new column(
|
||||
'shortname',
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_role\reportbuilder\local\entities;
|
||||
|
||||
use lang_string;
|
||||
use core_reportbuilder\local\entities\base;
|
||||
use core_reportbuilder\local\filters\date;
|
||||
use core_reportbuilder\local\helpers\format;
|
||||
use core_reportbuilder\local\report\{column, filter};
|
||||
|
||||
/**
|
||||
* Role assignment entity
|
||||
*
|
||||
* @package core_role
|
||||
* @copyright 2024 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class role_assignment extends base {
|
||||
|
||||
/**
|
||||
* Database tables that this entity uses
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
protected function get_default_tables(): array {
|
||||
return [
|
||||
'role_assignments',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* The default title for this entity
|
||||
*
|
||||
* @return lang_string
|
||||
*/
|
||||
protected function get_default_entity_title(): lang_string {
|
||||
return new lang_string('roleassignment', 'core_role');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialise the entity
|
||||
*
|
||||
* @return base
|
||||
*/
|
||||
public function initialise(): base {
|
||||
$columns = $this->get_all_columns();
|
||||
foreach ($columns as $column) {
|
||||
$this->add_column($column);
|
||||
}
|
||||
|
||||
// All the filters defined by the entity can also be used as conditions.
|
||||
$filters = $this->get_all_filters();
|
||||
foreach ($filters as $filter) {
|
||||
$this
|
||||
->add_filter($filter)
|
||||
->add_condition($filter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of all available columns
|
||||
*
|
||||
* @return column[]
|
||||
*/
|
||||
protected function get_all_columns(): array {
|
||||
$raalias = $this->get_table_alias('role_assignments');
|
||||
|
||||
// Time modified column.
|
||||
$columns[] = (new column(
|
||||
'timemodified',
|
||||
new lang_string('timemodified', 'core_reportbuilder'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TIMESTAMP)
|
||||
->add_field("{$raalias}.timemodified")
|
||||
->set_is_sortable(true)
|
||||
->set_callback([format::class, 'userdate']);
|
||||
|
||||
// Component column.
|
||||
$columns[] = (new column(
|
||||
'component',
|
||||
new lang_string('plugin'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_TEXT)
|
||||
->add_field("{$raalias}.component")
|
||||
->set_is_sortable(true);
|
||||
|
||||
// Item ID column.
|
||||
$columns[] = (new column(
|
||||
'itemid',
|
||||
new lang_string('pluginitemid'),
|
||||
$this->get_entity_name()
|
||||
))
|
||||
->add_joins($this->get_joins())
|
||||
->set_type(column::TYPE_INTEGER)
|
||||
->add_field("{$raalias}.itemid")
|
||||
->set_is_sortable(true);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of all available filters
|
||||
*
|
||||
* @return filter[]
|
||||
*/
|
||||
protected function get_all_filters(): array {
|
||||
$raalias = $this->get_table_alias('role_assignments');
|
||||
|
||||
// Time modified filter.
|
||||
$filters[] = (new filter(
|
||||
date::class,
|
||||
'timemodified',
|
||||
new lang_string('timemodified', 'core_reportbuilder'),
|
||||
$this->get_entity_name(),
|
||||
"{$raalias}.timemodified"
|
||||
))
|
||||
->add_joins($this->get_joins());
|
||||
|
||||
return $filters;
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ M.core_role.init_cap_table_filter = function(Y, tableid, contextid) {
|
||||
this.table = Y.one('#'+this.tableid);
|
||||
|
||||
// Create a div to hold the search UI.
|
||||
this.div = Y.Node.create('<div class="capabilitysearchui d-flex flex-wrap align-items-center"></div>').setStyles({
|
||||
this.div = Y.Node.create('<div class="capabilitysearchui form-inline"></div>').setStyles({
|
||||
width : this.table.get('offsetWidth'),
|
||||
marginLeft : 'auto',
|
||||
marginRight : 'auto'
|
||||
|
||||
@@ -27,7 +27,7 @@ use core_role_preset;
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class preset_test extends \advanced_testcase {
|
||||
public function test_xml(): void {
|
||||
public function test_xml() {
|
||||
global $DB;
|
||||
|
||||
$roles = $DB->get_records('role');
|
||||
@@ -81,7 +81,7 @@ class preset_test extends \advanced_testcase {
|
||||
* Tests covered method.
|
||||
* @covers \core_role_preset::parse_preset
|
||||
*/
|
||||
public function test_mixed_levels(): void {
|
||||
public function test_mixed_levels() {
|
||||
// The problem here is that we cannot guarantee plugin contexts
|
||||
// have unique short names, so we have to also support level numbers.
|
||||
$xml = file_get_contents(__DIR__ . '/fixtures/mixed_levels.xml');
|
||||
|
||||
@@ -45,7 +45,7 @@ class provider_test extends provider_testcase {
|
||||
* Test to check export_user_preferences.
|
||||
* returns user preferences data.
|
||||
*/
|
||||
public function test_export_user_preferences(): void {
|
||||
public function test_export_user_preferences() {
|
||||
$this->resetAfterTest();
|
||||
$this->setAdminUser();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
@@ -64,7 +64,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Check all contexts are returned if there is any user data for this user.
|
||||
*/
|
||||
public function test_get_contexts_for_userid(): void {
|
||||
public function test_get_contexts_for_userid() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -114,7 +114,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test that user data is exported correctly.
|
||||
*/
|
||||
public function test_export_user_data(): void {
|
||||
public function test_export_user_data() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -243,7 +243,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test for provider::delete_data_for_all_users_in_context().
|
||||
*/
|
||||
public function test_delete_data_for_all_users_in_context(): void {
|
||||
public function test_delete_data_for_all_users_in_context() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -329,7 +329,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test for provider::delete_data_for_user().
|
||||
*/
|
||||
public function test_delete_data_for_user(): void {
|
||||
public function test_delete_data_for_user() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -387,7 +387,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Export for a user with a key against a script where no instance is specified.
|
||||
*/
|
||||
public function test_export_user_role_to_cohort(): void {
|
||||
public function test_export_user_role_to_cohort() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -443,7 +443,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test for provider::delete_user_role_to_cohort().
|
||||
*/
|
||||
public function test_delete_user_role_to_cohort(): void {
|
||||
public function test_delete_user_role_to_cohort() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -478,7 +478,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test that only users within a course context are fetched.
|
||||
*/
|
||||
public function test_get_users_in_context(): void {
|
||||
public function test_get_users_in_context() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
@@ -599,7 +599,7 @@ class provider_test extends provider_testcase {
|
||||
/**
|
||||
* Test that data for users in approved userlist is deleted.
|
||||
*/
|
||||
public function test_delete_data_for_users(): void {
|
||||
public function test_delete_data_for_users() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_role\reportbuilder\datasource;
|
||||
|
||||
use core\context\course;
|
||||
use core_reportbuilder_generator;
|
||||
use core_reportbuilder_testcase;
|
||||
use core_reportbuilder\local\filters\{date, select, text};
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
|
||||
|
||||
/**
|
||||
* Unit tests for roles datasource
|
||||
*
|
||||
* @package core_role
|
||||
* @covers \core_role\reportbuilder\datasource\roles;
|
||||
* @copyright 2024 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
final class roles_test extends core_reportbuilder_testcase {
|
||||
|
||||
/**
|
||||
* Test default datasource
|
||||
*/
|
||||
public function test_datasource_default(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$context = course::instance($course->id);
|
||||
|
||||
$studentone = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
|
||||
$studenttwo = $this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Amy']);
|
||||
$manager = $this->getDataGenerator()->create_and_enrol($course, 'manager');
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Roles', 'source' => roles::class, 'default' => 1]);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
$this->assertCount(3, $content);
|
||||
|
||||
// Default columns are context link, original role name and user link. Sorted by each.
|
||||
[$contextlink, $rolename, $userlink] = array_values($content[0]);
|
||||
$this->assertStringContainsString($context->get_context_name(), $contextlink);
|
||||
$this->assertEquals('Manager', $rolename);
|
||||
$this->assertStringContainsString(fullname($manager), $userlink);
|
||||
|
||||
[$contextlink, $rolename, $userlink] = array_values($content[1]);
|
||||
$this->assertStringContainsString($context->get_context_name(), $contextlink);
|
||||
$this->assertEquals('Student', $rolename);
|
||||
$this->assertStringContainsString(fullname($studenttwo), $userlink);
|
||||
|
||||
[$contextlink, $rolename, $userlink] = array_values($content[2]);
|
||||
$this->assertStringContainsString($context->get_context_name(), $contextlink);
|
||||
$this->assertEquals('Student', $rolename);
|
||||
$this->assertStringContainsString(fullname($studentone), $userlink);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test datasource columns that aren't added by default
|
||||
*/
|
||||
public function test_datasource_non_default_columns(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$context = course::instance($course->id);
|
||||
|
||||
// Create an alias for our role.
|
||||
$roleid = $DB->get_field('role', 'id', ['shortname' => 'manager']);
|
||||
$DB->insert_record('role_names', (object) [
|
||||
'contextid' => $context->id,
|
||||
'roleid' => $roleid,
|
||||
'name' => 'Moocher',
|
||||
]);
|
||||
|
||||
$manager = $this->getDataGenerator()->create_user();
|
||||
$this->getDataGenerator()->enrol_user($manager->id, $course->id, $roleid);
|
||||
|
||||
/** @var core_reportbuilder_generator $generator */
|
||||
$generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
|
||||
$report = $generator->create_report(['name' => 'Roles', 'source' => roles::class, 'default' => 0]);
|
||||
|
||||
// Role.
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:name']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:shortname']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:description']);
|
||||
|
||||
// Role assignment.
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role_assignment:timemodified']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role_assignment:component']);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role_assignment:itemid']);
|
||||
|
||||
$content = $this->get_custom_report_content($report->get('id'));
|
||||
$this->assertCount(1, $content);
|
||||
|
||||
[$rolename, $roleshortname, $roledescription, $timemodified, $component, $itemid] = array_values($content[0]);
|
||||
|
||||
// Role.
|
||||
$this->assertEquals('Moocher (Manager)', $rolename);
|
||||
$this->assertEquals('manager', $roleshortname);
|
||||
$this->assertEquals('Managers can access courses and modify them, but usually do not participate in them.',
|
||||
$roledescription);
|
||||
|
||||
// Role assignment.
|
||||
$this->assertNotEmpty($timemodified);
|
||||
$this->assertEquals('', $component);
|
||||
$this->assertEquals(0, $itemid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for {@see test_datasource_filters}
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public static function datasource_filters_provider(): array {
|
||||
global $DB;
|
||||
|
||||
return [
|
||||
// Role.
|
||||
'Filter role name' => ['role:name', [
|
||||
'role:name_operator' => select::EQUAL_TO,
|
||||
'role:name_value' => $DB->get_field('role', 'id', ['shortname' => 'student']),
|
||||
], true],
|
||||
'Filter role name (no match)' => ['role:name', [
|
||||
'role:name_operator' => select::EQUAL_TO,
|
||||
'role:name_value' => -1,
|
||||
], false],
|
||||
|
||||
// Role assignment.
|
||||
'Filter role assignment time modified' => ['role_assignment:timemodified', [
|
||||
'role_assignment:timemodified_operator' => date::DATE_RANGE,
|
||||
'role_assignment:timemodified_from' => 1622502000,
|
||||
], true],
|
||||
'Filter role assignment time modified (no match)' => ['role_assignment:timemodified', [
|
||||
'role_assignment:timemodified_operator' => date::DATE_RANGE,
|
||||
'role_assignment:timemodified_to' => 1622502000,
|
||||
], false],
|
||||
|
||||
// Context.
|
||||
'Filter context level' => ['context:level', [
|
||||
'context:level_operator' => select::EQUAL_TO,
|
||||
'context:level_value' => CONTEXT_COURSE,
|
||||
], true],
|
||||
'Filter context level (no match)' => ['context:level', [
|
||||
'context:level_operator' => select::EQUAL_TO,
|
||||
'context:level_value' => CONTEXT_COURSECAT,
|
||||
], false],
|
||||
|
||||
// User.
|
||||
'Filter user firstname' => ['user:firstname', [
|
||||
'user:firstname_operator' => text::IS_EQUAL_TO,
|
||||
'user:firstname_value' => 'Zoe',
|
||||
], true],
|
||||
'Filter user firstname (no match)' => ['user:firstname', [
|
||||
'user:firstname_operator' => text::IS_EQUAL_TO,
|
||||
'user:firstname_value' => 'Amy',
|
||||
], 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();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->create_and_enrol($course, 'student', ['firstname' => 'Zoe']);
|
||||
|
||||
/** @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' => 'Roles', 'source' => roles::class, 'default' => 0]);
|
||||
$generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'role:shortname']);
|
||||
|
||||
// Add filter, set it's values.
|
||||
$generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
|
||||
$content = $this->get_custom_report_content($report->get('id'), 0, $filtervalues);
|
||||
|
||||
if ($expectmatch) {
|
||||
$this->assertCount(1, $content);
|
||||
$this->assertEquals('student', reset($content[0]));
|
||||
} else {
|
||||
$this->assertEmpty($content);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stress test datasource
|
||||
*
|
||||
* In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
|
||||
*/
|
||||
public function test_stress_datasource(): void {
|
||||
if (!PHPUNIT_LONGTEST) {
|
||||
$this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
|
||||
}
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
$this->getDataGenerator()->create_and_enrol($course);
|
||||
|
||||
$this->datasource_stress_test_columns(roles::class);
|
||||
$this->datasource_stress_test_columns_aggregation(roles::class);
|
||||
$this->datasource_stress_test_conditions(roles::class, 'role:shortname');
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,59 @@ $capabilities = array(
|
||||
);
|
||||
|
||||
if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // speedup for non-admins, add all caps used on this page
|
||||
|
||||
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themes')));
|
||||
// "themesettings" settingpage
|
||||
$temp = new admin_settingpage('themesettings', new lang_string('themesettings', 'admin'));
|
||||
$setting = new admin_setting_configtext('themelist', new lang_string('themelist', 'admin'),
|
||||
new lang_string('configthemelist', 'admin'), '', PARAM_NOTAGS);
|
||||
$setting->set_force_ltr(true);
|
||||
$temp->add($setting);
|
||||
$setting = new admin_setting_configcheckbox('themedesignermode', new lang_string('themedesignermode', 'admin'), new lang_string('configthemedesignermode', 'admin'), 0);
|
||||
$setting->set_updatedcallback('theme_reset_all_caches');
|
||||
$temp->add($setting);
|
||||
$temp->add(new admin_setting_configcheckbox('allowuserthemes', new lang_string('allowuserthemes', 'admin'), new lang_string('configallowuserthemes', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowcoursethemes', new lang_string('allowcoursethemes', 'admin'), new lang_string('configallowcoursethemes', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowcategorythemes', new lang_string('allowcategorythemes', 'admin'), new lang_string('configallowcategorythemes', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowcohortthemes', new lang_string('allowcohortthemes', 'admin'), new lang_string('configallowcohortthemes', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowthemechangeonurl', new lang_string('allowthemechangeonurl', 'admin'), new lang_string('configallowthemechangeonurl', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'), new lang_string('configallowuserblockhiding', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('langmenuinsecurelayout',
|
||||
new lang_string('langmenuinsecurelayout', 'admin'),
|
||||
new lang_string('langmenuinsecurelayout_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('logininfoinsecurelayout',
|
||||
new lang_string('logininfoinsecurelayout', 'admin'),
|
||||
new lang_string('logininfoinsecurelayout_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'),
|
||||
new lang_string('configcustommenuitems', 'admin'), '', PARAM_RAW, '50', '10'));
|
||||
$temp->add(new admin_setting_configtextarea(
|
||||
'customusermenuitems',
|
||||
new lang_string('customusermenuitems', 'admin'),
|
||||
new lang_string('configcustomusermenuitems', 'admin'),
|
||||
'profile,moodle|/user/profile.php
|
||||
grades,grades|/grade/report/mygrades.php
|
||||
calendar,core_calendar|/calendar/view.php?view=month
|
||||
privatefiles,moodle|/user/files.php
|
||||
reports,core_reportbuilder|/reportbuilder/index.php',
|
||||
PARAM_RAW,
|
||||
'50',
|
||||
'10'
|
||||
));
|
||||
$ADMIN->add('themes', $temp);
|
||||
$ADMIN->add('themes', new admin_externalpage('themeselector', new lang_string('themeselector','admin'), $CFG->wwwroot . '/theme/index.php'));
|
||||
|
||||
// settings for each theme
|
||||
foreach (core_component::get_plugin_list('theme') as $theme => $themedir) {
|
||||
$settings_path = "$themedir/settings.php";
|
||||
if (file_exists($settings_path)) {
|
||||
$settings = new admin_settingpage('themesetting'.$theme, new lang_string('pluginname', 'theme_'.$theme));
|
||||
include($settings_path);
|
||||
if ($settings) {
|
||||
$ADMIN->add('themes', $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logos section.
|
||||
$temp = new admin_settingpage('logos', new lang_string('logossettings', 'admin'));
|
||||
|
||||
@@ -181,6 +234,7 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
new lang_string('confignavcourselimit', 'admin'), 10, PARAM_INT));
|
||||
$temp->add(new admin_setting_configcheckbox('usesitenameforsitepages', new lang_string('usesitenameforsitepages', 'admin'), new lang_string('configusesitenameforsitepages', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('linkadmincategories', new lang_string('linkadmincategories', 'admin'), new lang_string('linkadmincategories_help', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('linkcoursesections', new lang_string('linkcoursesections', 'admin'), new lang_string('linkcoursesections_help', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('navshowfrontpagemods', new lang_string('navshowfrontpagemods', 'admin'), new lang_string('navshowfrontpagemods_help', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('navadduserpostslinks', new lang_string('navadduserpostslinks', 'admin'), new lang_string('navadduserpostslinks_help', 'admin'), 1));
|
||||
|
||||
@@ -282,85 +336,4 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
$temp = new admin_settingpage('templates', new lang_string('templates', 'admin'));
|
||||
$temp->add($setting);
|
||||
$ADMIN->add('appearance', $temp);
|
||||
|
||||
// Advanced theme settings page.
|
||||
$temp = new admin_settingpage('themesettingsadvanced', new lang_string('themesettingsadvanced', 'admin'));
|
||||
$setting = new admin_setting_configtext('themelist', new lang_string('themelist', 'admin'),
|
||||
new lang_string('configthemelist', 'admin'), '', PARAM_NOTAGS);
|
||||
$setting->set_force_ltr(true);
|
||||
$temp->add($setting);
|
||||
$setting = new admin_setting_configcheckbox('themedesignermode', new lang_string('themedesignermode', 'admin'),
|
||||
new lang_string('configthemedesignermode', 'admin'), 0);
|
||||
$setting->set_updatedcallback('theme_reset_all_caches');
|
||||
$temp->add($setting);
|
||||
|
||||
$setting = new admin_setting_configcheckbox('allowuserthemes', new lang_string('allowuserthemes', 'admin'),
|
||||
new lang_string('configallowuserthemes', 'admin'), 0);
|
||||
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
|
||||
$temp->add($setting);
|
||||
|
||||
$setting = new admin_setting_configcheckbox('allowcoursethemes', new lang_string('allowcoursethemes', 'admin'),
|
||||
new lang_string('configallowcoursethemes', 'admin'), 0);
|
||||
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
|
||||
$temp->add($setting);
|
||||
|
||||
$setting = new admin_setting_configcheckbox('allowcategorythemes', new lang_string('allowcategorythemes', 'admin'),
|
||||
new lang_string('configallowcategorythemes', 'admin'), 0);
|
||||
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
|
||||
$temp->add($setting);
|
||||
|
||||
$setting = new admin_setting_configcheckbox('allowcohortthemes', new lang_string('allowcohortthemes', 'admin'),
|
||||
new lang_string('configallowcohortthemes', 'admin'), 0);
|
||||
$setting->set_updatedcallback('theme_purge_used_in_context_caches');
|
||||
$temp->add($setting);
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('allowthemechangeonurl', new lang_string('allowthemechangeonurl', 'admin'),
|
||||
new lang_string('configallowthemechangeonurl', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'),
|
||||
new lang_string('configallowuserblockhiding', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('langmenuinsecurelayout',
|
||||
new lang_string('langmenuinsecurelayout', 'admin'),
|
||||
new lang_string('langmenuinsecurelayout_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('logininfoinsecurelayout',
|
||||
new lang_string('logininfoinsecurelayout', 'admin'),
|
||||
new lang_string('logininfoinsecurelayout_desc', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'),
|
||||
new lang_string('configcustommenuitems', 'admin'), '', PARAM_RAW, '50', '10'));
|
||||
$defaultsettingcustomusermenuitems = [
|
||||
'profile,moodle|/user/profile.php',
|
||||
'grades,grades|/grade/report/mygrades.php',
|
||||
'calendar,core_calendar|/calendar/view.php?view=month',
|
||||
'privatefiles,moodle|/user/files.php',
|
||||
'reports,core_reportbuilder|/reportbuilder/index.php',
|
||||
];
|
||||
$temp->add(new admin_setting_configtextarea(
|
||||
'customusermenuitems',
|
||||
new lang_string('customusermenuitems', 'admin'),
|
||||
new lang_string('configcustomusermenuitems', 'admin'),
|
||||
implode("\n", $defaultsettingcustomusermenuitems),
|
||||
PARAM_RAW,
|
||||
'50',
|
||||
'10'
|
||||
));
|
||||
$ADMIN->add('appearance', $temp);
|
||||
|
||||
// Theme selector page.
|
||||
$ADMIN->add('appearance', new admin_externalpage('themeselector',
|
||||
new lang_string('themeselector', 'admin'), $CFG->wwwroot . '/admin/themeselector.php'));
|
||||
|
||||
// Settings page for each theme.
|
||||
$ADMIN->add('appearance', new admin_category('themes', new lang_string('themesettingscustom', 'admin')));
|
||||
foreach (core_component::get_plugin_list('theme') as $theme => $themedir) {
|
||||
$settingspath = "$themedir/settings.php";
|
||||
if (file_exists($settingspath)) {
|
||||
$settings = new admin_settingpage("themesetting$theme", new lang_string('pluginname', "theme_$theme"),
|
||||
'moodle/site:config', true
|
||||
);
|
||||
include($settingspath);
|
||||
// Add settings if not hidden (to avoid displaying the section if it appears empty in the UI).
|
||||
if ($settings && !$settings->hidden) {
|
||||
$ADMIN->add('themes', $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end of speedup
|
||||
|
||||
@@ -727,12 +727,12 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
$temp = new admin_settingpage('asyncgeneralsettings', new lang_string('asyncgeneralsettings', 'backup'));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('enableasyncbackup', new lang_string('enableasyncbackup', 'backup'),
|
||||
new lang_string('enableasyncbackup_help', 'backup'), 1, 1, 0));
|
||||
new lang_string('enableasyncbackup_help', 'backup'), 0, 1, 0));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox(
|
||||
'backup/backup_async_message_users',
|
||||
new lang_string('asyncemailenable', 'backup'),
|
||||
new lang_string('asyncemailenabledetail', 'backup'), 1));
|
||||
new lang_string('asyncemailenabledetail', 'backup'), 0));
|
||||
$temp->hide_if('backup/backup_async_message_users', 'enableasyncbackup');
|
||||
|
||||
$temp->add(new admin_setting_configtext(
|
||||
|
||||
@@ -74,8 +74,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
$temp->add(new admin_setting_special_gradeexport());
|
||||
|
||||
$temp->add(new admin_setting_special_gradeexportdefault());
|
||||
|
||||
$temp->add(new admin_setting_special_gradelimiting());
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('grade_report_showmin',
|
||||
@@ -115,7 +113,7 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
$defaultvisible = array(GRADE_AGGREGATE_SUM);
|
||||
|
||||
$defaults = array('value' => GRADE_AGGREGATE_SUM, 'forced' => false);
|
||||
$defaults = array('value' => GRADE_AGGREGATE_SUM, 'forced' => false, 'adv' => false);
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregation', new lang_string('aggregation', 'grades'), new lang_string('aggregation_help', 'grades'), $defaults, $options));
|
||||
|
||||
$temp->add(new admin_setting_configmultiselect('grade_aggregations_visible', new lang_string('aggregationsvisible', 'grades'),
|
||||
@@ -123,10 +121,10 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
$options = array(0 => new lang_string('no'), 1 => new lang_string('yes'));
|
||||
|
||||
$defaults = array('value' => 1, 'forced' => false);
|
||||
$defaults = array('value'=>1, 'forced'=>false, 'adv'=>true);
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregateonlygraded', new lang_string('aggregateonlygraded', 'grades'),
|
||||
new lang_string('aggregateonlygraded_help', 'grades'), $defaults, $options));
|
||||
$defaults = array('value' => 0, 'forced' => false);
|
||||
$defaults = array('value'=>0, 'forced'=>false, 'adv'=>true);
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregateoutcomes', new lang_string('aggregateoutcomes', 'grades'),
|
||||
new lang_string('aggregateoutcomes_help', 'grades'), $defaults, $options));
|
||||
|
||||
@@ -163,6 +161,26 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
'3' => '3',
|
||||
'4' => '4',
|
||||
'5' => '5')));
|
||||
|
||||
$temp->add(new admin_setting_configmultiselect('grade_item_advanced', new lang_string('gradeitemadvanced', 'grades'), new lang_string('gradeitemadvanced_help', 'grades'),
|
||||
array('iteminfo', 'idnumber', 'gradepass', 'plusfactor', 'multfactor', 'display', 'decimals', 'hiddenuntil', 'locktime'),
|
||||
array('iteminfo' => new lang_string('iteminfo', 'grades'),
|
||||
'idnumber' => new lang_string('idnumbermod'),
|
||||
'gradetype' => new lang_string('gradetype', 'grades'),
|
||||
'scaleid' => new lang_string('scale'),
|
||||
'grademin' => new lang_string('grademin', 'grades'),
|
||||
'grademax' => new lang_string('grademax', 'grades'),
|
||||
'gradepass' => new lang_string('gradepass', 'grades'),
|
||||
'plusfactor' => new lang_string('plusfactor', 'grades'),
|
||||
'multfactor' => new lang_string('multfactor', 'grades'),
|
||||
'display' => new lang_string('gradedisplaytype', 'grades'),
|
||||
'decimals' => new lang_string('decimalpoints', 'grades'),
|
||||
'hidden' => new lang_string('hidden', 'grades'),
|
||||
'hiddenuntil' => new lang_string('hiddenuntil', 'grades'),
|
||||
'locked' => new lang_string('locked', 'grades'),
|
||||
'locktime' => new lang_string('locktime', 'grades'),
|
||||
'aggregationcoef' => new lang_string('aggregationcoef', 'grades'),
|
||||
'parentcategory' => new lang_string('parentcategory', 'grades'))));
|
||||
}
|
||||
$ADMIN->add('grades', $temp);
|
||||
|
||||
|
||||
@@ -41,18 +41,4 @@ if (!empty($defaulth5plib)) {
|
||||
|
||||
$settings->add(new admin_settings_h5plib_handler_select('h5plibraryhandler', new lang_string('h5plibraryhandler', 'core_h5p'),
|
||||
new lang_string('h5plibraryhandler_help', 'core_h5p'), $defaulth5plib));
|
||||
|
||||
$setting = new admin_setting_configtextarea(
|
||||
'core_h5p/h5pcustomcss',
|
||||
new lang_string('h5pcustomcss', 'core_h5p'),
|
||||
new lang_string('h5pcustomcss_help', 'core_h5p'),
|
||||
'',
|
||||
PARAM_NOTAGS
|
||||
);
|
||||
$setting->set_updatedcallback(function () {
|
||||
// Enables use of file_storage constants.
|
||||
\core_h5p\local\library\autoloader::register();
|
||||
\core_h5p\file_storage::generate_custom_styles();
|
||||
});
|
||||
$settings->add($setting);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file gives information about Moodle Services
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2018 Amaia Anabitarte <amaia@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
if ($hassiteconfig) {
|
||||
|
||||
// Create Moodle Services information.
|
||||
$moodleservices->add(new admin_setting_heading('moodleservicesintro', '',
|
||||
new lang_string('moodleservices_help', 'admin')));
|
||||
|
||||
// Moodle Partners information.
|
||||
if (empty($CFG->disableserviceads_partner)) {
|
||||
$moodleservices->add(new admin_setting_heading('moodlepartners',
|
||||
new lang_string('moodlepartners', 'admin'),
|
||||
new lang_string('moodlepartners_help', 'admin')));
|
||||
}
|
||||
|
||||
// Moodle app information.
|
||||
$moodleservices->add(new admin_setting_heading('moodleapp',
|
||||
new lang_string('moodleapp', 'admin'),
|
||||
new lang_string('moodleapp_help', 'admin')));
|
||||
|
||||
// Branded Moodle app information.
|
||||
if (empty($CFG->disableserviceads_branded)) {
|
||||
$moodleservices->add(new admin_setting_heading('moodlebrandedapp',
|
||||
new lang_string('moodlebrandedapp', 'admin'),
|
||||
new lang_string('moodlebrandedapp_help', 'admin')));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -135,18 +135,6 @@ if ($hassiteconfig) {
|
||||
$temp->add($setting);
|
||||
$ADMIN->add('authsettings', $temp);
|
||||
|
||||
// Toggle password visiblity icon.
|
||||
$temp->add(new admin_setting_configselect('loginpasswordtoggle',
|
||||
new lang_string('auth_loginpasswordtoggle', 'auth'),
|
||||
new lang_string('auth_loginpasswordtoggle_desc', 'auth'),
|
||||
TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY,
|
||||
[
|
||||
TOGGLE_SENSITIVE_DISABLED => get_string('disabled', 'admin'),
|
||||
TOGGLE_SENSITIVE_ENABLED => get_string('enabled', 'admin'),
|
||||
TOGGLE_SENSITIVE_SMALL_SCREENS_ONLY => get_string('smallscreensonly', 'admin'),
|
||||
],
|
||||
));
|
||||
|
||||
$temp = new admin_externalpage('authtestsettings', get_string('testsettings', 'core_auth'), new moodle_url("/auth/test_settings.php"), 'moodle/site:config', true);
|
||||
$ADMIN->add('authsettings', $temp);
|
||||
|
||||
@@ -196,10 +184,6 @@ if ($hassiteconfig) {
|
||||
$temp = new admin_settingpage('manageantiviruses', new lang_string('antivirussettings', 'antivirus'));
|
||||
$temp->add(new admin_setting_manageantiviruses());
|
||||
|
||||
// Status check.
|
||||
$temp->add(new admin_setting_heading('antivirus/statuschecks', new lang_string('statuschecks'), ''));
|
||||
$temp->add(new admin_setting_check('antivirus/checkantivirus', new \core\check\environment\antivirus()));
|
||||
|
||||
// Common settings.
|
||||
$temp->add(new admin_setting_heading('antiviruscommonsettings', new lang_string('antiviruscommonsettings', 'antivirus'), ''));
|
||||
|
||||
|
||||
@@ -152,9 +152,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$sensiblesettingsdefault .= 'server_password@@search_solr, ssl_keypassword@@search_solr, ';
|
||||
$sensiblesettingsdefault .= 'alternateserver_password@@search_solr, alternatessl_keypassword@@search_solr, ';
|
||||
$sensiblesettingsdefault .= 'test_password@@cachestore_redis, password@@mlbackend_python, ';
|
||||
$sensiblesettingsdefault .= 'badges_badgesalt@@none, calendar_exportsalt@@none, ';
|
||||
$sensiblesettingsdefault .= 'bigbluebuttonbn_shared_secret@@none, apikey@@tiny_premium, ';
|
||||
$sensiblesettingsdefault .= 'matrixaccesstoken@@communication_matrix, api_secret@@factor_sms';
|
||||
$sensiblesettingsdefault .= 'badges_badgesalt@@none, calendar_exportsalt@@none';
|
||||
$temp->add(new admin_setting_configtextarea('adminpresets/sensiblesettings',
|
||||
get_string('sensiblesettings', 'core_adminpresets'),
|
||||
get_string('sensiblesettingstext', 'core_adminpresets'),
|
||||
|
||||
@@ -390,17 +390,6 @@ if ($hassiteconfig) {
|
||||
30 * MINSECS
|
||||
)
|
||||
);
|
||||
|
||||
$temp->add(
|
||||
new admin_setting_configduration(
|
||||
'task_adhoc_failed_retention',
|
||||
new lang_string('task_adhoc_failed_retention', 'admin'),
|
||||
new lang_string('task_adhoc_failed_retention_desc', 'admin'),
|
||||
\core\task\manager::ADHOC_TASK_FAILED_RETENTION,
|
||||
WEEKSECS
|
||||
)
|
||||
);
|
||||
|
||||
$ADMIN->add('taskconfig', $temp);
|
||||
|
||||
// Task log configuration.
|
||||
|
||||
@@ -14,6 +14,12 @@ $ADMIN->add('root', new admin_externalpage('registrationmoodleorg', new lang_str
|
||||
new moodle_url("/admin/registration/index.php")));
|
||||
// hidden upgrade script
|
||||
$ADMIN->add('root', new admin_externalpage('upgradesettings', new lang_string('upgradesettings', 'admin'), "$CFG->wwwroot/$CFG->admin/upgradesettings.php", 'moodle/site:config', true));
|
||||
|
||||
// Adding Moodle Services information page.
|
||||
$moodleservices = new admin_settingpage('moodleservices', new lang_string('moodleservices',
|
||||
'admin'));
|
||||
$ADMIN->add('root', $moodleservices);
|
||||
|
||||
$userfeedback = new admin_settingpage('userfeedback', new lang_string('feedbacksettings', 'admin'));
|
||||
$ADMIN->add('root', $userfeedback);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
}
|
||||
}}
|
||||
<div class="simplesearchform d-flex justify-content-end">
|
||||
<form autocomplete="off" action="{{action}}" method="get" accept-charset="utf-8" class="mform d-flex flex-wrap align-items-center simplesearchform">
|
||||
<form autocomplete="off" action="{{action}}" method="get" accept-charset="utf-8" class="mform form-inline simplesearchform">
|
||||
<div class="input-group">
|
||||
<label for="searchinput-{{uniqid}}">
|
||||
<span class="sr-only">{{#str}} search, core {{/str}}</span>
|
||||
|
||||
@@ -38,6 +38,6 @@
|
||||
}
|
||||
}}
|
||||
<div class="form-checkbox defaultsnext">
|
||||
{{^readonly}}<input type="hidden" name="{{name}}" value="{{no}}">{{/readonly}}
|
||||
<input type="hidden" name="{{name}}" value="{{no}}">
|
||||
<input {{#readonly}}disabled{{/readonly}} type="checkbox" name="{{name}}" value="{{value}}" id="{{id}}" {{#checked}}checked{{/checked}}>
|
||||
</div>
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
Setting configduration.
|
||||
}}
|
||||
<div class="form-duration defaultsnext">
|
||||
<div class="d-flex flex-wrap align-items-center">
|
||||
<div class="form-inline">
|
||||
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
|
||||
<label class="sr-only" for="{{id}}u">{{#str}}durationunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
Setting configfile.
|
||||
}}
|
||||
<div class="form-file defaultsnext">
|
||||
<div class="d-flex flex-wrap align-items-center">
|
||||
<div class="form-inline">
|
||||
<input type="text" name="{{name}}" id="{{id}}" size="{{size}}" value="{{value}}" class="form-control text-ltr" {{#readonly}}readonly{{/readonly}}>
|
||||
{{#showvalidity}}
|
||||
{{#valid}}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
Setting configfilesize.
|
||||
}}
|
||||
<div class="form-filesize defaultsnext">
|
||||
<div class="d-flex flex-wrap align-items-center">
|
||||
<div class="form-inline">
|
||||
<input type="text" size="5" id="{{id}}v" name="{{name}}[v]" value="{{value}}" class="form-control text-ltr" {{#readonly}}disabled{{/readonly}}>
|
||||
<label class="sr-only" for="{{id}}u">{{#str}}filesizeunits, admin{{/str}}</label>
|
||||
<select id="{{id}}u" name="{{name}}[u]" class="form-control custom-select" {{#readonly}}disabled{{/readonly}}>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
}}
|
||||
<div class="form-multicheckbox">
|
||||
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="1">
|
||||
{{#hasoptions}}
|
||||
<ul>
|
||||
{{#options}}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
Setting configmultiselect.
|
||||
}}
|
||||
<div class="form-select">
|
||||
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="1">
|
||||
<select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
Setting configmultiselect with optgroup support.
|
||||
}}
|
||||
<div class="form-select">
|
||||
{{^readonly}}<input type="hidden" name="{{name}}[xxxxx]" value="1">{{/readonly}}
|
||||
<input type="hidden" name="{{name}}[xxxxx]" value="1">
|
||||
<select {{#readonly}}disabled{{/readonly}} id="{{id}}" name="{{name}}[]" size="{{size}}" class="form-control" multiple>
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
|
||||
@@ -27,8 +27,6 @@
|
||||
* forceltr - always display as ltr
|
||||
* attributes - list of additional attributes containing name, value
|
||||
* readonly - bool
|
||||
* data - list of arbitrary data attributes
|
||||
* maxcharacter - maximum character
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
@@ -38,19 +36,12 @@
|
||||
"size": "21",
|
||||
"forceltr": false,
|
||||
"readonly": false,
|
||||
"attributes": [ { "name": "readonly", "value": "readonly" } ],
|
||||
"data": [ { "key": "validation_max_length", "value": "10" } ],
|
||||
"maxcharacter": false
|
||||
"attributes": [ { "name": "readonly", "value": "readonly" } ]
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configtext.
|
||||
}}
|
||||
<div class="form-text defaultsnext">
|
||||
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}} {{#data}} data-{{key}}={{#quote}}{{{value}}}{{/quote}}{{/data}}>
|
||||
{{#data}}
|
||||
{{#maxcharacter}}
|
||||
<div class="form-defaultinfo text-muted d-block">{{#str}} maxcharacter, admin, {{value}} {{/str}}</div>
|
||||
{{/maxcharacter}}
|
||||
{{/data}}
|
||||
<input type="text" name="{{name}}" value="{{value}}" size="{{size}}" id="{{id}}" class="form-control {{#forceltr}}text-ltr{{/forceltr}}" {{#readonly}}disabled{{/readonly}}>
|
||||
</div>
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
Setting configtime.
|
||||
}}
|
||||
<div class="form-time defaultsnext">
|
||||
<div class="d-flex flex-wrap align-items-center text-ltr">
|
||||
<div class="form-inline text-ltr">
|
||||
<label class="sr-only" for="{{id}}h">{{#str}}hours{{/str}}</label>
|
||||
<select id="{{id}}h" name="{{name}}[h]" class="custom-select" {{#readonly}}disabled{{/readonly}}>
|
||||
{{#hours}}
|
||||
|
||||
@@ -40,9 +40,9 @@
|
||||
{{!
|
||||
Setting courselist_frontpage.
|
||||
}}
|
||||
<div class="mb-3">
|
||||
<div class="form-group">
|
||||
{{#selects}}
|
||||
<select id="{{id}}{{key}}" name="{{name}}[]" class="custom-select mb-1">
|
||||
<select id="{{id}}{{key}}" name="{{name}}[]" class="custom-select">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
{{/options}}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
{{!
|
||||
Setting emoticons.
|
||||
}}
|
||||
<div class="mb-3">
|
||||
<div class="form-group">
|
||||
<table id="emoticonsetting" class="admintable generaltable">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
* id - element id
|
||||
* options - list of options containing name, value and selected
|
||||
* forced - is it forced
|
||||
* advanced - is it advanced
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
@@ -32,13 +33,14 @@
|
||||
"options": [
|
||||
{ "name": "Option name", "value": "Value", "selected": true }
|
||||
],
|
||||
"forced": true
|
||||
"forced": true,
|
||||
"advanced": true
|
||||
}
|
||||
}}
|
||||
{{!
|
||||
Setting configselect.
|
||||
}}
|
||||
<div class="mb-3">
|
||||
<div class="form-group">
|
||||
<select id="{{id}}" name="{{name}}[value]" class="form-select custom-select">
|
||||
{{#options}}
|
||||
<option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
|
||||
@@ -46,5 +48,7 @@
|
||||
</select>
|
||||
<input type="checkbox" id="{{id}}force" name="{{name}}[forced]" value="1" {{#forced}}checked{{/forced}}>
|
||||
<label for="{{id}}force">{{#str}}force{{/str}}</label>
|
||||
<input type="checkbox" id="{{id}}adv" name="{{name}}[adv]" value="1" {{#advanced}}checked{{/advanced}}>
|
||||
<label for="{{id}}adv">{{#str}}advanced{{/str}}</label>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_admin/tasklogs
|
||||
|
||||
This is the template for the search form which appears above the task logs report.
|
||||
}}
|
||||
<form class="form-inline" method="GET" action="{{{action}}}">
|
||||
<label class="sr-only" for="tasklog-filter">{{#str}}filter{{/str}}</label>
|
||||
<input class="form-control" type="text" id="tasklog-filter" name="filter" value="{{{filter}}}">
|
||||
|
||||
<label class="sr-only" for="tasklog-resultfilter">{{#str}}resultfilter, admin{{/str}}</label>
|
||||
<select class="form-control custom-select" name="result" id="tasklog-resultfilter">
|
||||
{{#resultfilteroptions}}
|
||||
<option value="{{{value}}}"{{#selected}} selected="selected"{{/selected}}>{{title}}</option>
|
||||
{{/resultfilteroptions}}
|
||||
</select>
|
||||
|
||||
<input class="btn btn-primary" type="submit" value="{{#str}}filter{{/str}}">
|
||||
</form>
|
||||
@@ -1,101 +0,0 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_admin/themeselector/theme_card
|
||||
|
||||
This template renders the singular card for a theme.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"name": "Boost",
|
||||
"choose": "boost",
|
||||
"image": "http://moodlesite/theme/image.php?theme=boost&image=screenshot&component=theme",
|
||||
"current": true,
|
||||
"actionurl": "http://moodlesite/admin/themeselector.php",
|
||||
"sesskey": "123XYZ",
|
||||
"settingsurl": "http://moodlesite/admin/settings.php?section=themesettingboost",
|
||||
"reporturl": "http://moodlesite/report/themeusage/index.php?themechoice=boost"
|
||||
}
|
||||
}}
|
||||
<div class="card theme-card" role="listitem" id="theme-card-{{choose}}" aria-labelledby="theme-name-{{choose}} {{#current}}current-theme-{{choose}}{{/current}}">
|
||||
<div class="card-img card-img-top" style='background-image: url("{{image}}");'></div>
|
||||
<div class="card-body p-3">
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
<h3 class="h5" id="theme-name-{{choose}}">{{name}}</h3>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
type="button"
|
||||
id="theme-preview-{{choose}}"
|
||||
class="btn btn-link p-0"
|
||||
title="{{#str}}previewthemename, moodle, {{name}}{{/str}}"
|
||||
data-action="preview"
|
||||
data-name="{{name}}"
|
||||
data-image="{{image}}"
|
||||
data-current="{{current}}"
|
||||
data-actionurl="{{actionurl}}"
|
||||
data-choose="{{choose}}"
|
||||
data-sesskey="{{sesskey}}">
|
||||
<i class="icon fa fa-info-circle m-0" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{#str}}previewthemename, moodle, {{name}}{{/str}}</span>
|
||||
</button>
|
||||
{{#reporturl}}
|
||||
<a
|
||||
href="{{reporturl}}"
|
||||
id="theme-usage-report-{{choose}}"
|
||||
class="btn btn-link p-0 ml-2"
|
||||
title="{{#str}}themeusagereportname, admin, {{name}}{{/str}}">
|
||||
<i class="icon fa fa-area-chart m-0" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{#str}}themeusagereportname, admin, {{name}}{{/str}}</span>
|
||||
</a>
|
||||
{{/reporturl}}
|
||||
{{#settingsurl}}
|
||||
<a
|
||||
href="{{settingsurl}}"
|
||||
id="theme-settings-{{choose}}"
|
||||
class="btn btn-link p-0 ml-2"
|
||||
title="{{#str}}themeeditsettingsname, admin, {{name}}{{/str}}">
|
||||
<i class="icon fa fa-cog m-0" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{#str}}themeeditsettingsname, admin, {{name}}{{/str}}</span>
|
||||
</a>
|
||||
{{/settingsurl}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex align-items-end flex-column p-3">
|
||||
{{#current}}
|
||||
<strong><span class="text-success" id="current-theme-{{choose}}">{{#str}}currenttheme, moodle{{/str}}</span></strong>
|
||||
{{#definedinconfig}}
|
||||
<div class="alert alert-info p-1">{{#str}}configoverride, admin{{/str}}</div>
|
||||
{{/definedinconfig}}
|
||||
{{/current}}
|
||||
{{^current}}
|
||||
{{#actionurl}}
|
||||
<form method="post" action="{{actionurl}}" id="theme-select-form-{{choose}}">
|
||||
<input type="hidden" name="sesskey" value="{{sesskey}}">
|
||||
<input type="hidden" name="choose" value="{{choose}}">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<span aria-hidden="true">{{#str}}selecttheme, moodle{{/str}}</span>
|
||||
<span class="sr-only">{{#str}}selectthemename, moodle, {{name}}{{/str}}</span>
|
||||
</button>
|
||||
</form>
|
||||
{{/actionurl}}
|
||||
{{/current}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_admin/themeselector/theme_preview_modal
|
||||
|
||||
This template renders the modal for the selected theme.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"name": "Boost",
|
||||
"choose": "boost",
|
||||
"image": "http://moodlesite/theme/image.php?theme=boost&image=screenshot&component=theme",
|
||||
"description": "Boost is a modern highly-customisable theme...",
|
||||
"current": true,
|
||||
"actionurl": "http://moodlesite/admin/themeselector.php",
|
||||
"sesskey": "123XYZ"
|
||||
}
|
||||
}}
|
||||
<div>
|
||||
<div>
|
||||
<img
|
||||
src="{{image}}"
|
||||
alt=""
|
||||
id="modal-theme-preview-{{choose}}"
|
||||
class="w-100 mb-3">
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<div class="flex-grow-1">
|
||||
<p><strong>{{#str}}themepreviewdescription, moodle, {{name}}{{/str}}</strong></p>
|
||||
</div>
|
||||
<div class="d-flex align-items-end flex-column">
|
||||
{{#current}}
|
||||
<strong><span class="text-success">{{#str}}currenttheme, moodle{{/str}}</span></strong>
|
||||
{{#definedinconfig}}
|
||||
<div class="alert alert-info p-1">{{#str}}configoverride, admin{{/str}}</div>
|
||||
{{/definedinconfig}}
|
||||
{{/current}}
|
||||
</div>
|
||||
</div>
|
||||
<p>{{description}}</p>
|
||||
{{#actionurl}}
|
||||
<form method="post" action="{{actionurl}}" id="modal-theme-select-form-{{choose}}">
|
||||
<input type="hidden" name="sesskey" value="{{sesskey}}">
|
||||
<input type="hidden" name="choose" value="{{choose}}">
|
||||
</form>
|
||||
{{/actionurl}}
|
||||
</div>
|
||||
@@ -1,77 +0,0 @@
|
||||
{{!
|
||||
This file is part of Moodle - http://moodle.org/
|
||||
|
||||
Moodle is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Moodle is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
}}
|
||||
{{!
|
||||
@template core_admin/themeselector/theme_selector
|
||||
|
||||
This template renders the cards view for choosing a theme.
|
||||
|
||||
Example context (json):
|
||||
{
|
||||
"themes": [
|
||||
{
|
||||
"name": "Boost",
|
||||
"choose": "boost",
|
||||
"image": "http://moodlesite/theme/image.php?theme=boost&image=screenshot&component=theme",
|
||||
"current": true,
|
||||
"actionurl": "http://moodlesite/admin/themeselector.php",
|
||||
"sesskey": "123XYZ"
|
||||
},
|
||||
{
|
||||
"name": "Classic",
|
||||
"choose": "classic",
|
||||
"image": "http://moodlesite/theme/image.php?theme=classic&image=screenshot&component=theme",
|
||||
"actionurl": "http://moodlesite/admin/themeselector.php",
|
||||
"sesskey": "123XYZ"
|
||||
}
|
||||
],
|
||||
"resetbutton": {
|
||||
"id": "single_button123",
|
||||
"method": "post",
|
||||
"url": "index.php",
|
||||
"label": "Clear theme caches",
|
||||
"params": [
|
||||
{
|
||||
"name": "sesskey",
|
||||
"value": "123XYZ"
|
||||
},
|
||||
{
|
||||
"name": "reset",
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}}
|
||||
<h2>{{#str}}themeselector, admin{{/str}}</h2>
|
||||
{{#resetbutton}}
|
||||
<div class="mb-3">
|
||||
{{>core/single_button}}
|
||||
</div>
|
||||
{{/resetbutton}}
|
||||
<div class="card-grid row row-cols-1 row-cols-md-3 mx-0" id="themelist" data-region="card-deck" role="list" data-definedinconfig="{{definedinconfig}}">
|
||||
{{#themes}}
|
||||
<div class="col d-flex px-1 mb-2">
|
||||
{{>core_admin/themeselector/theme_card}}
|
||||
</div>
|
||||
{{/themes}}
|
||||
</div>
|
||||
|
||||
{{#js}}
|
||||
require(['core_admin/themeselector/preview_modal'], function(Modal) {
|
||||
Modal.init();
|
||||
});
|
||||
{{/js}}
|
||||
@@ -75,6 +75,7 @@ class behat_admin extends behat_base {
|
||||
// Multi element settings, interacting only the first one.
|
||||
$fieldxpath = "//*[label[contains(., $label)]|span[contains(., $label)]]" .
|
||||
"/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
"/descendant::div[contains(concat(' ', @class, ' '), ' form-group ')]" .
|
||||
"/descendant::*[self::input | self::textarea | self::select]" .
|
||||
"[not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_admin @core_reportbuilder
|
||||
@core @core_admin
|
||||
Feature: An administrator can browse user accounts
|
||||
In order to find the user accounts I am looking for
|
||||
As an admin
|
||||
@@ -17,24 +17,24 @@ Feature: An administrator can browse user accounts
|
||||
Scenario: User accounts display default fields
|
||||
When I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
# Name field always present, email field is default for showidentity.
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| First name | Email address |
|
||||
Then the following should exist in the "users" table:
|
||||
| First name / Last name | Email address |
|
||||
| User One | one@example.com |
|
||||
| User Two | two@example.com |
|
||||
# Should not see other identity fields or non-default name fields.
|
||||
And I should not see "Department" in the "reportbuilder-table" "table"
|
||||
And I should not see "Attack" in the "reportbuilder-table" "table"
|
||||
And I should not see "Favourite frog" in the "reportbuilder-table" "table"
|
||||
And I should not see "Kermit" in the "reportbuilder-table" "table"
|
||||
And I should not see "First name - phonetic" in the "reportbuilder-table" "table"
|
||||
And I should not see "Yoozare" in the "reportbuilder-table" "table"
|
||||
And I should not see "Department" in the "table" "css_element"
|
||||
And I should not see "Attack"
|
||||
And I should not see "Favourite frog" in the "table" "css_element"
|
||||
And I should not see "Kermit"
|
||||
And I should not see "First name - phonetic" in the "table" "css_element"
|
||||
And I should not see "Yoozare"
|
||||
|
||||
Scenario: User accounts with extra name fields
|
||||
Given the following config values are set as admin:
|
||||
| alternativefullnameformat | firstnamephonetic lastname |
|
||||
When I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| First name - phonetic | Email address |
|
||||
Then the following should exist in the "users" table:
|
||||
| First name - phonetic / Last name | Email address |
|
||||
| Yewzer One | one@example.com |
|
||||
| Yoozare Two | two@example.com |
|
||||
|
||||
@@ -42,14 +42,13 @@ Feature: An administrator can browse user accounts
|
||||
Given the following config values are set as admin:
|
||||
| showuseridentity | department,profile_field_frog |
|
||||
When I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| First name | Favourite frog | Department |
|
||||
Then the following should exist in the "users" table:
|
||||
| First name / Last name | Favourite frog | Department |
|
||||
| User One | Kermit | Attack |
|
||||
| User Two | Tree | Defence |
|
||||
And I should not see "Email address" in the "table" "css_element"
|
||||
And I should not see "one@example.com"
|
||||
|
||||
@javascript
|
||||
Scenario: Sort user accounts by custom profile field
|
||||
Given the following config values are set as admin:
|
||||
| showuseridentity | profile_field_frog |
|
||||
@@ -58,166 +57,3 @@ Feature: An administrator can browse user accounts
|
||||
Then "Kermit" "text" should appear before "Tree" "text"
|
||||
And I follow "Favourite frog"
|
||||
Then "Tree" "text" should appear before "Kermi" "text"
|
||||
|
||||
@javascript
|
||||
Scenario: Edit user information
|
||||
Given I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I press "Edit" action in the "User One" report row
|
||||
And I set the field "Last name" to "OneOne"
|
||||
And I press "Update profile"
|
||||
Then I should see "User OneOne"
|
||||
|
||||
@javascript
|
||||
Scenario: Suspend and activate user account
|
||||
Given I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I press "Suspend user account" action in the "User One" report row
|
||||
And I should see "Suspended" in the "User One" "table_row"
|
||||
And I press "Activate user account" action in the "User One" report row
|
||||
Then I should not see "Suspended" in the "User One" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: Delete a user account
|
||||
Given I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I press "Delete" action in the "User One" report row
|
||||
And I should see "Are you absolutely sure you want to completely delete the user User One" in the "Delete user" "dialogue"
|
||||
And I click on "Delete" "button" in the "Delete user" "dialogue"
|
||||
Then I should see "Deleted user User One"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
|
||||
@javascript
|
||||
Scenario: Resend email and confirm a user account
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | confirmed |
|
||||
| user3 | User | Three | three@example.com | 0 |
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then I should see "Confirmation pending" in the "User Three" "table_row"
|
||||
And I press "Resend confirmation email" action in the "User Three" report row
|
||||
And I should see "Confirmation email sent successfully"
|
||||
And I press "Confirm" action in the "User Three" report row
|
||||
And I should not see "Confirmation pending" in the "User Three" "table_row"
|
||||
|
||||
@javascript
|
||||
Scenario: User report filters
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | profile_field_frog |
|
||||
| user3 | User | Three | three@example.com | Glass |
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| First name | Email address |
|
||||
| User One | one@example.com |
|
||||
| User Two | two@example.com |
|
||||
| User Three | three@example.com |
|
||||
And I click on "Filters" "button"
|
||||
And I set the following fields in the "Last name" "core_reportbuilder > Filter" to these values:
|
||||
| Last name operator | Is equal to |
|
||||
| Last name value | Three |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I click on "Filters" "button"
|
||||
And I should see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I click on "Filters" "button"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
|
||||
| Favourite frog operator | Is equal to |
|
||||
| Favourite frog value | Kermit |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I click on "Filters" "button"
|
||||
And I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
|
||||
@javascript
|
||||
Scenario: User report enrolled in any course filter
|
||||
Given the following "courses" exist:
|
||||
| shortname | fullname |
|
||||
| C1 | Course 1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| user2 | C1 | student |
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| First name | Email address |
|
||||
| User One | one@example.com |
|
||||
| User Two | two@example.com |
|
||||
And I click on "Filters" "button"
|
||||
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
|
||||
| Enrolled in any course operator | Yes |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I click on "Filters" "button"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
|
||||
@javascript
|
||||
Scenario: User report system role and course role filters
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| user3 | User | Three | three@example.com |
|
||||
And the following "courses" exist:
|
||||
| shortname | fullname |
|
||||
| C1 | Course 1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| user1 | C1 | student |
|
||||
| user2 | C1 | editingteacher |
|
||||
| user3 | C1 | student |
|
||||
And the following "role assigns" exist:
|
||||
| user | role | contextlevel | reference |
|
||||
| user1 | coursecreator | system | |
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then the following should exist in the "reportbuilder-table" table:
|
||||
| First name | Email address |
|
||||
| User One | one@example.com |
|
||||
| User Two | two@example.com |
|
||||
| User Three | three@example.com |
|
||||
And I click on "Filters" "button"
|
||||
And I set the following fields in the "System role" "core_reportbuilder > Filter" to these values:
|
||||
| System role operator | Is equal to |
|
||||
| System role value | Course creator |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I click on "Filters" "button"
|
||||
And I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I click on "Filters" "button"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
|
||||
| Role name | Teacher |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I click on "Filters" "button"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
|
||||
Scenario: Add a new user
|
||||
Given I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on "Add a new user" "link"
|
||||
Then I should see "Username"
|
||||
And I should see "User picture"
|
||||
And I should see "Additional names"
|
||||
|
||||
@javascript
|
||||
Scenario: Browse user list as a person with limited capabilities
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| manager | Max | Manager | manager@example.com |
|
||||
And the following "roles" exist:
|
||||
| name | shortname | description | archetype |
|
||||
| Custom manager | custom1 | My custom role 1 | |
|
||||
And the following "permission overrides" exist:
|
||||
| capability | permission | role | contextlevel | reference |
|
||||
| moodle/site:configview | Allow | custom1 | System | |
|
||||
| moodle/user:update | Allow | custom1 | System | |
|
||||
And the following "role assigns" exist:
|
||||
| user | role | contextlevel | reference |
|
||||
| manager | custom1 | System | |
|
||||
When I log in as "manager"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
And I click on "User One" "checkbox"
|
||||
And the "Bulk user actions" select box should contain "Confirm"
|
||||
And the "Bulk user actions" select box should not contain "Delete"
|
||||
And I set the field "Bulk user actions" to "Force password change"
|
||||
And I should see "Are you absolutely sure you want to force a password change to User One ?"
|
||||
And I press "Yes"
|
||||
And I press "Continue"
|
||||
And I should see "Browse list of users"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@core @core_admin @core_reportbuilder
|
||||
@core @core_admin
|
||||
Feature: An administrator can filter user accounts by role, cohort and other profile fields
|
||||
In order to find the user accounts I am looking for
|
||||
As an admin
|
||||
@@ -33,150 +33,109 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
And I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by role and cohort
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Course role" "core_reportbuilder > Filter" to these values:
|
||||
| Role name | Student |
|
||||
| Course short name | C1 |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I set the following fields in the "Cohort ID" "core_reportbuilder > Filter" to these values:
|
||||
| Cohort ID operator | Is equal to |
|
||||
| Cohort ID value | CH1 |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should see "User Four" in the "reportbuilder-table" "table"
|
||||
When I set the following fields to these values:
|
||||
| courserole_rl | Student |
|
||||
| courserole_ct | any category |
|
||||
| courserole | C1 |
|
||||
And I press "Add filter"
|
||||
Then I should see "User One"
|
||||
And I should see "User Two"
|
||||
And I should see "User Three"
|
||||
And I should not see "User Four"
|
||||
And I set the following fields to these values:
|
||||
| cohort | CH1 |
|
||||
And I press "Add filter"
|
||||
And I should not see "User One"
|
||||
And I should see "User Two"
|
||||
And I should see "User Three"
|
||||
And I should not see "User Four"
|
||||
And I press "Remove all filters"
|
||||
And I should see "User One"
|
||||
And I should see "User Two"
|
||||
And I should see "User Three"
|
||||
And I should see "User Four"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by confirm and authentication method
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Confirmed" "core_reportbuilder > Filter" to these values:
|
||||
| Confirmed operator | No |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should see "User Four" in the "reportbuilder-table" "table"
|
||||
And I set the following fields in the "Authentication" "core_reportbuilder > Filter" to these values:
|
||||
| Authentication operator | Is equal to |
|
||||
| Authentication value | Manual accounts |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
When I set the following fields to these values:
|
||||
| Confirmed | No |
|
||||
And I press "Add filter"
|
||||
Then I should see "User One"
|
||||
And I should not see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should see "User Four"
|
||||
And I set the following fields to these values:
|
||||
| Authentication | manual |
|
||||
And I press "Add filter"
|
||||
And I should see "User One"
|
||||
And I should not see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should not see "User Four"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by enrolled in any course
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
|
||||
| Enrolled in any course operator | Yes |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I set the following fields in the "Enrolled in any course" "core_reportbuilder > Filter" to these values:
|
||||
| Enrolled in any course operator | No |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should see "User Four" in the "reportbuilder-table" "table"
|
||||
When I set the following fields to these values:
|
||||
| id_anycourses | Yes |
|
||||
And I press "Add filter"
|
||||
Then I should see "User One"
|
||||
And I should see "User Two"
|
||||
And I should see "User Three"
|
||||
And I should not see "User Four"
|
||||
And I press "Remove all filters"
|
||||
And I set the following fields to these values:
|
||||
| id_anycourses | No |
|
||||
And I press "Add filter"
|
||||
And I should not see "User One"
|
||||
And I should not see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should see "User Four"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by last IP address
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
|
||||
| Last IP address operator | Is equal to |
|
||||
| Last IP address value | 127.0.1.1 |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I set the following fields in the "Last IP address" "core_reportbuilder > Filter" to these values:
|
||||
| Last IP address operator | Is equal to |
|
||||
| Last IP address value | 127.0.1.2 |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should see "User Four" in the "reportbuilder-table" "table"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should see "User Four" in the "reportbuilder-table" "table"
|
||||
When I set the following fields to these values:
|
||||
| id_lastip | 127.0.1.1 |
|
||||
And I press "Add filter"
|
||||
Then I should see "User One"
|
||||
And I should not see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should not see "User Four"
|
||||
And I press "Remove all filters"
|
||||
And I set the following fields to these values:
|
||||
| id_lastip | 127.0.1.2 |
|
||||
And I press "Add filter"
|
||||
And I should not see "User One"
|
||||
And I should not see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should see "User Four"
|
||||
And I press "Remove all filters"
|
||||
And I should see "User One"
|
||||
And I should see "User Two"
|
||||
And I should see "User Three"
|
||||
And I should see "User Four"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter users by institution and department
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Institution" "core_reportbuilder > Filter" to these values:
|
||||
| Institution operator | Is equal to |
|
||||
| Institution value | moodle |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I set the following fields in the "Department" "core_reportbuilder > Filter" to these values:
|
||||
| Department operator | Is equal to |
|
||||
| Department value | red |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
When I set the field "id_institution" to "moodle"
|
||||
And I press "Add filter"
|
||||
Then I should see "User One"
|
||||
And I should see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should not see "User Four"
|
||||
And I set the field "id_department" to "red"
|
||||
And I press "Add filter"
|
||||
And I should see "User One"
|
||||
And I should not see "User Two"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter users by custom profile field (specific or any)
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Favourite frog" "core_reportbuilder > Filter" to these values:
|
||||
| Favourite frog operator | Is equal to |
|
||||
| Favourite frog value | Kermit |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I set the following fields in the "Type of undead" "core_reportbuilder > Filter" to these values:
|
||||
| Type of undead operator | Is equal to |
|
||||
| Type of undead value | Zombie |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter users by full name
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Full name" "core_reportbuilder > Filter" to these values:
|
||||
| Full name operator | Is equal to |
|
||||
| Full name value | User One |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I set the following fields in the "Full name" "core_reportbuilder > Filter" to these values:
|
||||
| Full name operator | Is equal to |
|
||||
| Full name value | User Two |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "User Two" in the "reportbuilder-table" "table"
|
||||
And I should not see "User One" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Three" in the "reportbuilder-table" "table"
|
||||
And I should not see "User Four" in the "reportbuilder-table" "table"
|
||||
When I set the field "id_profile_fld" to "Favourite frog"
|
||||
And I set the field "id_profile" to "Kermit"
|
||||
And I press "Add filter"
|
||||
Then I should see "User One"
|
||||
And I should not see "User Two"
|
||||
And I should not see "User Three"
|
||||
And I should not see "User Four"
|
||||
And I press "Remove all filters"
|
||||
And I set the field "id_profile_fld" to "any field"
|
||||
And I set the field "id_profile" to "Zombie"
|
||||
And I press "Add filter"
|
||||
And I should see "User Two"
|
||||
And I should not see "User One"
|
||||
And I should not see "User Three"
|
||||
And I should not see "User Four"
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
@core @core_admin @javascript
|
||||
Feature: An administrator can configure the available user list filters
|
||||
In order to have all needed user filters instantly at hand
|
||||
As an admin
|
||||
I want to configure the filters which are shown as default
|
||||
|
||||
Scenario: Do not change the user filter default configuration
|
||||
When I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then I should see "User full name"
|
||||
And I should not see "Last name" in the "New filter" "fieldset"
|
||||
And I should not see "Firstname" in the "New filter" "fieldset"
|
||||
And I should not see "Username" in the "New filter" "fieldset"
|
||||
And I should not see "Email address" in the "New filter" "fieldset"
|
||||
And I should not see "City/town" in the "New filter" "fieldset"
|
||||
And I should not see "Country" in the "New filter" "fieldset"
|
||||
And I should not see "Confirmed" in the "New filter" "fieldset"
|
||||
And I should not see "Suspended account" in the "New filter" "fieldset"
|
||||
And I should not see "User profile fields" in the "New filter" "fieldset"
|
||||
And I should not see "Course role" in the "New filter" "fieldset"
|
||||
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
|
||||
And I should not see "System role" in the "New filter" "fieldset"
|
||||
And I should not see "Cohort ID" in the "New filter" "fieldset"
|
||||
And I should not see "First access" in the "New filter" "fieldset"
|
||||
And I should not see "Last access" in the "New filter" "fieldset"
|
||||
And I should not see "Last modified" in the "New filter" "fieldset"
|
||||
And I should not see "Authentication" in the "New filter" "fieldset"
|
||||
And I should not see "ID number" in the "New filter" "fieldset"
|
||||
And I should not see "Last IP address" in the "New filter" "fieldset"
|
||||
And I should not see "MNet ID provider" in the "New filter" "fieldset"
|
||||
And I navigate to "Users > Accounts > Bulk user actions" in site administration
|
||||
Then I should see "User full name"
|
||||
And I should not see "Last name" in the "New filter" "fieldset"
|
||||
And I should not see "Firstname" in the "New filter" "fieldset"
|
||||
And I should not see "Username" in the "New filter" "fieldset"
|
||||
And I should not see "Email address" in the "New filter" "fieldset"
|
||||
And I should not see "City/town" in the "New filter" "fieldset"
|
||||
And I should not see "Country" in the "New filter" "fieldset"
|
||||
And I should not see "Confirmed" in the "New filter" "fieldset"
|
||||
And I should not see "Suspended account" in the "New filter" "fieldset"
|
||||
And I should not see "User profile fields" in the "New filter" "fieldset"
|
||||
And I should not see "Course role" in the "New filter" "fieldset"
|
||||
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
|
||||
And I should not see "System role" in the "New filter" "fieldset"
|
||||
And I should not see "Cohort ID" in the "New filter" "fieldset"
|
||||
And I should not see "First access" in the "New filter" "fieldset"
|
||||
And I should not see "Last access" in the "New filter" "fieldset"
|
||||
And I should not see "Last modified" in the "New filter" "fieldset"
|
||||
And I should not see "Authentication" in the "New filter" "fieldset"
|
||||
And I should not see "ID number" in the "New filter" "fieldset"
|
||||
And I should not see "Last IP address" in the "New filter" "fieldset"
|
||||
And I should not see "MNet ID provider" in the "New filter" "fieldset"
|
||||
|
||||
Scenario: Change the user filter default configuration to something else
|
||||
Given the following config values are set as admin:
|
||||
| userfiltersdefault | realname,username,email |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then I should see "User full name"
|
||||
And I should not see "Last name" in the "New filter" "fieldset"
|
||||
And I should not see "Firstname" in the "New filter" "fieldset"
|
||||
And I should see "Username" in the "New filter" "fieldset"
|
||||
And I should see "Email address" in the "New filter" "fieldset"
|
||||
And I should not see "City/town" in the "New filter" "fieldset"
|
||||
And I should not see "Country" in the "New filter" "fieldset"
|
||||
And I should not see "Confirmed" in the "New filter" "fieldset"
|
||||
And I should not see "Suspended account" in the "New filter" "fieldset"
|
||||
And I should not see "User profile fields" in the "New filter" "fieldset"
|
||||
And I should not see "Course role" in the "New filter" "fieldset"
|
||||
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
|
||||
And I should not see "System role" in the "New filter" "fieldset"
|
||||
And I should not see "Cohort ID" in the "New filter" "fieldset"
|
||||
And I should not see "First access" in the "New filter" "fieldset"
|
||||
And I should not see "Last access" in the "New filter" "fieldset"
|
||||
And I should not see "Last modified" in the "New filter" "fieldset"
|
||||
And I should not see "Authentication" in the "New filter" "fieldset"
|
||||
And I should not see "ID number" in the "New filter" "fieldset"
|
||||
And I should not see "Last IP address" in the "New filter" "fieldset"
|
||||
And I should not see "MNet ID provider" in the "New filter" "fieldset"
|
||||
And I navigate to "Users > Accounts > Bulk user actions" in site administration
|
||||
Then I should see "User full name"
|
||||
And I should not see "Last name" in the "New filter" "fieldset"
|
||||
And I should not see "Firstname" in the "New filter" "fieldset"
|
||||
And I should see "Username" in the "New filter" "fieldset"
|
||||
And I should see "Email address" in the "New filter" "fieldset"
|
||||
And I should not see "City/town" in the "New filter" "fieldset"
|
||||
And I should not see "Country" in the "New filter" "fieldset"
|
||||
And I should not see "Confirmed" in the "New filter" "fieldset"
|
||||
And I should not see "Suspended account" in the "New filter" "fieldset"
|
||||
And I should not see "User profile fields" in the "New filter" "fieldset"
|
||||
And I should not see "Course role" in the "New filter" "fieldset"
|
||||
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
|
||||
And I should not see "System role" in the "New filter" "fieldset"
|
||||
And I should not see "Cohort ID" in the "New filter" "fieldset"
|
||||
And I should not see "First access" in the "New filter" "fieldset"
|
||||
And I should not see "Last access" in the "New filter" "fieldset"
|
||||
And I should not see "Last modified" in the "New filter" "fieldset"
|
||||
And I should not see "Authentication" in the "New filter" "fieldset"
|
||||
And I should not see "ID number" in the "New filter" "fieldset"
|
||||
And I should not see "Last IP address" in the "New filter" "fieldset"
|
||||
And I should not see "MNet ID provider" in the "New filter" "fieldset"
|
||||
|
||||
Scenario: Change the user filter default configuration to no filter at all
|
||||
Given the following config values are set as admin:
|
||||
| userfiltersdefault | |
|
||||
And I log in as "admin"
|
||||
And I navigate to "Users > Accounts > Browse list of users" in site administration
|
||||
Then I should see "User full name"
|
||||
And I should not see "Last name" in the "New filter" "fieldset"
|
||||
And I should not see "Firstname" in the "New filter" "fieldset"
|
||||
And I should not see "Username" in the "New filter" "fieldset"
|
||||
And I should not see "Email address" in the "New filter" "fieldset"
|
||||
And I should not see "City/town" in the "New filter" "fieldset"
|
||||
And I should not see "Country" in the "New filter" "fieldset"
|
||||
And I should not see "Confirmed" in the "New filter" "fieldset"
|
||||
And I should not see "Suspended account" in the "New filter" "fieldset"
|
||||
And I should not see "User profile fields" in the "New filter" "fieldset"
|
||||
And I should not see "Course role" in the "New filter" "fieldset"
|
||||
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
|
||||
And I should not see "System role" in the "New filter" "fieldset"
|
||||
And I should not see "Cohort ID" in the "New filter" "fieldset"
|
||||
And I should not see "First access" in the "New filter" "fieldset"
|
||||
And I should not see "Last access" in the "New filter" "fieldset"
|
||||
And I should not see "Last modified" in the "New filter" "fieldset"
|
||||
And I should not see "Authentication" in the "New filter" "fieldset"
|
||||
And I should not see "ID number" in the "New filter" "fieldset"
|
||||
And I should not see "Last IP address" in the "New filter" "fieldset"
|
||||
And I should not see "MNet ID provider" in the "New filter" "fieldset"
|
||||
And I navigate to "Users > Accounts > Bulk user actions" in site administration
|
||||
Then I should see "User full name"
|
||||
And I should not see "Last name" in the "New filter" "fieldset"
|
||||
And I should not see "Firstname" in the "New filter" "fieldset"
|
||||
And I should not see "Username" in the "New filter" "fieldset"
|
||||
And I should not see "Email address" in the "New filter" "fieldset"
|
||||
And I should not see "City/town" in the "New filter" "fieldset"
|
||||
And I should not see "Country" in the "New filter" "fieldset"
|
||||
And I should not see "Confirmed" in the "New filter" "fieldset"
|
||||
And I should not see "Suspended account" in the "New filter" "fieldset"
|
||||
And I should not see "User profile fields" in the "New filter" "fieldset"
|
||||
And I should not see "Course role" in the "New filter" "fieldset"
|
||||
And I should not see "Enrolled in any course" in the "New filter" "fieldset"
|
||||
And I should not see "System role" in the "New filter" "fieldset"
|
||||
And I should not see "Cohort ID" in the "New filter" "fieldset"
|
||||
And I should not see "First access" in the "New filter" "fieldset"
|
||||
And I should not see "Last access" in the "New filter" "fieldset"
|
||||
And I should not see "Last modified" in the "New filter" "fieldset"
|
||||
And I should not see "Authentication" in the "New filter" "fieldset"
|
||||
And I should not see "ID number" in the "New filter" "fieldset"
|
||||
And I should not see "Last IP address" in the "New filter" "fieldset"
|
||||
And I should not see "MNet ID provider" in the "New filter" "fieldset"
|
||||
@@ -7,35 +7,35 @@ Feature: Reset course indentation
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | format |
|
||||
| Sections Course 1 | T1 | topics |
|
||||
| Sections Course 2 | T2 | topics |
|
||||
| Topics Course 1 | T1 | topics |
|
||||
| Topics Course 2 | T2 | topics |
|
||||
| Weekly Course 1 | W1 | weeks |
|
||||
| Weekly Course 2 | W2 | weeks |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| forum | Sections forum name | Sections forum description | T1 | forum1 |
|
||||
| data | Sections database name | Sections database description | T1 | data1 |
|
||||
| wiki | Sections wiki name | Sections wiki description | T2 | wiki1 |
|
||||
| forum | Weekly forum name | Weekly forum description | W1 | forum2 |
|
||||
| data | Weekly database name | Weekly database description | W1 | data2 |
|
||||
| wiki | Weekly wiki name | Weekly wiki description | W2 | wiki2 |
|
||||
| activity | name | intro | course | idnumber |
|
||||
| forum | Topics forum name | Topics forum description | T1 | forum1 |
|
||||
| data | Topics database name | Topics database description | T1 | data1 |
|
||||
| wiki | Topics wiki name | Topics wiki description | T2 | wiki1 |
|
||||
| forum | Weekly forum name | Weekly forum description | W1 | forum2 |
|
||||
| data | Weekly database name | Weekly database description | W1 | data2 |
|
||||
| wiki | Weekly wiki name | Weekly wiki description | W2 | wiki2 |
|
||||
And I log in as "admin"
|
||||
And I am on "Sections Course 1" course homepage with editing mode on
|
||||
And I open "Sections forum name" actions menu
|
||||
And I click on "Move right" "link" in the "Sections forum name" activity
|
||||
And I open "Sections forum name" actions menu
|
||||
And "Move right" "link" in the "Sections forum name" "activity" should not be visible
|
||||
And "Move left" "link" in the "Sections forum name" "activity" should be visible
|
||||
And I am on "Topics Course 1" course homepage with editing mode on
|
||||
And I open "Topics forum name" actions menu
|
||||
And I click on "Move right" "link" in the "Topics forum name" activity
|
||||
And I open "Topics forum name" actions menu
|
||||
And "Move right" "link" in the "Topics forum name" "activity" should not be visible
|
||||
And "Move left" "link" in the "Topics forum name" "activity" should be visible
|
||||
And I press the escape key
|
||||
And I open "Sections database name" actions menu
|
||||
And "Move right" "link" in the "Sections database name" "activity" should be visible
|
||||
And "Move left" "link" in the "Sections database name" "activity" should not be visible
|
||||
And I am on "Sections Course 2" course homepage with editing mode on
|
||||
And I open "Sections wiki name" actions menu
|
||||
And I click on "Move right" "link" in the "Sections wiki name" activity
|
||||
And I open "Sections wiki name" actions menu
|
||||
And "Move right" "link" in the "Sections wiki name" "activity" should not be visible
|
||||
And "Move left" "link" in the "Sections wiki name" "activity" should be visible
|
||||
And I open "Topics database name" actions menu
|
||||
And "Move right" "link" in the "Topics database name" "activity" should be visible
|
||||
And "Move left" "link" in the "Topics database name" "activity" should not be visible
|
||||
And I am on "Topics Course 2" course homepage with editing mode on
|
||||
And I open "Topics wiki name" actions menu
|
||||
And I click on "Move right" "link" in the "Topics wiki name" activity
|
||||
And I open "Topics wiki name" actions menu
|
||||
And "Move right" "link" in the "Topics wiki name" "activity" should not be visible
|
||||
And "Move left" "link" in the "Topics wiki name" "activity" should be visible
|
||||
And I am on "Weekly Course 1" course homepage with editing mode on
|
||||
And I open "Weekly forum name" actions menu
|
||||
And I click on "Move right" "link" in the "Weekly forum name" activity
|
||||
@@ -54,7 +54,7 @@ Feature: Reset course indentation
|
||||
And "Move left" "link" in the "Weekly wiki name" "activity" should be visible
|
||||
|
||||
Scenario Outline: Apply course indentation reset
|
||||
Given I navigate to "Plugins > Course formats > <format>" in site administration
|
||||
Given I navigate to "Plugins > Course formats > <format> format" in site administration
|
||||
And I wait "5" seconds
|
||||
And "Reset indentation sitewide" "link" should exist
|
||||
When I click on "Reset indentation sitewide" "link"
|
||||
@@ -62,31 +62,31 @@ Feature: Reset course indentation
|
||||
And "Reset indentation sitewide" "button" should exist
|
||||
And I click on "Reset indentation sitewide" "button"
|
||||
Then I should see "Indentation reset."
|
||||
And I am on "<prefix> Course 1" course homepage with editing mode on
|
||||
And I open "<prefix> forum name" actions menu
|
||||
And "Move right" "link" in the "<prefix> forum name" "activity" should be visible
|
||||
And "Move left" "link" in the "<prefix> forum name" "activity" should not be visible
|
||||
And I am on "<format> Course 1" course homepage with editing mode on
|
||||
And I open "<format> forum name" actions menu
|
||||
And "Move right" "link" in the "<format> forum name" "activity" should be visible
|
||||
And "Move left" "link" in the "<format> forum name" "activity" should not be visible
|
||||
And I press the escape key
|
||||
And I open "<prefix> database name" actions menu
|
||||
And "Move right" "link" in the "<prefix> database name" "activity" should be visible
|
||||
And "Move left" "link" in the "<prefix> database name" "activity" should not be visible
|
||||
And I am on "<prefix> Course 2" course homepage with editing mode on
|
||||
And I open "<prefix> wiki name" actions menu
|
||||
And "Move right" "link" in the "<prefix> wiki name" "activity" should be visible
|
||||
And "Move left" "link" in the "<prefix> wiki name" "activity" should not be visible
|
||||
# Check other course formats had not been reset
|
||||
And I open "<format> database name" actions menu
|
||||
And "Move right" "link" in the "<format> database name" "activity" should be visible
|
||||
And "Move left" "link" in the "<format> database name" "activity" should not be visible
|
||||
And I am on "<format> Course 2" course homepage with editing mode on
|
||||
And I open "<format> wiki name" actions menu
|
||||
And "Move right" "link" in the "<format> wiki name" "activity" should be visible
|
||||
And "Move left" "link" in the "<format> wiki name" "activity" should not be visible
|
||||
# Check other course formats had not been reset
|
||||
And I am on "<other> Course 1" course homepage with editing mode on
|
||||
And I open "<other> forum name" actions menu
|
||||
And "Move right" "link" in the "<other> forum name" "activity" should not be visible
|
||||
And "Move left" "link" in the "<other> forum name" "activity" should be visible
|
||||
|
||||
Examples:
|
||||
| format | prefix | other |
|
||||
| Custom sections | Sections | Weekly |
|
||||
| Weekly sections | Weekly | Sections |
|
||||
| format | other |
|
||||
| Topics | Weekly |
|
||||
| Weekly | Topics |
|
||||
|
||||
Scenario Outline: Cancel course indentation reset
|
||||
Given I navigate to "Plugins > Course formats > <format>" in site administration
|
||||
Given I navigate to "Plugins > Course formats > <format> format" in site administration
|
||||
And "Reset indentation sitewide" "link" should exist
|
||||
When I click on "Reset indentation sitewide" "link"
|
||||
And I should see "Reset indentation sitewide"
|
||||
@@ -94,20 +94,20 @@ Feature: Reset course indentation
|
||||
And "Cancel" "button" should exist
|
||||
And I click on "Cancel" "button"
|
||||
Then I should not see "Indentation reset."
|
||||
And I am on "<prefix> Course 1" course homepage with editing mode on
|
||||
And I open "<prefix> forum name" actions menu
|
||||
And "Move right" "link" in the "<prefix> forum name" "activity" should not be visible
|
||||
And "Move left" "link" in the "<prefix> forum name" "activity" should be visible
|
||||
And I am on "<format> Course 1" course homepage with editing mode on
|
||||
And I open "<format> forum name" actions menu
|
||||
And "Move right" "link" in the "<format> forum name" "activity" should not be visible
|
||||
And "Move left" "link" in the "<format> forum name" "activity" should be visible
|
||||
And I press the escape key
|
||||
And I open "<prefix> database name" actions menu
|
||||
And "Move right" "link" in the "<prefix> database name" "activity" should be visible
|
||||
And "Move left" "link" in the "<prefix> database name" "activity" should not be visible
|
||||
And I am on "<prefix> Course 2" course homepage with editing mode on
|
||||
And I open "<prefix> wiki name" actions menu
|
||||
And "Move right" "link" in the "<prefix> wiki name" "activity" should not be visible
|
||||
And "Move left" "link" in the "<prefix> wiki name" "activity" should be visible
|
||||
And I open "<format> database name" actions menu
|
||||
And "Move right" "link" in the "<format> database name" "activity" should be visible
|
||||
And "Move left" "link" in the "<format> database name" "activity" should not be visible
|
||||
And I am on "<format> Course 2" course homepage with editing mode on
|
||||
And I open "<format> wiki name" actions menu
|
||||
And "Move right" "link" in the "<format> wiki name" "activity" should not be visible
|
||||
And "Move left" "link" in the "<format> wiki name" "activity" should be visible
|
||||
|
||||
Examples:
|
||||
| format | prefix |
|
||||
| Custom sections | Sections |
|
||||
| Weekly sections | Weekly |
|
||||
| format |
|
||||
| Topics |
|
||||
| Weekly |
|
||||
|
||||
@@ -48,3 +48,25 @@ Feature: View task logs report and use its filters
|
||||
| operator | shouldornotsee |
|
||||
| Less than | should not see |
|
||||
| Greater than | should see |
|
||||
|
||||
@javascript
|
||||
Scenario: Reset task log filters
|
||||
Given I log in as "admin"
|
||||
And I change window size to "large"
|
||||
And I navigate to "Server > Tasks > Task logs" in site administration
|
||||
When I click on "Filters" "button"
|
||||
And I set the following fields in the "Result" "core_reportbuilder > Filter" to these values:
|
||||
| Result operator | Is equal to |
|
||||
| Result value | Fail |
|
||||
And I click on "Apply" "button" in the "[data-region='report-filters']" "css_element"
|
||||
Then I should see "Filters applied"
|
||||
And I should see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
|
||||
And I should see "Nothing to display"
|
||||
And I click on "Reset all" "button" in the "[data-region='report-filters']" "css_element"
|
||||
And I should see "Filters reset"
|
||||
And I should not see "Filters (1)" in the "#dropdownFiltersButton" "css_element"
|
||||
And I should see "Filters" in the "#dropdownFiltersButton" "css_element"
|
||||
And "[data-region='report-filters']" "css_element" should be visible
|
||||
And the following fields in the "Result" "core_reportbuilder > Filter" match these values:
|
||||
| Result operator | Is any value |
|
||||
And I should not see "Nothing to display"
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace core_admin\reportbuilder\local\filters;
|
||||
|
||||
use advanced_testcase;
|
||||
use lang_string;
|
||||
use core_reportbuilder\local\report\filter;
|
||||
|
||||
/**
|
||||
* Unit tests for course role report filter
|
||||
*
|
||||
* @package core_admin
|
||||
* @covers \core_admin\reportbuilder\local\filters\courserole
|
||||
* @copyright 2023 Paul Holden <paulh@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class courserole_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Data provider for {@see test_get_sql_filter}
|
||||
*
|
||||
* @return array[]
|
||||
*/
|
||||
public static function get_sql_filter_provider(): array {
|
||||
return [
|
||||
'Empty filter' => ['', '', '', ['admin', 'guest', 'user1', 'user2', 'user3', 'user4']],
|
||||
'Filter by role' => ['editingteacher', '', '', ['user1', 'user3', 'user4']],
|
||||
'Filter by role in category' => ['editingteacher', 'cat2', '', ['user1', 'user3']],
|
||||
'Filter by role in category and course' => ['editingteacher', 'cat2', 'course2', ['user1']],
|
||||
'Filter by role in course' => ['student', '', 'course2', ['user2']],
|
||||
'Filter by category' => ['', 'cat2', '', ['user1', 'user2', 'user3']],
|
||||
'Filter by category and course' => ['', 'cat2', 'course2', ['user1', 'user2']],
|
||||
'Filter by course' => ['', '', 'course3', ['user3']],
|
||||
'Filter by course (ensure whitespace is trimmed)' => ['', '', ' course3 ', ['user3']],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Test getting filter SQL
|
||||
*
|
||||
* @param string $rolename
|
||||
* @param string $categoryname
|
||||
* @param string $course
|
||||
* @param string[] $expectedusers
|
||||
*
|
||||
* @dataProvider get_sql_filter_provider
|
||||
*/
|
||||
public function test_get_sql_filter(
|
||||
string $rolename,
|
||||
string $categoryname,
|
||||
string $course,
|
||||
array $expectedusers,
|
||||
): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
// Create categories/course structure (categoryone: courseone; categorytwo: coursetwo/coursethree).
|
||||
$categoryone = $this->getDataGenerator()->create_category(['name' => 'cat1']);
|
||||
$courseone = $this->getDataGenerator()->create_course(['category' => $categoryone->id, 'shortname' => 'course1']);
|
||||
|
||||
$categorytwo = $this->getDataGenerator()->create_category(['name' => 'cat2']);
|
||||
$coursetwo = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course2']);
|
||||
$coursethree = $this->getDataGenerator()->create_course(['category' => $categorytwo->id, 'shortname' => 'course3']);
|
||||
|
||||
// User one is a teacher in courseone/coursetwo.
|
||||
$userone = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user1']);
|
||||
$this->getDataGenerator()->enrol_user($userone->id, $coursetwo->id, 'editingteacher');
|
||||
|
||||
// User two is a student in coursetwo.
|
||||
$usertwo = $this->getDataGenerator()->create_and_enrol($coursetwo, 'student', ['username' => 'user2']);
|
||||
|
||||
// User three is a teacher in courseone/coursethree.
|
||||
$userthree = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user3']);
|
||||
$this->getDataGenerator()->enrol_user($userthree->id, $coursethree->id, 'editingteacher');
|
||||
|
||||
// User four is a teacher in courseone.
|
||||
$userfour = $this->getDataGenerator()->create_and_enrol($courseone, 'editingteacher', ['username' => 'user4']);
|
||||
|
||||
$filter = new filter(
|
||||
courserole::class,
|
||||
'test',
|
||||
new lang_string('yes'),
|
||||
'testentity',
|
||||
'id',
|
||||
);
|
||||
|
||||
// Create instance of our filter, passing given operators (with lookups for role/category).
|
||||
[$select, $params] = courserole::create($filter)->get_sql_filter([
|
||||
$filter->get_unique_identifier() . '_role' => $DB->get_field('role', 'id', ['shortname' => $rolename]),
|
||||
$filter->get_unique_identifier() . '_category' => $DB->get_field('course_categories', 'id', ['name' => $categoryname]),
|
||||
$filter->get_unique_identifier() . '_course' => $course,
|
||||
]);
|
||||
|
||||
$users = $DB->get_fieldset_select('user', 'username', $select, $params);
|
||||
$this->assertEqualsCanonicalizing($expectedusers, $users);
|
||||
}
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Theme selector page for admin use.
|
||||
*
|
||||
* @package core_admin
|
||||
* @copyright 2023 David Woloszyn <david.woloszyn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__ . '/../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
|
||||
$choose = optional_param('choose', '', PARAM_PLUGIN);
|
||||
$reset = optional_param('reset', 0, PARAM_BOOL);
|
||||
$confirmation = optional_param('confirmation', 0, PARAM_BOOL);
|
||||
|
||||
admin_externalpage_setup('themeselector');
|
||||
|
||||
unset($SESSION->theme);
|
||||
|
||||
$PAGE->set_primary_active_tab('siteadminnode');
|
||||
$PAGE->navbar->add(get_string('themeselector', 'admin'), $PAGE->url);
|
||||
$PAGE->set_pagelayout('standard');
|
||||
|
||||
// Clear theme cache.
|
||||
if ($reset && confirm_sesskey()) {
|
||||
theme_reset_all_caches();
|
||||
}
|
||||
|
||||
$definedinconfig = array_key_exists('theme', $CFG->config_php_settings);
|
||||
if ($definedinconfig) {
|
||||
$forcedthemename = get_string('pluginname', 'theme_'.$CFG->theme);
|
||||
// Show a notification that the theme is defined in config.php.
|
||||
\core\notification::info(get_string('themedefinedinconfigphp', 'admin', $forcedthemename));
|
||||
}
|
||||
|
||||
// Change theme.
|
||||
if (!$definedinconfig && !empty($choose) && confirm_sesskey()) {
|
||||
|
||||
// Load the theme to make sure it is valid.
|
||||
$theme = theme_config::load($choose);
|
||||
|
||||
if ($theme instanceof \theme_config) {
|
||||
set_config('theme', $theme->name);
|
||||
$notifytype = 'success';
|
||||
$notifymessage = get_string('themesaved');
|
||||
} else {
|
||||
$notifytype = 'error';
|
||||
$notifymessage = get_string('error');
|
||||
}
|
||||
|
||||
// Redirect with notification.
|
||||
redirect(new moodle_url('/admin/themeselector.php'), $notifymessage, null, $notifytype);
|
||||
}
|
||||
|
||||
// Insert header.
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Prepare data for rendering.
|
||||
$data = [];
|
||||
$index = 0;
|
||||
$currentthemeindex = 0;
|
||||
$themes = core_component::get_plugin_list('theme');
|
||||
|
||||
// Loop through available themes.
|
||||
foreach ($themes as $themename => $themedir) {
|
||||
|
||||
try {
|
||||
$theme = theme_config::load($themename);
|
||||
} catch (Exception $e) {
|
||||
// Bad theme, just skip it for now.
|
||||
continue;
|
||||
}
|
||||
if ($themename !== $theme->name) {
|
||||
// Obsoleted or broken theme, just skip for now.
|
||||
continue;
|
||||
}
|
||||
if (empty($CFG->themedesignermode) && $theme->hidefromselector) {
|
||||
// The theme doesn't want to be shown in the theme selector and as theme
|
||||
// designer mode is switched off we will respect that decision.
|
||||
continue;
|
||||
}
|
||||
|
||||
// All params for modal use are set here, except for 'choosereadme' (description).
|
||||
// That string can be long. We will fetch it with JS as opposed to passing it as an attribute.
|
||||
$themedata = [];
|
||||
|
||||
// The 'name' param is formatted and should not to be confused with 'choose'.
|
||||
$themedata['name'] = get_string('pluginname', 'theme_'.$themename);;
|
||||
$themedata['choose'] = $themename;
|
||||
|
||||
// Image to display for previewing.
|
||||
$image = new moodle_url('/theme/image.php', ['theme' => $themename, 'image' => 'screenshot', 'component' => 'theme']);
|
||||
$themedata['image'] = $image;
|
||||
|
||||
// Is this the current theme?
|
||||
if ($themename === $CFG->theme) {
|
||||
$themedata['current'] = true;
|
||||
$currentthemeindex = $index;
|
||||
} else if (!$definedinconfig) {
|
||||
// Form params.
|
||||
$actionurl = new moodle_url('/admin/themeselector.php');
|
||||
$themedata['actionurl'] = $actionurl;
|
||||
$themedata['sesskey'] = sesskey();
|
||||
}
|
||||
|
||||
// Settings url.
|
||||
$settingspath = "$themedir/settings.php";
|
||||
if (file_exists($settingspath)) {
|
||||
$section = "themesetting{$themename}";
|
||||
$settingsurl = new moodle_url('/admin/settings.php', ['section' => $section]);
|
||||
$themedata['settingsurl'] = $settingsurl;
|
||||
}
|
||||
|
||||
// Link to the theme usage report if override enabled and it is being used in at least one context.
|
||||
if (\core\output\theme_usage::is_theme_used_in_any_context($themename) === \core\output\theme_usage::THEME_IS_USED) {
|
||||
$reporturl = new moodle_url($CFG->wwwroot . '/report/themeusage/index.php');
|
||||
$reporturl->params(['themechoice' => $themename]);
|
||||
$themedata['reporturl'] = $reporturl->out(false);
|
||||
}
|
||||
|
||||
$data[$index] = $themedata;
|
||||
$index++;
|
||||
}
|
||||
|
||||
// Reorder the array to always have the current theme first.
|
||||
if (isset($data[$currentthemeindex])) {
|
||||
$currenttheme = $data[$currentthemeindex];
|
||||
unset($data[$currentthemeindex]);
|
||||
array_unshift($data, $currenttheme);
|
||||
}
|
||||
|
||||
// Show theme selector.
|
||||
$renderable = new \core_admin\output\theme_selector($data, $definedinconfig);
|
||||
$renderer = $PAGE->get_renderer('core', 'admin');
|
||||
echo $renderer->theme_selector_list($renderable);
|
||||
|
||||
// Show footer.
|
||||
echo $OUTPUT->footer();
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
namespace tool_admin_presets\local\action;
|
||||
|
||||
use core_adminpresets\manager;
|
||||
use moodle_exception;
|
||||
|
||||
/**
|
||||
@@ -35,8 +34,8 @@ class delete extends base {
|
||||
public function show(): void {
|
||||
global $DB, $OUTPUT;
|
||||
|
||||
// Check the preset exists (cannot delete the pre-installed core "Starter" and "Full" presets).
|
||||
$presetdata = $DB->get_record('adminpresets', ['id' => $this->id, 'iscore' => manager::NONCORE_PRESET], 'name');
|
||||
// Getting the preset name.
|
||||
$presetdata = $DB->get_record('adminpresets', ['id' => $this->id], 'name');
|
||||
|
||||
if ($presetdata) {
|
||||
$deletetext = get_string('deletepreset', 'tool_admin_presets', $presetdata->name);
|
||||
@@ -65,7 +64,7 @@ class delete extends base {
|
||||
* Delete the DB preset
|
||||
*/
|
||||
public function execute(): void {
|
||||
require_sesskey();
|
||||
confirm_sesskey();
|
||||
|
||||
$this->manager->delete_preset($this->id);
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ class export extends base {
|
||||
* Stores a preset into the DB.
|
||||
*/
|
||||
public function execute(): void {
|
||||
confirm_sesskey();
|
||||
|
||||
$url = new \moodle_url('/admin/tool/admin_presets/index.php', ['action' => 'export', 'mode' => 'execute']);
|
||||
$this->moodleform = new export_form($url);
|
||||
|
||||
@@ -85,7 +87,7 @@ class export extends base {
|
||||
* @throws xml_writer_exception
|
||||
*/
|
||||
public function download_xml(): void {
|
||||
require_sesskey();
|
||||
confirm_sesskey();
|
||||
|
||||
list($xmlstr, $filename) = $this->manager->download_preset($this->id);
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ class import extends base {
|
||||
* Imports the xmlfile into DB
|
||||
*/
|
||||
public function execute(): void {
|
||||
confirm_sesskey();
|
||||
|
||||
$url = new \moodle_url('/admin/tool/admin_presets/index.php', ['action' => 'import', 'mode' => 'execute']);
|
||||
$this->moodleform = new import_form($url);
|
||||
|
||||
|
||||
@@ -38,6 +38,8 @@ class load extends base {
|
||||
public function execute(): void {
|
||||
global $OUTPUT;
|
||||
|
||||
confirm_sesskey();
|
||||
|
||||
$url = new \moodle_url('/admin/tool/admin_presets/index.php', ['action' => 'load', 'mode' => 'execute']);
|
||||
$this->moodleform = new load_form($url);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user