Compare commits
862 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 31059fd653 | |||
| cbdde9a495 | |||
| ce65706ceb | |||
| 65f8dc31d8 | |||
| 779303d869 | |||
| 28c9a1993d | |||
| 8f866fa1c3 | |||
| a556c4d02c | |||
| 87c0820260 | |||
| 0444bcffc7 | |||
| 15990b65ac | |||
| 1f3066f197 | |||
| 532c25d5bd | |||
| c256614eab | |||
| 0f67177a54 | |||
| 2e6e70ccd2 | |||
| a13ae2ac2d | |||
| e19f164fc7 | |||
| 702c4b1206 | |||
| 17a31c7a1f | |||
| 7b258d7186 | |||
| 609a129b84 | |||
| ecd01922e9 | |||
| c8782c56d7 | |||
| 4deed68f49 | |||
| 40b705e153 | |||
| 3b35ea4686 | |||
| 5a9dde69b1 | |||
| a02ad260e0 | |||
| 15f15ccddd | |||
| 346e41d042 | |||
| 36bf61e152 | |||
| bc180cd111 | |||
| b10d7c59ae | |||
| 6aee251874 | |||
| d1e9bdfbc8 | |||
| 0c18577317 | |||
| 255221acdf | |||
| 93bd10c300 | |||
| 03bdfbd37b | |||
| d7de792dac | |||
| 763e5d6c83 | |||
| 436c7825b1 | |||
| 9074f5914f | |||
| 62ff078fcf | |||
| df174952fd | |||
| 9d97806c7e | |||
| e6f1c141bf | |||
| 687f244a6f | |||
| 461532ecfc | |||
| 16b6239a88 | |||
| 8121a2fad0 | |||
| d78e72a940 | |||
| 16a175de06 | |||
| ec4f31f984 | |||
| 323a7a151b | |||
| 14eb0c478d | |||
| e8b487e010 | |||
| 641351118e | |||
| 12e42d2246 | |||
| 0a668af390 | |||
| 22290d726a | |||
| 03fc135cb6 | |||
| 0459ed43e1 | |||
| 928f531307 | |||
| 767dfb307d | |||
| 3efe531af4 | |||
| ef54b1272a | |||
| 2e97e57edb | |||
| 2f64ea2a2e | |||
| 3fda0a9736 | |||
| 0047e4612c | |||
| 44088a5aeb | |||
| 2507ecbd3e | |||
| 439f2e7e83 | |||
| b523d5bc33 | |||
| 63e0fee364 | |||
| 063c6e23d4 | |||
| 5c1f1690bb | |||
| b46ad4bdd5 | |||
| 8001ddd8b2 | |||
| b9894e1e9f | |||
| 0e26b1d309 | |||
| 5cc6700f27 | |||
| 090f8f300d | |||
| fc36873f61 | |||
| 315392626b | |||
| c27add8d87 | |||
| ae18cf2461 | |||
| deab7fda59 | |||
| af3085d2d5 | |||
| 55a8f72251 | |||
| af02385d49 | |||
| c5b3017b49 | |||
| 5ec684b353 | |||
| 0a03803081 | |||
| 6527b097e8 | |||
| 8f5c4f6b34 | |||
| b1325427ec | |||
| 5de6795ec0 | |||
| 0dc138d47c | |||
| f367cfcbef | |||
| c2b526c484 | |||
| b01092111c | |||
| 8ef945280c | |||
| fbfeb98d39 | |||
| 24276da9ce | |||
| 1f316df7d9 | |||
| 467aefd1a6 | |||
| f354a67357 | |||
| 32193155f5 | |||
| b3f6c093aa | |||
| 82a678c91e | |||
| f3f21f18c4 | |||
| 05c7b75672 | |||
| 39c01271f0 | |||
| c09f63c5ac | |||
| 9f9bcb251c | |||
| 39864d9e88 | |||
| 2a46808ed3 | |||
| 4221300426 | |||
| d14fe6017f | |||
| cdc0a8db3f | |||
| 9ddb811866 | |||
| 29dd7397e2 | |||
| bef5900bdb | |||
| 623379d82b | |||
| 8480fd9364 | |||
| 5faaf18173 | |||
| d23d771071 | |||
| 5f690a9be6 | |||
| 95dae00235 | |||
| 7c4e3db7c0 | |||
| 0ed1b7d277 | |||
| 690988d958 | |||
| 26b3b4e80e | |||
| a5e67c5bcc | |||
| 01327cfcf5 | |||
| 1b775e96c1 | |||
| ef467ee957 | |||
| 247b756248 | |||
| 1eedfdf2c0 | |||
| d4bbbedbde | |||
| c8abe81b99 | |||
| 7943aabfbe | |||
| 2de77919d8 | |||
| 5094443f65 | |||
| 9ec65dc485 | |||
| 068ef548de | |||
| bad563d2f4 | |||
| 50eb74065b | |||
| febd8afc8e | |||
| cac959739b | |||
| cef5600303 | |||
| 63a2e24bc2 | |||
| 35eefad6b3 | |||
| c8121c53d1 | |||
| 74f6a6ae5b | |||
| d560fb3e26 | |||
| 213220c159 | |||
| baa476ce92 | |||
| 795dc143c2 | |||
| a18e060c5b | |||
| 84ebf61b82 | |||
| 300dff939f | |||
| 2aa6dd4c60 | |||
| e59d25c944 | |||
| a86531f20b | |||
| 239bfa31b0 | |||
| 9056ee506a | |||
| 5a8fdd1c27 | |||
| be14be6175 | |||
| 0b09c8e48f | |||
| 90e4b26229 | |||
| 8b9c45b666 | |||
| 2c3eea86fa | |||
| 39259ea58b | |||
| 3ce36f6ac1 | |||
| 6a9a7005b0 | |||
| 2d9145638c | |||
| 531b675632 | |||
| c41d4355ac | |||
| ac4bf23c02 | |||
| 51c59e8b9f | |||
| 606db83726 | |||
| a62801941e | |||
| 0282c20862 | |||
| 915e21170c | |||
| 11b6abd02c | |||
| 6005337c33 | |||
| ea2833bc35 | |||
| 2271f1845c | |||
| b4875aa348 | |||
| 3b4cc68ff4 | |||
| 2f0d26c522 | |||
| 3dd8bd5069 | |||
| eede6aae43 | |||
| a623fdf11b | |||
| 617144f163 | |||
| 61d3898de9 | |||
| ec297cc65b | |||
| 5e33ee65e5 | |||
| 3bf4cc3887 | |||
| 4f88c9f38d | |||
| 096ef13c79 | |||
| c49e848571 | |||
| 25a0be8b27 | |||
| b760c63189 | |||
| b3569fb6fa | |||
| db14163584 | |||
| c58559191a | |||
| d86be9c53e | |||
| 7de6a916a2 | |||
| cf93e03ea0 | |||
| f2774239cb | |||
| 5049dfceca | |||
| 186af5a430 | |||
| 7a4826bc3e | |||
| 1b1432ab88 | |||
| 5bfbec5521 | |||
| eee25b4a13 | |||
| a175c5d1ba | |||
| d209e7161a | |||
| ef494edcd6 | |||
| 20ada5de55 | |||
| c21c4761d1 | |||
| 9ab9793c53 | |||
| 4a106a5759 | |||
| b5256231a6 | |||
| b29e02d57e | |||
| 95bb29b902 | |||
| 59fe1b009f | |||
| ab8571d19a | |||
| 90ff64881e | |||
| 1818308bca | |||
| b47604e938 | |||
| c1ee5cf31b | |||
| 18f802f85a | |||
| ea8c5bdc74 | |||
| 6b7a5f86a0 | |||
| f28ce6eb2e | |||
| 5bb55eeb21 | |||
| ddb652c706 | |||
| 648cc055c2 | |||
| 0fbda60bb3 | |||
| 486ad6e842 | |||
| 74980995b4 | |||
| 33c3193f06 | |||
| 95924516fa | |||
| 1663aa1fb9 | |||
| 970536b659 | |||
| b6fadf63d4 | |||
| f1213f3a75 | |||
| adac041f8c | |||
| acadd22a65 | |||
| acafcb18f5 | |||
| 71f4cb812c | |||
| b1f78408a5 | |||
| 1669cf37f0 | |||
| 71e7387f43 | |||
| 4eb9f7dd72 | |||
| 568e9560af | |||
| dc7fe6acca | |||
| 786a6227d0 | |||
| fd9ee7dd8b | |||
| 8ba664e245 | |||
| b88a31a654 | |||
| 76dc0848c1 | |||
| c838cb15d8 | |||
| 3b1fec6fb2 | |||
| 4939d0d71a | |||
| d61604b455 | |||
| ec085021f2 | |||
| 4c6481694e | |||
| fdeb6af76e | |||
| ee7af1e19d | |||
| 7561f3d64a | |||
| a65c0da40d | |||
| 1e07291026 | |||
| 1215c112c0 | |||
| 0e37d94b67 | |||
| 3264dcece0 | |||
| cc1dc858c0 | |||
| 6ca7efb157 | |||
| 72d49e8419 | |||
| cd2f4a87a4 | |||
| b8ba7f3619 | |||
| aa8ae42d24 | |||
| 1c7509bc86 | |||
| 7ed94cbe9c | |||
| 7c7d086ae1 | |||
| 725ce55546 | |||
| 1f55a12bf8 | |||
| ee0f0b3986 | |||
| 92d4bcd9f7 | |||
| e7215ce5b7 | |||
| 6dc0b5482b | |||
| 45d7ec6123 | |||
| a7e348e937 | |||
| eba7490c31 | |||
| a4798ada52 | |||
| 0cc8a0b4b2 | |||
| 6d32f6300e | |||
| 08348b8f86 | |||
| 519eec044c | |||
| ab156686ff | |||
| 1fc8ebf085 | |||
| 0086364857 | |||
| 05cc5bf052 | |||
| 8bd3dfd6f5 | |||
| 1c9e079b7c | |||
| 8b90e93c94 | |||
| 94f0349745 | |||
| 50cc7daa0f | |||
| 0a841ac85c | |||
| 28d6752d07 | |||
| 1d0f235097 | |||
| 93d7596d3f | |||
| aa9f17df92 | |||
| d251180b31 | |||
| 67a77fa36f | |||
| c3cf035fad | |||
| 8a52ccea0c | |||
| d35f49ba45 | |||
| 38748c6ada | |||
| 68fb3969e1 | |||
| 527afcfb8c | |||
| c62f8bc71f | |||
| d3c034f8e8 | |||
| 5f399d0c52 | |||
| a9e0505fde | |||
| 96d73266ef | |||
| 66a0fea650 | |||
| a4bba406ad | |||
| 20914ba26a | |||
| 8b5520877b | |||
| 7cacba3db3 | |||
| f4c37747dc | |||
| 3e65f72a40 | |||
| d613a0db57 | |||
| 26f004f29b | |||
| 0ed87e5063 | |||
| 87cc899c44 | |||
| e1661a6346 | |||
| 3ba2b5c925 | |||
| 7c5d28c26c | |||
| 67711964d1 | |||
| bf394372d8 | |||
| d927f222a9 | |||
| bbcbbcd130 | |||
| cc0b20ba9d | |||
| 8f15eebc22 | |||
| d8b6437fa9 | |||
| e257ad8372 | |||
| ba03dc18ad | |||
| 7c15d3b34c | |||
| 1c76803ec1 | |||
| 5660ceba8d | |||
| ae59c35eb9 | |||
| 3c129829ce | |||
| 050720be90 | |||
| 7573d5ff21 | |||
| b3656b26be | |||
| 804c22b8f1 | |||
| 8716b6c89f | |||
| 8b3d19c2f5 | |||
| cf9ed67a4e | |||
| 417b6921d5 | |||
| f72a23d69b | |||
| ca602b6beb | |||
| 2b8647034a | |||
| 956ec418c6 | |||
| 31d453f735 | |||
| b4d0a4479c | |||
| 3e07b8a2f3 | |||
| 383776876b | |||
| 91c8d4da71 | |||
| 1721c8eb85 | |||
| ad3d9452bf | |||
| c5f351435e | |||
| 03b06dedbc | |||
| da80885cc6 | |||
| 94ac7a87fa | |||
| 10b02d6d41 | |||
| ebb6f3e80b | |||
| 7f4db6f4d9 | |||
| 4fc5861cba | |||
| 40b205197c | |||
| cb914a71aa | |||
| 85f376892d | |||
| e0708141f8 | |||
| 76b012d611 | |||
| 53ca351f7a | |||
| ea9f3057da | |||
| f1406d3b39 | |||
| 91251e4889 | |||
| 8994593332 | |||
| 67b3704318 | |||
| 37e7d91b8c | |||
| 3fe64cbd7d | |||
| 22051a4e34 | |||
| e7cd680765 | |||
| 84d2c6f761 | |||
| f97581eda7 | |||
| 2c0b608cda | |||
| eb1381de1d | |||
| c7bfbb01c6 | |||
| 4eacb77012 | |||
| 93835758f3 | |||
| a238e7ed72 | |||
| 98ac33bcb0 | |||
| 0caa8c60d2 | |||
| 2dbdaedc3e | |||
| 30a264540b | |||
| 6d05bee940 | |||
| 2535dfaf64 | |||
| 35186e3725 | |||
| bfe4417cb7 | |||
| 6b6affec1f | |||
| 9e13649c89 | |||
| 1465b22f7d | |||
| f549deed15 | |||
| ab59b7db71 | |||
| 200a2b7fad | |||
| 9945bcec41 | |||
| b4ac5653ed | |||
| 0207466e77 | |||
| 2ca9e09dab | |||
| 6eaf5ec8e3 | |||
| 1d110af2d6 | |||
| 2d121036cc | |||
| 61961447c2 | |||
| 867f40990b | |||
| da6ce47102 | |||
| 78ba7d9e6b | |||
| 63010978b4 | |||
| c5e9bc48f0 | |||
| cd90445d4a | |||
| 0052796dbb | |||
| b522356839 | |||
| 1d45b926f3 | |||
| 0ba5f02b15 | |||
| a31fdfb145 | |||
| d019ffd21f | |||
| a93f8344ae | |||
| 2d7617aa18 | |||
| 84acc68175 | |||
| 38d8b7b703 | |||
| 69ddeb42e2 | |||
| 2bd9cd1077 | |||
| 35588aa876 | |||
| fc415ee908 | |||
| 10b4bda916 | |||
| 3708e1bb7c | |||
| e7e79055e1 | |||
| 3d4cf404df | |||
| 31c0efeac7 | |||
| 3571cd46d2 | |||
| fa6db7b8c1 | |||
| 947a90339a | |||
| dc30afaafc | |||
| 03a5278a38 | |||
| d683942c6a | |||
| 24c0432bbc | |||
| c16de45a14 | |||
| 9d19781014 | |||
| ab6ae906cd | |||
| f45b59d427 | |||
| 3add7d878f | |||
| c9bd902bd3 | |||
| 366124d222 | |||
| 89203e11a7 | |||
| dd83fbfbbc | |||
| 1fb374121a | |||
| f3163a2002 | |||
| 65764352dd | |||
| 2c7b800f2f | |||
| ed7d676329 | |||
| b23bc0a148 | |||
| df9a669791 | |||
| b1ab535efa | |||
| 1e9dce0df4 | |||
| 8dd0756226 | |||
| 8458e3d2c2 | |||
| 951a64f6ef | |||
| b336cf98b4 | |||
| b6ac868d71 | |||
| 57ce05c631 | |||
| f0538cee92 | |||
| f4f4965a1c | |||
| 93a593daab | |||
| c8c1a2cb10 | |||
| 793ab11d95 | |||
| 47221d5fdd | |||
| 1affa3ea22 | |||
| 70971d43eb | |||
| 99e0bb23bf | |||
| d95453d903 | |||
| 53fb01aef0 | |||
| cfd5ba4101 | |||
| 5eb386fd09 | |||
| 594848bb15 | |||
| 64fea720ce | |||
| 83d08fcc21 | |||
| 01e7204646 | |||
| 3152864fd5 | |||
| 2997bd6dce | |||
| 083d5a6f0c | |||
| c1ee80fef5 | |||
| 0a9815d14e | |||
| 3ac5a3544c | |||
| b7cb9c60c1 | |||
| 6f5ca6613f | |||
| a16755314a | |||
| a4919abf4f | |||
| 022a58af8d | |||
| 6480ec0c48 | |||
| 1e4e4a05d7 | |||
| 9dc9608795 | |||
| e08d290469 | |||
| 80bb90c3ca | |||
| a3ddcab336 | |||
| a839769c23 | |||
| 1eb503b379 | |||
| cc5f8bd53f | |||
| bb512f7c1f | |||
| 5b5a73019d | |||
| ce0b9bb7ca | |||
| 38063e7d1b | |||
| ee5b9e137d | |||
| 55103810f0 | |||
| e5b111f26b | |||
| 7c2e2133cc | |||
| 3352ffcfa2 | |||
| 8e74bfa8e8 | |||
| 9f630b6cc4 | |||
| c2779c9f29 | |||
| 7fecbba80b | |||
| 80b81e5094 | |||
| 6e977fcdd6 | |||
| 9c8c5f2d01 | |||
| 9134f3f0df | |||
| b093752289 | |||
| bd87c3e225 | |||
| 7bea1ea240 | |||
| afd6e7d542 | |||
| e29eef4bde | |||
| 63dd180030 | |||
| 8eacbd5a32 | |||
| 680ff52414 | |||
| 884e310a3b | |||
| 7eac026a02 | |||
| deaddfb6b8 | |||
| 85b40b18d5 | |||
| 3b6987cea3 | |||
| 14ff3d59b3 | |||
| dd02a787d8 | |||
| cefe7c7f59 | |||
| d9fc73dc7a | |||
| 3bc1e345ca | |||
| 5d3fe21ab2 | |||
| 17db3e8af1 | |||
| a0da864ac2 | |||
| 0978aab839 | |||
| 7d947ad66c | |||
| 5e63c8e57e | |||
| 34bcea8159 | |||
| 2a56e3c8b9 | |||
| 1fb1c6d456 | |||
| 469e7dd82d | |||
| 1461f9d664 | |||
| 8791525d88 | |||
| a0f39f2b57 | |||
| 6fc2264a8a | |||
| 8893b111c2 | |||
| 3362673173 | |||
| 49703ecf1d | |||
| d56f3531b4 | |||
| 902a36137a | |||
| 19e4d5ada8 | |||
| d81917322f | |||
| b657f6db05 | |||
| abd980d36d | |||
| 7b27045680 | |||
| e4a56bd9dd | |||
| 5807b224d9 | |||
| 8b1596c257 | |||
| 2649eefe1c | |||
| b3bb3a4422 | |||
| 6e10f195c5 | |||
| ab7c329acf | |||
| 95d39aabc7 | |||
| 6e515be94f | |||
| b3b4f9a4a4 | |||
| c71d8267ed | |||
| 1742e76777 | |||
| 2797fcc75e | |||
| 2538e2dab1 | |||
| 6bf5eeed56 | |||
| c14d87daaa | |||
| cb201e866b | |||
| cc6a8bc792 | |||
| fa71841e9d | |||
| be7809f5fd | |||
| 655cdde2dc | |||
| 7f75f1507e | |||
| 3fbf089303 | |||
| 8a453265d2 | |||
| 807d45073a | |||
| 253bbbb668 | |||
| 8fbc1919df | |||
| c41ace2f7a | |||
| 3be351cabc | |||
| 53bd21e7d8 | |||
| 217530dfca | |||
| 30271d87aa | |||
| f271df32ec | |||
| 77ae35faba | |||
| 32d746479b | |||
| b18fd23232 | |||
| bbd644ea34 | |||
| c4bfba91c2 | |||
| 6e7a7aecf3 | |||
| 635493f6dd | |||
| 0f583e0c91 | |||
| 1a7ded8989 | |||
| 159e18c977 | |||
| 801dea3298 | |||
| d468b949f1 | |||
| a0881872c7 | |||
| a9e9cd31e1 | |||
| 0085d95576 | |||
| e4226ddc26 | |||
| 4c7169437b | |||
| b2cdd35a46 | |||
| aa0fad65e3 | |||
| 4c06cef684 | |||
| 6871df272d | |||
| 40a4427420 | |||
| f76b5133a5 | |||
| d5a7b7873e | |||
| ffa71ca45e | |||
| 5248eb8831 | |||
| 5468d02e60 | |||
| 251fd097bb | |||
| 3ac721e5a3 | |||
| ecd99dc88a | |||
| 3097fca71c | |||
| bc1c896692 | |||
| 6a927661f2 | |||
| 601d32ae66 | |||
| 2dde0b96da | |||
| d420bf952f | |||
| a02d7831b6 | |||
| 604db7d557 | |||
| 41ab96e7ff | |||
| 9dfb59fa28 | |||
| ad94e63238 | |||
| 82c0485aab | |||
| 4524454ff2 | |||
| 658bba713a | |||
| 238c388016 | |||
| 5e10e88673 | |||
| 7b6bad24ee | |||
| 11be1e8b2b | |||
| 42126ff6a5 | |||
| f12f99241c | |||
| 8fde6e8ef9 | |||
| 36bd6f3319 | |||
| 0f52f263ca | |||
| b9e1842e02 | |||
| 99261fdf05 | |||
| 07388eaded | |||
| d983601e46 | |||
| fd85f4eeb9 | |||
| c11ac48868 | |||
| 0d5c68bfd8 | |||
| a6b91c8407 | |||
| f6cac05e9c | |||
| 9a2938c57c | |||
| f4d6bab1b4 | |||
| ebfbd63b3c | |||
| 9ec7228b03 | |||
| 0a1f0c4b1f | |||
| 7180fb19c1 | |||
| ac2015f2ce | |||
| 6fc8187375 | |||
| 81e433d505 | |||
| 9fbdee633a | |||
| f1dee5ce23 | |||
| 1ffce0c735 | |||
| 3e307259ac | |||
| 8455124070 | |||
| a1d932bd82 | |||
| d9ef98fc80 | |||
| 4affd3c42e | |||
| 8771f49c0a | |||
| b018b44b49 | |||
| 3d4f5c6bf8 | |||
| 6bbdb16bb1 | |||
| 07783f9c20 | |||
| b19370bd35 | |||
| 9d18c714b8 | |||
| 474dd3da66 | |||
| 5095725a00 | |||
| 02da49597c | |||
| 5f86aa9d14 | |||
| ae916b5d6a | |||
| ea66859873 | |||
| 23f43bb4c4 | |||
| 108d281f6b | |||
| 4a0e272c5b | |||
| 647a688de3 | |||
| 3f9ea21ae3 | |||
| 34a46904c2 | |||
| d73b1f3e71 | |||
| 2c356d8ecd | |||
| 62c7d543f6 | |||
| 008cfb2a1f | |||
| 243f766222 | |||
| 2b9259ed7f | |||
| c5d9d36e79 | |||
| 296029fadf | |||
| 7e78f9c4a5 | |||
| 83bc3ccfdf | |||
| 6a001a3223 | |||
| 1974f5ade7 | |||
| 837e3741fd | |||
| 4bdb702918 | |||
| e588f20b6c | |||
| ad7d8edf0c | |||
| 9f4a69a8cd | |||
| fd4c7d7b69 | |||
| e77b4ac0de | |||
| 4fe4fbba9d | |||
| 331298218b | |||
| db52d4058d | |||
| b5d1353575 | |||
| fb3663ae5c | |||
| 6825f882e2 | |||
| 04b949a8f5 | |||
| 86976c5bd9 | |||
| 33238bb24b | |||
| 2b548c27ee | |||
| e0cd7e44db | |||
| 184cdf0d52 | |||
| 472896acdd | |||
| 1ff977a5e5 | |||
| 68a1c2a8d9 | |||
| db77228155 | |||
| 8a0dcb91cc | |||
| 11b5d9b763 | |||
| dc195425ee | |||
| 72cf8ec5eb | |||
| 1130c181f9 | |||
| 443d4dae06 | |||
| a2720952c2 | |||
| 89262fa9f1 | |||
| bc3c2a8eed | |||
| fb7e5c42cd | |||
| 2e2a229f58 | |||
| d12b20d022 | |||
| 5ce5bc6bdd | |||
| 54c9048405 | |||
| 7b04f1fa49 | |||
| eebd7f8964 | |||
| 871af2ebc5 | |||
| 0d4b11ff88 | |||
| e342149a37 | |||
| 9054cd2a25 | |||
| 7d5e56cffd | |||
| 137c0261ee | |||
| 1c500e2157 | |||
| 46021b98b2 | |||
| 55739cdfb6 | |||
| 63e5416f5b | |||
| 689a8f383c | |||
| 10f981a794 | |||
| 556a760d0c | |||
| 2ba0565d7d | |||
| 16d5729223 | |||
| 38ef7ab379 | |||
| 740cb942ce | |||
| 3725adf852 | |||
| b9c49aefb2 | |||
| 60f8e19ce1 | |||
| d0f43772fb | |||
| 106be68e82 | |||
| f12ad8521f | |||
| 9efa210e32 | |||
| 79b146cb5c | |||
| 8711ce1f4a | |||
| 417fa07162 | |||
| 1910d01a86 | |||
| c9c530fd6e | |||
| dadeff80c9 | |||
| cc41096ad5 | |||
| db9987c267 | |||
| 8d8a5e8035 | |||
| b60373f3e4 | |||
| 1d8bebfeaf | |||
| 41d178f9da | |||
| d144e53188 | |||
| 49b50ef5ab | |||
| 4fac06549a | |||
| 7141921ad4 | |||
| 70e78a4315 | |||
| 520592c43d | |||
| 553b1e6f6d | |||
| bb5652829f | |||
| 288a79ccd4 | |||
| 8f6d8a5653 | |||
| c64368bb1d | |||
| 177beaf23a | |||
| 147d7af758 | |||
| 20bd24b70d | |||
| 7c75924319 | |||
| d90846033b | |||
| da02a3c472 | |||
| 61609ec274 | |||
| 228fc821e0 | |||
| d44071ee09 | |||
| 91fae7e9b4 | |||
| 3e7b9158f4 | |||
| 95f9c8f716 | |||
| 170392d4a0 | |||
| 3724b3aa8d | |||
| 9af90f03bb | |||
| 64a2dfba1f | |||
| 043cf8bab7 | |||
| 832393cfc9 | |||
| d8e7fa9196 | |||
| 075e999c1a | |||
| 8efb66741f | |||
| fa348b5d46 | |||
| ac2eafee91 | |||
| e6c69d835d | |||
| bfa6c5080e | |||
| 0f0729b157 | |||
| f75d82450a | |||
| 3dd33e3862 | |||
| e3b98ac6b6 | |||
| 3951213860 | |||
| 24b81e0566 | |||
| 0ab271dcfd | |||
| b9cb39eaf6 | |||
| c83407f033 | |||
| da75ffce68 | |||
| d48b1de9f7 | |||
| 38d1c9a886 | |||
| 1c48d7e188 | |||
| 11b39253d2 | |||
| 56e84a7985 | |||
| 133f83d557 | |||
| 17e57aa07d | |||
| 710b364b44 | |||
| 81d72831b8 | |||
| 3cfabf7190 | |||
| 0e5791a6cd | |||
| da3e5e0c5c | |||
| ae3b9e1e1f | |||
| 3485ecf225 |
@@ -1,3 +0,0 @@
|
||||
--errors=errors,duplicate-properties
|
||||
--warnings=known-properties,display-property-grouping,empty-rules,important
|
||||
--exclude-list=vendor/,lib/editor/tinymce/,lib/yuilib/,theme/bootstrapbase/style/
|
||||
@@ -35,4 +35,3 @@ composer.lock
|
||||
/lib/yuilib/*/build/*/*-coverage.js
|
||||
# lib/yuilib/version/module/module-coverage.js
|
||||
/lib/yuilib/*/*/*-coverage.js
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
+2
-1
@@ -67,6 +67,7 @@ if ($data = data_submitted() and confirm_sesskey()) {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
$firsterror = reset($adminroot->errors);
|
||||
}
|
||||
$adminroot = admin_get_root(true); //reload tree
|
||||
$settingspage = $adminroot->locate($category, true);
|
||||
}
|
||||
|
||||
@@ -155,4 +156,4 @@ echo $outputhtml;
|
||||
echo html_writer::end_tag('fieldset');
|
||||
echo html_writer::end_tag('form');
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
echo $OUTPUT->footer();
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Validate that the current db structure matches the install.xml files.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Petr Skoda <petr.skoda@totaralms.com>
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(__DIR__ . '/../../config.php');
|
||||
require_once($CFG->libdir.'/clilib.php');
|
||||
|
||||
$help = "Validate database structure
|
||||
|
||||
Options:
|
||||
-h, --help Print out this help.
|
||||
|
||||
Example:
|
||||
\$ sudo -u www-data /usr/bin/php admin/cli/check_database_schema.php
|
||||
";
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array(
|
||||
'help' => false,
|
||||
),
|
||||
array(
|
||||
'h' => 'help',
|
||||
)
|
||||
);
|
||||
|
||||
if ($options['help']) {
|
||||
echo $help;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (empty($CFG->version)) {
|
||||
echo "Database is not yet installed.\n";
|
||||
exit(2);
|
||||
}
|
||||
|
||||
$dbmanager = $DB->get_manager();
|
||||
$schema = $dbmanager->get_install_xml_schema();
|
||||
|
||||
if (!$errors = $dbmanager->check_database_schema($schema)) {
|
||||
echo "Database structure is ok.\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
foreach ($errors as $table => $items) {
|
||||
cli_separator();
|
||||
echo "$table\n";
|
||||
foreach ($items as $item) {
|
||||
echo " * $item\n";
|
||||
}
|
||||
}
|
||||
cli_separator();
|
||||
|
||||
exit(1);
|
||||
@@ -1,202 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* MySQL table row compression tool tool.
|
||||
*
|
||||
* @package core
|
||||
* @copyright 2014 Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Petr Skoda <petr.skoda@totaralms.com>
|
||||
*/
|
||||
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
require(dirname(__FILE__).'/../../config.php');
|
||||
require_once($CFG->libdir . '/clilib.php');
|
||||
|
||||
if ($DB->get_dbfamily() !== 'mysql') {
|
||||
cli_error('This script is used for MySQL databases only.');
|
||||
}
|
||||
|
||||
$engine = strtolower($DB->get_dbengine());
|
||||
if ($engine !== 'innodb' and $engine !== 'xtradb') {
|
||||
cli_error('This script is for MySQL servers using InnoDB or XtraDB engines only.');
|
||||
}
|
||||
|
||||
list($options, $unrecognized) = cli_get_params(
|
||||
array('help' => false, 'info' => false, 'list' => false, 'fix' => false, 'showsql' => false),
|
||||
array('h' => 'help', 'i' => 'info', 'l' => 'list', 'f' => 'fix', 's' => 'showsql')
|
||||
);
|
||||
|
||||
if ($unrecognized) {
|
||||
$unrecognized = implode("\n ", $unrecognized);
|
||||
cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
|
||||
}
|
||||
|
||||
$help =
|
||||
"Script for detection of row size problems in MySQL InnoDB tables.
|
||||
|
||||
By default InnoDB storage table is using legacy Antelope file format
|
||||
which has major restriction on database row size.
|
||||
Use this script to detect and fix database tables with potential data
|
||||
overflow problems.
|
||||
|
||||
Options:
|
||||
-i, --info Show database information
|
||||
-l, --list List problematic tables
|
||||
-f, --fix Attempt to fix all tables (requires SUPER privilege)
|
||||
-s, --showsql Print SQL statements for fixing of tables
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
\$ sudo -u www-data /usr/bin/php admin/cli/mysql_compressed_rows.php -l
|
||||
";
|
||||
|
||||
/** @var mysql_sql_generator $generator */
|
||||
$generator = $DB->get_manager()->generator;
|
||||
|
||||
$info = $DB->get_server_info();
|
||||
$filepertable = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_per_table'");
|
||||
$filepertable = $filepertable ? $filepertable->value : '';
|
||||
$fileformat = $DB->get_record_sql("SHOW VARIABLES LIKE 'innodb_file_format'");
|
||||
$fileformat = $fileformat ? $fileformat->value : '';
|
||||
$prefix = $DB->get_prefix();
|
||||
$database = $CFG->dbname;
|
||||
|
||||
if (!empty($options['info'])) {
|
||||
echo "Database version: " . $info['description'] . "\n";
|
||||
echo "Database name: $database\n";
|
||||
echo "Database engine: " . $DB->get_dbengine() . "\n";
|
||||
echo "innodb_file_per_table: $filepertable\n";
|
||||
echo "innodb_file_format: $fileformat\n";
|
||||
|
||||
exit(0);
|
||||
|
||||
} else if (!empty($options['list'])) {
|
||||
$problem = false;
|
||||
foreach ($DB->get_tables(false) as $table) {
|
||||
$columns = $DB->get_columns($table, false);
|
||||
$size = $generator->guess_antolope_row_size($columns);
|
||||
$format = $DB->get_row_format($table);
|
||||
if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT);
|
||||
echo str_pad($format, 11, ' ', STR_PAD_RIGHT);
|
||||
|
||||
if ($format === 'Compact' or $format === 'Redundant') {
|
||||
$problem = true;
|
||||
echo " (needs fixing)\n";
|
||||
|
||||
} else if ($format !== 'Compressed' and $format !== 'Dynamic') {
|
||||
echo " (unknown)\n";
|
||||
|
||||
} else {
|
||||
echo "\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($problem) {
|
||||
exit(1);
|
||||
}
|
||||
exit(0);
|
||||
|
||||
} else if (!empty($options['fix'])) {
|
||||
$fixtables = array();
|
||||
foreach ($DB->get_tables(false) as $table) {
|
||||
$columns = $DB->get_columns($table, false);
|
||||
$size = $generator->guess_antolope_row_size($columns);
|
||||
$format = $DB->get_row_format($table);
|
||||
if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
|
||||
continue;
|
||||
}
|
||||
if ($format === 'Compact' or $format === 'Redundant') {
|
||||
$fixtables[$table] = $table;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$fixtables) {
|
||||
echo "No changes necessary\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if ($filepertable !== 'ON') {
|
||||
try {
|
||||
$DB->execute("SET GLOBAL innodb_file_per_table=1");
|
||||
} catch (dml_exception $e) {
|
||||
echo "Cannot enable GLOBAL innodb_file_per_table setting, use --showsql option and execute the statements manually.";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
if ($fileformat !== 'Barracuda') {
|
||||
try {
|
||||
$DB->execute("SET GLOBAL innodb_file_format=Barracuda");
|
||||
} catch (dml_exception $e) {
|
||||
echo "Cannot change GLOBAL innodb_file_format setting, use --showsql option and execute the statements manually.";
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$DB->is_compressed_row_format_supported(false)) {
|
||||
echo "MySQL server is not compatible with compressed row format.";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
foreach ($fixtables as $table) {
|
||||
$DB->change_database_structure("ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed");
|
||||
echo str_pad($prefix . $table, 32, ' ', STR_PAD_RIGHT) . " ... Compressed\n";
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
||||
} else if (!empty($options['showsql'])) {
|
||||
$fixtables = array();
|
||||
|
||||
foreach ($DB->get_tables(false) as $table) {
|
||||
$columns = $DB->get_columns($table, false);
|
||||
$size = $generator->guess_antolope_row_size($columns);
|
||||
$format = $DB->get_row_format($table);
|
||||
if ($size <= $generator::ANTELOPE_MAX_ROW_SIZE) {
|
||||
continue;
|
||||
}
|
||||
if ($format === 'Compact' or $format === 'Redundant') {
|
||||
$fixtables[$table] = $table;
|
||||
}
|
||||
}
|
||||
if (!$fixtables) {
|
||||
echo "No changes necessary\n";
|
||||
exit(0);
|
||||
}
|
||||
|
||||
echo "Copy the following SQL statements and execute them using account with SUPER privilege:\n\n";
|
||||
echo "USE $database;\n";
|
||||
echo "SET SESSION sql_mode=STRICT_ALL_TABLES;\n";
|
||||
echo "SET GLOBAL innodb_file_per_table=1;\n";
|
||||
echo "SET GLOBAL innodb_file_format=Barracuda;\n";
|
||||
foreach ($fixtables as $table) {
|
||||
echo "ALTER TABLE {$prefix}$table ROW_FORMAT=Compressed;\n";
|
||||
}
|
||||
echo "\n";
|
||||
exit(0);
|
||||
|
||||
} else {
|
||||
echo $help;
|
||||
die;
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ admin_externalpage_setup('environment', '', $extraurlparams);
|
||||
// Handle the 'updatecomponent' action
|
||||
if ($action == 'updatecomponent' && confirm_sesskey()) {
|
||||
// Create component installer and execute it
|
||||
if ($cd = new component_installer('https://download.moodle.org',
|
||||
if ($cd = new component_installer('http://download.moodle.org',
|
||||
'environment',
|
||||
'environment.zip')) {
|
||||
$status = $cd->install(); //returns COMPONENT_(ERROR | UPTODATE | INSTALLED)
|
||||
@@ -53,7 +53,7 @@ if ($action == 'updatecomponent' && confirm_sesskey()) {
|
||||
case COMPONENT_ERROR:
|
||||
if ($cd->get_error() == 'remotedownloaderror') {
|
||||
$a = new stdClass();
|
||||
$a->url = 'https://download.moodle.org/environment/environment.zip';
|
||||
$a->url = 'http://download.moodle.org/environment/environment.zip';
|
||||
$a->dest = $CFG->dataroot . '/';
|
||||
print_error($cd->get_error(), 'error', $PAGE->url, $a);
|
||||
die();
|
||||
|
||||
@@ -1136,127 +1136,4 @@
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
<MOODLE version="2.8" requires="2.2">
|
||||
<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="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="question/engine/upgrade/upgradelib.php" function="quiz_attempts_upgraded" level="required">
|
||||
<FEEDBACK>
|
||||
<ON_ERROR message="quizattemptsupgradedmessage" />
|
||||
</FEEDBACK>
|
||||
</CUSTOM_CHECK>
|
||||
</CUSTOM_CHECKS>
|
||||
</MOODLE>
|
||||
</COMPATIBILITY_MATRIX>
|
||||
|
||||
+1
-2
@@ -555,8 +555,7 @@ if (isset($SESSION->pluginuninstallreturn)) {
|
||||
// Print default admin page with notifications.
|
||||
$errorsdisplayed = defined('WARN_DISPLAY_ERRORS_ENABLED');
|
||||
|
||||
// We make the assumption that at least one schedule task should run once per day.
|
||||
$lastcron = $DB->get_field_sql('SELECT MAX(lastruntime) FROM {task_scheduled}');
|
||||
$lastcron = $DB->get_field_sql('SELECT MAX(lastcron) FROM {modules}');
|
||||
$cronoverdue = ($lastcron < time() - 3600 * 24);
|
||||
$dbproblems = $DB->diagnose();
|
||||
$maintenancemode = !empty($CFG->maintenance_enabled);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?PHP
|
||||
|
||||
// Allows the admin to configure mnet stuff
|
||||
|
||||
|
||||
@@ -34,12 +34,21 @@ if (!defined('MOODLE_INTERNAL')) {
|
||||
}
|
||||
|
||||
$strmnetservices = get_string('mnetservices', 'mnet');
|
||||
$strmnetlog = get_string('mnetlog', 'mnet');
|
||||
$strmnetedithost = get_string('reviewhostdetails', 'mnet');
|
||||
|
||||
$logurl = $CFG->wwwroot.
|
||||
'/report/log/index.php?chooselog=1&showusers=1&showcourses=1&host_course='.$mnet_peer->id.
|
||||
'%2F1&user='.'0'.
|
||||
'&date=0'.
|
||||
'&modid=&modaction=0&logformat=showashtml';
|
||||
$tabs = array();
|
||||
if (isset($mnet_peer->id) && $mnet_peer->id > 0) {
|
||||
$tabs[] = new tabobject('mnetdetails', 'peers.php?step=update&hostid='.$mnet_peer->id, $strmnetedithost, $strmnetedithost, false);
|
||||
$tabs[] = new tabobject('mnetservices', 'services.php?hostid='.$mnet_peer->id, $strmnetservices, $strmnetservices, false);
|
||||
if ($mnet_peer->application->name == 'moodle' && $mnet_peer->id != $CFG->mnet_all_hosts_id) {
|
||||
$tabs[] = new tabobject('mnetlog', $logurl, $strmnetlog, $strmnetlog, false);
|
||||
}
|
||||
$tabs[] = new tabobject('mnetprofilefields', 'profilefields.php?hostid=' . $mnet_peer->id, get_string('profilefields', 'mnet'), get_string('profilefields', 'mnet'), false);
|
||||
} else {
|
||||
$tabs[] = new tabobject('mnetdetails', '#', $strmnetedithost, $strmnetedithost, false);
|
||||
|
||||
+11
-20
@@ -1039,28 +1039,19 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
foreach ($plugin->get_other_required_plugins() as $component => $requiredversion) {
|
||||
$ok = true;
|
||||
$otherplugin = $pluginman->get_plugin_info($component);
|
||||
$actions = array();
|
||||
|
||||
if (is_null($otherplugin)) {
|
||||
// The required plugin is not installed.
|
||||
$class = 'requires-failed requires-missing';
|
||||
$installurl = new moodle_url('https://moodle.org/plugins/view.php', array('plugin' => $component));
|
||||
$uploadurl = new moodle_url('/admin/tool/installaddon/');
|
||||
$actions[] = html_writer::link($installurl, get_string('dependencyinstall', 'core_plugin'));
|
||||
$actions[] = html_writer::link($uploadurl, get_string('dependencyupload', 'core_plugin'));
|
||||
|
||||
$ok = false;
|
||||
} else if ($requiredversion != ANY_VERSION and $otherplugin->versiondisk < $requiredversion) {
|
||||
// The required plugin is installed but needs to be updated.
|
||||
$class = 'requires-failed requires-outdated';
|
||||
if (!$otherplugin->is_standard()) {
|
||||
$updateurl = new moodle_url($this->page->url, array('sesskey' => sesskey(), 'fetchupdates' => 1));
|
||||
$actions[] = html_writer::link($updateurl, get_string('checkforupdates', 'core_plugin'));
|
||||
}
|
||||
$ok = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Already installed plugin with sufficient version.
|
||||
if ($ok) {
|
||||
$class = 'requires-ok';
|
||||
} else {
|
||||
$class = 'requires-failed';
|
||||
}
|
||||
|
||||
if ($requiredversion != ANY_VERSION) {
|
||||
@@ -1068,11 +1059,11 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
} else {
|
||||
$str = 'otherplugin';
|
||||
}
|
||||
|
||||
$componenturl = new moodle_url('https://moodle.org/plugins/view.php?plugin='.$component);
|
||||
$componenturl = html_writer::tag('a', $component, array('href' => $componenturl->out()));
|
||||
$requires[] = html_writer::tag('li',
|
||||
html_writer::div(get_string($str, 'core_plugin',
|
||||
array('component' => $component, 'version' => $requiredversion)), 'component').
|
||||
html_writer::div(implode(' | ', $actions), 'actions'),
|
||||
get_string($str, 'core_plugin',
|
||||
array('component' => $componenturl, 'version' => $requiredversion)),
|
||||
array('class' => $class));
|
||||
}
|
||||
|
||||
|
||||
@@ -41,24 +41,15 @@ class core_role_existing_role_holders extends core_role_assign_user_selector_bas
|
||||
list($sort, $sortparams) = users_order_by_sql('u', $search, $this->accesscontext);
|
||||
$params = array_merge($params, $sortparams);
|
||||
|
||||
$fields = "SELECT ra.id AS raid," . $this->required_fields_sql('u') . ",ra.contextid,ra.component ";
|
||||
$countfields = "SELECT COUNT(1) ";
|
||||
$sql = "FROM {role_assignments} ra
|
||||
$sql = "SELECT ra.id AS raid," . $this->required_fields_sql('u') . ",ra.contextid,ra.component
|
||||
FROM {role_assignments} ra
|
||||
JOIN {user} u ON u.id = ra.userid
|
||||
JOIN {context} ctx ON ra.contextid = ctx.id
|
||||
WHERE $wherecondition
|
||||
AND ctx.id $ctxcondition
|
||||
AND ra.roleid = :roleid";
|
||||
$order = " ORDER BY ctx.depth DESC, ra.component, $sort";
|
||||
|
||||
if (!$this->is_validating()) {
|
||||
$existinguserscount = $DB->count_records_sql($countfields . $sql, $params);
|
||||
if ($existinguserscount > $this->maxusersperpage) {
|
||||
return $this->too_many_results($search, $existinguserscount);
|
||||
}
|
||||
}
|
||||
|
||||
$contextusers = $DB->get_records_sql($fields . $sql . $order, $params);
|
||||
AND ra.roleid = :roleid
|
||||
ORDER BY ctx.depth DESC, ra.component, $sort";
|
||||
$contextusers = $DB->get_records_sql($sql, $params);
|
||||
|
||||
// No users at all.
|
||||
if (empty($contextusers)) {
|
||||
|
||||
@@ -48,12 +48,11 @@ class core_role_potential_assignees_below_course extends core_role_assign_user_s
|
||||
$fields = 'SELECT ' . $this->required_fields_sql('u');
|
||||
$countfields = 'SELECT COUNT(u.id)';
|
||||
|
||||
$sql = " FROM ($enrolsql) enrolled_users_view
|
||||
JOIN {user} u ON u.id = enrolled_users_view.id
|
||||
LEFT JOIN {role_assignments} ra ON (ra.userid = enrolled_users_view.id AND
|
||||
ra.roleid = :roleid AND ra.contextid = :contextid)
|
||||
WHERE ra.id IS NULL
|
||||
$wherecondition";
|
||||
$sql = " FROM {user} u
|
||||
LEFT JOIN {role_assignments} ra ON (ra.userid = u.id AND ra.roleid = :roleid AND ra.contextid = :contextid)
|
||||
WHERE u.id IN ($enrolsql)
|
||||
$wherecondition
|
||||
AND ra.id IS NULL";
|
||||
$params['contextid'] = $this->context->id;
|
||||
$params['roleid'] = $this->roleid;
|
||||
|
||||
|
||||
@@ -132,7 +132,7 @@ if ($courseid == SITEID) {
|
||||
$PAGE->set_heading($course->fullname.': '.$fullname);
|
||||
}
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($title);
|
||||
echo $OUTPUT->heading($title, 3);
|
||||
echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthnormal');
|
||||
|
||||
// Display them.
|
||||
|
||||
+3
-1
@@ -22,6 +22,7 @@ if ($data = data_submitted() and confirm_sesskey()) {
|
||||
if (admin_write_settings($data)) {
|
||||
$statusmsg = get_string('changessaved');
|
||||
}
|
||||
$adminroot = admin_get_root(true); //reload tree
|
||||
|
||||
if (!empty($adminroot->errors)) {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
@@ -43,9 +44,10 @@ if ($errormsg !== '') {
|
||||
|
||||
$resultshtml = admin_search_settings_html($query); // case insensitive search only
|
||||
|
||||
echo '<form action="' . $PAGE->url->out(true) . '" method="post" id="adminsettings">';
|
||||
echo '<form action="search.php" method="post" id="adminsettings">';
|
||||
echo '<div>';
|
||||
echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
|
||||
echo '<input type="hidden" name="query" value="'.s($query).'" />';
|
||||
echo '</div>';
|
||||
echo '<fieldset>';
|
||||
echo '<div class="clearer"><!-- --></div>';
|
||||
|
||||
@@ -48,6 +48,7 @@ if ($data = data_submitted() and confirm_sesskey()) {
|
||||
$errormsg = get_string('errorwithsettings', 'admin');
|
||||
$firsterror = reset($adminroot->errors);
|
||||
}
|
||||
$adminroot = admin_get_root(true); //reload tree
|
||||
$settingspage = $adminroot->locate($section, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,17 +23,6 @@ if ($hassiteconfig or has_any_capability($capabilities, $systemcontext)) { // sp
|
||||
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', new lang_string('allowuserblockhiding', 'admin'), new lang_string('configallowuserblockhiding', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('allowblockstodock', new lang_string('allowblockstodock', 'admin'), new lang_string('configallowblockstodock', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configtextarea('custommenuitems', new lang_string('custommenuitems', 'admin'), new lang_string('configcustommenuitems', 'admin'), '', PARAM_TEXT, '50', '10'));
|
||||
$temp->add(new admin_setting_configtextarea(
|
||||
'customusermenuitems',
|
||||
new lang_string('customusermenuitems', 'admin'),
|
||||
new lang_string('configcustomusermenuitems', 'admin'),
|
||||
'messages,message|/message/index.php|message
|
||||
myfiles,moodle|/user/files.php|download
|
||||
mybadges,badges|/badges/mybadges.php|award',
|
||||
PARAM_TEXT,
|
||||
'50',
|
||||
'10'
|
||||
));
|
||||
$temp->add(new admin_setting_configcheckbox('enabledevicedetection', new lang_string('enabledevicedetection', 'admin'), new lang_string('configenabledevicedetection', 'admin'), 1));
|
||||
$temp->add(new admin_setting_devicedetectregex('devicedetectregex', new lang_string('devicedetectregex', 'admin'), new lang_string('devicedetectregex_desc', 'admin'), ''));
|
||||
$ADMIN->add('themes', $temp);
|
||||
@@ -133,7 +122,6 @@ mybadges,badges|/badges/mybadges.php|award',
|
||||
$temp->add(new admin_setting_configcheckbox('navshowcategories', new lang_string('navshowcategories', 'admin'), new lang_string('confignavshowcategories', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('navshowmycoursecategories', new lang_string('navshowmycoursecategories', 'admin'), new lang_string('navshowmycoursecategories_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('navshowallcourses', new lang_string('navshowallcourses', 'admin'), new lang_string('confignavshowallcourses', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('navexpandmycourses', new lang_string('navexpandmycourses', 'admin'), new lang_string('navexpandmycourses_desc', 'admin'), 1));
|
||||
$sortoptions = array(
|
||||
'sortorder' => new lang_string('sort_sortorder', 'admin'),
|
||||
'fullname' => new lang_string('sort_fullname', 'admin'),
|
||||
|
||||
@@ -11,6 +11,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
//TODO: Re-enable cc-import once re-implemented in 2.0.x
|
||||
//$temp->add(new admin_setting_configcheckbox('enableimsccimport', new lang_string('enable_cc_import', 'imscc'), new lang_string('enable_cc_import_description', 'imscc'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('enablesafebrowserintegration', new lang_string('enablesafebrowserintegration', 'admin'), new lang_string('configenablesafebrowserintegration', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('enablegroupmembersonly', new lang_string('enablegroupmembersonly', 'admin'), new lang_string('configenablegroupmembersonly', 'admin'), 0));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('dndallowtextandlinks', new lang_string('dndallowtextandlinks', 'admin'), new lang_string('configdndallowtextandlinks', 'admin'), 0));
|
||||
// The CSS optimiser setting. When changed we need to reset the theme caches in order to ensure they are regenerated through the optimiser.
|
||||
|
||||
@@ -68,10 +68,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
|
||||
$temp->add(new admin_setting_special_gradelimiting());
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('grade_report_showmin',
|
||||
get_string('minimum_show', 'grades'),
|
||||
get_string('minimum_show_help', 'grades'), '1'));
|
||||
|
||||
$temp->add(new admin_setting_special_gradepointmax());
|
||||
|
||||
$temp->add(new admin_setting_special_gradepointdefault());
|
||||
@@ -96,9 +92,11 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
GRADE_AGGREGATE_MODE =>new lang_string('aggregatemode', 'grades'),
|
||||
GRADE_AGGREGATE_SUM =>new lang_string('aggregatesum', 'grades'));
|
||||
|
||||
$defaultvisible = array(GRADE_AGGREGATE_SUM);
|
||||
$defaultvisible = array(GRADE_AGGREGATE_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN, GRADE_AGGREGATE_WEIGHTED_MEAN2,
|
||||
GRADE_AGGREGATE_EXTRACREDIT_MEAN, GRADE_AGGREGATE_MEDIAN, GRADE_AGGREGATE_MIN,
|
||||
GRADE_AGGREGATE_MAX, GRADE_AGGREGATE_MODE, GRADE_AGGREGATE_SUM);
|
||||
|
||||
$defaults = array('value' => GRADE_AGGREGATE_SUM, 'forced' => false, 'adv' => false);
|
||||
$defaults = array('value'=>GRADE_AGGREGATE_WEIGHTED_MEAN2, 'forced'=>false, 'adv'=>false);
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregation', new lang_string('aggregation', 'grades'), new lang_string('aggregation_help', 'grades'), $defaults, $options));
|
||||
|
||||
$temp->add(new admin_setting_configmultiselect('grade_aggregations_visible', new lang_string('aggregationsvisible', 'grades'),
|
||||
@@ -112,6 +110,8 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
$defaults = array('value'=>0, 'forced'=>false, 'adv'=>true);
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregateoutcomes', new lang_string('aggregateoutcomes', 'grades'),
|
||||
new lang_string('aggregateoutcomes_help', 'grades'), $defaults, $options));
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_aggregatesubcats', new lang_string('aggregatesubcats', 'grades'),
|
||||
new lang_string('aggregatesubcats_help', 'grades'), $defaults, $options));
|
||||
|
||||
$options = array(0 => new lang_string('none'));
|
||||
for ($i=1; $i<=20; $i++) {
|
||||
@@ -125,9 +125,6 @@ if (has_capability('moodle/grade:manage', $systemcontext)
|
||||
$defaults['forced'] = false;
|
||||
$temp->add(new admin_setting_gradecat_combo('grade_droplow', new lang_string('droplow', 'grades'),
|
||||
new lang_string('droplow_help', 'grades'), $defaults, $options));
|
||||
|
||||
$temp->add(new admin_setting_configcheckbox('grade_overridecat', new lang_string('overridecat', 'grades'),
|
||||
new lang_string('overridecat_help', 'grades'), 1));
|
||||
}
|
||||
$ADMIN->add('grades', $temp);
|
||||
|
||||
|
||||
@@ -278,6 +278,9 @@ if ($hassiteconfig) {
|
||||
$ADMIN->add('webservicesettings', new admin_externalpage('webservicedocumentation', new lang_string('wsdocapi', 'webservice'), "$CFG->wwwroot/$CFG->admin/webservice/documentation.php", 'moodle/site:config', false));
|
||||
/// manage service
|
||||
$temp = new admin_settingpage('externalservices', new lang_string('externalservices', 'webservice'));
|
||||
$temp->add(new admin_setting_enablemobileservice('enablemobilewebservice',
|
||||
new lang_string('enablemobilewebservice', 'admin'),
|
||||
new lang_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), 0));
|
||||
$temp->add(new admin_setting_heading('manageserviceshelpexplaination', new lang_string('information', 'webservice'), new lang_string('servicehelpexplanation', 'webservice')));
|
||||
$temp->add(new admin_setting_manageexternalservices());
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
@@ -355,7 +358,7 @@ if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext))
|
||||
2 => get_string('showmarkandmax', 'question'),
|
||||
);
|
||||
$settings->add(new admin_setting_configselect('question_preview/marks',
|
||||
get_string('marks', 'question'), '', 2, $marksoptions));
|
||||
get_string('marks', 'question'), '', 1, $marksoptions));
|
||||
|
||||
$settings->add(new admin_setting_configselect('question_preview/markdp',
|
||||
get_string('decimalplacesingrades', 'question'), '', 2, array(0, 1, 2, 3, 4, 5, 6, 7)));
|
||||
|
||||
@@ -11,7 +11,6 @@ $temp = new admin_settingpage('systempaths', new lang_string('systempaths','admi
|
||||
$temp->add(new admin_setting_configexecutable('pathtodu', new lang_string('pathtodu', 'admin'), new lang_string('configpathtodu', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('aspellpath', new lang_string('aspellpath', 'admin'), new lang_string('edhelpaspellpath'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtodot', new lang_string('pathtodot', 'admin'), new lang_string('pathtodot_help', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configexecutable('pathtogs', new lang_string('pathtogs', 'admin'), new lang_string('pathtogs_help', 'admin'), '/usr/bin/gs'));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
@@ -24,44 +24,6 @@ if ($hassiteconfig
|
||||
$ADMIN->add('accounts', new admin_externalpage('editusers', new lang_string('userlist','admin'), "$CFG->wwwroot/$CFG->admin/user.php", array('moodle/user:update', 'moodle/user:delete')));
|
||||
$ADMIN->add('accounts', new admin_externalpage('userbulk', new lang_string('userbulk','admin'), "$CFG->wwwroot/$CFG->admin/user/user_bulk.php", array('moodle/user:update', 'moodle/user:delete')));
|
||||
$ADMIN->add('accounts', new admin_externalpage('addnewuser', new lang_string('addnewuser'), "$securewwwroot/user/editadvanced.php?id=-1", 'moodle/user:create'));
|
||||
|
||||
// "User default preferences" settingpage.
|
||||
$temp = new admin_settingpage('userdefaultpreferences', new lang_string('userdefaultpreferences', 'admin'));
|
||||
if ($ADMIN->fulltree) {
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('emaildisplayno');
|
||||
$choices['1'] = new lang_string('emaildisplayyes');
|
||||
$choices['2'] = new lang_string('emaildisplaycourse');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_maildisplay', new lang_string('emaildisplay'),
|
||||
'', 2, $choices));
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('textformat');
|
||||
$choices['1'] = new lang_string('htmlformat');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_mailformat', new lang_string('emailformat'), '', 1, $choices));
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('emaildigestoff');
|
||||
$choices['1'] = new lang_string('emaildigestcomplete');
|
||||
$choices['2'] = new lang_string('emaildigestsubjects');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_maildigest', new lang_string('emaildigest'),
|
||||
new lang_string('emaildigest_help'), 0, $choices));
|
||||
|
||||
|
||||
$choices = array();
|
||||
$choices['1'] = new lang_string('autosubscribeyes');
|
||||
$choices['0'] = new lang_string('autosubscribeno');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_autosubscribe', new lang_string('autosubscribe'),
|
||||
'', 1, $choices));
|
||||
|
||||
$choices = array();
|
||||
$choices['0'] = new lang_string('trackforumsno');
|
||||
$choices['1'] = new lang_string('trackforumsyes');
|
||||
$temp->add(new admin_setting_configselect('defaultpreference_trackforums', new lang_string('trackforums'),
|
||||
'', 0, $choices));
|
||||
}
|
||||
$ADMIN->add('accounts', $temp);
|
||||
|
||||
$ADMIN->add('accounts', new admin_externalpage('profilefields', new lang_string('profilefields','admin'), "$CFG->wwwroot/user/profile/index.php", 'moodle/site:config'));
|
||||
$ADMIN->add('accounts', new admin_externalpage('cohorts', new lang_string('cohorts', 'cohort'), $CFG->wwwroot . '/cohort/index.php', array('moodle/cohort:manage', 'moodle/cohort:view')));
|
||||
|
||||
@@ -190,9 +152,6 @@ if ($hassiteconfig
|
||||
'institution' => new lang_string('institution'),
|
||||
)));
|
||||
$temp->add(new admin_setting_configtext('fullnamedisplay', new lang_string('fullnamedisplay', 'admin'), new lang_string('configfullnamedisplay', 'admin'), 'language', PARAM_TEXT, 50));
|
||||
$temp->add(new admin_setting_configtext('alternativefullnameformat', new lang_string('alternativefullnameformat', 'admin'),
|
||||
new lang_string('alternativefullnameformat_desc', 'admin'),
|
||||
'language', PARAM_RAW, 50));
|
||||
$temp->add(new admin_setting_configtext('maxusersperpage', new lang_string('maxusersperpage','admin'), new lang_string('configmaxusersperpage','admin'), 100, PARAM_INT));
|
||||
$temp->add(new admin_setting_configcheckbox('enablegravatar', new lang_string('enablegravatar', 'admin'), new lang_string('enablegravatar_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configtext('gravatardefaulturl', new lang_string('gravatardefaulturl', 'admin'), new lang_string('gravatardefaulturl_help', 'admin'), 'mm'));
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000;
|
||||
$plugin->requires = 2014110400;
|
||||
$plugin->version = 2014051200;
|
||||
$plugin->requires = 2014050800;
|
||||
$plugin->component = 'tool_assignmentupgrade';
|
||||
$plugin->dependencies = array('mod_assign' => 2014110400);
|
||||
$plugin->dependencies = array('mod_assign' => 2014050800);
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000;
|
||||
$plugin->requires = 2014110400;
|
||||
$plugin->version = 2014051200;
|
||||
$plugin->requires = 2014050800;
|
||||
$plugin->component = 'tool_availabilityconditions';
|
||||
|
||||
@@ -185,12 +185,6 @@ Feature: Set up contextual data for tests
|
||||
| url | Test url name | Test url description | C1 | url1 |
|
||||
| wiki | Test wiki name | Test wiki description | C1 | wiki1 |
|
||||
| workshop | Test workshop name | Test workshop description | C1 | workshop1 |
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale 1 | Disappointing, Good, Very good, Excellent |
|
||||
And the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | grade |
|
||||
| assign | Test assignment name with scale | Test assignment description | C1 | assign1 | Test Scale 1 |
|
||||
When I log in as "admin"
|
||||
And I follow "Course 1"
|
||||
Then I should see "Test assignment name"
|
||||
@@ -220,10 +214,6 @@ Feature: Set up contextual data for tests
|
||||
And I should see "Test workshop name"
|
||||
And I follow "Test assignment name"
|
||||
And I should see "Test assignment description"
|
||||
And I follow "C1"
|
||||
And I follow "Test assignment name with scale"
|
||||
And I follow "Edit settings"
|
||||
And the field "Type" matches value "Scale"
|
||||
|
||||
@javascript
|
||||
Scenario: Add relations between users and groups
|
||||
@@ -263,168 +253,24 @@ Feature: Set up contextual data for tests
|
||||
And I set the field "groups" to "Group 2 (1)"
|
||||
And the "members" select box should contain "Student 2"
|
||||
|
||||
Scenario: Add cohorts and cohort members with data generator
|
||||
Scenario: Add cohorts with data generator
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Student | 1 | student1@asd.com |
|
||||
| student2 | Student | 2 | student2@asd.com |
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber |
|
||||
| System cohort A | CHSA |
|
||||
| System cohort 1 | CH01 |
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber | contextlevel | reference |
|
||||
| System cohort B | CHSB | System | |
|
||||
| Cohort in category | CHC | Category | CAT1 |
|
||||
| Empty cohort | CHE | Category | CAT1 |
|
||||
And the following "cohort members" exist:
|
||||
| user | cohort |
|
||||
| student1 | CHSA |
|
||||
| student2 | CHSB |
|
||||
| student1 | CHSB |
|
||||
| student1 | CHC |
|
||||
| System cohort 2 | CH02 | System | |
|
||||
| Cohort in category 1 | CH1 | Category | CAT1 |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Cohorts" node in "Site administration > Users > Accounts"
|
||||
Then the following should exist in the "cohorts" table:
|
||||
| Name | Cohort size |
|
||||
| System cohort A | 1 |
|
||||
| System cohort B | 2 |
|
||||
Then I should see "System cohort 1"
|
||||
And I should see "System cohort 2"
|
||||
And I should not see "Cohort in category"
|
||||
And I follow "Courses"
|
||||
And I follow "Cat 1"
|
||||
And I follow "Cohorts"
|
||||
And I should see "Cohort in category 1"
|
||||
And I should not see "System cohort"
|
||||
And the following should exist in the "cohorts" table:
|
||||
| Name | Cohort size |
|
||||
| Cohort in category | 1 |
|
||||
| Empty cohort | 0 |
|
||||
|
||||
Scenario: Add grade categories with data generator
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course |
|
||||
| Grade category 1 | C1 |
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course | gradecategory |
|
||||
| Grade sub category 2 | C1 | Grade category 1 |
|
||||
When I log in as "admin"
|
||||
And I follow "Courses"
|
||||
And I follow "Course 1"
|
||||
And I navigate to "Grades" node in "Course administration"
|
||||
Then I should see "Grade category 1"
|
||||
And I should see "Grade sub category 2"
|
||||
|
||||
Scenario: Add a bunch of grade items
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course |
|
||||
| Grade category 1 | C1 |
|
||||
And the following "grade categories" exist:
|
||||
| fullname | course | gradecategory |
|
||||
| Grade sub category 2 | C1 | Grade category 1 |
|
||||
And the following "grade items" exist:
|
||||
| itemname | course |
|
||||
| Test Grade Item 1 | C1 |
|
||||
And the following "grade items" exist:
|
||||
| itemname | course | gradecategory |
|
||||
| Test Grade Item 2 | C1 | Grade category 1 |
|
||||
| Test Grade Item 3 | C1 | Grade sub category 2 |
|
||||
When I log in as "admin"
|
||||
And I follow "Course 1"
|
||||
And I follow "Grades"
|
||||
And I expand "Setup" node
|
||||
And I follow "Categories and items"
|
||||
Then I should see "Test Grade Item 1"
|
||||
And I follow "Edit Test Grade Item 1"
|
||||
And I expand all fieldsets
|
||||
And I should see "Course 1"
|
||||
And I press "Cancel"
|
||||
And I should see "Grade category 1"
|
||||
And I should see "Test Grade Item 2"
|
||||
And I follow "Edit Test Grade Item 2"
|
||||
And I expand all fieldsets
|
||||
And I should see "Grade category 1"
|
||||
And I press "Cancel"
|
||||
And I should see "Grade sub category 2"
|
||||
And I should see "Test Grade Item 3"
|
||||
And I follow "Edit Test Grade Item 3"
|
||||
And I expand all fieldsets
|
||||
And I should see "Grade sub category 2"
|
||||
And I press "Cancel"
|
||||
|
||||
Scenario: Add a bunch of scales
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale 1 | Disappointing, Good, Very good, Excellent |
|
||||
When I log in as "admin"
|
||||
And I follow "Course 1"
|
||||
And I follow "Grades"
|
||||
And I follow "Scales"
|
||||
Then I should see "Test Scale 1"
|
||||
And I should see "Disappointing, Good, Very good, Excellent"
|
||||
|
||||
Scenario: Add a bunch of outcomes
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale 1 | Disappointing, Good, Very good, Excellent |
|
||||
And the following "grade outcomes" exist:
|
||||
| fullname | shortname | scale |
|
||||
| Grade outcome 1 | OT1 | Test Scale 1 |
|
||||
And the following "grade outcomes" exist:
|
||||
| fullname | shortname | course | scale |
|
||||
| Grade outcome 2 | OT2 | C1 | Test Scale 1 |
|
||||
When I log in as "admin"
|
||||
And I set the following administration settings values:
|
||||
| Enable outcomes | 1 |
|
||||
And I follow "Home"
|
||||
And I follow "Course 1"
|
||||
And I follow "Outcomes"
|
||||
Then I should see "Grade outcome 1" in the "#addoutcomes" "css_element"
|
||||
And I should see "Grade outcome 2" in the "#removeoutcomes" "css_element"
|
||||
And I follow "Edit outcomes"
|
||||
And the following should exist in the "generaltable" table:
|
||||
| Full name | Short name | Scale |
|
||||
| Grade outcome 2 | OT2 | Test Scale 1 |
|
||||
|
||||
Scenario: Add a bunch of outcome grade items
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "scales" exist:
|
||||
| name | scale |
|
||||
| Test Scale 1 | Disappointing, Good, Very good, Excellent |
|
||||
And the following "grade outcomes" exist:
|
||||
| fullname | shortname | course | scale |
|
||||
| Grade outcome 1 | OT1 | C1 | Test Scale 1 |
|
||||
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 |
|
||||
When I log in as "admin"
|
||||
And I set the following administration settings values:
|
||||
| Enable outcomes | 1 |
|
||||
And I follow "Home"
|
||||
And I follow "Course 1"
|
||||
And I follow "Grades"
|
||||
And I expand "Setup" node
|
||||
And I follow "Categories and items"
|
||||
Then I should see "Test Outcome Grade Item 1"
|
||||
And I follow "Edit Test Outcome Grade Item 1"
|
||||
And the field "Outcome" matches value "Grade outcome 1"
|
||||
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"
|
||||
|
||||
@@ -159,7 +159,6 @@ Feature: Verify that all form fields values can be get and set
|
||||
And I add a "Lesson" to section "1"
|
||||
And I set the following fields to these values:
|
||||
| Name | Test lesson |
|
||||
| Description | Test lesson description |
|
||||
| available[enabled] | 1 |
|
||||
And I set the field "deadline[enabled]" to "1"
|
||||
# Checkbox (AJAX) - Checking "the field matches value" before saving.
|
||||
|
||||
@@ -11,7 +11,6 @@ Feature: Forms manipulation
|
||||
When I set the field "First name" to "Field value"
|
||||
And I set the field "Text editor" to "Plain text area"
|
||||
And I set the field "Unmask" to "1"
|
||||
And I expand all fieldsets
|
||||
Then the field "First name" matches value "Field value"
|
||||
And the "Text editor" select box should contain "Plain text area"
|
||||
And the field "Unmask" matches value "1"
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version
|
||||
$plugin->component = 'tool_behat'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_capability'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -48,8 +48,5 @@ function xmldb_tool_customlang_upgrade($oldversion) {
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000;
|
||||
$plugin->requires = 2014110400;
|
||||
$plugin->version = 2014051200;
|
||||
$plugin->requires = 2014050800;
|
||||
$plugin->component = 'tool_customlang'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_dbtransfer'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -308,7 +308,8 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
$username = 'tool_generator_' . $textnumber;
|
||||
|
||||
// Create user account.
|
||||
$record = array('username' => $username, 'idnumber' => $number);
|
||||
$record = array('firstname' => get_string('firstname', 'tool_generator'),
|
||||
'lastname' => $number, 'username' => $username);
|
||||
|
||||
// We add a user password if it has been specified.
|
||||
if (!empty($CFG->tool_generator_users_password)) {
|
||||
|
||||
@@ -62,6 +62,7 @@ $string['error_nonexistingcourse'] = 'The specified course does not exist';
|
||||
$string['error_nopageinstances'] = 'The selected course does not contain page module instances';
|
||||
$string['error_notdebugging'] = 'Not available on this server because debugging is not set to DEVELOPER';
|
||||
$string['error_nouserspassword'] = 'You need to set $CFG->tool_generator_users_password in config.php to generate the test plan';
|
||||
$string['firstname'] = 'Test course user';
|
||||
$string['fullname'] = 'Test course: {$a->size}';
|
||||
$string['maketestcourse'] = 'Make test course';
|
||||
$string['maketestplan'] = 'Make JMeter test plan';
|
||||
|
||||
@@ -136,7 +136,7 @@ class tool_generator_maketestcourse_testcase extends advanced_testcase {
|
||||
$lastusernumber = 0;
|
||||
$discussionstarters = array();
|
||||
foreach ($discussions as $discussion) {
|
||||
$usernumber = core_user::get_user($discussion->userid, 'id, idnumber')->idnumber;
|
||||
$usernumber = intval($discussion->lastname);
|
||||
|
||||
// Checks that the users are odd numbers.
|
||||
$this->assertEquals(1, $usernumber % 2);
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000;
|
||||
$plugin->requires = 2014110400;
|
||||
$plugin->version = 2014051200;
|
||||
$plugin->requires = 2014050800;
|
||||
$plugin->component = 'tool_generator';
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version
|
||||
$plugin->component = 'tool_health'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
$plugin->maturity = MATURITY_ALPHA; // this version's maturity level
|
||||
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version
|
||||
$plugin->component = 'tool_innodb'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -66,7 +66,6 @@ $string['validationmsg_filenotexists'] = 'Extracted file not found';
|
||||
$string['validationmsg_filesnumber'] = 'Not enough files found in the package';
|
||||
$string['validationmsg_filestatus'] = 'Unable to extract all files';
|
||||
$string['validationmsg_filestatus_info'] = 'Attempting to extract file {$a->file} resulted in error \'{$a->status}\'.';
|
||||
$string['validationmsg_foundlangfile'] = 'Found language file';
|
||||
$string['validationmsg_maturity'] = 'Declared maturity level';
|
||||
$string['validationmsg_maturity_help'] = 'The plugin can declare its maturity level. If the maintainer considers the plugin stable, the declared maturity level will read MATURITY_STABLE. All other maturity levels (such as alpha or beta) should be considered unstable and a warning is raised.';
|
||||
$string['validationmsg_missingexpectedlangenfile'] = 'English language file name mismatch';
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->component = 'tool_installaddon';
|
||||
$plugin->version = 2014111000;
|
||||
$plugin->requires = 2014110400;
|
||||
$plugin->version = 2014051200;
|
||||
$plugin->requires = 2014050800;
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Lang import controller
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
/**
|
||||
* Lang import controller
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class controller {
|
||||
/** @var array list of informational messages */
|
||||
public $info;
|
||||
/** @var array list of error messages */
|
||||
public $errors;
|
||||
/** @var \lang_installer */
|
||||
private $installer;
|
||||
/** @var array languages available on the remote server */
|
||||
public $availablelangs;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
make_temp_directory('');
|
||||
make_upload_directory('lang');
|
||||
|
||||
$this->info = array();
|
||||
$this->errors = array();
|
||||
$this->installer = new \lang_installer();
|
||||
|
||||
$this->availablelangs = $this->installer->get_remote_list_of_languages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Install language packs provided
|
||||
*
|
||||
* @param string|array $langs array of langcodes or individual langcodes
|
||||
* @param bool $updating true if updating the langpacks
|
||||
* @return int false if an error encountered or
|
||||
* @throws \moodle_exception when error is encountered installing langpack
|
||||
*/
|
||||
public function install_languagepacks($langs, $updating = false) {
|
||||
global $CFG;
|
||||
|
||||
$this->installer->set_queue($langs);
|
||||
$results = $this->installer->run();
|
||||
|
||||
$updatedpacks = 0;
|
||||
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
switch ($langstatus) {
|
||||
case \lang_installer::RESULT_DOWNLOADERROR:
|
||||
$a = new \stdClass();
|
||||
$a->url = $this->installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
$this->errors[] = get_string('remotedownloaderror', 'error', $a);
|
||||
throw new \moodle_exception('remotedownloaderror', 'error', $a);
|
||||
break;
|
||||
case \lang_installer::RESULT_INSTALLED:
|
||||
$updatedpacks++;
|
||||
if ($updating) {
|
||||
event\langpack_updated::event_with_langcode($langcode)->trigger();
|
||||
$this->info[] = get_string('langpackupdated', 'tool_langimport', $langcode);
|
||||
} else {
|
||||
$this->info[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
|
||||
event\langpack_imported::event_with_langcode($langcode)->trigger();
|
||||
}
|
||||
break;
|
||||
case \lang_installer::RESULT_UPTODATE:
|
||||
$this->info[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $updatedpacks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uninstall language pack
|
||||
*
|
||||
* @param string $lang language code
|
||||
* @return bool true if language succesfull installed
|
||||
*/
|
||||
public function uninstall_language($lang) {
|
||||
global $CFG;
|
||||
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$lang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$lang;
|
||||
$rm1 = false;
|
||||
$rm2 = false;
|
||||
if (file_exists($dest1)) {
|
||||
$rm1 = remove_dir($dest1);
|
||||
}
|
||||
if (file_exists($dest2)) {
|
||||
$rm2 = remove_dir($dest2);
|
||||
}
|
||||
|
||||
if ($rm1 or $rm2) {
|
||||
$this->info[] = get_string('langpackremoved', 'tool_langimport', $lang);
|
||||
event\langpack_removed::event_with_langcode($lang)->trigger();
|
||||
return true;
|
||||
} else { // Nothing deleted, possibly due to permission error.
|
||||
$this->errors[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updated all install language packs with the latest found on servre
|
||||
*
|
||||
* @return bool true if languages succesfully updated.
|
||||
*/
|
||||
public function update_all_installed_languages() {
|
||||
global $CFG;
|
||||
|
||||
if (!$availablelangs = $this->installer->get_remote_list_of_languages()) {
|
||||
$this->errors[] = get_string('cannotdownloadlanguageupdatelist', 'error');
|
||||
return false;
|
||||
}
|
||||
|
||||
$md5array = array(); // Convert to (string)langcode => (string)md5.
|
||||
foreach ($availablelangs as $alang) {
|
||||
$md5array[$alang[0]] = $alang[1];
|
||||
}
|
||||
|
||||
// Filter out unofficial packs.
|
||||
$currentlangs = array_keys(get_string_manager()->get_list_of_translations(true));
|
||||
$updateablelangs = array();
|
||||
foreach ($currentlangs as $clang) {
|
||||
if (!array_key_exists($clang, $md5array)) {
|
||||
$this->info[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
|
||||
continue;
|
||||
}
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$clang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$clang;
|
||||
|
||||
if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')) {
|
||||
$updateablelangs[] = $clang;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out packs that have the same md5 key.
|
||||
$neededlangs = array();
|
||||
foreach ($updateablelangs as $ulang) {
|
||||
if (!$this->is_installed_lang($ulang, $md5array[$ulang])) {
|
||||
$neededlangs[] = $ulang;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$updated = $this->install_languagepacks($neededlangs, true);
|
||||
} catch (\moodle_exception $e) {
|
||||
$this->errors[] = 'An exception occurred while installing language packs: ' . $e->getMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($updated) {
|
||||
$this->info[] = get_string('langupdatecomplete', 'tool_langimport');
|
||||
} else {
|
||||
$this->info[] = get_string('nolangupdateneeded', 'tool_langimport');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks the md5 of the zip file, grabbed from download.moodle.org,
|
||||
* against the md5 of the local language file from last update
|
||||
* @param string $lang language code
|
||||
* @param string $md5check md5 to check
|
||||
* @return bool true if installed
|
||||
*/
|
||||
public function is_installed_lang($lang, $md5check) {
|
||||
global $CFG;
|
||||
$md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
|
||||
if (file_exists($md5file)) {
|
||||
return (file_get_contents($md5file) == $md5check);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The langimport langpack imported event.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_langimport langpack imported event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string langcode: the langpage pack code.
|
||||
* }
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class langpack_imported extends \core\event\base {
|
||||
/**
|
||||
* Create instance of event.
|
||||
*
|
||||
* @param string $langcode
|
||||
* @return langpack_updated
|
||||
*/
|
||||
public static function event_with_langcode($langcode) {
|
||||
$data = array(
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'langcode' => $langcode,
|
||||
)
|
||||
);
|
||||
|
||||
return self::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The language pack '{$this->other['langcode']}' was installed.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('langpackinstalledevent', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relevant URL.
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/langimport/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['langcode'])) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set');
|
||||
}
|
||||
// We can't use PARAM_LANG here as the string manager might not be aware of langpack yet.
|
||||
$cleanedlang = clean_param($this->other['langcode'], PARAM_SAFEDIR);
|
||||
if ($cleanedlang !== $this->other['langcode']) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The langimport langpack removed event.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_langimport langpack removed event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string langcode: the langpage pack code.
|
||||
* }
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class langpack_removed extends \core\event\base {
|
||||
/**
|
||||
* Create instance of event.
|
||||
*
|
||||
* @param string $langcode
|
||||
* @return langpack_updated
|
||||
*/
|
||||
public static function event_with_langcode($langcode) {
|
||||
$data = array(
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'langcode' => $langcode,
|
||||
)
|
||||
);
|
||||
|
||||
return self::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The language pack '{$this->other['langcode']}' was removed.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relevant URL.
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/langimport/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('langpackremovedevent', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['langcode'])) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set');
|
||||
}
|
||||
|
||||
// We can't use PARAM_LANG here as it queries installed strings.
|
||||
$cleanedlang = clean_param($this->other['langcode'], PARAM_SAFEDIR);
|
||||
if ($cleanedlang !== $this->other['langcode']) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,115 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The langimport langpack updated event.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_langimport\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_langimport langpack updated event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string langcode: the langpage pack code.
|
||||
* }
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class langpack_updated extends \core\event\base {
|
||||
/**
|
||||
* Create instance of event.
|
||||
*
|
||||
* @param string $langcode
|
||||
* @return langpack_updated
|
||||
*/
|
||||
public static function event_with_langcode($langcode) {
|
||||
$data = array(
|
||||
'context' => \context_system::instance(),
|
||||
'other' => array(
|
||||
'langcode' => $langcode,
|
||||
)
|
||||
);
|
||||
|
||||
return self::create($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The language pack '{$this->other['langcode']}' was updated.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('langpackupdatedevent', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns relevant URL.
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/langimport/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['langcode'])) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set');
|
||||
}
|
||||
|
||||
$cleanedlang = clean_param($this->other['langcode'], PARAM_LANG);
|
||||
if ($cleanedlang !== $this->other['langcode']) {
|
||||
throw new \coding_exception('The \'langcode\' value must be set to a valid language code');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A scheduled task for updating langpacks.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_langimport\task;
|
||||
|
||||
/**
|
||||
* A scheduled task for updating langpacks.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class update_langpacks_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('updatelangs', 'tool_langimport');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run langpack update
|
||||
*/
|
||||
public function execute() {
|
||||
global $CFG;
|
||||
|
||||
if (!empty($CFG->skiplangupgrade)) {
|
||||
mtrace('Langpack update skipped. ($CFG->skiplangupgrade set)');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$controller = new \tool_langimport\controller();
|
||||
if ($controller->update_all_installed_languages()) {
|
||||
foreach ($controller->info as $message) {
|
||||
mtrace($message);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
foreach ($controller->errors as $message) {
|
||||
mtrace($message);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Definition of langimport tasks
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category task
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$tasks = array(
|
||||
array(
|
||||
'classname' => 'tool_langimport\task\update_langpacks_task',
|
||||
'blocking' => 0,
|
||||
'minute' => 'R',
|
||||
'hour' => '4',
|
||||
'day' => '*',
|
||||
'month' => '*',
|
||||
'dayofweek' => '*'
|
||||
)
|
||||
);
|
||||
+166
-15
@@ -17,7 +17,7 @@
|
||||
/**
|
||||
* Fetches language packages from download.moodle.org server
|
||||
*
|
||||
* Language packages are available at https://download.moodle.org/langpack/
|
||||
* Language packages are available at http://download.moodle.org/langpack/
|
||||
* in ZIP format together with a file languages.md5 containing their hashes
|
||||
* and meta info.
|
||||
* Locally, language packs are saved into $CFG->dataroot/lang/
|
||||
@@ -28,8 +28,10 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require(__DIR__.'/../../../config.php');
|
||||
require(dirname(dirname(dirname(dirname(__FILE__)))) . '/config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
admin_externalpage_setup('toollangimport');
|
||||
|
||||
@@ -63,17 +65,37 @@ define('UPDATE_ALL_LANG', 5);
|
||||
|
||||
get_string_manager()->reset_caches();
|
||||
|
||||
$controller = new tool_langimport\controller();
|
||||
$notice_ok = array();
|
||||
$notice_error = array();
|
||||
|
||||
if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($pack)) {
|
||||
core_php_time_limit::raise();
|
||||
$controller->install_languagepacks($pack);
|
||||
make_temp_directory('');
|
||||
make_upload_directory('lang');
|
||||
|
||||
$installer = new lang_installer($pack);
|
||||
$results = $installer->run();
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
switch ($langstatus) {
|
||||
case lang_installer::RESULT_DOWNLOADERROR:
|
||||
$a = new stdClass();
|
||||
$a->url = $installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
print_error('remotedownloaderror', 'error', 'index.php', $a);
|
||||
break;
|
||||
case lang_installer::RESULT_INSTALLED:
|
||||
$notice_ok[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
|
||||
break;
|
||||
case lang_installer::RESULT_UPTODATE:
|
||||
$notice_ok[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
|
||||
if ($uninstalllang == 'en') {
|
||||
// TODO.
|
||||
$controller->errors[] = 'English language pack can not be uninstalled';
|
||||
$notice_error[] = 'English language pack can not be uninstalled';
|
||||
|
||||
} else if (!$confirm and confirm_sesskey()) {
|
||||
echo $OUTPUT->header();
|
||||
@@ -84,13 +106,120 @@ if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
|
||||
die;
|
||||
|
||||
} else if (confirm_sesskey()) {
|
||||
$controller->uninstall_language($uninstalllang);
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$uninstalllang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$uninstalllang;
|
||||
$rm1 = false;
|
||||
$rm2 = false;
|
||||
if (file_exists($dest1)){
|
||||
$rm1 = remove_dir($dest1);
|
||||
}
|
||||
if (file_exists($dest2)){
|
||||
$rm2 = remove_dir($dest2);
|
||||
}
|
||||
if ($rm1 or $rm2) {
|
||||
$notice_ok[] = get_string('langpackremoved', 'tool_langimport');
|
||||
} else { //nothing deleted, possibly due to permission error
|
||||
$notice_error[] = 'An error has occurred, language pack is not completely uninstalled, please check file permissions';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($mode == UPDATE_ALL_LANG) {
|
||||
core_php_time_limit::raise();
|
||||
$controller->update_all_installed_languages();
|
||||
|
||||
$installer = new lang_installer();
|
||||
|
||||
if (!$availablelangs = $installer->get_remote_list_of_languages()) {
|
||||
print_error('cannotdownloadlanguageupdatelist', 'error');
|
||||
}
|
||||
$md5array = array(); // (string)langcode => (string)md5
|
||||
foreach ($availablelangs as $alang) {
|
||||
$md5array[$alang[0]] = $alang[1];
|
||||
}
|
||||
|
||||
// filter out unofficial packs
|
||||
$currentlangs = array_keys(get_string_manager()->get_list_of_translations(true));
|
||||
$updateablelangs = array();
|
||||
foreach ($currentlangs as $clang) {
|
||||
if (!array_key_exists($clang, $md5array)) {
|
||||
$notice_ok[] = get_string('langpackupdateskipped', 'tool_langimport', $clang);
|
||||
continue;
|
||||
}
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$clang;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$clang;
|
||||
|
||||
if (file_exists($dest1.'/langconfig.php') || file_exists($dest2.'/langconfig.php')){
|
||||
$updateablelangs[] = $clang;
|
||||
}
|
||||
}
|
||||
|
||||
// then filter out packs that have the same md5 key
|
||||
$neededlangs = array(); // all the packs that needs updating
|
||||
foreach ($updateablelangs as $ulang) {
|
||||
if (!is_installed_lang($ulang, $md5array[$ulang])) {
|
||||
$neededlangs[] = $ulang;
|
||||
}
|
||||
}
|
||||
|
||||
make_temp_directory('');
|
||||
make_upload_directory('lang');
|
||||
|
||||
// clean-up currently installed versions of the packs
|
||||
foreach ($neededlangs as $packindex => $pack) {
|
||||
if ($pack == 'en') {
|
||||
continue;
|
||||
}
|
||||
|
||||
// delete old directories
|
||||
$dest1 = $CFG->dataroot.'/lang/'.$pack;
|
||||
$dest2 = $CFG->dirroot.'/lang/'.$pack;
|
||||
$rm1 = false;
|
||||
$rm2 = false;
|
||||
if (file_exists($dest1)) {
|
||||
if (!remove_dir($dest1)) {
|
||||
$notice_error[] = 'Could not delete old directory '.$dest1.', update of '.$pack.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (file_exists($dest2)) {
|
||||
if (!remove_dir($dest2)) {
|
||||
$notice_error[] = 'Could not delete old directory '.$dest2.', update of '.$pack.' failed, please check permissions.';
|
||||
unset($neededlangs[$packindex]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// install all needed language packs
|
||||
$installer->set_queue($neededlangs);
|
||||
$results = $installer->run();
|
||||
$updated = false; // any packs updated?
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
switch ($langstatus) {
|
||||
case lang_installer::RESULT_DOWNLOADERROR:
|
||||
$a = new stdClass();
|
||||
$a->url = $installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
print_error('remotedownloaderror', 'error', 'index.php', $a);
|
||||
break;
|
||||
case lang_installer::RESULT_INSTALLED:
|
||||
$updated = true;
|
||||
$notice_ok[] = get_string('langpackinstalled', 'tool_langimport', $langcode);
|
||||
break;
|
||||
case lang_installer::RESULT_UPTODATE:
|
||||
$notice_ok[] = get_string('langpackuptodate', 'tool_langimport', $langcode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($updated) {
|
||||
$notice_ok[] = get_string('langupdatecomplete', 'tool_langimport');
|
||||
} else {
|
||||
$notice_ok[] = get_string('nolangupdateneeded', 'tool_langimport');
|
||||
}
|
||||
|
||||
unset($installer);
|
||||
}
|
||||
get_string_manager()->reset_caches();
|
||||
|
||||
@@ -110,7 +239,9 @@ foreach ($installedlangs as $installedlang => $unused) {
|
||||
}
|
||||
}
|
||||
|
||||
if ($availablelangs = $controller->availablelangs) {
|
||||
$installer = new lang_installer();
|
||||
|
||||
if ($availablelangs = $installer->get_remote_list_of_languages()) {
|
||||
$remote = true;
|
||||
} else {
|
||||
$remote = false;
|
||||
@@ -120,18 +251,18 @@ if ($availablelangs = $controller->availablelangs) {
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
|
||||
if ($controller->info) {
|
||||
$info = implode('<br />', $controller->info);
|
||||
if ($notice_ok) {
|
||||
$info = implode('<br />', $notice_ok);
|
||||
echo $OUTPUT->notification($info, 'notifysuccess');
|
||||
}
|
||||
|
||||
if ($controller->errors) {
|
||||
$info = implode('<br />', $controller->errors);
|
||||
if ($notice_error) {
|
||||
$info = implode('<br />', $notice_error);
|
||||
echo $OUTPUT->notification($info, 'notifyproblem');
|
||||
}
|
||||
|
||||
if ($missingparents) {
|
||||
foreach ($missingparents as $l => $parent) {
|
||||
foreach ($missingparents as $l=>$parent) {
|
||||
$a = new stdClass();
|
||||
$a->lang = $installedlangs[$l];
|
||||
$a->parent = $parent;
|
||||
@@ -175,7 +306,7 @@ echo html_writer::end_tag('td');
|
||||
// list of available languages
|
||||
$options = array();
|
||||
foreach ($availablelangs as $alang) {
|
||||
if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !$controller->is_installed_lang($alang[0], $alang[1])) {
|
||||
if (!empty($alang[0]) and trim($alang[0]) !== 'en' and !is_installed_lang($alang[0], $alang[1])) {
|
||||
$options[$alang[0]] = $alang[2].' ('.$alang[0].')';
|
||||
}
|
||||
}
|
||||
@@ -200,3 +331,23 @@ echo html_writer::end_tag('table');
|
||||
echo $OUTPUT->box_end();
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Local functions /////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* checks the md5 of the zip file, grabbed from download.moodle.org,
|
||||
* against the md5 of the local language file from last update
|
||||
* @param string $lang
|
||||
* @param string $md5check
|
||||
* @return bool
|
||||
*/
|
||||
function is_installed_lang($lang, $md5check) {
|
||||
global $CFG;
|
||||
$md5file = $CFG->dataroot.'/lang/'.$lang.'/'.$lang.'.md5';
|
||||
if (file_exists($md5file)){
|
||||
return (file_get_contents($md5file) == $md5check);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -27,21 +27,17 @@ $string['install'] = 'Install selected language pack(s)';
|
||||
$string['installedlangs'] = 'Installed language packs';
|
||||
$string['langimport'] = 'Language import utility';
|
||||
$string['langimportdisabled'] = 'Language import feature has been disabled. You have to update your language packs manually at the file-system level. Do not forget to purge string caches after you do so.';
|
||||
$string['langpackinstalled'] = 'Language pack \'{$a}\' was successfully installed';
|
||||
$string['langpackinstalledevent'] = 'Language pack installed';
|
||||
$string['langpackremoved'] = 'Language pack \'{$a}\' was uninstalled';
|
||||
$string['langpackremovedevent'] = 'Language pack uninstalled';
|
||||
$string['langpackupdateskipped'] = 'Update of \'{$a}\' language pack skipped';
|
||||
$string['langpackuptodate'] = 'Language pack \'{$a}\' is up-to-date';
|
||||
$string['langpackupdated'] = 'Language pack \'{$a}\' was successfully updated';
|
||||
$string['langpackupdatedevent'] = 'Language pack updated';
|
||||
$string['langpackinstalled'] = 'Language pack {$a} was successfully installed';
|
||||
$string['langpackremoved'] = 'Language pack was uninstalled';
|
||||
$string['langpackupdateskipped'] = 'Update of {$a} language pack skipped';
|
||||
$string['langpackuptodate'] = 'Language pack {$a} is up-to-date';
|
||||
$string['langupdatecomplete'] = 'Language pack update completed';
|
||||
$string['missingcfglangotherroot'] = 'Missing configuration value $CFG->langotherroot';
|
||||
$string['missinglangparent'] = 'Missing parent language <em>{$a->parent}</em> of <em>{$a->lang}</em>.';
|
||||
$string['nolangupdateneeded'] = 'All your language packs are up to date, no update is needed';
|
||||
$string['pluginname'] = 'Language packs';
|
||||
$string['purgestringcaches'] = 'Purge string caches';
|
||||
$string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="https://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
|
||||
$string['remotelangnotavailable'] = 'Because Moodle cannot connect to download.moodle.org, it is not possible for language packs to be installed automatically. Please download the appropriate ZIP file(s) from <a href="http://download.moodle.org/langpack/">download.moodle.org/langpack</a>, copy them to your {$a} directory and unzip them manually.';
|
||||
$string['uninstall'] = 'Uninstall selected language pack';
|
||||
$string['uninstallconfirm'] = 'You are about to completely uninstall language pack {$a}, are you sure?';
|
||||
$string['updatelangs'] = 'Update all installed language packs';
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Behat steps definitions for Language import tool
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// NOTE: no MOODLE_INTERNAL test here, this file may be required by behat before including /config.php.
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
|
||||
use Moodle\BehatExtension\Exception\SkippedException;
|
||||
|
||||
/**
|
||||
* Steps definitions related with the Language import tool
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @category test
|
||||
* @copyright 2014 Dan Poltawski <dan@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_tool_langimport extends behat_base {
|
||||
|
||||
/**
|
||||
* This step looks to see if the remote language import tests should be run (indicated by
|
||||
* setting TOOL_LANGIMPORT_REMOTE_TESTS in config.php.
|
||||
*
|
||||
* @Given /^remote langimport tests are enabled$/
|
||||
*/
|
||||
public function remote_langimport_tests_are_enabled() {
|
||||
if (!defined('TOOL_LANGIMPORT_REMOTE_TESTS')) {
|
||||
throw new SkippedException('To run the remote langimport tests you must '.
|
||||
'define TOOL_LANGIMPORT_REMOTE_TESTS in config.php');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads a langpack and fakes it being outdated
|
||||
*
|
||||
* @param string $langcode The language code (e.g. en)
|
||||
* @Given /^outdated langpack \'([^\']*)\' is installed$/
|
||||
*/
|
||||
public function outdated_langpack_is_installed($langcode) {
|
||||
global $CFG;
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
// Download the langpack.
|
||||
$dir = make_upload_directory('lang');
|
||||
$installer = new lang_installer($langcode);
|
||||
$result = $installer->run();
|
||||
|
||||
if ($result[$langcode] !== lang_installer::RESULT_INSTALLED) {
|
||||
throw new coding_exception("Failed to install langpack '$langcode'");
|
||||
}
|
||||
|
||||
$path = "$dir/$langcode/$langcode.md5";
|
||||
|
||||
if (!file_exists($path)) {
|
||||
throw new coding_exception("Failed to find '$langcode' checksum");
|
||||
}
|
||||
file_put_contents($path, '000000');
|
||||
}
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
@tool @tool_langimport
|
||||
Feature: Manage language packs
|
||||
In order to support different languages
|
||||
As an administrator
|
||||
I need to be able to add, update and remove language packs
|
||||
|
||||
|
||||
Background:
|
||||
Given remote langimport tests are enabled
|
||||
|
||||
# The pirate language pack is used for testing because its small to download.
|
||||
|
||||
Scenario: Install language pack
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
When I set the field "Available language packs" to "English - Pirate (en_ar)"
|
||||
And I press "Install selected language pack(s)"
|
||||
Then I should see "Language pack 'en_ar' was successfully installed"
|
||||
And the "Installed language packs" select box should contain "English - Pirate (en_ar)"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should see "The language pack 'en_ar' was installed."
|
||||
And I log out
|
||||
|
||||
Scenario: Update language pack
|
||||
Given outdated langpack 'en_ar' is installed
|
||||
And I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
When I press "Update all installed language packs"
|
||||
Then I should see "Language pack 'en_ar' was successfully updated"
|
||||
And I should see "Language pack update completed"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should see "The language pack 'en_ar' was updated."
|
||||
And I log out
|
||||
|
||||
Scenario: Try to uninstall language pack
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
And I set the field "Available language packs" to "English - Pirate (en_ar)"
|
||||
And I press "Install selected language pack(s)"
|
||||
When I set the field "Installed language packs" to "English - Pirate (en_ar)"
|
||||
And I press "Uninstall selected language pack"
|
||||
And I press "Continue"
|
||||
Then I should see "Language pack 'en_ar' was uninstalled"
|
||||
And the "Installed language packs" select box should not contain "English - Pirate (en_ar)"
|
||||
And the "Available language packs" select box should contain "English - Pirate (en_ar)"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should see "The language pack 'en_ar' was removed."
|
||||
And I should see "Language pack uninstalled"
|
||||
And I log out
|
||||
|
||||
Scenario: Try to uninstall English language pack
|
||||
Given I log in as "admin"
|
||||
And I navigate to "Language packs" node in "Site administration > Language"
|
||||
When I set the field "Installed language packs" to "English (en)"
|
||||
And I press "Uninstall selected language pack"
|
||||
Then I should see "English language pack can not be uninstalled"
|
||||
And I navigate to "Live logs" node in "Site administration > Reports"
|
||||
And I should not see "Language pack uninstalled"
|
||||
And I log out
|
||||
@@ -1,102 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Tests for langimport events.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Test class for langimport events.
|
||||
*
|
||||
* @package tool_langimport
|
||||
* @copyright 2014 Dan Poltawski
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
|
||||
*/
|
||||
class tool_langimport_events_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Setup testcase.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->setAdminUser();
|
||||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
public function test_langpack_updated() {
|
||||
global $CFG;
|
||||
|
||||
$event = \tool_langimport\event\langpack_updated::event_with_langcode($CFG->lang);
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\tool_langimport\event\langpack_updated', $event);
|
||||
$this->assertEquals(context_system::instance(), $event->get_context());
|
||||
}
|
||||
|
||||
public function test_langpack_updated_validation() {
|
||||
$this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
|
||||
|
||||
\tool_langimport\event\langpack_updated::event_with_langcode('broken langcode');
|
||||
}
|
||||
|
||||
public function test_langpack_installed() {
|
||||
$event = \tool_langimport\event\langpack_imported::event_with_langcode('fr');
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\tool_langimport\event\langpack_imported', $event);
|
||||
$this->assertEquals(context_system::instance(), $event->get_context());
|
||||
}
|
||||
|
||||
public function test_langpack_installed_validation() {
|
||||
$this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
|
||||
|
||||
\tool_langimport\event\langpack_imported::event_with_langcode('broken langcode');
|
||||
}
|
||||
|
||||
public function test_langpack_removed() {
|
||||
$event = \tool_langimport\event\langpack_removed::event_with_langcode('fr');
|
||||
|
||||
// Trigger and capture the event.
|
||||
$sink = $this->redirectEvents();
|
||||
$event->trigger();
|
||||
$events = $sink->get_events();
|
||||
$event = reset($events);
|
||||
|
||||
$this->assertInstanceOf('\tool_langimport\event\langpack_removed', $event);
|
||||
$this->assertEquals(context_system::instance(), $event->get_context());
|
||||
}
|
||||
|
||||
public function test_langpack_removed_validation() {
|
||||
$this->setExpectedException('coding_exception', 'The \'langcode\' value must be set to a valid language code');
|
||||
|
||||
\tool_langimport\event\langpack_removed::event_with_langcode('broken langcode');
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX)
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version
|
||||
$plugin->component = 'tool_langimport'; // Full name of the plugin (used for diagnostics)
|
||||
|
||||
@@ -213,14 +213,11 @@ class manager implements \core\log\manager {
|
||||
* @param string $info Additional description information
|
||||
* @param int $cm The course_module->id if there is one
|
||||
* @param int|\stdClass $user If log regards $user other than $USER
|
||||
* @param string $ip Override the IP, should only be used for restore.
|
||||
* @param int $time Override the log time, should only be used for restore.
|
||||
*/
|
||||
public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '',
|
||||
$cm = 0, $user = 0, $ip = null, $time = null) {
|
||||
public function legacy_add_to_log($courseid, $module, $action, $url = '', $info = '', $cm = 0, $user = 0) {
|
||||
$this->init();
|
||||
if (isset($this->stores['logstore_legacy'])) {
|
||||
$this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip, $time);
|
||||
$this->stores['logstore_legacy']->legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,8 +46,5 @@ function xmldb_tool_log_upgrade($oldversion) {
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -36,8 +36,5 @@ function xmldb_logstore_database_upgrade($oldversion) {
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'logstore_database'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -143,10 +143,8 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
|
||||
* @param string $info Additional description information
|
||||
* @param int $cm The course_module->id if there is one
|
||||
* @param int|\stdClass $user If log regards $user other than $USER
|
||||
* @param string $ip Override the IP, should only be used for restore.
|
||||
* @param int $time Override the log time, should only be used for restore.
|
||||
*/
|
||||
public function legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user, $ip = null, $time = null) {
|
||||
public function legacy_add_to_log($courseid, $module, $action, $url, $info, $cm, $user) {
|
||||
// Note that this function intentionally does not follow the normal Moodle DB access idioms.
|
||||
// This is for a good reason: it is the most frequently used DB update function,
|
||||
// so it has been optimised for speed.
|
||||
@@ -174,9 +172,9 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
|
||||
}
|
||||
}
|
||||
|
||||
$remoteaddr = (is_null($ip)) ? getremoteaddr() : $ip;
|
||||
$remoteaddr = getremoteaddr();
|
||||
|
||||
$timenow = (is_null($time)) ? time() : $time;
|
||||
$timenow = time();
|
||||
if (!empty($url)) { // Could break doing html_entity_decode on an empty var.
|
||||
$url = html_entity_decode($url, ENT_QUOTES, 'UTF-8');
|
||||
} else {
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'logstore_legacy'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -114,8 +114,5 @@ function xmldb_logstore_standard_upgrade($oldversion) {
|
||||
// Moodle v2.7.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
// Moodle v2.8.0 release upgrade line.
|
||||
// Put any upgrade step following this.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'logstore_standard'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -24,6 +24,6 @@
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$plugin->version = 2014111000; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014110400; // Requires this Moodle version.
|
||||
$plugin->version = 2014051200; // The current plugin version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2014050800; // Requires this Moodle version.
|
||||
$plugin->component = 'tool_log'; // Full name of the plugin (used for diagnostics).
|
||||
|
||||
@@ -1,139 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Form to edit handlers.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
|
||||
/**
|
||||
* Form to edit handlers.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_messageinbound_edit_handler_form extends moodleform {
|
||||
public function definition() {
|
||||
$mform = $this->_form;
|
||||
|
||||
$handler = $this->_customdata['handler'];
|
||||
|
||||
// Set up the options for formatting text for descriptions, etc.
|
||||
$formatoptions = new stdClass();
|
||||
$formatoptions->trusted = false;
|
||||
$formatoptions->noclean = false;
|
||||
$formatoptions->smiley = false;
|
||||
$formatoptions->filter = false;
|
||||
$formatoptions->para = true;
|
||||
$formatoptions->newlines = false;
|
||||
$formatoptions->overflowdiv = true;
|
||||
|
||||
// General information about the handler.
|
||||
$mform->addElement('header', 'general', get_string('general'));
|
||||
$mform->addElement('static', 'name', get_string('name', 'tool_messageinbound'),
|
||||
$handler->name);
|
||||
$mform->addElement('static', 'classname', get_string('classname', 'tool_messageinbound'));
|
||||
|
||||
$description = format_text($handler->description, FORMAT_MARKDOWN, $formatoptions);
|
||||
|
||||
$mform->addElement('static', 'description', get_string('description', 'tool_messageinbound'),
|
||||
$description);
|
||||
|
||||
// Items which can be configured.
|
||||
$mform->addElement('header', 'configuration', get_string('configuration'));
|
||||
|
||||
if ($handler->can_change_defaultexpiration()) {
|
||||
// Show option to change expiry only if the handler supports it.
|
||||
$options = array(
|
||||
HOURSECS => get_string('onehour', 'tool_messageinbound'),
|
||||
DAYSECS => get_string('oneday', 'tool_messageinbound'),
|
||||
WEEKSECS => get_string('oneweek', 'tool_messageinbound'),
|
||||
YEARSECS => get_string('oneyear', 'tool_messageinbound'),
|
||||
0 => get_string('noexpiry', 'tool_messageinbound'),
|
||||
);
|
||||
$mform->addElement('select', 'defaultexpiration', get_string('defaultexpiration', 'tool_messageinbound'), $options);
|
||||
$mform->addHelpButton('defaultexpiration', 'defaultexpiration', 'tool_messageinbound');
|
||||
} else {
|
||||
$text = $this->get_defaultexpiration_text($handler);
|
||||
$mform->addElement('static', 'defaultexpiration_fake', get_string('defaultexpiration', 'tool_messageinbound'), $text);
|
||||
$mform->addElement('hidden', 'defaultexpiration');
|
||||
$mform->addHelpButton('defaultexpiration_fake', 'defaultexpiration', 'tool_messageinbound');
|
||||
$mform->setType('defaultexpiration', PARAM_INT);
|
||||
}
|
||||
|
||||
if ($handler->can_change_validateaddress()) {
|
||||
$mform->addElement('checkbox', 'validateaddress', get_string('requirevalidation', 'tool_messageinbound'));
|
||||
$mform->addHelpButton('validateaddress', 'validateaddress', 'tool_messageinbound');
|
||||
} else {
|
||||
if ($handler->validateaddress) {
|
||||
$text = get_string('yes');
|
||||
} else {
|
||||
$text = get_string('no');
|
||||
}
|
||||
$mform->addElement('static', 'validateaddress_fake', get_string('requirevalidation', 'tool_messageinbound'), $text);
|
||||
$mform->addElement('hidden', 'validateaddress');
|
||||
$mform->addHelpButton('validateaddress_fake', 'fixedvalidateaddress', 'tool_messageinbound');
|
||||
$mform->setType('validateaddress', PARAM_INT);
|
||||
}
|
||||
|
||||
if ($handler->can_change_enabled()) {
|
||||
$mform->addElement('checkbox', 'enabled', get_string('enabled', 'tool_messageinbound'));
|
||||
} else {
|
||||
if ($handler->enabled) {
|
||||
$text = get_string('yes');
|
||||
} else {
|
||||
$text = get_string('no');
|
||||
}
|
||||
$mform->addElement('static', 'enabled_fake', get_string('enabled', 'tool_messageinbound'), $text);
|
||||
$mform->addHelpButton('enabled', 'fixedenabled', 'tool_messageinbound');
|
||||
$mform->addElement('hidden', 'enabled');
|
||||
$mform->setType('enabled', PARAM_INT);
|
||||
}
|
||||
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a text string representing the selected default expiration for the handler.
|
||||
*
|
||||
* @param \core\message\inbound\handler $handler handler instance.
|
||||
*
|
||||
* @return string localised text string.
|
||||
*/
|
||||
protected function get_defaultexpiration_text(\core\message\inbound\handler $handler) {
|
||||
switch($handler->defaultexpiration) {
|
||||
case HOURSECS :
|
||||
return get_string('onehour', 'tool_messageinbound');
|
||||
case DAYSECS :
|
||||
return get_string('oneday', 'tool_messageinbound');
|
||||
case WEEKSECS :
|
||||
return get_string('oneweek', 'tool_messageinbound');
|
||||
case YEARSECS :
|
||||
return get_string('oneyear', 'tool_messageinbound');
|
||||
case 0:
|
||||
return get_string('noexpiry', 'tool_messageinbound');
|
||||
default:
|
||||
return ''; // Should never happen.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,998 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The Mail Pickup Manager.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Mail Pickup Manager.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class manager {
|
||||
|
||||
/**
|
||||
* @var string The main mailbox to check.
|
||||
*/
|
||||
const MAILBOX = 'INBOX';
|
||||
|
||||
/**
|
||||
* @var string The mailbox to store messages in when they are awaiting confirmation.
|
||||
*/
|
||||
const CONFIRMATIONFOLDER = 'tobeconfirmed';
|
||||
|
||||
/**
|
||||
* @var string The flag for seen/read messages.
|
||||
*/
|
||||
const MESSAGE_SEEN = '\seen';
|
||||
|
||||
/**
|
||||
* @var string The flag for flagged messages.
|
||||
*/
|
||||
const MESSAGE_FLAGGED = '\flagged';
|
||||
|
||||
/**
|
||||
* @var string The flag for deleted messages.
|
||||
*/
|
||||
const MESSAGE_DELETED = '\deleted';
|
||||
|
||||
/**
|
||||
* @var Horde_Imap_Client_Socket A reference to the IMAP client.
|
||||
*/
|
||||
protected $client = null;
|
||||
|
||||
/**
|
||||
* @var \core\message\inbound\address_manager A reference to the Inbound Message Address Manager instance.
|
||||
*/
|
||||
protected $addressmanager = null;
|
||||
|
||||
/**
|
||||
* @var stdClass The data for the current message being processed.
|
||||
*/
|
||||
protected $currentmessagedata = null;
|
||||
|
||||
/**
|
||||
* Retrieve the connection to the IMAP client.
|
||||
*
|
||||
* @return bool Whether a connection was successfully established.
|
||||
*/
|
||||
protected function get_imap_client() {
|
||||
global $CFG;
|
||||
|
||||
if (!\core\message\inbound\manager::is_enabled()) {
|
||||
// E-mail processing not set up.
|
||||
mtrace("Inbound Message not fully configured - exiting early.");
|
||||
return false;
|
||||
}
|
||||
|
||||
mtrace("Connecting to {$CFG->messageinbound_host} as {$CFG->messageinbound_hostuser}...");
|
||||
|
||||
$configuration = array(
|
||||
'username' => $CFG->messageinbound_hostuser,
|
||||
'password' => $CFG->messageinbound_hostpass,
|
||||
'hostspec' => $CFG->messageinbound_host,
|
||||
'secure' => $CFG->messageinbound_hostssl,
|
||||
);
|
||||
|
||||
$this->client = new \Horde_Imap_Client_Socket($configuration);
|
||||
|
||||
try {
|
||||
$this->client->login();
|
||||
mtrace("Connection established.");
|
||||
return true;
|
||||
|
||||
} catch (\Horde_Imap_Client_Exception $e) {
|
||||
$message = $e->getMessage();
|
||||
mtrace("Unable to connect to IMAP server. Failed with '{$message}'");
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Shutdown and close the connection to the IMAP client.
|
||||
*/
|
||||
protected function close_connection() {
|
||||
if ($this->client) {
|
||||
$this->client->close();
|
||||
}
|
||||
$this->client = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current mailbox information.
|
||||
*
|
||||
* @return \Horde_Imap_Client_Mailbox
|
||||
*/
|
||||
protected function get_mailbox() {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->client->currentMailbox();
|
||||
|
||||
if (isset($mailbox['mailbox'])) {
|
||||
return $mailbox['mailbox'];
|
||||
} else {
|
||||
throw new \core\message\inbound\processing_failed_exception('couldnotopenmailbox', 'tool_messageinbound');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the main Inbound Message pickup task.
|
||||
*/
|
||||
public function pickup_messages() {
|
||||
if (!$this->get_imap_client()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Restrict results to messages which are unseen, and have not been flagged.
|
||||
$search = new \Horde_Imap_Client_Search_Query();
|
||||
$search->flag(self::MESSAGE_SEEN, false);
|
||||
$search->flag(self::MESSAGE_FLAGGED, false);
|
||||
mtrace("Searching for Unseen, Unflagged email in the folder '" . self::MAILBOX . "'");
|
||||
$results = $this->client->search(self::MAILBOX, $search);
|
||||
|
||||
// We require the envelope data and structure of each message.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->envelope();
|
||||
$query->structure();
|
||||
|
||||
// Retrieve the message id.
|
||||
$messages = $this->client->fetch(self::MAILBOX, $query, array('ids' => $results['match']));
|
||||
|
||||
mtrace("Found " . $messages->count() . " messages to parse. Parsing...");
|
||||
$this->addressmanager = new \core\message\inbound\address_manager();
|
||||
foreach ($messages as $message) {
|
||||
$this->process_message($message);
|
||||
}
|
||||
|
||||
// Close the client connection.
|
||||
$this->close_connection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message received and validated by the Inbound Message processor.
|
||||
*
|
||||
* @param stdClass $maildata The data retrieved from the database for the current record.
|
||||
* @return bool Whether the message was successfully processed.
|
||||
*/
|
||||
public function process_existing_message(\stdClass $maildata) {
|
||||
// Grab the new IMAP client.
|
||||
if (!$this->get_imap_client()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build the search.
|
||||
$search = new \Horde_Imap_Client_Search_Query();
|
||||
// When dealing with Inbound Message messages, we mark them as flagged and seen. Restrict the search to those criterion.
|
||||
$search->flag(self::MESSAGE_SEEN, true);
|
||||
$search->flag(self::MESSAGE_FLAGGED, true);
|
||||
mtrace("Searching for a Seen, Flagged message in the folder '" . self::CONFIRMATIONFOLDER . "'");
|
||||
|
||||
// Match the message ID.
|
||||
$search->headerText('message-id', $maildata->messageid);
|
||||
$search->headerText('to', $maildata->address);
|
||||
|
||||
$results = $this->client->search(self::CONFIRMATIONFOLDER, $search);
|
||||
|
||||
// Build the base query.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->envelope();
|
||||
$query->structure();
|
||||
|
||||
|
||||
// Fetch the first message from the client.
|
||||
$messages = $this->client->fetch(self::CONFIRMATIONFOLDER, $query, array('ids' => $results['match']));
|
||||
$this->addressmanager = new \core\message\inbound\address_manager();
|
||||
if ($message = $messages->first()) {
|
||||
mtrace("--> Found the message. Passing back to the pickup system.");
|
||||
|
||||
// Process the message.
|
||||
$this->process_message($message, true, true);
|
||||
|
||||
// Close the client connection.
|
||||
$this->close_connection();
|
||||
|
||||
mtrace("============================================================================");
|
||||
return true;
|
||||
} else {
|
||||
// Close the client connection.
|
||||
$this->close_connection();
|
||||
|
||||
mtrace("============================================================================");
|
||||
throw new \core\message\inbound\processing_failed_exception('oldmessagenotfound', 'tool_messageinbound');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tidy up old messages in the confirmation folder.
|
||||
*
|
||||
* @return bool Whether tidying occurred successfully.
|
||||
*/
|
||||
public function tidy_old_messages() {
|
||||
// Grab the new IMAP client.
|
||||
if (!$this->get_imap_client()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Open the mailbox.
|
||||
mtrace("Searching for messages older than 24 hours in the '" .
|
||||
self::CONFIRMATIONFOLDER . "' folder.");
|
||||
$this->client->openMailbox(self::CONFIRMATIONFOLDER);
|
||||
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Build the search.
|
||||
$search = new \Horde_Imap_Client_Search_Query();
|
||||
|
||||
// Delete messages older than 24 hours old.
|
||||
$search->intervalSearch(DAYSECS, \Horde_Imap_Client_Search_Query::INTERVAL_OLDER);
|
||||
|
||||
$results = $this->client->search($mailbox, $search);
|
||||
|
||||
// Build the base query.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->envelope();
|
||||
|
||||
// Retrieve the messages and mark them for removal.
|
||||
$messages = $this->client->fetch($mailbox, $query, array('ids' => $results['match']));
|
||||
mtrace("Found " . $messages->count() . " messages for removal.");
|
||||
foreach ($messages as $message) {
|
||||
$this->add_flag_to_message($message->getUid(), self::MESSAGE_DELETED);
|
||||
}
|
||||
|
||||
mtrace("Finished removing messages.");
|
||||
$this->close_connection();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message and pass it through the Inbound Message handling systems.
|
||||
*
|
||||
* @param Horde_Imap_Client_Data_Fetch $message The message to process
|
||||
* @param bool $viewreadmessages Whether to also look at messages which have been marked as read
|
||||
* @param bool $skipsenderverification Whether to skip the sender verificiation stage
|
||||
*/
|
||||
public function process_message(
|
||||
\Horde_Imap_Client_Data_Fetch $message,
|
||||
$viewreadmessages = false,
|
||||
$skipsenderverification = false) {
|
||||
global $USER;
|
||||
|
||||
// We use the Client IDs several times - store them here.
|
||||
$messageid = new \Horde_Imap_Client_Ids($message->getUid());
|
||||
|
||||
mtrace("- Parsing message " . $messageid);
|
||||
|
||||
// First flag this message to prevent another running hitting this message while we look at the headers.
|
||||
$this->add_flag_to_message($messageid, self::MESSAGE_FLAGGED);
|
||||
|
||||
if ($this->is_bulk_message($message, $messageid)) {
|
||||
mtrace("- The message has a bulk header set. This is likely an auto-generated reply - discarding.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Record the user that this script is currently being run as. This is important when re-processing existing
|
||||
// messages, as cron_setup_user is called multiple times.
|
||||
$originaluser = $USER;
|
||||
|
||||
$envelope = $message->getEnvelope();
|
||||
$recipients = $envelope->to->bare_addresses;
|
||||
foreach ($recipients as $recipient) {
|
||||
if (!\core\message\inbound\address_manager::is_correct_format($recipient)) {
|
||||
// Message did not contain a subaddress.
|
||||
mtrace("- Recipient '{$recipient}' did not match Inbound Message headers.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Message contained a match.
|
||||
$senders = $message->getEnvelope()->from->bare_addresses;
|
||||
if (count($senders) !== 1) {
|
||||
mtrace("- Received multiple senders. Only the first sender will be used.");
|
||||
}
|
||||
$sender = array_shift($senders);
|
||||
|
||||
mtrace("-- Subject:\t" . $envelope->subject);
|
||||
mtrace("-- From:\t" . $sender);
|
||||
mtrace("-- Recipient:\t" . $recipient);
|
||||
|
||||
// Grab messagedata including flags.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->structure();
|
||||
$messagedata = $this->client->fetch($this->get_mailbox(), $query, array(
|
||||
'ids' => $messageid,
|
||||
))->first();
|
||||
|
||||
if (!$viewreadmessages && $this->message_has_flag($messageid, self::MESSAGE_SEEN)) {
|
||||
// Something else has already seen this message. Skip it now.
|
||||
mtrace("-- Skipping the message - it has been marked as seen - perhaps by another process.");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Mark it as read to lock the message.
|
||||
$this->add_flag_to_message($messageid, self::MESSAGE_SEEN);
|
||||
|
||||
// Now pass it through the Inbound Message processor.
|
||||
$status = $this->addressmanager->process_envelope($recipient, $sender);
|
||||
|
||||
if (($status & ~ \core\message\inbound\address_manager::VALIDATION_DISABLED_HANDLER) !== $status) {
|
||||
// The handler is disabled.
|
||||
mtrace("-- Skipped message - Handler is disabled. Fail code {$status}");
|
||||
// In order to handle the user error, we need more information about the message being failed.
|
||||
$this->process_message_data($envelope, $messagedata, $messageid);
|
||||
$this->inform_user_of_error(get_string('handlerdisabled', 'tool_messageinbound', $this->currentmessagedata));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the validation status early. No point processing garbage messages, but we do need to process it
|
||||
// for some validation failure types.
|
||||
if (!$this->passes_key_validation($status, $messageid)) {
|
||||
// None of the above validation failures were found. Skip this message.
|
||||
mtrace("-- Skipped message - it does not appear to relate to a Inbound Message pickup. Fail code {$status}");
|
||||
|
||||
// Remove the seen flag from the message as there may be multiple recipients.
|
||||
$this->remove_flag_from_message($messageid, self::MESSAGE_SEEN);
|
||||
|
||||
// Skip further processing for this recipient.
|
||||
continue;
|
||||
}
|
||||
|
||||
// Process the message as the user.
|
||||
$user = $this->addressmanager->get_data()->user;
|
||||
mtrace("-- Processing the message as user {$user->id} ({$user->username}).");
|
||||
cron_setup_user($user);
|
||||
|
||||
// Process and retrieve the message data for this message.
|
||||
// This includes fetching the full content, as well as all headers, and attachments.
|
||||
if (!$this->process_message_data($envelope, $messagedata, $messageid)) {
|
||||
mtrace("--- Message could not be found on the server. Is another process removing messages?");
|
||||
return;
|
||||
}
|
||||
|
||||
// When processing validation replies, we need to skip the sender verification phase as this has been
|
||||
// manually completed.
|
||||
if (!$skipsenderverification && $status !== 0) {
|
||||
// Check the validation status for failure types which require confirmation.
|
||||
// The validation result is tested in a bitwise operation.
|
||||
mtrace("-- Message did not meet validation but is possibly recoverable. Fail code {$status}");
|
||||
// This is a recoverable error, but requires user input.
|
||||
|
||||
if ($this->handle_verification_failure($messageid, $recipient)) {
|
||||
mtrace("--- Original message retained on mail server and confirmation message sent to user.");
|
||||
} else {
|
||||
mtrace("--- Invalid Recipient Handler - unable to save. Informing the user of the failure.");
|
||||
$this->inform_user_of_error(get_string('invalidrecipientfinal', 'tool_messageinbound', $this->currentmessagedata));
|
||||
}
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the content and attachment data.
|
||||
mtrace("-- Validation completed. Fetching rest of message content.");
|
||||
$this->process_message_data_body($messagedata, $messageid);
|
||||
|
||||
// The message processor throws exceptions upon failure. These must be caught and notifications sent to
|
||||
// the user here.
|
||||
try {
|
||||
$result = $this->send_to_handler();
|
||||
} catch (\core\message\inbound\processing_failed_exception $e) {
|
||||
// We know about these kinds of errors and they should result in the user being notified of the
|
||||
// failure. Send the user a notification here.
|
||||
$this->inform_user_of_error($e->getMessage());
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
return;
|
||||
} catch (\Exception $e) {
|
||||
// An unknown error occurred. The user is not informed, but the administrator is.
|
||||
mtrace("-- Message processing failed. An unexpected exception was thrown. Details follow.");
|
||||
mtrace($e->getMessage());
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
return;
|
||||
}
|
||||
|
||||
if ($result) {
|
||||
// Handle message cleanup. Messages are deleted once fully processed.
|
||||
mtrace("-- Marking the message for removal.");
|
||||
$this->add_flag_to_message($messageid, self::MESSAGE_DELETED);
|
||||
} else {
|
||||
mtrace("-- The Inbound Message processor did not return a success status. Skipping message removal.");
|
||||
}
|
||||
|
||||
// Returning to normal cron user.
|
||||
mtrace("-- Returning to the original user.");
|
||||
cron_setup_user($originaluser);
|
||||
|
||||
mtrace("-- Finished processing " . $message->getUid());
|
||||
|
||||
// Skip the outer loop too. The message has already been processed and it could be possible for there to
|
||||
// be two recipients in the envelope which match somehow.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message to retrieve it's header data without body and attachemnts.
|
||||
*
|
||||
* @param Horde_Imap_Client_Data_Envelope $envelope The Envelope of the message
|
||||
* @param Horde_Imap_Client_Data_Fetch $messagedata The structure and part of the message body
|
||||
* @param string|Horde_Imap_Client_Ids $messageid The Hore message Uid
|
||||
* @return \stdClass The current value of the messagedata
|
||||
*/
|
||||
private function process_message_data(
|
||||
\Horde_Imap_Client_Data_Envelope $envelope,
|
||||
\Horde_Imap_Client_Data_Fetch $basemessagedata,
|
||||
$messageid) {
|
||||
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// We need the structure at various points below.
|
||||
$structure = $basemessagedata->getStructure();
|
||||
|
||||
// Now fetch the rest of the message content.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->imapDate();
|
||||
|
||||
// Fetch the message header.
|
||||
$query->headerText();
|
||||
|
||||
// Retrieve the message with the above components.
|
||||
$messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first();
|
||||
|
||||
if (!$messagedata) {
|
||||
// Message was not found! Somehow it has been removed or is no longer returned.
|
||||
return null;
|
||||
}
|
||||
|
||||
// The message ID should always be in the first part.
|
||||
$data = new \stdClass();
|
||||
$data->messageid = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Message-ID');
|
||||
$data->subject = $envelope->subject;
|
||||
$data->timestamp = $messagedata->getImapDate()->__toString();
|
||||
$data->envelope = $envelope;
|
||||
$data->data = $this->addressmanager->get_data();
|
||||
$data->headers = $messagedata->getHeaderText();
|
||||
|
||||
$this->currentmessagedata = $data;
|
||||
|
||||
return $this->currentmessagedata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message again to add body and attachment data.
|
||||
*
|
||||
* @param \Horde_Imap_Client_Data_Fetch $basemessagedata The structure and part of the message body
|
||||
* @param string|\Horde_Imap_Client_Ids $messageid The Hore message Uid
|
||||
* @return \stdClass The current value of the messagedata
|
||||
*/
|
||||
private function process_message_data_body(
|
||||
\Horde_Imap_Client_Data_Fetch $basemessagedata,
|
||||
$messageid) {
|
||||
global $CFG;
|
||||
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// We need the structure at various points below.
|
||||
$structure = $basemessagedata->getStructure();
|
||||
|
||||
// Now fetch the rest of the message content.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->fullText();
|
||||
|
||||
// Fetch all of the message parts too.
|
||||
$typemap = $structure->contentTypeMap();
|
||||
foreach ($typemap as $part => $type) {
|
||||
// The body of the part - attempt to decode it on the server.
|
||||
$query->bodyPart($part, array(
|
||||
'decode' => true,
|
||||
'peek' => true,
|
||||
));
|
||||
$query->bodyPartSize($part);
|
||||
}
|
||||
|
||||
$messagedata = $this->client->fetch($mailbox, $query, array('ids' => $messageid))->first();
|
||||
|
||||
// Store the data for this message.
|
||||
$contentplain = '';
|
||||
$contenthtml = '';
|
||||
$attachments = array(
|
||||
'inline' => array(),
|
||||
'attachment' => array(),
|
||||
);
|
||||
|
||||
$plainpartid = $structure->findBody('plain');
|
||||
$htmlpartid = $structure->findBody('html');
|
||||
|
||||
foreach ($typemap as $part => $type) {
|
||||
// Get the message data from the body part, and combine it with the structure to give a fully-formed output.
|
||||
$stream = $messagedata->getBodyPart($part, true);
|
||||
$partdata = $structure->getPart($part);
|
||||
$partdata->setContents($stream, array(
|
||||
'usestream' => true,
|
||||
));
|
||||
|
||||
if ($part === $plainpartid) {
|
||||
$contentplain = $this->process_message_part_body($messagedata, $partdata, $part);
|
||||
|
||||
} else if ($part === $htmlpartid) {
|
||||
$contenthtml = $this->process_message_part_body($messagedata, $partdata, $part);
|
||||
|
||||
} else if ($filename = $partdata->getName($part)) {
|
||||
if ($attachment = $this->process_message_part_attachment($messagedata, $partdata, $part, $filename)) {
|
||||
// The disposition should be one of 'attachment', 'inline'.
|
||||
// If an empty string is provided, default to 'attachment'.
|
||||
$disposition = $partdata->getDisposition();
|
||||
$disposition = $disposition == 'inline' ? 'inline' : 'attachment';
|
||||
$attachments[$disposition][] = $attachment;
|
||||
}
|
||||
}
|
||||
|
||||
// We don't handle any of the other MIME content at this stage.
|
||||
}
|
||||
|
||||
// The message ID should always be in the first part.
|
||||
$this->currentmessagedata->plain = $contentplain;
|
||||
$this->currentmessagedata->html = $contenthtml;
|
||||
$this->currentmessagedata->attachments = $attachments;
|
||||
|
||||
return $this->currentmessagedata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the messagedata and part data to extract the content of this part.
|
||||
*
|
||||
* @param $messagedata The structure and part of the message body
|
||||
* @param $partdata The part data
|
||||
* @param $part The part ID
|
||||
* @return string
|
||||
*/
|
||||
private function process_message_part_body($messagedata, $partdata, $part) {
|
||||
// This is a content section for the main body.
|
||||
|
||||
// Get the string version of it.
|
||||
$content = $messagedata->getBodyPart($part);
|
||||
if (!$messagedata->getBodyPartDecode($part)) {
|
||||
// Decode the content.
|
||||
$partdata->setContents($content);
|
||||
$content = $partdata->getContents();
|
||||
}
|
||||
|
||||
// Convert the text from the current encoding to UTF8.
|
||||
$content = \core_text::convert($content, $partdata->getCharset());
|
||||
|
||||
// Fix any invalid UTF8 characters.
|
||||
// Note: XSS cleaning is not the responsibility of this code. It occurs immediately before display when
|
||||
// format_text is called.
|
||||
$content = clean_param($content, PARAM_RAW);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message again to add body and attachment data.
|
||||
*
|
||||
* @param $messagedata The structure and part of the message body
|
||||
* @param $partdata The part data
|
||||
* @param $filename The filename of the attachment
|
||||
* @return \stdClass
|
||||
*/
|
||||
private function process_message_part_attachment($messagedata, $partdata, $part, $filename) {
|
||||
global $CFG;
|
||||
|
||||
// For Antivirus, the repository/lib.php must be included as it is not autoloaded.
|
||||
require_once($CFG->dirroot . '/repository/lib.php');
|
||||
|
||||
// If a filename is present, assume that this part is an attachment.
|
||||
$attachment = new \stdClass();
|
||||
$attachment->filename = $filename;
|
||||
$attachment->type = $partdata->getType();
|
||||
$attachment->content = $partdata->getContents();
|
||||
$attachment->charset = $partdata->getCharset();
|
||||
$attachment->description = $partdata->getDescription();
|
||||
$attachment->contentid = $partdata->getContentId();
|
||||
$attachment->filesize = $messagedata->getBodyPartSize($part);
|
||||
|
||||
if (empty($CFG->runclamonupload) or empty($CFG->pathtoclam)) {
|
||||
mtrace("--> Attempting virus scan of '{$attachment->filename}'");
|
||||
|
||||
// Store the file on disk - it will need to be virus scanned first.
|
||||
$itemid = rand(1, 999999999);;
|
||||
$directory = make_temp_directory("/messageinbound/{$itemid}", false);
|
||||
$filepath = $directory . "/" . $attachment->filename;
|
||||
if (!$fp = fopen($filepath, "w")) {
|
||||
// Unable to open the temporary file to write this to disk.
|
||||
mtrace("--> Unable to save the file to disk for virus scanning. Check file permissions.");
|
||||
|
||||
throw new \core\message\inbound\processing_failed_exception('attachmentfilepermissionsfailed',
|
||||
'tool_messageinbound');
|
||||
}
|
||||
|
||||
fwrite($fp, $attachment->content);
|
||||
fclose($fp);
|
||||
|
||||
// Perform a virus scan now.
|
||||
try {
|
||||
\repository::antivir_scan_file($filepath, $attachment->filename, true);
|
||||
} catch (\moodle_exception $e) {
|
||||
mtrace("--> A virus was found in the attachment '{$attachment->filename}'.");
|
||||
$this->inform_attachment_virus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return $attachment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the key provided is valid.
|
||||
*
|
||||
* @param $status The Message to process
|
||||
* @param $messageid The Hore message Uid
|
||||
* @return bool
|
||||
*/
|
||||
private function passes_key_validation($status, $messageid) {
|
||||
// The validation result is tested in a bitwise operation.
|
||||
if ((
|
||||
$status & ~ \core\message\inbound\address_manager::VALIDATION_SUCCESS
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_UNKNOWN_DATAKEY
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_EXPIRED_DATAKEY
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_INVALID_HASH
|
||||
& ~ \core\message\inbound\address_manager::VALIDATION_ADDRESS_MISMATCH) !== 0) {
|
||||
|
||||
// One of the above bits was found in the status - fail the validation.
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified flag to the message.
|
||||
*
|
||||
* @param $messageid
|
||||
* @param string $flag The flag to add
|
||||
*/
|
||||
private function add_flag_to_message($messageid, $flag) {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Mark it as read to lock the message.
|
||||
$this->client->store($mailbox, array(
|
||||
'ids' => new \Horde_Imap_Client_Ids($messageid),
|
||||
'add' => $flag,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified flag from the message.
|
||||
*
|
||||
* @param $messageid
|
||||
* @param string $flag The flag to remove
|
||||
*/
|
||||
private function remove_flag_from_message($messageid, $flag) {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Mark it as read to lock the message.
|
||||
$this->client->store($mailbox, array(
|
||||
'ids' => $messageid,
|
||||
'delete' => $flag,
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the message has the specified flag
|
||||
*
|
||||
* @param $messageid
|
||||
* @param string $flag The flag to check
|
||||
* @return bool
|
||||
*/
|
||||
private function message_has_flag($messageid, $flag) {
|
||||
// Get the current mailbox.
|
||||
$mailbox = $this->get_mailbox();
|
||||
|
||||
// Grab messagedata including flags.
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->flags();
|
||||
$query->structure();
|
||||
$messagedata = $this->client->fetch($mailbox, $query, array(
|
||||
'ids' => $messageid,
|
||||
))->first();
|
||||
$flags = $messagedata->getFlags();
|
||||
|
||||
return in_array($flag, $flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to determine whether this message is a bulk message (e.g. automated reply).
|
||||
*
|
||||
* @param \Horde_Imap_Client_Data_Fetch $message The message to process
|
||||
* @param string|\Horde_Imap_Client_Ids $messageid The Hore message Uid
|
||||
* @return boolean
|
||||
*/
|
||||
private function is_bulk_message(
|
||||
\Horde_Imap_Client_Data_Fetch $message,
|
||||
$messageid) {
|
||||
$query = new \Horde_Imap_Client_Fetch_Query();
|
||||
$query->headerText(array('peek' => true));
|
||||
|
||||
$messagedata = $this->client->fetch($this->get_mailbox(), $query, array('ids' => $messageid))->first();
|
||||
|
||||
// Assume that this message is not bulk to begin with.
|
||||
$isbulk = false;
|
||||
|
||||
// An auto-reply may itself include the Bulk Precedence.
|
||||
$precedence = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Precedence');
|
||||
$isbulk = $isbulk || strtolower($precedence) == 'bulk';
|
||||
|
||||
// If the X-Autoreply header is set, and not 'no', then this is an automatic reply.
|
||||
$autoreply = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('X-Autoreply');
|
||||
$isbulk = $isbulk || ($autoreply && $autoreply != 'no');
|
||||
|
||||
// If the X-Autorespond header is set, and not 'no', then this is an automatic response.
|
||||
$autorespond = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('X-Autorespond');
|
||||
$isbulk = $isbulk || ($autorespond && $autorespond != 'no');
|
||||
|
||||
// If the Auto-Submitted header is set, and not 'no', then this is a non-human response.
|
||||
$autosubmitted = $messagedata->getHeaderText(0, \Horde_Imap_Client_Data_Fetch::HEADER_PARSE)->getValue('Auto-Submitted');
|
||||
$isbulk = $isbulk || ($autosubmitted && $autosubmitted != 'no');
|
||||
|
||||
return $isbulk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message to the appropriate handler.
|
||||
*
|
||||
*/
|
||||
private function send_to_handler() {
|
||||
try {
|
||||
mtrace("--> Passing to Inbound Message handler {$this->addressmanager->get_handler()->classname}");
|
||||
if ($result = $this->addressmanager->handle_message($this->currentmessagedata)) {
|
||||
$this->inform_user_of_success($this->currentmessagedata, $result);
|
||||
// Request that this message be marked for deletion.
|
||||
return true;
|
||||
}
|
||||
|
||||
} catch (\core\message\inbound\processing_failed_exception $e) {
|
||||
mtrace("-> The Inbound Message handler threw an exception. Unable to process this message. The user has been informed.");
|
||||
mtrace("--> " . $e->getMessage());
|
||||
// Throw the exception again, with additional data.
|
||||
$error = new \stdClass();
|
||||
$error->subject = $this->currentmessagedata->envelope->subject;
|
||||
$error->message = $e->getMessage();
|
||||
throw new \core\message\inbound\processing_failed_exception('messageprocessingfailed', 'tool_messageinbound', $error);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
mtrace("-> The Inbound Message handler threw an exception. Unable to process this message. User informed.");
|
||||
mtrace("--> " . $e->getMessage());
|
||||
// An unknown error occurred. Still inform the user but, this time do not include the specific
|
||||
// message information.
|
||||
$error = new \stdClass();
|
||||
$error->subject = $this->currentmessagedata->envelope->subject;
|
||||
throw new \core\message\inbound\processing_failed_exception('messageprocessingfailedunknown',
|
||||
'tool_messageinbound', $error);
|
||||
|
||||
}
|
||||
|
||||
// Something went wrong and the message was not handled well in the Inbound Message handler.
|
||||
mtrace("-> The Inbound Message handler reported an error. The message may not have been processed.");
|
||||
|
||||
// It is the responsiblity of the handler to throw an appropriate exception if the message was not processed.
|
||||
// Do not inform the user at this point.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle failure of sender verification.
|
||||
*
|
||||
* This will send a notification to the user identified in the Inbound Message address informing them that a message has been
|
||||
* stored. The message includes a verification link and reply-to address which is handled by the
|
||||
* invalid_recipient_handler.
|
||||
*
|
||||
* @param $recipient The message recipient
|
||||
*/
|
||||
private function handle_verification_failure(
|
||||
\Horde_Imap_Client_Ids $messageids,
|
||||
$recipient) {
|
||||
global $DB, $USER;
|
||||
|
||||
if (!$messageid = $this->currentmessagedata->messageid) {
|
||||
mtrace("---> Warning: Unable to determine the Message-ID of the message.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Move the message into a new mailbox.
|
||||
$this->client->copy(self::MAILBOX, self::CONFIRMATIONFOLDER, array(
|
||||
'create' => true,
|
||||
'ids' => $messageids,
|
||||
'move' => true,
|
||||
));
|
||||
|
||||
// Store the data from the failed message in the associated table.
|
||||
$record = new \stdClass();
|
||||
$record->messageid = $messageid;
|
||||
$record->userid = $USER->id;
|
||||
$record->address = $recipient;
|
||||
$record->timecreated = time();
|
||||
$record->id = $DB->insert_record('messageinbound_messagelist', $record);
|
||||
|
||||
// Setup the Inbound Message generator for the invalid recipient handler.
|
||||
$addressmanager = new \core\message\inbound\address_manager();
|
||||
$addressmanager->set_handler('\tool_messageinbound\message\inbound\invalid_recipient_handler');
|
||||
$addressmanager->set_data($record->id);
|
||||
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->component = 'tool_messageinbound';
|
||||
$eventdata->name = 'invalidrecipienthandler';
|
||||
|
||||
$userfrom = clone $USER;
|
||||
$userfrom->customheaders = array();
|
||||
// Adding the In-Reply-To header ensures that it is seen as a reply.
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$eventdata->userfrom = \core_user::get_noreply_user();
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = $this->get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = get_string('invalidrecipientdescription', 'tool_messageinbound', $this->currentmessagedata);
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = get_string('invalidrecipientdescriptionhtml', 'tool_messageinbound', $this->currentmessagedata);
|
||||
$eventdata->smallmessage = $eventdata->fullmessage;
|
||||
$eventdata->notification = 1;
|
||||
$eventdata->replyto = $addressmanager->generate($USER->id);
|
||||
|
||||
mtrace("--> Sending a message to the user to report an verification failure.");
|
||||
if (!message_send($eventdata)) {
|
||||
mtrace("---> Warning: Message could not be sent.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the identified sender of a processing error.
|
||||
*
|
||||
* @param string $error The error message
|
||||
*/
|
||||
private function inform_user_of_error($error) {
|
||||
global $USER;
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$userfrom = clone $USER;
|
||||
$userfrom->customheaders = array();
|
||||
|
||||
if ($messageid = $this->currentmessagedata->messageid) {
|
||||
// Adding the In-Reply-To header ensures that it is seen as a reply and threading is maintained.
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
}
|
||||
|
||||
$messagedata = new \stdClass();
|
||||
$messagedata->subject = $this->currentmessagedata->envelope->subject;
|
||||
$messagedata->error = $error;
|
||||
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->component = 'tool_messageinbound';
|
||||
$eventdata->name = 'messageprocessingerror';
|
||||
$eventdata->userfrom = $userfrom;
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = self::get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = get_string('messageprocessingerror', 'tool_messageinbound', $messagedata);
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = get_string('messageprocessingerrorhtml', 'tool_messageinbound', $messagedata);
|
||||
$eventdata->smallmessage = $eventdata->fullmessage;
|
||||
$eventdata->notification = 1;
|
||||
|
||||
if (message_send($eventdata)) {
|
||||
mtrace("---> Notification sent to {$USER->email}.");
|
||||
} else {
|
||||
mtrace("---> Unable to send notification.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inform the identified sender that message processing was successful.
|
||||
*
|
||||
* @param stdClass $messagedata The data for the current message being processed.
|
||||
* @param mixed $handlerresult The result returned by the handler.
|
||||
*/
|
||||
private function inform_user_of_success(\stdClass $messagedata, $handlerresult) {
|
||||
global $USER;
|
||||
|
||||
// Check whether the handler has a success notification.
|
||||
$handler = $this->addressmanager->get_handler();
|
||||
$message = $handler->get_success_message($messagedata, $handlerresult);
|
||||
|
||||
if (!$message) {
|
||||
mtrace("---> Handler has not defined a success notification e-mail.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wrap the message in the notification wrapper.
|
||||
$messageparams = new \stdClass();
|
||||
$messageparams->html = $message->html;
|
||||
$messageparams->plain = $message->plain;
|
||||
$messagepreferencesurl = new \moodle_url("/message/edit.php", array('id' => $USER->id));
|
||||
$messageparams->messagepreferencesurl = $messagepreferencesurl->out();
|
||||
$htmlmessage = get_string('messageprocessingsuccesshtml', 'tool_messageinbound', $messageparams);
|
||||
$plainmessage = get_string('messageprocessingsuccess', 'tool_messageinbound', $messageparams);
|
||||
|
||||
// The message will be sent from the intended user.
|
||||
$userfrom = clone $USER;
|
||||
$userfrom->customheaders = array();
|
||||
|
||||
if ($messageid = $this->currentmessagedata->messageid) {
|
||||
// Adding the In-Reply-To header ensures that it is seen as a reply and threading is maintained.
|
||||
$userfrom->customheaders[] = 'In-Reply-To: ' . $messageid;
|
||||
}
|
||||
|
||||
$messagedata = new \stdClass();
|
||||
$messagedata->subject = $this->currentmessagedata->envelope->subject;
|
||||
|
||||
$eventdata = new \stdClass();
|
||||
$eventdata->component = 'tool_messageinbound';
|
||||
$eventdata->name = 'messageprocessingsuccess';
|
||||
$eventdata->userfrom = $userfrom;
|
||||
$eventdata->userto = $USER;
|
||||
$eventdata->subject = self::get_reply_subject($this->currentmessagedata->envelope->subject);
|
||||
$eventdata->fullmessage = $plainmessage;
|
||||
$eventdata->fullmessageformat = FORMAT_PLAIN;
|
||||
$eventdata->fullmessagehtml = $htmlmessage;
|
||||
$eventdata->smallmessage = $eventdata->fullmessage;
|
||||
$eventdata->notification = 1;
|
||||
|
||||
if (message_send($eventdata)) {
|
||||
mtrace("---> Success notification sent to {$USER->email}.");
|
||||
} else {
|
||||
mtrace("---> Unable to send success notification.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a formatted subject line for replies.
|
||||
*
|
||||
* @param $subject string The subject string
|
||||
* @return string The formatted reply subject
|
||||
*/
|
||||
private function get_reply_subject($subject) {
|
||||
$prefix = get_string('replysubjectprefix', 'tool_messageinbound');
|
||||
if (!(substr($subject, 0, strlen($prefix)) == $prefix)) {
|
||||
$subject = $prefix . ' ' . $subject;
|
||||
}
|
||||
|
||||
return $subject;
|
||||
}
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A Handler to re-process messages which previously failed sender
|
||||
* verification.
|
||||
*
|
||||
* @package task_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound\message\inbound;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/repository/lib.php');
|
||||
|
||||
/**
|
||||
* A Handler to re-process messages which previously failed sender
|
||||
* verification.
|
||||
*
|
||||
* This may happen if the user did not use their registerd e-mail address,
|
||||
* the verification hash used had expired, or if some erroneous content was
|
||||
* introduced into the content hash.
|
||||
*
|
||||
* @package task
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class invalid_recipient_handler extends \core\message\inbound\handler {
|
||||
|
||||
/**
|
||||
* Do not allow changes to the address validation setting.
|
||||
*/
|
||||
public function can_change_validateaddress() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a description for the current handler.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return get_string('invalid_recipient_handler', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a name for the current handler.
|
||||
* This appears in the admin pages as a human-readable name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('invalid_recipient_handler_name', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process a message received and validated by the Inbound Message processor.
|
||||
*
|
||||
* @param $messagedata The Inbound Message record
|
||||
* @param $messagedata The message data packet.
|
||||
* @return bool Whether the message was successfully processed.
|
||||
*/
|
||||
public function process_message(\stdClass $record, \stdClass $data) {
|
||||
global $DB;
|
||||
|
||||
if (!$maildata = $DB->get_record('messageinbound_messagelist', array('id' => $record->datavalue))) {
|
||||
// The message requested couldn't be found. Failing here will alert the user that we failed.
|
||||
throw new \core\message\inbound\processing_failed_exception('oldmessagenotfound', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
mtrace("=== Request to re-process message {$record->datavalue} from server.");
|
||||
mtrace("=== Message-Id:\t{$maildata->messageid}");
|
||||
mtrace("=== Recipient:\t{$maildata->address}");
|
||||
|
||||
$manager = new \tool_messageinbound\manager();
|
||||
return $manager->process_existing_message($maildata);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A scheduled task to handle cleanup of old, unconfirmed e-mails.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound\task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A scheduled task to handle cleanup of old, unconfirmed e-mails.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class cleanup_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskcleanup', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the main Inbound Message pickup task.
|
||||
*/
|
||||
public function execute() {
|
||||
$manager = new \tool_messageinbound\manager();
|
||||
return $manager->tidy_old_messages();
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* A scheduled task to handle Inbound Message e-mail pickup.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_messageinbound\task;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* A scheduled task to handle Inbound Message e-mail pickup.
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class pickup_task extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task (shown to admins).
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskpickup', 'tool_messageinbound');
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the main Inbound Message pickup task.
|
||||
*/
|
||||
public function execute() {
|
||||
$manager = new \tool_messageinbound\manager();
|
||||
return $manager->pickup_messages();
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Handlers for tool_messageinbound.
|
||||
*
|
||||
* @package task
|
||||
* @category tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$handlers = array(
|
||||
array(
|
||||
'classname' => '\tool_messageinbound\message\inbound\invalid_recipient_handler',
|
||||
'enabled' => true,
|
||||
'validateaddress' => false,
|
||||
),
|
||||
);
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Message Providers for task_messageinbound.
|
||||
*
|
||||
* @package task
|
||||
* @category messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$messageproviders = array (
|
||||
// Invalid recipient handler.
|
||||
'invalidrecipienthandler' => array(),
|
||||
|
||||
// A generic message processing error.
|
||||
'messageprocessingerror' => array(),
|
||||
|
||||
// A generic message processing success message.
|
||||
'messageprocessingsuccess' => array(),
|
||||
);
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The Main Manager tasks.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$tasks = array(
|
||||
array(
|
||||
'classname' => '\tool_messageinbound\task\pickup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '*',
|
||||
'hour' => '*',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
|
||||
array(
|
||||
'classname' => '\tool_messageinbound\task\cleanup_task',
|
||||
'blocking' => 0,
|
||||
'minute' => '55',
|
||||
'hour' => '1',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
),
|
||||
);
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Inbound Message Settings pages.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew NIcols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(__FILE__) . '/../../../config.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/tablelib.php');
|
||||
|
||||
admin_externalpage_setup('messageinbound_handlers');
|
||||
|
||||
$classname = optional_param('classname', '', PARAM_RAW);
|
||||
|
||||
$pageurl = new moodle_url('/admin/tool/messageinbound/index.php');
|
||||
|
||||
if (empty($classname)) {
|
||||
$renderer = $PAGE->get_renderer('tool_messageinbound');
|
||||
|
||||
$records = $DB->get_recordset('messageinbound_handlers', null, 'enabled desc', 'classname');
|
||||
$instances = array();
|
||||
foreach ($records as $record) {
|
||||
$instances[] = \core\message\inbound\manager::get_handler($record->classname);
|
||||
}
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $renderer->messageinbound_handlers_table($instances);
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
} else {
|
||||
// Retrieve the handler and its record.
|
||||
$handler = \core\message\inbound\manager::get_handler($classname);
|
||||
$record = \core\message\inbound\manager::record_from_handler($handler);
|
||||
|
||||
$formurl = new moodle_url($PAGE->url, array('classname' => $classname));
|
||||
$mform = new tool_messageinbound_edit_handler_form($formurl, array(
|
||||
'handler' => $handler,
|
||||
));
|
||||
|
||||
if ($mform->is_cancelled()) {
|
||||
redirect($PAGE->url);
|
||||
} else if ($data = $mform->get_data()) {
|
||||
|
||||
// Update the record from the form.
|
||||
if ($handler->can_change_defaultexpiration()) {
|
||||
$record->defaultexpiration = (int) $data->defaultexpiration;
|
||||
}
|
||||
|
||||
if ($handler->can_change_validateaddress()) {
|
||||
$record->validateaddress = !empty($data->validateaddress);
|
||||
}
|
||||
|
||||
if ($handler->can_change_enabled()) {
|
||||
$record->enabled = !empty($data->enabled);
|
||||
}
|
||||
$DB->update_record('messageinbound_handlers', $record);
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
// Add the breadcrumb.
|
||||
$pageurl->param('classname', $handler->classname);
|
||||
$PAGE->navbar->add($handler->name, $pageurl);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('editinghandler', 'tool_messageinbound', $handler->name));
|
||||
$mform->set_data($record);
|
||||
$mform->display();
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Strings for component 'tool_messageinbound', language 'en'
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['classname'] = 'Class name';
|
||||
$string['component'] = 'Component';
|
||||
$string['configmessageinboundhost'] = 'The address of the server that Moodle should check mail against. To specify a non-default port, you can use the [server]:[port], for example mail.example.com:587 format. If you leave this field blank, Moodle will use the default port for the type of mail server you specify.';
|
||||
$string['defaultexpiration'] = 'Default address expiry period';
|
||||
$string['defaultexpiration_help'] = 'When an email address is generated by the handler, it can be set to automatically expire after a period of time, so that it can no longer be used. It is advisable to set an expiry period.';
|
||||
$string['description'] = 'Description';
|
||||
$string['domain'] = 'Email domain';
|
||||
$string['edit'] = 'Edit';
|
||||
$string['edithandler'] = 'Edit settings for the {$a} handler';
|
||||
$string['editinghandler'] = 'Editing {$a}';
|
||||
$string['enabled'] = 'Enabled';
|
||||
$string['fixedvalidateaddress'] = 'Validate sender address';
|
||||
$string['fixedvalidateaddress_help'] = 'You cannot change the address validation for this handler. This may be because the handler requires a specific setting.';
|
||||
$string['fixedenabled_help'] = 'You cannot change the state of this handler. This may be because the handler is required by other handlers.';
|
||||
$string['handlerdisabled'] = 'The email handler you tried to contact has been disabled. Unable to process message at this time.';
|
||||
$string['incomingmailconfiguration'] = 'Incoming mail configuration';
|
||||
$string['incomingmailserversettings'] = 'Incoming mail server settings';
|
||||
$string['incomingmailserversettings_desc'] = 'Moodle is capable of connecting to appropriately configured IMAP servers. You can specify the settings used to connect to your IMAP server here.';
|
||||
$string['invalid_recipient_handler'] = 'If a valid message is received but the sender cannot be authenticated, the message is stored on the email server and the user is contacted using the email address in their user profile. The user is given the chance to reply to confirm the authenticity of the original message.
|
||||
|
||||
This handler processes those replies.
|
||||
|
||||
It is not possible to disable sender verification of this handler because the user may reply from an incorrect email address if their email client configuration is incorrect.';
|
||||
$string['invalid_recipient_handler_name'] = 'Invalid recipient handler';
|
||||
$string['invalidrecipientdescription'] = 'The message "{$a->subject}" could not be authenticated, since it was sent from a different email address than in your user profile. For the message to be authenticated, you need to reply to this message.';
|
||||
$string['invalidrecipientdescriptionhtml'] = 'The message "{$a->subject}" could not be authenticated, since it was sent from a different email address than in your user profile. For the message to be authenticated, you need to reply to this message.';
|
||||
$string['invalidrecipientfinal'] = 'The message "{$a->subject}" could not be authenticated. Please check that you are sending your message from the same email address as in your profile.';
|
||||
$string['mailbox'] = 'Mailbox name';
|
||||
$string['mailboxconfiguration'] = 'Mailbox configuration';
|
||||
$string['mailboxdescription'] = '[mailbox]+subaddress@[domain]';
|
||||
$string['mailsettings'] = 'Mail settings';
|
||||
$string['message_handlers'] = 'Message handlers';
|
||||
$string['messageprocessingerror'] = 'You recently sent an email "{$a->subject}" but unfortunately it could not be processed.
|
||||
|
||||
The details of the error are shown below.
|
||||
|
||||
{$a->error}';
|
||||
$string['messageprocessingerrorhtml'] = '<p>You recently sent an email "{$a->subject}" but unfortunately it could not be processed.</p>
|
||||
<p>The details of the error are shown below.</p>
|
||||
<p>{$a->error}</p>';
|
||||
$string['messageprocessingfailed'] = 'The email "{$a->subject}" could not be processed. The error is as follows: "{$a->message}".';
|
||||
$string['messageprocessingfailedunknown'] = 'The email "{$a->subject}" could not be processed. Contact your administrator for further information.';
|
||||
$string['messageprocessingsuccess'] = '{$a->plain}
|
||||
|
||||
If you do not wish to receive these notifications in the future, you can edit your personal messaging preferences by opening {$a->messagepreferencesurl} in your browser.';
|
||||
$string['messageprocessingsuccesshtml'] = '{$a->html}
|
||||
<p>If you do not wish to receive these notifications in the future, you can <a href="{$a->messagepreferencesurl}">edit your personal messaging preferences</a>.</p>';
|
||||
$string['messageinbound'] = 'Message Inbound';
|
||||
$string['messageinboundenabled'] = 'Enable incoming mail processing';
|
||||
$string['messageinboundenabled_desc'] = 'Incoming mail processing must be enabled in order for messages to be sent with the appropriate information.';
|
||||
$string['messageinboundgeneralconfiguration'] = 'General configuration';
|
||||
$string['messageinboundgeneralconfiguration_desc'] = 'Inbound message processing allows you to receive and process email within Moodle. This has applications such as sending email replies to forum posts or adding files to a user\'s private files.';
|
||||
$string['messageinboundhost'] = 'Incoming Mail Server';
|
||||
$string['messageinboundhostpass'] = 'Password';
|
||||
$string['messageinboundhostpass_desc'] = 'This is the password your service provider will have provided to log in to your email account with.';
|
||||
$string['messageinboundhostssl'] = 'Use SSL';
|
||||
$string['messageinboundhostssl_desc'] = 'Some mail servers support an additional level of security by encrypting communication between Moodle and your server. We recommend using this SSL encryption if your server supports it.';
|
||||
$string['messageinboundhosttype'] = 'Server type';
|
||||
$string['messageinboundhostuser'] = 'Username';
|
||||
$string['messageinboundhostuser_desc'] = 'This is the username your service provider will have provided to log in to your email account with.';
|
||||
$string['messageinboundmailboxconfiguration_desc'] = 'When messages are sent out, they fit into the format address+data@example.com. To reliably generate addresses from Moodle, please specify the address that you would normally use before the @ sign, and the domain after the @ sign separately. For example, the Mailbox name in the example would be "address", and the E-mail domain would be "example.com". You should use a dedicated e-mail account for this purpose.';
|
||||
$string['messageprovider:invalidrecipienthandler'] = 'Message to confirm that an inbound message came from you';
|
||||
$string['messageprovider:messageprocessingerror'] = 'Warning when an inbound message could not be processed';
|
||||
$string['messageprovider:messageprocessingsuccess'] = 'Confirmation that a message was successfully processed';
|
||||
$string['noencryption'] = 'Off - No encryption';
|
||||
$string['noexpiry'] = 'No expiry';
|
||||
$string['oldmessagenotfound'] = 'You tried to manually authenticate a message, but the message could not be found. This could be because it has already been processed, or because the message expired.';
|
||||
$string['oneday'] = 'One day';
|
||||
$string['onehour'] = 'One hour';
|
||||
$string['oneweek'] = 'One week';
|
||||
$string['oneyear'] = 'One year';
|
||||
$string['pluginname'] = 'Inbound message configuration';
|
||||
$string['replysubjectprefix'] = 'Re:';
|
||||
$string['requirevalidation'] = 'Validate sender address';
|
||||
$string['name'] = 'Name';
|
||||
$string['ssl'] = 'SSL (Auto-detect SSL version)';
|
||||
$string['sslv2'] = 'SSLv2 (Force SSL Version 2)';
|
||||
$string['sslv3'] = 'SSLv2 (Force SSL Version 3)';
|
||||
$string['taskcleanup'] = 'Cleanup of unverified incoming email';
|
||||
$string['taskpickup'] = 'Incoming email pickup';
|
||||
$string['tls'] = 'TLS (TLS; started via protocol-level negotiation over unencrypted channel; RECOMMENDED way of initiating secure connection)';
|
||||
$string['tlsv1'] = 'TLSv1 (TLS direct version 1.x connection to server)';
|
||||
$string['validateaddress'] = 'Validate sender email address';
|
||||
$string['validateaddress_help'] = 'When a message is received from a user, Moodle attempts to validate the message by comparing the email address of the sender with the email address in their user profile.
|
||||
|
||||
If the sender does not match, then the user is sent a notification to confirm that they really did send the email.
|
||||
|
||||
If this setting is disabled, then the email address of the sender is not checked at all.';
|
||||
@@ -1,109 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Output rendering for the plugin.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Implements the plugin renderer
|
||||
*
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class tool_messageinbound_renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Render a table listing all of the Inbound Message handlers.
|
||||
*
|
||||
* @param array $handlers - list of all messageinbound handlers.
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function messageinbound_handlers_table(array $handlers) {
|
||||
global $CFG;
|
||||
|
||||
$table = new html_table();
|
||||
$handlername = new html_table_cell(get_string('name', 'tool_messageinbound') . "\n" .
|
||||
html_writer::tag('span', get_string('classname', 'tool_messageinbound'), array('class' => 'handler-function')));
|
||||
|
||||
// Prepare some of the rows with additional styling.
|
||||
$enabled = new html_table_cell(get_string('enabled', 'tool_messageinbound'));
|
||||
$enabled->attributes['class'] = 'state';
|
||||
$edit = new html_table_cell(get_string('edit', 'tool_messageinbound'));
|
||||
$edit->attributes['class'] = 'edit';
|
||||
$table->head = array(
|
||||
$handlername,
|
||||
get_string('description', 'tool_messageinbound'),
|
||||
$enabled,
|
||||
$edit,
|
||||
);
|
||||
$table->attributes['class'] = 'admintable generaltable messageinboundhandlers';
|
||||
|
||||
$yes = get_string('yes');
|
||||
$no = get_string('no');
|
||||
|
||||
$data = array();
|
||||
|
||||
// Options for description formatting.
|
||||
$descriptionoptions = new stdClass();
|
||||
$descriptionoptions->trusted = false;
|
||||
$descriptionoptions->noclean = false;
|
||||
$descriptionoptions->smiley = false;
|
||||
$descriptionoptions->filter = false;
|
||||
$descriptionoptions->para = true;
|
||||
$descriptionoptions->newlines = false;
|
||||
$descriptionoptions->overflowdiv = true;
|
||||
|
||||
$editurlbase = new moodle_url('/admin/tool/messageinbound/index.php');
|
||||
foreach ($handlers as $handler) {
|
||||
$handlername = new html_table_cell($handler->name . "\n" .
|
||||
html_writer::tag('span', $handler->classname, array('class' => 'handler-function')));
|
||||
$handlername->header = true;
|
||||
|
||||
$editurl = new moodle_url($editurlbase, array('classname' => $handler->classname));
|
||||
$editlink = $this->action_icon($editurl, new pix_icon('t/edit',
|
||||
get_string('edithandler', 'tool_messageinbound', $handler->classname)));
|
||||
|
||||
// Prepare some of the rows with additional styling.
|
||||
$enabled = new html_table_cell($handler->enabled ? $yes : $no);
|
||||
$enabled->attributes['class'] = 'state';
|
||||
$edit = new html_table_cell($editlink);
|
||||
$edit->attributes['class'] = 'edit';
|
||||
|
||||
// Add the row.
|
||||
$row = new html_table_row(array(
|
||||
$handlername,
|
||||
format_text($handler->description, FORMAT_MARKDOWN, $descriptionoptions),
|
||||
$enabled,
|
||||
$edit,
|
||||
));
|
||||
|
||||
if (!$handler->enabled) {
|
||||
$row->attributes['class'] = 'disabled';
|
||||
}
|
||||
$data[] = $row;
|
||||
}
|
||||
$table->data = $data;
|
||||
return html_writer::table($table);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Inbound Message Settings.
|
||||
*
|
||||
* @package tool_messageinbound
|
||||
* @copyright 2014 Andrew Nicols
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
if ($hassiteconfig) {
|
||||
$category = new admin_category('messageinbound', new lang_string('incomingmailconfiguration', 'tool_messageinbound'));
|
||||
|
||||
// Create a settings page for all of the mail server settings.
|
||||
$settings = new admin_settingpage('messageinbound_mailsettings', new lang_string('mailsettings', 'tool_messageinbound'));
|
||||
|
||||
$settings->add(new admin_setting_heading('messageinbound_generalconfiguration',
|
||||
new lang_string('messageinboundgeneralconfiguration', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundgeneralconfiguration_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configcheckbox('messageinbound_enabled',
|
||||
new lang_string('messageinboundenabled', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundenabled_desc', 'tool_messageinbound'), 0));
|
||||
|
||||
// These settings are used when generating a Inbound Message address.
|
||||
$settings->add(new admin_setting_heading('messageinbound_mailboxconfiguration',
|
||||
new lang_string('mailboxconfiguration', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundmailboxconfiguration_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_mailbox',
|
||||
new lang_string('mailbox', 'tool_messageinbound'),
|
||||
null, '', PARAM_RAW));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_domain',
|
||||
new lang_string('domain', 'tool_messageinbound'),
|
||||
null, '', PARAM_RAW));
|
||||
|
||||
// These settings are used when checking the incoming mailbox for mail.
|
||||
$settings->add(new admin_setting_heading('messageinbound_serversettings',
|
||||
new lang_string('incomingmailserversettings', 'tool_messageinbound'),
|
||||
new lang_string('incomingmailserversettings_desc', 'tool_messageinbound'), ''));
|
||||
$settings->add(new admin_setting_configtext('messageinbound_host',
|
||||
new lang_string('messageinboundhost', 'tool_messageinbound'),
|
||||
new lang_string('configmessageinboundhost', 'tool_messageinbound'), '', PARAM_RAW));
|
||||
|
||||
$options = array(
|
||||
'' => get_string('noencryption', 'tool_messageinbound'),
|
||||
'ssl' => get_string('ssl', 'tool_messageinbound'),
|
||||
'sslv2' => get_string('sslv2', 'tool_messageinbound'),
|
||||
'sslv3' => get_string('sslv3', 'tool_messageinbound'),
|
||||
'tls' => get_string('tls', 'tool_messageinbound'),
|
||||
'tlsv1' => get_string('tlsv1', 'tool_messageinbound'),
|
||||
);
|
||||
$settings->add(new admin_setting_configselect('messageinbound_hostssl',
|
||||
new lang_string('messageinboundhostssl', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundhostssl_desc', 'tool_messageinbound'), 'ssl', $options));
|
||||
|
||||
$settings->add(new admin_setting_configtext('messageinbound_hostuser',
|
||||
new lang_string('messageinboundhostuser', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundhostuser_desc', 'tool_messageinbound'), '', PARAM_NOTAGS));
|
||||
$settings->add(new admin_setting_configpasswordunmask('messageinbound_hostpass',
|
||||
new lang_string('messageinboundhostpass', 'tool_messageinbound'),
|
||||
new lang_string('messageinboundhostpass_desc', 'tool_messageinbound'), ''));
|
||||
|
||||
$category->add('messageinbound', $settings);
|
||||
|
||||
// Link to the external page for Inbound Message handler configuration.
|
||||
$category->add('messageinbound', new admin_externalpage('messageinbound_handlers',
|
||||
new lang_string('message_handlers', 'tool_messageinbound'),
|
||||
"$CFG->wwwroot/$CFG->admin/tool/messageinbound/index.php"));
|
||||
|
||||
// Add the category to the admin tree.
|
||||
$ADMIN->add('server', $category);
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#page-admin-tool-messageinbound-index .handler-function {
|
||||
display: block;
|
||||
padding: 0 0.5em;
|
||||
color: #888;
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
#page-admin-tool-messageinbound-index .state,
|
||||
#page-admin-tool-messageinbound-index .edit {
|
||||
text-align: center;
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The tool_monitor rule created event.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_monitor rule created event class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rule_created extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tool_monitor_rules';
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventrulecreated', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' created the event monitor rule with id '$this->objectid'.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $this->objectid,
|
||||
'courseid' => $this->courseid));
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The tool_monitor rule deleted event.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_monitor rule deleted event class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rule_deleted extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tool_monitor_rules';
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventruledeleted', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' deleted the event monitor rule with id '$this->objectid'.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/monitor/managerules.php', array('courseid' => $this->courseid));
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The tool_monitor rule updated event.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_monitor rule updated event class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rule_updated extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tool_monitor_rules';
|
||||
$this->data['crud'] = 'u';
|
||||
$this->data['edulevel'] = self::LEVEL_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventruleupdated', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' updated the event monitor rule with id '$this->objectid'.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get URL related to the action
|
||||
*
|
||||
* @return \moodle_url
|
||||
*/
|
||||
public function get_url() {
|
||||
return new \moodle_url('/admin/tool/monitor/edit.php', array('ruleid' => $this->objectid,
|
||||
'courseid' => $this->courseid));
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The tool_monitor subscription created event.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_monitor subscription created event class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription_created extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tool_monitor_subscriptions';
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_TEACHING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventsubcreated', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' created the event monitor subscription with id '$this->objectid'.";
|
||||
}
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The tool_monitor subscription criteria met event.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_monitor subscription criteria met event class.
|
||||
*
|
||||
* @property-read array $other {
|
||||
* Extra information about event.
|
||||
*
|
||||
* - string subscriptionid: id of the subscription.
|
||||
* }
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription_criteria_met extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['crud'] = 'c';
|
||||
$this->data['edulevel'] = self::LEVEL_TEACHING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventsubcriteriamet', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The criteria for the subscription with id '{$this->other['subscriptionid']}' was met.";
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom validation.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
* @return void
|
||||
*/
|
||||
protected function validate_data() {
|
||||
parent::validate_data();
|
||||
|
||||
if (!isset($this->other['subscriptionid'])) {
|
||||
throw new \coding_exception('The \'subscriptionid\' value must be set in other.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The tool_monitor subscription deleted event.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\event;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* The tool_monitor subscription deleted event class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription_deleted extends \core\event\base {
|
||||
|
||||
/**
|
||||
* Init method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init() {
|
||||
$this->data['objecttable'] = 'tool_monitor_subscriptions';
|
||||
$this->data['crud'] = 'd';
|
||||
$this->data['edulevel'] = self::LEVEL_TEACHING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return localised event name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_name() {
|
||||
return get_string('eventsubdeleted', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns description of what happened.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_description() {
|
||||
return "The user with id '$this->userid' deleted the event monitor subscription with id '$this->objectid'.";
|
||||
}
|
||||
}
|
||||
@@ -1,221 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Event documentation
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class for returning event information.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class eventlist {
|
||||
/**
|
||||
* Return all of the core event files.
|
||||
*
|
||||
* @return array Core events.
|
||||
*/
|
||||
protected static function get_core_eventlist() {
|
||||
global $CFG;
|
||||
|
||||
// Disable developer debugging as deprecated events will fire warnings.
|
||||
// Setup backup variables to restore the following settings back to what they were when we are finished.
|
||||
$debuglevel = $CFG->debug;
|
||||
$debugdisplay = $CFG->debugdisplay;
|
||||
$debugdeveloper = $CFG->debugdeveloper;
|
||||
$CFG->debug = 0;
|
||||
$CFG->debugdisplay = false;
|
||||
$CFG->debugdeveloper = false;
|
||||
|
||||
$eventinformation = array();
|
||||
$directory = $CFG->libdir . '/classes/event';
|
||||
$files = self::get_file_list($directory);
|
||||
|
||||
// Remove exceptional events that will cause problems being displayed.
|
||||
if (isset($files['unknown_logged'])) {
|
||||
unset($files['unknown_logged']);
|
||||
}
|
||||
foreach ($files as $file => $location) {
|
||||
$classname = '\\core\\event\\' . $file;
|
||||
// Check to see if this is actually a valid event.
|
||||
if (method_exists($classname, 'get_static_info')) {
|
||||
$ref = new \ReflectionClass($classname);
|
||||
// Ignore abstracts.
|
||||
if (!$ref->isAbstract() && $file != 'manager') {
|
||||
$eventinformation[$classname] = $classname::get_name();
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now enable developer debugging as event information has been retrieved.
|
||||
$CFG->debug = $debuglevel;
|
||||
$CFG->debugdisplay = $debugdisplay;
|
||||
$CFG->debugdeveloper = $debugdeveloper;
|
||||
return $eventinformation;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns an array of all events for the plugins of the system.
|
||||
*
|
||||
* @param bool $withoutcomponent Return an eventlist without associated components.
|
||||
*
|
||||
* @return array A list of events from all plug-ins.
|
||||
*/
|
||||
protected static function get_non_core_eventlist($withoutcomponent = false) {
|
||||
global $CFG;
|
||||
// Disable developer debugging as deprecated events will fire warnings.
|
||||
// Setup backup variables to restore the following settings back to what they were when we are finished.
|
||||
$debuglevel = $CFG->debug;
|
||||
$debugdisplay = $CFG->debugdisplay;
|
||||
$debugdeveloper = $CFG->debugdeveloper;
|
||||
$CFG->debug = 0;
|
||||
$CFG->debugdisplay = false;
|
||||
$CFG->debugdeveloper = false;
|
||||
|
||||
$noncorepluginlist = array();
|
||||
$plugintypes = \core_component::get_plugin_types();
|
||||
foreach ($plugintypes as $plugintype => $notused) {
|
||||
$pluginlist = \core_component::get_plugin_list($plugintype);
|
||||
foreach ($pluginlist as $plugin => $directory) {
|
||||
$plugindirectory = $directory . '/classes/event';
|
||||
foreach (self::get_file_list($plugindirectory) as $eventname => $notused) {
|
||||
$plugineventname = '\\' . $plugintype . '_' . $plugin . '\\event\\' . $eventname;
|
||||
// Check that this is actually an event.
|
||||
if (method_exists($plugineventname, 'get_static_info') && $plugin != 'monitor') { // No selfie here.
|
||||
$ref = new \ReflectionClass($plugineventname);
|
||||
if (!$ref->isAbstract() && $plugin != 'legacy') {
|
||||
if ($withoutcomponent) {
|
||||
$noncorepluginlist[$plugineventname] = $plugineventname::get_name();
|
||||
} else {
|
||||
$noncorepluginlist[$plugintype . '_' . $plugin][$plugineventname] = $plugineventname::get_name();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now enable developer debugging as event information has been retrieved.
|
||||
$CFG->debug = $debuglevel;
|
||||
$CFG->debugdisplay = $debugdisplay;
|
||||
$CFG->debugdeveloper = $debugdeveloper;
|
||||
|
||||
return $noncorepluginlist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of files with a full directory path in a specified directory.
|
||||
*
|
||||
* @param string $directory location of files.
|
||||
* @return array full location of files from the specified directory.
|
||||
*/
|
||||
protected static function get_file_list($directory) {
|
||||
global $CFG;
|
||||
$directoryroot = $CFG->dirroot;
|
||||
$finalfiles = array();
|
||||
if (is_dir($directory)) {
|
||||
if ($handle = opendir($directory)) {
|
||||
$files = scandir($directory);
|
||||
foreach ($files as $file) {
|
||||
if ($file != '.' && $file != '..') {
|
||||
// Ignore the file if it is external to the system.
|
||||
if (strrpos($directory, $directoryroot) !== false) {
|
||||
$location = substr($directory, strlen($directoryroot));
|
||||
$name = substr($file, 0, -4);
|
||||
$finalfiles[$name] = $location . '/' . $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $finalfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of events present in the system.
|
||||
*
|
||||
* @param bool $withoutcomponent Return an eventlist without associated components.
|
||||
*
|
||||
* @return array list of events present in the system.
|
||||
*/
|
||||
public static function get_all_eventlist($withoutcomponent = false) {
|
||||
if ($withoutcomponent) {
|
||||
$return = array_merge(self::get_core_eventlist(), self::get_non_core_eventlist($withoutcomponent));
|
||||
array_multisort($return, SORT_NATURAL);
|
||||
} else {
|
||||
$return = array_merge(array('core' => self::get_core_eventlist()),
|
||||
self::get_non_core_eventlist($withoutcomponent = false));
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of plugins that have events.
|
||||
*
|
||||
* @param array $eventlist a list of events present in the system {@link eventlist::get_all_eventlist}.
|
||||
*
|
||||
* @return array list of plugins with human readable name.
|
||||
*/
|
||||
public static function get_plugin_list($eventlist = array()) {
|
||||
if (empty($eventlist)) {
|
||||
$eventlist = self::get_all_eventlist();
|
||||
}
|
||||
$plugins = array_keys($eventlist);
|
||||
$return = array();
|
||||
foreach ($plugins as $plugin) {
|
||||
if ($plugin === 'core') {
|
||||
$return[$plugin] = get_string('core', 'tool_monitor');
|
||||
} else if (get_string_manager()->string_exists('pluginname', $plugin)) {
|
||||
$return[$plugin] = get_string('pluginname', $plugin);
|
||||
} else {
|
||||
$return[$plugin] = $plugin;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate if the given event belongs to the given plugin.
|
||||
*
|
||||
* @param string $plugin Frankenstyle name of the plugin.
|
||||
* @param string $eventname Full qualified event name.
|
||||
* @param array $eventlist List of events generated by {@link eventlist::get_all_eventlist}
|
||||
*
|
||||
* @return bool Returns true if the selected event belongs to the selected plugin, false otherwise.
|
||||
*/
|
||||
public static function validate_event_plugin($plugin, $eventname, $eventlist = array()) {
|
||||
if (empty($eventlist)) {
|
||||
$eventlist = self::get_all_eventlist();
|
||||
}
|
||||
if (isset($eventlist[$plugin][$eventname])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,253 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Observer class containing methods monitoring various events.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Observer class containing methods monitoring various events.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class eventobservers {
|
||||
|
||||
/** @var array $buffer buffer of events. */
|
||||
protected $buffer = array();
|
||||
|
||||
/** @var int Number of entries in the buffer. */
|
||||
protected $count = 0;
|
||||
|
||||
/** @var eventobservers a reference to a self instance. */
|
||||
protected static $instance;
|
||||
|
||||
/**
|
||||
* Course delete event observer.
|
||||
* This observer monitors course delete event, and when a course is deleted it deletes any rules and subscriptions associated
|
||||
* with it, so no orphan data is left behind.
|
||||
*
|
||||
* @param \core\event\course_deleted $event The course deleted event.
|
||||
*/
|
||||
public static function course_deleted(\core\event\course_deleted $event) {
|
||||
$rules = rule_manager::get_rules_by_courseid($event->courseid, 0, 0, false);
|
||||
foreach ($rules as $rule) {
|
||||
rule_manager::delete_rule($rule->id, $event->get_context());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The observer monitoring all the events.
|
||||
*
|
||||
* This observers puts small event objects in buffer for later writing to the database. At the end of the request the buffer
|
||||
* is cleaned up and all data dumped into the tool_monitor_events table.
|
||||
*
|
||||
* @param \core\event\base $event event object
|
||||
*/
|
||||
public static function process_event(\core\event\base $event) {
|
||||
if (!get_config('tool_monitor', 'enablemonitor')) {
|
||||
return; // The tool is disabled. Nothing to do.
|
||||
}
|
||||
|
||||
if (empty(self::$instance)) {
|
||||
self::$instance = new static();
|
||||
// Register shutdown handler - this is useful for buffering, processing events, etc.
|
||||
\core_shutdown_manager::register_function(array(self::$instance, 'process_buffer'));
|
||||
}
|
||||
|
||||
self::$instance->buffer_event($event);
|
||||
|
||||
if (PHPUNIT_TEST) {
|
||||
// Process buffer after every event when unit testing.
|
||||
self::$instance->process_buffer();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Api to buffer events to store, to reduce db queries.
|
||||
*
|
||||
* @param \core\event\base $event
|
||||
*/
|
||||
protected function buffer_event(\core\event\base $event) {
|
||||
|
||||
// If there are no subscriptions for this event do not buffer it.
|
||||
if (!\tool_monitor\subscription_manager::event_has_subscriptions($event->eventname, $event->courseid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$eventdata = $event->get_data();
|
||||
$eventobj = new \stdClass();
|
||||
$eventobj->eventname = $eventdata['eventname'];
|
||||
$eventobj->contextid = $eventdata['contextid'];
|
||||
$eventobj->contextlevel = $eventdata['contextlevel'];
|
||||
$eventobj->contextinstanceid = $eventdata['contextinstanceid'];
|
||||
if ($event->get_url()) {
|
||||
// Get link url if exists.
|
||||
$eventobj->link = $event->get_url()->out();
|
||||
} else {
|
||||
$eventobj->link = '';
|
||||
}
|
||||
$eventobj->courseid = $eventdata['courseid'];
|
||||
$eventobj->timecreated = $eventdata['timecreated'];
|
||||
|
||||
$this->buffer[] = $eventobj;
|
||||
$this->count++;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method process all events stored in the buffer.
|
||||
*
|
||||
* This is a multi purpose api. It does the following:-
|
||||
* 1. Write event data to tool_monitor_events
|
||||
* 2. Find out users that need to be notified about rule completion and schedule a task to send them messages.
|
||||
*/
|
||||
public function process_buffer() {
|
||||
global $DB;
|
||||
|
||||
$events = $this->flush(); // Flush data.
|
||||
|
||||
$select = "SELECT COUNT(id) FROM {tool_monitor_events} ";
|
||||
$now = time();
|
||||
$messagestosend = array();
|
||||
$allsubids = array();
|
||||
|
||||
// Let us now process the events and check for subscriptions.
|
||||
foreach ($events as $eventobj) {
|
||||
$subscriptions = subscription_manager::get_subscriptions_by_event($eventobj);
|
||||
$idstosend = array();
|
||||
foreach ($subscriptions as $subscription) {
|
||||
$starttime = $now - $subscription->timewindow;
|
||||
$starttime = ($starttime > $subscription->lastnotificationsent) ? $starttime : $subscription->lastnotificationsent;
|
||||
if ($subscription->courseid == 0) {
|
||||
// Site level subscription. Count all events.
|
||||
$where = "eventname = :eventname AND timecreated > :starttime";
|
||||
$params = array('eventname' => $eventobj->eventname, 'starttime' => $starttime);
|
||||
} else {
|
||||
// Course level subscription.
|
||||
if ($subscription->cmid == 0) {
|
||||
// All modules.
|
||||
$where = "eventname = :eventname AND courseid = :courseid AND timecreated > :starttime";
|
||||
$params = array('eventname' => $eventobj->eventname, 'courseid' => $eventobj->courseid,
|
||||
'starttime' => $starttime);
|
||||
} else {
|
||||
// Specific module.
|
||||
$where = "eventname = :eventname AND courseid = :courseid AND contextinstanceid = :cmid
|
||||
AND timecreated > :starttime";
|
||||
$params = array('eventname' => $eventobj->eventname, 'courseid' => $eventobj->courseid,
|
||||
'cmid' => $eventobj->contextinstanceid, 'starttime' => $starttime);
|
||||
|
||||
}
|
||||
}
|
||||
$sql = $select . "WHERE " . $where;
|
||||
$count = $DB->count_records_sql($sql, $params);
|
||||
if (!empty($count) && $count >= $subscription->frequency) {
|
||||
$idstosend[] = $subscription->id;
|
||||
|
||||
// Trigger a subscription_criteria_met event.
|
||||
// It's possible that the course has been deleted since the criteria was met, so in that case use
|
||||
// the system context. Set it here and change later if needed.
|
||||
$context = \context_system::instance();
|
||||
// We can't perform if (!empty($subscription->courseid)) below as it uses the magic method
|
||||
// __get to return the variable, which will always result in being empty.
|
||||
$courseid = $subscription->courseid;
|
||||
if (!empty($courseid)) {
|
||||
if ($coursecontext = \context_course::instance($courseid, IGNORE_MISSING)) {
|
||||
$context = $coursecontext;
|
||||
}
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'userid' => $subscription->userid,
|
||||
'courseid' => $subscription->courseid,
|
||||
'context' => $context,
|
||||
'other' => array(
|
||||
'subscriptionid' => $subscription->id
|
||||
)
|
||||
);
|
||||
$event = \tool_monitor\event\subscription_criteria_met::create($params);
|
||||
$event->trigger();
|
||||
}
|
||||
}
|
||||
if (!empty($idstosend)) {
|
||||
$messagestosend[] = array('subscriptionids' => $idstosend, 'event' => $eventobj);
|
||||
$allsubids = array_merge($allsubids, $idstosend);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($allsubids)) {
|
||||
// Update the last trigger flag.
|
||||
list($sql, $params) = $DB->get_in_or_equal($allsubids, SQL_PARAMS_NAMED);
|
||||
$params['now'] = $now;
|
||||
$sql = "UPDATE {tool_monitor_subscriptions} SET lastnotificationsent = :now WHERE id $sql";
|
||||
$DB->execute($sql, $params);
|
||||
}
|
||||
|
||||
// Schedule a task to send notification.
|
||||
if (!empty($messagestosend)) {
|
||||
$adhocktask = new notification_task();
|
||||
$adhocktask->set_custom_data($messagestosend);
|
||||
$adhocktask->set_component('tool_monitor');
|
||||
\core\task\manager::queue_adhoc_task($adhocktask);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected method that flushes the buffer of events and writes them to the database.
|
||||
*
|
||||
* @return array a copy of the events buffer.
|
||||
*/
|
||||
protected function flush() {
|
||||
global $DB;
|
||||
|
||||
// Flush the buffer to the db.
|
||||
$events = $this->buffer;
|
||||
$DB->insert_records('tool_monitor_events', $events); // Insert the whole chunk into the database.
|
||||
$this->buffer = array();
|
||||
$this->count = 0;
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer that monitors user deleted event and delete user subscriptions.
|
||||
*
|
||||
* @param \core\event\user_deleted $event the event object.
|
||||
*/
|
||||
public static function user_deleted(\core\event\user_deleted $event) {
|
||||
$userid = $event->objectid;
|
||||
subscription_manager::delete_user_subscriptions($userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Observer that monitors course module deleted event and delete user subscriptions.
|
||||
*
|
||||
* @param \core\event\course_module_deleted $event the event object.
|
||||
*/
|
||||
public static function course_module_deleted(\core\event\course_module_deleted $event) {
|
||||
$cmid = $event->contextinstanceid;
|
||||
subscription_manager::delete_cm_subscriptions($cmid);
|
||||
}
|
||||
}
|
||||
@@ -1,124 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file defines an adhoc task to send notifications.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Adhock class, used to send notifications to users.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class notification_task extends \core\task\adhoc_task {
|
||||
|
||||
/**
|
||||
* Send out messages.
|
||||
*/
|
||||
public function execute() {
|
||||
foreach ($this->get_custom_data() as $data) {
|
||||
$eventobj = $data->event;
|
||||
$subscriptionids = $data->subscriptionids;
|
||||
foreach ($subscriptionids as $id) {
|
||||
if ($message = $this->generate_message($id, $eventobj)) {
|
||||
mtrace("Sending message to the user with id " . $message->userto->id . " for the subscription with id $id...");
|
||||
message_send($message);
|
||||
mtrace("Sent.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the message object for a give subscription and event.
|
||||
*
|
||||
* @param int $subscriptionid Subscription instance
|
||||
* @param \stdClass $eventobj Event data
|
||||
*
|
||||
* @return false|\stdClass message object
|
||||
*/
|
||||
protected function generate_message($subscriptionid, \stdClass $eventobj) {
|
||||
|
||||
try {
|
||||
$subscription = subscription_manager::get_subscription($subscriptionid);
|
||||
} catch (\dml_exception $e) {
|
||||
// Race condition, someone deleted the subscription.
|
||||
return false;
|
||||
}
|
||||
$user = \core_user::get_user($subscription->userid);
|
||||
if (empty($user)) {
|
||||
// User doesn't exist. Should never happen, nothing to do return.
|
||||
return false;
|
||||
}
|
||||
$context = \context_user::instance($user->id, IGNORE_MISSING);
|
||||
if ($context === false) {
|
||||
// User context doesn't exist. Should never happen, nothing to do return.
|
||||
return false;
|
||||
}
|
||||
|
||||
$template = $subscription->template;
|
||||
$template = $this->replace_placeholders($template, $subscription, $eventobj, $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->smallmessage = '';
|
||||
$msgdata->notification = 1; // This is only set to 0 for personal messages between users.
|
||||
|
||||
return $msgdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace place holders in the template with respective content.
|
||||
*
|
||||
* @param string $template Message template.
|
||||
* @param subscription $subscription subscription instance
|
||||
* @param \stdclass $eventobj Event data
|
||||
* @param \context $context context object
|
||||
*
|
||||
* @return mixed final template string.
|
||||
*/
|
||||
protected function replace_placeholders($template, subscription $subscription, $eventobj, $context) {
|
||||
$template = str_replace('{link}', $eventobj->link, $template);
|
||||
if ($eventobj->contextlevel == CONTEXT_MODULE && !empty($eventobj->contextinstanceid)
|
||||
&& (strpos($template, '{modulelink}') !== false)) {
|
||||
$cm = get_fast_modinfo($eventobj->courseid)->get_cm($eventobj->contextinstanceid);
|
||||
$modulelink = $cm->url;
|
||||
$template = str_replace('{modulelink}', $modulelink, $template);
|
||||
}
|
||||
$template = str_replace('{rulename}', $subscription->get_name($context), $template);
|
||||
$template = str_replace('{description}', $subscription->get_description($context), $template);
|
||||
$template = str_replace('{eventname}', $subscription->get_event_name(), $template);
|
||||
|
||||
return $template;
|
||||
}
|
||||
}
|
||||
@@ -1,214 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderable class for manage rules page.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\output\managerules;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
/**
|
||||
* Renderable class for manage rules page.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderable extends \table_sql implements \renderable {
|
||||
|
||||
/**
|
||||
* @var int course id.
|
||||
*/
|
||||
public $courseid;
|
||||
|
||||
/**
|
||||
* @var \context_course|\context_system context of the page to be rendered.
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* @var bool Does the user have capability to manage rules at site context.
|
||||
*/
|
||||
protected $hassystemcap;
|
||||
|
||||
/**
|
||||
* Sets up the table_log parameters.
|
||||
*
|
||||
* @param string $uniqueid unique id of form.
|
||||
* @param \moodle_url $url url where this table is displayed.
|
||||
* @param int $courseid course id.
|
||||
* @param int $perpage Number of rules to display per page.
|
||||
*/
|
||||
public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) {
|
||||
parent::__construct($uniqueid);
|
||||
|
||||
$this->set_attribute('id', 'toolmonitorrules_table');
|
||||
$this->set_attribute('class', 'toolmonitor managerules generaltable generalbox');
|
||||
$this->define_columns(array('name', 'description', 'course', 'plugin', 'eventname', 'filters', 'manage'));
|
||||
$this->define_headers(array(
|
||||
get_string('rulename', 'tool_monitor'),
|
||||
get_string('description'),
|
||||
get_string('course'),
|
||||
get_string('area', 'tool_monitor'),
|
||||
get_string('event', 'tool_monitor'),
|
||||
get_string('frequency', 'tool_monitor'),
|
||||
get_string('manage', 'tool_monitor'),
|
||||
)
|
||||
);
|
||||
$this->courseid = $courseid;
|
||||
$this->pagesize = $perpage;
|
||||
$systemcontext = \context_system::instance();
|
||||
$this->context = empty($courseid) ? $systemcontext : \context_course::instance($courseid);
|
||||
$this->hassystemcap = has_capability('tool/monitor:managerules', $systemcontext);
|
||||
$this->collapsible(false);
|
||||
$this->sortable(false);
|
||||
$this->pageable(true);
|
||||
$this->is_downloadable(false);
|
||||
$this->define_baseurl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for name column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the column field.
|
||||
*/
|
||||
public function col_name(\tool_monitor\rule $rule) {
|
||||
return $rule->get_name($this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for description column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the column field.
|
||||
*/
|
||||
public function col_description(\tool_monitor\rule $rule) {
|
||||
return $rule->get_description($this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for course column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the context column field.
|
||||
*/
|
||||
public function col_course(\tool_monitor\rule $rule) {
|
||||
$coursename = $rule->get_course_name($this->context);
|
||||
|
||||
$courseid = $rule->courseid;
|
||||
if (empty($courseid)) {
|
||||
return $coursename;
|
||||
} else {
|
||||
return \html_writer::link(new \moodle_url('/course/view.php', array('id' => $courseid)), $coursename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for plugin column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the column field.
|
||||
*/
|
||||
public function col_plugin(\tool_monitor\rule $rule) {
|
||||
return $rule->get_plugin_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for eventname column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the column field.
|
||||
*/
|
||||
public function col_eventname(\tool_monitor\rule $rule) {
|
||||
return $rule->get_event_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for filters column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the filters column field.
|
||||
*/
|
||||
public function col_filters(\tool_monitor\rule $rule) {
|
||||
return $rule->get_filters_description();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for manage column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the manage column field.
|
||||
*/
|
||||
public function col_manage(\tool_monitor\rule $rule) {
|
||||
global $OUTPUT, $CFG;
|
||||
|
||||
$manage = '';
|
||||
|
||||
// Do not allow the user to edit the rule unless they have the system capability, or we are viewing the rules
|
||||
// for a course, and not the site. Note - we don't need to check for the capability at a course level since
|
||||
// the user is never shown this page otherwise.
|
||||
if ($this->hassystemcap || ($rule->courseid != 0)) {
|
||||
$editurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('ruleid' => $rule->id,
|
||||
'courseid' => $rule->courseid, 'sesskey' => sesskey()));
|
||||
$icon = $OUTPUT->render(new \pix_icon('t/edit', get_string('editrule', 'tool_monitor')));
|
||||
$manage .= \html_writer::link($editurl, $icon, array('class' => 'action-icon'));
|
||||
}
|
||||
|
||||
// The user should always be able to copy the rule if they are able to view the page.
|
||||
$copyurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php',
|
||||
array('ruleid' => $rule->id, 'action' => 'copy', 'courseid' => $this->courseid, 'sesskey' => sesskey()));
|
||||
$icon = $OUTPUT->render(new \pix_icon('t/copy', get_string('duplicaterule', 'tool_monitor')));
|
||||
$manage .= \html_writer::link($copyurl, $icon, array('class' => 'action-icon'));
|
||||
|
||||
if ($this->hassystemcap || ($rule->courseid != 0)) {
|
||||
$deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/managerules.php', array('ruleid' => $rule->id,
|
||||
'action' => 'delete', 'courseid' => $rule->courseid, 'sesskey' => sesskey()));
|
||||
$icon = $OUTPUT->render(new \pix_icon('t/delete', get_string('deleterule', 'tool_monitor')));
|
||||
$manage .= \html_writer::link($deleteurl, $icon, array('class' => 'action-icon'));
|
||||
}
|
||||
|
||||
return $manage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the reader. Store results in the object for use by build_table.
|
||||
*
|
||||
* @param int $pagesize size of page for paginated displayed table.
|
||||
* @param bool $useinitialsbar do you want to use the initials bar.
|
||||
*/
|
||||
public function query_db($pagesize, $useinitialsbar = true) {
|
||||
|
||||
$total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid);
|
||||
$this->pagesize($pagesize, $total);
|
||||
$rules = \tool_monitor\rule_manager::get_rules_by_courseid($this->courseid, $this->get_page_start(),
|
||||
$this->get_page_size());
|
||||
$this->rawdata = $rules;
|
||||
// Set initial bars.
|
||||
if ($useinitialsbar) {
|
||||
$this->initialbars($total > $pagesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderer class for manage rules page.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\output\managerules;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
/**
|
||||
* Renderer class for manage rules page.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer extends \plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Get html to display on the page.
|
||||
*
|
||||
* @param renderable $renderable renderable widget
|
||||
*
|
||||
* @return string to display on the mangerules page.
|
||||
*/
|
||||
protected function render_renderable(renderable $renderable) {
|
||||
$o = $this->render_table($renderable);
|
||||
$o .= $this->render_add_button($renderable->courseid);
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get html to display on the page.
|
||||
*
|
||||
* @param renderable $renderable renderable widget
|
||||
*
|
||||
* @return string to display on the mangerules page.
|
||||
*/
|
||||
protected function render_table(renderable $renderable) {
|
||||
$o = '';
|
||||
ob_start();
|
||||
$renderable->out($renderable->pagesize, true);
|
||||
$o = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Html to add a button for adding a new rule.
|
||||
*
|
||||
* @param int $courseid course id.
|
||||
*
|
||||
* @return string html for the button.
|
||||
*/
|
||||
protected function render_add_button($courseid) {
|
||||
global $CFG;
|
||||
|
||||
$button = \html_writer::tag('button', get_string('addrule', 'tool_monitor'));
|
||||
$addurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/edit.php', array('courseid' => $courseid));
|
||||
return \html_writer::link($addurl, $button);
|
||||
}
|
||||
|
||||
/**
|
||||
* Html to add a link to go to the subscription page.
|
||||
*
|
||||
* @param moodle_url $manageurl The url of the subscription page.
|
||||
*
|
||||
* @return string html for the link to the subscription page.
|
||||
*/
|
||||
public function render_subscriptions_link($manageurl) {
|
||||
echo \html_writer::start_div();
|
||||
$a = \html_writer::link($manageurl, get_string('managesubscriptions', 'tool_monitor'));
|
||||
$link = \html_writer::tag('span', get_string('managesubscriptionslink', 'tool_monitor', $a));
|
||||
echo $link;
|
||||
echo \html_writer::end_div();
|
||||
}
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderer class for manage subscriptions page.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\output\managesubs;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
/**
|
||||
* Renderer class for manage subscriptions page.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class renderer extends \plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Get html to display on the page.
|
||||
*
|
||||
* @param subs $renderable renderable widget
|
||||
*
|
||||
* @return string to display on the mangesubs page.
|
||||
*/
|
||||
protected function render_subs(subs $renderable) {
|
||||
$o = $this->render_table($renderable);
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get html to display on the page.
|
||||
*
|
||||
* @param rules $renderable renderable widget
|
||||
*
|
||||
* @return string to display on the mangesubs page.
|
||||
*/
|
||||
protected function render_rules(rules $renderable) {
|
||||
$o = $this->render_course_select($renderable);
|
||||
if (!empty($renderable->totalcount)) {
|
||||
$o .= $this->render_table($renderable);
|
||||
}
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get html to display on the page for select dropdown..
|
||||
*
|
||||
* @param rules $renderable renderable widget
|
||||
*
|
||||
* @return string to display on the mangesubs page.
|
||||
*/
|
||||
protected function render_course_select(rules $renderable) {
|
||||
if ($select = $renderable->get_user_courses_select()) {
|
||||
return $this->render($select);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get html to display on the page.
|
||||
*
|
||||
* @param rules|subs $renderable renderable widget
|
||||
*
|
||||
* @return string to display on the mangesubs page.
|
||||
*/
|
||||
protected function render_table($renderable) {
|
||||
$o = '';
|
||||
ob_start();
|
||||
$renderable->out($renderable->pagesize, true);
|
||||
$o = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Html to add a link to go to the rule manager page.
|
||||
*
|
||||
* @param moodle_url $ruleurl The url of the rule manager page.
|
||||
*
|
||||
* @return string html for the link to the rule manager page.
|
||||
*/
|
||||
public function render_rules_link($ruleurl) {
|
||||
echo \html_writer::start_div();
|
||||
$a = \html_writer::link($ruleurl, get_string('managerules', 'tool_monitor'));
|
||||
$link = \html_writer::tag('span', get_string('manageruleslink', 'tool_monitor', $a));
|
||||
echo $link;
|
||||
echo \html_writer::end_div();
|
||||
}
|
||||
}
|
||||
@@ -1,230 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderable class to display a set of rules in the manage subscriptions page.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\output\managesubs;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
/**
|
||||
* Renderable class to display a set of rules in the manage subscriptions page.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rules extends \table_sql implements \renderable {
|
||||
|
||||
/**
|
||||
* @var int course id.
|
||||
*/
|
||||
public $courseid;
|
||||
|
||||
/**
|
||||
* @var int total rules present.
|
||||
*/
|
||||
public $totalcount = 0;
|
||||
|
||||
/**
|
||||
* @var \context_course|\context_system context of the page to be rendered.
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* Sets up the table_log parameters.
|
||||
*
|
||||
* @param string $uniqueid unique id of form.
|
||||
* @param \moodle_url $url url where this table is displayed.
|
||||
* @param int $courseid course id.
|
||||
* @param int $perpage Number of rules to display per page.
|
||||
*/
|
||||
public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) {
|
||||
parent::__construct($uniqueid);
|
||||
|
||||
$this->set_attribute('class', 'toolmonitor subscriberules generaltable generalbox');
|
||||
$this->define_columns(array('name', 'description', 'course', 'plugin', 'eventname', 'filters', 'select'));
|
||||
$this->define_headers(array(
|
||||
get_string('rulename', 'tool_monitor'),
|
||||
get_string('description'),
|
||||
get_string('course'),
|
||||
get_string('area', 'tool_monitor'),
|
||||
get_string('event', 'tool_monitor'),
|
||||
get_string('frequency', 'tool_monitor'),
|
||||
''
|
||||
)
|
||||
);
|
||||
$this->courseid = $courseid;
|
||||
$this->pagesize = $perpage;
|
||||
$systemcontext = \context_system::instance();
|
||||
$this->context = empty($courseid) ? $systemcontext : \context_course::instance($courseid);
|
||||
$this->collapsible(false);
|
||||
$this->sortable(false);
|
||||
$this->pageable(true);
|
||||
$this->is_downloadable(false);
|
||||
$this->define_baseurl($url);
|
||||
$total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid);
|
||||
$this->totalcount = $total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for name column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the rule name.
|
||||
*/
|
||||
public function col_name(\tool_monitor\rule $rule) {
|
||||
return $rule->get_name($this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for description column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the description.
|
||||
*/
|
||||
public function col_description(\tool_monitor\rule $rule) {
|
||||
return $rule->get_description($this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for course column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the course name.
|
||||
*/
|
||||
public function col_course(\tool_monitor\rule $rule) {
|
||||
$coursename = $rule->get_course_name($this->context);
|
||||
|
||||
$courseid = $rule->courseid;
|
||||
if (empty($courseid)) {
|
||||
return $coursename;
|
||||
} else {
|
||||
return \html_writer::link(new \moodle_url('/course/view.php', array('id' => $this->courseid)), $coursename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for plugin column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the plugin name.
|
||||
*/
|
||||
public function col_plugin(\tool_monitor\rule $rule) {
|
||||
return $rule->get_plugin_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for eventname column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the event name.
|
||||
*/
|
||||
public function col_eventname(\tool_monitor\rule $rule) {
|
||||
return $rule->get_event_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for filters column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the filters.
|
||||
*/
|
||||
public function col_filters(\tool_monitor\rule $rule) {
|
||||
return $rule->get_filters_description();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for select column.
|
||||
*
|
||||
* @param \tool_monitor\rule $rule rule object
|
||||
* @return string html used to display the select field.
|
||||
*/
|
||||
public function col_select(\tool_monitor\rule $rule) {
|
||||
global $OUTPUT;
|
||||
|
||||
$options = $rule->get_subscribe_options($this->courseid);
|
||||
$text = get_string('subscribeto', 'tool_monitor', $rule->get_name($this->context));
|
||||
|
||||
if ($options instanceof \single_select) {
|
||||
$options->set_label($text, array('class' => 'accesshide'));
|
||||
return $OUTPUT->render($options);
|
||||
} else if ($options instanceof \moodle_url) {
|
||||
// A \moodle_url to subscribe.
|
||||
$icon = $OUTPUT->pix_icon('t/add', $text);
|
||||
$link = new \action_link($options, $icon);
|
||||
return $OUTPUT->render($link);
|
||||
} else {
|
||||
return $options;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the reader. Store results in the object for use by build_table.
|
||||
*
|
||||
* @param int $pagesize size of page for paginated displayed table.
|
||||
* @param bool $useinitialsbar do you want to use the initials bar.
|
||||
*/
|
||||
public function query_db($pagesize, $useinitialsbar = true) {
|
||||
|
||||
$total = \tool_monitor\rule_manager::count_rules_by_courseid($this->courseid);
|
||||
$this->pagesize($pagesize, $total);
|
||||
$rules = \tool_monitor\rule_manager::get_rules_by_courseid($this->courseid, $this->get_page_start(),
|
||||
$this->get_page_size());
|
||||
$this->rawdata = $rules;
|
||||
// Set initial bars.
|
||||
if ($useinitialsbar) {
|
||||
$this->initialbars($total > $pagesize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of courses where the current user can subscribe to rules as a dropdown.
|
||||
*
|
||||
* @return \single_select|bool returns the list of courses, or false if the select box
|
||||
* should not be displayed.
|
||||
*/
|
||||
public function get_user_courses_select() {
|
||||
global $DB;
|
||||
|
||||
// If the number of courses on the site exceed the maximum drop down limit do not display the select box.
|
||||
$numcourses = $DB->count_records('course');
|
||||
if ($numcourses > COURSE_MAX_COURSES_PER_DROPDOWN) {
|
||||
return false;
|
||||
}
|
||||
$orderby = 'visible DESC, sortorder ASC';
|
||||
$options = array(0 => get_string('site'));
|
||||
if ($courses = get_user_capability_course('tool/monitor:subscribe', null, true, 'fullname', $orderby)) {
|
||||
foreach ($courses as $course) {
|
||||
$options[$course->id] = format_string($course->fullname, true,
|
||||
array('context' => \context_course::instance($course->id)));
|
||||
}
|
||||
}
|
||||
$url = new \moodle_url('/admin/tool/monitor/index.php');
|
||||
$select = new \single_select($url, 'courseid', $options, $this->courseid);
|
||||
$select->set_label(get_string('selectacourse', 'tool_monitor'));
|
||||
return $select;
|
||||
}
|
||||
}
|
||||
@@ -1,197 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Renderable class to display a set of subscriptions in the manage subscriptions page.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\output\managesubs;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
/**
|
||||
* Renderable class to display a set of subscriptions in the manage subscriptions page.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subs extends \table_sql implements \renderable {
|
||||
|
||||
/**
|
||||
* @var int course id.
|
||||
*/
|
||||
public $courseid;
|
||||
|
||||
/**
|
||||
* @var \context_course|\context_system context of the page to be rendered.
|
||||
*/
|
||||
protected $context;
|
||||
|
||||
/**
|
||||
* Sets up the table_log parameters.
|
||||
*
|
||||
* @param string $uniqueid unique id of form.
|
||||
* @param \moodle_url $url url where this table is displayed.
|
||||
* @param int $courseid course id.
|
||||
* @param int $perpage Number of rules to display per page.
|
||||
*/
|
||||
public function __construct($uniqueid, \moodle_url $url, $courseid = 0, $perpage = 100) {
|
||||
parent::__construct($uniqueid);
|
||||
|
||||
$this->set_attribute('class', 'toolmonitor subscriptions generaltable generalbox');
|
||||
$this->define_columns(array('name', 'description', 'course', 'plugin', 'instance', 'eventname',
|
||||
'filters', 'unsubscribe'));
|
||||
$this->define_headers(array(
|
||||
get_string('rulename', 'tool_monitor'),
|
||||
get_string('description'),
|
||||
get_string('course'),
|
||||
get_string('area', 'tool_monitor'),
|
||||
get_string('moduleinstance', 'tool_monitor'),
|
||||
get_string('event', 'tool_monitor'),
|
||||
get_string('frequency', 'tool_monitor'),
|
||||
get_string('unsubscribe', 'tool_monitor')
|
||||
)
|
||||
);
|
||||
$this->courseid = $courseid;
|
||||
$this->pagesize = $perpage;
|
||||
$systemcontext = \context_system::instance();
|
||||
$this->context = empty($courseid) ? $systemcontext : \context_course::instance($courseid);
|
||||
$this->collapsible(false);
|
||||
$this->sortable(false);
|
||||
$this->pageable(true);
|
||||
$this->is_downloadable(false);
|
||||
$this->define_baseurl($url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for name column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the rule name.
|
||||
*/
|
||||
public function col_name(\tool_monitor\subscription $sub) {
|
||||
return $sub->get_name($this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for description column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the description.
|
||||
*/
|
||||
public function col_description(\tool_monitor\subscription $sub) {
|
||||
return $sub->get_description($this->context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for course column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the course name.
|
||||
*/
|
||||
public function col_course(\tool_monitor\subscription $sub) {
|
||||
$coursename = $sub->get_course_name($this->context);
|
||||
|
||||
$courseid = $sub->courseid;
|
||||
if (empty($courseid)) {
|
||||
return $coursename;
|
||||
} else {
|
||||
return \html_writer::link(new \moodle_url('/course/view.php', array('id' => $courseid)), $coursename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for plugin column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the plugin name.
|
||||
*/
|
||||
public function col_plugin(\tool_monitor\subscription $sub) {
|
||||
return $sub->get_plugin_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for instance column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the instance name.
|
||||
*/
|
||||
public function col_instance(\tool_monitor\subscription $sub) {
|
||||
return $sub->get_instance_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for eventname column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the event name.
|
||||
*/
|
||||
public function col_eventname(\tool_monitor\subscription $sub) {
|
||||
return $sub->get_event_name();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for filters column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the filters.
|
||||
*/
|
||||
public function col_filters(\tool_monitor\subscription $sub) {
|
||||
return $sub->get_filters_description();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate content for unsubscribe column.
|
||||
*
|
||||
* @param \tool_monitor\subscription $sub subscription object
|
||||
* @return string html used to display the unsubscribe field.
|
||||
*/
|
||||
public function col_unsubscribe(\tool_monitor\subscription $sub) {
|
||||
global $OUTPUT, $CFG;
|
||||
|
||||
$deleteurl = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array('subscriptionid' => $sub->id,
|
||||
'action' => 'unsubscribe', 'courseid' => $this->courseid, 'sesskey' => sesskey()));
|
||||
$icon = $OUTPUT->render(new \pix_icon('t/delete', get_string('deletesubscription', 'tool_monitor')));
|
||||
|
||||
return \html_writer::link($deleteurl, $icon, array('class' => 'action-icon'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the reader. Store results in the object for use by build_table.
|
||||
*
|
||||
* @param int $pagesize size of page for paginated displayed table.
|
||||
* @param bool $useinitialsbar do you want to use the initials bar.
|
||||
*/
|
||||
public function query_db($pagesize, $useinitialsbar = true) {
|
||||
|
||||
$total = \tool_monitor\subscription_manager::count_user_subscriptions();
|
||||
$this->pagesize($pagesize, $total);
|
||||
$subs = \tool_monitor\subscription_manager::get_user_subscriptions($this->get_page_start(), $this->get_page_size());
|
||||
$this->rawdata = $subs;
|
||||
// Set initial bars.
|
||||
if ($useinitialsbar) {
|
||||
$this->initialbars($total > $pagesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class represents a single rule.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class represents a single rule.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rule {
|
||||
|
||||
/**
|
||||
* @var \stdClass The rule object form database.
|
||||
*/
|
||||
protected $rule;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param \stdClass $rule A rule object from database.
|
||||
*/
|
||||
public function __construct($rule) {
|
||||
$this->rule = $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the current user manage this rule?
|
||||
*
|
||||
* @return bool true if the current user can manage this rule, else false.
|
||||
*/
|
||||
public function can_manage_rule() {
|
||||
$courseid = $this->courseid;
|
||||
$context = empty($courseid) ? \context_system::instance() : \context_course::instance($this->courseid);
|
||||
return has_capability('tool/monitor:managerules', $context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Api to duplicate a rule in a given courseid.
|
||||
*
|
||||
* @param int $finalcourseid Final course id.
|
||||
*/
|
||||
public function duplicate_rule($finalcourseid) {
|
||||
$rule = fullclone($this->rule);
|
||||
unset($rule->id);
|
||||
$rule->courseid = $finalcourseid;
|
||||
$time = time();
|
||||
$rule->timecreated = $time;
|
||||
$rule->timemodified = $time;
|
||||
rule_manager::add_rule($rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete this rule.
|
||||
*
|
||||
* Note: It also removes all associated subscriptions.
|
||||
*/
|
||||
public function delete_rule() {
|
||||
rule_manager::delete_rule($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the rule subscribe options for a given course and rule.
|
||||
*
|
||||
* Could be a select drop down with a list of possible module
|
||||
* instances or a single link to subscribe if the rule plugin
|
||||
* is not a module.
|
||||
*
|
||||
* @param int $courseid course id
|
||||
*
|
||||
* @return \single_select|\moodle_url|string
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_subscribe_options($courseid) {
|
||||
global $CFG;
|
||||
|
||||
$url = new \moodle_url($CFG->wwwroot. '/admin/tool/monitor/index.php', array(
|
||||
'courseid' => $courseid,
|
||||
'ruleid' => $this->id,
|
||||
'action' => 'subscribe',
|
||||
'sesskey' => sesskey()
|
||||
));
|
||||
|
||||
if (strpos($this->plugin, 'mod_') !== 0) {
|
||||
return $url;
|
||||
|
||||
} else {
|
||||
// Single select when the plugin is an activity.
|
||||
$options = array();
|
||||
$options[0] = get_string('allmodules', 'tool_monitor');
|
||||
|
||||
if ($courseid == 0) {
|
||||
// They need to be in a course to select module instance.
|
||||
return get_string('selectcourse', 'tool_monitor');
|
||||
}
|
||||
|
||||
// Let them select an instance.
|
||||
$cms = get_fast_modinfo($courseid);
|
||||
$instances = $cms->get_instances_of(str_replace('mod_', '', $this->plugin));
|
||||
foreach ($instances as $cminfo) {
|
||||
// Don't list instances that are not visible or available to the user.
|
||||
if ($cminfo->uservisible && $cminfo->available) {
|
||||
$options[$cminfo->id] = $cminfo->get_formatted_name();
|
||||
}
|
||||
}
|
||||
|
||||
return new \single_select($url, 'cmid', $options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe an user to this rule.
|
||||
*
|
||||
* @param int $courseid Course id.
|
||||
* @param int $cmid Course module id.
|
||||
* @param int $userid User id.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function subscribe_user($courseid, $cmid, $userid = 0) {
|
||||
global $USER;
|
||||
|
||||
if ($this->courseid != $courseid && $this->courseid != 0) {
|
||||
// Trying to subscribe to a rule that belongs to a different course. Should never happen.
|
||||
throw new \coding_exception('Can not subscribe to rules from a different course');
|
||||
}
|
||||
if ($cmid !== 0) {
|
||||
$cms = get_fast_modinfo($courseid);
|
||||
$cminfo = $cms->get_cm($cmid);
|
||||
if (!$cminfo->uservisible || !$cminfo->available) {
|
||||
// Trying to subscribe to a hidden or restricted cm. Should never happen.
|
||||
throw new \coding_exception('You cannot do that');
|
||||
}
|
||||
}
|
||||
$userid = empty($userid) ? $USER->id : $userid;
|
||||
|
||||
subscription_manager::create_subscription($this->id, $courseid, $cmid, $userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic get method.
|
||||
*
|
||||
* @param string $prop property to get.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function __get($prop) {
|
||||
if (property_exists($this->rule, $prop)) {
|
||||
return $this->rule->$prop;
|
||||
}
|
||||
throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rule data to be used while setting mform.
|
||||
*
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_mform_set_data() {
|
||||
if (!empty($this->rule)) {
|
||||
$rule = fullclone($this->rule);
|
||||
$rule->description = array('text' => $rule->description, 'format' => $rule->descriptionformat);
|
||||
$rule->template = array('text' => $rule->template, 'format' => $rule->templateformat);
|
||||
return $rule;
|
||||
}
|
||||
throw new \coding_exception('Invalid call to get_mform_set_data.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get event name.
|
||||
*
|
||||
* @return string
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_event_name() {
|
||||
$eventclass = $this->eventname;
|
||||
if (class_exists($eventclass)) {
|
||||
return $eventclass::get_name();
|
||||
}
|
||||
return get_string('eventnotfound', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_filters_description() {
|
||||
$a = new \stdClass();
|
||||
$a->freq = $this->frequency;
|
||||
$mins = $this->timewindow / MINSECS; // Convert seconds to minutes.
|
||||
$a->mins = $mins;
|
||||
return get_string('freqdesc', 'tool_monitor', $a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properly formatted name of the course associated.
|
||||
*
|
||||
* @param \context $context context where this name would be displayed.
|
||||
* @return string The course fullname.
|
||||
*/
|
||||
public function get_course_name($context) {
|
||||
$courseid = $this->courseid;
|
||||
if (empty($courseid)) {
|
||||
return get_string('site');
|
||||
} else {
|
||||
$course = get_course($courseid);
|
||||
return format_string($course->fullname, true, array('context' => $context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properly formatted name of the rule associated.
|
||||
*
|
||||
* @param \context $context context where this name would be displayed.
|
||||
* @return string Formatted name of the rule.
|
||||
*/
|
||||
public function get_name(\context $context) {
|
||||
return format_text($this->name, FORMAT_HTML, array('context' => $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properly formatted description of the rule associated.
|
||||
*
|
||||
* @param \context $context context where this description would be displayed.
|
||||
* @return string Formatted description of the rule.
|
||||
*/
|
||||
public function get_description(\context $context) {
|
||||
return format_text($this->description, $this->descriptionformat, array('context' => $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name of the plugin associated with this rule
|
||||
*
|
||||
* @return string Plugin name.
|
||||
*/
|
||||
public function get_plugin_name() {
|
||||
if ($this->plugin === 'core') {
|
||||
$string = get_string('core', 'tool_monitor');
|
||||
} else if (get_string_manager()->string_exists('pluginname', $this->plugin)) {
|
||||
$string = get_string('pluginname', $this->plugin);
|
||||
} else {
|
||||
$string = $this->plugin;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* The mform for creating and editing a rule.
|
||||
*
|
||||
* @copyright 2014 onwards Simey Lameze <lameze@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package tool_monitor
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
require_once($CFG->dirroot.'/lib/formslib.php');
|
||||
|
||||
/**
|
||||
* The mform for creating and editing a rule.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @copyright 2014 onwards Simey Lameze <lameze@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @package tool_monitor
|
||||
*/
|
||||
class rule_form extends \moodleform {
|
||||
|
||||
/**
|
||||
* Mform class definition
|
||||
*
|
||||
*/
|
||||
public function definition () {
|
||||
$mform = $this->_form;
|
||||
$eventlist = $this->_customdata['eventlist'];
|
||||
$pluginlist = $this->_customdata['pluginlist'];
|
||||
$rule = $this->_customdata['rule'];
|
||||
$courseid = $this->_customdata['courseid'];
|
||||
$subscriptioncount = $this->_customdata['subscriptioncount'];
|
||||
|
||||
// General section header.
|
||||
$mform->addElement('header', 'general', get_string('general'));
|
||||
|
||||
// Hidden course ID.
|
||||
$mform->addElement('hidden', 'courseid');
|
||||
$mform->setType('courseid', PARAM_INT);
|
||||
|
||||
// We are editing a existing rule.
|
||||
if (!empty($rule->id)) {
|
||||
// Hidden rule id.
|
||||
$mform->addElement('hidden', 'ruleid');
|
||||
$mform->setType('ruleid', PARAM_INT);
|
||||
$mform->setConstant('ruleid', $rule->id);
|
||||
|
||||
// Force course id.
|
||||
$courseid = $rule->courseid;
|
||||
}
|
||||
|
||||
// Make course id a constant.
|
||||
$mform->setConstant('courseid', $courseid);
|
||||
|
||||
if (empty($courseid)) {
|
||||
$context = \context_system::instance();
|
||||
} else {
|
||||
$context = \context_course::instance($courseid);
|
||||
}
|
||||
|
||||
$editoroptions = array(
|
||||
'subdirs' => 0,
|
||||
'maxbytes' => 0,
|
||||
'maxfiles' => 0,
|
||||
'changeformat' => 0,
|
||||
'context' => $context,
|
||||
'noclean' => 0,
|
||||
'trusttext' => 0
|
||||
);
|
||||
|
||||
// Name field.
|
||||
$mform->addElement('text', 'name', get_string('rulename', 'tool_monitor'), 'size="50"');
|
||||
$mform->addRule('name', get_string('required'), 'required');
|
||||
$mform->setType('name', PARAM_TEXT);
|
||||
|
||||
// Plugin field.
|
||||
$mform->addElement('select', 'plugin', get_string('areatomonitor', 'tool_monitor'), $pluginlist);
|
||||
$mform->addRule('plugin', get_string('required'), 'required');
|
||||
|
||||
// Event field.
|
||||
$mform->addElement('select', 'eventname', get_string('event', 'tool_monitor'), $eventlist);
|
||||
$mform->addRule('eventname', get_string('required'), 'required');
|
||||
|
||||
// Freeze plugin and event fields for editing if there's a subscription for this rule.
|
||||
if ($subscriptioncount > 0) {
|
||||
$mform->freeze('plugin');
|
||||
$mform->setConstant('plugin', $rule->plugin);
|
||||
$mform->freeze('eventname');
|
||||
$mform->setConstant('eventname', $rule->eventname);
|
||||
}
|
||||
|
||||
// Description field.
|
||||
$mform->addElement('editor', 'description', get_string('description'), $editoroptions);
|
||||
|
||||
// Filters.
|
||||
$freq = array(1 => 1, 5 => 5, 10 => 10, 20 => 20, 30 => 30, 40 => 40, 50 => 50, 60 => 60, 70 => 70, 80 => 80, 90 => 90,
|
||||
100 => 100, 1000 => 1000);
|
||||
$mform->addElement('select', 'frequency', get_string('frequency', 'tool_monitor'), $freq);
|
||||
$mform->addRule('frequency', get_string('required'), 'required');
|
||||
$mform->addHelpButton('frequency', 'frequency', 'tool_monitor');
|
||||
|
||||
$mins = array(1 => 1, 5 => 5, 10 => 10, 15 => 15, 20 => 20, 25 => 25, 30 => 30, 35 => 35, 40 => 40, 45 => 45, 50 => 50,
|
||||
55 => 55, 60 => 60);
|
||||
$mform->addElement('select', 'minutes', get_string('inminutes', 'tool_monitor'), $mins);
|
||||
$mform->addRule('minutes', get_string('required'), 'required');
|
||||
|
||||
// Message template.
|
||||
$mform->addElement('editor', 'template', get_string('messagetemplate', 'tool_monitor'), $editoroptions);
|
||||
$mform->setDefault('template', array('text' => get_string('defaultmessagetemplate', 'tool_monitor'),
|
||||
'format' => FORMAT_HTML));
|
||||
$mform->addRule('template', get_string('required'), 'required');
|
||||
$mform->addHelpButton('template', 'messagetemplate', 'tool_monitor');
|
||||
|
||||
// Action buttons.
|
||||
$this->add_action_buttons(true, get_string('savechanges'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Form validation
|
||||
*
|
||||
* @param array $data data from the form.
|
||||
* @param array $files files uploaded.
|
||||
*
|
||||
* @return array of errors.
|
||||
*/
|
||||
public function validation($data, $files) {
|
||||
$errors = parent::validation($data, $files);
|
||||
|
||||
if (!eventlist::validate_event_plugin($data['plugin'], $data['eventname'])) {
|
||||
$errors['eventname'] = get_string('errorincorrectevent', 'tool_monitor');
|
||||
}
|
||||
|
||||
return $errors;
|
||||
}
|
||||
}
|
||||
@@ -1,290 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Rule manager class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Simey Lameze <lameze@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Rule manager class.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Simey Lameze <lameze@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class rule_manager {
|
||||
|
||||
/**
|
||||
* Create a new rule.
|
||||
*
|
||||
* @param \stdClass $ruledata data to insert as new rule entry.
|
||||
*
|
||||
* @return rule An instance of rule class.
|
||||
*/
|
||||
public static function add_rule($ruledata) {
|
||||
global $DB;
|
||||
|
||||
$now = time();
|
||||
$ruledata->timecreated = $now;
|
||||
$ruledata->timemodified = $now;
|
||||
|
||||
$ruledata->id = $DB->insert_record('tool_monitor_rules', $ruledata);
|
||||
|
||||
// Trigger a rule created event.
|
||||
if ($ruledata->id) {
|
||||
if (!empty($ruledata->courseid)) {
|
||||
$courseid = $ruledata->courseid;
|
||||
$context = \context_course::instance($ruledata->courseid);
|
||||
} else {
|
||||
$courseid = 0;
|
||||
$context = \context_system::instance();
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'objectid' => $ruledata->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => $context
|
||||
);
|
||||
$event = \tool_monitor\event\rule_created::create($params);
|
||||
$event->trigger();
|
||||
}
|
||||
|
||||
return new rule($ruledata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean data submitted by mform.
|
||||
*
|
||||
* @param \stdClass $mformdata data to insert as new rule entry.
|
||||
*
|
||||
* @return \stdClass Cleaned rule data.
|
||||
*/
|
||||
public static function clean_ruledata_form($mformdata) {
|
||||
global $USER;
|
||||
|
||||
$rule = new \stdClass();
|
||||
if (!empty($mformdata->ruleid)) {
|
||||
$rule->id = $mformdata->ruleid;
|
||||
}
|
||||
$rule->userid = empty($mformdata->userid) ? $USER->id : $mformdata->userid;
|
||||
$rule->courseid = $mformdata->courseid;
|
||||
$rule->name = $mformdata->name;
|
||||
$rule->plugin = $mformdata->plugin;
|
||||
$rule->eventname = $mformdata->eventname;
|
||||
$rule->description = $mformdata->description['text'];
|
||||
$rule->descriptionformat = $mformdata->description['format'];
|
||||
$rule->frequency = $mformdata->frequency;
|
||||
$rule->timewindow = $mformdata->minutes * MINSECS;
|
||||
$rule->template = $mformdata->template['text'];
|
||||
$rule->templateformat = $mformdata->template['format'];
|
||||
|
||||
return $rule;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a rule and associated subscriptions, by rule id.
|
||||
*
|
||||
* @param int $ruleid id of rule to be deleted.
|
||||
* @param \context|null $coursecontext the context of the course - this is passed when we
|
||||
* can not get the context via \context_course as the course has been deleted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete_rule($ruleid, $coursecontext = null) {
|
||||
global $DB;
|
||||
|
||||
subscription_manager::remove_all_subscriptions_for_rule($ruleid, $coursecontext);
|
||||
|
||||
// Retrieve the rule from the DB before we delete it, so we have a record when we trigger a rule deleted event.
|
||||
$rule = $DB->get_record('tool_monitor_rules', array('id' => $ruleid));
|
||||
|
||||
$success = $DB->delete_records('tool_monitor_rules', array('id' => $ruleid));
|
||||
|
||||
// If successful trigger a rule deleted event.
|
||||
if ($success) {
|
||||
// It is possible that we are deleting rules associated with a deleted course, so we should be
|
||||
// passing the context as the second parameter.
|
||||
if (!is_null($coursecontext)) {
|
||||
$context = $coursecontext;
|
||||
$courseid = $rule->courseid;
|
||||
} else if (!empty($rule->courseid) && ($context = \context_course::instance($rule->courseid,
|
||||
IGNORE_MISSING))) {
|
||||
$courseid = $rule->courseid;
|
||||
} else {
|
||||
$courseid = 0;
|
||||
$context = \context_system::instance();
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'objectid' => $rule->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => $context
|
||||
);
|
||||
$event = \tool_monitor\event\rule_deleted::create($params);
|
||||
$event->add_record_snapshot('tool_monitor_rules', $rule);
|
||||
$event->trigger();
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an instance of rule class.
|
||||
*
|
||||
* @param \stdClass|int $ruleorid A rule object from database or rule id.
|
||||
*
|
||||
* @return rule object with rule id.
|
||||
*/
|
||||
public static function get_rule($ruleorid) {
|
||||
global $DB;
|
||||
if (!is_object($ruleorid)) {
|
||||
$rule = $DB->get_record('tool_monitor_rules', array('id' => $ruleorid), '*', MUST_EXIST);
|
||||
} else {
|
||||
$rule = $ruleorid;
|
||||
}
|
||||
|
||||
return new rule($rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update rule data.
|
||||
*
|
||||
* @throws \coding_exception if $record->ruleid is invalid.
|
||||
* @param object $ruledata rule data to be updated.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function update_rule($ruledata) {
|
||||
global $DB;
|
||||
if (!self::get_rule($ruledata->id)) {
|
||||
throw new \coding_exception('Invalid rule ID.');
|
||||
}
|
||||
$ruledata->timemodified = time();
|
||||
|
||||
$success = $DB->update_record('tool_monitor_rules', $ruledata);
|
||||
|
||||
// If successful trigger a rule updated event.
|
||||
if ($success) {
|
||||
// If we do not have the course id we need to retrieve it.
|
||||
if (!isset($ruledata->courseid)) {
|
||||
$courseid = $DB->get_field('tool_monitor_rules', 'courseid', array('id' => $ruledata->id), MUST_EXIST);
|
||||
} else {
|
||||
$courseid = $ruledata->courseid;
|
||||
}
|
||||
|
||||
if (!empty($courseid)) {
|
||||
$context = \context_course::instance($courseid);
|
||||
} else {
|
||||
$context = \context_system::instance();
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'objectid' => $ruledata->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => $context
|
||||
);
|
||||
$event = \tool_monitor\event\rule_updated::create($params);
|
||||
$event->trigger();
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rules by course id.
|
||||
*
|
||||
* @param int $courseid course id of the rule.
|
||||
* @param int $limitfrom Limit from which to fetch rules.
|
||||
* @param int $limitto Limit to which rules need to be fetched.
|
||||
* @param bool $includesite Determines whether we return site wide rules or not.
|
||||
*
|
||||
* @return array List of rules for the given course id, if specified will also include site rules.
|
||||
*/
|
||||
public static function get_rules_by_courseid($courseid, $limitfrom = 0, $limitto = 0, $includesite = true) {
|
||||
global $DB;
|
||||
|
||||
$select = 'courseid = ?';
|
||||
$params = array();
|
||||
$params[] = $courseid;
|
||||
if ($includesite) {
|
||||
$select .= ' OR courseid = ?';
|
||||
$params[] = 0;
|
||||
}
|
||||
$orderby = 'courseid DESC, name ASC';
|
||||
|
||||
return self::get_instances($DB->get_records_select('tool_monitor_rules', $select, $params, $orderby,
|
||||
'*', $limitfrom, $limitto));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rule count by course id.
|
||||
*
|
||||
* @param int $courseid course id of the rule.
|
||||
*
|
||||
* @return int count of rules present in system visible in the given course id.
|
||||
*/
|
||||
public static function count_rules_by_courseid($courseid) {
|
||||
global $DB;
|
||||
$select = "courseid = ? OR courseid = ?";
|
||||
return $DB->count_records_select('tool_monitor_rules', $select, array(0, $courseid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rules by plugin name.
|
||||
*
|
||||
* @param string $plugin plugin name of the rule.
|
||||
*
|
||||
* @return array List of rules for the given plugin name.
|
||||
*/
|
||||
public static function get_rules_by_plugin($plugin) {
|
||||
global $DB;
|
||||
return self::get_instances($DB->get_records('tool_monitor_rules', array('plugin' => $plugin)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rules by event name.
|
||||
*
|
||||
* @param string $eventname event name of the rule.
|
||||
*
|
||||
* @return array List of rules for the given event.
|
||||
*/
|
||||
public static function get_rules_by_event($eventname) {
|
||||
global $DB;
|
||||
return self::get_instances($DB->get_records('tool_monitor_rules', array('eventname' => $eventname)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert db records to instances.
|
||||
*
|
||||
* @param array $arr of rules.
|
||||
*
|
||||
* @return array of rules as instances.
|
||||
*/
|
||||
protected static function get_instances($arr) {
|
||||
$result = array();
|
||||
foreach ($arr as $key => $sub) {
|
||||
$result[$key] = new rule($sub);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class represents a single subscription.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class represents a single subscription instance (i.e with all the subscription info).
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription {
|
||||
/**
|
||||
* @var \stdClass
|
||||
*/
|
||||
protected $subscription;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* use {@link \tool_monitor\subscription_manager::get_subscription} to get an instance instead of directly calling this method.
|
||||
*
|
||||
* @param \stdClass $subscription
|
||||
*/
|
||||
public function __construct($subscription) {
|
||||
$this->subscription = $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)) {
|
||||
return $this->subscription->$prop;
|
||||
}
|
||||
throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a human readable name for instances associated with this subscription.
|
||||
*
|
||||
* @return string
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_instance_name() {
|
||||
if ($this->plugin === 'core') {
|
||||
$string = get_string('allevents', 'tool_monitor');
|
||||
} else {
|
||||
if ($this->cmid == 0) {
|
||||
$string = get_string('allmodules', 'tool_monitor');
|
||||
} else {
|
||||
$cms = get_fast_modinfo($this->courseid);
|
||||
$cms = $cms->get_cms();
|
||||
if (isset($cms[$this->cmid])) {
|
||||
$string = $cms[$this->cmid]->get_formatted_name(); // Instance name.
|
||||
} else {
|
||||
// Something is wrong, instance is not present anymore.
|
||||
$string = get_string('invalidmodule', 'tool_monitor');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to get event name.
|
||||
*
|
||||
* @return string
|
||||
* @throws \coding_exception
|
||||
*/
|
||||
public function get_event_name() {
|
||||
$eventclass = $this->eventname;
|
||||
if (class_exists($eventclass)) {
|
||||
return $eventclass::get_name();
|
||||
}
|
||||
return get_string('eventnotfound', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filter description.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_filters_description() {
|
||||
$a = new \stdClass();
|
||||
$a->freq = $this->frequency;
|
||||
$mins = $this->timewindow / MINSECS; // Convert seconds to minutes.
|
||||
$a->mins = $mins;
|
||||
return get_string('freqdesc', 'tool_monitor', $a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properly formatted name of the rule associated.
|
||||
*
|
||||
* @param \context $context context where this name would be displayed.
|
||||
* @return string Formatted name of the rule.
|
||||
*/
|
||||
public function get_name(\context $context) {
|
||||
return format_text($this->name, FORMAT_HTML, array('context' => $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properly formatted description of the rule associated.
|
||||
*
|
||||
* @param \context $context context where this description would be displayed.
|
||||
* @return string Formatted description of the rule.
|
||||
*/
|
||||
public function get_description(\context $context) {
|
||||
return format_text($this->description, $this->descriptionformat, array('context' => $context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get name of the plugin associated with this rule
|
||||
*
|
||||
* @return string Plugin name.
|
||||
*/
|
||||
public function get_plugin_name() {
|
||||
if ($this->plugin === 'core') {
|
||||
$string = get_string('core', 'tool_monitor');
|
||||
} else if (get_string_manager()->string_exists('pluginname', $this->plugin)) {
|
||||
$string = get_string('pluginname', $this->plugin);
|
||||
} else {
|
||||
$string = $this->plugin;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get properly formatted name of the course associated.
|
||||
*
|
||||
* @param \context $context context where this name would be displayed.
|
||||
* @return string Formatted name of the rule.
|
||||
*/
|
||||
public function get_course_name(\context $context) {
|
||||
$courseid = $this->courseid;
|
||||
if (empty($courseid)) {
|
||||
return get_string('site');
|
||||
} else {
|
||||
$course = get_course($courseid);
|
||||
return format_string($course->fullname, true, array('context' => $context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can the current user manage the rule associate with this subscription?
|
||||
*
|
||||
* @return bool true if the current user can manage this rule, else false.
|
||||
*/
|
||||
public function can_manage_rule() {
|
||||
$courseid = $this->rulecourseid;
|
||||
$context = empty($courseid) ? \context_system::instance() : \context_course::instance($courseid);
|
||||
return has_capability('tool/monitor:managerules', $context);
|
||||
}
|
||||
}
|
||||
@@ -1,459 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Class to manage subscriptions.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Class to manage subscriptions.
|
||||
*
|
||||
* @since Moodle 2.8
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class subscription_manager {
|
||||
/**
|
||||
* Subscribe a user to a given rule.
|
||||
*
|
||||
* @param int $ruleid Rule id.
|
||||
* @param int $courseid Course id.
|
||||
* @param int $cmid Course module id.
|
||||
* @param int $userid User who is subscribing, defaults to $USER.
|
||||
*
|
||||
* @return bool|int returns id of the created subscription.
|
||||
*/
|
||||
public static function create_subscription($ruleid, $courseid, $cmid, $userid = 0) {
|
||||
global $DB, $USER;
|
||||
|
||||
$subscription = new \stdClass();
|
||||
$subscription->ruleid = $ruleid;
|
||||
$subscription->courseid = $courseid;
|
||||
$subscription->cmid = $cmid;
|
||||
$subscription->userid = empty($userid) ? $USER->id : $userid;
|
||||
if ($DB->record_exists('tool_monitor_subscriptions', (array)$subscription)) {
|
||||
// Subscription already exists.
|
||||
return false;
|
||||
}
|
||||
|
||||
$subscription->timecreated = time();
|
||||
$subscription->id = $DB->insert_record('tool_monitor_subscriptions', $subscription);
|
||||
|
||||
// Trigger a subscription created event.
|
||||
if ($subscription->id) {
|
||||
if (!empty($subscription->courseid)) {
|
||||
$courseid = $subscription->courseid;
|
||||
$context = \context_course::instance($subscription->courseid);
|
||||
} else {
|
||||
$courseid = 0;
|
||||
$context = \context_system::instance();
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'objectid' => $subscription->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => $context
|
||||
);
|
||||
$event = \tool_monitor\event\subscription_created::create($params);
|
||||
$event->trigger();
|
||||
|
||||
// Let's invalidate the cache.
|
||||
$cache = \cache::make('tool_monitor', 'eventsubscriptions');
|
||||
$cache->delete($courseid);
|
||||
}
|
||||
|
||||
return $subscription->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a subscription.
|
||||
*
|
||||
* @param subscription|int $subscriptionorid an instance of subscription class or id.
|
||||
* @param bool $checkuser Check if the subscription belongs to current user before deleting.
|
||||
*
|
||||
* @return bool
|
||||
* @throws \coding_exception if $checkuser is true and the subscription doesn't belong to the current user.
|
||||
*/
|
||||
public static function delete_subscription($subscriptionorid, $checkuser = true) {
|
||||
global $DB, $USER;
|
||||
if (is_object($subscriptionorid)) {
|
||||
$subscription = $subscriptionorid;
|
||||
} else {
|
||||
$subscription = self::get_subscription($subscriptionorid);
|
||||
}
|
||||
if ($checkuser && $subscription->userid != $USER->id) {
|
||||
throw new \coding_exception('Invalid subscription supplied');
|
||||
}
|
||||
|
||||
// Store the subscription before we delete it.
|
||||
$subscription = $DB->get_record('tool_monitor_subscriptions', array('id' => $subscription->id));
|
||||
|
||||
$success = $DB->delete_records('tool_monitor_subscriptions', array('id' => $subscription->id));
|
||||
|
||||
// If successful trigger a subscription_deleted event.
|
||||
if ($success) {
|
||||
if (!empty($subscription->courseid)) {
|
||||
$courseid = $subscription->courseid;
|
||||
$context = \context_course::instance($subscription->courseid);
|
||||
} else {
|
||||
$courseid = 0;
|
||||
$context = \context_system::instance();
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'objectid' => $subscription->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => $context
|
||||
);
|
||||
$event = \tool_monitor\event\subscription_deleted::create($params);
|
||||
$event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
|
||||
$event->trigger();
|
||||
|
||||
// Let's invalidate the cache.
|
||||
$cache = \cache::make('tool_monitor', 'eventsubscriptions');
|
||||
$cache->delete($courseid);
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all subscriptions for a user.
|
||||
*
|
||||
* @param int $userid user id.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function delete_user_subscriptions($userid) {
|
||||
global $DB;
|
||||
return $DB->delete_records('tool_monitor_subscriptions', array('userid' => $userid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all subscriptions for a course module.
|
||||
*
|
||||
* @param int $cmid cm id.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function delete_cm_subscriptions($cmid) {
|
||||
global $DB;
|
||||
return $DB->delete_records('tool_monitor_subscriptions', array('cmid' => $cmid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all subscribers for a given rule.
|
||||
*
|
||||
* @param int $ruleid rule id.
|
||||
* @param \context|null $coursecontext the context of the course - this is passed when we
|
||||
* can not get the context via \context_course as the course has been deleted.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function remove_all_subscriptions_for_rule($ruleid, $coursecontext = null) {
|
||||
global $DB;
|
||||
|
||||
// Store all the subscriptions we have to delete.
|
||||
$subscriptions = $DB->get_recordset('tool_monitor_subscriptions', array('ruleid' => $ruleid));
|
||||
|
||||
// Now delete them.
|
||||
$success = $DB->delete_records('tool_monitor_subscriptions', array('ruleid' => $ruleid));
|
||||
|
||||
// If successful and there were subscriptions that were deleted trigger a subscription deleted event.
|
||||
if ($success && $subscriptions) {
|
||||
foreach ($subscriptions as $subscription) {
|
||||
// It is possible that we are deleting rules associated with a deleted course, so we should be
|
||||
// passing the context as the second parameter.
|
||||
if (!is_null($coursecontext)) {
|
||||
$context = $coursecontext;
|
||||
$courseid = $subscription->courseid;
|
||||
} else if (!empty($subscription->courseid) && ($coursecontext =
|
||||
\context_course::instance($subscription->courseid, IGNORE_MISSING))) {
|
||||
$courseid = $subscription->courseid;
|
||||
$context = $coursecontext;
|
||||
} else {
|
||||
$courseid = 0;
|
||||
$context = \context_system::instance();
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'objectid' => $subscription->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => $context
|
||||
);
|
||||
$event = \tool_monitor\event\subscription_deleted::create($params);
|
||||
$event->add_record_snapshot('tool_monitor_subscriptions', $subscription);
|
||||
$event->trigger();
|
||||
|
||||
// Let's invalidate the cache.
|
||||
$cache = \cache::make('tool_monitor', 'eventsubscriptions');
|
||||
$cache->delete($courseid);
|
||||
}
|
||||
}
|
||||
|
||||
$subscriptions->close();
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a subscription instance for an given subscription id.
|
||||
*
|
||||
* @param subscription|int $subscriptionorid an instance of subscription class or id.
|
||||
*
|
||||
* @return subscription returns a instance of subscription class.
|
||||
*/
|
||||
public static function get_subscription($subscriptionorid) {
|
||||
global $DB;
|
||||
|
||||
if (is_object($subscriptionorid)) {
|
||||
return new subscription($subscriptionorid);
|
||||
}
|
||||
|
||||
$sql = self::get_subscription_join_rule_sql();
|
||||
$sql .= "WHERE s.id = :id";
|
||||
$sub = $DB->get_record_sql($sql, array('id' => $subscriptionorid), MUST_EXIST);
|
||||
return new subscription($sub);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of subscriptions for a given user in a given course.
|
||||
*
|
||||
* @param int $courseid course id.
|
||||
* @param int $limitfrom Limit from which to fetch rules.
|
||||
* @param int $limitto Limit to which rules need to be fetched.
|
||||
* @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
|
||||
* @param string $order Order to sort the subscriptions.
|
||||
*
|
||||
* @return array list of subscriptions
|
||||
*/
|
||||
public static function get_user_subscriptions_for_course($courseid, $limitfrom = 0, $limitto = 0, $userid = 0,
|
||||
$order = 's.timecreated DESC' ) {
|
||||
global $DB, $USER;
|
||||
if ($userid == 0) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
$sql = self::get_subscription_join_rule_sql();
|
||||
$sql .= "WHERE s.courseid = :courseid AND s.userid = :userid ORDER BY $order";
|
||||
|
||||
return self::get_instances($DB->get_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid), $limitfrom,
|
||||
$limitto));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of subscriptions for a given user in a given course.
|
||||
*
|
||||
* @param int $courseid course id.
|
||||
* @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
|
||||
*
|
||||
* @return int number of subscriptions
|
||||
*/
|
||||
public static function count_user_subscriptions_for_course($courseid, $userid = 0) {
|
||||
global $DB, $USER;
|
||||
if ($userid == 0) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
$sql = self::get_subscription_join_rule_sql(true);
|
||||
$sql .= "WHERE s.courseid = :courseid AND s.userid = :userid";
|
||||
|
||||
return $DB->count_records_sql($sql, array('courseid' => $courseid, 'userid' => $userid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array of subscriptions for a given user.
|
||||
*
|
||||
* @param int $limitfrom Limit from which to fetch rules.
|
||||
* @param int $limitto Limit to which rules need to be fetched.
|
||||
* @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
|
||||
* @param string $order Order to sort the subscriptions.
|
||||
*
|
||||
* @return array list of subscriptions
|
||||
*/
|
||||
public static function get_user_subscriptions($limitfrom = 0, $limitto = 0, $userid = 0,
|
||||
$order = 's.courseid ASC, r.name' ) {
|
||||
global $DB, $USER;
|
||||
if ($userid == 0) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
$sql = self::get_subscription_join_rule_sql();
|
||||
$sql .= "WHERE s.userid = :userid ORDER BY $order";
|
||||
|
||||
return self::get_instances($DB->get_records_sql($sql, array('userid' => $userid), $limitfrom, $limitto));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of subscriptions for a given user.
|
||||
*
|
||||
* @param int $userid Id of the user for which the subscription needs to be fetched. Defaults to $USER;
|
||||
*
|
||||
* @return int number of subscriptions
|
||||
*/
|
||||
public static function count_user_subscriptions($userid = 0) {
|
||||
global $DB, $USER;;
|
||||
if ($userid == 0) {
|
||||
$userid = $USER->id;
|
||||
}
|
||||
$sql = self::get_subscription_join_rule_sql(true);
|
||||
$sql .= "WHERE s.userid = :userid";
|
||||
|
||||
return $DB->count_records_sql($sql, array('userid' => $userid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of subscriptions for a given event.
|
||||
*
|
||||
* @param \stdClass $event the event object.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscriptions_by_event(\stdClass $event) {
|
||||
global $DB;
|
||||
|
||||
$sql = self::get_subscription_join_rule_sql();
|
||||
if ($event->contextlevel == CONTEXT_MODULE && $event->contextinstanceid != 0) {
|
||||
$sql .= "WHERE r.eventname = :eventname AND s.courseid = :courseid AND (s.cmid = :cmid OR s.cmid = 0)";
|
||||
$params = array('eventname' => $event->eventname, 'courseid' => $event->courseid, 'cmid' => $event->contextinstanceid);
|
||||
} else {
|
||||
$sql .= "WHERE r.eventname = :eventname AND (s.courseid = :courseid OR s.courseid = 0)";
|
||||
$params = array('eventname' => $event->eventname, 'courseid' => $event->courseid);
|
||||
}
|
||||
return self::get_instances($DB->get_records_sql($sql, $params));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return sql to join rule and subscription table.
|
||||
*
|
||||
* @param bool $count Weather if this is a count query or not.
|
||||
*
|
||||
* @return string the sql.
|
||||
*/
|
||||
protected static function get_subscription_join_rule_sql($count = false) {
|
||||
if ($count) {
|
||||
$select = "SELECT COUNT(s.id) ";
|
||||
} else {
|
||||
$select = "SELECT s.*, r.description, r.descriptionformat, r.name, r.userid as ruleuserid, r.courseid as rulecourseid,
|
||||
r.plugin, r.eventname, r.template, r.templateformat, r.frequency, r.timewindow";
|
||||
}
|
||||
$sql = $select . "
|
||||
FROM {tool_monitor_rules} r
|
||||
JOIN {tool_monitor_subscriptions} s
|
||||
ON r.id = s.ruleid ";
|
||||
return $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to convert db records to instances.
|
||||
*
|
||||
* @param array $arr of subscriptions.
|
||||
*
|
||||
* @return array of subscriptions as instances.
|
||||
*/
|
||||
protected static function get_instances($arr) {
|
||||
$result = array();
|
||||
foreach ($arr as $key => $sub) {
|
||||
$result[$key] = new subscription($sub);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of subscriptions for a given rule.
|
||||
*
|
||||
* @param int $ruleid rule id of the subscription.
|
||||
*
|
||||
* @return int number of subscriptions
|
||||
*/
|
||||
public static function count_rule_subscriptions($ruleid) {
|
||||
global $DB;
|
||||
$sql = self::get_subscription_join_rule_sql(true);
|
||||
$sql .= "WHERE s.ruleid = :ruleid";
|
||||
|
||||
return $DB->count_records_sql($sql, array('ruleid' => $ruleid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if an event in a particular course has a subscription.
|
||||
*
|
||||
* @param string $eventname the name of the event
|
||||
* @param int $courseid the course id
|
||||
* @return bool returns true if the event has subscriptions in a given course, false otherwise.
|
||||
*/
|
||||
public static function event_has_subscriptions($eventname, $courseid) {
|
||||
global $DB;
|
||||
|
||||
// Check if we can return these from cache.
|
||||
$cache = \cache::make('tool_monitor', 'eventsubscriptions');
|
||||
|
||||
// The SQL we will be using to fill the cache if it is empty.
|
||||
$sql = "SELECT DISTINCT(r.eventname)
|
||||
FROM {tool_monitor_subscriptions} s
|
||||
INNER JOIN {tool_monitor_rules} r
|
||||
ON s.ruleid = r.id
|
||||
WHERE s.courseid = :courseid";
|
||||
|
||||
$sitesubscriptions = $cache->get(0);
|
||||
// If we do not have the site subscriptions in the cache then return them from the DB.
|
||||
if ($sitesubscriptions === false) {
|
||||
// Set the array for the cache.
|
||||
$sitesubscriptions = array();
|
||||
if ($subscriptions = $DB->get_records_sql($sql, array('courseid' => 0))) {
|
||||
foreach ($subscriptions as $subscription) {
|
||||
$sitesubscriptions[$subscription->eventname] = true;
|
||||
}
|
||||
}
|
||||
$cache->set(0, $sitesubscriptions);
|
||||
}
|
||||
|
||||
// Check if a subscription exists for this event site wide.
|
||||
if (isset($sitesubscriptions[$eventname])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the course id is for the site, and we reached here then there is no site wide subscription for this event.
|
||||
if (empty($courseid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$coursesubscriptions = $cache->get($courseid);
|
||||
// If we do not have the course subscriptions in the cache then return them from the DB.
|
||||
if ($coursesubscriptions === false) {
|
||||
// Set the array for the cache.
|
||||
$coursesubscriptions = array();
|
||||
if ($subscriptions = $DB->get_records_sql($sql, array('courseid' => $courseid))) {
|
||||
foreach ($subscriptions as $subscription) {
|
||||
$coursesubscriptions[$subscription->eventname] = true;
|
||||
}
|
||||
}
|
||||
$cache->set($courseid, $coursesubscriptions);
|
||||
}
|
||||
|
||||
// Check if a subscription exists for this event in this course.
|
||||
if (isset($coursesubscriptions[$eventname])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Clean the tool_monitor_events table.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
namespace tool_monitor\task;
|
||||
|
||||
/**
|
||||
* Simple task to clean the tool_monitor_events table.
|
||||
*/
|
||||
class clean_events extends \core\task\scheduled_task {
|
||||
|
||||
/**
|
||||
* Get a descriptive name for this task.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name() {
|
||||
return get_string('taskcleanevents', 'tool_monitor');
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the cleaning of events.
|
||||
*/
|
||||
public function execute() {
|
||||
global $DB;
|
||||
|
||||
if (!get_config('tool_monitor', 'enablemonitor')) {
|
||||
return; // The tool is disabled. Nothing to do.
|
||||
}
|
||||
|
||||
// Array to store which events have been triggered in which course.
|
||||
$courses = array();
|
||||
|
||||
// Firstly, let's go through the site wide rules. There may be multiple rules for the site that rely on
|
||||
// the same event being triggered, so we only remove the events when they reach the max timewindow.
|
||||
if ($siterules = $DB->get_recordset('tool_monitor_rules', array('courseid' => 0), 'timewindow DESC')) {
|
||||
// Go through each rule and check if there are any events we can remove.
|
||||
foreach ($siterules as $rule) {
|
||||
// Check if we have already processed this event.
|
||||
if (isset($courses[$rule->courseid][$rule->eventname])) {
|
||||
continue;
|
||||
}
|
||||
// Store the timewindow for this event.
|
||||
$courses[$rule->courseid][$rule->eventname] = $rule->timewindow;
|
||||
// Delete any events that may exist that have exceeded the timewindow.
|
||||
$DB->delete_records_select('tool_monitor_events', 'eventname = :eventname AND
|
||||
courseid = :courseid AND timecreated <= :timewindow',
|
||||
array('eventname' => $rule->eventname, 'courseid' => $rule->courseid,
|
||||
'timewindow' => time() - $rule->timewindow));
|
||||
}
|
||||
// Free resources.
|
||||
$siterules->close();
|
||||
}
|
||||
|
||||
// Now, get the course rules. The same applies here - there may be multiple rules for the course that rely on
|
||||
// the same event being triggered, so we only remove the events when they reach the max timewindow.
|
||||
if ($rules = $DB->get_recordset_select('tool_monitor_rules', 'courseid != 0', array(), 'timewindow DESC')) {
|
||||
// Go through each rule and check if there are any events we can remove.
|
||||
foreach ($rules as $rule) {
|
||||
// Check if we have already processed this event for this particular course.
|
||||
if (isset($courses[$rule->courseid][$rule->eventname])) {
|
||||
continue;
|
||||
}
|
||||
// Add the course and event to the list.
|
||||
$courses[$rule->courseid][$rule->eventname] = $rule->timewindow;
|
||||
// If there is a site wide rule listening for this event do not remove it unless the maximum
|
||||
// timewindow between the two has exceeded.
|
||||
$timewindow = $rule->timewindow;
|
||||
if (isset($courses[0][$rule->eventname]) && ($courses[0][$rule->eventname] > $timewindow)) {
|
||||
$timewindow = $courses[0][$rule->eventname];
|
||||
}
|
||||
// Delete any events that may exist that have exceeded the timewindow.
|
||||
$DB->delete_records_select('tool_monitor_events', 'eventname = :eventname AND
|
||||
courseid = :courseid AND timecreated <= :timewindow',
|
||||
array('eventname' => $rule->eventname, 'courseid' => $rule->courseid,
|
||||
'timewindow' => time() - $timewindow));
|
||||
}
|
||||
// Free resources.
|
||||
$rules->close();
|
||||
}
|
||||
|
||||
if ($siterules || $rules) { // Check that there are rules present.
|
||||
// Get a list of all the events we have been through.
|
||||
$allevents = array();
|
||||
foreach ($courses as $key => $value) {
|
||||
foreach ($courses[$key] as $event => $notused) {
|
||||
$allevents[] = $event;
|
||||
}
|
||||
}
|
||||
// Remove all the events in the table that are not applicable to any rule. There may be a rule in one course
|
||||
// listening for a certain event, but not in another course, so we can delete the event from the course
|
||||
// where there is no rule. We also have to consider site wide rules. We may have an event that is triggered
|
||||
// in a course we can't remove because there is a site wide rule for this event.
|
||||
if ($events = $DB->get_recordset('tool_monitor_events')) {
|
||||
// Array to store which events we need to remove.
|
||||
$eventstodelete = array();
|
||||
// Store the current time.
|
||||
$now = time();
|
||||
foreach ($events as $event) {
|
||||
// If the event is not required for a course rule and there is no site wide rule for it, or
|
||||
// it has extended past or equal to the timewindow for the site rule - it can be deleted.
|
||||
if (!isset($courses[$event->courseid][$event->eventname]) && (!isset($courses[0][$event->eventname])
|
||||
|| $courses[0][$event->eventname] <= ($now - $event->timecreated))) {
|
||||
$eventstodelete[] = $event->id;
|
||||
}
|
||||
}
|
||||
// Free resources.
|
||||
$events->close();
|
||||
|
||||
// Remove the events.
|
||||
if (!empty($eventstodelete)) {
|
||||
list($eventidsql, $params) = $DB->get_in_or_equal($eventstodelete);
|
||||
$DB->delete_records_select('tool_monitor_events', "id $eventidsql", $params);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove all the events in the table that are not used by any rule.
|
||||
if (!empty($allevents)) {
|
||||
list($eventnamesql, $params) = $DB->get_in_or_equal($allevents, SQL_PARAMS_QM, 'param', false);
|
||||
$DB->delete_records_select('tool_monitor_events', "eventname $eventnamesql", $params);
|
||||
}
|
||||
} else { // No rules, just remove everything.
|
||||
$DB->delete_records('tool_monitor_events');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Capabilities.
|
||||
*
|
||||
* This files lists capabilities related to tool_monitor.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$capabilities = array(
|
||||
|
||||
'tool/monitor:subscribe' => array(
|
||||
'riskbitmask' => RISK_PERSONAL,
|
||||
'captype' => 'read',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'teacher' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
),
|
||||
|
||||
'tool/monitor:managerules' => array(
|
||||
'riskbitmask' => RISK_XSS,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_COURSE,
|
||||
'archetypes' => array(
|
||||
'teacher' => CAP_ALLOW,
|
||||
'editingteacher' => CAP_ALLOW,
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
),
|
||||
|
||||
'tool/monitor:managetool' => array(
|
||||
'riskbitmask' => RISK_XSS, RISK_CONFIG,
|
||||
'captype' => 'write',
|
||||
'contextlevel' => CONTEXT_SYSTEM,
|
||||
'archetypes' => array(
|
||||
'manager' => CAP_ALLOW
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Event monitor cache definitions.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
$definitions = array(
|
||||
'eventsubscriptions' => array(
|
||||
'mode' => cache_store::MODE_APPLICATION,
|
||||
'simplekeys' => true,
|
||||
'simpledata' => true,
|
||||
'staticacceleration' => true,
|
||||
'staticaccelerationsize' => 10
|
||||
)
|
||||
);
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file definies observers needed by the tool.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// List of observers.
|
||||
$observers = array(
|
||||
array(
|
||||
'eventname' => '\core\event\course_deleted',
|
||||
'priority' => 1,
|
||||
'callback' => '\tool_monitor\eventobservers::course_deleted',
|
||||
),
|
||||
array(
|
||||
'eventname' => '*',
|
||||
'callback' => '\tool_monitor\eventobservers::process_event',
|
||||
),
|
||||
array(
|
||||
'eventname' => '\core\event\user_deleted',
|
||||
'callback' => '\tool_monitor\eventobservers::user_deleted',
|
||||
),
|
||||
array(
|
||||
'eventname' => '\core\event\course_module_deleted',
|
||||
'callback' => '\tool_monitor\eventobservers::course_module_deleted',
|
||||
)
|
||||
);
|
||||
@@ -1,81 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<XMLDB PATH="tool/monitor/db" VERSION="20141103" COMMENT="XMLDB file for Moodle tool/monitor"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
|
||||
>
|
||||
<TABLES>
|
||||
<TABLE NAME="tool_monitor_rules" COMMENT="Table to store rules">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="description" TYPE="text" NOTNULL="false" SEQUENCE="false" COMMENT="Description of the rule"/>
|
||||
<FIELD NAME="descriptionformat" TYPE="int" LENGTH="1" NOTNULL="true" SEQUENCE="false" COMMENT="Description format"/>
|
||||
<FIELD NAME="name" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Name of the rule"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Id of user who created the rule"/>
|
||||
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Id of course to which this rule belongs."/>
|
||||
<FIELD NAME="plugin" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Frankenstlye name of the plguin"/>
|
||||
<FIELD NAME="eventname" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Fully qualified name of the event"/>
|
||||
<FIELD NAME="template" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Message template"/>
|
||||
<FIELD NAME="templateformat" TYPE="int" LENGTH="1" NOTNULL="true" SEQUENCE="false" COMMENT="Template format"/>
|
||||
<FIELD NAME="frequency" TYPE="int" LENGTH="4" NOTNULL="true" SEQUENCE="false" COMMENT="Frequency"/>
|
||||
<FIELD NAME="timewindow" TYPE="int" LENGTH="5" NOTNULL="true" SEQUENCE="false" COMMENT="Time window in seconds"/>
|
||||
<FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Timestamp when this rule was last modified"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time stamp of when this rule was created"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="courseanduser" UNIQUE="false" FIELDS="courseid, userid" COMMENT="Index on courseid and userid"/>
|
||||
<INDEX NAME="eventname" UNIQUE="false" FIELDS="eventname" COMMENT="eventname"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="tool_monitor_subscriptions" COMMENT="Table to store user subscriptions to various rules">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course id of the subscription"/>
|
||||
<FIELD NAME="ruleid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Rule id"/>
|
||||
<FIELD NAME="cmid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Course module id"/>
|
||||
<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."/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="rulekey" TYPE="foreign" FIELDS="ruleid" REFTABLE="tool_monitor_rules" REFFIELDS="id" COMMENT="Foreign key"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="courseanduser" UNIQUE="false" FIELDS="courseid, userid" COMMENT="Course and user"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="tool_monitor_history" COMMENT="Table to store history of message notifications sent">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="sid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Subscription id"/>
|
||||
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="User to whom this notification was sent"/>
|
||||
<FIELD NAME="timesent" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Timestamp of when the message was sent."/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
<KEY NAME="subscrptionid" TYPE="foreign" FIELDS="sid" REFTABLE="tool_monitor_subscriptions" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
<INDEXES>
|
||||
<INDEX NAME="sid_userid_timesent" UNIQUE="true" FIELDS="sid, userid, timesent"/>
|
||||
</INDEXES>
|
||||
</TABLE>
|
||||
<TABLE NAME="tool_monitor_events" COMMENT="A table that keeps a log of events related to subscriptions">
|
||||
<FIELDS>
|
||||
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
|
||||
<FIELD NAME="eventname" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Event name"/>
|
||||
<FIELD NAME="contextid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Context id"/>
|
||||
<FIELD NAME="contextlevel" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Context level"/>
|
||||
<FIELD NAME="contextinstanceid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Context instance id"/>
|
||||
<FIELD NAME="link" TYPE="char" LENGTH="254" NOTNULL="true" SEQUENCE="false" COMMENT="Link to the event location"/>
|
||||
<FIELD NAME="courseid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="course id"/>
|
||||
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Time created"/>
|
||||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
</TABLES>
|
||||
</XMLDB>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Message providers list.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
$messageproviders = array (
|
||||
// Notify a user that a rule has happened.
|
||||
'notification' => array (
|
||||
'capability' => 'tool/monitor:subscribe'
|
||||
)
|
||||
);
|
||||
@@ -1,36 +0,0 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* This file defines tasks performed by the tool.
|
||||
*
|
||||
* @package tool_monitor
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
// List of tasks.
|
||||
$tasks = array(
|
||||
array(
|
||||
'classname' => 'tool_monitor\task\clean_events',
|
||||
'blocking' => 0,
|
||||
'minute' => '*',
|
||||
'hour' => '*',
|
||||
'day' => '*',
|
||||
'dayofweek' => '*',
|
||||
'month' => '*'
|
||||
)
|
||||
);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user