Compare commits
884 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 567ab3d5d1 | |||
| ebbad9ca59 | |||
| b2d737b90d | |||
| db46fe6c59 | |||
| b31ba08ffa | |||
| 365ecbead3 | |||
| 51bde4b0dc | |||
| 72f8b25b24 | |||
| ce75268a2f | |||
| 2d6e97b5c2 | |||
| f14fa82b5b | |||
| 4fd4f002ee | |||
| 139f1a0ad8 | |||
| fa8fb6fbe1 | |||
| 27d127b9c5 | |||
| 1174a463f3 | |||
| 33d0756aac | |||
| 41d01a8f98 | |||
| 67889ed5be | |||
| 65c1213e00 | |||
| df4907d146 | |||
| 85d91d18b4 | |||
| b0dd37fa73 | |||
| 4f5fba677a | |||
| 95ac714f8f | |||
| 1ea01c9c50 | |||
| 94587407ec | |||
| f3076b17b4 | |||
| b54ac35cb3 | |||
| 8b3a8b9438 | |||
| e3e619e845 | |||
| c345c3a460 | |||
| 81b1e515f4 | |||
| 218d2c0eb3 | |||
| 81fcfc2065 | |||
| 5c18bd041a | |||
| ad1b3e2a11 | |||
| e647d73811 | |||
| 554826ec78 | |||
| d23c5c8c8d | |||
| 9ea5796a63 | |||
| 061fd45c33 | |||
| 178d87e0b6 | |||
| ebdec47991 | |||
| 18c4978bba | |||
| 383b1ae15d | |||
| b53f8c676c | |||
| 6cae543378 | |||
| 53a51dab0a | |||
| cf0374d303 | |||
| 3194244721 | |||
| b1b9ddc302 | |||
| 9e96e0b36f | |||
| 93b0e733cc | |||
| 16227d8ef3 | |||
| 2950f9fb91 | |||
| 872fe961f8 | |||
| d98c246599 | |||
| bc890913fe | |||
| 6739845c85 | |||
| aaa49aa835 | |||
| 8ed8c68dfb | |||
| 6a59a0b349 | |||
| 1cb6ac499a | |||
| 9a5709f474 | |||
| efa18040dc | |||
| f2aa7e7bd9 | |||
| fe404e039c | |||
| 2a8f372e1c | |||
| a9cca2b893 | |||
| ae77a3d6d1 | |||
| 85ac3cdbb0 | |||
| 809233d23f | |||
| 166a09028f | |||
| a34068d126 | |||
| 7d0051154e | |||
| d19d7309e6 | |||
| ecccb0d30c | |||
| 3ece99e9d0 | |||
| 283375144b | |||
| 6d9f6af6ef | |||
| 5056eeab3a | |||
| 99913f0b50 | |||
| 9b9c08cdbb | |||
| 4f3a6d382e | |||
| 47f7b1e386 | |||
| e50f5d51a5 | |||
| 0f8a2d6734 | |||
| c01cbb3e1a | |||
| 44465eddef | |||
| ded031cfc8 | |||
| 9a7adbcd32 | |||
| d3d1f84271 | |||
| 4039f94021 | |||
| 382274be5b | |||
| 9909401af4 | |||
| c3732af3f3 | |||
| 180e818331 | |||
| a94e86d9cc | |||
| 2779372c17 | |||
| 7159a9ab0c | |||
| 953b8cb7c8 | |||
| 8c1d988566 | |||
| f570ad59cf | |||
| 0138da3949 | |||
| e7975d1443 | |||
| 753cde3442 | |||
| 38dbbecc4d | |||
| 9b2faf2056 | |||
| af61aeda9b | |||
| 9abda98e48 | |||
| be0f46f922 | |||
| 75dcdc098e | |||
| 35720ce43b | |||
| 2e97e1fee1 | |||
| 4ead6b97f0 | |||
| 46b091a67e | |||
| b61f86a052 | |||
| 867824322f | |||
| 92f2b31f74 | |||
| 445312d685 | |||
| 59d7b59a0b | |||
| 54df1bdcf7 | |||
| 256cd103ba | |||
| 48d1f7267b | |||
| bf980316b0 | |||
| 88546dad6b | |||
| f32bd23f8f | |||
| e0339be416 | |||
| fefe867a72 | |||
| eb81e0b50a | |||
| a1468ef48b | |||
| 795e302ea4 | |||
| a6d9d5f7e4 | |||
| ff51028d8d | |||
| e43bea4883 | |||
| 3f80f680ad | |||
| 5f100892d0 | |||
| e561b3b818 | |||
| 6837221beb | |||
| 475c4d7ca8 | |||
| 95a2aa2e1c | |||
| a3ac5646e4 | |||
| 91a5c94a00 | |||
| 44019add1f | |||
| e938870101 | |||
| 98eb681cc0 | |||
| d414753678 | |||
| 451d540527 | |||
| aab5ef2cbc | |||
| 378b622a09 | |||
| 888adbee07 | |||
| 6e56027b5b | |||
| bc1ded6ef4 | |||
| ff0cc2dc3c | |||
| ec0a000564 | |||
| e596ea8ca5 | |||
| 10c227830e | |||
| 1b46b00f98 | |||
| 1f7044c5b9 | |||
| dfaf8c5ad8 | |||
| 61b4aaab0a | |||
| 9b59cfbb52 | |||
| 01d1a3300b | |||
| aa86e76af8 | |||
| de14b56501 | |||
| ef19640b64 | |||
| b2095de913 | |||
| bc4ad1c39e | |||
| d59e64b4f1 | |||
| 5e01d61014 | |||
| b2c13a1120 | |||
| a39a67a436 | |||
| 27cc73e9e2 | |||
| 278ff79d84 | |||
| a8afcb2e4a | |||
| 64224cb840 | |||
| b5f8d6b1a1 | |||
| 4709d5dfcb | |||
| 9f724212ee | |||
| c8d840561c | |||
| 8f7dc60ad2 | |||
| d0841d8c4a | |||
| 66f2486da2 | |||
| 64aaf5ff59 | |||
| d77bdd910c | |||
| 7cd6eefe28 | |||
| 7eb83278bb | |||
| 616a362577 | |||
| b09ac036dc | |||
| 2e40d98863 | |||
| cbadf3ac6b | |||
| c67965f6d7 | |||
| f61e80bd87 | |||
| c055478914 | |||
| d5ef4a3706 | |||
| bbd073a455 | |||
| 996a5331ab | |||
| 27891b6a0d | |||
| 5c65da3a2e | |||
| bd9348c532 | |||
| 3668f28734 | |||
| a2e4255a34 | |||
| 1912e615f7 | |||
| a1c33bf60f | |||
| c46180ef04 | |||
| 3529bdaa22 | |||
| b40e2262d3 | |||
| e2133abd7b | |||
| 10d22b709c | |||
| 03edf12b9c | |||
| 62a16f7ca0 | |||
| f1fcb8e252 | |||
| f7e12e6d14 | |||
| 922fa7a2f2 | |||
| 7055d71865 | |||
| 2084e35009 | |||
| 069cea91f6 | |||
| 06ecd3de42 | |||
| acb947d98a | |||
| d0f1a93260 | |||
| 2183bea2f8 | |||
| dda9cf907f | |||
| f9b568088e | |||
| 256a84657b | |||
| 4dde5d381e | |||
| bf56548d60 | |||
| 7aee70bd08 | |||
| 67405a0d68 | |||
| b8b55ad3f4 | |||
| bbf6676fb4 | |||
| af22f8a159 | |||
| 5ff9e45817 | |||
| 389ba35049 | |||
| be454c9310 | |||
| 4e285f7f45 | |||
| ea26ec7524 | |||
| c0ed242820 | |||
| 352c88f166 | |||
| 263be92760 | |||
| 8489c94238 | |||
| feed83488b | |||
| bfc7fd680e | |||
| ba84a7e3f4 | |||
| 14f7892048 | |||
| 3648a75ef1 | |||
| 627cfe2398 | |||
| 905626ba79 | |||
| d67e511a9a | |||
| b0f0573e74 | |||
| e600e7c368 | |||
| 6967933d4a | |||
| 75a2731b32 | |||
| 73e226c971 | |||
| b53f9ed5f1 | |||
| be7a01b355 | |||
| 0fa77a0fb6 | |||
| 4c4acce05c | |||
| dbade23e87 | |||
| 214950de2a | |||
| 82d0c0b521 | |||
| 54d6ee8c08 | |||
| 2e735a14f9 | |||
| b8c31d0786 | |||
| 9ba2218a2a | |||
| 01b19e761f | |||
| 5c166e1f1a | |||
| 094fddd00f | |||
| d2acadec4c | |||
| c4bd64c245 | |||
| 853cae5ebc | |||
| 06e664ebbf | |||
| a815974aab | |||
| 2e24a0f873 | |||
| bce1ce2780 | |||
| ff7bacf32b | |||
| 1faf581711 | |||
| 4d6f159f68 | |||
| 17c67de63f | |||
| 3c069c16db | |||
| fe5146d598 | |||
| ad67b7eeea | |||
| 5208032b23 | |||
| 854e7b8ed0 | |||
| ead2dd9c16 | |||
| 2e89b87552 | |||
| 77fc63989e | |||
| dcf6ffd131 | |||
| d8a4ec8e68 | |||
| e6cc9e7e7d | |||
| f60f03732e | |||
| 50d5283cff | |||
| dc5f068009 | |||
| 44f63e0f22 | |||
| a1c1726249 | |||
| dc1329ff4c | |||
| d481dc01e4 | |||
| b02a001b6e | |||
| 89068f47cf | |||
| f2d1cbfae4 | |||
| 7db166d2e6 | |||
| 9a04ae9665 | |||
| aa683c28a8 | |||
| 68af175e84 | |||
| f386e713f1 | |||
| 16d73f6748 | |||
| 8dacf05f4b | |||
| 7bd521d654 | |||
| 463d31a871 | |||
| b4af6f22fc | |||
| a72cb6b487 | |||
| fccf727fd8 | |||
| 361b0abcc8 | |||
| 193982441d | |||
| 1116aded07 | |||
| 05392ca9aa | |||
| fc47609b41 | |||
| fb6d37154a | |||
| 7c5ed224f7 | |||
| 257b40c30c | |||
| cad0fdaad7 | |||
| aa3c00934c | |||
| a2808a8e04 | |||
| aa7c4bed07 | |||
| 87de9d4eae | |||
| b125674d97 | |||
| 1292a65011 | |||
| f87e97fa3a | |||
| 9a1c7bcce4 | |||
| 53512ca571 | |||
| 10a6b8a233 | |||
| 040dd3a96e | |||
| 6579770fee | |||
| 0986adb745 | |||
| 99f7e407f0 | |||
| 4193dd1a33 | |||
| dbf9d4ca75 | |||
| f82d9ae3eb | |||
| 2b8d27b29d | |||
| d3a379512f | |||
| 22af3705ce | |||
| 0f94bbec5b | |||
| 749e8dbe54 | |||
| 104560bcb6 | |||
| d95934f0ae | |||
| 12dcda9f4b | |||
| 3fe95f7007 | |||
| 5f14b92f65 | |||
| b54a69b11f | |||
| 38980e2047 | |||
| e6e1210e81 | |||
| a602c8023e | |||
| 81ec4cb7d1 | |||
| 631ee3b3e3 | |||
| dea76f367c | |||
| f10ac6371f | |||
| 5a1269a629 | |||
| 800b8ebcaf | |||
| b6ea64f734 | |||
| cf0ffe26e6 | |||
| 1fb8c6312f | |||
| 1fe1e78286 | |||
| 8f21c6ea96 | |||
| bc2a4e90cd | |||
| 52e9efa347 | |||
| a69ee4e7d3 | |||
| e4ccccc799 | |||
| ef126dbaff | |||
| 11e6e6c8e3 | |||
| b33cd6d8ba | |||
| 9bbbf76bae | |||
| a003bc4710 | |||
| 0bdea2767e | |||
| 15b9554a3b | |||
| 48426a041d | |||
| f08c3486a7 | |||
| c10236355a | |||
| cdd4d84eda | |||
| 6d7a12e085 | |||
| 4e70e41424 | |||
| 1401015347 | |||
| ad1485c866 | |||
| 56044641b0 | |||
| d3371a8778 | |||
| a111eada22 | |||
| 232ad11f86 | |||
| 533ce6d38d | |||
| 4a6ce8ace3 | |||
| d037aee9d3 | |||
| 9bb6b38dea | |||
| c0b2fb25c6 | |||
| 98b518c17a | |||
| 7b04c158a0 | |||
| 456c92917f | |||
| e86d1aacc0 | |||
| 69b8e578ea | |||
| 3241582038 | |||
| 325348beda | |||
| f5bd067fbe | |||
| d3a744ddf1 | |||
| d6b44eeea2 | |||
| e090357eb0 | |||
| 063642c4cb | |||
| c735752066 | |||
| 0bdb44d34f | |||
| 4275fb0ebe | |||
| 2afba12004 | |||
| e2f8826fa8 | |||
| 8d071293ac | |||
| d1c9a47b04 | |||
| 4339f877d4 | |||
| b292fa181c | |||
| 93ea68f50d | |||
| ac17792858 | |||
| 142c8f08c3 | |||
| 0a127f2b4e | |||
| 7d3472a753 | |||
| 634d3fd207 | |||
| 81711b63e4 | |||
| fd7218a4c1 | |||
| b28c953839 | |||
| 1e33a8a53b | |||
| 0c34179b52 | |||
| 642660aa35 | |||
| 75f61371a0 | |||
| f78700dc47 | |||
| 20d0c2e8ce | |||
| 9981108170 | |||
| d0991e9f02 | |||
| 870953541c | |||
| 25c6437296 | |||
| 5ff2c7d8a6 | |||
| 6ca893ecb2 | |||
| 9876fc13e1 | |||
| 26685f13a0 | |||
| 5f90d5f42d | |||
| 12b9fad2ed | |||
| ec75674961 | |||
| e66281a8b0 | |||
| a9745eb95a | |||
| 92992280ad | |||
| a84dfd422a | |||
| 211fedbad5 | |||
| bc3bf84afd | |||
| 89d1a3f83b | |||
| 5a906c5727 | |||
| 8127f39eee | |||
| 80b09028d1 | |||
| f8a00db3b2 | |||
| 070f816bc6 | |||
| 94d07f8ad9 | |||
| fec7104bec | |||
| 008fd8869c | |||
| b0ab180666 | |||
| f9d8799390 | |||
| fb52b37e38 | |||
| 41f75a63da | |||
| 55631fe3d4 | |||
| 3ab2388c5a | |||
| ff2e424d07 | |||
| 36fe93a53a | |||
| 1d69dc53ef | |||
| 2dcf1dabc3 | |||
| afeffc0a74 | |||
| c3cd93ddf1 | |||
| ba9e80c7c7 | |||
| 01478c3ae7 | |||
| b2f5f27afa | |||
| 9f16ba4a76 | |||
| e54c30d48d | |||
| 22b696c5c7 | |||
| 75832b8976 | |||
| 2e4b4ac7c2 | |||
| 0ce1d907e3 | |||
| a0d4ebd22a | |||
| 86f762d976 | |||
| b5f3ff575b | |||
| 900f56bcf2 | |||
| 86560bedd1 | |||
| 14dd6d9dcf | |||
| 7e0eef76d4 | |||
| 76d2a91004 | |||
| eea379ed55 | |||
| 2b6815b7dd | |||
| 66b1d84058 | |||
| f251776434 | |||
| 93c63eefb4 | |||
| f19e2ee750 | |||
| d7bb11f148 | |||
| 95dd0adc3b | |||
| 117e9a638c | |||
| 3a8736831c | |||
| ba120a362c | |||
| 0935b7f057 | |||
| 51c311b333 | |||
| 55f6a330ba | |||
| 81e264eb35 | |||
| 4ad98ddd26 | |||
| 32830571c6 | |||
| f16385e051 | |||
| 54fdc12876 | |||
| 0168e431aa | |||
| c45ef8bc2f | |||
| b68dc98398 | |||
| 7db80d7c10 | |||
| aa0b28c5e5 | |||
| 3804b919c0 | |||
| e7e317a5fc | |||
| 7802d9187b | |||
| 8f76e5565b | |||
| 2cf3857c74 | |||
| 9d9d8856b8 | |||
| 8d5d3539f5 | |||
| 14156fca7d | |||
| 9a27d73d5d | |||
| 4c3f695e58 | |||
| ce91756a53 | |||
| a6218b45e2 | |||
| 03a86c6d0b | |||
| 2c5bd27b75 | |||
| 3541d50ecc | |||
| a34afb637e | |||
| 71b091caf8 | |||
| 42c2ceb9ee | |||
| 2362ba8beb | |||
| be38a2b3e8 | |||
| e4ebb67b46 | |||
| 1b10b7b979 | |||
| 5865d62c35 | |||
| b7e1c7b48c | |||
| f97d3d2b1b | |||
| 6587d7eab1 | |||
| bbb76a0ef5 | |||
| 85fabe0539 | |||
| 5dc26908e3 | |||
| 834bce7f5c | |||
| 1b829e9ea5 | |||
| e9ec2b17aa | |||
| f0121062ef | |||
| 8520046ad2 | |||
| db60642ced | |||
| 36a826affb | |||
| 13c88d9b8d | |||
| bbb2f117c3 | |||
| c99d5f6492 | |||
| 5e92d726cb | |||
| 8fce1ed876 | |||
| 97921bc354 | |||
| e8623f580a | |||
| 247f5bee76 | |||
| 566abee0a9 | |||
| f51aafc730 | |||
| a0aef397f8 | |||
| d454a4ece8 | |||
| 409649db96 | |||
| 2916c971cd | |||
| 2b2f987725 | |||
| 6c57573b7c | |||
| b74243950e | |||
| 6850c24a9c | |||
| f809ee9e45 | |||
| d95dbc01e2 | |||
| a899a7af13 | |||
| 645816a244 | |||
| a176f71a43 | |||
| c2c4302d74 | |||
| 01989e77ac | |||
| cf9e808967 | |||
| 65e74ad477 | |||
| 576c6bf5c8 | |||
| 01258058c2 | |||
| 0e116ee392 | |||
| 353d1888aa | |||
| 4a5fb82772 | |||
| 4d4ea7647d | |||
| ccc259b268 | |||
| d16cdbd81f | |||
| 3617ae07f3 | |||
| dccbafa7e9 | |||
| db0f899c72 | |||
| 505b87d89d | |||
| 13df246e98 | |||
| a1cd2000fb | |||
| 8069645f56 | |||
| e4ddf13091 | |||
| a1409ba644 | |||
| 81a3c47001 | |||
| 08aeda7b07 | |||
| 49e4b4922b | |||
| 97ef1d1420 | |||
| 1eb45d6e2b | |||
| 9c56531610 | |||
| 0d8bbb774e | |||
| 518f8a7ced | |||
| c0fbed07ee | |||
| ebbb58556a | |||
| 0f479ba76e | |||
| 3c3ed4c0f8 | |||
| 17babdbaf7 | |||
| dcc8e34187 | |||
| 39dce68e4a | |||
| 374639d3e6 | |||
| 62fe924127 | |||
| 69e22263ad | |||
| a8c51a689d | |||
| a88106bdd9 | |||
| d3b1d6a004 | |||
| 51ddd51271 | |||
| 6d5aecf22e | |||
| 0e4483cf57 | |||
| a286741d9c | |||
| d9ddd1d13d | |||
| 82470d8ebc | |||
| 0272a95dc8 | |||
| 048f8d9ae7 | |||
| e259354c91 | |||
| 5994edb30b | |||
| 0d8ad43873 | |||
| 91d5491ee2 | |||
| 8d94e92599 | |||
| 8e00c5c8ed | |||
| 078babf6d2 | |||
| 9a03fe6ebd | |||
| 8a48bf5beb | |||
| 2780c284c5 | |||
| e73d9075e9 | |||
| fabb658ff6 | |||
| 9a30a23456 | |||
| 38436bfd65 | |||
| 0cad1c25dc | |||
| 656808ea40 | |||
| 80ea373e2c | |||
| 680ebf2315 | |||
| bab4badd06 | |||
| 13f89eaf11 | |||
| c72cac3879 | |||
| 7238ffc65d | |||
| 75bc323bf1 | |||
| 15d4f7a72a | |||
| e056d8b19d | |||
| 26ec60a016 | |||
| 2de94975a3 | |||
| ab7493b61c | |||
| b826a2a180 | |||
| 384711fe8c | |||
| 401c7b680d | |||
| 333097ea67 | |||
| 1d96718214 | |||
| 012f850733 | |||
| 690d2c69a3 | |||
| a0c5c98dc5 | |||
| 9e1feec44b | |||
| 2a416b3466 | |||
| a3fbe80044 | |||
| 38ac93aace | |||
| 403a814535 | |||
| 7dabe1053c | |||
| e1011a09cf | |||
| 81c8f80dae | |||
| 65d64de0cd | |||
| fed63e1d27 | |||
| 94d60b142c | |||
| 561f53a702 | |||
| 27527f6c36 | |||
| a53db0ab73 | |||
| e493cb7d9c | |||
| 0dc39f21c3 | |||
| 2d89b5ea52 | |||
| 6af476cab2 | |||
| 785f9f97a8 | |||
| 110843c03c | |||
| 396e086575 | |||
| c2ab40848b | |||
| 7f4cd77843 | |||
| b074e8a1a2 | |||
| affd686294 | |||
| 2d645be2a5 | |||
| fc1c26b8c0 | |||
| 3891d6d398 | |||
| 33b8447c60 | |||
| 755f2c3eae | |||
| 9f5dd71d82 | |||
| c4ad68a8b7 | |||
| 5276206f43 | |||
| 890de8ab6a | |||
| 747f4468fb | |||
| 86ecd214da | |||
| 2fae9db702 | |||
| 8ec0823dfe | |||
| 0f64a45eaf | |||
| 38b700180f | |||
| 31f6946c8f | |||
| 5a03c7b447 | |||
| d242d558ae | |||
| 60059b9216 | |||
| 14695e5f4c | |||
| ae73287803 | |||
| 0b8f8f3402 | |||
| 89db762c0e | |||
| 5d11d337d2 | |||
| e6e3aa975a | |||
| e8af997888 | |||
| 464f907c4c | |||
| 3f355629ee | |||
| 5adb27669c | |||
| e794852ff5 | |||
| 23c63a1afe | |||
| c44388a7cf | |||
| 61bc523600 | |||
| 4ee2ff34b1 | |||
| df1e5786c2 | |||
| 4818800a69 | |||
| 8b936c2483 | |||
| 89a1d7cc73 | |||
| 2f1de062c6 | |||
| 500202997b | |||
| a17167118a | |||
| 7361129133 | |||
| f3629d3204 | |||
| 116a88c6bc | |||
| 97898d4faa | |||
| 122214a8db | |||
| b957465b35 | |||
| 59a0253332 | |||
| 04422a0396 | |||
| c3033419cc | |||
| a99bf936fb | |||
| 84a77ce35d | |||
| cc3992585a | |||
| c2176f5451 | |||
| 00802d0930 | |||
| ff4cc15c72 | |||
| 1caf3fe169 | |||
| d69efaf872 | |||
| 3e7d409d72 | |||
| b967175480 | |||
| 9678041d7d | |||
| 1a62cb7567 | |||
| 3a1a3639aa | |||
| 89349cd5a7 | |||
| 4211ec36a5 | |||
| 328a9d57ca | |||
| 62f2a0d05a | |||
| 278eba8cfa | |||
| 36f5996a19 | |||
| 54e328d0f6 | |||
| 4e07b2cfbd | |||
| ae5cf0490f | |||
| 6f08d4ee0b | |||
| ad552b3502 | |||
| 3de05a67ed | |||
| 5e3989dfcf | |||
| e634f04355 | |||
| 5eb6f7500a | |||
| 694b4d4274 | |||
| baddb058a9 | |||
| 8d77d104bf | |||
| 6a66d9b08d | |||
| f788c16f00 | |||
| 66620e48b7 | |||
| f3a92d07b6 | |||
| 8dfc18bed3 | |||
| 1199aab2c1 | |||
| 48cf88458c | |||
| 45600c4a0b | |||
| 4b0075414e | |||
| b9c333f5db | |||
| ea5431e351 | |||
| 4c4295061c | |||
| 33eb190484 | |||
| 1240c086eb | |||
| f056d6fb88 | |||
| 8fa1397886 | |||
| 0baa4c581e | |||
| 998305db0a | |||
| fd9c9c807f | |||
| 66270fd6e6 | |||
| 07ae362341 | |||
| 51ad4489b9 | |||
| 3439a8196e | |||
| 165d174c7f | |||
| 3874af089a | |||
| 28c0272a16 | |||
| 7bf842111f | |||
| 8cf4568280 | |||
| 5526ce914b | |||
| a5ef15bbb0 | |||
| d4e7c98dd6 | |||
| 184ed2b8f9 | |||
| 2fe04a14e2 | |||
| f6dd11e3ff | |||
| 2825fc7249 | |||
| cfb85df80c | |||
| 8229a2b85d | |||
| fc1a399565 | |||
| f4b608041c | |||
| 0e967898bd | |||
| 6e1654b79b | |||
| 3c5a929ef2 | |||
| e45ba0143b | |||
| 63f070cab1 | |||
| b61dfdaf8f | |||
| 021f11b6b6 | |||
| 516280b3a0 | |||
| 90c5e7f8d1 | |||
| 2d98e42166 | |||
| a4e43f3d13 | |||
| 014be0ff8b | |||
| 5afb2e2601 | |||
| f907ed40e6 | |||
| be2dd2fd10 | |||
| 9c56b617f5 | |||
| d5956a3f17 | |||
| 986906d64b | |||
| 2ce6daca4b | |||
| 9620e23384 | |||
| 502a3b29b6 | |||
| 597b71cf55 | |||
| f190723ad5 | |||
| 83da404228 | |||
| 411a25c7eb | |||
| 1e7d81b51d | |||
| 1ef65952ee | |||
| b7075e690c | |||
| d1d6c611ef | |||
| 3e520d2b7c | |||
| b521ed1eae | |||
| 9d9a0b070a | |||
| 0084e7efd7 | |||
| 64a5038847 | |||
| 8dcf53b73e | |||
| a923ed028d | |||
| c4277bcdd0 | |||
| c78df8f42b | |||
| ddf844a904 | |||
| 3e443eb1f3 | |||
| fd673f2b8d | |||
| 616de3dff9 | |||
| b93f4c7570 | |||
| 1a968ade33 | |||
| 68d41752c5 | |||
| 48c50f4e7f | |||
| a15378e431 | |||
| e30f11ede6 | |||
| 607d46adc9 | |||
| f548f950ea | |||
| 491f57a2b0 | |||
| 9a99818016 | |||
| 0b6cc260c7 | |||
| 4789682191 | |||
| 5ddcdfd743 | |||
| 9873593120 | |||
| 8b94100661 | |||
| 3f0687bcdf | |||
| a9bb11731c | |||
| c773d10247 | |||
| 7e0516eab3 | |||
| 45e37067f6 | |||
| 4529cf6c76 | |||
| 81ebc2746e | |||
| 5821639bb7 | |||
| 12c17ffaee | |||
| 05d6d57101 | |||
| 663287d08f | |||
| eb7fb32928 | |||
| 1542f9d5b0 | |||
| 7634d30a74 | |||
| 9376718334 | |||
| e265092be4 | |||
| b7191a5616 | |||
| 8aa81abdc0 | |||
| bc1d433972 | |||
| 7ba8e5dbd9 | |||
| 4b25851bcc | |||
| 48125a9408 | |||
| 5dda224ef6 | |||
| 4641507d92 | |||
| 9b67f1b9db | |||
| 7bed522217 | |||
| f2f35e85d8 | |||
| 0e5b2e1997 | |||
| b63ab17d52 | |||
| dc325d9891 | |||
| 59a5dbe18b |
@@ -0,0 +1,4 @@
|
||||
**/yui/build/** -diff
|
||||
**/amd/build/** -diff
|
||||
theme/bootstrapbase/style/editor.css -diff
|
||||
theme/bootstrapbase/style/moodle.css -diff
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
# PLEASE NOTE: Travis is not currently utilised by the Moodle core integration
|
||||
# process (which uses our internal CI system) this file is here for the benefit
|
||||
# of community developers git clones - see MDL-51458.
|
||||
|
||||
sudo: false
|
||||
|
||||
# We currently disable Travis notifications entirely until https://github.com/travis-ci/travis-ci/issues/4976
|
||||
# is fixed.
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
# We only run the highest and lowest supported versions to reduce the load on travis-ci.org.
|
||||
- 5.6
|
||||
# - 5.5
|
||||
- 5.4
|
||||
|
||||
env:
|
||||
# Although we want to run these jobs and see failures as quickly as possible, we also want to get the slowest job to
|
||||
# start first so that the total run time is not too high.
|
||||
#
|
||||
# We only run MySQL on PHP 5.6, so run that first.
|
||||
# CI Tests should be second-highest in priority as these only take <= 60 seconds to run under normal circumstances.
|
||||
# Postgres is significantly is pretty reasonable in its run-time.
|
||||
|
||||
# Run unit tests on MySQL
|
||||
- DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
|
||||
# Run CI Tests without running PHPUnit.
|
||||
- DB=none PHPUNIT=false INSTALL=false CITEST=true
|
||||
|
||||
# Run unit tests on Postgres
|
||||
- DB=pgsql PHPUNIT=true INSTALL=false CITEST=false
|
||||
|
||||
matrix:
|
||||
# Enable fast finish.
|
||||
# This will fail the build if a single job fails (except those in allow_failures).
|
||||
# It will not stop the jobs from running.
|
||||
fast_finish: true
|
||||
|
||||
exclude:
|
||||
# MySQL - it's just too slow.
|
||||
# Exclude it on all versions except for latest.
|
||||
# - env: DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
# php: 5.6
|
||||
#
|
||||
# - env: DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
# php: 5.5
|
||||
|
||||
- env: DB=mysqli PHPUNIT=true INSTALL=false CITEST=false
|
||||
php: 5.4
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache
|
||||
|
||||
install:
|
||||
# Disable xdebug. We aren't generating code coverage, and it has a huge impact upon test performance.
|
||||
- rm /home/travis/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini
|
||||
|
||||
# Set the encrypted GITHUB_TOKEN if it's available to raise the API limit.
|
||||
- if [ -n "$GITHUB_APITOKEN" ]; then composer config github-oauth.github.com $GITHUB_APITOKEN; fi
|
||||
|
||||
# Install composer dependencies.
|
||||
# We need --no-interaction in case we hit API limits for composer. This causes it to fall back to a standard clone.
|
||||
# Typically it should be able to use the Composer cache if any other job has already completed before we started here.
|
||||
- travis_retry composer install --prefer-dist --no-interaction
|
||||
|
||||
before_script:
|
||||
- >
|
||||
if [ "$INSTALL" = 'true' -o "$PHPUNIT" = 'true' ];
|
||||
then
|
||||
# Copy generic configuration in place.
|
||||
cp config-dist.php config.php ;
|
||||
|
||||
# Create the moodledata directory.
|
||||
mkdir -p "$HOME"/roots/base
|
||||
|
||||
# The database name and password.
|
||||
sed -i \
|
||||
-e "s%= 'moodle'%= 'travis_ci_test'%" \
|
||||
-e "s%= 'password'%= ''%" \
|
||||
config.php ;
|
||||
|
||||
# The wwwroot and dataroot.
|
||||
sed -i \
|
||||
-e "s%http://example.com/moodle%http://localhost%" \
|
||||
-e "s%/home/example/moodledata%/home/travis/roots/base%" \
|
||||
config.php ;
|
||||
|
||||
if [ "$DB" = 'pgsql' ];
|
||||
then
|
||||
# Postgres-specific setup.
|
||||
sed -i \
|
||||
-e "s%= 'username'%= 'postgres'%" \
|
||||
config.php ;
|
||||
|
||||
psql -c 'CREATE DATABASE travis_ci_test;' -U postgres;
|
||||
fi
|
||||
|
||||
if [ "$DB" = 'mysqli' ];
|
||||
then
|
||||
# MySQL-specific setup.
|
||||
sed -i \
|
||||
-e "s%= 'pgsql'%= 'mysqli'%" \
|
||||
-e "s%= 'username'%= 'travis'%" \
|
||||
config.php;
|
||||
|
||||
mysql -u root -e 'SET GLOBAL innodb_file_format=barracuda;' ;
|
||||
mysql -u root -e 'SET GLOBAL innodb_file_per_table=ON;' ;
|
||||
mysql -e 'CREATE DATABASE travis_ci_test DEFAULT CHARACTER SET utf8 DEFAULT COLLATE utf8_bin;' ;
|
||||
fi
|
||||
|
||||
if [ "$PHPUNIT" = 'true' ];
|
||||
then
|
||||
# Create a directory for the phpunit dataroot.
|
||||
mkdir -p "$HOME"/roots/phpunit
|
||||
|
||||
# The phpunit dataroot and prefix..
|
||||
sed -i \
|
||||
-e "/require_once/i \\\$CFG->phpunit_dataroot = '\/home\/travis\/roots\/phpunit';" \
|
||||
-e "/require_once/i \\\$CFG->phpunit_prefix = 'p_';" \
|
||||
config.php ;
|
||||
|
||||
# Initialise PHPUnit for Moodle.
|
||||
php admin/tool/phpunit/cli/init.php
|
||||
fi
|
||||
fi
|
||||
|
||||
script:
|
||||
########################################################################
|
||||
# PHPUnit
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$PHPUNIT" = 'true' ];
|
||||
then
|
||||
vendor/bin/phpunit;
|
||||
fi
|
||||
|
||||
########################################################################
|
||||
# CI Tests
|
||||
########################################################################
|
||||
- >
|
||||
if [ "$CITEST" = 'true' ];
|
||||
then
|
||||
# Note - this is deliberately placed in the script section as we
|
||||
# should not add any code until after phpunit has run.
|
||||
|
||||
# The following repositories are required.
|
||||
# The local_ci repository does the actual checking.
|
||||
git clone https://github.com/moodlehq/moodle-local_ci.git local/ci
|
||||
|
||||
# We need the official upstream for comparison
|
||||
git remote add upstream https://github.com/moodle/moodle.git;
|
||||
|
||||
git fetch upstream MOODLE_29_STABLE;
|
||||
export GIT_PREVIOUS_COMMIT="`git merge-base FETCH_HEAD $TRAVIS_COMMIT`";
|
||||
export GIT_COMMIT="$TRAVIS_COMMIT";
|
||||
export UPSTREAM_FETCH_HEAD=`git rev-parse FETCH_HEAD`
|
||||
|
||||
# Variables required by our linter.
|
||||
export gitcmd=`which git`;
|
||||
export gitdir="$TRAVIS_BUILD_DIR";
|
||||
export phpcmd=`which php`;
|
||||
fi
|
||||
|
||||
# Actually run the CI Tests - do this outside of the main test to make output clearer.
|
||||
- >
|
||||
if [ "$CITEST" = 'true' ];
|
||||
then
|
||||
bash local/ci/php_lint/php_lint.sh;
|
||||
fi
|
||||
+162
-141
@@ -12,6 +12,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
/* jshint node: true, browser: false */
|
||||
|
||||
/**
|
||||
* @copyright 2014 Andrew Nicols
|
||||
@@ -24,100 +25,163 @@
|
||||
|
||||
module.exports = function(grunt) {
|
||||
var path = require('path'),
|
||||
fs = require('fs'),
|
||||
tasks = {},
|
||||
cwd = process.env.PWD || process.cwd();
|
||||
|
||||
// Windows users can't run grunt in a subdirectory, so allow them to set
|
||||
// the root by passing --root=path/to/dir.
|
||||
if (grunt.option('root')) {
|
||||
var root = grunt.option('root');
|
||||
if (grunt.file.exists(__dirname, root)) {
|
||||
cwd = path.join(__dirname, root);
|
||||
grunt.log.ok('Setting root to '+cwd);
|
||||
} else {
|
||||
grunt.fail.fatal('Setting root to '+root+' failed - path does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
var inAMD = path.basename(cwd) == 'amd';
|
||||
|
||||
// Globbing pattern for matching all AMD JS source files.
|
||||
var amdSrc = [inAMD ? cwd + '/src/*.js' : '**/amd/src/*.js'];
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
* @param {String} destPath the current destination
|
||||
* @param {String} srcPath the matched src path
|
||||
* @return {String} The rewritten destination path.
|
||||
*/
|
||||
var uglify_rename = function (destPath, srcPath) {
|
||||
destPath = srcPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
destPath = path.resolve(cwd, destPath);
|
||||
return destPath;
|
||||
};
|
||||
|
||||
// Project configuration.
|
||||
grunt.initConfig({
|
||||
jshint: {
|
||||
options: {jshintrc: '.jshintrc'},
|
||||
files: ['**/amd/src/*.js']
|
||||
amd: { src: amdSrc }
|
||||
},
|
||||
uglify: {
|
||||
dynamic_mappings: {
|
||||
files: grunt.file.expandMapping(
|
||||
['**/src/*.js', '!**/node_modules/**'],
|
||||
'',
|
||||
{
|
||||
cwd: cwd,
|
||||
rename: function(destBase, destPath) {
|
||||
destPath = destPath.replace('src', 'build');
|
||||
destPath = destPath.replace('.js', '.min.js');
|
||||
destPath = path.resolve(cwd, destPath);
|
||||
return destPath;
|
||||
}
|
||||
}
|
||||
)
|
||||
amd: {
|
||||
files: [{
|
||||
expand: true,
|
||||
src: amdSrc,
|
||||
rename: uglify_rename
|
||||
}]
|
||||
}
|
||||
},
|
||||
less: {
|
||||
bootstrapbase: {
|
||||
files: {
|
||||
"theme/bootstrapbase/style/moodle.css": "theme/bootstrapbase/less/moodle.less",
|
||||
"theme/bootstrapbase/style/editor.css": "theme/bootstrapbase/less/editor.less",
|
||||
},
|
||||
options: {
|
||||
compress: true
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
options: {
|
||||
nospawn: true // We need not to spawn so config can be changed dynamically.
|
||||
},
|
||||
amd: {
|
||||
files: ['**/amd/src/**/*.js'],
|
||||
tasks: ['amd']
|
||||
},
|
||||
bootstrapbase: {
|
||||
files: ["theme/bootstrapbase/less/**/*.less"],
|
||||
tasks: ["less:bootstrapbase"]
|
||||
},
|
||||
yui: {
|
||||
files: ['**/yui/src/**/*.js'],
|
||||
tasks: ['shifter']
|
||||
},
|
||||
},
|
||||
shifter: {
|
||||
options: {
|
||||
recursive: true,
|
||||
paths: [cwd]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Shifter task. Is configured with a path to a specific file or a directory,
|
||||
* in the case of a specific file it will work out the right module to be built.
|
||||
*
|
||||
* Note that this task runs the invidiaul shifter jobs async (becase it spawns
|
||||
* so be careful to to call done().
|
||||
*/
|
||||
tasks.shifter = function() {
|
||||
var exec = require('child_process').spawn,
|
||||
var async = require('async'),
|
||||
done = this.async(),
|
||||
args = [],
|
||||
options = {
|
||||
recursive: true,
|
||||
watch: false,
|
||||
walk: false,
|
||||
module: false
|
||||
},
|
||||
shifter;
|
||||
options = grunt.config('shifter.options');
|
||||
|
||||
// Run the shifter processes one at a time to avoid confusing output.
|
||||
async.eachSeries(options.paths, function (src, filedone) {
|
||||
var args = [];
|
||||
args.push( path.normalize(__dirname + '/node_modules/shifter/bin/shifter'));
|
||||
|
||||
// Determine the most appropriate options to run with based upon the current location.
|
||||
if (path.basename(cwd) === 'src') {
|
||||
// Detect whether we're in a src directory.
|
||||
grunt.log.debug('In a src directory');
|
||||
args.push('--walk');
|
||||
options.walk = true;
|
||||
} else if (path.basename(path.dirname(cwd)) === 'src') {
|
||||
// Detect whether we're in a module directory.
|
||||
grunt.log.debug('In a module directory');
|
||||
options.module = true;
|
||||
}
|
||||
|
||||
if (grunt.option('watch')) {
|
||||
if (!options.walk && !options.module) {
|
||||
grunt.fail.fatal('Unable to watch unless in a src or module directory');
|
||||
}
|
||||
|
||||
// It is not advisable to run with recursivity and watch - this
|
||||
// leads to building the build directory in a race-like fashion.
|
||||
grunt.log.debug('Detected a watch - disabling recursivity');
|
||||
options.recursive = false;
|
||||
args.push('--watch');
|
||||
}
|
||||
|
||||
if (options.recursive) {
|
||||
args.push('--recursive');
|
||||
}
|
||||
|
||||
// Always ignore the node_modules directory.
|
||||
args.push('--excludes', 'node_modules');
|
||||
|
||||
// Determine the most appropriate options to run with based upon the current location.
|
||||
if (grunt.file.isMatch('**/yui/**/*.js', src)) {
|
||||
// When passed a JS file, build our containing module (this happen with
|
||||
// watch).
|
||||
grunt.log.debug('Shifter passed a specific JS file');
|
||||
src = path.dirname(path.dirname(src));
|
||||
options.recursive = false;
|
||||
} else if (grunt.file.isMatch('**/yui/src', src)) {
|
||||
// When in a src directory --walk all modules.
|
||||
grunt.log.debug('In a src directory');
|
||||
args.push('--walk');
|
||||
options.recursive = false;
|
||||
} else if (grunt.file.isMatch('**/yui/src/*', src)) {
|
||||
// When in module, only build our module.
|
||||
grunt.log.debug('In a module directory');
|
||||
options.recursive = false;
|
||||
} else if (grunt.file.isMatch('**/yui/src/*/js', src)) {
|
||||
// When in module src, only build our module.
|
||||
grunt.log.debug('In a source directory');
|
||||
src = path.dirname(src);
|
||||
options.recursive = false;
|
||||
}
|
||||
|
||||
if (grunt.option('watch')) {
|
||||
grunt.fail.fatal('The --watch option has been removed, please use `grunt watch` instead');
|
||||
}
|
||||
|
||||
// Add the stderr option if appropriate
|
||||
if (grunt.option('verbose')) {
|
||||
args.push('--lint-stderr');
|
||||
}
|
||||
|
||||
if (grunt.option('no-color')) {
|
||||
args.push('--color=false');
|
||||
}
|
||||
|
||||
var execShifter = function() {
|
||||
|
||||
shifter = exec("node", args, {
|
||||
cwd: cwd,
|
||||
stdio: 'inherit',
|
||||
env: process.env
|
||||
});
|
||||
|
||||
// Tidy up after exec.
|
||||
shifter.on('exit', function (code) {
|
||||
grunt.log.ok("Running shifter on " + src);
|
||||
grunt.util.spawn({
|
||||
cmd: "node",
|
||||
args: args,
|
||||
opts: {cwd: src, stdio: 'inherit', env: process.env}
|
||||
}, function (error, result, code) {
|
||||
if (code) {
|
||||
grunt.fail.fatal('Shifter failed with code: ' + code);
|
||||
} else {
|
||||
grunt.log.ok('Shifter build complete.');
|
||||
done();
|
||||
filedone();
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -127,79 +191,15 @@ module.exports = function(grunt) {
|
||||
execShifter();
|
||||
} else {
|
||||
// Check that there are yui modules otherwise shifter ends with exit code 1.
|
||||
var found = false;
|
||||
var hasYuiModules = function(directory, callback) {
|
||||
fs.readdir(directory, function(err, files) {
|
||||
if (err) {
|
||||
return callback(err, null);
|
||||
}
|
||||
|
||||
// If we already found a match there is no need to continue scanning.
|
||||
if (found === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We need to track the number of files to know when we return a result.
|
||||
var pending = files.length;
|
||||
|
||||
// We first check files, so if there is a match we don't need further
|
||||
// async calls and we just return a true.
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i] === 'yui') {
|
||||
return callback(null, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through subdirs if there were no matches.
|
||||
files.forEach(function (file) {
|
||||
|
||||
var p = path.join(directory, file);
|
||||
stat = fs.statSync(p);
|
||||
if (!stat.isDirectory()) {
|
||||
pending--;
|
||||
} else {
|
||||
|
||||
// We defer the pending-1 until we scan the whole dir and subdirs.
|
||||
hasYuiModules(p, function(err, result) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
if (result === true) {
|
||||
// Once we get a true we notify the caller.
|
||||
found = true;
|
||||
return callback(null, true);
|
||||
}
|
||||
|
||||
pending--;
|
||||
if (pending === 0) {
|
||||
// Notify the caller that the whole dir has been scaned and there are no matches.
|
||||
return callback(null, false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// No subdirs here, otherwise the return would be deferred until all subdirs are scanned.
|
||||
if (pending === 0) {
|
||||
return callback(null, false);
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
hasYuiModules(cwd, function(err, result) {
|
||||
if (err) {
|
||||
grunt.fail.fatal(err.message);
|
||||
}
|
||||
|
||||
if (result === true) {
|
||||
execShifter();
|
||||
} else {
|
||||
grunt.log.ok('No YUI modules to build.');
|
||||
done();
|
||||
}
|
||||
});
|
||||
if (grunt.file.expand({cwd: src}, '**/yui/src/**/*.js').length > 0) {
|
||||
args.push('--recursive');
|
||||
execShifter();
|
||||
} else {
|
||||
grunt.log.ok('No YUI modules to build.');
|
||||
filedone();
|
||||
}
|
||||
}
|
||||
}, done);
|
||||
};
|
||||
|
||||
tasks.startup = function() {
|
||||
@@ -207,24 +207,45 @@ module.exports = function(grunt) {
|
||||
if (path.basename(path.resolve(cwd, '../../')) == 'yui') {
|
||||
grunt.task.run('shifter');
|
||||
// Are we in an AMD directory?
|
||||
} else if (path.basename(cwd) == 'amd') {
|
||||
grunt.task.run('jshint');
|
||||
grunt.task.run('uglify');
|
||||
} else if (inAMD) {
|
||||
grunt.task.run('amd');
|
||||
} else {
|
||||
// Run them all!.
|
||||
grunt.task.run('shifter');
|
||||
grunt.task.run('jshint');
|
||||
grunt.task.run('uglify');
|
||||
grunt.task.run('css');
|
||||
grunt.task.run('js');
|
||||
}
|
||||
};
|
||||
|
||||
// On watch, we dynamically modify config to build only affected files. This
|
||||
// method is slightly complicated to deal with multiple changed files at once (copied
|
||||
// from the grunt-contrib-watch readme).
|
||||
var changedFiles = Object.create(null);
|
||||
var onChange = grunt.util._.debounce(function() {
|
||||
var files = Object.keys(changedFiles);
|
||||
grunt.config('jshint.amd.src', files);
|
||||
grunt.config('uglify.amd.files', [{ expand: true, src: files, rename: uglify_rename }]);
|
||||
grunt.config('shifter.options.paths', files);
|
||||
changedFiles = Object.create(null);
|
||||
}, 200);
|
||||
|
||||
grunt.event.on('watch', function(action, filepath) {
|
||||
changedFiles[filepath] = action;
|
||||
onChange();
|
||||
});
|
||||
|
||||
// Register NPM tasks.
|
||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
||||
grunt.loadNpmTasks('grunt-contrib-less');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
// Register the shifter task.
|
||||
// Register JS tasks.
|
||||
grunt.registerTask('shifter', 'Run Shifter against the current directory', tasks.shifter);
|
||||
grunt.registerTask('amd', ['jshint', 'uglify']);
|
||||
grunt.registerTask('js', ['amd', 'shifter']);
|
||||
|
||||
// Register CSS taks.
|
||||
grunt.registerTask('css', ['less:bootstrapbase']);
|
||||
|
||||
// Register the startup task.
|
||||
grunt.registerTask('startup', 'Run the correct tasks for the current directory', tasks.startup);
|
||||
|
||||
+2
-1
@@ -155,7 +155,8 @@
|
||||
} else if ($blocksettings instanceof admin_settingpage) {
|
||||
$settings = '<a href="'.$CFG->wwwroot.'/'.$CFG->admin.'/settings.php?section=blocksetting'.$block->name.'">'.$strsettings.'</a>';
|
||||
} else {
|
||||
$settings = '<a href="block.php?block='.$blockid.'">'.$strsettings.'</a>';
|
||||
debugging('Warning: block_'.$block->name.' returns true in has_config() but does not provide a settings.php file',
|
||||
DEBUG_DEVELOPER);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+285
-1
@@ -1434,7 +1434,6 @@
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.4.4" level="required">
|
||||
<RESTRICT function="restrict_php_version_7" message="unsupportedphpversion7" />
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
@@ -1559,4 +1558,289 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.1" requires="2.7">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.1" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.4.4" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opensslrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="intlrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="3.2" requires="2.7">
|
||||
<UNICODE level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unicoderequired" />
|
||||
</FEEDBACK>
|
||||
</UNICODE>
|
||||
<DATABASE level="required">
|
||||
<VENDOR name="mariadb" version="5.5.31" />
|
||||
<VENDOR name="mysql" version="5.5.31" />
|
||||
<VENDOR name="postgres" version="9.1" />
|
||||
<VENDOR name="mssql" version="10.0" />
|
||||
<VENDOR name="oracle" version="10.2" />
|
||||
</DATABASE>
|
||||
<PHP version="5.6.5" level="required">
|
||||
</PHP>
|
||||
<PCREUNICODE level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="pcreunicodewarning" />
|
||||
</FEEDBACK>
|
||||
</PCREUNICODE>
|
||||
<PHP_EXTENSIONS>
|
||||
<PHP_EXTENSION name="iconv" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="iconvrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="mbstring" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="mbstringrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="curl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="curlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="openssl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opensslrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="tokenizer" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="tokenizerrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlrpc" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="xmlrpcrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="soap" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="soaprecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="ctype" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ctyperequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zip" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="ziprequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="zlib" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="gd" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="gdrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="simplexml" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="simplexmlrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="spl" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="splrequired" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="pcre" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="dom" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xml" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="xmlreader" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="intl" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="intlrecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="json" level="required">
|
||||
</PHP_EXTENSION>
|
||||
<PHP_EXTENSION name="hash" level="required"/>
|
||||
</PHP_EXTENSIONS>
|
||||
<PHP_SETTINGS>
|
||||
<PHP_SETTING name="memory_limit" value="96M" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="settingmemorylimit" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="file_uploads" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="settingfileuploads" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
<PHP_SETTING name="opcache.enable" value="1" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="opcacherecommended" />
|
||||
</FEEDBACK>
|
||||
</PHP_SETTING>
|
||||
</PHP_SETTINGS>
|
||||
<CUSTOM_CHECKS>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_storage_engine" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="unsupporteddbstorageengine" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_slasharguments" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="slashargumentswarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_database_tables_row_format" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unsupporteddbtablerowformat" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
<CUSTOM_CHECK file="lib/upgradelib.php" function="check_unoconv_version" level="optional">
|
||||
<FEEDBACK>
|
||||
<ON_CHECK message="unoconvwarning" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
@@ -201,7 +201,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey() && $de
|
||||
$event = \core\event\role_capabilities_updated::create(
|
||||
array(
|
||||
'context' => $systemcontext,
|
||||
'objectid' => $roleid
|
||||
'objectid' => $tableroleid
|
||||
)
|
||||
);
|
||||
$event->set_legacy_logdata(array(SITEID, 'role', $action, 'admin/roles/define.php?action=view&roleid=' . $tableroleid,
|
||||
|
||||
+5
-1
@@ -20,7 +20,11 @@ $adminroot = admin_get_root(); // need all settings
|
||||
$settingspage = $adminroot->locate($section, true);
|
||||
|
||||
if (empty($settingspage) or !($settingspage instanceof admin_settingpage)) {
|
||||
print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
|
||||
if (moodle_needs_upgrading()) {
|
||||
redirect(new moodle_url('/admin/index.php'));
|
||||
} else {
|
||||
print_error('sectionerror', 'admin', "$CFG->wwwroot/$CFG->admin/");
|
||||
}
|
||||
die;
|
||||
}
|
||||
|
||||
|
||||
@@ -205,6 +205,9 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) {
|
||||
// Create a page for general import configuration and defaults.
|
||||
$temp = new admin_settingpage('importgeneralsettings', new lang_string('importgeneralsettings', 'backup'), 'moodle/backup:backupcourse');
|
||||
$temp->add(new admin_setting_configtext('backup/import_general_maxresults', new lang_string('importgeneralmaxresults', 'backup'), new lang_string('importgeneralmaxresults_desc', 'backup'), 10));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/import_general_duplicate_admin_allowed',
|
||||
new lang_string('importgeneralduplicateadminallowed', 'backup'),
|
||||
new lang_string('importgeneralduplicateadminallowed_desc', 'backup'), 0));
|
||||
$ADMIN->add('backups', $temp);
|
||||
|
||||
// Create a page for automated backups configuration and defaults.
|
||||
|
||||
@@ -18,11 +18,10 @@ $ADMIN->add('server', $temp);
|
||||
|
||||
// "supportcontact" settingpage
|
||||
$temp = new admin_settingpage('supportcontact', new lang_string('supportcontact','admin'));
|
||||
if (isloggedin()) {
|
||||
global $USER;
|
||||
$primaryadminemail = $USER->email;
|
||||
$primaryadminname = fullname($USER, true);
|
||||
|
||||
$primaryadmin = get_admin();
|
||||
if ($primaryadmin) {
|
||||
$primaryadminemail = $primaryadmin->email;
|
||||
$primaryadminname = fullname($primaryadmin, true);
|
||||
} else {
|
||||
// no defaults during installation - admin user must be created first
|
||||
$primaryadminemail = NULL;
|
||||
|
||||
@@ -27,7 +27,6 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
And I add "User Three (three@example.com)" user to "CH1" cohort members
|
||||
And I follow "Browse list of users"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by role and cohort
|
||||
When I set the following fields to these values:
|
||||
| courserole_rl | Student |
|
||||
@@ -51,7 +50,6 @@ Feature: An administrator can filter user accounts by role, cohort and other pro
|
||||
And I should see "User Three"
|
||||
And I should see "User Four"
|
||||
|
||||
@javascript
|
||||
Scenario: Filter user accounts by confirm and authentication method
|
||||
When I set the following fields to these values:
|
||||
| Confirmed | No |
|
||||
|
||||
@@ -120,8 +120,8 @@ $tags = '';
|
||||
|
||||
if ($options['profile']) {
|
||||
$profile = $options['profile'];
|
||||
if (!isset($CFG->behat_config[$profile])) {
|
||||
echo "Invalid profile passed: " . $profile;
|
||||
if (!isset($CFG->behat_config[$profile]) && !isset($CFG->behat_profiles[$profile])) {
|
||||
echo "Invalid profile passed: " . $profile . PHP_EOL;
|
||||
exit(1);
|
||||
}
|
||||
$extraopts[] = '--profile="' . $profile . '"';
|
||||
@@ -226,22 +226,27 @@ $exitcodes = print_combined_run_output($processes, $stoponfail);
|
||||
$time = round(microtime(true) - $time, 1);
|
||||
echo "Finished in " . gmdate("G\h i\m s\s", $time) . PHP_EOL . PHP_EOL;
|
||||
|
||||
ksort($exitcodes);
|
||||
|
||||
// Print exit info from each run.
|
||||
$status = false;
|
||||
// Status bits contains pass/fail status of parallel runs.
|
||||
$status = 0;
|
||||
$processcounter = 0;
|
||||
foreach ($exitcodes as $exitcode) {
|
||||
$status = (bool)$status || (bool)$exitcode;
|
||||
if ($exitcode) {
|
||||
$status |= (1 << $processcounter);
|
||||
}
|
||||
$processcounter++;
|
||||
}
|
||||
|
||||
// Run finished. Show exit code and output from individual process.
|
||||
$verbose = empty($options['verbose']) ? false : true;
|
||||
$verbose = $verbose || $status;
|
||||
$verbose = $verbose || !empty($status);
|
||||
|
||||
// Show exit code from each process, if any process failed.
|
||||
if ($verbose) {
|
||||
// Echo exit codes.
|
||||
echo "Exit codes for each behat run: " . PHP_EOL;
|
||||
ksort($exitcodes);
|
||||
foreach ($exitcodes as $run => $exitcode) {
|
||||
echo $run . ": " . $exitcode . PHP_EOL;
|
||||
}
|
||||
@@ -263,7 +268,7 @@ print_each_process_info($processes, $verbose);
|
||||
// Remove site symlink if necessary.
|
||||
behat_config_manager::drop_parallel_site_links();
|
||||
|
||||
exit((int) $status);
|
||||
exit($status);
|
||||
|
||||
/**
|
||||
* Signal handler for terminal exit.
|
||||
|
||||
@@ -173,6 +173,7 @@ if ($options['install']) {
|
||||
|
||||
// This is only displayed once for parallel install.
|
||||
if (empty($options['run'])) {
|
||||
|
||||
$runtestscommand = behat_command::get_behat_command(true, !empty($options['run']));
|
||||
|
||||
$runtestscommand .= ' --config ' . behat_config_manager::get_behat_cli_config_filepath();
|
||||
|
||||
@@ -424,9 +424,9 @@ Feature: Set up contextual data for tests
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course |
|
||||
| Grade category 1 | C1 |
|
||||
And the following "grade items" exist:
|
||||
| itemname | course | outcome | gradecategory |
|
||||
| Test Outcome Grade Item 1 | C1 | OT1 | Grade category 1 |
|
||||
And the following "grade items" exist:
|
||||
| itemname | course | outcome | gradecategory |
|
||||
| Test Outcome Grade Item 1 | C1 | OT1 | Grade category 1 |
|
||||
And the following config values are set as admin:
|
||||
| enableoutcomes | 1 |
|
||||
When I log in as "admin"
|
||||
@@ -441,3 +441,15 @@ Feature: Set up contextual data for tests
|
||||
And I expand all fieldsets
|
||||
And "//div[contains(@class, 'fitem')]/div[contains(@class, 'fitemtitle')]/div[contains(@class, fstaticlabel) and contains(., 'Grade category')]/../../div[contains(@class, 'felement') and contains(., 'Grade category 1')]" "xpath_element" should exist
|
||||
And I press "Cancel"
|
||||
|
||||
Scenario: Add a block
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "blocks" exist:
|
||||
| blockname | contextlevel | reference | pagetypepattern | defaultregion |
|
||||
| online_users | Course | C1 | course-view-* | site-pre |
|
||||
When I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
Then I should see "Online users"
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Display environment used for running behat.
|
||||
*
|
||||
* This file is used for behat testing to ensure cli and apache
|
||||
* version of environment is same.
|
||||
*
|
||||
* @package tool_behat
|
||||
* @copyright 2016 onwards Rajesh Taneja
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(__DIR__.'/../../../../../../config.php');
|
||||
|
||||
// Only continue for behat site.
|
||||
defined('BEHAT_SITE_RUNNING') || die();
|
||||
|
||||
require_once($CFG->libdir.'/behat/classes/util.php');
|
||||
echo json_encode(behat_util::get_environment(), true);
|
||||
@@ -176,7 +176,7 @@ echo html_writer::end_tag('td');
|
||||
$options = array();
|
||||
foreach ($availablelangs as $alang) {
|
||||
if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !$controller->is_installed_lang($alang[0], $alang[1])) {
|
||||
$options[$alang[0]] = $alang[2].' ('.$alang[0].')';
|
||||
$options[$alang[0]] = $alang[2].' ‎('.$alang[0].')‎';
|
||||
}
|
||||
}
|
||||
if (!empty($options)) {
|
||||
|
||||
@@ -52,8 +52,7 @@ class logstore_database_store_testcase extends advanced_testcase {
|
||||
$this->assertCount(0, $stores);
|
||||
|
||||
// Fake the settings, we will abuse the standard plugin table here...
|
||||
$parts = explode('_', get_class($DB));
|
||||
set_config('dbdriver', $parts[1] . '/' . $parts[0], 'logstore_database');
|
||||
set_config('dbdriver', $CFG->dblibrary . '/' . $CFG->dbtype, 'logstore_database');
|
||||
set_config('dbhost', $CFG->dbhost, 'logstore_database');
|
||||
set_config('dbuser', $CFG->dbuser, 'logstore_database');
|
||||
set_config('dbpass', $CFG->dbpass, 'logstore_database');
|
||||
|
||||
@@ -898,7 +898,7 @@ class manager {
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$eventdata->userfrom = \core_user::get_noreply_user();
|
||||
$eventdata->userfrom = \core_user::get_support_user();
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = $this->get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = get_string('invalidrecipientdescription', 'tool_messageinbound', $this->currentmessagedata);
|
||||
|
||||
@@ -140,6 +140,10 @@ class eventobservers {
|
||||
$subscriptions = subscription_manager::get_subscriptions_by_event($eventobj);
|
||||
$idstosend = array();
|
||||
foreach ($subscriptions as $subscription) {
|
||||
// Only proceed to fire events and notifications if the subscription is active.
|
||||
if (!subscription_manager::subscription_is_active($subscription)) {
|
||||
continue;
|
||||
}
|
||||
$starttime = $now - $subscription->timewindow;
|
||||
$starttime = ($starttime > $subscription->lastnotificationsent) ? $starttime : $subscription->lastnotificationsent;
|
||||
if ($subscription->courseid == 0) {
|
||||
|
||||
@@ -82,15 +82,16 @@ class notification_task extends \core\task\adhoc_task {
|
||||
|
||||
$template = $subscription->template;
|
||||
$template = $this->replace_placeholders($template, $subscription, $eventobj, $context);
|
||||
$htmlmessage = format_text($template, $subscription->templateformat, array('context' => $context));
|
||||
$msgdata = new \stdClass();
|
||||
$msgdata->component = 'tool_monitor'; // Your component name.
|
||||
$msgdata->name = 'notification'; // This is the message name from messages.php.
|
||||
$msgdata->userfrom = \core_user::get_noreply_user();
|
||||
$msgdata->userto = $user;
|
||||
$msgdata->subject = $subscription->get_name($context);
|
||||
$msgdata->fullmessage = format_text($template, $subscription->templateformat, array('context' => $context));
|
||||
$msgdata->fullmessageformat = $subscription->templateformat;
|
||||
$msgdata->fullmessagehtml = format_text($template, $subscription->templateformat, array('context' => $context));
|
||||
$msgdata->fullmessage = html_to_text($htmlmessage);
|
||||
$msgdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$msgdata->fullmessagehtml = $htmlmessage;
|
||||
$msgdata->smallmessage = '';
|
||||
$msgdata->notification = 1; // This is only set to 0 for personal messages between users.
|
||||
|
||||
|
||||
@@ -55,17 +55,26 @@ class subscription {
|
||||
* Magic get method.
|
||||
*
|
||||
* @param string $prop property to get.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function __get($prop) {
|
||||
if (property_exists($this->subscription, $prop)) {
|
||||
if (isset($this->subscription->$prop)) {
|
||||
return $this->subscription->$prop;
|
||||
}
|
||||
throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic isset method.
|
||||
*
|
||||
* @param string $prop the property to get.
|
||||
* @return bool true if the property is set, false otherwise.
|
||||
*/
|
||||
public function __isset($prop) {
|
||||
return property_exists($this->subscription, $prop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human readable name for instances associated with this subscription.
|
||||
*
|
||||
|
||||
@@ -35,6 +35,10 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription_manager {
|
||||
|
||||
/** @const Period of time, in days, after which an inactive subscription will be removed completely.*/
|
||||
const INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS = 30;
|
||||
|
||||
/**
|
||||
* Subscribe a user to a given rule.
|
||||
*
|
||||
@@ -456,4 +460,78 @@ class subscription_manager {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates a group of subscriptions based on an input array of ids.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param array $ids of subscription ids.
|
||||
* @return bool true if the operation was successful, false otherwise.
|
||||
*/
|
||||
public static function activate_subscriptions(array $ids) {
|
||||
global $DB;
|
||||
if (!empty($ids)) {
|
||||
list($sql, $params) = $DB->get_in_or_equal($ids);
|
||||
$success = $DB->set_field_select('tool_monitor_subscriptions', 'inactivedate', '0', 'id ' . $sql, $params);
|
||||
return $success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates a group of subscriptions based on an input array of ids.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param array $ids of subscription ids.
|
||||
* @return bool true if the operation was successful, false otherwise.
|
||||
*/
|
||||
public static function deactivate_subscriptions(array $ids) {
|
||||
global $DB;
|
||||
if (!empty($ids)) {
|
||||
$inactivedate = time();
|
||||
list($sql, $params) = $DB->get_in_or_equal($ids);
|
||||
$success = $DB->set_field_select('tool_monitor_subscriptions', 'inactivedate', $inactivedate, 'id ' . $sql,
|
||||
$params);
|
||||
return $success;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes subscriptions which have been inactive for a period of time.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param int $userid if provided, only this user's stale subscriptions will be deleted.
|
||||
* @return bool true if the operation was successful, false otherwise.
|
||||
*/
|
||||
public static function delete_stale_subscriptions($userid = 0) {
|
||||
global $DB;
|
||||
// Get the expiry duration, in days.
|
||||
$cutofftime = strtotime("-" . self::INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS . " days", time());
|
||||
|
||||
if (!empty($userid)) {
|
||||
// Remove any stale subscriptions for the desired user only.
|
||||
$success = $DB->delete_records_select('tool_monitor_subscriptions',
|
||||
'userid = ? AND inactivedate < ? AND inactivedate <> 0',
|
||||
array($userid, $cutofftime));
|
||||
|
||||
} else {
|
||||
// Remove all stale subscriptions.
|
||||
$success = $DB->delete_records_select('tool_monitor_subscriptions',
|
||||
'inactivedate < ? AND inactivedate <> 0',
|
||||
array($cutofftime));
|
||||
}
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a subscription is active.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \tool_monitor\subscription $subscription instance.
|
||||
* @return bool true if the subscription is active, false otherwise.
|
||||
*/
|
||||
public static function subscription_is_active(subscription $subscription) {
|
||||
return empty($subscription->inactivedate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,274 @@
|
||||
<?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 tool_monitor\task;
|
||||
use tool_monitor\subscription;
|
||||
use tool_monitor\subscription_manager;
|
||||
|
||||
/**
|
||||
* Simple task class responsible for activating, deactivating and removing subscriptions.
|
||||
*
|
||||
* Activation/deactivation is managed by looking at the same access rules used to determine whether a user can
|
||||
* subscribe to the rule in the first place.
|
||||
*
|
||||
* Removal occurs when a subscription has been inactive for a period of time exceeding the lifespan, as set by
|
||||
* subscription_manager::get_inactive_subscription_lifespan().
|
||||
*
|
||||
* I.e.
|
||||
* - Activation: If a user can subscribe currently, then an existing subscription should be made active.
|
||||
* - Deactivation: If a user cannot subscribe currently, then an existing subscription should be made inactive.
|
||||
* - Removal: If a user has a subscription that has been inactive for longer than the prescribed period, then
|
||||
* delete the subscription entirely.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @package tool_monitor
|
||||
* @copyright 2016 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class check_subscriptions extends \core\task\scheduled_task {
|
||||
|
||||
/** @var array 1d static cache, indexed by userid, storing whether or not the user has been fully set up.*/
|
||||
protected $userssetupcache = array();
|
||||
|
||||
/** @var array 2d static cache, indexed by courseid and userid, storing whether a user can access the course with
|
||||
* the 'tool/monitor:subscribe' capability.
|
||||
*/
|
||||
protected $courseaccesscache = array();
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @return string name of the task.
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskchecksubscriptions', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks all course-level rule subscriptions and activates/deactivates based on current course access.
|
||||
*
|
||||
* The ordering of checks within the task is important for optimisation purposes. The aim is to be able to make a decision
|
||||
* about whether to activate/deactivate each subscription without making unnecessary checks. The ordering roughly follows the
|
||||
* context model, starting with system and user checks and moving down to course and course-module only when necessary.
|
||||
*
|
||||
* For example, if the user is suspended, then any active subscription is made inactive right away. I.e. there is no need to
|
||||
* check site-level, course-level or course-module-level permissions. Likewise, if a subscriptions is site-level, there is no
|
||||
* need to check course-level and course-module-level permissions.
|
||||
*
|
||||
* The task performs the following checks, in this order:
|
||||
* 1. Check for a suspended user, breaking if suspended.
|
||||
* 2. Check for an incomplete (not set up) user, breaking if not fully set up.
|
||||
* 3. Check for the required capability in the relevant context, breaking if the capability is not found.
|
||||
* 4. Check whether the subscription is site-context, breaking if true.
|
||||
* 5. Check whether the user has course access, breaking only if the subscription is not also course-module-level.
|
||||
* 6. Check whether the user has course-module access.
|
||||
*
|
||||
* @since 2.9.7
|
||||
*/
|
||||
public function execute() {
|
||||
global $DB;
|
||||
|
||||
if (!get_config('tool_monitor', 'enablemonitor')) {
|
||||
return; // The tool is disabled. Nothing to do.
|
||||
}
|
||||
|
||||
$toactivate = array(); // Store the ids of subscriptions to be activated upon completion.
|
||||
$todeactivate = array(); // Store the ids of subscriptions to be deactivated upon completion.
|
||||
|
||||
// Resultset rows are ordered by userid and courseid to work nicely with get_fast_modinfo() caching.
|
||||
$sql = "SELECT u.id AS userid, u.firstname AS userfirstname, u.lastname AS userlastname, u.suspended AS usersuspended,
|
||||
u.email AS useremail, c.visible as coursevisible, c.cacherev as coursecacherev, s.courseid AS subcourseid,
|
||||
s.userid AS subuserid, s.cmid AS subcmid, s.inactivedate AS subinactivedate, s.id AS subid
|
||||
FROM {user} u
|
||||
JOIN {tool_monitor_subscriptions} s ON (s.userid = u.id)
|
||||
LEFT JOIN {course} c ON (c.id = s.courseid)
|
||||
WHERE u.id = s.userid
|
||||
ORDER BY s.userid, s.courseid";
|
||||
$rs = $DB->get_recordset_sql($sql);
|
||||
|
||||
foreach ($rs as $row) {
|
||||
// Create skeleton records from the result. This should be enough to use in subsequent access calls and avoids DB hits.
|
||||
$sub = $this->get_subscription_from_rowdata($row);
|
||||
$sub = new subscription($sub);
|
||||
if (!isset($user) || $user->id != $sub->userid) {
|
||||
$user= $this->get_user_from_rowdata($row);
|
||||
}
|
||||
if ((!isset($course) || $course->id != $sub->courseid) && !empty($sub->courseid)) {
|
||||
$course = $this->get_course_from_rowdata($row);
|
||||
}
|
||||
|
||||
// The user is suspended at site level, so deactivate any active subscriptions.
|
||||
if ($user->suspended) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the user fully set up? As per require_login on the subscriptions page.
|
||||
if (!$this->is_user_setup($user)) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine the context, based on the subscription course id.
|
||||
$sitelevelsubscription = false;
|
||||
if (empty($sub->courseid)) {
|
||||
$context = \context_system::instance();
|
||||
$sitelevelsubscription = true;
|
||||
} else {
|
||||
$context = \context_course::instance($sub->courseid);
|
||||
}
|
||||
|
||||
// Check capability in the context.
|
||||
if (!has_capability('tool/monitor:subscribe', $context, $user)) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the subscription is site-level, then we've run all the checks required to make an access decision.
|
||||
if ($sitelevelsubscription) {
|
||||
if (!subscription_manager::subscription_is_active($sub)) {
|
||||
$toactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check course access.
|
||||
if (!$this->user_can_access_course($user, $course, 'tool/monitor:subscribe')) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the subscription has no course module relationship.
|
||||
if (empty($sub->cmid)) {
|
||||
if (!subscription_manager::subscription_is_active($sub)) {
|
||||
$toactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Otherwise, check the course module info. We use the same checks as on the subscription page.
|
||||
$modinfo = get_fast_modinfo($course, $sub->userid);
|
||||
$cm = $modinfo->get_cm($sub->cmid);
|
||||
if (!$cm || !$cm->uservisible || !$cm->available) {
|
||||
if (subscription_manager::subscription_is_active($sub)) {
|
||||
$todeactivate[] = $sub->id;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// The course module is available and visible, so make a decision.
|
||||
if (!subscription_manager::subscription_is_active($sub)) {
|
||||
$toactivate[] = $sub->id;
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
|
||||
// Activate/deactivate/delete relevant subscriptions.
|
||||
subscription_manager::activate_subscriptions($toactivate);
|
||||
subscription_manager::deactivate_subscriptions($todeactivate);
|
||||
subscription_manager::delete_stale_subscriptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a user is fully set up, using cached results where possible.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $user the user record.
|
||||
* @return bool true if the user is fully set up, false otherwise.
|
||||
*/
|
||||
protected function is_user_setup($user) {
|
||||
if (!isset($this->userssetupcache[$user->id])) {
|
||||
$this->userssetupcache[$user->id] = !user_not_fully_set_up($user);
|
||||
}
|
||||
return $this->userssetupcache[$user->id];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines a user's access to a course with a given capability, using cached results where possible.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $user the user record.
|
||||
* @param \stdClass $course the course record.
|
||||
* @param string $capability the capability to check.
|
||||
* @return bool true if the user can access the course with the specified capability, false otherwise.
|
||||
*/
|
||||
protected function user_can_access_course($user, $course, $capability) {
|
||||
if (!isset($this->courseaccesscache[$course->id][$user->id][$capability])) {
|
||||
$this->courseaccesscache[$course->id][$user->id][$capability] = can_access_course($course, $user, $capability, true);
|
||||
}
|
||||
return $this->courseaccesscache[$course->id][$user->id][$capability];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial subscription record, created from properties of the supplied recordset row object.
|
||||
* Intended to return a minimal record for specific use within this class and in subsequent access control calls only.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $rowdata the row object.
|
||||
* @return \stdClass a partial subscription record.
|
||||
*/
|
||||
protected function get_subscription_from_rowdata($rowdata) {
|
||||
$sub = new \stdClass();
|
||||
$sub->id = $rowdata->subid;
|
||||
$sub->userid = $rowdata->subuserid;
|
||||
$sub->courseid = $rowdata->subcourseid;
|
||||
$sub->cmid = $rowdata->subcmid;
|
||||
$sub->inactivedate = $rowdata->subinactivedate;
|
||||
return $sub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial course record, created from properties of the supplied recordset row object.
|
||||
* Intended to return a minimal record for specific use within this class and in subsequent access control calls only.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $rowdata the row object.
|
||||
* @return \stdClass a partial course record.
|
||||
*/
|
||||
protected function get_course_from_rowdata($rowdata) {
|
||||
$course = new \stdClass();
|
||||
$course->id = $rowdata->subcourseid;
|
||||
$course->visible = $rowdata->coursevisible;
|
||||
$course->cacherev = $rowdata->coursecacherev;
|
||||
return $course;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partial user record, created from properties of the supplied recordset row object.
|
||||
* Intended to return a minimal record for specific use within this class and in subsequent access control calls only.
|
||||
*
|
||||
* @since 2.9.7
|
||||
* @param \stdClass $rowdata the row object.
|
||||
* @return \stdClass a partial user record.
|
||||
*/
|
||||
protected function get_user_from_rowdata($rowdata) {
|
||||
$user = new \stdClass();
|
||||
$user->id = $rowdata->userid;
|
||||
$user->firstname = $rowdata->userfirstname;
|
||||
$user->lastname = $rowdata->userlastname;
|
||||
$user->email = $rowdata->useremail;
|
||||
$user->suspended = $rowdata->usersuspended;
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User id of the subscriber"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Timestamp of when this subscription was created"/>
|
||||
<FIELD NAME="lastnotificationsent" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Timestamp of the time when a notification was last sent for this subscription."/>
|
||||
<FIELD NAME="inactivedate" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
|
||||
@@ -32,5 +32,14 @@ $tasks = array(
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
array(
|
||||
'classname' => 'tool_monitor\task\check_subscriptions',
|
||||
'blocking' => 0,
|
||||
'minute' => 'R',
|
||||
'hour' => 'R',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
)
|
||||
);
|
||||
|
||||
@@ -56,5 +56,20 @@ function xmldb_tool_monitor_upgrade($oldversion) {
|
||||
// Moodle v2.9.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
if ($oldversion < 2015051101) {
|
||||
|
||||
// Define field inactivedate to be added to tool_monitor_subscriptions.
|
||||
$table = new xmldb_table('tool_monitor_subscriptions');
|
||||
$field = new xmldb_field('inactivedate', XMLDB_TYPE_INTEGER, '10', null, true, null, 0, 'lastnotificationsent');
|
||||
|
||||
// Conditionally launch add field inactivedate.
|
||||
if (!$dbman->field_exists($table, $field)) {
|
||||
$dbman->add_field($table, $field);
|
||||
}
|
||||
|
||||
// Monitor savepoint reached.
|
||||
upgrade_plugin_savepoint(true, 2015051101, 'tool', 'monitor');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -99,4 +99,5 @@ $string['subhelp'] = 'Subscription details';
|
||||
$string['subhelp_help'] = 'This subscription listens for when the event \'{$a->eventname}\' has been triggered in \'{$a->moduleinstance}\' {$a->frequency} time(s) in {$a->minutes} minute(s).';
|
||||
$string['subscribeto'] = 'Subscribe to rule "{$a}"';
|
||||
$string['taskcleanevents'] = 'Removes any unnecessary event monitor events';
|
||||
$string['taskchecksubscriptions'] = 'Activate/deactivate invalid rule subscriptions';
|
||||
$string['unsubscribe'] = 'Unsubscribe';
|
||||
|
||||
@@ -103,10 +103,12 @@ function tool_monitor_get_user_courses() {
|
||||
if (has_capability('tool/monitor:subscribe', context_system::instance())) {
|
||||
$options[0] = get_string('site');
|
||||
}
|
||||
if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname', $orderby)) {
|
||||
if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname, visible', $orderby)) {
|
||||
foreach ($courses as $course) {
|
||||
$options[$course->id] = format_string($course->fullname, true,
|
||||
array('context' => context_course::instance($course->id)));
|
||||
$coursectx = context_course::instance($course->id);
|
||||
if ($course->visible || has_capability('moodle/course:viewhiddencourses', $coursectx)) {
|
||||
$options[$course->id] = format_string($course->fullname, true, array('context' => $coursectx));
|
||||
}
|
||||
}
|
||||
}
|
||||
// If there are no courses and there is no site permission then return false.
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
@javascript @tool @tool_monitor
|
||||
@tool @tool_monitor
|
||||
Feature: Enable/disable managment of the event monitor
|
||||
In order to manage event monitoring
|
||||
As an admin
|
||||
I need to enable/disable it
|
||||
|
||||
@javascript
|
||||
Scenario: Tool is disabled by default.
|
||||
Given I log in as "admin"
|
||||
When I navigate to "Event monitoring rules" node in "Site administration > Reports"
|
||||
|
||||
@@ -467,7 +467,13 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
|
||||
$rulerecord->eventname = '\mod_book\event\course_module_viewed';
|
||||
$rulerecord->cmid = $book->cmid;
|
||||
$rulerecord->frequency = 1;
|
||||
$rulerecord->template = '{link} {modulelink} {rulename} {description} {eventname}';
|
||||
$rulerecord->template = '## {link} ##
|
||||
|
||||
* {modulelink}
|
||||
* __{rulename}__
|
||||
* {description}
|
||||
* {eventname}';
|
||||
$rulerecord->templateformat = FORMAT_MARKDOWN;
|
||||
|
||||
$rule = $toolgenerator->create_rule($rulerecord);
|
||||
|
||||
@@ -491,13 +497,21 @@ class tool_monitor_eventobservers_testcase extends advanced_testcase {
|
||||
$msg = array_pop($msgs);
|
||||
|
||||
$modurl = new moodle_url('/mod/book/view.php', array('id' => $book->cmid));
|
||||
$expectedmsg = $event->get_url()->out() . ' ' .
|
||||
$modurl->out() . ' ' .
|
||||
$rule->get_name($context) . ' ' .
|
||||
$rule->get_description($context) . ' ' .
|
||||
$rule->get_event_name();
|
||||
|
||||
$this->assertEquals($expectedmsg, $msg->fullmessage);
|
||||
$this->assertContains('<h2>'.$event->get_url()->out().'</h2>', $msg->fullmessagehtml);
|
||||
$this->assertContains('<li>'.$modurl->out().'</li>', $msg->fullmessagehtml);
|
||||
$this->assertContains('<li><strong>'.$rule->get_name($context).'</strong></li>', $msg->fullmessagehtml);
|
||||
$this->assertContains('<li>'.$rule->get_description($context).'</li>', $msg->fullmessagehtml);
|
||||
$this->assertContains('<li>'.$rule->get_event_name().'</li>', $msg->fullmessagehtml);
|
||||
|
||||
$this->assertEquals(FORMAT_PLAIN, $msg->fullmessageformat);
|
||||
$this->assertNotContains('<h2>', $msg->fullmessage);
|
||||
$this->assertNotContains('##', $msg->fullmessage);
|
||||
$this->assertContains(strtoupper($event->get_url()->out()), $msg->fullmessage);
|
||||
$this->assertContains('* '.$modurl->out(), $msg->fullmessage);
|
||||
$this->assertContains('* '.strtoupper($rule->get_name($context)), $msg->fullmessage);
|
||||
$this->assertContains('* '.$rule->get_description($context), $msg->fullmessage);
|
||||
$this->assertContains('* '.$rule->get_event_name(), $msg->fullmessage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<?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/>.
|
||||
defined('MOODLE_INTERNAL') || exit();
|
||||
|
||||
/**
|
||||
* Unit tests for the subscription class.
|
||||
* @since 2.9.7
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @category test
|
||||
* @copyright 2016 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_monitor_subscription_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* @var \tool_monitor\subscription $subscription object.
|
||||
*/
|
||||
private $subscription;
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// Create the mock subscription.
|
||||
$sub = new stdClass();
|
||||
$sub->id = 100;
|
||||
$sub->name = 'My test rule';
|
||||
$sub->courseid = 20;
|
||||
$this->subscription = $this->getMock('\tool_monitor\subscription',null, array($sub));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the magic __isset method.
|
||||
*/
|
||||
public function test_magic_isset() {
|
||||
$this->assertEquals(true, isset($this->subscription->name));
|
||||
$this->assertEquals(true, isset($this->subscription->courseid));
|
||||
$this->assertEquals(false, isset($this->subscription->ruleid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for the magic __get method.
|
||||
*/
|
||||
public function test_magic_get() {
|
||||
$this->assertEquals(20, $this->subscription->courseid);
|
||||
$this->setExpectedException('coding_exception');
|
||||
$this->subscription->ruleid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?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/>.
|
||||
defined('MOODLE_INTERNAL') || exit();
|
||||
|
||||
/**
|
||||
* Unit tests for the tool_monitor clean events task.
|
||||
* @since 2.9.7
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @category test
|
||||
* @copyright 2016 Jake Dallimore <jrhdallimore@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_monitor_task_check_subscriptions_testcase extends advanced_testcase {
|
||||
|
||||
private $course;
|
||||
private $user;
|
||||
private $rule;
|
||||
private $subscription;
|
||||
private $teacherrole;
|
||||
private $studentrole;
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
global $DB;
|
||||
set_config('enablemonitor', 1, 'tool_monitor');
|
||||
$this->resetAfterTest(true);
|
||||
|
||||
// All tests defined herein need a user, course, rule and subscription, so set these up.
|
||||
$this->user = $this->getDataGenerator()->create_user();
|
||||
$this->course = $this->getDataGenerator()->create_course();
|
||||
|
||||
$rule = new stdClass();
|
||||
$rule->userid = 2; // Rule created by admin.
|
||||
$rule->courseid = $this->course->id;
|
||||
$rule->plugin = 'mod_book';
|
||||
$rule->eventname = '\mod_book\event\course_module_viewed';
|
||||
$rule->timewindow = 500;
|
||||
$monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
|
||||
$this->rule = $monitorgenerator->create_rule($rule);
|
||||
|
||||
$sub = new stdClass();
|
||||
$sub->courseid = $this->course->id;
|
||||
$sub->userid = $this->user->id;
|
||||
$sub->ruleid = $this->rule->id;
|
||||
$this->subscription = $monitorgenerator->create_subscription($sub);
|
||||
|
||||
// Also set up a student and a teacher role for use in some tests.
|
||||
$this->teacherrole = $DB->get_record('role', array('shortname' => 'teacher'));
|
||||
$this->studentrole = $DB->get_record('role', array('shortname' => 'student'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Reloads the subscription object from the DB.
|
||||
*
|
||||
* @return void.
|
||||
*/
|
||||
private function reload_subscription() {
|
||||
global $DB;
|
||||
$sub = $DB->get_record('tool_monitor_subscriptions', array('id' => $this->subscription->id));
|
||||
$this->subscription = new \tool_monitor\subscription($sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm the task is named correctly.
|
||||
*/
|
||||
public function test_task_name() {
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$this->assertEquals(get_string('taskchecksubscriptions', 'tool_monitor'), $task->get_name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that site level subscriptions are activated and deactivated according to system capabilities.
|
||||
*/
|
||||
public function test_site_level_subscription() {
|
||||
// Create a site level subscription.
|
||||
$monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
|
||||
$sub = new stdClass();
|
||||
$sub->userid = $this->user->id;
|
||||
$sub->ruleid = $this->rule->id;
|
||||
$this->subscription = $monitorgenerator->create_subscription($sub);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be inactive as the user doesn't have the capability. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Now, assign the user as a teacher role at system context.
|
||||
$this->getDataGenerator()->role_assign($this->teacherrole->id, $this->user->id, context_system::instance());
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be active now. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that if the module is disabled, no changes are made to active subscriptions.
|
||||
*/
|
||||
public function test_module_disabled() {
|
||||
set_config('enablemonitor', 0, 'tool_monitor');
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task. Note, we never enrolled the user.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should still be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm an active, valid subscription stays active once the scheduled task is run.
|
||||
*/
|
||||
public function test_active_unaffected() {
|
||||
// Enrol the user as a teacher. This role should have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should still be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that a subscription for a user without an enrolment to the course is made inactive.
|
||||
*/
|
||||
public function test_course_enrolment() {
|
||||
// Subscription should be active until deactivated by the scheduled task. Remember, by default the test setup
|
||||
// doesn't enrol the user, so the first run of the task should deactivate it.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should NOT be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Enrol the user.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// Subscription should now be active again.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for enrolled users without the required capability are made inactive.
|
||||
*/
|
||||
public function test_enrolled_user_with_no_capability() {
|
||||
// Enrol the user. By default, students won't have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->studentrole->id);
|
||||
|
||||
// The subscription should be active to start with. Pass in the id only to refetch the data.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should NOT be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for users who fail can_access_course(), are deactivated.
|
||||
*/
|
||||
public function test_can_access_course() {
|
||||
// Enrol the user as a teacher. This role should have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Strip the ability to see hidden courses, so we'll fail the check_subscriptions->user_can_access_course call.
|
||||
$context = \context_course::instance($this->course->id);
|
||||
assign_capability('moodle/course:viewhiddencourses', CAP_PROHIBIT, $this->teacherrole->id, $context);
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Hide the course.
|
||||
course_change_visibility($this->course->id, false);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be inactive. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for enrolled users who don't have CM access, are deactivated.
|
||||
*/
|
||||
public function test_cm_access() {
|
||||
// Enrol the user as a student but grant to ability to subscribe. Students cannot view hidden activities.
|
||||
$context = \context_course::instance($this->course->id);
|
||||
assign_capability('tool/monitor:subscribe', CAP_ALLOW, $this->studentrole->id, $context);
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->studentrole->id);
|
||||
|
||||
// Generate a course module.
|
||||
$book = $this->getDataGenerator()->create_module('book', array('course' => $this->course->id));
|
||||
|
||||
// And add a subscription to it.
|
||||
$sub = new stdClass();
|
||||
$sub->courseid = $this->course->id;
|
||||
$sub->userid = $this->user->id;
|
||||
$sub->ruleid = $this->rule->id;
|
||||
$sub->cmid = $book->cmid;
|
||||
$monitorgenerator = $this->getDataGenerator()->get_plugin_generator('tool_monitor');
|
||||
$this->subscription = $monitorgenerator->create_subscription($sub);
|
||||
|
||||
// The subscription should be active to start with. Pass in the id only to refetch the data.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should still be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Make the course module invisible, which should in turn make the subscription inactive.
|
||||
set_coursemodule_visible($book->cmid, false);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should NOT be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Make the course module visible again.
|
||||
set_coursemodule_visible($book->cmid, true);
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should be active. Pass in the id only to refetch the data.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that long term inactive subscriptions are removed entirely.
|
||||
*/
|
||||
public function test_stale_subscription_removal() {
|
||||
global $DB;
|
||||
// Manually set the inactivedate to 1 day older than the limit allowed.
|
||||
$daysold = 1 + \tool_monitor\subscription_manager::INACTIVE_SUBSCRIPTION_LIFESPAN_IN_DAYS;
|
||||
|
||||
$inactivedate = strtotime("-$daysold days", time());
|
||||
$DB->set_field('tool_monitor_subscriptions', 'inactivedate', $inactivedate, array('id' => $this->subscription->id));
|
||||
|
||||
// Subscription should be inactive to start with.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// Subscription should now not exist at all.
|
||||
$this->assertEquals(false, $DB->record_exists('tool_monitor_subscriptions', array('id' => $this->subscription->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that subscriptions for a partially set up user are deactivated.
|
||||
*/
|
||||
public function test_user_not_fully_set_up() {
|
||||
global $DB;
|
||||
|
||||
// Enrol the user as a teacher.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// The subscription should be active to start.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Unset the user's email address, so we fail the check_subscriptions->is_user_setup() call.
|
||||
$DB->set_field('user', 'email', '', array('id' => $this->user->id));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should now be inactive.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to confirm that a suspended user's subscriptions are deactivated properly.
|
||||
*/
|
||||
public function test_suspended_user() {
|
||||
global $DB;
|
||||
|
||||
// Enrol the user as a teacher. This role should have the required capability.
|
||||
$this->getDataGenerator()->enrol_user($this->user->id, $this->course->id, $this->teacherrole->id);
|
||||
|
||||
// Subscription should be active to start with.
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Suspend the user.
|
||||
$DB->set_field('user', 'suspended', '1', array('id' => $this->user->id));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should now be inactive.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(false, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
|
||||
// Unsuspend the user.
|
||||
$DB->set_field('user', 'suspended', '0', array('id' => $this->user->id));
|
||||
|
||||
// Run the task.
|
||||
$task = new \tool_monitor\task\check_subscriptions();
|
||||
$task->execute();
|
||||
|
||||
// The subscription should now be active again.
|
||||
$this->reload_subscription();
|
||||
$this->assertEquals(true, \tool_monitor\subscription_manager::subscription_is_active($this->subscription));
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$plugin->version = 2015051100; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2015051101; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2015050500; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_monitor'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -567,8 +567,18 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
}
|
||||
if ($existinguser->$column !== $user->$column) {
|
||||
if ($column === 'email') {
|
||||
if ($DB->record_exists('user', array('email'=>$user->email))) {
|
||||
if ($noemailduplicates) {
|
||||
$select = $DB->sql_like('email', ':email', false, true, false, '|');
|
||||
$params = array('email' => $DB->sql_like_escape($user->email, '|'));
|
||||
if ($DB->record_exists_select('user', $select , $params)) {
|
||||
|
||||
$changeincase = core_text::strtolower($existinguser->$column) === core_text::strtolower(
|
||||
$user->$column);
|
||||
|
||||
if ($changeincase) {
|
||||
// If only case is different then switch to lower case and carry on.
|
||||
$user->$column = core_text::strtolower($user->$column);
|
||||
continue;
|
||||
} else if ($noemailduplicates) {
|
||||
$upt->track('email', $stremailduplicate, 'error');
|
||||
$upt->track('status', $strusernotupdated, 'error');
|
||||
$userserrors++;
|
||||
@@ -1177,7 +1187,10 @@ while ($linenum <= $previewrows and $fields = $cir->next()) {
|
||||
if (!validate_email($rowcols['email'])) {
|
||||
$rowcols['status'][] = get_string('invalidemail');
|
||||
}
|
||||
if ($DB->record_exists('user', array('email'=>$rowcols['email']))) {
|
||||
|
||||
$select = $DB->sql_like('email', ':email', false, true, false, '|');
|
||||
$params = array('email' => $DB->sql_like_escape($rowcols['email'], '|'));
|
||||
if ($DB->record_exists_select('user', $select , $params)) {
|
||||
$rowcols['status'][] = $stremailduplicate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +328,7 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
$updateuser = new stdClass();
|
||||
$updateuser->id = $user->id;
|
||||
$updateuser->suspended = 1;
|
||||
$updateuser = $this->clean_data($updateuser);
|
||||
user_update_user($updateuser, false);
|
||||
$trace->output(get_string('auth_dbsuspenduser', 'auth_db', array('name'=>$user->username, 'id'=>$user->id)), 1);
|
||||
}
|
||||
@@ -414,6 +415,7 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
$updateuser = new stdClass();
|
||||
$updateuser->id = $olduser->id;
|
||||
$updateuser->suspended = 0;
|
||||
$updateuser = $this->clean_data($updateuser);
|
||||
user_update_user($updateuser);
|
||||
$trace->output(get_string('auth_dbreviveduser', 'auth_db', array('name' => $username,
|
||||
'id' => $olduser->id)), 1);
|
||||
@@ -436,6 +438,7 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
$trace->output(get_string('auth_dbinsertuserduplicate', 'auth_db', array('username'=>$user->username, 'auth'=>$collision->auth)), 1);
|
||||
continue;
|
||||
}
|
||||
$user = $this->clean_data($user);
|
||||
try {
|
||||
$id = user_create_user($user, false); // It is truly a new user.
|
||||
$trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)), 1);
|
||||
@@ -577,6 +580,7 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
}
|
||||
if ($needsupdate) {
|
||||
require_once($CFG->dirroot . '/user/lib.php');
|
||||
$updateuser = $this->clean_data($updateuser);
|
||||
user_update_user($updateuser);
|
||||
}
|
||||
return $DB->get_record('user', array('id'=>$userid, 'deleted'=>0));
|
||||
@@ -906,6 +910,30 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
error_reporting($CFG->debug);
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean the user data that comes from an external database.
|
||||
*
|
||||
* @param array $user the user data to be validated against properties definition.
|
||||
* @return stdClass $user the cleaned user data.
|
||||
*/
|
||||
public function clean_data($user) {
|
||||
if (empty($user)) {
|
||||
return $user;
|
||||
}
|
||||
|
||||
foreach ($user as $field => $value) {
|
||||
// Get the property parameter type and do the cleaning.
|
||||
try {
|
||||
$property = core_user::get_property_definition($field);
|
||||
$user->$field = clean_param($value, $property['type']);
|
||||
} catch (coding_exception $e) {
|
||||
debugging("The property '$field' could not be cleaned.", DEBUG_DEVELOPER);
|
||||
}
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ $string['auth_dbname'] = 'Name of the database itself. Leave empty if using an O
|
||||
$string['auth_dbname_key'] = 'DB name';
|
||||
$string['auth_dbpass'] = 'Password matching the above username';
|
||||
$string['auth_dbpass_key'] = 'Password';
|
||||
$string['auth_dbpasstype'] = '<p>Specify the format that the password field is using. MD5 hashing is useful for connecting to other common web applications like PostNuke.</p> <p>Use \'internal\' if you want to the external DB to manage usernames & email addresses, but Moodle to manage passwords. If you use \'internal\', you <i>must</i> provide a populated email address field in the external DB, and you must execute both admin/cron.php and auth/db/cli/sync_users.php regularly. Moodle will send an email to new users with a temporary password.</p>';
|
||||
$string['auth_dbpasstype'] = '<p>Specify the format that the password field is using. MD5 hashing is useful for connecting to other common web applications like PostNuke.</p> <p>Use \'internal\' if you want the external database to manage usernames and email addresses, but Moodle to manage passwords. If you use \'internal\', you <i>must</i> provide a populated email address field in the external database, and you must execute both admin/cron.php and auth/db/cli/sync_users.php regularly. Moodle will send an email to new users with a temporary password.</p>';
|
||||
$string['auth_dbpasstype_key'] = 'Password format';
|
||||
$string['auth_dbreviveduser'] = 'Revived user {$a->name} id {$a->id}';
|
||||
$string['auth_dbrevivedusererror'] = 'Error reviving user {$a}';
|
||||
|
||||
@@ -309,7 +309,7 @@ class auth_db_testcase extends advanced_testcase {
|
||||
require_once($CFG->libdir.'/password_compat/lib/password.php');
|
||||
set_config('passtype', 'saltedcrypt', 'auth/db');
|
||||
$auth->config->passtype = 'saltedcrypt';
|
||||
$user3->pass = password_hash('heslo', PASSWORD_BCRYPT, array('salt' => 'best_salt_ever_moodle_rocks_dont_tell'));
|
||||
$user3->pass = password_hash('heslo', PASSWORD_BCRYPT);
|
||||
$DB->update_record('auth_db_users', $user3);
|
||||
$this->assertTrue($auth->user_login('u3', 'heslo'));
|
||||
|
||||
@@ -381,4 +381,77 @@ class auth_db_testcase extends advanced_testcase {
|
||||
|
||||
$this->cleanup_auth_database();
|
||||
}
|
||||
|
||||
/**
|
||||
* Testing the clean_data() method.
|
||||
*/
|
||||
public function test_clean_data() {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest(false);
|
||||
$this->preventResetByRollback();
|
||||
$this->init_auth_database();
|
||||
$auth = get_auth_plugin('db');
|
||||
$auth->db_init();
|
||||
|
||||
// Create users on external table.
|
||||
$extdbuser1 = (object)array('name'=>'u1', 'pass'=>'heslo', 'email'=>'u1@example.com');
|
||||
$extdbuser1->id = $DB->insert_record('auth_db_users', $extdbuser1);
|
||||
|
||||
// User with malicious data on the name.
|
||||
$extdbuser2 = (object)array('name'=>'user<script>alert(1);</script>xss', 'pass'=>'heslo', 'email'=>'xssuser@example.com');
|
||||
$extdbuser2->id = $DB->insert_record('auth_db_users', $extdbuser2);
|
||||
|
||||
$trace = new null_progress_trace();
|
||||
|
||||
// Let's test user sync make sure still works as expected..
|
||||
$auth->sync_users($trace, true);
|
||||
|
||||
// Get the user on moodle user table.
|
||||
$user2 = $DB->get_record('user', array('email'=> $extdbuser2->email, 'auth'=>'db'));
|
||||
|
||||
// The malicious code should be sanitized.
|
||||
$this->assertEquals($user2->username, 'userscriptalert1scriptxss');
|
||||
$this->assertNotEquals($user2->username, $extdbuser2->name);
|
||||
|
||||
// User with correct data, should be equal to external db.
|
||||
$user1 = $DB->get_record('user', array('email'=> $extdbuser1->email, 'auth'=>'db'));
|
||||
$this->assertEquals($extdbuser1->name, $user1->username);
|
||||
$this->assertEquals($extdbuser1->email, $user1->email);
|
||||
|
||||
// Now, let's update the name.
|
||||
$extdbuser2->name = 'user no xss anymore';
|
||||
$DB->update_record('auth_db_users', $extdbuser2);
|
||||
|
||||
// Run sync again to update the user data.
|
||||
$auth->sync_users($trace, true);
|
||||
|
||||
// The user information should be updated.
|
||||
$user2 = $DB->get_record('user', array('username' => 'usernoxssanymore', 'auth' => 'db'));
|
||||
// The spaces should be removed, as it's the username.
|
||||
$this->assertEquals($user2->username, 'usernoxssanymore');
|
||||
|
||||
// Now let's test just the clean_data() method isolated.
|
||||
// Testing PARAM_USERNAME, PARAM_NOTAGS, PARAM_RAW_TRIMMED and others.
|
||||
$user3 = new stdClass();
|
||||
$user3->firstname = 'John <script>alert(1)</script> Doe';
|
||||
$user3->username = 'john%#&~%*_doe';
|
||||
$user3->email = ' john@testing.com ';
|
||||
$user3->deleted = 'no';
|
||||
$user3->description = '<b>A description about myself.</b>';
|
||||
$user3cleaned = $auth->clean_data($user3);
|
||||
|
||||
// Expected results.
|
||||
$this->assertEquals($user3cleaned->firstname, 'John alert(1) Doe');
|
||||
$this->assertEquals($user3cleaned->email, 'john@testing.com');
|
||||
$this->assertEquals($user3cleaned->deleted, 0);
|
||||
$this->assertEquals($user3->description, '<b>A description about myself.</b>');
|
||||
$this->assertEquals($user3->username, 'john_doe');
|
||||
|
||||
// Try to clean an invalid property (fullname).
|
||||
$user3->fullname = 'John Doe';
|
||||
$auth->clean_data($user3);
|
||||
$this->assertDebuggingCalled("The property 'fullname' could not be cleaned.");
|
||||
$this->cleanup_auth_database();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ $string['auth_ldap_gracelogins_desc'] = 'Enable LDAP gracelogin support. After p
|
||||
$string['auth_ldap_gracelogins_key'] = 'Grace logins';
|
||||
$string['auth_ldap_groupecreators'] = 'List of groups or contexts whose members are allowed to create groups. Separate multiple groups with \';\'. Usually something like \'cn=teachers,ou=staff,o=myorg\'';
|
||||
$string['auth_ldap_groupecreators_key'] = 'Group creators';
|
||||
$string['auth_ldap_host_url'] = 'Specify LDAP host in URL-form like \'ldap://ldap.myorg.com/\' or \'ldaps://ldap.myorg.com/\' Separate multipleservers with \';\' to get failover support.';
|
||||
$string['auth_ldap_host_url'] = 'Specify LDAP host in URL-form like \'ldap://ldap.myorg.com/\' or \'ldaps://ldap.myorg.com/\'. Separate multiple servers with \';\' to get failover support.';
|
||||
$string['auth_ldap_host_url_key'] = 'Host URL';
|
||||
$string['auth_ldap_changepasswordurl_key'] = 'Password-change URL';
|
||||
$string['auth_ldap_ldap_encoding'] = 'Specify encoding used by LDAP server. Most probably utf-8, MS AD v2 uses default platform encoding such as cp1252, cp1250, etc.';
|
||||
|
||||
@@ -35,6 +35,7 @@ $wantsremoteurl = optional_param('remoteurl', false, PARAM_BOOL);
|
||||
$url = new moodle_url('/auth/mnet/jump.php', array('token'=>$token, 'idp'=>$remotewwwroot, 'wantsurl'=>$wantsurl));
|
||||
if ($wantsremoteurl !== false) $url->param('remoteurl', $wantsremoteurl);
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_context(context_system::instance());
|
||||
|
||||
$site = get_site();
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ if (!is_enabled_auth('shibboleth')) {
|
||||
}
|
||||
|
||||
// Front channel logout.
|
||||
$inputstream = file_get_contents("php://input");
|
||||
if ($action == 'logout' && !empty($redirect)) {
|
||||
|
||||
if ($USER->auth == 'shibboleth') {
|
||||
@@ -32,7 +33,7 @@ if ($action == 'logout' && !empty($redirect)) {
|
||||
redirect($redirect);
|
||||
}
|
||||
|
||||
} else if (!empty($HTTP_RAW_POST_DATA)) {
|
||||
} else if (!empty($inputstream)) {
|
||||
|
||||
// Back channel logout.
|
||||
// Set SOAP header.
|
||||
|
||||
@@ -47,34 +47,15 @@ class behat_auth extends behat_base {
|
||||
* @Given /^I log in as "(?P<username_string>(?:[^"]|\\")*)"$/
|
||||
*/
|
||||
public function i_log_in_as($username) {
|
||||
// Visit login page.
|
||||
$this->getSession()->visit($this->locate_path('login/index.php'));
|
||||
|
||||
// Running this step using the API rather than a chained step because
|
||||
// we need to see if the 'Log in' link is available or we need to click
|
||||
// the dropdown to expand the navigation bar before.
|
||||
$this->getSession()->visit($this->locate_path('/'));
|
||||
// Enter username and password.
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('Username', $this->escape($username)));
|
||||
$this->execute('behat_forms::i_set_the_field_to', array('Password', $this->escape($username)));
|
||||
|
||||
// Generic steps (we will prefix them later expanding the navigation dropdown if necessary).
|
||||
$steps = array(
|
||||
new Given('I click on "' . get_string('login') . '" "link" in the ".logininfo" "css_element"'),
|
||||
new Given('I set the field "' . get_string('username') . '" to "' . $this->escape($username) . '"'),
|
||||
new Given('I set the field "' . get_string('password') . '" to "'. $this->escape($username) . '"'),
|
||||
new Given('I press "' . get_string('login') . '"')
|
||||
);
|
||||
|
||||
// If Javascript is disabled we have enough with these steps.
|
||||
if (!$this->running_javascript()) {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
// Wait for the homepage to be ready.
|
||||
$this->getSession()->wait(self::TIMEOUT * 1000, self::PAGE_READY_JS);
|
||||
|
||||
// If it is needed, it expands the navigation bar with the 'Log in' link.
|
||||
if ($clicknavbar = $this->get_expand_navbar_step()) {
|
||||
array_unshift($steps, $clicknavbar);
|
||||
}
|
||||
|
||||
return $steps;
|
||||
// Press log in button, no need to check for exceptions as it will checked after this step execution.
|
||||
$this->execute('behat_forms::press_button', get_string('login'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,53 +64,16 @@ class behat_auth extends behat_base {
|
||||
* @Given /^I log out$/
|
||||
*/
|
||||
public function i_log_out() {
|
||||
|
||||
$steps = array(new When('I follow "' . get_string('logout') . '"'));
|
||||
|
||||
// No need to check anything else if we run without JS.
|
||||
if (!$this->running_javascript()) {
|
||||
return $steps;
|
||||
}
|
||||
|
||||
// There is no longer any need to worry about whether the navigation
|
||||
// bar needs to be expanded; user_menu now lives outside the
|
||||
// hamburger.
|
||||
|
||||
// However, the user menu *always* needs to be expanded.
|
||||
$xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
|
||||
array_unshift($steps, new When('I click on "'.$xpath.'" "xpath_element"'));
|
||||
|
||||
return $steps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a step to open the navigation bar if it is needed.
|
||||
*
|
||||
* The top log in and log out links are hidden when middle or small
|
||||
* size windows (or devices) are used. This step returns a step definition
|
||||
* clicking to expand the navbar if it is hidden.
|
||||
*
|
||||
* @return Given|bool A step definition or false if there is no need to show the navbar.
|
||||
*/
|
||||
protected function get_expand_navbar_step() {
|
||||
|
||||
// Checking if we need to click the navbar button to show the navigation menu, it
|
||||
// is hidden by default when using clean theme and a medium or small screen size.
|
||||
|
||||
// The DOM and the JS should be all ready and loaded. Running without spinning
|
||||
// as this is a widely used step and we can not spend time here trying to see
|
||||
// a DOM node that is not always there (at the moment clean is not even the
|
||||
// default theme...).
|
||||
$navbuttonjs = "return (
|
||||
Y.one('.btn-navbar') &&
|
||||
Y.one('.btn-navbar').getComputedStyle('display') !== 'none'
|
||||
)";
|
||||
|
||||
// Adding an extra click we need to show the 'Log in' link.
|
||||
if (!$this->getSession()->getDriver()->evaluateScript($navbuttonjs)) {
|
||||
return false;
|
||||
// However, the user menu *always* needs to be expanded. if running JS.
|
||||
if ($this->running_javascript()) {
|
||||
$xpath = "//div[@class='usermenu']//a[contains(concat(' ', @class, ' '), ' toggle-display ')]";
|
||||
$this->execute('behat_general::i_click_on', array($xpath, "xpath_element"));
|
||||
}
|
||||
|
||||
return new Given('I click on ".btn-navbar" "css_element"');
|
||||
// No need to check for exceptions as it will checked after this step execution.
|
||||
$this->execute('behat_general::click_link', get_string('logout'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
-1
@@ -138,7 +138,9 @@ if ($backup->get_stage() == backup_ui::STAGE_FINAL) {
|
||||
}
|
||||
|
||||
// Get HTML from logger.
|
||||
$loghtml = $logger->get_html();
|
||||
if ($CFG->debugdisplay) {
|
||||
$loghtml = $logger->get_html();
|
||||
}
|
||||
|
||||
// Hide the progress display and first backup step bar (the 'finished' step will show next).
|
||||
echo html_writer::end_div();
|
||||
|
||||
@@ -1700,27 +1700,54 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
*/
|
||||
public function process_course($data) {
|
||||
global $CFG, $DB;
|
||||
$context = context::instance_by_id($this->task->get_contextid());
|
||||
$userid = $this->task->get_userid();
|
||||
$target = $this->get_task()->get_target();
|
||||
$isnewcourse = $target != backup::TARGET_CURRENT_ADDING && $target != backup::TARGET_EXISTING_ADDING;
|
||||
|
||||
// When restoring to a new course we can set all the things except for the ID number.
|
||||
$canchangeidnumber = $isnewcourse || has_capability('moodle/course:changeidnumber', $context, $userid);
|
||||
$canchangeshortname = $isnewcourse || has_capability('moodle/course:changeshortname', $context, $userid);
|
||||
$canchangefullname = $isnewcourse || has_capability('moodle/course:changefullname', $context, $userid);
|
||||
$canchangesummary = $isnewcourse || has_capability('moodle/course:changesummary', $context, $userid);
|
||||
|
||||
$data = (object)$data;
|
||||
$data->id = $this->get_courseid();
|
||||
|
||||
$fullname = $this->get_setting_value('course_fullname');
|
||||
$shortname = $this->get_setting_value('course_shortname');
|
||||
$startdate = $this->get_setting_value('course_startdate');
|
||||
|
||||
// Calculate final course names, to avoid dupes
|
||||
// Calculate final course names, to avoid dupes.
|
||||
list($fullname, $shortname) = restore_dbops::calculate_course_names($this->get_courseid(), $fullname, $shortname);
|
||||
|
||||
// Need to change some fields before updating the course record
|
||||
$data->id = $this->get_courseid();
|
||||
$data->fullname = $fullname;
|
||||
$data->shortname= $shortname;
|
||||
if ($canchangefullname) {
|
||||
$data->fullname = $fullname;
|
||||
} else {
|
||||
unset($data->fullname);
|
||||
}
|
||||
|
||||
if ($canchangeshortname) {
|
||||
$data->shortname = $shortname;
|
||||
} else {
|
||||
unset($data->shortname);
|
||||
}
|
||||
|
||||
if (!$canchangesummary) {
|
||||
unset($data->summary);
|
||||
unset($data->summaryformat);
|
||||
}
|
||||
|
||||
// Only allow the idnumber to be set if the user has permission and the idnumber is not already in use by
|
||||
// another course on this site.
|
||||
$context = context::instance_by_id($this->task->get_contextid());
|
||||
if (!empty($data->idnumber) && has_capability('moodle/course:changeidnumber', $context, $this->task->get_userid()) &&
|
||||
$this->task->is_samesite() && !$DB->record_exists('course', array('idnumber' => $data->idnumber))) {
|
||||
if (!empty($data->idnumber) && $canchangeidnumber && $this->task->is_samesite()
|
||||
&& !$DB->record_exists('course', array('idnumber' => $data->idnumber))) {
|
||||
// Do not reset idnumber.
|
||||
|
||||
} else if (!$isnewcourse) {
|
||||
// Prevent override when restoring as merge.
|
||||
unset($data->idnumber);
|
||||
|
||||
} else {
|
||||
$data->idnumber = '';
|
||||
}
|
||||
|
||||
+3
-1
@@ -110,7 +110,9 @@ if (!$restore->is_independent()) {
|
||||
// Do actual restore.
|
||||
$restore->execute();
|
||||
// Get HTML from logger.
|
||||
$loghtml = $logger->get_html();
|
||||
if ($CFG->debugdisplay) {
|
||||
$loghtml = $logger->get_html();
|
||||
}
|
||||
// Hide this section because we are now going to make the page show 'finished'.
|
||||
echo html_writer::end_div();
|
||||
echo html_writer::script('document.getElementById("executionprogress").style.display = "none";');
|
||||
|
||||
@@ -1287,7 +1287,11 @@ abstract class restore_dbops {
|
||||
* 1F - None of the above, return true => User needs to be created
|
||||
*
|
||||
* if restoring from another site backup (cannot match by id here, replace it by email/firstaccess combination):
|
||||
* 2A - Normal check: If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
|
||||
* 2A - Normal check:
|
||||
* 2A1 - If match by username and mnethost and (email or non-zero firstaccess) => ok, return target user
|
||||
* 2A2 - Exceptional handling (MDL-21912): Match "admin" username. Then, if import_general_duplicate_admin_allowed is
|
||||
* enabled, attempt to map the admin user to the user 'admin_[oldsiteid]' if it exists. If not,
|
||||
* the user 'admin_[oldsiteid]' will be created in precheck_included users
|
||||
* 2B - Handle users deleted in DB and "alive" in backup file:
|
||||
* 2B1 - If match by mnethost and user is deleted in DB and not empty email = md5(username) and
|
||||
* (username LIKE 'backup_email.%' or non-zero firstaccess) => ok, return target user
|
||||
@@ -1305,7 +1309,7 @@ abstract class restore_dbops {
|
||||
* Note: for DB deleted users md5(username) is stored *sometimes* in the email field,
|
||||
* hence we are looking there for usernames if not empty. See delete_user()
|
||||
*/
|
||||
protected static function precheck_user($user, $samesite) {
|
||||
protected static function precheck_user($user, $samesite, $siteid = null) {
|
||||
global $CFG, $DB;
|
||||
|
||||
// Handle checks from same site backups
|
||||
@@ -1376,7 +1380,7 @@ abstract class restore_dbops {
|
||||
// Handle checks from different site backups
|
||||
} else {
|
||||
|
||||
// 2A - If match by username and mnethost and
|
||||
// 2A1 - If match by username and mnethost and
|
||||
// (email or non-zero firstaccess) => ok, return target user
|
||||
if ($rec = $DB->get_record_sql("SELECT *
|
||||
FROM {user} u
|
||||
@@ -1393,6 +1397,14 @@ abstract class restore_dbops {
|
||||
return $rec; // Matching user found, return it
|
||||
}
|
||||
|
||||
// 2A2 - If we're allowing conflicting admins, attempt to map user to admin_[oldsiteid].
|
||||
if (get_config('backup', 'import_general_duplicate_admin_allowed') && $user->username === 'admin' && $siteid
|
||||
&& $user->mnethostid == $CFG->mnet_localhost_id) {
|
||||
if ($rec = $DB->get_record('user', array('username' => 'admin_' . $siteid))) {
|
||||
return $rec;
|
||||
}
|
||||
}
|
||||
|
||||
// 2B - Handle users deleted in DB and "alive" in backup file
|
||||
// Note: for DB deleted users email is stored in username field, hence we
|
||||
// are looking there for emails. See delete_user()
|
||||
@@ -1500,6 +1512,9 @@ abstract class restore_dbops {
|
||||
// Calculate the context we are going to use for capability checking
|
||||
$context = context_course::instance($courseid);
|
||||
|
||||
// When conflicting users are detected we may need original site info.
|
||||
$restoreinfo = restore_controller_dbops::load_controller($restoreid)->get_info();
|
||||
|
||||
// Calculate if we have perms to create users, by checking:
|
||||
// to 'moodle/restore:createuser' and 'moodle/restore:userinfo'
|
||||
// and also observe $CFG->disableusercreationonrestore
|
||||
@@ -1535,14 +1550,28 @@ abstract class restore_dbops {
|
||||
}
|
||||
|
||||
// Now, precheck that user and, based on returned results, annotate action/problem
|
||||
$usercheck = self::precheck_user($user, $samesite);
|
||||
$usercheck = self::precheck_user($user, $samesite, $restoreinfo->original_site_identifier_hash);
|
||||
|
||||
if (is_object($usercheck)) { // No problem, we have found one user in DB to be mapped to
|
||||
// Annotate it, for later process. Set newitemid to mapping user->id
|
||||
self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, $usercheck->id);
|
||||
|
||||
} else if ($usercheck === false) { // Found conflict, report it as problem
|
||||
$problems[] = get_string('restoreuserconflict', '', $user->username);
|
||||
if (!get_config('backup', 'import_general_duplicate_admin_allowed')) {
|
||||
$problems[] = get_string('restoreuserconflict', '', $user->username);
|
||||
} else if ($user->username == 'admin') {
|
||||
if (!$cancreateuser) {
|
||||
$problems[] = get_string('restorecannotcreateuser', '', $user->username);
|
||||
}
|
||||
if ($user->mnethostid != $CFG->mnet_localhost_id) {
|
||||
$problems[] = get_string('restoremnethostidmismatch', '', $user->username);
|
||||
}
|
||||
if (!$problems) {
|
||||
// Duplicate admin allowed, append original site idenfitier to username.
|
||||
$user->username .= '_' . $restoreinfo->original_site_identifier_hash;
|
||||
self::set_backup_ids_record($restoreid, 'user', $recuser->itemid, 0, null, (array)$user);
|
||||
}
|
||||
}
|
||||
|
||||
} else if ($usercheck === true) { // User needs to be created, check if we are able
|
||||
if ($cancreateuser) { // Can create user, set newitemid to 0 so will be created later
|
||||
|
||||
@@ -97,7 +97,10 @@ class restore_log_rule implements processable {
|
||||
return $this->module . '-' . $this->action;
|
||||
}
|
||||
|
||||
public function process($log) {
|
||||
public function process($inputlog) {
|
||||
|
||||
// There might be multiple rules that process this log, we can't alter it in the process of checking it.
|
||||
$log = clone($inputlog);
|
||||
|
||||
// Reset the allpairs array
|
||||
$this->allpairs = array();
|
||||
|
||||
@@ -89,11 +89,12 @@ class restore_logs_processor {
|
||||
}
|
||||
// Arrived here log is empty, no rule was able to perform the conversion, log the problem
|
||||
if (empty($newlog)) {
|
||||
self::$task->log('Log module-action "' . $keyname . '" process problem. Not restored', backup::LOG_DEBUG);
|
||||
self::$task->log('Log module-action "' . $keyname . '" process problem. Not restored. ' .
|
||||
json_encode($log), backup::LOG_DEBUG);
|
||||
}
|
||||
|
||||
} else { // Action not found log the problem
|
||||
self::$task->log('Log module-action "' . $keyname . '" unknown. Not restored', backup::LOG_DEBUG);
|
||||
self::$task->log('Log module-action "' . $keyname . '" unknown. Not restored. '.json_encode($log), backup::LOG_DEBUG);
|
||||
$newlog = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* @package core_backup
|
||||
* @category test
|
||||
* @copyright 2015 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
// Include all the needed stuff
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
|
||||
|
||||
class backup_restore_log_rule_testcase extends basic_testcase {
|
||||
|
||||
function test_process_keeps_log_unmodified() {
|
||||
|
||||
// Prepare a tiny log entry.
|
||||
$originallog = new stdClass();
|
||||
$originallog->url = 'original';
|
||||
$originallog->info = 'original';
|
||||
$log = clone($originallog);
|
||||
|
||||
// Process it with a tiny log rule, only modifying url and info.
|
||||
$lr = new restore_log_rule('test', 'test', 'changed', 'changed');
|
||||
$result = $lr->process($log);
|
||||
|
||||
// The log has been processed.
|
||||
$this->assertEquals('changed', $result->url);
|
||||
$this->assertEquals('changed', $result->info);
|
||||
|
||||
// But the original log has been kept unmodified by the process() call.
|
||||
$this->assertEquals($originallog, $log);
|
||||
}
|
||||
}
|
||||
@@ -172,8 +172,8 @@ class behat_backup extends behat_base {
|
||||
"/descendant::tr[contains(., $fromcourse)]" .
|
||||
"/descendant::input[@type='radio']";
|
||||
$radionode = $this->find('xpath', $xpath, $exception);
|
||||
$radionode->check();
|
||||
$radionode->click();
|
||||
$radiofield = new behat_form_field($this->getSession(), $radionode);
|
||||
$radiofield->set_value(1);
|
||||
|
||||
$this->find_button(get_string('continue'))->press();
|
||||
$this->wait();
|
||||
|
||||
@@ -4,7 +4,6 @@ Feature: Import course's contents into another course
|
||||
As a teacher
|
||||
I need to import a course contents into another course selecting what I want to import
|
||||
|
||||
@javascript
|
||||
Scenario: Import course's contents to another course
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
|
||||
@@ -28,7 +28,6 @@ Feature: Option to include groups and groupings when importing a course to anoth
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
|
||||
@javascript
|
||||
Scenario: Include groups and groupings when importing a course to another course
|
||||
When I import "Course 1" course into "Course 2" course using this options:
|
||||
| Initial | Include groups and groupings | 1 |
|
||||
@@ -40,7 +39,6 @@ Feature: Option to include groups and groupings when importing a course to anoth
|
||||
And I should see "Grouping 1"
|
||||
And I should see "Grouping 2"
|
||||
|
||||
@javascript
|
||||
Scenario: Do not include groups and groupings when importing a course to another course
|
||||
When I import "Course 1" course into "Course 2" course using this options:
|
||||
| Initial | Include groups and groupings | 0 |
|
||||
|
||||
+2
-8
@@ -45,13 +45,7 @@ function core_badges_myprofile_navigation(\core_user\output\myprofile\tree $tree
|
||||
// Add category. This node should appear after 'contact' so that administration block appears towards the end. Refer MDL-49928.
|
||||
$category = new core_user\output\myprofile\category('badges', get_string('badges', 'badges'), 'contact');
|
||||
$tree->add_category($category);
|
||||
|
||||
// Determine context.
|
||||
if (isloggedin()) {
|
||||
$context = context_user::instance($USER->id);
|
||||
} else {
|
||||
$context = context_system::instance();
|
||||
}
|
||||
$context = context_user::instance($user->id);
|
||||
$courseid = empty($course) ? 0 : $course->id;
|
||||
|
||||
if ($USER->id == $user->id || has_capability('moodle/badges:viewotherbadges', $context)) {
|
||||
@@ -78,4 +72,4 @@ function core_badges_myprofile_navigation(\core_user\output\myprofile\tree $tree
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/badgeslib.php');
|
||||
require_once($CFG->dirroot . '/badges/lib.php');
|
||||
|
||||
class core_badges_badgeslib_testcase extends advanced_testcase {
|
||||
protected $badgeid;
|
||||
@@ -472,4 +473,69 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
|
||||
$this->assertStringMatchesFormat($testassertion->class, json_encode($assertion->get_badge_class()));
|
||||
$this->assertStringMatchesFormat($testassertion->issuer, json_encode($assertion->get_issuer()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the core_badges_myprofile_navigation() function.
|
||||
*/
|
||||
public function test_core_badges_myprofile_navigation() {
|
||||
// Set up the test.
|
||||
$tree = new \core_user\output\myprofile\tree();
|
||||
$this->setAdminUser();
|
||||
$badge = new badge($this->badgeid);
|
||||
$badge->issue($this->user->id, true);
|
||||
$iscurrentuser = true;
|
||||
$course = null;
|
||||
|
||||
// Enable badges.
|
||||
set_config('enablebadges', true);
|
||||
|
||||
// Check the node tree is correct.
|
||||
core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course);
|
||||
$reflector = new ReflectionObject($tree);
|
||||
$nodes = $reflector->getProperty('nodes');
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayHasKey('localbadges', $nodes->getValue($tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the core_badges_myprofile_navigation() function with badges disabled..
|
||||
*/
|
||||
public function test_core_badges_myprofile_navigation_badges_disabled() {
|
||||
// Set up the test.
|
||||
$tree = new \core_user\output\myprofile\tree();
|
||||
$this->setAdminUser();
|
||||
$badge = new badge($this->badgeid);
|
||||
$badge->issue($this->user->id, true);
|
||||
$iscurrentuser = false;
|
||||
$course = null;
|
||||
|
||||
// Disable badges.
|
||||
set_config('enablebadges', false);
|
||||
|
||||
// Check the node tree is correct.
|
||||
core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $course);
|
||||
$reflector = new ReflectionObject($tree);
|
||||
$nodes = $reflector->getProperty('nodes');
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayNotHasKey('localbadges', $nodes->getValue($tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the core_badges_myprofile_navigation() function with a course badge.
|
||||
*/
|
||||
public function test_core_badges_myprofile_navigation_with_course_badge() {
|
||||
// Set up the test.
|
||||
$tree = new \core_user\output\myprofile\tree();
|
||||
$this->setAdminUser();
|
||||
$badge = new badge($this->coursebadge);
|
||||
$badge->issue($this->user->id, true);
|
||||
$iscurrentuser = false;
|
||||
|
||||
// Check the node tree is correct.
|
||||
core_badges_myprofile_navigation($tree, $this->user, $iscurrentuser, $this->course);
|
||||
$reflector = new ReflectionObject($tree);
|
||||
$nodes = $reflector->getProperty('nodes');
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayHasKey('localbadges', $nodes->getValue($tree));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,16 +221,13 @@ Feature: Award badges
|
||||
And I follow "Course 1"
|
||||
And I press "Mark as complete: Test assignment name"
|
||||
And I log out
|
||||
And I log in as "admin"
|
||||
# We can't wait for cron to happen, so the admin manually triggers it.
|
||||
And I trigger cron
|
||||
# The admin needs to trigger cron twice to see the completion status as completed.
|
||||
# We wait more than 1 minute because of the next cron run scheduled time.
|
||||
And I wait "61" seconds
|
||||
And I trigger cron
|
||||
# Finally the admin goes back to homepage to continue the user story.
|
||||
And I am on site homepage
|
||||
And I log out
|
||||
# Completion cron won't mark the whole course completed unless the
|
||||
# individual criteria was marked completed more than a second ago. So
|
||||
# run it twice, first to mark the criteria and second for the course.
|
||||
And I run the scheduled task "core\task\completion_cron_task"
|
||||
And I wait "1" seconds
|
||||
And I run the scheduled task "core\task\completion_cron_task"
|
||||
# The student should now see their badge.
|
||||
And I log in as "student1"
|
||||
And I follow "Profile" in the user menu
|
||||
Then I should see "Course Badge"
|
||||
|
||||
@@ -35,6 +35,6 @@ Feature: The activity results block displays student scores
|
||||
When I follow "Test assignment"
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I set the following fields to these values:
|
||||
| id_modgrade_type | None |
|
||||
| id_grade_modgrade_type | None |
|
||||
And I press "Save and return to course"
|
||||
Then I should see "Error: the activity selected uses a grading method that is not supported by this block." in the "Activity results" "block"
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
@block @block_activity_results
|
||||
Feature: The activity results block displays student scores as scales
|
||||
In order to be display student scores as scales
|
||||
As a user
|
||||
I need to see the activity results block
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
| student2 | Student | 2 | student2@example.com | S2 |
|
||||
| student3 | Student | 3 | student3@example.com | S3 |
|
||||
| student4 | Student | 4 | student4@example.com | S4 |
|
||||
| student5 | Student | 5 | student5@example.com | S5 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Scales" node in "Grade administration"
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "Average" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "Not good enough" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Display full names |
|
||||
| id_config_decimalpoints | 0 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using full names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Display full names |
|
||||
And I press "Save changes"
|
||||
Then I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Student 2" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Display only ID numbers |
|
||||
And I press "Save changes"
|
||||
Then I should see "User S1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "User S2" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "User S3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Anonymous results |
|
||||
And I press "Save changes"
|
||||
Then I should see "User" in the "Activity results" "block"
|
||||
And I should not see "Student 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should not see "Student 2" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should not see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
@@ -0,0 +1,153 @@
|
||||
@block @block_activity_results
|
||||
Feature: The activity results block displays student scores as scales
|
||||
In order to be display student scores as scales
|
||||
As a user
|
||||
I need to see the activity results block
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
| student2 | Student | 2 | student2@example.com | S2 |
|
||||
| student3 | Student | 3 | student3@example.com | S3 |
|
||||
| student4 | Student | 4 | student4@example.com | S4 |
|
||||
| student5 | Student | 5 | student5@example.com | S5 |
|
||||
| student6 | Student | 6 | student6@example.com | S6 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Group 1 | C1 | G1 |
|
||||
| Group 2 | C1 | G2 |
|
||||
| Group 3 | C1 | G3 |
|
||||
| Group 4 | C1 | G4 |
|
||||
| Group 5 | C1 | G5 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
| student6 | C1 | student |
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Scales" node in "Grade administration"
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "Average" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show 1 high score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Display full names |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using full names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Display full names |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Group 2" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I follow "Course 1"
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Display only ID numbers |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I should see "User S1" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "User S2" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
| id_config_showworst | 0 |
|
||||
| id_config_nameformat | Anonymous results |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should see "Excellent!" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
@@ -33,19 +33,15 @@ Feature: The activity results block displays student scores
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
| student6 | C1 | student |
|
||||
|
||||
@javascript
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
@@ -64,7 +60,9 @@ Feature: The activity results block displays student scores
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
@@ -77,37 +75,8 @@ Feature: The activity results block displays student scores
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 high score as a fraction
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
@@ -124,37 +93,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "100.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
@@ -171,37 +111,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 1" in the "Activity results" "block"
|
||||
And I should see "100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores as percentages
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -225,37 +136,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 2" in the "Activity results" "block"
|
||||
And I should see "90%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores as fractions
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -278,37 +160,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
And I should see "80.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -331,37 +184,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 2" in the "Activity results" "block"
|
||||
And I should see "90.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -382,37 +206,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "User S2" in the "Activity results" "block"
|
||||
And I should see "90.00%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
|
||||
@@ -33,19 +33,15 @@ Feature: The activity results block displays student scores
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
| student6 | C1 | student |
|
||||
|
||||
@javascript
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
@@ -64,7 +60,9 @@ Feature: The activity results block displays student scores
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 high score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
@@ -77,37 +75,8 @@ Feature: The activity results block displays student scores
|
||||
Then I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 high score as a fraction
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
@@ -122,37 +91,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 high score as a absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 1 |
|
||||
@@ -167,37 +107,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 1" in the "Activity results" "block"
|
||||
And I should see "95.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores as percentages
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -217,37 +128,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores as fractions
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -266,37 +148,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores as absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -315,37 +168,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
@@ -362,37 +186,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 3 |
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
@block @block_activity_results
|
||||
Feature: The activity results block displays student scores as scales
|
||||
In order to be display student scores as scales
|
||||
As a user
|
||||
I need to see the activity results block
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
| student2 | Student | 2 | student2@example.com | S2 |
|
||||
| student3 | Student | 3 | student3@example.com | S3 |
|
||||
| student4 | Student | 4 | student4@example.com | S4 |
|
||||
| student5 | Student | 5 | student5@example.com | S5 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Scales" node in "Grade administration"
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "Average" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "Not good enough" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 1 |
|
||||
| id_config_gradeformat | Percentages |
|
||||
| id_config_nameformat | Display full names |
|
||||
| id_config_decimalpoints | 0 |
|
||||
And I press "Save changes"
|
||||
Then I should see "Student 5" in the "Activity results" "block"
|
||||
And I should see "Not good enough" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using full names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 3 |
|
||||
| id_config_nameformat | Display full names |
|
||||
And I press "Save changes"
|
||||
Then I should see "Student 5" in the "Activity results" "block"
|
||||
And I should see "Not good enough" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 3 |
|
||||
| id_config_nameformat | Display only ID numbers |
|
||||
And I press "Save changes"
|
||||
Then I should see "User S5" in the "Activity results" "block"
|
||||
And I should see "Not good enough" in the "Activity results" "block"
|
||||
And I should see "User S4" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
And I should see "User S3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 3 |
|
||||
| id_config_nameformat | Anonymous results |
|
||||
And I press "Save changes"
|
||||
Then I should see "User" in the "Activity results" "block"
|
||||
And I should not see "Student 5" in the "Activity results" "block"
|
||||
And I should see "Not good enough" in the "Activity results" "block"
|
||||
And I should not see "Student 4" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
And I should not see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
@@ -0,0 +1,150 @@
|
||||
@block @block_activity_results
|
||||
Feature: The activity results block displays student scores as scales
|
||||
In order to be display student scores as scales
|
||||
As a user
|
||||
I need to see the activity results block
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
| student2 | Student | 2 | student2@example.com | S2 |
|
||||
| student3 | Student | 3 | student3@example.com | S3 |
|
||||
| student4 | Student | 4 | student4@example.com | S4 |
|
||||
| student5 | Student | 5 | student5@example.com | S5 |
|
||||
| student6 | Student | 6 | student6@example.com | S6 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "groups" exist:
|
||||
| name | course | idnumber |
|
||||
| Group 1 | C1 | G1 |
|
||||
| Group 2 | C1 | G2 |
|
||||
| Group 3 | C1 | G3 |
|
||||
| Group 4 | C1 | G4 |
|
||||
| Group 5 | C1 | G5 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
| student3 | C1 | student |
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
| student6 | C1 | student |
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I navigate to "Scales" node in "Grade administration"
|
||||
And I press "Add a new scale"
|
||||
And I set the following fields to these values:
|
||||
| Name | My Scale |
|
||||
| Scale | Disappointing, Not good enough, Average, Good, Very good, Excellent! |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| id_grade_modgrade_type | Scale |
|
||||
| id_grade_modgrade_scale | My Scale |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "Excellent!" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "Very good" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "Good" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "Average" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 1 |
|
||||
| id_config_nameformat | Display full names |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I follow "Course 1"
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using full names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 2 |
|
||||
| id_config_nameformat | Display full names |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group 2" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student3"
|
||||
And I follow "Course 1"
|
||||
And I should see "Student 3" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using ID numbers
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 2 |
|
||||
| id_config_nameformat | Display only ID numbers |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I follow "Course 1"
|
||||
And I should see "User S5" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I should see "User S6" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
|
||||
Scenario: Try to configure the block on the course page to show multiple high scores using anonymous names
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
| id_config_showworst | 2 |
|
||||
| id_config_nameformat | Anonymous results |
|
||||
| id_config_usegroups | Yes |
|
||||
And I press "Save changes"
|
||||
Then I should see "Group" in the "Activity results" "block"
|
||||
And I should see "Very good" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I log out
|
||||
And I log in as "student5"
|
||||
And I follow "Course 1"
|
||||
And I should see "User" in the "Activity results" "block"
|
||||
And I should see "Good" in the "Activity results" "block"
|
||||
And I should see "Average" in the "Activity results" "block"
|
||||
|
||||
@@ -33,19 +33,15 @@ Feature: The activity results block displays student scores
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
| student6 | C1 | student |
|
||||
|
||||
@javascript
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
@@ -64,7 +60,9 @@ Feature: The activity results block displays student scores
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -77,37 +75,8 @@ Feature: The activity results block displays student scores
|
||||
Then I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 low score as a fraction
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -124,37 +93,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "70.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -171,37 +111,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "70.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores as percentages
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -223,37 +134,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 5" in the "Activity results" "block"
|
||||
And I should see "80%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores as fractions
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -274,37 +156,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 4" in the "Activity results" "block"
|
||||
And I should see "80.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -325,37 +178,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Student 6" in the "Activity results" "block"
|
||||
And I should see "70.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -375,37 +199,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "User S2" in the "Activity results" "block"
|
||||
And I should see "90.00%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Separate groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
|
||||
@@ -33,19 +33,15 @@ Feature: The activity results block displays student scores
|
||||
| student4 | C1 | student |
|
||||
| student5 | C1 | student |
|
||||
| student6 | C1 | student |
|
||||
|
||||
@javascript
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And the following "group members" exist:
|
||||
| user | group |
|
||||
| student1 | G1 |
|
||||
| student2 | G1 |
|
||||
| student3 | G2 |
|
||||
| student4 | G2 |
|
||||
| student5 | G3 |
|
||||
| student6 | G3 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
@@ -64,7 +60,9 @@ Feature: The activity results block displays student scores
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
|
||||
Scenario: Configure the block on the course page to show 1 low score
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -77,37 +75,8 @@ Feature: The activity results block displays student scores
|
||||
Then I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 low score as a fraction
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -122,37 +91,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show 1 low score as a absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -167,37 +107,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores as percentages
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -219,37 +130,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores as fractions
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -266,37 +148,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00/100.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores as absolute numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -313,37 +166,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "Group 3" in the "Activity results" "block"
|
||||
And I should see "75.00" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using ID numbers
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
@@ -359,37 +183,8 @@ Feature: The activity results block displays student scores
|
||||
And I should see "85.00%" in the "Activity results" "block"
|
||||
And I should see "75.00%" in the "Activity results" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: Try to configure the block on the course page to show multiple low scores using anonymous names
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I expand "Users" node
|
||||
And I follow "Groups"
|
||||
And I add "Student 1 (student1@example.com)" user to "Group 1" group members
|
||||
And I add "Student 2 (student2@example.com)" user to "Group 1" group members
|
||||
And I add "Student 3 (student3@example.com)" user to "Group 2" group members
|
||||
And I add "Student 4 (student4@example.com)" user to "Group 2" group members
|
||||
And I add "Student 5 (student5@example.com)" user to "Group 3" group members
|
||||
And I add "Student 6 (student6@example.com)" user to "Group 3" group members
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
| Group mode | Visible groups |
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
And I turn editing mode on
|
||||
And I give the grade "100.00" to the user "Student 1" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 2" for the grade item "Test assignment"
|
||||
And I give the grade "90.00" to the user "Student 3" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 4" for the grade item "Test assignment"
|
||||
And I give the grade "80.00" to the user "Student 5" for the grade item "Test assignment"
|
||||
And I give the grade "70.00" to the user "Student 6" for the grade item "Test assignment"
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I add the "Activity results" block
|
||||
Given I add the "Activity results" block
|
||||
When I configure the "Activity results" block
|
||||
And I set the following fields to these values:
|
||||
| id_config_showbest | 0 |
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
@block @block_admin_bookmarks
|
||||
Feature: Add a bookmarks to an admin pages
|
||||
In order to speed up common tasks
|
||||
As an admin
|
||||
I need to add and access pages through bookmarks
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Scheduled tasks" node in "Site administration > Server"
|
||||
And I click on "Bookmark this page" "link" in the "Admin bookmarks" "block"
|
||||
And I log out
|
||||
|
||||
# Test bookmark functionality using the "User profile fields" page as our bookmark.
|
||||
Scenario: Admin page can be bookmarked
|
||||
Given I log in as "admin"
|
||||
And I navigate to "User profile fields" node in "Site administration > Users > Accounts"
|
||||
When I click on "Bookmark this page" "link" in the "Admin bookmarks" "block"
|
||||
Then I should see "User profile fields" in the "Admin bookmarks" "block"
|
||||
# See the existing bookmark is there too.
|
||||
And I should see "Scheduled tasks" in the "Admin bookmarks" "block"
|
||||
|
||||
Scenario: Admin page can be accessed through bookmarks block
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Notifications" node in "Site administration"
|
||||
And I click on "Scheduled tasks" "link" in the "Admin bookmarks" "block"
|
||||
# Verify that we are on the right page.
|
||||
Then I should see "Scheduled tasks" in the "h1" "css_element"
|
||||
|
||||
Scenario: Admin page can be removed from bookmarks
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Notifications" node in "Site administration"
|
||||
And I click on "Scheduled tasks" "link" in the "Admin bookmarks" "block"
|
||||
When I click on "Unbookmark this page" "link" in the "Admin bookmarks" "block"
|
||||
Then I should see "Bookmark deleted"
|
||||
And I wait to be redirected
|
||||
And I should not see "Scheduled tasks" in the "Admin bookmarks" "block"
|
||||
@@ -0,0 +1,81 @@
|
||||
@block @block_blog_menu
|
||||
Feature: Enable Block blog menu in a course
|
||||
In order to enable the blog menu in a course
|
||||
As a teacher
|
||||
I can add blog menu block to a course
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
|
||||
Scenario: Add the block to a the course when blogs are disabled
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| enableblogs | 0 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
When I add the "Blog menu" block
|
||||
Then I should see "Blogging is disabled!" in the "Blog menu" "block"
|
||||
|
||||
Scenario: Add the block to a the course when blog associations are disabled
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| useblogassociations | 0 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
When I add the "Blog menu" block
|
||||
Then I should see "Blog entries" in the "Blog menu" "block"
|
||||
And I should see "Add a new entry" in the "Blog menu" "block"
|
||||
And I should not see "View all entries for this course" in the "Blog menu" "block"
|
||||
And I should not see "View my entries about this course" in the "Blog menu" "block"
|
||||
And I should not see "Add an entry about this course" in the "Blog menu" "block"
|
||||
|
||||
Scenario: Add the block to a the course when blog associations are enabled
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| useblogassociations | 1 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
When I add the "Blog menu" block
|
||||
Then I should see "Blog entries" in the "Blog menu" "block"
|
||||
And I should see "Add a new entry" in the "Blog menu" "block"
|
||||
And I should see "View all entries for this course" in the "Blog menu" "block"
|
||||
And I should see "View my entries about this course" in the "Blog menu" "block"
|
||||
And I should see "Add an entry about this course" in the "Blog menu" "block"
|
||||
|
||||
Scenario: Add the block to a the course when RSS is disabled
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| enablerssfeeds | 0 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
When I add the "Blog menu" block
|
||||
Then I should not see "Blog RSS feed" in the "Blog menu" "block"
|
||||
And I should see "Add a new entry" in the "Blog menu" "block"
|
||||
|
||||
Scenario: Add the block to a the course when RSS is enabled
|
||||
Given I log in as "admin"
|
||||
And the following config values are set as admin:
|
||||
| enablerssfeeds | 1 |
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
When I add the "Blog menu" block
|
||||
Then I should see "Blog RSS feed" in the "Blog menu" "block"
|
||||
And I should see "Add a new entry" in the "Blog menu" "block"
|
||||
@@ -0,0 +1,222 @@
|
||||
@block @block_blog_menu
|
||||
Feature: Enable Block blog menu in an activity
|
||||
In order to enable the blog menu in an activity
|
||||
As a teacher
|
||||
I can add blog menu block to a course
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
| student2 | Student | 2 | student2@example.com | S2 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add a "Assignment" to section "1" and I fill the form with:
|
||||
| Assignment name | Test assignment 1 |
|
||||
| Description | Offline text |
|
||||
| assignsubmission_file_enabled | 0 |
|
||||
And I follow "Test assignment 1"
|
||||
And I add the "Blog menu" block
|
||||
And I log out
|
||||
|
||||
Scenario: Students use the blog menu block to post blogs
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add a new entry"
|
||||
When I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog! |
|
||||
And I press "Save changes"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog!"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Blog entries"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog!"
|
||||
|
||||
Scenario: Students use the blog menu block to view their blogs about the activity
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this Assignment! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this Assignment!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
When I follow "View my entries about this Assignment"
|
||||
Then I should see "S2 First Blog"
|
||||
And I should not see "S2 Second Blog"
|
||||
And I should not see "S1 First Blog"
|
||||
|
||||
Scenario: Students use the blog menu block to view all blogs about the assignment
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this Assignment! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this Assignment!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
When I follow "View all entries about this Assignment"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "S2 First Blog"
|
||||
And I should not see "S2 Second Blog"
|
||||
|
||||
Scenario: Students use the blog menu block to view all their blog entries
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this Assignment! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this Assignment!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
When I follow "Blog entries"
|
||||
Then I should see "S2 First Blog"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should not see "S1 First Blog"
|
||||
|
||||
Scenario: Teacher searches for student blogs
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this Assignment! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this Assignment!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Assignment: Test assignment 1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I follow "Add an entry about this Assignment"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Assignment: Test assignment 1"
|
||||
And I log out
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Test assignment 1"
|
||||
And I set the field "blogsearchquery" to "First"
|
||||
And I press "Search"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "S2 First Blog"
|
||||
And I should not see "S2 Second Blog"
|
||||
@@ -0,0 +1,199 @@
|
||||
@block @block_blog_menu
|
||||
Feature: Enable Block blog menu in a course
|
||||
In order to enable the blog menu in a course
|
||||
As a teacher
|
||||
I can add blog menu block to a course
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| teacher1 | Teacher | 1 | teacher1@example.com | T1 |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
| student2 | Student | 2 | student2@example.com | S2 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course 1 | C1 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
| student2 | C1 | student |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Blog menu" block
|
||||
And I log out
|
||||
|
||||
Scenario: Students use the blog menu block to post blogs
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add a new entry"
|
||||
When I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog! |
|
||||
And I press "Save changes"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog!"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Blog entries"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog!"
|
||||
|
||||
Scenario: Students use the blog menu block to view their blogs about the course
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this course! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this course!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
When I follow "View my entries about this course"
|
||||
Then I should see "S2 First Blog"
|
||||
And I should not see "S2 Second Blog"
|
||||
And I should not see "S1 First Blog"
|
||||
|
||||
Scenario: Students use the blog menu block to view all blogs about the course
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this course! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this course!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
When I follow "View all entries for this course"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "S2 First Blog"
|
||||
And I should not see "S2 Second Blog"
|
||||
|
||||
Scenario: Students use the blog menu block to view all their blog entries
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this course! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this course!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
When I follow "Blog entries"
|
||||
Then I should see "S2 First Blog"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should not see "S1 First Blog"
|
||||
|
||||
Scenario: Teacher searches for student blogs
|
||||
Given I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog about this course! |
|
||||
And I press "Save changes"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog about this course!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I log out
|
||||
And I log in as "student2"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 Second Blog |
|
||||
| Blog entry body | My unrelated blog! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 Second Blog"
|
||||
And I should see "My unrelated blog!"
|
||||
And I should not see "Associated Course: C1"
|
||||
And I follow "Dashboard"
|
||||
And I follow "Course 1"
|
||||
And I follow "Add an entry about this course"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | S2 First Blog |
|
||||
| Blog entry body | My course blog is better! |
|
||||
And I press "Save changes"
|
||||
And I should see "S2 First Blog"
|
||||
And I should see "My course blog is better!"
|
||||
And I should see "Associated Course: C1"
|
||||
And I log out
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I set the field "blogsearchquery" to "First"
|
||||
And I press "Search"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "S2 First Blog"
|
||||
And I should not see "S2 Second Blog"
|
||||
@@ -0,0 +1,30 @@
|
||||
@block @block_blog_menu
|
||||
Feature: Enable Block blog menu on the frontpage
|
||||
In order to enable the blog menu on the frontpage
|
||||
As an admin
|
||||
I can add blog menu block to the frontpage
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email | idnumber |
|
||||
| student1 | Student | 1 | student1@example.com | S1 |
|
||||
And I log in as "admin"
|
||||
And I am on site homepage
|
||||
And I navigate to "Turn editing on" node in "Front page settings"
|
||||
And I add the "Blog menu" block
|
||||
And I log out
|
||||
|
||||
Scenario: Students use the blog menu block to post blogs
|
||||
Given I log in as "student1"
|
||||
And I am on site homepage
|
||||
And I follow "Add a new entry"
|
||||
When I set the following fields to these values:
|
||||
| Entry title | S1 First Blog |
|
||||
| Blog entry body | This is my awesome blog! |
|
||||
And I press "Save changes"
|
||||
Then I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog!"
|
||||
And I am on site homepage
|
||||
And I follow "Blog entries"
|
||||
And I should see "S1 First Blog"
|
||||
And I should see "This is my awesome blog!"
|
||||
@@ -325,7 +325,7 @@ class block_course_overview_renderer extends plugin_renderer_base {
|
||||
* @return string html string for welcome area.
|
||||
*/
|
||||
public function welcome_area($msgcount) {
|
||||
global $USER;
|
||||
global $CFG, $USER;
|
||||
$output = $this->output->box_start('welcome_area');
|
||||
|
||||
$picture = $this->output->user_picture($USER, array('size' => 75, 'class' => 'welcome_userpicture'));
|
||||
@@ -334,16 +334,19 @@ class block_course_overview_renderer extends plugin_renderer_base {
|
||||
$output .= $this->output->box_start('welcome_message');
|
||||
$output .= $this->output->heading(get_string('welcome', 'block_course_overview', $USER->firstname));
|
||||
|
||||
$plural = 's';
|
||||
if ($msgcount > 0) {
|
||||
$output .= get_string('youhavemessages', 'block_course_overview', $msgcount);
|
||||
if ($msgcount == 1) {
|
||||
$plural = '';
|
||||
if (!empty($CFG->messaging)) {
|
||||
$plural = 's';
|
||||
if ($msgcount > 0) {
|
||||
$output .= get_string('youhavemessages', 'block_course_overview', $msgcount);
|
||||
if ($msgcount == 1) {
|
||||
$plural = '';
|
||||
}
|
||||
} else {
|
||||
$output .= get_string('youhavenomessages', 'block_course_overview');
|
||||
}
|
||||
} else {
|
||||
$output .= get_string('youhavenomessages', 'block_course_overview');
|
||||
$output .= html_writer::link(new moodle_url('/message/index.php'),
|
||||
get_string('message'.$plural, 'block_course_overview'));
|
||||
}
|
||||
$output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview'));
|
||||
$output .= $this->output->box_end();
|
||||
$output .= $this->output->box('', 'flush');
|
||||
$output .= $this->output->box_end();
|
||||
|
||||
@@ -62,9 +62,16 @@ class restore_glossary_random_block_task extends restore_block_task {
|
||||
if (!empty($config->glossary)) {
|
||||
// Get glossary mapping and replace it in config
|
||||
if ($glossarymap = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'glossary', $config->glossary)) {
|
||||
$config->glossary = $glossarymap->newitemid;
|
||||
$mappedglossary = $DB->get_record('glossary', array('id' => $glossarymap->newitemid),
|
||||
'id,course,globalglossary', MUST_EXIST);
|
||||
$config->glossary = $mappedglossary->id;
|
||||
$config->courseid = $mappedglossary->course;
|
||||
$config->globalglossary = $mappedglossary->globalglossary;
|
||||
$configdata = base64_encode(serialize($config));
|
||||
$DB->set_field('block_instances', 'configdata', $configdata, array('id' => $blockid));
|
||||
} else {
|
||||
// The block refers to a glossary not present in the backup file.
|
||||
$DB->set_field('block_instances', 'configdata', '', array('id' => $blockid));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,14 +84,13 @@ class block_glossary_random extends block_base {
|
||||
$limitfrom = 0;
|
||||
$limitnum = 1;
|
||||
|
||||
$BROWSE = 'timemodified';
|
||||
$orderby = 'timemodified ASC';
|
||||
|
||||
switch ($this->config->type) {
|
||||
|
||||
case BGR_RANDOMLY:
|
||||
$i = rand(1,$numberofentries);
|
||||
$limitfrom = $i-1;
|
||||
$SORT = 'ASC';
|
||||
break;
|
||||
|
||||
case BGR_NEXTONE:
|
||||
@@ -104,11 +103,10 @@ class block_glossary_random extends block_base {
|
||||
$i = 1;
|
||||
}
|
||||
$limitfrom = $i-1;
|
||||
$SORT = 'ASC';
|
||||
break;
|
||||
|
||||
case BGR_NEXTALPHA:
|
||||
$BROWSE = 'concept';
|
||||
$orderby = 'concept ASC';
|
||||
if (isset($this->config->previous)) {
|
||||
$i = $this->config->previous + 1;
|
||||
} else {
|
||||
@@ -118,20 +116,19 @@ class block_glossary_random extends block_base {
|
||||
$i = 1;
|
||||
}
|
||||
$limitfrom = $i-1;
|
||||
$SORT = 'ASC';
|
||||
break;
|
||||
|
||||
default: // BGR_LASTMODIFIED
|
||||
$i = $numberofentries;
|
||||
$limitfrom = 0;
|
||||
$SORT = 'DESC';
|
||||
$orderby = 'timemodified DESC, id DESC';
|
||||
break;
|
||||
}
|
||||
|
||||
if ($entry = $DB->get_records_sql("SELECT id, concept, definition, definitionformat, definitiontrust
|
||||
FROM {glossary_entries}
|
||||
WHERE glossaryid = ? AND approved = 1
|
||||
ORDER BY $BROWSE $SORT", array($this->config->glossary), $limitfrom, $limitnum)) {
|
||||
ORDER BY $orderby", array($this->config->glossary), $limitfrom, $limitnum)) {
|
||||
|
||||
$entry = reset($entry);
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
.block_navigation .block_tree .tree_item.hasicon .item-content-wrap {
|
||||
display: inline-block;
|
||||
white-space: normal;
|
||||
width: calc(100% - 21px);
|
||||
}
|
||||
|
||||
.block_navigation .block_tree ul {
|
||||
|
||||
+3
-3
@@ -524,9 +524,9 @@ BRANCH.prototype = {
|
||||
branchicon.setAttribute('title', icon.title);
|
||||
}
|
||||
if (icon.classes) {
|
||||
for (var i in icon.classes) {
|
||||
branchicon.addClass(icon.classes[i]);
|
||||
}
|
||||
icon.classes.forEach(function(element) {
|
||||
branchicon.addClass(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-2
File diff suppressed because one or more lines are too long
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js
Vendored
+3
-3
@@ -523,9 +523,9 @@ BRANCH.prototype = {
|
||||
branchicon.setAttribute('title', icon.title);
|
||||
}
|
||||
if (icon.classes) {
|
||||
for (var i in icon.classes) {
|
||||
branchicon.addClass(icon.classes[i]);
|
||||
}
|
||||
icon.classes.forEach(function(element) {
|
||||
branchicon.addClass(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -522,9 +522,9 @@ BRANCH.prototype = {
|
||||
branchicon.setAttribute('title', icon.title);
|
||||
}
|
||||
if (icon.classes) {
|
||||
for (var i in icon.classes) {
|
||||
branchicon.addClass(icon.classes[i]);
|
||||
}
|
||||
icon.classes.forEach(function(element) {
|
||||
branchicon.addClass(element);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,29 +35,4 @@ defined('MOODLE_INTERNAL') || die();
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class block_online_users_generator extends testing_block_generator {
|
||||
|
||||
/**
|
||||
* Create new block instance
|
||||
* @param array|stdClass $record
|
||||
* @param array $options
|
||||
* @return stdClass activity record with extra cmid field
|
||||
*/
|
||||
public function create_instance($record = null, array $options = null) {
|
||||
global $DB, $CFG;
|
||||
require_once("$CFG->dirroot/mod/page/locallib.php");
|
||||
|
||||
$this->instancecount++;
|
||||
|
||||
$record = (object)(array)$record;
|
||||
$options = (array)$options;
|
||||
|
||||
$record = $this->prepare_record($record);
|
||||
|
||||
$id = $DB->insert_record('block_instances', $record);
|
||||
context_block::instance($id);
|
||||
|
||||
$instance = $DB->get_record('block_instances', array('id'=>$id), '*', MUST_EXIST);
|
||||
|
||||
return $instance;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
*/
|
||||
class block_tags_edit_form extends block_edit_form {
|
||||
protected function specific_definition($mform) {
|
||||
global $CFG;
|
||||
// Fields for editing HTML block title and contents.
|
||||
$mform->addElement('header', 'configheader', get_string('blocksettings', 'block'));
|
||||
|
||||
@@ -44,8 +45,10 @@ class block_tags_edit_form extends block_edit_form {
|
||||
$mform->addElement('select', 'config_numberoftags', get_string('numberoftags', 'blog'), $numberoftags);
|
||||
$mform->setDefault('config_numberoftags', 80);
|
||||
|
||||
$defaults = array('default'=>'default', 'official'=>'official', ''=>'both');
|
||||
$mform->addElement('select', 'config_tagtype', get_string('defaultdisplay', 'block_tags'), $defaults);
|
||||
$mform->setDefault('config_tagtype', '');
|
||||
if (!empty($CFG->block_tags_showcoursetags)) {
|
||||
$defaults = array('default'=>'default', 'official'=>'official', ''=>'both');
|
||||
$mform->addElement('select', 'config_tagtype', get_string('defaultdisplay', 'block_tags'), $defaults);
|
||||
$mform->setDefault('config_tagtype', '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-7
@@ -63,9 +63,13 @@ if ($id) {
|
||||
|
||||
$sitecontext = context_system::instance();
|
||||
$usercontext = context_user::instance($userid);
|
||||
$PAGE->set_context($usercontext);
|
||||
$blognode = $PAGE->settingsnav->find('blogadd', null);
|
||||
$blognode->make_active();
|
||||
if ($modid) {
|
||||
$PAGE->set_context($sitecontext);
|
||||
} else {
|
||||
$PAGE->set_context($usercontext);
|
||||
$blognode = $PAGE->settingsnav->find('blogadd', null);
|
||||
$blognode->make_active();
|
||||
}
|
||||
|
||||
require_login($courseid);
|
||||
|
||||
@@ -138,14 +142,15 @@ if ($action === 'delete') {
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
|
||||
echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'),
|
||||
new moodle_url('edit.php', $optionsyes),
|
||||
new moodle_url('index.php', $optionsno));
|
||||
|
||||
echo '<br />';
|
||||
// Output the entry.
|
||||
$entry->prepare_render();
|
||||
echo $output->render($entry);
|
||||
|
||||
echo '<br />';
|
||||
echo $OUTPUT->confirm(get_string('blogdeleteconfirm', 'blog'),
|
||||
new moodle_url('edit.php', $optionsyes),
|
||||
new moodle_url('index.php', $optionsno));
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
}
|
||||
|
||||
@@ -94,14 +94,16 @@ if (!empty($blogs)) {
|
||||
$editurl = new moodle_url('/blog/external_blog_edit.php', array('id' => $blog->id));
|
||||
$editicon = $OUTPUT->action_icon($editurl, new pix_icon('t/edit', get_string('editexternalblog', 'blog')));
|
||||
|
||||
$deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey'=>sesskey()));
|
||||
$deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')));
|
||||
$deletelink = new moodle_url('/blog/external_blogs.php', array('delete' => $blog->id, 'sesskey' => sesskey()));
|
||||
$action = new confirm_action(get_string('externalblogdeleteconfirm', 'blog'));
|
||||
$deleteicon = $OUTPUT->action_icon($deletelink, new pix_icon('t/delete', get_string('deleteexternalblog', 'blog')),
|
||||
$action);
|
||||
|
||||
$table->data[] = new html_table_row(array($blog->name,
|
||||
$blog->url,
|
||||
userdate($blog->timefetched),
|
||||
$validicon,
|
||||
$editicon . ' '. $deleteicon));
|
||||
$editicon . $deleteicon));
|
||||
}
|
||||
echo html_writer::table($table);
|
||||
}
|
||||
|
||||
+2
-2
@@ -63,9 +63,9 @@ if ($entryid and !isset($userid)) {
|
||||
$userid = $entry->userid;
|
||||
}
|
||||
|
||||
if (isset($userid) && !isset($courseid)) {
|
||||
if (isset($userid) && empty($courseid) && empty($modid)) {
|
||||
$context = context_user::instance($userid);
|
||||
} else if (isset($courseid) && $courseid != SITEID) {
|
||||
} else if (!empty($courseid) && $courseid != SITEID) {
|
||||
$context = context_course::instance($courseid);
|
||||
} else {
|
||||
$context = context_system::instance();
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
@core @core_blog
|
||||
Feature: Delete a blog entry
|
||||
In order to manage my blog entries
|
||||
As a user
|
||||
I need to be able to delete entries I no longer wish to appear
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| testuser | Test | User | moodle@example.com |
|
||||
And I log in as "testuser"
|
||||
And I expand "Site pages" node
|
||||
And I follow "Site blogs"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | Blog post one |
|
||||
| Blog entry body | User 1 blog post content |
|
||||
And I press "Save changes"
|
||||
And I follow "Add a new entry"
|
||||
And I set the following fields to these values:
|
||||
| Entry title | Blog post two |
|
||||
| Blog entry body | User 1 blog post content |
|
||||
And I press "Save changes"
|
||||
And I am on site homepage
|
||||
And I expand "Site pages" node
|
||||
And I follow "Site blogs"
|
||||
|
||||
Scenario: Delete blog post results in post deleted
|
||||
Given I follow "Blog post one"
|
||||
And I follow "Delete"
|
||||
And I should see "Delete this blog entry?"
|
||||
When I press "Continue"
|
||||
Then I should not see "Blog post one"
|
||||
And I should see "Blog post two"
|
||||
|
||||
Scenario: Delete confirmation screen works and allows cancel
|
||||
Given I follow "Blog post one"
|
||||
When I follow "Delete"
|
||||
Then I should see "Delete this blog entry?"
|
||||
And I press "Cancel"
|
||||
And I should see "Blog post one"
|
||||
And I should see "Blog post two"
|
||||
|
||||
@@ -30,7 +30,7 @@ require_once($CFG->dirroot . '/blog/lib.php');
|
||||
/**
|
||||
* Test functions that rely on the DB tables
|
||||
*/
|
||||
class core_bloglib_testcase extends advanced_testcase {
|
||||
class core_blog_lib_testcase extends advanced_testcase {
|
||||
|
||||
private $courseid;
|
||||
private $cmid;
|
||||
@@ -472,5 +472,73 @@ class core_bloglib_testcase extends advanced_testcase {
|
||||
$this->assertEquals($url, $event->get_url());
|
||||
$this->assertEventContextNotUsed($event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the core_blog_myprofile_navigation() function.
|
||||
*/
|
||||
public function test_core_blog_myprofile_navigation() {
|
||||
global $USER;
|
||||
|
||||
// Set up the test.
|
||||
$tree = new \core_user\output\myprofile\tree();
|
||||
$this->setAdminUser();
|
||||
$iscurrentuser = true;
|
||||
$course = null;
|
||||
|
||||
// Enable blogs.
|
||||
set_config('enableblogs', true);
|
||||
|
||||
// Check the node tree is correct.
|
||||
core_blog_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
|
||||
$reflector = new ReflectionObject($tree);
|
||||
$nodes = $reflector->getProperty('nodes');
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayHasKey('blogs', $nodes->getValue($tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the core_blog_myprofile_navigation() function as a guest.
|
||||
*/
|
||||
public function test_core_blog_myprofile_navigation_as_guest() {
|
||||
global $USER;
|
||||
|
||||
// Set up the test.
|
||||
$tree = new \core_user\output\myprofile\tree();
|
||||
$iscurrentuser = false;
|
||||
$course = null;
|
||||
|
||||
// Set user as guest.
|
||||
$this->setGuestUser();
|
||||
|
||||
// Check the node tree is correct.
|
||||
core_blog_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
|
||||
$reflector = new ReflectionObject($tree);
|
||||
$nodes = $reflector->getProperty('nodes');
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayNotHasKey('blogs', $nodes->getValue($tree));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the core_blog_myprofile_navigation() function when blogs are disabled.
|
||||
*/
|
||||
public function test_core_blog_myprofile_navigation_blogs_disabled() {
|
||||
global $USER;
|
||||
|
||||
// Set up the test.
|
||||
$tree = new \core_user\output\myprofile\tree();
|
||||
$this->setAdminUser();
|
||||
$iscurrentuser = false;
|
||||
$course = null;
|
||||
|
||||
// Disable blogs.
|
||||
set_config('enableblogs', false);
|
||||
|
||||
// Check the node tree is correct.
|
||||
core_blog_myprofile_navigation($tree, $USER, $iscurrentuser, $course);
|
||||
$reflector = new ReflectionObject($tree);
|
||||
$nodes = $reflector->getProperty('nodes');
|
||||
$nodes->setAccessible(true);
|
||||
$this->assertArrayNotHasKey('blogs', $nodes->getValue($tree));
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+5
-1
@@ -330,7 +330,11 @@ class cache_config {
|
||||
if (!file_exists($cachefile)) {
|
||||
throw new cache_exception('Default cache config could not be found. It should have already been created by now.');
|
||||
}
|
||||
include($cachefile);
|
||||
|
||||
if (!include($cachefile)) {
|
||||
throw new cache_exception('Unable to load the cache configuration file');
|
||||
}
|
||||
|
||||
if (!is_array($configuration)) {
|
||||
throw new cache_exception('Invalid cache configuration file');
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -190,9 +190,9 @@ class cachestore_dummy extends cache_store {
|
||||
foreach ($keyvaluearray as $pair) {
|
||||
$this->store[$pair['key']] = $pair['value'];
|
||||
}
|
||||
return count($keyvaluearray);
|
||||
|
||||
}
|
||||
return 0;
|
||||
return count($keyvaluearray);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+19
-2
@@ -450,6 +450,13 @@ class cache implements cache_loader {
|
||||
// Create an array with the original keys and the found values. This will be what we return.
|
||||
$fullresult = array();
|
||||
foreach ($result as $key => $value) {
|
||||
if (!is_scalar($value)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
$fullresult[$parsedkeys[$key]] = $value;
|
||||
}
|
||||
unset($result);
|
||||
@@ -1270,7 +1277,9 @@ class cache_application extends cache implements cache_loader_with_locking {
|
||||
$this->delete_many($todelete);
|
||||
}
|
||||
// Set the time of the last invalidation.
|
||||
$this->set('lastinvalidation', cache::now());
|
||||
if ($purgeall || !empty($todelete)) {
|
||||
$this->set('lastinvalidation', cache::now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1669,7 +1678,9 @@ class cache_session extends cache {
|
||||
$this->delete_many($todelete);
|
||||
}
|
||||
// Set the time of the last invalidation.
|
||||
$this->set('lastsessioninvalidation', cache::now());
|
||||
if ($purgeall || !empty($todelete)) {
|
||||
$this->set('lastsessioninvalidation', cache::now());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1918,6 +1929,12 @@ class cache_session extends cache {
|
||||
if ($value instanceof cache_cached_object) {
|
||||
/* @var cache_cached_object $value */
|
||||
$value = $value->restore_object();
|
||||
} else if (!is_scalar($value)) {
|
||||
// If data is an object it will be a reference.
|
||||
// If data is an array if may contain references.
|
||||
// We want to break references so that the cache cannot be modified outside of itself.
|
||||
// Call the function to unreference it (in the best way possible).
|
||||
$value = $this->unref($value);
|
||||
}
|
||||
$return[$key] = $value;
|
||||
if ($value === false) {
|
||||
|
||||
Vendored
+69
-1
@@ -407,7 +407,7 @@ class core_cache_testcase extends advanced_testcase {
|
||||
$this->assertEquals('pork', $var->subobj->subobj->key);
|
||||
$this->assertTrue($cache->delete('obj'));
|
||||
|
||||
// Death reference test... basicaly we don't want this to die.
|
||||
// Death reference test... basically we don't want this to die.
|
||||
$obj = new stdClass;
|
||||
$obj->key = 'value';
|
||||
$obj->self =& $obj;
|
||||
@@ -433,6 +433,32 @@ class core_cache_testcase extends advanced_testcase {
|
||||
|
||||
$this->assertTrue($cache->delete('obj'));
|
||||
|
||||
// Death reference test on get_many... basically we don't want this to die.
|
||||
$obj = new stdClass;
|
||||
$obj->key = 'value';
|
||||
$obj->self =& $obj;
|
||||
$this->assertEquals(1, $cache->set_many(array('obj' => $obj)));
|
||||
$var = $cache->get_many(array('obj'));
|
||||
$this->assertInstanceOf('stdClass', $var['obj']);
|
||||
$this->assertEquals('value', $var['obj']->key);
|
||||
|
||||
// Reference test after retrieve.
|
||||
$obj = new stdClass;
|
||||
$obj->key = 'value';
|
||||
$this->assertEquals(1, $cache->set_many(array('obj' => $obj)));
|
||||
|
||||
$var1 = $cache->get_many(array('obj'));
|
||||
$this->assertInstanceOf('stdClass', $var1['obj']);
|
||||
$this->assertEquals('value', $var1['obj']->key);
|
||||
$var1['obj']->key = 'eulav';
|
||||
$this->assertEquals('eulav', $var1['obj']->key);
|
||||
|
||||
$var2 = $cache->get_many(array('obj'));
|
||||
$this->assertInstanceOf('stdClass', $var2['obj']);
|
||||
$this->assertEquals('value', $var2['obj']->key);
|
||||
|
||||
$this->assertTrue($cache->delete('obj'));
|
||||
|
||||
// Test strictness exceptions.
|
||||
try {
|
||||
$cache->get('exception', MUST_EXIST);
|
||||
@@ -989,6 +1015,48 @@ class core_cache_testcase extends advanced_testcase {
|
||||
));
|
||||
$cache = cache::make('phpunit', 'eventinvalidationtest');
|
||||
$this->assertFalse($cache->get('testkey1'));
|
||||
|
||||
// Test 3: Verify that an existing lastinvalidation cache file is updated when needed.
|
||||
|
||||
// Make a new cache class. This should should invalidate testkey2.
|
||||
$cache = cache::make('phpunit', 'eventinvalidationtest');
|
||||
// Timestamp should have updated to cache::now().
|
||||
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
|
||||
|
||||
// Set testkey2 data.
|
||||
$cache->set('testkey2', 'test data 2');
|
||||
// Backdate the event invalidation time by 30 seconds.
|
||||
$invalidationcache = cache::make('core', 'eventinvalidation');
|
||||
$invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 30));
|
||||
// Lastinvalidation should already be cache::now().
|
||||
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
|
||||
// Set it to 15 seconds ago so that we know if it changes.
|
||||
$cache->set('lastinvalidation', cache::now() - 15);
|
||||
// Make a new cache class. This should not invalidate anything.
|
||||
cache_factory::instance()->reset_cache_instances();
|
||||
$cache = cache::make('phpunit', 'eventinvalidationtest');
|
||||
// Lastinvalidation shouldn't change since it was already newer than invalidation event.
|
||||
$this->assertEquals(cache::now() - 15, $cache->get('lastinvalidation'));
|
||||
|
||||
// Now set the event invalidation to newer than the lastinvalidation time.
|
||||
$invalidationcache->set('crazyevent', array('testkey2' => cache::now() - 5));
|
||||
// Make a new cache class. This should should invalidate testkey2.
|
||||
cache_factory::instance()->reset_cache_instances();
|
||||
$cache = cache::make('phpunit', 'eventinvalidationtest');
|
||||
// Lastinvalidation timestamp should have updated to cache::now().
|
||||
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
|
||||
|
||||
// Now simulate a purge_by_event 5 seconds ago.
|
||||
$invalidationcache = cache::make('core', 'eventinvalidation');
|
||||
$invalidationcache->set('crazyevent', array('purged' => cache::now() - 5));
|
||||
// Set our lastinvalidation timestamp to 15 seconds ago.
|
||||
$cache->set('lastinvalidation', cache::now() - 15);
|
||||
// Make a new cache class. This should invalidate the cache.
|
||||
cache_factory::instance()->reset_cache_instances();
|
||||
$cache = cache::make('phpunit', 'eventinvalidationtest');
|
||||
// Lastinvalidation timestamp should have updated to cache::now().
|
||||
$this->assertEquals(cache::now(), $cache->get('lastinvalidation'));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -173,6 +173,8 @@ class core_calendar_external extends external_api {
|
||||
|
||||
// Let us findout courses that we can return events from.
|
||||
if (!$hassystemcap) {
|
||||
$courses = enrol_get_my_courses('id');
|
||||
$courses = array_keys($courses);
|
||||
foreach ($params['events']['courseids'] as $id) {
|
||||
try {
|
||||
$context = context_course::instance($id);
|
||||
@@ -185,7 +187,6 @@ class core_calendar_external extends external_api {
|
||||
'warningcode' => 'nopermissions',
|
||||
'message' => 'No access rights in course context '.$e->getMessage().$e->getTraceAsString()
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -226,21 +227,21 @@ class core_calendar_external extends external_api {
|
||||
$params['options']['timeend'] = PHP_INT_MAX;
|
||||
}
|
||||
|
||||
// Event list does not check visibility and permissions, we'll check that later.
|
||||
$eventlist = calendar_get_events($params['options']['timestart'], $params['options']['timeend'], $funcparam['users'], $funcparam['groups'],
|
||||
$funcparam['courses'], true, $params['options']['ignorehidden']);
|
||||
|
||||
// WS expects arrays.
|
||||
$events = array();
|
||||
foreach ($eventlist as $id => $event) {
|
||||
$events[$id] = (array) $event;
|
||||
}
|
||||
|
||||
// We need to get events asked for eventids.
|
||||
$eventsbyid = calendar_get_events_by_id($params['events']['eventids']);
|
||||
foreach ($eventsbyid as $eventid => $eventobj) {
|
||||
if ($eventsbyid = calendar_get_events_by_id($params['events']['eventids'])) {
|
||||
$eventlist += $eventsbyid;
|
||||
}
|
||||
|
||||
foreach ($eventlist as $eventid => $eventobj) {
|
||||
$event = (array) $eventobj;
|
||||
if (isset($events[$eventid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($hassystemcap) {
|
||||
// User can see everything, no further check is needed.
|
||||
$events[$eventid] = $event;
|
||||
|
||||
+2
-2
@@ -693,8 +693,8 @@ function calendar_get_events($tstart, $tend, $users, $groups, $courses, $withdur
|
||||
|
||||
$whereclause = '';
|
||||
$params = array();
|
||||
// Quick test
|
||||
if(is_bool($users) && is_bool($groups) && is_bool($courses)) {
|
||||
// Quick test.
|
||||
if (empty($users) && empty($groups) && empty($courses)) {
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,7 @@ class behat_calendar extends behat_base {
|
||||
$dayofmonth = "a[{$daycontains}]";
|
||||
return array(
|
||||
new Given('I hover "//' . $currentmonth . '/descendant::' . $daycell . '/' . $dayofmonth . '" "xpath_element"'),
|
||||
new Given('I wait until the page is ready'),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -363,6 +363,37 @@ class core_calendar_externallib_testcase extends externallib_advanced_testcase {
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
$this->assertEquals(1, count($events['events'])); // site.
|
||||
$this->assertEquals(0, count($events['warnings']));
|
||||
|
||||
// Try getting a course event by its id.
|
||||
$paramevents = array ('eventids' => array($courseevent->id));
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
$this->assertEquals(1, count($events['events']));
|
||||
$this->assertEquals(0, count($events['warnings']));
|
||||
|
||||
// Now, create an activity event.
|
||||
$this->setAdminUser();
|
||||
$nexttime = time() + DAYSECS;
|
||||
$assign = $this->getDataGenerator()->create_module('assign', array('course' => $course->id, 'duedate' => $nexttime));
|
||||
|
||||
$this->setUser($user);
|
||||
$paramevents = array ('courseids' => array($course->id));
|
||||
$options = array ('siteevents' => true, 'userevents' => true, 'timeend' => time() + WEEKSECS);
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
|
||||
$this->assertCount(5, $events['events']);
|
||||
|
||||
// Hide the assignment.
|
||||
set_coursemodule_visible($assign->cmid, 0);
|
||||
// Empty all the caches that may be affected by this change.
|
||||
accesslib_clear_all_caches_for_unit_testing();
|
||||
course_modinfo::clear_instance_cache();
|
||||
|
||||
$events = core_calendar_external::get_calendar_events($paramevents, $options);
|
||||
$events = external_api::clean_returnvalue(core_calendar_external::get_calendar_events_returns(), $events);
|
||||
// Expect one less.
|
||||
$this->assertCount(4, $events['events']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -78,13 +78,8 @@ class core_calendar_lib_testcase extends advanced_testcase {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/lib/cronlib.php');
|
||||
|
||||
// Moodle ICal URL (moodle.org events).
|
||||
$presetwhat = 'all';
|
||||
$presettime = 'recentupcoming';
|
||||
$userid = 1;
|
||||
$authtoken = 'a8bcfee2fb868a05357f650bd65dc0699b026524';
|
||||
$subscriptionurl = 'https://moodle.org/calendar/export_execute.php'
|
||||
. '?preset_what='.$presetwhat.'&preset_time='.$presettime.'&userid='.$userid.'&authtoken='.$authtoken;
|
||||
// ICal URL from external test repo.
|
||||
$subscriptionurl = $this->getExternalTestFileUrl('/ical.ics');
|
||||
|
||||
$subscription = new stdClass();
|
||||
$subscription->eventtype = 'site';
|
||||
|
||||
+12
-11
@@ -53,27 +53,28 @@ $time = optional_param('time', 0, PARAM_INT);
|
||||
|
||||
$url = new moodle_url('/calendar/view.php');
|
||||
|
||||
if ($courseid != SITEID) {
|
||||
$url->param('course', $courseid);
|
||||
}
|
||||
|
||||
if ($view !== 'upcoming') {
|
||||
$url->param('view', $view);
|
||||
}
|
||||
|
||||
// If a day, month and year were passed then convert it to a timestamp. If these were passed
|
||||
// then we can assume the day, month and year are passed as Gregorian, as no where in core
|
||||
// should we be passing these values rather than the time. This is done for BC.
|
||||
if (!empty($day) && !empty($mon) && !empty($year)) {
|
||||
if (checkdate($mon, $day, $year)) {
|
||||
$time = make_timestamp($year, $mon, $day);
|
||||
} else {
|
||||
$time = time();
|
||||
}
|
||||
} else if (empty($time)) {
|
||||
}
|
||||
|
||||
if (empty($time)) {
|
||||
$time = time();
|
||||
}
|
||||
|
||||
if ($courseid != SITEID) {
|
||||
$url->param('course', $courseid);
|
||||
}
|
||||
|
||||
if ($view !== 'upcoming') {
|
||||
$time = usergetmidnight($time);
|
||||
$url->param('view', $view);
|
||||
}
|
||||
|
||||
$url->param('time', $time);
|
||||
|
||||
$PAGE->set_url($url);
|
||||
|
||||
+12
-9
@@ -208,7 +208,7 @@ class core_cohort_external extends external_api {
|
||||
return new external_function_parameters(
|
||||
array(
|
||||
'cohortids' => new external_multiple_structure(new external_value(PARAM_INT, 'Cohort ID')
|
||||
, 'List of cohort id. A cohort id is an integer.'),
|
||||
, 'List of cohort id. A cohort id is an integer.', VALUE_DEFAULT, array()),
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -220,16 +220,19 @@ class core_cohort_external extends external_api {
|
||||
* @return array of cohort objects (id, courseid, name)
|
||||
* @since Moodle 2.5
|
||||
*/
|
||||
public static function get_cohorts($cohortids) {
|
||||
public static function get_cohorts($cohortids = array()) {
|
||||
global $DB;
|
||||
|
||||
$params = self::validate_parameters(self::get_cohorts_parameters(), array('cohortids' => $cohortids));
|
||||
|
||||
$cohorts = array();
|
||||
foreach ($params['cohortids'] as $cohortid) {
|
||||
// Validate params.
|
||||
$cohort = $DB->get_record('cohort', array('id' => $cohortid), '*', MUST_EXIST);
|
||||
if (empty($cohortids)) {
|
||||
$cohorts = $DB->get_records('cohort');
|
||||
} else {
|
||||
$cohorts = $DB->get_records_list('cohort', 'id', $params['cohortids']);
|
||||
}
|
||||
|
||||
$cohortsinfo = array();
|
||||
foreach ($cohorts as $cohort) {
|
||||
// Now security checks.
|
||||
$context = context::instance_by_id($cohort->contextid, MUST_EXIST);
|
||||
if ($context->contextlevel != CONTEXT_COURSECAT and $context->contextlevel != CONTEXT_SYSTEM) {
|
||||
@@ -244,12 +247,12 @@ class core_cohort_external extends external_api {
|
||||
external_format_text($cohort->description, $cohort->descriptionformat,
|
||||
$context->id, 'cohort', 'description', $cohort->id);
|
||||
|
||||
$cohorts[] = (array) $cohort;
|
||||
$cohortsinfo[] = (array) $cohort;
|
||||
}
|
||||
|
||||
return $cohorts;
|
||||
return $cohortsinfo;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns description of method result value
|
||||
*
|
||||
|
||||
@@ -44,12 +44,11 @@ Feature: Access visible and hidden cohorts
|
||||
| user | course | role |
|
||||
| teacher | C1 | editingteacher |
|
||||
|
||||
@javascript
|
||||
Scenario: Teacher can see visible cohorts defined in the above contexts
|
||||
When I log in as "teacher"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Enrolment methods" node in "Course administration > Users"
|
||||
And I set the field "Add method" to "Cohort sync"
|
||||
And I select "Cohort sync" from the "Add method" singleselect
|
||||
Then the "Cohort" select box should contain "Cohort in category 1"
|
||||
And the "Cohort" select box should contain "System cohort"
|
||||
And the "Cohort" select box should not contain "Cohort hidden in category 1"
|
||||
@@ -71,13 +70,12 @@ Feature: Access visible and hidden cohorts
|
||||
And the "Select members from cohort" select box should not contain "Cohort empty in category 1"
|
||||
And the "Select members from cohort" select box should not contain "System empty cohort"
|
||||
|
||||
@javascript
|
||||
Scenario: System manager can see all cohorts defined in the above contexts
|
||||
When I log in as "user1"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Enrolment methods" node in "Course administration > Users"
|
||||
And I set the field "Add method" to "Cohort sync"
|
||||
And I select "Cohort sync" from the "Add method" singleselect
|
||||
Then the "Cohort" select box should contain "Cohort in category 1"
|
||||
And the "Cohort" select box should contain "System cohort"
|
||||
And the "Cohort" select box should contain "Cohort hidden in category 1"
|
||||
@@ -99,13 +97,12 @@ Feature: Access visible and hidden cohorts
|
||||
And the "Select members from cohort" select box should not contain "Cohort empty in category 1"
|
||||
And the "Select members from cohort" select box should not contain "System empty cohort"
|
||||
|
||||
@javascript
|
||||
Scenario: Category manager can see all cohorts defined in his category and visible cohorts defined above
|
||||
When I log in as "user2"
|
||||
And I am on site homepage
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Enrolment methods" node in "Course administration > Users"
|
||||
And I set the field "Add method" to "Cohort sync"
|
||||
And I select "Cohort sync" from the "Add method" singleselect
|
||||
Then the "Cohort" select box should contain "Cohort in category 1"
|
||||
And the "Cohort" select box should contain "System cohort"
|
||||
And the "Cohort" select box should contain "Cohort hidden in category 1"
|
||||
|
||||
@@ -21,7 +21,6 @@ Feature: Add cohorts of users
|
||||
| Description | Test cohort description |
|
||||
And I press "Save changes"
|
||||
|
||||
@javascript
|
||||
Scenario: Add a cohort
|
||||
When I follow "Cohorts"
|
||||
Then I should see "Test cohort name"
|
||||
@@ -29,7 +28,6 @@ Feature: Add cohorts of users
|
||||
And I should see "Test cohort description"
|
||||
And I should see "Created manually"
|
||||
|
||||
@javascript
|
||||
Scenario: Add users to a cohort selecting them from the system users list
|
||||
When I add "First User (first@example.com)" user to "333" cohort members
|
||||
And I add "Second User (second@example.com)" user to "333" cohort members
|
||||
@@ -39,7 +37,6 @@ Feature: Add cohorts of users
|
||||
And the "Current users" select box should contain "Second User (second@example.com)"
|
||||
And the "Current users" select box should not contain "Forth User (forth@example.com)"
|
||||
|
||||
@javascript
|
||||
Scenario: Add users to a cohort using a bulk user action
|
||||
When I follow "Bulk user actions"
|
||||
And I set the field "Available" to "Third User"
|
||||
|
||||
@@ -59,29 +59,16 @@ class behat_cohort extends behat_base {
|
||||
if (!$this->getSession()->getPage()->find('css', 'input#cohort_search_q')) {
|
||||
|
||||
// With JS enabled we should expand a few tree nodes.
|
||||
if ($this->running_javascript()) {
|
||||
$parentnodes = get_string('administrationsite') . ' > ' .
|
||||
get_string('users', 'admin') . ' > ' .
|
||||
get_string('accounts', 'admin');
|
||||
$steps = array_merge(
|
||||
array(
|
||||
new Given('I am on homepage'),
|
||||
new Given('I navigate to "' . get_string('cohorts', 'cohort') . '" node in "' . $parentnodes . '"')
|
||||
),
|
||||
$steps
|
||||
);
|
||||
|
||||
} else {
|
||||
// JS disabled.
|
||||
$steps = array_merge(
|
||||
array(
|
||||
new Given('I am on homepage'),
|
||||
new Given('I follow "' . get_string('administrationsite') . '" node'),
|
||||
new Given('I follow "' . get_string('cohorts', 'cohort') . '"')
|
||||
),
|
||||
$steps
|
||||
);
|
||||
}
|
||||
$parentnodes = get_string('administrationsite') . ' > ' .
|
||||
get_string('users', 'admin') . ' > ' .
|
||||
get_string('accounts', 'admin');
|
||||
$steps = array_merge(
|
||||
array(
|
||||
new Given('I am on homepage'),
|
||||
new Given('I navigate to "' . get_string('cohorts', 'cohort') . '" node in "' . $parentnodes . '"')
|
||||
),
|
||||
$steps
|
||||
);
|
||||
}
|
||||
|
||||
return $steps;
|
||||
|
||||
@@ -27,7 +27,6 @@ Feature: View cohort list
|
||||
| user1 | manager | System | |
|
||||
| user2 | manager | Category | CAT1 |
|
||||
|
||||
@javascript
|
||||
Scenario: Admin can see system cohorts and all cohorts
|
||||
When I log in as "admin"
|
||||
And I navigate to "Cohorts" node in "Site administration > Users > Accounts"
|
||||
@@ -40,7 +39,6 @@ Feature: View cohort list
|
||||
And I should see "Cohort in category 3"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Manager can see system cohorts and all cohorts
|
||||
When I log in as "user1"
|
||||
And I navigate to "Cohorts" node in "Site administration > Users > Accounts"
|
||||
@@ -53,7 +51,6 @@ Feature: View cohort list
|
||||
And I should see "Cohort in category 3"
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: Manager in category can see cohorts in the category
|
||||
When I log in as "user2"
|
||||
And I follow "Courses"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
This files describes API changes in /cohort/ information provided here is intended
|
||||
especially for developers.
|
||||
|
||||
=== 2.9.5 ===
|
||||
* The Webservice core_cohort_get_cohorts now has the added functionality of getting all cohorts
|
||||
by not passing any parameters
|
||||
|
||||
=== 2.6 ===
|
||||
* Webservice core_cohort_update_cohorts was incorrectly specifiying float as the parameter type
|
||||
for cohort id. This field is actually int and input is now reported and processed as such.
|
||||
|
||||
@@ -65,11 +65,13 @@ class completion_criteria_grade extends completion_criteria {
|
||||
$mform->addElement('text', 'criteria_grade_value', get_string('graderequired', 'completion'));
|
||||
$mform->disabledIf('criteria_grade_value', 'criteria_grade');
|
||||
$mform->setType('criteria_grade_value', PARAM_RAW); // Uses unformat_float.
|
||||
$mform->setDefault('criteria_grade_value', format_float($data));
|
||||
// Grades are stored in Moodle with 5 decimal points, make sure we do not accidentally round them
|
||||
// when setting the form value.
|
||||
$mform->setDefault('criteria_grade_value', format_float($data, 5));
|
||||
|
||||
if ($this->id) {
|
||||
$mform->setDefault('criteria_grade', 1);
|
||||
$mform->setDefault('criteria_grade_value', format_float($this->gradepass));
|
||||
$mform->setDefault('criteria_grade_value', format_float($this->gradepass, 5));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +143,10 @@ class completion_criteria_grade extends completion_criteria {
|
||||
* @return string
|
||||
*/
|
||||
public function get_title_detailed() {
|
||||
$graderequired = round($this->gradepass, 2).'%';
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/gradelib.php');
|
||||
$decimalpoints = grade_get_setting($this->course, 'decimalpoints', $CFG->grade_decimalpoints);
|
||||
$graderequired = format_float($this->gradepass, $decimalpoints);
|
||||
return get_string('gradexrequired', 'completion', $graderequired);
|
||||
}
|
||||
|
||||
@@ -161,11 +166,15 @@ class completion_criteria_grade extends completion_criteria {
|
||||
* @return string
|
||||
*/
|
||||
public function get_status($completion) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/gradelib.php');
|
||||
$decimalpoints = grade_get_setting($this->course, 'decimalpoints', $CFG->grade_decimalpoints);
|
||||
|
||||
$grade = $this->get_grade($completion);
|
||||
$graderequired = $this->get_title_detailed();
|
||||
|
||||
if ($grade) {
|
||||
$grade = round($grade, 2).'%';
|
||||
$grade = format_float($grade, $decimalpoints);
|
||||
} else {
|
||||
$grade = get_string('nograde');
|
||||
}
|
||||
@@ -235,15 +244,19 @@ class completion_criteria_grade extends completion_criteria {
|
||||
* type, criteria, requirement, status
|
||||
*/
|
||||
public function get_details($completion) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir . '/gradelib.php');
|
||||
$decimalpoints = grade_get_setting($this->course, 'decimalpoints', $CFG->grade_decimalpoints);
|
||||
|
||||
$details = array();
|
||||
$details['type'] = get_string('coursegrade', 'completion');
|
||||
$details['criteria'] = get_string('graderequired', 'completion');
|
||||
$details['requirement'] = round($this->gradepass, 2).'%';
|
||||
$details['requirement'] = format_float($this->gradepass, $decimalpoints);
|
||||
$details['status'] = '';
|
||||
|
||||
$grade = round($this->get_grade($completion), 2);
|
||||
$grade = format_float($this->get_grade($completion), $decimalpoints);
|
||||
if ($grade) {
|
||||
$details['status'] = $grade.'%';
|
||||
$details['status'] = $grade;
|
||||
}
|
||||
|
||||
return $details;
|
||||
|
||||
@@ -41,12 +41,9 @@ Feature: Allow teachers to manually mark users as complete when configured
|
||||
And I follow "View course report"
|
||||
And I should see "Student First"
|
||||
And I follow "Click to mark user complete"
|
||||
# Running cron just after clicking sometimes fail, so navigate back
|
||||
# and ensure the student completion is updated before running cron.
|
||||
And I am on site homepage
|
||||
And I follow "Completion course"
|
||||
And I follow "View course report"
|
||||
And "//img[contains(@alt, 'Completed')]" "xpath_element" should exist in the "student1" "table_row"
|
||||
# Running cron just after clicking sometimes fail, as record
|
||||
# should be created before the cron runs.
|
||||
And I wait "1" seconds
|
||||
And I trigger cron
|
||||
And I am on site homepage
|
||||
And I log out
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user