Compare commits
971 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3d765bc299 | |||
| 9e4b400c67 | |||
| 9a31f96622 | |||
| 8e6e5adb5b | |||
| 51acffb94a | |||
| 74126d6d3e | |||
| c9cfe78950 | |||
| d5ca7b11b7 | |||
| 33091e7e58 | |||
| 019e897604 | |||
| bdf95827b5 | |||
| c03a8543f0 | |||
| fdd6b2fa57 | |||
| 2602c1ce44 | |||
| f5edf4eba4 | |||
| ee281f15a7 | |||
| 490057db33 | |||
| 6dd8588504 | |||
| e2c3a02bb8 | |||
| 5dd5818c9a | |||
| 1f6a502674 | |||
| 067a949f46 | |||
| 4824e2deff | |||
| 95a14f5d55 | |||
| 77738c4562 | |||
| e93dd0d650 | |||
| 98b723b1ce | |||
| d6a7cac991 | |||
| ec9b8fb68d | |||
| 8bd76f9e65 | |||
| 4dbfb1becc | |||
| c06645a539 | |||
| 85906b4ae5 | |||
| 424cb3b0ef | |||
| ab37ff5952 | |||
| b38867187f | |||
| 1cef86131d | |||
| 14b0fea807 | |||
| 9fb272baaa | |||
| 44e9ca744e | |||
| a80c9b9816 | |||
| 3f1ef9ec5a | |||
| d754f1b012 | |||
| 4ca24885a5 | |||
| d69c84b185 | |||
| 87fccbc271 | |||
| dbde930a58 | |||
| 63cca18b3a | |||
| 18c99c67fa | |||
| 00b4aadafe | |||
| 13e183dd84 | |||
| b558672db4 | |||
| 627282714b | |||
| 199e7e9f85 | |||
| 20b76253fb | |||
| 690ef509de | |||
| 0442a23878 | |||
| df50b954c6 | |||
| 38be5071c8 | |||
| 041d4b3fab | |||
| a53366f7ab | |||
| bacfad505d | |||
| fff222f460 | |||
| 60df5b0c05 | |||
| d2175fceaa | |||
| aa114967bb | |||
| e60ca6985b | |||
| b506a6f08e | |||
| 5751edbcb1 | |||
| 7c144c47e5 | |||
| 5f32139fde | |||
| 30a7869e49 | |||
| f2b7714f6b | |||
| d0830107cb | |||
| 953560c9c4 | |||
| b2f46deb0b | |||
| 5ea58ff4e1 | |||
| 3603e0856a | |||
| 91c578c06d | |||
| 7608f458e3 | |||
| 78d1df7fd5 | |||
| bdf1df7058 | |||
| 6c6a05e561 | |||
| 0972d40ad9 | |||
| 58d7e8cf60 | |||
| ebc788d13e | |||
| 9d19a2bcd8 | |||
| c538ea951f | |||
| 1239f5a5c4 | |||
| 47147e2ff5 | |||
| c418df9c94 | |||
| 6ec18f437b | |||
| 2d56b929c0 | |||
| 8dce32bb7b | |||
| 51e1e3d536 | |||
| 0ca9b41b50 | |||
| 5e2f228709 | |||
| 387bde00c2 | |||
| b9bed21722 | |||
| eebe41c9d3 | |||
| 5e90b425fb | |||
| 1a17422d24 | |||
| 722bbfc81f | |||
| 3ee798f85f | |||
| 5e51b68a18 | |||
| 0243159817 | |||
| 2bc77f9cc9 | |||
| 439de8cf42 | |||
| c1beb0fa2d | |||
| 30721d4913 | |||
| aed1ff8d29 | |||
| facb211577 | |||
| f6b9535c4b | |||
| 3a5dd161c2 | |||
| 54b3f85625 | |||
| c865e54938 | |||
| e157c695c9 | |||
| 1d469cae30 | |||
| 7039fa8d96 | |||
| 312a8e0436 | |||
| 59bc05c4a2 | |||
| 3df2ab8d98 | |||
| 77962f179e | |||
| ce7582df1f | |||
| 29134ecc9e | |||
| 2d1e165183 | |||
| f3f329d1be | |||
| e2ea315c5b | |||
| 25c976527b | |||
| 06a8b8482d | |||
| 62920e80ba | |||
| 5fbc1470b1 | |||
| f196ac57ca | |||
| 479af9ed9f | |||
| 52c00a59c6 | |||
| 42a349855f | |||
| 1fc6a6046a | |||
| 13b7a5d4e5 | |||
| f4aea09ea4 | |||
| b086b19faa | |||
| ef9d05cd99 | |||
| e60fc41fdb | |||
| d561fa9527 | |||
| 53c074a81c | |||
| a31173a6a6 | |||
| f850a316f7 | |||
| f0a75425cb | |||
| 43426f3bf8 | |||
| 42d4cf091e | |||
| c841c104f0 | |||
| 57ee29839a | |||
| 64e085e1d1 | |||
| 4f65f98942 | |||
| f3266ff658 | |||
| bede2a2a34 | |||
| c2731a79e2 | |||
| 85ae284e59 | |||
| 029a753b91 | |||
| cba00bdb69 | |||
| 39f5ddeeb7 | |||
| 556c446f32 | |||
| 70e16becad | |||
| 146ada0aa6 | |||
| 11dd2fdb74 | |||
| 98b8818735 | |||
| 52ed7bb7e3 | |||
| f364f5628f | |||
| 2c90eef264 | |||
| 55b0567707 | |||
| 08aaea9856 | |||
| 1749c7aa31 | |||
| b1e71dac7d | |||
| a2c3c37cb6 | |||
| a4c5837ad7 | |||
| a167057d58 | |||
| 14d8d6b7bb | |||
| 687e61cdea | |||
| e186fee5e3 | |||
| 1e7cd615c1 | |||
| 92a3823994 | |||
| 8068301cd7 | |||
| 15141ad25f | |||
| 724641e59a | |||
| 832ea65890 | |||
| 311c3e9365 | |||
| 65ab1ffa5b | |||
| b7424c7693 | |||
| 081d16475b | |||
| b15713760e | |||
| f24f704630 | |||
| 22a35ffaaf | |||
| 96083d8068 | |||
| 31bb03f6e1 | |||
| 00f706d1f5 | |||
| d3e5802d97 | |||
| 6b27edcc47 | |||
| 28883e9b45 | |||
| e79edb11ee | |||
| d5d16e1f9c | |||
| a1e52c70e5 | |||
| b9720b8869 | |||
| 3f4a67b330 | |||
| 62da28c64d | |||
| 1179c92d0b | |||
| 3388d2f9f9 | |||
| 58609afebb | |||
| 6a10905864 | |||
| 87a4bba39c | |||
| 179b60aea6 | |||
| d52f9563d1 | |||
| de8c58715a | |||
| 2771063982 | |||
| acb05b5d4d | |||
| d45e517538 | |||
| df40fa5f66 | |||
| 02e5cdbeb8 | |||
| 029e7f5eae | |||
| 9a529b0753 | |||
| 3c0b7e9468 | |||
| ce7519c27e | |||
| 0a2be338a8 | |||
| d3ff99e745 | |||
| 91d77b17bd | |||
| 142af01f32 | |||
| 6551049f07 | |||
| ed246c21db | |||
| e5073fe305 | |||
| 9ef338d744 | |||
| 68e22328b5 | |||
| 9986fe8d0d | |||
| 13c04d1701 | |||
| bf3e4e030f | |||
| f22a7de23f | |||
| f9356f85ce | |||
| 3c94cc716e | |||
| 5a80cab06d | |||
| b1f400ae6f | |||
| 551fa5f4dd | |||
| bec1c29d84 | |||
| 89f5428879 | |||
| 84c656a557 | |||
| 367f1a7300 | |||
| 725ef19f1f | |||
| 12acab953b | |||
| 1425c0b449 | |||
| 4f24a95cdd | |||
| f4a57f80ef | |||
| feb6542872 | |||
| 1c59b0ad97 | |||
| 9e47a85a24 | |||
| a25ae4ff1b | |||
| 14f9c0cbcd | |||
| c9a0802794 | |||
| 078bd6815c | |||
| c7cce21d67 | |||
| be3aba207e | |||
| c2a64d94ff | |||
| 780cdcea5f | |||
| 4cc5500d0e | |||
| c2fe54c236 | |||
| 104524f504 | |||
| 664a07f74e | |||
| a0e1c31535 | |||
| bf479611db | |||
| 1f52e72526 | |||
| 03af3e075d | |||
| 9a287f8a49 | |||
| 76a07a1da5 | |||
| 46894c5058 | |||
| 52dd1d84a3 | |||
| 75e815fe72 | |||
| 8634bb229e | |||
| 7431abde3c | |||
| eac56e02bc | |||
| 5a52740940 | |||
| 6e4ece5640 | |||
| e84cef850a | |||
| cf93bcd37d | |||
| b5e0ee6f4a | |||
| 230a4ab6a2 | |||
| 41977bb4cc | |||
| 1d34dc5aa3 | |||
| 2c01ba7bb7 | |||
| 5b5bef12f0 | |||
| 88a7dcab1e | |||
| aa1e13ed2e | |||
| 6a008b485e | |||
| 659b8d8dc6 | |||
| 0dd1a7cb66 | |||
| 07d9ba8e9b | |||
| 9d228de05a | |||
| c8028c9371 | |||
| a2cfc3e460 | |||
| 8b805ced71 | |||
| 55ffbabe6d | |||
| e39ee61705 | |||
| 3e7ff59eb4 | |||
| cca2289111 | |||
| e8a165d2a3 | |||
| fcda253026 | |||
| 3728b69f31 | |||
| c8e7fdd9af | |||
| 2bdfe77686 | |||
| 1b8b39cbde | |||
| c874785067 | |||
| cbf4d62ccd | |||
| 6ad6368adc | |||
| 58cbfde495 | |||
| a743d4a77c | |||
| f3a2907f15 | |||
| a873af4dfe | |||
| 47a6e69179 | |||
| 4ecd7134e5 | |||
| 269255473f | |||
| 3bbbd26ee6 | |||
| 81c77993e3 | |||
| 6aec498812 | |||
| 11909e87a0 | |||
| 48db633522 | |||
| 1a6bfd3c1e | |||
| e4ff5b5d74 | |||
| 4e86cbabb0 | |||
| 5bdd8b8e7a | |||
| fd526f38ce | |||
| 56eff94252 | |||
| b6cbbb862c | |||
| 0683e9c5be | |||
| 3b7127a9b7 | |||
| 6740639cef | |||
| dcaa0b4e21 | |||
| 190cae0e09 | |||
| 4b85dc13ac | |||
| 761a9abd02 | |||
| 763fc56f9a | |||
| 43424771b6 | |||
| 4ac89c85d4 | |||
| d98c8aedb2 | |||
| a6a58c3485 | |||
| 6e6b96d57b | |||
| c9f31ba3a3 | |||
| 3675dbc32b | |||
| b8a5c64e95 | |||
| 984c6bd358 | |||
| 1389810600 | |||
| 0f68bcbc52 | |||
| 033be70faa | |||
| c440ddfb58 | |||
| 6a60e3f282 | |||
| f15c1b78ab | |||
| 0b1bc0a771 | |||
| 43b2bb6cd9 | |||
| 7d5f92870e | |||
| e99d784ffe | |||
| 25f8084ba0 | |||
| 187c395673 | |||
| 902b6d7df4 | |||
| d5addee28f | |||
| a8562f6c01 | |||
| e29521960d | |||
| 914cbfa714 | |||
| 54641661e1 | |||
| b7342c4c7b | |||
| e8e1ad9100 | |||
| 8c598be92d | |||
| dcb368720a | |||
| 9d9e5bc707 | |||
| e8ce08c331 | |||
| f84058a263 | |||
| 3b81d3b0e2 | |||
| 03e29fff56 | |||
| 3765c3f098 | |||
| b3ebbd4fc8 | |||
| 919304d4bf | |||
| 01ae3d20da | |||
| 15125314eb | |||
| 44e6b8ff57 | |||
| 8684284e49 | |||
| c46c673568 | |||
| aa79f99d53 | |||
| ef65eefff8 | |||
| df390ba9f0 | |||
| 2a41529f68 | |||
| e9adc8f6eb | |||
| 22edb9944a | |||
| ceedbe876d | |||
| 213eaa94f6 | |||
| 2acfb396ec | |||
| 936f6706c2 | |||
| 2e3a96e192 | |||
| 417fdfab6b | |||
| 77c9ae457d | |||
| a8fd6146e7 | |||
| 538e680d39 | |||
| ec5f521a59 | |||
| 100308ce24 | |||
| f6fc3616de | |||
| 9a8343cdde | |||
| a4e3607a21 | |||
| 27a2c6bffd | |||
| b6481ac993 | |||
| 2abbe6e2a3 | |||
| 3687ab70bc | |||
| 201159335f | |||
| c3ceb8d218 | |||
| 9df28ce5a3 | |||
| 784c24fde1 | |||
| cf264063c1 | |||
| 3f51ad2a70 | |||
| 6b0b96c581 | |||
| 8190a2911f | |||
| e336ad1b80 | |||
| ac30618786 | |||
| e9889abe38 | |||
| c0e1e425be | |||
| 517d606401 | |||
| f3cbcc623d | |||
| be36e2ad1d | |||
| aff1c65c3d | |||
| d96d964425 | |||
| 4f76e7ddf7 | |||
| 393d636e25 | |||
| 2b98c3d5e0 | |||
| 2bd3fc4d03 | |||
| 6b43f50c41 | |||
| 533a766447 | |||
| 59f3144e0a | |||
| ef5a198d1c | |||
| 60e7f2b113 | |||
| 68bc5b7b68 | |||
| 45222fc50f | |||
| 78092d6742 | |||
| a3fe5348ab | |||
| e3f6f30896 | |||
| 50296e134b | |||
| a6c44179e5 | |||
| ab93b02919 | |||
| 07ea543a1c | |||
| 768dd79e1f | |||
| c7f51d2dfe | |||
| ebbc9e717f | |||
| 617027cf84 | |||
| 21dc44b4df | |||
| 922817560c | |||
| 4b9cb37191 | |||
| a4673317a7 | |||
| deba736fbc | |||
| badddcab36 | |||
| be1f4ab759 | |||
| 01bb865997 | |||
| 79f544a45f | |||
| eadbd73918 | |||
| bf9f318ead | |||
| c015236f00 | |||
| 7a3156d001 | |||
| b22eb6a987 | |||
| c7c83663e1 | |||
| 49d85b7cfa | |||
| bc5d53c15c | |||
| 95f780c200 | |||
| 3656becc4a | |||
| 89ba1d6c2b | |||
| cca30c4795 | |||
| c78b71efb6 | |||
| 35a5d3b2fc | |||
| 40638405ea | |||
| a53760ef5a | |||
| 1193e6b023 | |||
| 8c5b86e044 | |||
| 6bc177e912 | |||
| 1f7907dac3 | |||
| 25c53e2b9f | |||
| 83fcca9346 | |||
| ab837e6113 | |||
| 96651cf9ed | |||
| 583c465a3a | |||
| 24f90eedb9 | |||
| 0d81404f9a | |||
| 7ba9375e84 | |||
| 15ffa46a1a | |||
| 38bc3c281a | |||
| 9bb6e09468 | |||
| 77de688b82 | |||
| dd8e618917 | |||
| ea819f2205 | |||
| 05deeaacdb | |||
| 19dd687377 | |||
| f2c12522c3 | |||
| 79a80529f8 | |||
| 70a649e40c | |||
| 38a94e0d39 | |||
| 327c88b76b | |||
| b229f563e5 | |||
| 7769615e76 | |||
| 056d2682a1 | |||
| a103d27e06 | |||
| d9c90952bb | |||
| 89b2800f75 | |||
| e12559481f | |||
| 6761018805 | |||
| 9948122905 | |||
| 308e53f572 | |||
| 3367e3ee1e | |||
| c1979ef02d | |||
| 25a5bd96f9 | |||
| 536c7aa882 | |||
| 534eebdd35 | |||
| e317113746 | |||
| ac473cb811 | |||
| fea115dab3 | |||
| 46306d8a25 | |||
| 2c9b8852f0 | |||
| 413b73ffe3 | |||
| 5bda351ef7 | |||
| e5180a491c | |||
| 5d7b69cd80 | |||
| 4bd293ee63 | |||
| 8252cd2848 | |||
| a35be2f5ef | |||
| 668a9eb90b | |||
| 606e175133 | |||
| 2e214b26f3 | |||
| c24ad72ba0 | |||
| ed26ad33ca | |||
| 9a380fbb53 | |||
| 6893e10840 | |||
| c18a7f9d94 | |||
| 07ca3c6816 | |||
| 9315fd7200 | |||
| 10bc60a163 | |||
| 0f9a1467e2 | |||
| 8b3405e8f2 | |||
| c5b7c1f627 | |||
| cc56539e51 | |||
| ae8da34929 | |||
| 0a6604e525 | |||
| 385e9d72ec | |||
| ae912070ea | |||
| 988f1a05e7 | |||
| b8369f5e9f | |||
| 020f0ffc5b | |||
| 087a329eef | |||
| 39025fe177 | |||
| 473afcbfec | |||
| 1dcb107bd4 | |||
| 7cf9937724 | |||
| f6c6bb4d39 | |||
| 814bce6575 | |||
| f12c714e6f | |||
| 74e78f3ad8 | |||
| 4a7e2298a3 | |||
| 910c941fa8 | |||
| bfb0183f6d | |||
| add39c57dd | |||
| 1b024a0b51 | |||
| 9d12edfcae | |||
| 746f1ac85c | |||
| 8277c39c76 | |||
| fb654f651f | |||
| 494f645bf4 | |||
| a26a8c6a6f | |||
| 27beb68c4b | |||
| 8254083dc9 | |||
| 9b7ac1ea57 | |||
| b214520d8b | |||
| abfe9dbe6e | |||
| 8c75bb5976 | |||
| e78632643c | |||
| f114cff65f | |||
| 3c18677ad1 | |||
| 1a199937f0 | |||
| b39029f718 | |||
| 7cb1a84978 | |||
| 8f7c097a09 | |||
| 5dc47fbbc6 | |||
| bac9a5e95e | |||
| 4a8d589d41 | |||
| ffd06a7394 | |||
| ba55e33828 | |||
| 3fcd1d05b9 | |||
| 29f02f10f0 | |||
| ff555b58be | |||
| 42d1a03acc | |||
| 80a90f8d71 | |||
| 4a225b69bb | |||
| 727242750d | |||
| 454efc509f | |||
| 1bef145b49 | |||
| 1a20976561 | |||
| 2558ce3593 | |||
| ab14ec06d2 | |||
| d072124ba4 | |||
| d9c19266c8 | |||
| cf93662ffe | |||
| 177f14d6f6 | |||
| bdcea1a221 | |||
| 25ebb1df63 | |||
| 39af096daf | |||
| 0ff186d7d7 | |||
| 26a92149cc | |||
| 38961259de | |||
| 528cde2db2 | |||
| 0ca33a3835 | |||
| 2a02a3f0de | |||
| 8445c4724c | |||
| 3e6c1d4d55 | |||
| 2c85a824fc | |||
| 6ce26b03e7 | |||
| ae18165edd | |||
| 5def8d573d | |||
| 41c5f54940 | |||
| 39b5360e69 | |||
| 6409d38377 | |||
| 945df69ff3 | |||
| 16aae71dcd | |||
| 371e83db2d | |||
| f4bc50d2bb | |||
| b32484d582 | |||
| 6750bec6c9 | |||
| 6a8787828e | |||
| 466b23caf7 | |||
| a4d6717aec | |||
| cc50a2fbc4 | |||
| 3345c20e29 | |||
| c06e87a410 | |||
| db005da178 | |||
| cfc9f55ca6 | |||
| 15f0d2ed37 | |||
| a370e4e4fa | |||
| a9e0bc82fb | |||
| ec05915767 | |||
| b5e8919b7c | |||
| 397262e292 | |||
| ea1e93b265 | |||
| 29e42725a4 | |||
| 91c59dbd8e | |||
| 87c8b752ca | |||
| 4fcc689dfc | |||
| 27f31cc626 | |||
| 9660303cc2 | |||
| 9abec7278b | |||
| ba7c14c1a7 | |||
| 97161e5008 | |||
| 25041083d5 | |||
| a1c5868475 | |||
| d4e94648cf | |||
| b651e7bb74 | |||
| d527599fcd | |||
| c1d93d47e9 | |||
| 6160c1721c | |||
| 71472b0a82 | |||
| ba3721d463 | |||
| 1a1f7b0eec | |||
| 0c60b1113e | |||
| 79121602c4 | |||
| ba16180449 | |||
| 01765239b0 | |||
| d65a2b2262 | |||
| 4754c0edd1 | |||
| ec441b6dd0 | |||
| df01a82082 | |||
| 00338d8b94 | |||
| 57e034c094 | |||
| c5b9fe0dda | |||
| 07511dbe6d | |||
| df70dfe4ee | |||
| f872b32778 | |||
| beb807e033 | |||
| 98d17b5bad | |||
| bca840b4bc | |||
| 80406e9dd8 | |||
| f4c5e50440 | |||
| 1382f8a549 | |||
| c372808e97 | |||
| f279137a86 | |||
| 0ad12999d7 | |||
| a390156411 | |||
| b84a272faf | |||
| f2ba68efc1 | |||
| 629ea4957b | |||
| 4c1db5b4ea | |||
| 7ea0f8e519 | |||
| ece057943d | |||
| edb8d49d35 | |||
| 8c23e3f5ff | |||
| 30a39ee2b7 | |||
| c3a68f4496 | |||
| d230fb7bcd | |||
| 0f37e97dc6 | |||
| c33e534dce | |||
| 65814f90c1 | |||
| 3a1380d81a | |||
| 743010f779 | |||
| 5a1a6fc1f0 | |||
| b0022f8d91 | |||
| 838f1bcdf4 | |||
| 014fba4928 | |||
| 32eadaf080 | |||
| dba24103ea | |||
| 0a770d5c6c | |||
| 29775a8e89 | |||
| f2855813c7 | |||
| b5e1c2e748 | |||
| 98c1207c46 | |||
| 3466a42f31 | |||
| 3fc24f1238 | |||
| 2e8ab7269c | |||
| 72ca02b0b2 | |||
| 22a7afd577 | |||
| c281550ce5 | |||
| 4a94bae470 | |||
| 92480bc82b | |||
| 2ff8943027 | |||
| da63c93657 | |||
| 4e184a9ce6 | |||
| 36420f78c1 | |||
| 93e980d52b | |||
| 9e5855cb1a | |||
| f9ba5c5222 | |||
| f79dd3b57d | |||
| f5eec88fb6 | |||
| f5a4f25375 | |||
| d714350a11 | |||
| a021f72a34 | |||
| 32af9814f1 | |||
| bcb785fa9e | |||
| 733bd07b8b | |||
| 19ab387d06 | |||
| 02a03f4fe2 | |||
| 75c92b6306 | |||
| e56ac08a5c | |||
| 0cf31e061b | |||
| 65150b26cd | |||
| e1ad9ae4f5 | |||
| ffa12b8397 | |||
| 890c7fae4e | |||
| 9f2e9b535d | |||
| c7d4a92ccf | |||
| 5bd0e7af9f | |||
| 794fb0e565 | |||
| 998b74a160 | |||
| 9ae0b69f59 | |||
| f4dc83e6e6 | |||
| ca2b2eb8af | |||
| 5399e053d1 | |||
| 6ef4ef1ee5 | |||
| f5a1b068cc | |||
| b9d64ab18f | |||
| 39d106ee76 | |||
| 07373d91a8 | |||
| 633fcef536 | |||
| dde17843e0 | |||
| 2430319b52 | |||
| adabef8bf6 | |||
| 22ea14df25 | |||
| 6867fc94b7 | |||
| 8385249f5b | |||
| 30dc7311ad | |||
| 9784520acb | |||
| d015c2352f | |||
| 35fa620a2e | |||
| 15516e6445 | |||
| 280a641232 | |||
| 14dac82376 | |||
| 06ede85e1f | |||
| 31a43cca97 | |||
| 8ad8b7dba8 | |||
| a09897b4b1 | |||
| 5e00f29019 | |||
| 36f0835e72 | |||
| 259b9d05f3 | |||
| da20cd7b43 | |||
| acb4688d29 | |||
| 471952fe82 | |||
| 0d738689bd | |||
| 7390fdde63 | |||
| 1374c61bb4 | |||
| 98d9209a34 | |||
| 8351ce1bd0 | |||
| b911ab236c | |||
| b4730465e6 | |||
| 78cc7bee62 | |||
| 5d6eafcf10 | |||
| 090e19328e | |||
| 34b5e856b0 | |||
| c44a5d5946 | |||
| b7d7679112 | |||
| 90061a6d95 | |||
| c9c031fc90 | |||
| 64a17788aa | |||
| 0baa1eee59 | |||
| 9f6eeb4abf | |||
| 6a48b42ae8 | |||
| 2dd90f136c | |||
| e6647397b9 | |||
| 07fa10d725 | |||
| 98032d512d | |||
| 389235fb00 | |||
| 656237dd55 | |||
| e3cc5b1a7f | |||
| 0742ea86b2 | |||
| 41f79b5c07 | |||
| ed85c0acd2 | |||
| 9c39028179 | |||
| 9fb4a6300b | |||
| 44c9dc6e7b | |||
| 4af7c9d188 | |||
| 847dee60ce | |||
| b7551bdf23 | |||
| e0be8fd6a3 | |||
| 55e03d1233 | |||
| e391f907af | |||
| bef867a96c | |||
| 4207d47742 | |||
| bd7193c7ac | |||
| 77e4a16c4f | |||
| 7daba2713e | |||
| 03b1be3005 | |||
| 5c8511ecf7 | |||
| 52435228c5 | |||
| c9dc3e5564 | |||
| ffaf18a8c1 | |||
| f5fddc6081 | |||
| 9d5a4e2b7c | |||
| ba9103b2c6 | |||
| 79196c9ed5 | |||
| a572cfe5bd | |||
| 92d7776478 | |||
| 2715f96932 | |||
| 6919d9f790 | |||
| 8be0517692 | |||
| a4b65c11b9 | |||
| 64e711f04b | |||
| e6cf40de78 | |||
| 174f5a0189 | |||
| dd56fd7c64 | |||
| 436f83f8ff | |||
| d03f904759 | |||
| 15a6af91f5 | |||
| 0a23dec07a | |||
| 6f8081bef4 | |||
| c643d3ae06 | |||
| 507ccf1c4b | |||
| 60bc533ee8 | |||
| 42f2b8d0dd | |||
| 84047d1fc9 | |||
| b79ac7e0d6 | |||
| 241ceba38c | |||
| 8e49e0833c | |||
| f6bf9c932d | |||
| 1fb2369b09 | |||
| 4de0925820 | |||
| 81f2a1686a | |||
| 5f509554a5 | |||
| edd5d0693d | |||
| d59a75a841 | |||
| 9b482d1cbe | |||
| ca090f3262 | |||
| 12db898084 | |||
| c79345c0f0 | |||
| d691571218 | |||
| 4e1bb6e10c | |||
| a7e920fbfb | |||
| 7a725d6b59 | |||
| 489c6ef357 | |||
| dbb6157aa1 | |||
| 50467e50c9 | |||
| 85a91fb98e | |||
| 75454e2567 | |||
| 06c09f30e3 | |||
| 26daa23d9d | |||
| 74a2ee73ed | |||
| fca41d2589 | |||
| 6de6a45a10 | |||
| 0f1fac1f1f | |||
| 692134ecd4 | |||
| d7706bac2c | |||
| 391e054c03 | |||
| 71f2316fe6 | |||
| 16d610019a | |||
| 4f5791da64 | |||
| c5e3a242b1 | |||
| 13ad1eaf37 | |||
| 7ca448fa83 | |||
| 37efb4f1ee | |||
| 81bd2292bc | |||
| 8fa13d155d | |||
| 465846f082 | |||
| f68815ffcf | |||
| 67b5d74b2c | |||
| 3d0e3ade75 | |||
| 7d1fb2f6ec | |||
| 227e54d65a | |||
| ee6181b1e7 | |||
| 3962c89bbf | |||
| 59137c2c5b | |||
| b83e494d6f | |||
| 3b2164bdca | |||
| aa54d70440 | |||
| d2d4bccec1 | |||
| f3a3c59f48 | |||
| 3d62a46b26 | |||
| 9aacfedb22 | |||
| 12b734434b | |||
| f9068e531c | |||
| 96506c474a | |||
| 0d66e33da5 | |||
| 934fa3ed6c | |||
| 6743d6c520 | |||
| cf76e10e4a | |||
| c800e31213 | |||
| 23580ddacb | |||
| 827fcdb347 | |||
| 60aaf1dc77 | |||
| fd8fa6f9d0 | |||
| 8adf19eda8 | |||
| a6e29ac6a3 | |||
| 52e184904f | |||
| b8d80c062e | |||
| eb9d692f8b | |||
| a805d653d1 | |||
| fe4a0cfe63 | |||
| d0e3447e43 | |||
| f046221272 | |||
| 42a50a0a45 | |||
| 77335e76e9 | |||
| ddf3e875f3 | |||
| 91fa7abf3d | |||
| b060e5b0b8 | |||
| f9c8746704 | |||
| c629aeabe3 | |||
| 27614a5e5d | |||
| ba32fc0042 | |||
| 87b05ba3e0 | |||
| 728f3c9d08 | |||
| d7dd177eb4 | |||
| 507de745e3 | |||
| bf8ff4889b | |||
| f9112bda35 | |||
| ba63612bfa | |||
| 408612d111 | |||
| 60e837038a | |||
| 4cb05cea9d | |||
| 0960f2f417 | |||
| 09c1e72a56 | |||
| d2455301b7 | |||
| 1be2b904ab | |||
| 337817e669 | |||
| b17a3a5591 | |||
| c44c552efa | |||
| faa297ce6f | |||
| b6225c0f2f | |||
| 50496af78b | |||
| 8fc52ccf46 | |||
| 9f9324f408 | |||
| d4dc367a5b | |||
| 3ede344b5c | |||
| 5c686792c6 | |||
| 91a4b3bd3e | |||
| 1a6a1487f4 | |||
| a5286ae4cc | |||
| 5b97bff526 | |||
| 1c4873ba1b | |||
| 9a8f8cea49 | |||
| c37f03543b | |||
| cd4ca97611 | |||
| 77bfc4ce0f | |||
| 13c53a4a2e | |||
| d3796a2c61 | |||
| 7bb8ae5911 | |||
| dbe6d9f821 | |||
| 4927443761 |
+57
-4
@@ -12,6 +12,8 @@
|
||||
$hide = optional_param('hide', 0, PARAM_INT);
|
||||
$show = optional_param('show', 0, PARAM_INT);
|
||||
$delete = optional_param('delete', 0, PARAM_INT);
|
||||
$unprotect = optional_param('unprotect', 0, PARAM_INT);
|
||||
$protect = optional_param('protect', 0, PARAM_INT);
|
||||
|
||||
/// Print headings
|
||||
|
||||
@@ -24,6 +26,9 @@
|
||||
$strcourses = get_string('blockinstances', 'admin');
|
||||
$strname = get_string('name');
|
||||
$strshowblockcourse = get_string('showblockcourse');
|
||||
$strprotecthdr = get_string('blockprotect', 'admin'). $OUTPUT->help_icon('blockprotect','admin');
|
||||
$strprotect = get_string('blockprotect', 'admin');
|
||||
$strunprotect = get_string('blockunprotect', 'admin');
|
||||
|
||||
/// If data submitted, then process and store.
|
||||
|
||||
@@ -43,6 +48,36 @@
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
}
|
||||
|
||||
if (!isset($CFG->undeletableblocktypes) || (!is_array($CFG->undeletableblocktypes) && !is_string($CFG->undeletableblocktypes))) {
|
||||
$undeletableblocktypes = array('navigation', 'settings');
|
||||
} else if (is_string($CFG->undeletableblocktypes)) {
|
||||
$undeletableblocktypes = explode(',', $CFG->undeletableblocktypes);
|
||||
} else {
|
||||
$undeletableblocktypes = $CFG->undeletableblocktypes;
|
||||
}
|
||||
|
||||
if (!empty($protect) && confirm_sesskey()) {
|
||||
if (!$block = $DB->get_record('block', array('id'=>$protect))) {
|
||||
print_error('blockdoesnotexist', 'error');
|
||||
}
|
||||
if (!in_array($block->name, $undeletableblocktypes)) {
|
||||
$undeletableblocktypes[] = $block->name;
|
||||
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
|
||||
}
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
}
|
||||
|
||||
if (!empty($unprotect) && confirm_sesskey()) {
|
||||
if (!$block = $DB->get_record('block', array('id'=>$unprotect))) {
|
||||
print_error('blockdoesnotexist', 'error');
|
||||
}
|
||||
if (in_array($block->name, $undeletableblocktypes)) {
|
||||
$undeletableblocktypes = array_diff($undeletableblocktypes, array($block->name));
|
||||
set_config('undeletableblocktypes', implode(',', $undeletableblocktypes));
|
||||
}
|
||||
admin_get_root(true, false); // settings not required - only pages
|
||||
}
|
||||
|
||||
if (!empty($delete) && confirm_sesskey()) {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strmanageblocks);
|
||||
@@ -114,11 +149,12 @@
|
||||
|
||||
$table = new flexible_table('admin-blocks-compatible');
|
||||
|
||||
$table->define_columns(array('name', 'instances', 'version', 'hideshow', 'delete', 'settings'));
|
||||
$table->define_headers(array($strname, $strcourses, $strversion, $strhide.'/'.$strshow, $strdelete, $strsettings));
|
||||
$table->define_columns(array('name', 'instances', 'version', 'hideshow', 'undeletable', 'delete', 'settings'));
|
||||
$table->define_headers(array($strname, $strcourses, $strversion, $strhide.'/'.$strshow, $strprotecthdr, $strdelete, $strsettings));
|
||||
$table->define_baseurl($CFG->wwwroot.'/'.$CFG->admin.'/blocks.php');
|
||||
$table->set_attribute('class', 'compatibleblockstable blockstable generaltable');
|
||||
$table->setup();
|
||||
$tablerows = array();
|
||||
|
||||
foreach ($blocks as $blockid=>$block) {
|
||||
$blockname = $block->name;
|
||||
@@ -191,15 +227,32 @@
|
||||
$version = "$block->version ($plugin->version)";
|
||||
}
|
||||
|
||||
if (!$blockobject) {
|
||||
// ignore
|
||||
$undeletable = '';
|
||||
} else if (in_array($blockname, $undeletableblocktypes)) {
|
||||
$undeletable = '<a href="blocks.php?unprotect='.$blockid.'&sesskey='.sesskey().'" title="'.$strunprotect.'">'.
|
||||
'<img src="'.$OUTPUT->pix_url('t/unlock') . '" class="icon" alt="'.$strunprotect.'" /></a>';
|
||||
} else {
|
||||
$undeletable = '<a href="blocks.php?protect='.$blockid.'&sesskey='.sesskey().'" title="'.$strprotect.'">'.
|
||||
'<img src="'.$OUTPUT->pix_url('t/unlock_gray') . '" class="icon" alt="'.$strprotect.'" /></a>';
|
||||
}
|
||||
|
||||
$table->add_data(array(
|
||||
$row = array(
|
||||
'<span'.$class.'>'.$strblockname.'</span>',
|
||||
$blocklist,
|
||||
'<span'.$class.'>'.$version.'</span>',
|
||||
$visible,
|
||||
$undeletable,
|
||||
$delete,
|
||||
$settings
|
||||
));
|
||||
);
|
||||
$tablerows[] = array(strip_tags($strblockname), $row); // first element will be used for sorting
|
||||
}
|
||||
|
||||
textlib_get_instance()->asort($tablerows);
|
||||
foreach ($tablerows as $row) {
|
||||
$table->add_data($row[1]);
|
||||
}
|
||||
|
||||
$table->print_html();
|
||||
|
||||
+19
-10
@@ -376,16 +376,25 @@ if ($interactive) {
|
||||
}
|
||||
}
|
||||
|
||||
// download required lang packs
|
||||
if ($CFG->lang !== 'en') {
|
||||
$installer = new lang_installer($CFG->lang);
|
||||
$results = $installer->run();
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
|
||||
$a = new stdClass();
|
||||
$a->url = $installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
cli_problem(get_string('remotedownloaderror', 'error', $a));
|
||||
//download lang pack with optional notification
|
||||
if ($CFG->lang != 'en') {
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $CFG->lang.'.zip', 'languages.md5', 'lang')) {
|
||||
if ($cd->install() == COMPONENT_ERROR) {
|
||||
if ($cd->get_error() == 'remotedownloaderror') {
|
||||
$a = new stdClass();
|
||||
$a->url = 'http://download.moodle.org/langpack/2.0/'.$CFG->lang.'.zip';
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
cli_problem(get_string($cd->get_error(), 'error', $a));
|
||||
} else {
|
||||
cli_problem(get_string($cd->get_error(), 'error'));
|
||||
}
|
||||
} else {
|
||||
// install parent lang if defined
|
||||
if ($parentlang = get_parent_language()) {
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
|
||||
$cd->install();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ Options:
|
||||
--adminuser=USERNAME Username for the moodle admin account. Default is admin.
|
||||
--adminpass=PASSWORD Password for the moodle admin account.
|
||||
--agree-license Indicates agreement with software license.
|
||||
--fullname Name of the site
|
||||
--shortname Name of the site
|
||||
-h, --help Print out this help
|
||||
|
||||
Example:
|
||||
@@ -93,6 +95,8 @@ list($options, $unrecognized) = cli_get_params(
|
||||
'lang' => 'en',
|
||||
'adminuser' => 'admin',
|
||||
'adminpass' => '',
|
||||
'fullname' => '',
|
||||
'shortname' => '',
|
||||
'agree-license' => false,
|
||||
'help' => false
|
||||
),
|
||||
@@ -121,17 +125,26 @@ if (!file_exists($CFG->dirroot.'/install/lang/'.$options['lang'])) {
|
||||
}
|
||||
$CFG->lang = $options['lang'];
|
||||
|
||||
// download required lang packs
|
||||
if ($CFG->lang !== 'en') {
|
||||
//download lang pack with optional notification
|
||||
if ($CFG->lang != 'en') {
|
||||
make_upload_directory('lang');
|
||||
$installer = new lang_installer($CFG->lang);
|
||||
$results = $installer->run();
|
||||
foreach ($results as $langcode => $langstatus) {
|
||||
if ($langstatus === lang_installer::RESULT_DOWNLOADERROR) {
|
||||
$a = new stdClass();
|
||||
$a->url = $installer->lang_pack_url($langcode);
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
cli_problem(get_string('remotedownloaderror', 'error', $a));
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $CFG->lang.'.zip', 'languages.md5', 'lang')) {
|
||||
if ($cd->install() == COMPONENT_ERROR) {
|
||||
if ($cd->get_error() == 'remotedownloaderror') {
|
||||
$a = new stdClass();
|
||||
$a->url = 'http://download.moodle.org/langpack/2.0/'.$CFG->lang.'.zip';
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
cli_problem(get_string($cd->get_error(), 'error', $a));
|
||||
} else {
|
||||
cli_problem(get_string($cd->get_error(), 'error'));
|
||||
}
|
||||
} else {
|
||||
// install parent lang if defined
|
||||
if ($parentlang = get_parent_language()) {
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/2.0', $parentlang.'.zip', 'languages.md5', 'lang')) {
|
||||
$cd->install();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,12 @@
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
if (defined('STDIN')) {
|
||||
fwrite(STDERR, "ERROR: This script no longer supports CLI, please use admin/cli/cron.php instead\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// This is a fake CLI script, it is a really ugly hack which emulates
|
||||
// CLI via web interface, please do not use this hack elsewhere
|
||||
define('CLI_SCRIPT', true);
|
||||
|
||||
+1
-1
@@ -622,7 +622,7 @@ class generator {
|
||||
require_once($CFG->libdir .'/questionlib.php');
|
||||
require_once($CFG->dirroot .'/mod/quiz/editlib.php');
|
||||
$questions = array();
|
||||
$questionsmenu = question_bank::get_creatable_qtypes();
|
||||
$questionsmenu = question_type_menu();
|
||||
$questiontypes = array();
|
||||
foreach ($questionsmenu as $qtype => $qname) {
|
||||
$questiontypes[] = $qtype;
|
||||
|
||||
+20
-36
@@ -48,7 +48,6 @@ $id = optional_param('id', '', PARAM_TEXT);
|
||||
$confirmupgrade = optional_param('confirmupgrade', 0, PARAM_BOOL);
|
||||
$confirmrelease = optional_param('confirmrelease', 0, PARAM_BOOL);
|
||||
$confirmplugins = optional_param('confirmplugincheck', 0, PARAM_BOOL);
|
||||
$showallplugins = optional_param('showallplugins', 0, PARAM_BOOL);
|
||||
$agreelicense = optional_param('agreelicense', 0, PARAM_BOOL);
|
||||
|
||||
// Check some PHP server settings
|
||||
@@ -124,7 +123,7 @@ if (!core_tables_exist()) {
|
||||
echo $OUTPUT->box($copyrightnotice, 'copyrightnotice');
|
||||
echo '<br />';
|
||||
$continue = new single_button(new moodle_url('/admin/index.php', array('lang'=>$CFG->lang, 'agreelicense'=>1)), get_string('continue'), 'get');
|
||||
echo $OUTPUT->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/en/License");
|
||||
echo $OUTPUT->confirm(get_string('doyouagree'), $continue, "http://docs.moodle.org/dev/License");
|
||||
echo $OUTPUT->footer();
|
||||
die;
|
||||
}
|
||||
@@ -194,7 +193,6 @@ if (empty($CFG->version)) {
|
||||
}
|
||||
|
||||
if ($version > $CFG->version) { // upgrade
|
||||
purge_all_caches();
|
||||
$PAGE->set_pagelayout('maintenance');
|
||||
$PAGE->set_popup_notification_allowed(false);
|
||||
|
||||
@@ -257,19 +255,17 @@ if ($version > $CFG->version) { // upgrade
|
||||
$PAGE->set_title($strplugincheck);
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$pluginman = plugin_manager::instance();
|
||||
|
||||
echo $output->header();
|
||||
echo $output->box_start('generalbox');
|
||||
echo $output->container(get_string('pluginchecknotice', 'core_plugin'), 'generalbox', 'notice');
|
||||
echo $output->plugins_check($pluginman->get_plugins(), array('full' => $showallplugins));
|
||||
echo $output->box_end();
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strplugincheck);
|
||||
echo $OUTPUT->box_start('generalbox', 'notice');
|
||||
print_string('pluginchecknotice');
|
||||
echo $OUTPUT->box_end();
|
||||
print_plugin_tables();
|
||||
print_upgrade_reload('index.php?confirmupgrade=1&confirmrelease=1');
|
||||
$button = new single_button(new moodle_url('index.php', array('confirmupgrade'=>1, 'confirmrelease'=>1, 'confirmplugincheck'=>1)), get_string('upgradestart', 'admin'), 'get');
|
||||
$button->class = 'continuebutton';
|
||||
echo $output->render($button);
|
||||
echo $output->footer();
|
||||
echo $OUTPUT->render($button);
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
|
||||
} else {
|
||||
@@ -297,19 +293,17 @@ if (moodle_needs_upgrading()) {
|
||||
$PAGE->set_title($strplugincheck);
|
||||
$PAGE->set_heading($strplugincheck);
|
||||
$PAGE->set_cacheable(false);
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$pluginman = plugin_manager::instance();
|
||||
|
||||
echo $output->header();
|
||||
echo $output->box_start('generalbox');
|
||||
echo $output->container(get_string('pluginchecknotice', 'core_plugin'), 'generalbox', 'notice');
|
||||
echo $output->plugins_check($pluginman->get_plugins(), array('full' => $showallplugins));
|
||||
echo $output->box_end();
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strplugincheck);
|
||||
echo $OUTPUT->box_start('generalbox', 'notice');
|
||||
print_string('pluginchecknotice');
|
||||
echo $OUTPUT->box_end();
|
||||
print_plugin_tables();
|
||||
print_upgrade_reload('index.php');
|
||||
$button = new single_button(new moodle_url('index.php', array('confirmplugincheck'=>1)), get_string('upgradestart', 'admin'), 'get');
|
||||
$button->class = 'continuebutton';
|
||||
echo $output->render($button);
|
||||
echo $output->footer();
|
||||
echo $OUTPUT->render($button);
|
||||
echo $OUTPUT->footer();
|
||||
die();
|
||||
}
|
||||
}
|
||||
@@ -355,6 +349,7 @@ if (during_initial_install()) {
|
||||
}
|
||||
// login user and let him set password and admin details
|
||||
$adminuser->newadminuser = 1;
|
||||
message_set_default_message_preferences($adminuser);
|
||||
complete_user_login($adminuser, false);
|
||||
redirect("$CFG->wwwroot/user/editadvanced.php?id=$adminuser->id"); // Edit thyself
|
||||
|
||||
@@ -407,17 +402,6 @@ if (any_new_admin_settings($adminroot)){
|
||||
admin_externalpage_setup('adminnotifications');
|
||||
echo $OUTPUT->header();
|
||||
|
||||
// Unstable code warning
|
||||
if (isset($maturity)) {
|
||||
if ($maturity < MATURITY_STABLE) {
|
||||
$maturitylevel = get_string('maturity'.$maturity, 'admin');
|
||||
echo $OUTPUT->box(
|
||||
get_string('maturitycoreinfo', 'admin', $maturitylevel) . ' ' .
|
||||
$OUTPUT->doc_link('admin/versions', get_string('morehelp')),
|
||||
'generalbox adminwarning maturityinfo');
|
||||
}
|
||||
}
|
||||
|
||||
if ($insecuredataroot == INSECURE_DATAROOT_WARNING) {
|
||||
echo $OUTPUT->box(get_string('datarootsecuritywarning', 'admin', $CFG->dataroot), 'generalbox adminwarning');
|
||||
} else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) {
|
||||
@@ -458,8 +442,8 @@ if (!empty($CFG->maintenance_enabled)) {
|
||||
$copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
|
||||
'<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
|
||||
'Copyright © 1999 onwards, Martin Dougiamas<br />'.
|
||||
'and <a href="http://docs.moodle.org/en/Credits">many other contributors</a>.<br />'.
|
||||
'<a href="http://docs.moodle.org/en/License">GNU Public License</a>';
|
||||
'and <a href="http://docs.moodle.org/dev/Credits">many other contributors</a>.<br />'.
|
||||
'<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
|
||||
echo $OUTPUT->box($copyrighttext, 'copyright');
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
+91
-50
@@ -18,7 +18,7 @@
|
||||
/**
|
||||
* Fetches language packages from download.moodle.org server
|
||||
*
|
||||
* Language packages are available at http://download.moodle.org/langpack/
|
||||
* Language packages are available at http://download.moodle.org/langpack/2.0/
|
||||
* in ZIP format together with a file languages.md5 containing their hashes
|
||||
* and meta info.
|
||||
* Locally, language packs are saved into $CFG->dataroot/lang/
|
||||
@@ -33,6 +33,8 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->libdir.'/filelib.php');
|
||||
require_once($CFG->libdir.'/componentlib.class.php');
|
||||
|
||||
$thisversion = '2.0'; // TODO this information should be taken from version.php or similar source
|
||||
|
||||
admin_externalpage_setup('langimport');
|
||||
|
||||
if (!empty($CFG->skiplangupgrade)) {
|
||||
@@ -61,22 +63,41 @@ if (($mode == INSTALLATION_OF_SELECTED_LANG) and confirm_sesskey() and !empty($p
|
||||
make_upload_directory('temp');
|
||||
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', 'langimport.php', $a);
|
||||
break;
|
||||
case lang_installer::RESULT_INSTALLED:
|
||||
$notice_ok[] = get_string('langpackinstalled', 'admin', $langcode);
|
||||
break;
|
||||
case lang_installer::RESULT_UPTODATE:
|
||||
$notice_ok[] = get_string('langpackuptodate', 'admin', $langcode);
|
||||
break;
|
||||
if (is_array($pack)) {
|
||||
$packs = $pack;
|
||||
} else {
|
||||
$packs = array($pack);
|
||||
}
|
||||
|
||||
foreach ($packs as $pack) {
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion, $pack.'.zip', 'languages.md5', 'lang')) {
|
||||
$status = $cd->install();
|
||||
switch ($status) {
|
||||
case COMPONENT_ERROR:
|
||||
if ($cd->get_error() == 'remotedownloaderror') {
|
||||
$a = new stdClass();
|
||||
$a->url = 'http://download.moodle.org/langpack/'.$thisversion.'/'.$pack.'.zip';
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
print_error($cd->get_error(), 'error', 'langimport.php', $a);
|
||||
} else {
|
||||
print_error($cd->get_error(), 'error', 'langimport.php');
|
||||
}
|
||||
break;
|
||||
case COMPONENT_INSTALLED:
|
||||
$notice_ok[] = get_string('langpackinstalled','admin',$pack);
|
||||
if ($parentlang = get_parent_language($pack)) {
|
||||
// install also parent pack if specified
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion,
|
||||
$parentlang.'.zip', 'languages.md5', 'lang')) {
|
||||
$cd->install();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COMPONENT_UPTODATE:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
echo $OUTPUT->notification('Had an unspecified error with the component installer, sorry.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,9 +136,7 @@ if ($mode == DELETION_OF_SELECTED_LANG and !empty($uninstalllang)) {
|
||||
if ($mode == UPDATE_ALL_LANG) {
|
||||
set_time_limit(0);
|
||||
|
||||
$installer = new lang_installer();
|
||||
|
||||
if (!$availablelangs = $installer->get_remote_list_of_languages()) {
|
||||
if (!$availablelangs = get_remote_list_of_languages()) {
|
||||
print_error('cannotdownloadlanguageupdatelist', 'error');
|
||||
}
|
||||
$md5array = array(); // (string)langcode => (string)md5
|
||||
@@ -152,8 +171,8 @@ if ($mode == UPDATE_ALL_LANG) {
|
||||
make_upload_directory('temp');
|
||||
make_upload_directory('lang');
|
||||
|
||||
// clean-up currently installed versions of the packs
|
||||
foreach ($neededlangs as $packindex => $pack) {
|
||||
$updated = false; // any packs updated?
|
||||
foreach ($neededlangs as $pack) {
|
||||
if ($pack == 'en') {
|
||||
continue;
|
||||
}
|
||||
@@ -166,38 +185,41 @@ if ($mode == UPDATE_ALL_LANG) {
|
||||
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', 'langimport.php', $a);
|
||||
break;
|
||||
case lang_installer::RESULT_INSTALLED:
|
||||
$updated = true;
|
||||
$notice_ok[] = get_string('langpackinstalled', 'admin', $langcode);
|
||||
break;
|
||||
case lang_installer::RESULT_UPTODATE:
|
||||
$notice_ok[] = get_string('langpackuptodate', 'admin', $langcode);
|
||||
break;
|
||||
// copy and unzip new version
|
||||
if ($cd = new component_installer('http://download.moodle.org', 'langpack/'.$thisversion, $pack.'.zip', 'languages.md5', 'lang')) {
|
||||
$status = $cd->install();
|
||||
switch ($status) {
|
||||
|
||||
case COMPONENT_ERROR:
|
||||
if ($cd->get_error() == 'remotedownloaderror') {
|
||||
$a = new stdClass();
|
||||
$a->url = 'http://download.moodle.org/langpack/'.$thisversion.'/'.$pack.'.zip';
|
||||
$a->dest = $CFG->dataroot.'/lang';
|
||||
print_error($cd->get_error(), 'error', 'langimport.php', $a);
|
||||
} else {
|
||||
print_error($cd->get_error(), 'error', 'langimport.php');
|
||||
}
|
||||
break;
|
||||
|
||||
case COMPONENT_UPTODATE:
|
||||
// should not get here
|
||||
break;
|
||||
|
||||
case COMPONENT_INSTALLED:
|
||||
$notice_ok[] = get_string('langpackupdated', 'admin', $pack);
|
||||
$updated = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,8 +228,6 @@ if ($mode == UPDATE_ALL_LANG) {
|
||||
} else {
|
||||
$notice_ok[] = get_string('nolangupdateneeded','admin');
|
||||
}
|
||||
|
||||
unset($installer);
|
||||
}
|
||||
get_string_manager()->reset_caches();
|
||||
|
||||
@@ -219,7 +239,7 @@ $installedlangs = get_string_manager()->get_list_of_translations(true);
|
||||
$missingparents = array();
|
||||
foreach ($installedlangs as $installedlang => $unused) {
|
||||
$parent = get_parent_language($installedlang);
|
||||
if (empty($parent)) {
|
||||
if (empty($parent) or ($parent === 'en')) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($installedlangs[$parent])) {
|
||||
@@ -227,9 +247,7 @@ foreach ($installedlangs as $installedlang => $unused) {
|
||||
}
|
||||
}
|
||||
|
||||
$installer = new lang_installer();
|
||||
|
||||
if ($availablelangs = $installer->get_remote_list_of_languages()) {
|
||||
if ($availablelangs = get_remote_list_of_languages()) {
|
||||
$remote = true;
|
||||
} else {
|
||||
$remote = false;
|
||||
@@ -339,3 +357,26 @@ function is_installed_lang($lang, $md5check) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of available language packs from download.moodle.org
|
||||
*
|
||||
* @return array|bool false if can not download
|
||||
*/
|
||||
function get_remote_list_of_languages() {
|
||||
$source = 'http://download.moodle.org/langpack/2.0/languages.md5';
|
||||
$availablelangs = array();
|
||||
|
||||
if ($content = download_file_content($source)) {
|
||||
$alllines = explode("\n", $content);
|
||||
foreach($alllines as $line) {
|
||||
if (!empty($line)){
|
||||
$availablelangs[] = explode(',', $line);
|
||||
}
|
||||
}
|
||||
return $availablelangs;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,70 +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 outputs configuration page
|
||||
*
|
||||
* @package message
|
||||
* @copyright 2011 Lancaster University Network Services Limited
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->dirroot . '/message/lib.php');
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
// This is an admin page
|
||||
admin_externalpage_setup('managemessageoutputs');
|
||||
|
||||
// Require site configuration capability
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
// Get the submitted params
|
||||
$disable = optional_param('disable', 0, PARAM_INT);
|
||||
$enable = optional_param('enable', 0, PARAM_INT);
|
||||
|
||||
if (!empty($disable) && confirm_sesskey()) {
|
||||
if (!$processor = $DB->get_record('message_processors', array('id'=>$disable))) {
|
||||
print_error('outputdoesnotexist', 'message');
|
||||
}
|
||||
$DB->set_field('message_processors', 'enabled', '0', array('id'=>$processor->id)); // Disable output
|
||||
}
|
||||
|
||||
if (!empty($enable) && confirm_sesskey() ) {
|
||||
if (!$processor = $DB->get_record('message_processors', array('id'=>$enable))) {
|
||||
print_error('outputdoesnotexist', 'message');
|
||||
}
|
||||
$DB->set_field('message_processors', 'enabled', '1', array('id'=>$processor->id)); // Enable output
|
||||
}
|
||||
|
||||
if ($disable || $enable) {
|
||||
$url = new moodle_url('message.php');
|
||||
redirect($url);
|
||||
}
|
||||
// Page settings
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
|
||||
|
||||
// Grab the renderer
|
||||
$renderer = $PAGE->get_renderer('core', 'message');
|
||||
|
||||
// Display the manage message outputs interface
|
||||
$processors = get_message_processors();
|
||||
$messageoutputs = $renderer->manage_messageoutputs($processors);
|
||||
|
||||
// Display the page
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('managemessageoutputs', 'message'));
|
||||
echo $messageoutputs;
|
||||
echo $OUTPUT->footer();
|
||||
@@ -1,41 +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/>.
|
||||
|
||||
/**
|
||||
* UI for general plugins management
|
||||
*
|
||||
* @package core
|
||||
* @subpackage admin
|
||||
* @copyright 2011 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once(dirname(dirname(__FILE__)) . '/config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/pluginlib.php');
|
||||
|
||||
require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM));
|
||||
admin_externalpage_setup('pluginsoverview');
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$pluginman = plugin_manager::instance();
|
||||
|
||||
echo $output->header();
|
||||
echo $output->heading(get_string('pluginsoverview', 'core_admin'));
|
||||
echo $output->box_start('generalbox');
|
||||
echo $output->plugins_control_panel($pluginman->get_plugins());
|
||||
echo $output->box_end();
|
||||
echo $output->footer();
|
||||
@@ -1,302 +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/>.
|
||||
|
||||
/**
|
||||
* Allows the admin to manage question behaviours.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionengine
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
// Check permissions.
|
||||
require_login();
|
||||
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
require_capability('moodle/question:config', $systemcontext);
|
||||
|
||||
admin_externalpage_setup('manageqbehaviours');
|
||||
$thispageurl = new moodle_url('/admin/qbehaviours.php');
|
||||
|
||||
$behaviours = get_plugin_list('qbehaviour');
|
||||
|
||||
// Get some data we will need - question counts and which types are needed.
|
||||
$counts = $DB->get_records_sql_menu("
|
||||
SELECT behaviour, COUNT(1)
|
||||
FROM {question_attempts} GROUP BY behaviour");
|
||||
$needed = array();
|
||||
$archetypal = array();
|
||||
foreach ($behaviours as $behaviour => $notused) {
|
||||
if (!array_key_exists($behaviour, $counts)) {
|
||||
$counts[$behaviour] = 0;
|
||||
}
|
||||
$needed[$behaviour] = $counts[$behaviour] > 0;
|
||||
$archetypal[$behaviour] = question_engine::is_behaviour_archetypal($behaviour);
|
||||
}
|
||||
|
||||
foreach ($behaviours as $behaviour => $notused) {
|
||||
foreach (question_engine::get_behaviour_required_behaviours($behaviour) as $reqbehaviour) {
|
||||
$needed[$reqbehaviour] = true;
|
||||
}
|
||||
}
|
||||
foreach ($counts as $behaviour => $count) {
|
||||
if (!array_key_exists($behaviour, $behaviours)) {
|
||||
$counts['missingtype'] += $count;
|
||||
}
|
||||
}
|
||||
|
||||
// Work of the correct sort order.
|
||||
$config = get_config('question');
|
||||
$sortedbehaviours = array();
|
||||
foreach ($behaviours as $behaviour => $notused) {
|
||||
$sortedbehaviours[$behaviour] = question_engine::get_behaviour_name($behaviour);
|
||||
}
|
||||
if (!empty($config->behavioursortorder)) {
|
||||
$sortedbehaviours = question_engine::sort_behaviours($sortedbehaviours,
|
||||
$config->behavioursortorder, '');
|
||||
}
|
||||
|
||||
if (!empty($config->disabledbehaviours)) {
|
||||
$disabledbehaviours = explode(',', $config->disabledbehaviours);
|
||||
} else {
|
||||
$disabledbehaviours = array();
|
||||
}
|
||||
|
||||
// Process actions ============================================================
|
||||
|
||||
// Disable.
|
||||
if (($disable = optional_param('disable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($behaviours[$disable])) {
|
||||
print_error('unknownbehaviour', 'question', $thispageurl, $disable);
|
||||
}
|
||||
|
||||
if (array_search($disable, $disabledbehaviours) === false) {
|
||||
$disabledbehaviours[] = $disable;
|
||||
set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
|
||||
}
|
||||
redirect($thispageurl);
|
||||
}
|
||||
|
||||
// Enable.
|
||||
if (($enable = optional_param('enable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($behaviours[$enable])) {
|
||||
print_error('unknownbehaviour', 'question', $thispageurl, $enable);
|
||||
}
|
||||
|
||||
if (!$archetypal[$enable]) {
|
||||
print_error('cannotenablebehaviour', 'question', $thispageurl, $enable);
|
||||
}
|
||||
|
||||
if (($key = array_search($enable, $disabledbehaviours)) !== false) {
|
||||
unset($disabledbehaviours[$key]);
|
||||
set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
|
||||
}
|
||||
redirect($thispageurl);
|
||||
}
|
||||
|
||||
// Move up in order.
|
||||
if (($up = optional_param('up', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($behaviours[$up])) {
|
||||
print_error('unknownbehaviour', 'question', $thispageurl, $up);
|
||||
}
|
||||
|
||||
// This function works fine for behaviours, as well as qtypes.
|
||||
$neworder = question_reorder_qtypes($sortedbehaviours, $up, -1);
|
||||
set_config('behavioursortorder', implode(',', $neworder), 'question');
|
||||
redirect($thispageurl);
|
||||
}
|
||||
|
||||
// Move down in order.
|
||||
if (($down = optional_param('down', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($behaviours[$down])) {
|
||||
print_error('unknownbehaviour', 'question', $thispageurl, $down);
|
||||
}
|
||||
|
||||
// This function works fine for behaviours, as well as qtypes.
|
||||
$neworder = question_reorder_qtypes($sortedbehaviours, $down, +1);
|
||||
set_config('behavioursortorder', implode(',', $neworder), 'question');
|
||||
redirect($thispageurl);
|
||||
}
|
||||
|
||||
// Delete.
|
||||
if (($delete = optional_param('delete', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
// Check it is OK to delete this question type.
|
||||
if ($delete == 'missing') {
|
||||
print_error('cannotdeletemissingbehaviour', 'question', $thispageurl);
|
||||
}
|
||||
|
||||
if (!isset($behaviours[$delete])) {
|
||||
print_error('unknownbehaviour', 'question', $thispageurl, $delete);
|
||||
}
|
||||
|
||||
$behaviourname = $sortedbehaviours[$delete];
|
||||
if ($counts[$delete] > 0) {
|
||||
print_error('cannotdeletebehaviourinuse', 'question', $thispageurl, $behaviourname);
|
||||
}
|
||||
if ($needed[$delete] > 0) {
|
||||
print_error('cannotdeleteneededbehaviour', 'question', $thispageurl, $behaviourname);
|
||||
}
|
||||
|
||||
// If not yet confirmed, display a confirmation message.
|
||||
if (!optional_param('confirm', '', PARAM_BOOL)) {
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('deletebehaviourareyousure', 'question', $behaviourname));
|
||||
echo $OUTPUT->confirm(
|
||||
get_string('deletebehaviourareyousuremessage', 'question', $behaviourname),
|
||||
new moodle_url($thispageurl, array('delete' => $delete, 'confirm' => 1)),
|
||||
$thispageurl);
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Do the deletion.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('deletingbehaviour', 'question', $behaviourname));
|
||||
|
||||
// Delete any configuration records.
|
||||
if (!unset_all_config_for_plugin('qbehaviour_' . $delete)) {
|
||||
echo $OUTPUT->notification(get_string('errordeletingconfig', 'admin', 'qbehaviour_' . $delete));
|
||||
}
|
||||
if (($key = array_search($delete, $disabledbehaviours)) !== false) {
|
||||
unset($disabledbehaviours[$key]);
|
||||
set_config('disabledbehaviours', implode(',', $disabledbehaviours), 'question');
|
||||
}
|
||||
$behaviourorder = explode(',', $config->behavioursortorder);
|
||||
if (($key = array_search($delete, $behaviourorder)) !== false) {
|
||||
unset($behaviourorder[$key]);
|
||||
set_config('behavioursortorder', implode(',', $behaviourorder), 'question');
|
||||
}
|
||||
|
||||
// Then the tables themselves
|
||||
drop_plugin_tables($delete, get_plugin_directory('qbehaviour', $delete) . '/db/install.xml', false);
|
||||
|
||||
// Remove event handlers and dequeue pending events
|
||||
events_uninstall('qbehaviour_' . $delete);
|
||||
|
||||
$a->behaviour = $behaviourname;
|
||||
$a->directory = get_plugin_directory('qbehaviour', $delete);
|
||||
echo $OUTPUT->box(get_string('qbehaviourdeletefiles', 'question', $a), 'generalbox', 'notice');
|
||||
echo $OUTPUT->continue_button($thispageurl);
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// End of process actions ==================================================
|
||||
|
||||
// Print the page heading.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('manageqbehaviours', 'admin'));
|
||||
|
||||
// Set up the table.
|
||||
$table = new flexible_table('qbehaviouradmintable');
|
||||
$table->define_baseurl($thispageurl);
|
||||
$table->define_columns(array('behaviour', 'numqas', 'version', 'requires',
|
||||
'available', 'delete'));
|
||||
$table->define_headers(array(get_string('behaviour', 'question'), get_string('numqas', 'question'),
|
||||
get_string('version'), get_string('requires', 'admin'),
|
||||
get_string('availableq', 'question'), get_string('delete')));
|
||||
$table->set_attribute('id', 'qbehaviours');
|
||||
$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
|
||||
$table->setup();
|
||||
|
||||
// Add a row for each question type.
|
||||
foreach ($sortedbehaviours as $behaviour => $behaviourname) {
|
||||
$row = array();
|
||||
|
||||
// Question icon and name.
|
||||
$row[] = $behaviourname;
|
||||
|
||||
// Count
|
||||
$row[] = $counts[$behaviour];
|
||||
|
||||
// Question version number.
|
||||
$version = get_config('qbehaviour_' . $behaviour, 'version');
|
||||
if ($version) {
|
||||
$row[] = $version;
|
||||
} else {
|
||||
$row[] = html_writer::tag('span', get_string('nodatabase', 'admin'), array('class' => 'disabled'));
|
||||
}
|
||||
|
||||
// Other question types required by this one.
|
||||
$requiredbehaviours = question_engine::get_behaviour_required_behaviours($behaviour);
|
||||
if (!empty($requiredbehaviours)) {
|
||||
$strrequiredbehaviours = array();
|
||||
foreach ($requiredbehaviours as $required) {
|
||||
$strrequiredbehaviours[] = $sortedbehaviours[$required];
|
||||
}
|
||||
$row[] = implode(', ', $strrequiredbehaviours);
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
// Are people allowed to create new questions of this type?
|
||||
$rowclass = '';
|
||||
if ($archetypal[$behaviour]) {
|
||||
$enabled = array_search($behaviour, $disabledbehaviours) === false;
|
||||
$icons = question_behaviour_enable_disable_icons($behaviour, $enabled);
|
||||
if (!$enabled) {
|
||||
$rowclass = 'dimmed_text';
|
||||
}
|
||||
} else {
|
||||
$icons = $OUTPUT->spacer() . ' ';
|
||||
}
|
||||
|
||||
// Move icons.
|
||||
$icons .= question_behaviour_icon_html('up', $behaviour, 't/up', get_string('up'), null);
|
||||
$icons .= question_behaviour_icon_html('down', $behaviour, 't/down', get_string('down'), null);
|
||||
$row[] = $icons;
|
||||
|
||||
// Delete link, if available.
|
||||
if ($needed[$behaviour]) {
|
||||
$row[] = '';
|
||||
} else {
|
||||
$row[] = html_writer::link(new moodle_url($thispageurl,
|
||||
array('delete' => $behaviour, 'sesskey' => sesskey())), get_string('delete'),
|
||||
array('title' => get_string('uninstallbehaviour', 'question')));
|
||||
}
|
||||
|
||||
$table->add_data($row, $rowclass);
|
||||
}
|
||||
|
||||
$table->finish_output();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
function question_behaviour_enable_disable_icons($behaviour, $enabled) {
|
||||
if ($enabled) {
|
||||
return question_behaviour_icon_html('disable', $behaviour, 'i/hide',
|
||||
get_string('enabled', 'question'), get_string('disable'));
|
||||
} else {
|
||||
return question_behaviour_icon_html('enable', $behaviour, 'i/show',
|
||||
get_string('disabled', 'question'), get_string('enable'));
|
||||
}
|
||||
}
|
||||
|
||||
function question_behaviour_icon_html($action, $behaviour, $icon, $alt, $tip) {
|
||||
global $OUTPUT;
|
||||
return $OUTPUT->action_icon(new moodle_url('/admin/qbehaviours.php',
|
||||
array($action => $behaviour, 'sesskey' => sesskey())),
|
||||
new pix_icon($icon, $alt, 'moodle', array('title' => '')),
|
||||
null, array('title' => $tip)) . ' ';
|
||||
}
|
||||
|
||||
+247
-266
@@ -1,312 +1,293 @@
|
||||
<?php
|
||||
// Allows the admin to manage question types.
|
||||
|
||||
// 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/>.
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
/**
|
||||
* Allows the admin to manage question types.
|
||||
*
|
||||
* @package moodlecore
|
||||
* @subpackage questionbank
|
||||
* @copyright 2008 Tim Hunt
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
/// Check permissions.
|
||||
require_login();
|
||||
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
require_capability('moodle/question:config', $systemcontext);
|
||||
$canviewreports = has_capability('report/questioninstances:view', $systemcontext);
|
||||
|
||||
admin_externalpage_setup('manageqtypes');
|
||||
|
||||
require_once(dirname(__FILE__) . '/../config.php');
|
||||
require_once($CFG->libdir . '/questionlib.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require_once($CFG->libdir . '/tablelib.php');
|
||||
|
||||
// Check permissions.
|
||||
require_login();
|
||||
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
require_capability('moodle/question:config', $systemcontext);
|
||||
$canviewreports = has_capability('report/questioninstances:view', $systemcontext);
|
||||
|
||||
admin_externalpage_setup('manageqtypes');
|
||||
$thispageurl = new moodle_url('/admin/qtypes.php');
|
||||
|
||||
$qtypes = question_bank::get_all_qtypes();
|
||||
|
||||
// Get some data we will need - question counts and which types are needed.
|
||||
$counts = $DB->get_records_sql("
|
||||
SELECT qtype, COUNT(1) as numquestions, SUM(hidden) as numhidden
|
||||
FROM {question} GROUP BY qtype", array());
|
||||
$needed = array();
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
if (!isset($counts[$qtypename])) {
|
||||
$counts[$qtypename] = new stdClass;
|
||||
$counts[$qtypename]->numquestions = 0;
|
||||
$counts[$qtypename]->numhidden = 0;
|
||||
/// Get some data we will need - question counts and which types are needed.
|
||||
$counts = $DB->get_records_sql("
|
||||
SELECT qtype, COUNT(1) as numquestions, SUM(hidden) as numhidden
|
||||
FROM {question} GROUP BY qtype", array());
|
||||
$needed = array();
|
||||
foreach ($QTYPES as $qtypename => $qtype) {
|
||||
if (!isset($counts[$qtypename])) {
|
||||
$counts[$qtypename] = new stdClass;
|
||||
$counts[$qtypename]->numquestions = 0;
|
||||
$counts[$qtypename]->numhidden = 0;
|
||||
}
|
||||
$needed[$qtypename] = $counts[$qtypename]->numquestions > 0;
|
||||
$counts[$qtypename]->numquestions -= $counts[$qtypename]->numhidden;
|
||||
}
|
||||
$needed[$qtypename] = $counts[$qtypename]->numquestions > 0;
|
||||
$counts[$qtypename]->numquestions -= $counts[$qtypename]->numhidden;
|
||||
}
|
||||
$needed['missingtype'] = true; // The system needs the missing question type.
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
foreach ($qtype->requires_qtypes() as $reqtype) {
|
||||
$needed[$reqtype] = true;
|
||||
$needed['missingtype'] = true; // The system needs the missing question type.
|
||||
foreach ($QTYPES as $qtypename => $qtype) {
|
||||
foreach ($qtype->requires_qtypes() as $reqtype) {
|
||||
$needed[$reqtype] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($counts as $qtypename => $count) {
|
||||
if (!isset($qtypes[$qtypename])) {
|
||||
$counts['missingtype']->numquestions += $count->numquestions - $count->numhidden;
|
||||
$counts['missingtype']->numhidden += $count->numhidden;
|
||||
}
|
||||
}
|
||||
|
||||
// Work of the correct sort order.
|
||||
$config = get_config('question');
|
||||
$sortedqtypes = array();
|
||||
foreach ($qtypes as $qtypename => $qtype) {
|
||||
$sortedqtypes[$qtypename] = $qtype->local_name();
|
||||
}
|
||||
$sortedqtypes = question_bank::sort_qtype_array($sortedqtypes, $config);
|
||||
|
||||
// Process actions ============================================================
|
||||
|
||||
// Disable.
|
||||
if (($disable = optional_param('disable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$disable])) {
|
||||
print_error('unknownquestiontype', 'question', $thispageurl, $disable);
|
||||
foreach ($counts as $qtypename => $count) {
|
||||
if (!isset($QTYPES[$qtypename])) {
|
||||
$counts['missingtype']->numquestions += $count->numquestions - $count->numhidden;
|
||||
$counts['missingtype']->numhidden += $count->numhidden;
|
||||
}
|
||||
}
|
||||
|
||||
set_config($disable . '_disabled', 1, 'question');
|
||||
redirect($thispageurl);
|
||||
}
|
||||
/// Work of the correct sort order.
|
||||
$config = get_config('question');
|
||||
$sortedqtypes = array();
|
||||
foreach ($QTYPES as $qtypename => $qtype) {
|
||||
$sortedqtypes[$qtypename] = $qtype->local_name();
|
||||
}
|
||||
$sortedqtypes = question_sort_qtype_array($sortedqtypes, $config);
|
||||
|
||||
// Enable.
|
||||
if (($enable = optional_param('enable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$enable])) {
|
||||
print_error('unknownquestiontype', 'question', $thispageurl, $enable);
|
||||
/// Process actions ============================================================
|
||||
|
||||
// Disable.
|
||||
if (($disable = optional_param('disable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$disable])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $disable);
|
||||
}
|
||||
|
||||
set_config($disable . '_disabled', 1, 'question');
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
|
||||
if (!$qtypes[$enable]->menu_name()) {
|
||||
print_error('cannotenable', 'question', $thispageurl, $enable);
|
||||
// Enable.
|
||||
if (($enable = optional_param('enable', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$enable])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $enable);
|
||||
}
|
||||
|
||||
if (!$QTYPES[$enable]->menu_name()) {
|
||||
print_error('cannotenable', 'question', admin_url('qtypes.php'), $enable);
|
||||
}
|
||||
|
||||
unset_config($enable . '_disabled', 'question');
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
|
||||
unset_config($enable . '_disabled', 'question');
|
||||
redirect($thispageurl);
|
||||
}
|
||||
// Move up in order.
|
||||
if (($up = optional_param('up', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$up])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $up);
|
||||
}
|
||||
|
||||
// Move up in order.
|
||||
if (($up = optional_param('up', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$up])) {
|
||||
print_error('unknownquestiontype', 'question', $thispageurl, $up);
|
||||
$neworder = question_reorder_qtypes($sortedqtypes, $up, -1);
|
||||
question_save_qtype_order($neworder, $config);
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
|
||||
$neworder = question_reorder_qtypes($sortedqtypes, $up, -1);
|
||||
question_save_qtype_order($neworder, $config);
|
||||
redirect($thispageurl);
|
||||
}
|
||||
// Move down in order.
|
||||
if (($down = optional_param('down', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($QTYPES[$down])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $down);
|
||||
}
|
||||
|
||||
// Move down in order.
|
||||
if (($down = optional_param('down', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
if (!isset($qtypes[$down])) {
|
||||
print_error('unknownquestiontype', 'question', $thispageurl, $down);
|
||||
$neworder = question_reorder_qtypes($sortedqtypes, $down, +1);
|
||||
question_save_qtype_order($neworder, $config);
|
||||
redirect(admin_url('qtypes.php'));
|
||||
}
|
||||
|
||||
$neworder = question_reorder_qtypes($sortedqtypes, $down, +1);
|
||||
question_save_qtype_order($neworder, $config);
|
||||
redirect($thispageurl);
|
||||
}
|
||||
// Delete.
|
||||
if (($delete = optional_param('delete', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
// Check it is OK to delete this question type.
|
||||
if ($delete == 'missingtype') {
|
||||
print_error('cannotdeletemissingqtype', 'admin', admin_url('qtypes.php'));
|
||||
}
|
||||
|
||||
// Delete.
|
||||
if (($delete = optional_param('delete', '', PARAM_SAFEDIR)) && confirm_sesskey()) {
|
||||
// Check it is OK to delete this question type.
|
||||
if ($delete == 'missingtype') {
|
||||
print_error('cannotdeletemissingqtype', 'question', $thispageurl);
|
||||
}
|
||||
if (!isset($QTYPES[$delete])) {
|
||||
print_error('unknownquestiontype', 'question', admin_url('qtypes.php'), $delete);
|
||||
}
|
||||
|
||||
if (!isset($qtypes[$delete])) {
|
||||
print_error('unknownquestiontype', 'question', $thispageurl, $delete);
|
||||
}
|
||||
$qtypename = $QTYPES[$delete]->local_name();
|
||||
if ($counts[$delete]->numquestions + $counts[$delete]->numhidden > 0) {
|
||||
print_error('cannotdeleteqtypeinuse', 'admin', admin_url('qtypes.php'), $qtypename);
|
||||
}
|
||||
|
||||
$qtypename = $qtypes[$delete]->local_name();
|
||||
if ($counts[$delete]->numquestions + $counts[$delete]->numhidden > 0) {
|
||||
print_error('cannotdeleteqtypeinuse', 'question', $thispageurl, $qtypename);
|
||||
}
|
||||
if ($needed[$delete] > 0) {
|
||||
print_error('cannotdeleteqtypeneeded', 'admin', admin_url('qtypes.php'), $qtypename);
|
||||
}
|
||||
|
||||
if ($needed[$delete] > 0) {
|
||||
print_error('cannotdeleteqtypeneeded', 'question', $thispageurl, $qtypename);
|
||||
}
|
||||
// If not yet confirmed, display a confirmation message.
|
||||
if (!optional_param('confirm', '', PARAM_BOOL)) {
|
||||
$qtypename = $QTYPES[$delete]->local_name();
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('deleteqtypeareyousure', 'admin', $qtypename));
|
||||
echo $OUTPUT->confirm(get_string('deleteqtypeareyousuremessage', 'admin', $qtypename),
|
||||
admin_url('qtypes.php?delete=' . $delete . '&confirm=1'),
|
||||
admin_url('qtypes.php'));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// If not yet confirmed, display a confirmation message.
|
||||
if (!optional_param('confirm', '', PARAM_BOOL)) {
|
||||
$qtypename = $qtypes[$delete]->local_name();
|
||||
// Do the deletion.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('deleteqtypeareyousure', 'question', $qtypename));
|
||||
echo $OUTPUT->confirm(get_string('deleteqtypeareyousuremessage', 'question', $qtypename),
|
||||
new moodle_url($thispageurl, array('delete' => $delete, 'confirm' => 1)),
|
||||
$thispageurl);
|
||||
echo $OUTPUT->heading(get_string('deletingqtype', 'admin', $qtypename));
|
||||
|
||||
// Delete any configuration records.
|
||||
if (!unset_all_config_for_plugin('qtype_' . $delete)) {
|
||||
echo $OUTPUT->notification(get_string('errordeletingconfig', 'admin', 'qtype_' . $delete));
|
||||
}
|
||||
unset_config($delete . '_disabled', 'question');
|
||||
unset_config($delete . '_sortorder', 'question');
|
||||
|
||||
// Then the tables themselves
|
||||
drop_plugin_tables($delete, $QTYPES[$delete]->plugin_dir() . '/db/install.xml', false);
|
||||
|
||||
// Remove event handlers and dequeue pending events
|
||||
events_uninstall('qtype/' . $delete);
|
||||
|
||||
$a->qtype = $qtypename;
|
||||
$a->directory = $QTYPES[$delete]->plugin_dir();
|
||||
echo $OUTPUT->box(get_string('qtypedeletefiles', 'admin', $a), 'generalbox', 'notice');
|
||||
echo $OUTPUT->continue_button(admin_url('qtypes.php'));
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
}
|
||||
|
||||
// Do the deletion.
|
||||
// End of process actions ==================================================
|
||||
|
||||
/// Print the page heading.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('deletingqtype', 'question', $qtypename));
|
||||
echo $OUTPUT->heading(get_string('manageqtypes', 'admin'));
|
||||
|
||||
// Delete any configuration records.
|
||||
if (!unset_all_config_for_plugin('qtype_' . $delete)) {
|
||||
echo $OUTPUT->notification(get_string('errordeletingconfig', 'admin', 'qtype_' . $delete));
|
||||
/// Set up the table.
|
||||
$table = new flexible_table('qtypeadmintable');
|
||||
$table->define_columns(array('questiontype', 'numquestions', 'version', 'requires',
|
||||
'availableto', 'delete', 'settings'));
|
||||
$table->define_headers(array(get_string('questiontype', 'admin'), get_string('numquestions', 'admin'),
|
||||
get_string('version'), get_string('requires', 'admin'), get_string('availableq', 'question'),
|
||||
get_string('delete'), get_string('settings')));
|
||||
$table->set_attribute('id', 'qtypes');
|
||||
$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
|
||||
$table->setup();
|
||||
|
||||
/// Add a row for each question type.
|
||||
$createabletypes = question_type_menu();
|
||||
foreach ($sortedqtypes as $qtypename => $localname) {
|
||||
$qtype = $QTYPES[$qtypename];
|
||||
$row = array();
|
||||
|
||||
// Question icon and name.
|
||||
$fakequestion = new stdClass;
|
||||
$fakequestion->qtype = $qtypename;
|
||||
$icon = print_question_icon($fakequestion, true);
|
||||
$row[] = $icon . ' ' . $localname;
|
||||
|
||||
// Number of questions of this type.
|
||||
if ($counts[$qtypename]->numquestions + $counts[$qtypename]->numhidden > 0) {
|
||||
if ($counts[$qtypename]->numhidden > 0) {
|
||||
$strcount = get_string('numquestionsandhidden', 'admin', $counts[$qtypename]);
|
||||
} else {
|
||||
$strcount = $counts[$qtypename]->numquestions;
|
||||
}
|
||||
if ($canviewreports) {
|
||||
$row[] = '<a href="' . admin_url('/report/questioninstances/index.php?qtype=' . $qtypename) .
|
||||
'" title="' . get_string('showdetails', 'admin') . '">' . $strcount . '</a>';
|
||||
} else {
|
||||
$strcount;
|
||||
}
|
||||
} else {
|
||||
$row[] = 0;
|
||||
}
|
||||
|
||||
// Question version number.
|
||||
$version = get_config('qtype_' . $qtypename, 'version');
|
||||
if ($version) {
|
||||
$row[] = $version;
|
||||
} else {
|
||||
$row[] = '<span class="disabled">' . get_string('nodatabase', 'admin') . '</span>';
|
||||
}
|
||||
|
||||
// Other question types required by this one.
|
||||
$requiredtypes = $qtype->requires_qtypes();
|
||||
$strtypes = array();
|
||||
if (!empty($requiredtypes)) {
|
||||
foreach ($requiredtypes as $required) {
|
||||
$strtypes[] = $QTYPES[$required]->local_name();
|
||||
}
|
||||
$row[] = implode(', ', $strtypes);
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
// Are people allowed to create new questions of this type?
|
||||
$rowclass = '';
|
||||
if ($qtype->menu_name()) {
|
||||
$createable = isset($createabletypes[$qtypename]);
|
||||
$icons = enable_disable_button($qtypename, $createable);
|
||||
if (!$createable) {
|
||||
$rowclass = 'dimmed_text';
|
||||
}
|
||||
} else {
|
||||
$icons = '<img src="' . $OUTPUT->pix_url('spacer') . '" alt="" class="spacer" />';
|
||||
}
|
||||
|
||||
// Move icons.
|
||||
$icons .= icon_html('up', $qtypename, 't/up', get_string('up'), '');
|
||||
$icons .= icon_html('down', $qtypename, 't/down', get_string('down'), '');
|
||||
$row[] = $icons;
|
||||
|
||||
// Delete link, if available.
|
||||
if ($needed[$qtypename]) {
|
||||
$row[] = '';
|
||||
} else {
|
||||
$row[] = '<a href="' . admin_url('qtypes.php?delete=' . $qtypename .
|
||||
'&sesskey=' . sesskey()) . '" title="' .
|
||||
get_string('uninstallqtype', 'admin') . '">' . get_string('delete') . '</a>';
|
||||
}
|
||||
|
||||
// Settings link, if available.
|
||||
$settings = admin_get_root()->locate('qtypesetting' . $qtypename);
|
||||
if ($settings instanceof admin_externalpage) {
|
||||
$row[] = '<a href="' . $settings->url .
|
||||
'">' . get_string('settings') . '</a>';
|
||||
} else if ($settings instanceof admin_settingpage) {
|
||||
$row[] = '<a href="' . admin_url('settings.php?section=qtypesetting' . $qtypename) .
|
||||
'">' . get_string('settings') . '</a>';
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
$table->add_data($row, $rowclass);
|
||||
}
|
||||
unset_config($delete . '_disabled', 'question');
|
||||
unset_config($delete . '_sortorder', 'question');
|
||||
|
||||
// Then the tables themselves
|
||||
drop_plugin_tables($delete, $qtypes[$delete]->plugin_dir() . '/db/install.xml', false);
|
||||
$table->finish_output();
|
||||
|
||||
// Remove event handlers and dequeue pending events
|
||||
events_uninstall('qtype_' . $delete);
|
||||
|
||||
$a->qtype = $qtypename;
|
||||
$a->directory = $qtypes[$delete]->plugin_dir();
|
||||
echo $OUTPUT->box(get_string('qtypedeletefiles', 'question', $a), 'generalbox', 'notice');
|
||||
echo $OUTPUT->continue_button($thispageurl);
|
||||
echo $OUTPUT->footer();
|
||||
exit;
|
||||
|
||||
function admin_url($endbit) {
|
||||
global $CFG;
|
||||
return $CFG->wwwroot . '/' . $CFG->admin . '/' . $endbit;
|
||||
}
|
||||
|
||||
// End of process actions ==================================================
|
||||
|
||||
// Print the page heading.
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('manageqtypes', 'admin'));
|
||||
|
||||
// Set up the table.
|
||||
$table = new flexible_table('qtypeadmintable');
|
||||
$table->define_baseurl($thispageurl);
|
||||
$table->define_columns(array('questiontype', 'numquestions', 'version', 'requires',
|
||||
'availableto', 'delete', 'settings'));
|
||||
$table->define_headers(array(get_string('questiontype', 'question'), get_string('numquestions', 'question'),
|
||||
get_string('version'), get_string('requires', 'admin'), get_string('availableq', 'question'),
|
||||
get_string('delete'), get_string('settings')));
|
||||
$table->set_attribute('id', 'qtypes');
|
||||
$table->set_attribute('class', 'generaltable generalbox boxaligncenter boxwidthwide');
|
||||
$table->setup();
|
||||
|
||||
// Add a row for each question type.
|
||||
$createabletypes = question_bank::get_creatable_qtypes();
|
||||
foreach ($sortedqtypes as $qtypename => $localname) {
|
||||
$qtype = $qtypes[$qtypename];
|
||||
$row = array();
|
||||
|
||||
// Question icon and name.
|
||||
$fakequestion = new stdClass;
|
||||
$fakequestion->qtype = $qtypename;
|
||||
$icon = print_question_icon($fakequestion, true);
|
||||
$row[] = $icon . ' ' . $localname;
|
||||
|
||||
// Number of questions of this type.
|
||||
if ($counts[$qtypename]->numquestions + $counts[$qtypename]->numhidden > 0) {
|
||||
if ($counts[$qtypename]->numhidden > 0) {
|
||||
$strcount = get_string('numquestionsandhidden', 'question', $counts[$qtypename]);
|
||||
} else {
|
||||
$strcount = $counts[$qtypename]->numquestions;
|
||||
}
|
||||
if ($canviewreports) {
|
||||
$row[] = html_writer::link(new moodle_url('/admin/report/questioninstances/index.php',
|
||||
array('qtype' => $qtypename)), $strcount, array('title' => get_string('showdetails', 'admin')));
|
||||
} else {
|
||||
$strcount;
|
||||
}
|
||||
} else {
|
||||
$row[] = 0;
|
||||
}
|
||||
|
||||
// Question version number.
|
||||
$version = get_config('qtype_' . $qtypename, 'version');
|
||||
if ($version) {
|
||||
$row[] = $version;
|
||||
} else {
|
||||
$row[] = html_writer::tag('span', get_string('nodatabase', 'admin'), array('class' => 'disabled'));
|
||||
}
|
||||
|
||||
// Other question types required by this one.
|
||||
$requiredtypes = $qtype->requires_qtypes();
|
||||
$strtypes = array();
|
||||
if (!empty($requiredtypes)) {
|
||||
foreach ($requiredtypes as $required) {
|
||||
$strtypes[] = $qtypes[$required]->local_name();
|
||||
}
|
||||
$row[] = implode(', ', $strtypes);
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
// Are people allowed to create new questions of this type?
|
||||
$rowclass = '';
|
||||
if ($qtype->menu_name()) {
|
||||
$createable = isset($createabletypes[$qtypename]);
|
||||
$icons = question_types_enable_disable_icons($qtypename, $createable);
|
||||
if (!$createable) {
|
||||
$rowclass = 'dimmed_text';
|
||||
}
|
||||
} else {
|
||||
$icons = $OUTPUT->spacer() . ' ';
|
||||
}
|
||||
|
||||
// Move icons.
|
||||
$icons .= question_type_icon_html('up', $qtypename, 't/up', get_string('up'), '');
|
||||
$icons .= question_type_icon_html('down', $qtypename, 't/down', get_string('down'), '');
|
||||
$row[] = $icons;
|
||||
|
||||
// Delete link, if available.
|
||||
if ($needed[$qtypename]) {
|
||||
$row[] = '';
|
||||
} else {
|
||||
$row[] = html_writer::link(new moodle_url($thispageurl,
|
||||
array('delete' => $qtypename, 'sesskey' => sesskey())), get_string('delete'),
|
||||
array('title' => get_string('uninstallqtype', 'question')));
|
||||
}
|
||||
|
||||
// Settings link, if available.
|
||||
$settings = admin_get_root()->locate('qtypesetting' . $qtypename);
|
||||
if ($settings instanceof admin_externalpage) {
|
||||
$row[] = html_writer::link($settings->url, get_string('settings'));
|
||||
} else if ($settings instanceof admin_settingpage) {
|
||||
$row[] = html_writer::link(new moodle_url('/admin/settings.php',
|
||||
array('section' => 'qtypesetting' . $qtypename)), get_string('settings'));
|
||||
} else {
|
||||
$row[] = '';
|
||||
}
|
||||
|
||||
$table->add_data($row, $rowclass);
|
||||
}
|
||||
|
||||
$table->finish_output();
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
function question_types_enable_disable_icons($qtypename, $createable) {
|
||||
function enable_disable_button($qtypename, $createable) {
|
||||
if ($createable) {
|
||||
return question_type_icon_html('disable', $qtypename, 'i/hide',
|
||||
get_string('enabled', 'question'), get_string('disable'));
|
||||
return icon_html('disable', $qtypename, 'i/hide', get_string('enabled', 'question'), get_string('disable'));
|
||||
} else {
|
||||
return question_type_icon_html('enable', $qtypename, 'i/show',
|
||||
get_string('disabled', 'question'), get_string('enable'));
|
||||
return icon_html('enable', $qtypename, 'i/show', get_string('disabled', 'question'), get_string('enable'));
|
||||
}
|
||||
}
|
||||
|
||||
function question_type_icon_html($action, $qtypename, $icon, $alt, $tip) {
|
||||
function icon_html($action, $qtypename, $icon, $alt, $tip) {
|
||||
global $OUTPUT;
|
||||
return $OUTPUT->action_icon(new moodle_url('/admin/qtypes.php',
|
||||
array($action => $qtypename, 'sesskey' => sesskey())),
|
||||
new pix_icon($icon, $alt, 'moodle', array('title' => '')),
|
||||
null, array('title' => $tip)) . ' ';
|
||||
if ($tip) {
|
||||
$tip = 'title="' . $tip . '" ';
|
||||
}
|
||||
$html = ' <form action="' . admin_url('qtypes.php') . '" method="post"><div>';
|
||||
$html .= '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
|
||||
$html .= '<input type="image" name="' . $action . '" value="' . $qtypename .
|
||||
'" src="' . $OUTPUT->pix_url($icon) . '" alt="' . $alt . '" ' . $tip . '/>';
|
||||
$html .= '</div></form>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,296 +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 for core_admin subsystem
|
||||
*
|
||||
* @package core
|
||||
* @subpackage admin
|
||||
* @copyright 2011 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->libdir . '/pluginlib.php');
|
||||
|
||||
/**
|
||||
* Standard HTML output renderer for core_admin subsystem
|
||||
*/
|
||||
class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
/**
|
||||
* Displays all known plugins and information about their installation or upgrade
|
||||
*
|
||||
* This default implementation renders all plugins into one big table. The rendering
|
||||
* options support:
|
||||
* (bool)full = false: whether to display up-to-date plugins, too
|
||||
*
|
||||
* @param array $plugininfo as returned by {@see plugin_manager::get_plugins()}
|
||||
* @param array $options rendering options
|
||||
* @return string HTML code
|
||||
*/
|
||||
public function plugins_check(array $plugininfo, array $options = null) {
|
||||
|
||||
if (empty($plugininfo)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (empty($options)) {
|
||||
$options = array(
|
||||
'full' => false,
|
||||
);
|
||||
}
|
||||
|
||||
$pluginman = plugin_manager::instance();
|
||||
|
||||
$table = new html_table();
|
||||
$table->id = 'plugins-check';
|
||||
$table->head = array(
|
||||
get_string('displayname', 'core_plugin'),
|
||||
get_string('rootdir', 'core_plugin'),
|
||||
get_string('source', 'core_plugin'),
|
||||
get_string('versiondb', 'core_plugin'),
|
||||
get_string('versiondisk', 'core_plugin'),
|
||||
get_string('status', 'core_plugin'),
|
||||
);
|
||||
$table->colclasses = array(
|
||||
'displayname', 'rootdir', 'source', 'versiondb', 'versiondisk', 'status',
|
||||
);
|
||||
$table->data = array();
|
||||
|
||||
$numofhighlighted = array(); // number of highlighted rows per this subsection
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
|
||||
$header = new html_table_cell($pluginman->plugintype_name_plural($type));
|
||||
$header->header = true;
|
||||
$header->colspan = count($table->head);
|
||||
$header = new html_table_row(array($header));
|
||||
$header->attributes['class'] = 'plugintypeheader type-' . $type;
|
||||
|
||||
$numofhighlighted[$type] = 0;
|
||||
|
||||
if (empty($plugins) and $options['full']) {
|
||||
$msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
|
||||
$msg->colspan = count($table->head);
|
||||
$row = new html_table_row(array($msg));
|
||||
$row->attributes['class'] .= 'msg msg-noneinstalled';
|
||||
$table->data[] = $header;
|
||||
$table->data[] = $row;
|
||||
continue;
|
||||
}
|
||||
|
||||
$plugintyperows = array();
|
||||
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
$row = new html_table_row();
|
||||
$row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
|
||||
|
||||
if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
|
||||
$icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
|
||||
} else {
|
||||
$icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
|
||||
}
|
||||
$displayname = $icon . ' ' . $plugin->displayname;
|
||||
$displayname = new html_table_cell($displayname);
|
||||
|
||||
$rootdir = new html_table_cell($plugin->get_dir());
|
||||
|
||||
if ($isstandard = $plugin->is_standard()) {
|
||||
$row->attributes['class'] .= ' standard';
|
||||
$source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
|
||||
} else {
|
||||
$row->attributes['class'] .= ' extension';
|
||||
$source = new html_table_cell(get_string('sourceext', 'core_plugin'));
|
||||
}
|
||||
|
||||
$versiondb = new html_table_cell($plugin->versiondb);
|
||||
$versiondisk = new html_table_cell($plugin->versiondisk);
|
||||
|
||||
$statuscode = $plugin->get_status();
|
||||
$row->attributes['class'] .= ' status-' . $statuscode;
|
||||
|
||||
$status = new html_table_cell(get_string('status_' . $statuscode, 'core_plugin'));
|
||||
|
||||
if ($isstandard and in_array($statuscode, array(plugin_manager::PLUGIN_STATUS_NODB, plugin_manager::PLUGIN_STATUS_UPTODATE))) {
|
||||
if (empty($options['full'])) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$numofhighlighted[$type]++;
|
||||
}
|
||||
|
||||
$row->cells = array($displayname, $rootdir, $source, $versiondb, $versiondisk, $status);
|
||||
$plugintyperows[] = $row;
|
||||
}
|
||||
|
||||
if (empty($numofhighlighted[$type]) and empty($options['full'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$table->data[] = $header;
|
||||
$table->data = array_merge($table->data, $plugintyperows);
|
||||
}
|
||||
|
||||
$sumofhighlighted = array_sum($numofhighlighted);
|
||||
|
||||
if ($sumofhighlighted == 0) {
|
||||
$out = $this->output->container_start('nonehighlighted', 'plugins-check-info');
|
||||
$out .= $this->output->heading(get_string('nonehighlighted', 'core_plugin'));
|
||||
if (empty($options['full'])) {
|
||||
$out .= html_writer::link(new moodle_url('/admin/index.php',
|
||||
array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
|
||||
get_string('nonehighlightedinfo', 'core_plugin'));
|
||||
}
|
||||
$out .= $this->output->container_end();
|
||||
|
||||
} else {
|
||||
$out = $this->output->container_start('somehighlighted', 'plugins-check-info');
|
||||
$out .= $this->output->heading(get_string('somehighlighted', 'core_plugin', $sumofhighlighted));
|
||||
if (empty($options['full'])) {
|
||||
$out .= html_writer::link(new moodle_url('/admin/index.php',
|
||||
array('confirmupgrade' => 1, 'confirmrelease' => 1, 'showallplugins' => 1)),
|
||||
get_string('somehighlightedinfo', 'core_plugin'));
|
||||
}
|
||||
$out .= $this->output->container_end();
|
||||
}
|
||||
|
||||
if ($sumofhighlighted > 0 or $options['full']) {
|
||||
$out .= html_writer::table($table);
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays all known plugins and links to manage them
|
||||
*
|
||||
* This default implementation renders all plugins into one big table.
|
||||
*
|
||||
* @param array $plugininfo as returned by {@see plugin_manager::get_plugins()}
|
||||
* @return string HTML code
|
||||
*/
|
||||
public function plugins_control_panel(array $plugininfo) {
|
||||
|
||||
if (empty($plugininfo)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$pluginman = plugin_manager::instance();
|
||||
|
||||
$table = new html_table();
|
||||
$table->id = 'plugins-control-panel';
|
||||
$table->head = array(
|
||||
get_string('displayname', 'core_plugin'),
|
||||
get_string('systemname', 'core_plugin'),
|
||||
get_string('source', 'core_plugin'),
|
||||
get_string('version', 'core_plugin'),
|
||||
get_string('availability', 'core_plugin'),
|
||||
get_string('settings', 'core_plugin'),
|
||||
get_string('uninstall','core_plugin'),
|
||||
);
|
||||
$table->colclasses = array(
|
||||
'displayname', 'systemname', 'source', 'version', 'availability', 'settings', 'uninstall',
|
||||
);
|
||||
|
||||
foreach ($plugininfo as $type => $plugins) {
|
||||
|
||||
$header = new html_table_cell($pluginman->plugintype_name_plural($type));
|
||||
$header->header = true;
|
||||
$header->colspan = count($table->head);
|
||||
$header = new html_table_row(array($header));
|
||||
$header->attributes['class'] = 'plugintypeheader type-' . $type;
|
||||
$table->data[] = $header;
|
||||
|
||||
if (empty($plugins)) {
|
||||
$msg = new html_table_cell(get_string('noneinstalled', 'core_plugin'));
|
||||
$msg->colspan = count($table->head);
|
||||
$row = new html_table_row(array($msg));
|
||||
$row->attributes['class'] .= 'msg msg-noneinstalled';
|
||||
$table->data[] = $row;
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($plugins as $name => $plugin) {
|
||||
$row = new html_table_row();
|
||||
$row->attributes['class'] = 'type-' . $plugin->type . ' name-' . $plugin->type . '_' . $plugin->name;
|
||||
|
||||
if ($this->page->theme->resolve_image_location('icon', $plugin->type . '_' . $plugin->name)) {
|
||||
$icon = $this->output->pix_icon('icon', '', $plugin->type . '_' . $plugin->name, array('class' => 'smallicon pluginicon'));
|
||||
} else {
|
||||
$icon = $this->output->pix_icon('spacer', '', 'moodle', array('class' => 'smallicon pluginicon noicon'));
|
||||
}
|
||||
if ($plugin->get_status() === plugin_manager::PLUGIN_STATUS_MISSING) {
|
||||
$msg = html_writer::tag('span', get_string('status_missing', 'core_plugin'), array('class' => 'notifyproblem'));
|
||||
$row->attributes['class'] .= ' missingfromdisk';
|
||||
} else {
|
||||
$msg = '';
|
||||
}
|
||||
$displayname = $icon . ' ' . $plugin->displayname . ' ' . $msg;
|
||||
$displayname = new html_table_cell($displayname);
|
||||
|
||||
$systemname = new html_table_cell($plugin->type . '_' . $plugin->name);
|
||||
|
||||
if ($plugin->is_standard()) {
|
||||
$row->attributes['class'] .= ' standard';
|
||||
$source = new html_table_cell(get_string('sourcestd', 'core_plugin'));
|
||||
} else {
|
||||
$row->attributes['class'] .= ' extension';
|
||||
$source = new html_table_cell(get_string('sourceext', 'core_plugin'));
|
||||
}
|
||||
|
||||
$version = new html_table_cell($plugin->versiondb);
|
||||
|
||||
$isenabled = $plugin->is_enabled();
|
||||
if (is_null($isenabled)) {
|
||||
$availability = new html_table_cell('');
|
||||
} else if ($isenabled) {
|
||||
$row->attributes['class'] .= ' enabled';
|
||||
$icon = $this->output->pix_icon('i/hide', get_string('pluginenabled', 'core_plugin'));
|
||||
$availability = new html_table_cell($icon . ' ' . get_string('pluginenabled', 'core_plugin'));
|
||||
} else {
|
||||
$row->attributes['class'] .= ' disabled';
|
||||
$icon = $this->output->pix_icon('i/show', get_string('plugindisabled', 'core_plugin'));
|
||||
$availability = new html_table_cell($icon . ' ' . get_string('plugindisabled', 'core_plugin'));
|
||||
}
|
||||
|
||||
$settingsurl = $plugin->get_settings_url();
|
||||
if (is_null($settingsurl)) {
|
||||
$settings = new html_table_cell('');
|
||||
} else {
|
||||
$settings = html_writer::link($settingsurl, get_string('settings', 'core_plugin'));
|
||||
$settings = new html_table_cell($settings);
|
||||
}
|
||||
|
||||
$uninstallurl = $plugin->get_uninstall_url();
|
||||
if (is_null($uninstallurl)) {
|
||||
$uninstall = new html_table_cell('');
|
||||
} else {
|
||||
$uninstall = html_writer::link($uninstallurl, get_string('uninstall', 'core_plugin'));
|
||||
$uninstall = new html_table_cell($uninstall);
|
||||
}
|
||||
|
||||
$row->cells = array(
|
||||
$displayname, $systemname, $source, $version, $availability, $settings, $uninstall
|
||||
);
|
||||
$table->data[] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return html_writer::table($table);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,6 @@
|
||||
defined('MOODLE_INTERNAL') || die;
|
||||
|
||||
// profiling report, added to development
|
||||
if (extension_loaded('xhprof') && function_exists('xhprof_enable') && (!empty($CFG->profilingenabled) || !empty($CFG->earlyprofilingenabled))) {
|
||||
if (extension_loaded('xhprof') && function_exists('xhprof_enable') && !empty($CFG->profilingenabled)) {
|
||||
$ADMIN->add('development', new admin_externalpage('reportprofiling', get_string('pluginname', 'report_profiling'), "$CFG->wwwroot/$CFG->admin/report/profiling/index.php", 'moodle/site:config'));
|
||||
}
|
||||
|
||||
@@ -22,9 +22,8 @@ echo $OUTPUT->header();
|
||||
add_to_log(SITEID, "admin", "report questioninstances", "report/questioninstances/index.php?qtype=$requestedqtype", $requestedqtype);
|
||||
|
||||
// Prepare the list of capabilities to choose from
|
||||
$qtypes = question_bank::get_all_qtypes();
|
||||
$qtypechoices = array();
|
||||
foreach ($qtypes as $qtype) {
|
||||
foreach ($QTYPES as $qtype) {
|
||||
$qtypechoices[$qtype->name()] = $qtype->local_name();
|
||||
}
|
||||
|
||||
@@ -46,7 +45,7 @@ if ($requestedqtype) {
|
||||
|
||||
// Work out the bits needed for the SQL WHERE clauses.
|
||||
if ($requestedqtype == 'missingtype') {
|
||||
$othertypes = array_keys($qtypes);
|
||||
$othertypes = array_keys($QTYPES);
|
||||
$key = array_search('missingtype', $othertypes);
|
||||
unset($othertypes[$key]);
|
||||
list($sqlqtypetest, $params) = $DB->get_in_or_equal($othertypes, SQL_PARAMS_QM, '', false);
|
||||
@@ -59,8 +58,7 @@ if ($requestedqtype) {
|
||||
} else {
|
||||
$sqlqtypetest = 'WHERE qtype = ?';
|
||||
$params = array($requestedqtype);
|
||||
$title = get_string('reportforqtype', 'report_questioninstances',
|
||||
question_bank::get_qtype($requestedqtype)->local_name());
|
||||
$title = get_string('reportforqtype', 'report_questioninstances', $QTYPES[$requestedqtype]->local_name());
|
||||
}
|
||||
|
||||
// Get the question counts, and all the context information, for each
|
||||
|
||||
@@ -18,8 +18,6 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_configcheckbox('allowuserblockhiding', get_string('allowuserblockhiding', 'admin'), get_string('configallowuserblockhiding', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('allowblockstodock', get_string('allowblockstodock', 'admin'), get_string('configallowblockstodock', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configtextarea('custommenuitems', get_string('custommenuitems', 'admin'), get_string('configcustommenuitems', 'admin'), '', PARAM_TEXT, '50', '10'));
|
||||
$temp->add(new admin_setting_configcheckbox('enabledevicedetection', get_string('enabledevicedetection', 'admin'), get_string('configenabledevicedetection', 'admin'), 1));
|
||||
$temp->add(new admin_setting_devicedetectregex('devicedetectregex', get_string('devicedetectregex', 'admin'), get_string('devicedetectregex_desc', 'admin'), ''));
|
||||
$ADMIN->add('themes', $temp);
|
||||
$ADMIN->add('themes', new admin_externalpage('themeselector', get_string('themeselector','admin'), $CFG->wwwroot . '/theme/index.php'));
|
||||
|
||||
|
||||
@@ -21,11 +21,10 @@ if ($hassiteconfig
|
||||
$formcourseformats[$courseformat] = get_string('pluginname', "format_$courseformat");
|
||||
}
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/format', get_string('format'), get_string('coursehelpformat'), 'weeks',$formcourseformats));
|
||||
|
||||
$temp->add(new admin_setting_configtext('moodlecourse/maxsections', get_string('maxnumberweeks'), get_string('maxnumberweeks_desc'), 52));
|
||||
|
||||
$temp->add(new admin_settings_num_course_sections('moodlecourse/numsections', get_string('numberweeks'), get_string('coursehelpnumberweeks'), 10));
|
||||
|
||||
for ($i=1; $i<=52; $i++) {
|
||||
$sectionmenu[$i] = "$i";
|
||||
}
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/numsections', get_string('numberweeks'), get_string('coursehelpnumberweeks'), 10,$sectionmenu));
|
||||
$choices = array();
|
||||
$choices['0'] = get_string('hiddensectionscollapsed');
|
||||
$choices['1'] = get_string('hiddensectionsinvisible');
|
||||
@@ -34,14 +33,15 @@ if ($hassiteconfig
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/newsitems', get_string('newsitemsnumber'), get_string('coursehelpnewsitemsnumber'), 5,$options));
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/showgrades', get_string('showgrades'), get_string('coursehelpshowgrades'), 1,array(0 => get_string('no'), 1 => get_string('yes'))));
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/showreports', get_string('showreports'), '', 0,array(0 => get_string('no'), 1 => get_string('yes'))));
|
||||
|
||||
if (isset($CFG->maxbytes)) {
|
||||
$choices = get_max_upload_sizes($CFG->maxbytes);
|
||||
} else {
|
||||
$choices = get_max_upload_sizes();
|
||||
}
|
||||
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/maxbytes', get_string('maximumupload'), get_string('coursehelpmaximumupload'), key($choices), $choices));
|
||||
|
||||
|
||||
if (!empty($CFG->legacyfilesinnewcourses)) {
|
||||
$choices = array('0'=>get_string('no'), '2'=>get_string('yes'));
|
||||
$temp->add(new admin_setting_configselect('moodlecourse/legacyfiles', get_string('courselegacyfiles'), get_string('courselegacyfiles_help'), key($choices), $choices));
|
||||
@@ -142,7 +142,7 @@ if ($hassiteconfig
|
||||
|
||||
|
||||
$temp->add(new admin_setting_heading('automatedsettings', get_string('automatedsettings','backup'), ''));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_users', get_string('users'), get_string('backupusershelp'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_users', get_string('generalusers', 'backup'), get_string('configgeneralusers', 'backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_role_assignments', get_string('generalroleassignments','backup'), get_string('configgeneralroleassignments','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_user_files', get_string('generaluserfiles', 'backup'), get_string('configgeneraluserfiles','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_activities', get_string('generalactivities','backup'), get_string('configgeneralactivities','backup'), 1));
|
||||
@@ -150,7 +150,7 @@ if ($hassiteconfig
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_filters', get_string('generalfilters','backup'), get_string('configgeneralfilters','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_comments', get_string('generalcomments','backup'), get_string('configgeneralcomments','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_userscompletion', get_string('generaluserscompletion','backup'), get_string('configgeneraluserscompletion','backup'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_logs', get_string('logs'), get_string('backuplogshelp'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_logs', get_string('generallogs', 'backup'), get_string('configgenerallogs', 'backup'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('backup/backup_auto_histories', get_string('generalhistories','backup'), get_string('configgeneralhistories','backup'), 0));
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
if ($hassiteconfig) {
|
||||
$ADMIN->add('modules', new admin_page_pluginsoverview());
|
||||
$ADMIN->add('modules', new admin_category('modsettings', get_string('activitymodules')));
|
||||
$ADMIN->add('modsettings', new admin_page_managemods());
|
||||
$modules = $DB->get_records('modules', array(), "name ASC");
|
||||
@@ -46,27 +45,6 @@ if ($hassiteconfig) {
|
||||
}
|
||||
}
|
||||
|
||||
// message outputs
|
||||
$ADMIN->add('modules', new admin_category('messageoutputs', get_string('messageoutputs', 'message')));
|
||||
$ADMIN->add('messageoutputs', new admin_page_managemessageoutputs());
|
||||
$ADMIN->add('messageoutputs', new admin_page_defaultmessageoutputs());
|
||||
require_once($CFG->dirroot.'/message/lib.php');
|
||||
$processors = get_message_processors();
|
||||
foreach ($processors as $processor) {
|
||||
$processorname = $processor->name;
|
||||
if (!$processor->available) {
|
||||
continue;
|
||||
}
|
||||
if ($processor->hassettings) {
|
||||
$strprocessorname = get_string('pluginname', 'message_'.$processorname);
|
||||
$settings = new admin_settingpage('messagesetting'.$processorname, $strprocessorname, 'moodle/site:config', !$processor->enabled);
|
||||
include($CFG->dirroot.'/message/output/'.$processor->name.'/settings.php');
|
||||
if ($settings) {
|
||||
$ADMIN->add('messageoutputs', $settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// authentication plugins
|
||||
$ADMIN->add('modules', new admin_category('authsettings', get_string('authentication', 'admin')));
|
||||
|
||||
@@ -74,7 +52,6 @@ if ($hassiteconfig) {
|
||||
$temp->add(new admin_setting_manageauths());
|
||||
$temp->add(new admin_setting_heading('manageauthscommonheading', get_string('commonsettings', 'admin'), ''));
|
||||
$temp->add(new admin_setting_special_registerauth());
|
||||
$temp->add(new admin_setting_configcheckbox('loginpageautofocus', get_string('loginpageautofocus', 'admin'), get_string('loginpageautofocus_help', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configselect('guestloginbutton', get_string('guestloginbutton', 'auth'),
|
||||
get_string('showguestlogin', 'auth'), '1', array('0'=>get_string('hide'), '1'=>get_string('show'))));
|
||||
$temp->add(new admin_setting_configtext('alternateloginurl', get_string('alternateloginurl', 'auth'),
|
||||
@@ -344,11 +321,10 @@ if ($hassiteconfig) {
|
||||
$temp = new admin_settingpage('webservicesoverview', get_string('webservicesoverview', 'webservice'));
|
||||
$temp->add(new admin_setting_webservicesoverview());
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
//API documentation
|
||||
$ADMIN->add('webservicesettings', new admin_externalpage('webservicedocumentation', get_string('wsdocapi', 'webservice'), "$CFG->wwwroot/$CFG->admin/webservice/documentation.php", 'moodle/site:config', false));
|
||||
/// manage service
|
||||
$temp = new admin_settingpage('externalservices', get_string('externalservices', 'webservice'));
|
||||
$enablemobiledocurl = new moodle_url(get_docs_url('Enable_mobile_web_services'));
|
||||
$enablemobiledoclink = html_writer::link($enablemobiledocurl, get_string('documentation'));
|
||||
$temp->add(new admin_setting_enablemobileservice('enablemobilewebservice', get_string('enablemobilewebservice', 'admin'), get_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), 0));
|
||||
$temp->add(new admin_setting_heading('manageserviceshelpexplaination', get_string('information', 'webservice'), get_string('servicehelpexplanation', 'webservice')));
|
||||
$temp->add(new admin_setting_manageexternalservices());
|
||||
$ADMIN->add('webservicesettings', $temp);
|
||||
@@ -395,10 +371,6 @@ if ($hassiteconfig) {
|
||||
|
||||
// Question type settings
|
||||
if ($hassiteconfig || has_capability('moodle/question:config', $systemcontext)) {
|
||||
// Question behaviour settings.
|
||||
$ADMIN->add('modules', new admin_category('qbehavioursettings', get_string('questionbehaviours', 'admin')));
|
||||
$ADMIN->add('qbehavioursettings', new admin_page_manageqbehaviours());
|
||||
|
||||
// Question type settings.
|
||||
$ADMIN->add('modules', new admin_category('qtypesettings', get_string('questiontypes', 'admin')));
|
||||
$ADMIN->add('qtypesettings', new admin_page_manageqtypes());
|
||||
|
||||
@@ -71,6 +71,7 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
$temp->add(new admin_setting_configcheckbox('groupenrolmentkeypolicy', get_string('groupenrolmentkeypolicy', 'admin'), get_string('groupenrolmentkeypolicy_desc', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('disableuserimages', get_string('disableuserimages', 'admin'), get_string('configdisableuserimages', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configcheckbox('emailchangeconfirmation', get_string('emailchangeconfirmation', 'admin'), get_string('configemailchangeconfirmation', 'admin'), 1));
|
||||
$temp->add(new admin_setting_configcheckbox('strictformsrequired', get_string('strictformsrequired', 'admin'), get_string('configstrictformsrequired', 'admin'), 0));
|
||||
$ADMIN->add('security', $temp);
|
||||
|
||||
|
||||
@@ -91,9 +92,14 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
|
||||
'all' => get_string('fulllistofcourses'),
|
||||
'requested' => get_string('requestedcourses'))));
|
||||
$temp->add(new admin_setting_configcheckbox('restrictbydefault', get_string('restrictbydefault', 'admin'), get_string('configrestrictbydefault', 'admin'), 0));
|
||||
$temp->add(new admin_setting_configmultiselect_modules('defaultallowedmodules',
|
||||
get_string('defaultallowedmodules', 'admin'),
|
||||
get_string('configdefaultallowedmodules', 'admin')));
|
||||
if (!$options = $DB->get_records('modules')) {
|
||||
$options = array();
|
||||
}
|
||||
$options2 = array();
|
||||
foreach ($options as $option) {
|
||||
$options2[$option->id] = $option->name;
|
||||
}
|
||||
$temp->add(new admin_setting_configmultiselect('defaultallowedmodules', get_string('defaultallowedmodules', 'admin'), get_string('configdefaultallowedmodules', 'admin'), array(), $options2));
|
||||
$ADMIN->add('security', $temp);
|
||||
|
||||
|
||||
|
||||
@@ -17,8 +17,46 @@ $ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
// "supportcontact" settingpage
|
||||
$temp = new admin_settingpage('supportcontact', get_string('supportcontact','admin'));
|
||||
// "email" settingpage
|
||||
$temp = new admin_settingpage('mail', get_string('mail','admin'));
|
||||
$temp->add(new admin_setting_configtext('smtphosts', get_string('smtphosts', 'admin'), get_string('configsmtphosts', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('smtpuser', get_string('smtpuser', 'admin'), get_string('configsmtpuser', 'admin'), '', PARAM_NOTAGS));
|
||||
$temp->add(new admin_setting_configpasswordunmask('smtppass', get_string('smtppass', 'admin'), get_string('configsmtpuser', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('smtpmaxbulk', get_string('smtpmaxbulk', 'admin'), get_string('configsmtpmaxbulk', 'admin'), 1, PARAM_INT));
|
||||
$temp->add(new admin_setting_configtext('noreplyaddress', get_string('noreplyaddress', 'admin'), get_string('confignoreplyaddress', 'admin'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_NOTAGS));
|
||||
$temp->add(new admin_setting_configselect('digestmailtime', get_string('digestmailtime', 'admin'), get_string('configdigestmailtime', 'admin'), 17, array('00' => '00',
|
||||
'01' => '01',
|
||||
'02' => '02',
|
||||
'03' => '03',
|
||||
'04' => '04',
|
||||
'05' => '05',
|
||||
'06' => '06',
|
||||
'07' => '07',
|
||||
'08' => '08',
|
||||
'09' => '09',
|
||||
'10' => '10',
|
||||
'11' => '11',
|
||||
'12' => '12',
|
||||
'13' => '13',
|
||||
'14' => '14',
|
||||
'15' => '15',
|
||||
'16' => '16',
|
||||
'17' => '17',
|
||||
'18' => '18',
|
||||
'19' => '19',
|
||||
'20' => '20',
|
||||
'21' => '21',
|
||||
'22' => '22',
|
||||
'23' => '23')));
|
||||
$charsets = get_list_of_charsets();
|
||||
unset($charsets['UTF-8']); // not needed here
|
||||
$options = array();
|
||||
$options['0'] = 'UTF-8';
|
||||
$options = array_merge($options, $charsets);
|
||||
$temp->add(new admin_setting_configselect('sitemailcharset', get_string('sitemailcharset', 'admin'), get_string('configsitemailcharset','admin'), '0', $options));
|
||||
$temp->add(new admin_setting_configcheckbox('allowusermailcharset', get_string('allowusermailcharset', 'admin'), get_string('configallowusermailcharset', 'admin'), 0));
|
||||
$options = array('LF'=>'LF', 'CRLF'=>'CRLF');
|
||||
$temp->add(new admin_setting_configselect('mailnewline', get_string('mailnewline', 'admin'), get_string('configmailnewline','admin'), 'LF', $options));
|
||||
if (isloggedin()) {
|
||||
global $USER;
|
||||
$primaryadminemail = $USER->email;
|
||||
@@ -35,6 +73,17 @@ $temp->add(new admin_setting_configtext('supportpage', get_string('supportpage',
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
// Jabber settingpage
|
||||
$temp = new admin_settingpage('jabber', get_string('jabber', 'admin'));
|
||||
$temp->add(new admin_setting_configtext('jabberhost', get_string('jabberhost', 'admin'), get_string('configjabberhost', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('jabberserver', get_string('jabberserver', 'admin'), get_string('configjabberserver', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configtext('jabberusername', get_string('jabberusername', 'admin'), get_string('configjabberusername', 'admin'), '', PARAM_RAW));
|
||||
$temp->add(new admin_setting_configpasswordunmask('jabberpassword', get_string('jabberpassword', 'admin'), get_string('configjabberpassword', 'admin'), ''));
|
||||
$temp->add(new admin_setting_configtext('jabberport', get_string('jabberport', 'admin'), get_string('configjabberport', 'admin'), 5222, PARAM_INT));
|
||||
$ADMIN->add('server', $temp);
|
||||
|
||||
|
||||
|
||||
// "sessionhandling" settingpage
|
||||
$temp = new admin_settingpage('sessionhandling', get_string('sessionhandling', 'admin'));
|
||||
$temp->add(new admin_setting_configcheckbox('dbsessions', get_string('dbsessions', 'admin'), get_string('configdbsessions', 'admin'), 1));
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Web services API documentation
|
||||
*
|
||||
* @package webservice
|
||||
* @copyright 2011 Moodle Pty Ltd (http://moodle.com)
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @author Jerome Mouneyrac
|
||||
*/
|
||||
require_once('../../config.php');
|
||||
require_once($CFG->libdir . '/adminlib.php');
|
||||
require($CFG->dirroot . '/webservice/lib.php');
|
||||
|
||||
admin_externalpage_setup('webservicedocumentation');
|
||||
|
||||
// get all the function descriptions
|
||||
$functions = $DB->get_records('external_functions', array(), 'name');
|
||||
$functiondescs = array();
|
||||
foreach ($functions as $function) {
|
||||
$functiondescs[$function->name] = external_function_info($function);
|
||||
}
|
||||
|
||||
//display the documentation for all documented protocols,
|
||||
//regardless if they are activated or not
|
||||
$protocols = array();
|
||||
$protocols['rest'] = true;
|
||||
$protocols['xmlrpc'] = true;
|
||||
|
||||
/// Check if we are in printable mode
|
||||
$printableformat = optional_param('print', false, PARAM_BOOL);
|
||||
|
||||
/// OUTPUT
|
||||
echo $OUTPUT->header();
|
||||
|
||||
$renderer = $PAGE->get_renderer('core', 'webservice');
|
||||
echo $renderer->documentation_html($functiondescs,
|
||||
$printableformat, $protocols, array(), $PAGE->url);
|
||||
|
||||
/// trigger browser print operation
|
||||
if (!empty($printableformat)) {
|
||||
$PAGE->requires->js_function_call('window.print', array());
|
||||
}
|
||||
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
+36
-1
@@ -360,7 +360,7 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
* @return boolean result
|
||||
*/
|
||||
function iscreator($username) {
|
||||
if ((empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) {
|
||||
if (empty($this->config->host_url) or (empty($this->config->attrcreators) && empty($this->config->groupecreators)) or empty($this->config->memberattribute)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -405,4 +405,39 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads user information from LDAP and returns it as array()
|
||||
*
|
||||
* If no LDAP servers are configured, user information has to be
|
||||
* provided via other methods (CSV file, manually, etc.). Return
|
||||
* an empty array so existing user info is not lost. Otherwise,
|
||||
* calls parent class method to get user info.
|
||||
*
|
||||
* @param string $username username
|
||||
* @return mixed array with no magic quotes or false on error
|
||||
*/
|
||||
function get_userinfo($username) {
|
||||
if (empty($this->config->host_url)) {
|
||||
return array();
|
||||
}
|
||||
return parent::get_userinfo($username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Syncronizes users from LDAP server to moodle user table.
|
||||
*
|
||||
* If no LDAP servers are configured, simply return. Otherwise,
|
||||
* call parent class method to do the work.
|
||||
*
|
||||
* @param bool $do_updates will do pull in data updates from LDAP if relevant
|
||||
* @return nothing
|
||||
*/
|
||||
function sync_users($do_updates=true) {
|
||||
if (empty($this->config->host_url)) {
|
||||
error_log('[AUTH CAS] '.get_string('noldapserver', 'auth_cas'));
|
||||
return;
|
||||
}
|
||||
parent::sync_users($do_updates);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,4 +61,5 @@ $string['auth_cas_text'] = 'Secure connection';
|
||||
$string['auth_cas_use_cas'] = 'Use CAS';
|
||||
$string['auth_cas_version'] = 'Version of CAS';
|
||||
$string['CASform'] = 'Authentication choice';
|
||||
$string['noldapserver'] = 'No LDAP server configured for CAS! Syncing disabled.';
|
||||
$string['pluginname'] = 'CAS server (SSO)';
|
||||
|
||||
@@ -24,8 +24,23 @@
|
||||
*/
|
||||
|
||||
$string['auth_emaildescription'] = 'Email confirmation is the default authentication method. When the user signs up, choosing their own new username and password, a confirmation email is sent to the user\'s email address. This email contains a secure link to a page where the user can confirm their account. Future logins just check the username and password against the stored values in the Moodle database.';
|
||||
$string['auth_emailchangecancel'] = 'Cancel email change';
|
||||
$string['auth_emailchangepending'] = 'Change pending. Open the link sent to you at {$a->preference_newemail}.';
|
||||
$string['auth_emailnoemail'] = 'Tried to send you an email but failed!';
|
||||
$string['auth_emailnoinsert'] = 'Could not add your record to the database!';
|
||||
$string['auth_emailnowexists'] = 'The email address you tried to assign to your profile has been assigned to someone else since your original request. Your request for change of email address is hereby cancelled, but you may try again with a different address.';
|
||||
$string['auth_emailrecaptcha'] = 'Adds a visual/audio confirmation form element to the signup page for email self-registering users. This protects your site against spammers and contributes to a worthwhile cause. See http://www.google.com/recaptcha/learnmore for more details. <br /><em>PHP cURL extension is required.</em>';
|
||||
$string['auth_emailrecaptcha_key'] = 'Enable reCAPTCHA element';
|
||||
$string['auth_emailsettings'] = 'Settings';
|
||||
$string['auth_emailupdate'] = 'Email address update';
|
||||
$string['auth_emailupdatemessage'] = 'Dear {$a->fullname},
|
||||
|
||||
You have requested a change of your email address for your user account at {$a->site}. Please open the following URL in your browser in order to confirm this change.
|
||||
|
||||
{$a->url}';
|
||||
$string['auth_emailupdatesuccess'] = 'Email address of user <em>{$a->fullname}</em> was successfully updated to <em>{$a->email}</em>.';
|
||||
$string['auth_emailupdatetitle'] = 'Confirmation of email update at {$a->site}';
|
||||
$string['auth_changingemailaddress'] = 'You have requested a change of email address, from {$a->oldemail} to {$a->newemail}. For security reasons, we are sending you an email message at the new address to confirm that it belongs to you. Your email address will be updated as soon as you open the URL sent to you in that message.';
|
||||
$string['auth_invalidnewemailkey'] = 'Error: if you are trying to confirm a change of email address, you may have made a mistake in copying the URL we sent you by email. Please copy the address and try again.';
|
||||
$string['auth_outofnewemailupdateattempts'] = 'You have run out of allowed attempts to update your email address. Your update request has been cancelled.';
|
||||
$string['pluginname'] = 'Email-based self-registration';
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
LDAP-module README
|
||||
|
||||
Please read comments from lib.php
|
||||
Please read comments from auth.php in this directory.
|
||||
|
||||
+12
-11
@@ -502,7 +502,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
events_trigger('user_created', $user);
|
||||
|
||||
if (! send_confirmation_email($user)) {
|
||||
print_error('noemail', 'auth_ldap');
|
||||
print_error('auth_emailnoemail', 'auth_email');
|
||||
}
|
||||
|
||||
if ($notify) {
|
||||
@@ -579,16 +579,17 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
$sr = ldap_read($ldapconnection, $user_dn, '(objectClass=*)', $search_attribs);
|
||||
if ($sr) {
|
||||
$info = ldap_get_entries_moodle($ldapconnection, $sr);
|
||||
$info = array_change_key_case($info, CASE_LOWER);
|
||||
if (!empty ($info) and !empty($info[0][$this->config->expireattr][0])) {
|
||||
$expiretime = $this->ldap_expirationtime2unix($info[0][$this->config->expireattr][0], $ldapconnection, $user_dn);
|
||||
if ($expiretime != 0) {
|
||||
$now = time();
|
||||
if ($expiretime > $now) {
|
||||
$result = ceil(($expiretime - $now) / DAYSECS);
|
||||
}
|
||||
else {
|
||||
$result = floor(($expiretime - $now) / DAYSECS);
|
||||
if (!empty ($info)) {
|
||||
$info = array_change_key_case($info[0], CASE_LOWER);
|
||||
if (!empty($info[$this->config->expireattr][0])) {
|
||||
$expiretime = $this->ldap_expirationtime2unix($info[$this->config->expireattr][0], $ldapconnection, $user_dn);
|
||||
if ($expiretime != 0) {
|
||||
$now = time();
|
||||
if ($expiretime > $now) {
|
||||
$result = ceil(($expiretime - $now) / DAYSECS);
|
||||
} else {
|
||||
$result = floor(($expiretime - $now) / DAYSECS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,7 +114,6 @@ $string['morethanoneuser'] = 'Strange! More than one user record found in ldap.
|
||||
$string['needbcmath'] = 'You need the BCMath extension to use grace logins with Active Directory';
|
||||
$string['needmbstring'] = 'You need the mbstring extension to change passwords in Active Directory';
|
||||
$string['nodnforusername'] = 'Error in user_update_password(). No DN for: {$a->username}';
|
||||
$string['noemail'] = 'Tried to send you an email but failed!';
|
||||
$string['notcalledfromserver'] = 'Should not be called from the web server!';
|
||||
$string['noupdatestobedone'] = "No updates to be done\n";
|
||||
$string['nouserentriestoremove'] = "No user entries to be removed\n";
|
||||
|
||||
@@ -45,8 +45,5 @@ function xmldb_auth_manual_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2011022700, 'auth', 'manual');
|
||||
}
|
||||
|
||||
// Moodle v2.1.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-2
@@ -276,6 +276,7 @@ class auth_plugin_mnet extends auth_plugin_base {
|
||||
*/
|
||||
$remoteuser->mnethostid = $remotehost->id;
|
||||
$remoteuser->firstaccess = time(); // First time user in this server, grab it here
|
||||
$remoteuser->confirmed = 1;
|
||||
|
||||
$remoteuser->id = $DB->insert_record('user', $remoteuser);
|
||||
$firsttime = true;
|
||||
@@ -889,8 +890,6 @@ class auth_plugin_mnet extends auth_plugin_base {
|
||||
global $CFG, $DB;
|
||||
$remoteclient = get_mnet_remote_client();
|
||||
|
||||
$CFG->usesid = true;
|
||||
|
||||
// We don't want to output anything to the client machine
|
||||
$start = ob_start();
|
||||
|
||||
|
||||
@@ -43,8 +43,5 @@ function xmldb_auth_mnet_upgrade($oldversion) {
|
||||
upgrade_plugin_savepoint(true, 2010071300, 'auth', 'mnet');
|
||||
}
|
||||
|
||||
// Moodle v2.1.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -193,18 +193,13 @@ class auth_plugin_shibboleth extends auth_plugin_base {
|
||||
*
|
||||
*/
|
||||
function logoutpage_hook() {
|
||||
global $redirect;
|
||||
global $SESSION, $redirect;
|
||||
|
||||
// Only do this if logout handler is defined
|
||||
if (
|
||||
isset($this->config->logout_handler)
|
||||
&& !empty($this->config->logout_handler)
|
||||
){
|
||||
// Only do this if logout handler is defined, and if the user is actually logged in via Shibboleth
|
||||
$logouthandlervalid = isset($this->config->logout_handler) && !empty($this->config->logout_handler);
|
||||
if ( isset($SESSION->shibboleth_session_id) && $logouthandlervalid) {
|
||||
// Check if there is an alternative logout return url defined
|
||||
if (
|
||||
isset($this->config->logout_return_url)
|
||||
&& !empty($this->config->logout_return_url)
|
||||
){
|
||||
if (isset($this->config->logout_return_url) && !empty($this->config->logout_return_url)) {
|
||||
// Set temp_redirect to alternative return url
|
||||
$temp_redirect = $this->config->logout_return_url;
|
||||
} else {
|
||||
|
||||
@@ -54,7 +54,6 @@ abstract class backup implements checksumable {
|
||||
const MODE_HUB = 30;
|
||||
const MODE_SAMESITE = 40;
|
||||
const MODE_AUTOMATED = 50;
|
||||
const MODE_CONVERTED = 60;
|
||||
|
||||
// Target (new/existing/current/adding/deleting)
|
||||
const TARGET_CURRENT_DELETING = 0;
|
||||
@@ -108,8 +107,8 @@ abstract class backup implements checksumable {
|
||||
const OPERATION_RESTORE ='restore';// We are performing one restore
|
||||
|
||||
// Version (to keep CFG->backup_version (and release) updated automatically)
|
||||
const VERSION = 2011063000;
|
||||
const RELEASE = '2.1';
|
||||
const VERSION = 2010111800;
|
||||
const RELEASE = '2.0';
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -118,6 +117,6 @@ abstract class backup implements checksumable {
|
||||
abstract class backup_exception extends moodle_exception {
|
||||
|
||||
public function __construct($errorcode, $a=NULL, $debuginfo=null) {
|
||||
parent::__construct($errorcode, 'error', '', $a, $debuginfo);
|
||||
parent::__construct($errorcode, 'error', '', $a, null, $debuginfo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,3 +92,5 @@ define('MOODLE_QUIZ_MULTIPLE_RESPONSE', 'multichoice');
|
||||
define('MOODLE_QUIZ_MACHT', 'match');
|
||||
define('MOODLE_QUIZ_ESSAY', 'essay');
|
||||
define('MOODLE_QUIZ_SHORTANSWER', 'shortanswer');
|
||||
|
||||
?>
|
||||
|
||||
@@ -339,7 +339,7 @@ class backup_controller extends backup implements loggable {
|
||||
|
||||
protected function apply_defaults() {
|
||||
$this->log('applying plan defaults', backup::LOG_DEBUG);
|
||||
backup_controller_dbops::apply_general_config_defaults($this);
|
||||
backup_controller_dbops::apply_config_defaults($this);
|
||||
$this->set_status(backup::STATUS_CONFIGURED);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -380,44 +380,38 @@ class restore_controller extends backup implements loggable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts from current format to backup::MOODLE format
|
||||
* convert from current format to backup::MOODLE format
|
||||
*/
|
||||
public function convert() {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');
|
||||
|
||||
// Basic/initial prevention against time/memory limits
|
||||
set_time_limit(1 * 60 * 60); // 1 hour for 1 course initially granted
|
||||
raise_memory_limit(MEMORY_EXTRA);
|
||||
|
||||
if ($this->status != backup::STATUS_REQUIRE_CONV) {
|
||||
throw new restore_controller_exception('cannot_convert_not_required_status');
|
||||
}
|
||||
|
||||
$this->log('backup format conversion required', backup::LOG_INFO);
|
||||
|
||||
// Run conversion to the proper format
|
||||
if (!convert_helper::to_moodle2_format($this->get_tempdir(), $this->format, $this->get_logger())) {
|
||||
// todo - unable to find the conversion path, what to do now?
|
||||
// throwing the exception as a temporary solution
|
||||
throw new restore_controller_exception('unable_to_find_conversion_path');
|
||||
if ($this->format == backup::FORMAT_UNKNOWN) {
|
||||
throw new restore_controller_exception('cannot_convert_from_unknown_format');
|
||||
}
|
||||
if ($this->format == backup::FORMAT_MOODLE1) {
|
||||
// TODO: Implement moodle1 => moodle2 conversion
|
||||
throw new restore_controller_exception('cannot_convert_yet_from_moodle1_format');
|
||||
}
|
||||
|
||||
$this->log('backup format conversion successful', backup::LOG_INFO);
|
||||
// Once conversions have finished, we check again the format
|
||||
$newformat = backup_general_helper::detect_backup_format($tempdir);
|
||||
|
||||
// If no exceptions were thrown, then we are in the proper format
|
||||
$this->format = backup::FORMAT_MOODLE;
|
||||
// If format is moodle2, load plan, apply security and set status based on interactivity
|
||||
if ($newformat === backup::FORMAT_MOODLE) {
|
||||
// Load plan
|
||||
$this->load_plan();
|
||||
|
||||
// Load plan, apply security and set status based on interactivity
|
||||
$this->load_plan();
|
||||
// Perform all initial security checks and apply (2nd param) them to settings automatically
|
||||
restore_check::check_security($this, true);
|
||||
|
||||
// Perform all initial security checks and apply (2nd param) them to settings automatically
|
||||
restore_check::check_security($this, true);
|
||||
|
||||
if ($this->interactive == backup::INTERACTIVE_YES) {
|
||||
$this->set_status(backup::STATUS_SETTING_UI);
|
||||
if ($this->interactive == backup::INTERACTIVE_YES) {
|
||||
$this->set_status(backup::STATUS_SETTING_UI);
|
||||
} else {
|
||||
$this->set_status(backup::STATUS_NEED_PRECHECK);
|
||||
}
|
||||
} else {
|
||||
$this->set_status(backup::STATUS_NEED_PRECHECK);
|
||||
throw new restore_controller_exception('conversion_ended_with_wrong_format', $newformat);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,286 +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/>.
|
||||
|
||||
/**
|
||||
* Provides base converter classes
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup-convert
|
||||
* @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/backup/util/includes/convert_includes.php');
|
||||
|
||||
/**
|
||||
* Base converter class
|
||||
*
|
||||
* All Moodle backup converters are supposed to extend this base class.
|
||||
*
|
||||
* @throws convert_exception
|
||||
*/
|
||||
abstract class base_converter implements loggable {
|
||||
|
||||
/** @var string unique identifier of this converter instance */
|
||||
protected $id;
|
||||
|
||||
/** @var string the name of the directory containing the unpacked backup being converted */
|
||||
protected $tempdir;
|
||||
|
||||
/** @var string the name of the directory where the backup is converted to */
|
||||
protected $workdir;
|
||||
|
||||
/** @var null|base_logger logger to use during the conversion */
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $tempdir the relative path to the directory containing the unpacked backup to convert
|
||||
* @param null|base_logger logger to use during the conversion
|
||||
*/
|
||||
public function __construct($tempdir, $logger = null) {
|
||||
|
||||
$this->tempdir = $tempdir;
|
||||
$this->id = convert_helper::generate_id($tempdir);
|
||||
$this->workdir = $tempdir . '_' . $this->get_name() . '_' . $this->id;
|
||||
$this->set_logger($logger);
|
||||
$this->log('instantiating '.$this->get_name().' converter '.$this->get_id(), backup::LOG_DEBUG);
|
||||
$this->log('conversion source directory', backup::LOG_DEBUG, $this->tempdir);
|
||||
$this->log('conversion target directory', backup::LOG_DEBUG, $this->workdir);
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the logger to use during the conversion
|
||||
*
|
||||
* @param null|base_logger $logger
|
||||
*/
|
||||
public function set_logger($logger) {
|
||||
if (is_null($logger) or ($logger instanceof base_logger)) {
|
||||
$this->logger = $logger;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the logger was set for the converter, log the message
|
||||
*
|
||||
* If the $display is enabled, the spaces in the $message text are removed
|
||||
* and the text is used as a string identifier in the core_backup language file.
|
||||
*
|
||||
* @see backup_helper::log()
|
||||
* @param string $message message text
|
||||
* @param int $level message level {@example backup::LOG_WARNING}
|
||||
* @param null|mixed $a additional information
|
||||
* @param null|int $depth the message depth
|
||||
* @param bool $display whether the message should be sent to the output, too
|
||||
*/
|
||||
public function log($message, $level, $a = null, $depth = null, $display = false) {
|
||||
if ($this->logger instanceof base_logger) {
|
||||
backup_helper::log($message, $level, $a, $depth, $display, $this->logger);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get instance identifier
|
||||
*
|
||||
* @return string the unique identifier of this converter instance
|
||||
*/
|
||||
public function get_id() {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get converter name
|
||||
*
|
||||
* @return string the system name of the converter
|
||||
*/
|
||||
public function get_name() {
|
||||
return array_shift(explode('_', get_class($this)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the backup directory
|
||||
*/
|
||||
public function convert() {
|
||||
|
||||
try {
|
||||
$this->log('creating the target directory', backup::LOG_DEBUG);
|
||||
$this->create_workdir();
|
||||
|
||||
$this->log('executing the conversion', backup::LOG_DEBUG);
|
||||
$this->execute();
|
||||
|
||||
$this->log('replacing the source directory with the converted version', backup::LOG_DEBUG);
|
||||
$this->replace_tempdir();
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
|
||||
// clean-up stuff if needed
|
||||
$this->destroy();
|
||||
|
||||
// eventually re-throw the execution exception
|
||||
if (isset($e) and ($e instanceof Exception)) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the full path to the working directory
|
||||
*/
|
||||
public function get_workdir_path() {
|
||||
global $CFG;
|
||||
|
||||
return "$CFG->dataroot/temp/backup/$this->workdir";
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the full path to the directory with the source backup
|
||||
*/
|
||||
public function get_tempdir_path() {
|
||||
global $CFG;
|
||||
|
||||
return "$CFG->dataroot/temp/backup/$this->tempdir";
|
||||
}
|
||||
|
||||
/// public static methods //////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Makes sure that this converter is available at this site
|
||||
*
|
||||
* This is intended for eventual PHP extensions check, environment check etc.
|
||||
* All checks that do not depend on actual backup data should be done here.
|
||||
*
|
||||
* @return boolean true if this converter should be considered as available
|
||||
*/
|
||||
public static function is_available() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the format of the backup directory
|
||||
*
|
||||
* Moodle 2.x format is being detected by the core itself. The converters are
|
||||
* therefore supposed to detect the source format. Eventually, if the target
|
||||
* format os not {@link backup::FORMAT_MOODLE} then they should be able to
|
||||
* detect both source and target formats.
|
||||
*
|
||||
* @param string $tempdir the name of the backup directory
|
||||
* @return null|string null if not recognized, backup::FORMAT_xxx otherwise
|
||||
*/
|
||||
public static function detect_format($tempdir) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the basic information about the converter
|
||||
*
|
||||
* The returned array must contain the following keys:
|
||||
* 'from' - the supported source format, eg. backup::FORMAT_MOODLE1
|
||||
* 'to' - the supported target format, eg. backup::FORMAT_MOODLE
|
||||
* 'cost' - the cost of the conversion, non-negative non-zero integer
|
||||
*/
|
||||
public static function description() {
|
||||
|
||||
return array(
|
||||
'from' => null,
|
||||
'to' => null,
|
||||
'cost' => null,
|
||||
);
|
||||
}
|
||||
|
||||
/// end of public API //////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Initialize the instance if needed, called by the constructor
|
||||
*/
|
||||
protected function init() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the contents of the tempdir into the target format in the workdir
|
||||
*/
|
||||
protected abstract function execute();
|
||||
|
||||
/**
|
||||
* Prepares a new empty working directory
|
||||
*/
|
||||
protected function create_workdir() {
|
||||
|
||||
fulldelete($this->get_workdir_path());
|
||||
if (!check_dir_exists($this->get_workdir_path())) {
|
||||
throw new convert_exception('failed_create_workdir');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the source backup directory with the converted version
|
||||
*
|
||||
* If $CFG->keeptempdirectoriesonbackup is defined, the original source
|
||||
* source backup directory is kept for debugging purposes.
|
||||
*/
|
||||
protected function replace_tempdir() {
|
||||
global $CFG;
|
||||
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||||
fulldelete($this->get_tempdir_path());
|
||||
} else {
|
||||
if (!rename($this->get_tempdir_path(), $this->get_tempdir_path() . '_' . $this->get_name() . '_' . $this->id . '_source')) {
|
||||
throw new convert_exception('failed_rename_source_tempdir');
|
||||
}
|
||||
}
|
||||
|
||||
if (!rename($this->get_workdir_path(), $this->get_tempdir_path())) {
|
||||
throw new convert_exception('failed_move_converted_into_place');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up stuff after the execution
|
||||
*
|
||||
* Note that we do not know if the execution was successful or not.
|
||||
* An exception might have been thrown.
|
||||
*/
|
||||
protected function destroy() {
|
||||
global $CFG;
|
||||
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||||
fulldelete($this->get_workdir_path());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General convert-related exception
|
||||
*
|
||||
* @author David Mudrak <david@moodle.com>
|
||||
*/
|
||||
class convert_exception extends moodle_exception {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $errorcode key for the corresponding error string
|
||||
* @param object $a extra words and phrases that might be required in the error string
|
||||
* @param string $debuginfo optional debugging information
|
||||
*/
|
||||
public function __construct($errorcode, $a = null, $debuginfo = null) {
|
||||
parent::__construct($errorcode, '', '', $a, $debuginfo);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 127 B |
@@ -1,602 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<MOODLE_BACKUP>
|
||||
<INFO>
|
||||
<NAME>restore.zip</NAME>
|
||||
<MOODLE_VERSION>2007101520</MOODLE_VERSION>
|
||||
<MOODLE_RELEASE>1.9.2 (Build: 20080711)</MOODLE_RELEASE>
|
||||
<BACKUP_VERSION>2008030300</BACKUP_VERSION>
|
||||
<BACKUP_RELEASE>1.9</BACKUP_RELEASE>
|
||||
<DATE>1299774017</DATE>
|
||||
<ORIGINAL_WWWROOT>http://elearning-testadam.uss.lsu.edu/moodle</ORIGINAL_WWWROOT>
|
||||
<ZIP_METHOD>internal</ZIP_METHOD>
|
||||
<DETAILS>
|
||||
<MOD>
|
||||
<NAME>forum</NAME>
|
||||
<INCLUDED>true</INCLUDED>
|
||||
<USERINFO>false</USERINFO>
|
||||
<INSTANCES>
|
||||
<INSTANCE>
|
||||
<ID>57</ID>
|
||||
<NAME>News forum</NAME>
|
||||
<INCLUDED>true</INCLUDED>
|
||||
<USERINFO>false</USERINFO>
|
||||
</INSTANCE>
|
||||
</INSTANCES>
|
||||
</MOD>
|
||||
<METACOURSE>false</METACOURSE>
|
||||
<USERS>course</USERS>
|
||||
<LOGS>false</LOGS>
|
||||
<USERFILES>true</USERFILES>
|
||||
<COURSEFILES>true</COURSEFILES>
|
||||
<SITEFILES>true</SITEFILES>
|
||||
<GRADEBOOKHISTORIES>false</GRADEBOOKHISTORIES>
|
||||
<MESSAGES>false</MESSAGES>
|
||||
<BLOGS>false</BLOGS>
|
||||
<BLOCKFORMAT>instances</BLOCKFORMAT>
|
||||
</DETAILS>
|
||||
</INFO>
|
||||
<ROLES>
|
||||
</ROLES>
|
||||
<COURSE>
|
||||
<HEADER>
|
||||
<ID>33</ID>
|
||||
<CATEGORY>
|
||||
<ID>1</ID>
|
||||
<NAME>Miscellaneous</NAME>
|
||||
</CATEGORY>
|
||||
<PASSWORD></PASSWORD>
|
||||
<FULLNAME>Moodle 2.0 Test Restore</FULLNAME>
|
||||
<SHORTNAME>M2TR</SHORTNAME>
|
||||
<IDNUMBER></IDNUMBER>
|
||||
<SUMMARY>Cazzin'</SUMMARY>
|
||||
<FORMAT>weeks</FORMAT>
|
||||
<SHOWGRADES>1</SHOWGRADES>
|
||||
<NEWSITEMS>5</NEWSITEMS>
|
||||
<TEACHER>Teacher</TEACHER>
|
||||
<TEACHERS>Teachers</TEACHERS>
|
||||
<STUDENT>Student</STUDENT>
|
||||
<STUDENTS>Students</STUDENTS>
|
||||
<GUEST>0</GUEST>
|
||||
<STARTDATE>1299823200</STARTDATE>
|
||||
<NUMSECTIONS>10</NUMSECTIONS>
|
||||
<MAXBYTES>52428800</MAXBYTES>
|
||||
<SHOWREPORTS>0</SHOWREPORTS>
|
||||
<GROUPMODE>0</GROUPMODE>
|
||||
<GROUPMODEFORCE>0</GROUPMODEFORCE>
|
||||
<DEFAULTGROUPINGID>0</DEFAULTGROUPINGID>
|
||||
<LANG></LANG>
|
||||
<THEME></THEME>
|
||||
<COST></COST>
|
||||
<CURRENCY>USD</CURRENCY>
|
||||
<MARKER>0</MARKER>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<HIDDENSECTIONS>0</HIDDENSECTIONS>
|
||||
<TIMECREATED>1299773769</TIMECREATED>
|
||||
<TIMEMODIFIED>1299773769</TIMEMODIFIED>
|
||||
<METACOURSE>0</METACOURSE>
|
||||
<EXPIRENOTIFY>0</EXPIRENOTIFY>
|
||||
<NOTIFYSTUDENTS>0</NOTIFYSTUDENTS>
|
||||
<EXPIRYTHRESHOLD>864000</EXPIRYTHRESHOLD>
|
||||
<ENROLLABLE>1</ENROLLABLE>
|
||||
<ENROLSTARTDATE>0</ENROLSTARTDATE>
|
||||
<ENROLENDDATE>0</ENROLENDDATE>
|
||||
<ENROLPERIOD>0</ENROLPERIOD>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</HEADER>
|
||||
<BLOCKS>
|
||||
<BLOCK>
|
||||
<ID>314</ID>
|
||||
<NAME>participants</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>l</POSITION>
|
||||
<WEIGHT>0</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>315</ID>
|
||||
<NAME>activity_modules</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>l</POSITION>
|
||||
<WEIGHT>1</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>316</ID>
|
||||
<NAME>search_forums</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>l</POSITION>
|
||||
<WEIGHT>2</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>317</ID>
|
||||
<NAME>admin</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>l</POSITION>
|
||||
<WEIGHT>3</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>318</ID>
|
||||
<NAME>course_list</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>l</POSITION>
|
||||
<WEIGHT>4</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>319</ID>
|
||||
<NAME>news_items</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>r</POSITION>
|
||||
<WEIGHT>0</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>320</ID>
|
||||
<NAME>calendar_upcoming</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>r</POSITION>
|
||||
<WEIGHT>1</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
<BLOCK>
|
||||
<ID>321</ID>
|
||||
<NAME>recent_activity</NAME>
|
||||
<PAGEID>33</PAGEID>
|
||||
<PAGETYPE>course-view</PAGETYPE>
|
||||
<POSITION>r</POSITION>
|
||||
<WEIGHT>2</WEIGHT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<CONFIGDATA>Tjs=</CONFIGDATA>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</BLOCK>
|
||||
</BLOCKS>
|
||||
<SECTIONS>
|
||||
<SECTION>
|
||||
<ID>436</ID>
|
||||
<NUMBER>0</NUMBER>
|
||||
<SUMMARY>$@NULL@$</SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<MODS>
|
||||
<MOD>
|
||||
<ID>250</ID>
|
||||
<TYPE>forum</TYPE>
|
||||
<INSTANCE>57</INSTANCE>
|
||||
<ADDED>1299773780</ADDED>
|
||||
<SCORE>0</SCORE>
|
||||
<INDENT>0</INDENT>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
<GROUPMODE>0</GROUPMODE>
|
||||
<GROUPINGID>0</GROUPINGID>
|
||||
<GROUPMEMBERSONLY>0</GROUPMEMBERSONLY>
|
||||
<IDNUMBER>$@NULL@$</IDNUMBER>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</MOD>
|
||||
</MODS>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>437</ID>
|
||||
<NUMBER>1</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>438</ID>
|
||||
<NUMBER>2</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>439</ID>
|
||||
<NUMBER>3</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>440</ID>
|
||||
<NUMBER>4</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>441</ID>
|
||||
<NUMBER>5</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>442</ID>
|
||||
<NUMBER>6</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>443</ID>
|
||||
<NUMBER>7</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>444</ID>
|
||||
<NUMBER>8</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>445</ID>
|
||||
<NUMBER>9</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
<SECTION>
|
||||
<ID>446</ID>
|
||||
<NUMBER>10</NUMBER>
|
||||
<SUMMARY></SUMMARY>
|
||||
<VISIBLE>1</VISIBLE>
|
||||
</SECTION>
|
||||
</SECTIONS>
|
||||
<USERS>
|
||||
<USER>
|
||||
<ID>2</ID>
|
||||
<AUTH>manual</AUTH>
|
||||
<CONFIRMED>1</CONFIRMED>
|
||||
<POLICYAGREED>0</POLICYAGREED>
|
||||
<DELETED>0</DELETED>
|
||||
<USERNAME>admin</USERNAME>
|
||||
<PASSWORD>ea557cf33bda866d97b07465f1ea3867</PASSWORD>
|
||||
<IDNUMBER>891220979</IDNUMBER>
|
||||
<FIRSTNAME>Admin</FIRSTNAME>
|
||||
<LASTNAME>User</LASTNAME>
|
||||
<EMAIL>adamzap@gmail.com</EMAIL>
|
||||
<EMAILSTOP>0</EMAILSTOP>
|
||||
<ICQ></ICQ>
|
||||
<SKYPE></SKYPE>
|
||||
<YAHOO></YAHOO>
|
||||
<AIM></AIM>
|
||||
<MSN></MSN>
|
||||
<PHONE1></PHONE1>
|
||||
<PHONE2></PHONE2>
|
||||
<INSTITUTION></INSTITUTION>
|
||||
<DEPARTMENT></DEPARTMENT>
|
||||
<ADDRESS></ADDRESS>
|
||||
<CITY>br</CITY>
|
||||
<COUNTRY>US</COUNTRY>
|
||||
<LANG>en_utf8</LANG>
|
||||
<THEME></THEME>
|
||||
<TIMEZONE>99</TIMEZONE>
|
||||
<FIRSTACCESS>0</FIRSTACCESS>
|
||||
<LASTACCESS>1265755409</LASTACCESS>
|
||||
<LASTLOGIN>1265658108</LASTLOGIN>
|
||||
<CURRENTLOGIN>1265741271</CURRENTLOGIN>
|
||||
<LASTIP>130.39.194.172</LASTIP>
|
||||
<SECRET>lknsJoSw0S6myJA</SECRET>
|
||||
<PICTURE>1</PICTURE>
|
||||
<URL></URL>
|
||||
<DESCRIPTION></DESCRIPTION>
|
||||
<MAILFORMAT>1</MAILFORMAT>
|
||||
<MAILDIGEST>0</MAILDIGEST>
|
||||
<MAILDISPLAY>1</MAILDISPLAY>
|
||||
<HTMLEDITOR>1</HTMLEDITOR>
|
||||
<AJAX>1</AJAX>
|
||||
<AUTOSUBSCRIBE>1</AUTOSUBSCRIBE>
|
||||
<TRACKFORUMS>0</TRACKFORUMS>
|
||||
<TIMEMODIFIED>1265216036</TIMEMODIFIED>
|
||||
<ROLES>
|
||||
<ROLE>
|
||||
<TYPE>needed</TYPE>
|
||||
</ROLE>
|
||||
</ROLES>
|
||||
<USER_PREFERENCES>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>email_bounce_count</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>email_send_count</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>user_editadvanced_form_showadvanced</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
</USER_PREFERENCES>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</USER>
|
||||
<USER>
|
||||
<ID>3</ID>
|
||||
<AUTH>cas</AUTH>
|
||||
<CONFIRMED>1</CONFIRMED>
|
||||
<POLICYAGREED>0</POLICYAGREED>
|
||||
<DELETED>0</DELETED>
|
||||
<USERNAME>azaple1</USERNAME>
|
||||
<PASSWORD>fb005bdc5fb1b23ea95d238fb5ecb9e2</PASSWORD>
|
||||
<IDNUMBER>891111111</IDNUMBER>
|
||||
<FIRSTNAME>Adam</FIRSTNAME>
|
||||
<LASTNAME>Zapletal</LASTNAME>
|
||||
<EMAIL>azaple1@lsu.edu</EMAIL>
|
||||
<EMAILSTOP>0</EMAILSTOP>
|
||||
<ICQ></ICQ>
|
||||
<SKYPE></SKYPE>
|
||||
<YAHOO></YAHOO>
|
||||
<AIM></AIM>
|
||||
<MSN></MSN>
|
||||
<PHONE1></PHONE1>
|
||||
<PHONE2></PHONE2>
|
||||
<INSTITUTION></INSTITUTION>
|
||||
<DEPARTMENT></DEPARTMENT>
|
||||
<ADDRESS></ADDRESS>
|
||||
<CITY>asdf</CITY>
|
||||
<COUNTRY>AL</COUNTRY>
|
||||
<LANG>en_utf8</LANG>
|
||||
<THEME></THEME>
|
||||
<TIMEZONE>99</TIMEZONE>
|
||||
<FIRSTACCESS>0</FIRSTACCESS>
|
||||
<LASTACCESS>1299774054</LASTACCESS>
|
||||
<LASTLOGIN>1297979000</LASTLOGIN>
|
||||
<CURRENTLOGIN>1299773727</CURRENTLOGIN>
|
||||
<LASTIP>173.253.129.223</LASTIP>
|
||||
<SECRET></SECRET>
|
||||
<PICTURE>1</PICTURE>
|
||||
<URL></URL>
|
||||
<DESCRIPTION></DESCRIPTION>
|
||||
<MAILFORMAT>1</MAILFORMAT>
|
||||
<MAILDIGEST>0</MAILDIGEST>
|
||||
<MAILDISPLAY>2</MAILDISPLAY>
|
||||
<HTMLEDITOR>1</HTMLEDITOR>
|
||||
<AJAX>1</AJAX>
|
||||
<AUTOSUBSCRIBE>1</AUTOSUBSCRIBE>
|
||||
<TRACKFORUMS>0</TRACKFORUMS>
|
||||
<TIMEMODIFIED>1288033285</TIMEMODIFIED>
|
||||
<ROLES>
|
||||
<ROLE>
|
||||
<TYPE>needed</TYPE>
|
||||
</ROLE>
|
||||
</ROLES>
|
||||
<USER_PREFERENCES>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>assignment_mailinfo</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>assignment_perpage</NAME>
|
||||
<VALUE>10</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>assignment_quickgrade</NAME>
|
||||
<VALUE>0</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>auth_forcepasswordchange</NAME>
|
||||
<VALUE>0</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>forum_displaymode</NAME>
|
||||
<VALUE>3</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>grader_report_preferences_form_showadvanced</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>grade_report_simple_aggregationview51</NAME>
|
||||
<VALUE>0</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>grade_report_simple_grader_collapsed_categories</NAME>
|
||||
<VALUE>a:2:{s:14:"aggregatesonly";a:4:{i:0;s:2:"70";i:1;s:2:"71";i:2;s:2:"72";i:3;s:2:"73";}s:10:"gradesonly";a:0:{}}</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>grade_report_simple_meanselection</NAME>
|
||||
<VALUE>2</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>grade_report_simple_showranges</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>grade_report_simple_showstickytab</NAME>
|
||||
<VALUE>0</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>lesson_view</NAME>
|
||||
<VALUE>collapsed</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>mod_resource_mod_form_showadvanced</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
<USER_PREFERENCE>
|
||||
<NAME>user_editadvanced_form_showadvanced</NAME>
|
||||
<VALUE>1</VALUE>
|
||||
</USER_PREFERENCE>
|
||||
</USER_PREFERENCES>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</USER>
|
||||
<USER>
|
||||
<ID>6</ID>
|
||||
<AUTH>cas</AUTH>
|
||||
<CONFIRMED>1</CONFIRMED>
|
||||
<POLICYAGREED>0</POLICYAGREED>
|
||||
<DELETED>0</DELETED>
|
||||
<USERNAME>pcali1</USERNAME>
|
||||
<PASSWORD>fb005bdc5fb1b23ea95d238fb5ecb9e2</PASSWORD>
|
||||
<IDNUMBER></IDNUMBER>
|
||||
<FIRSTNAME>Philip</FIRSTNAME>
|
||||
<LASTNAME>Cali</LASTNAME>
|
||||
<EMAIL>pcali1@lsu.edu</EMAIL>
|
||||
<EMAILSTOP>0</EMAILSTOP>
|
||||
<ICQ></ICQ>
|
||||
<SKYPE></SKYPE>
|
||||
<YAHOO></YAHOO>
|
||||
<AIM></AIM>
|
||||
<MSN></MSN>
|
||||
<PHONE1></PHONE1>
|
||||
<PHONE2></PHONE2>
|
||||
<INSTITUTION></INSTITUTION>
|
||||
<DEPARTMENT></DEPARTMENT>
|
||||
<ADDRESS></ADDRESS>
|
||||
<CITY></CITY>
|
||||
<COUNTRY></COUNTRY>
|
||||
<LANG>en_utf8</LANG>
|
||||
<THEME></THEME>
|
||||
<TIMEZONE>99</TIMEZONE>
|
||||
<FIRSTACCESS>0</FIRSTACCESS>
|
||||
<LASTACCESS>1268662392</LASTACCESS>
|
||||
<LASTLOGIN>0</LASTLOGIN>
|
||||
<CURRENTLOGIN>1268662284</CURRENTLOGIN>
|
||||
<LASTIP>68.105.37.237</LASTIP>
|
||||
<SECRET></SECRET>
|
||||
<PICTURE>1</PICTURE>
|
||||
<URL></URL>
|
||||
<DESCRIPTION>$@NULL@$</DESCRIPTION>
|
||||
<MAILFORMAT>1</MAILFORMAT>
|
||||
<MAILDIGEST>0</MAILDIGEST>
|
||||
<MAILDISPLAY>2</MAILDISPLAY>
|
||||
<HTMLEDITOR>1</HTMLEDITOR>
|
||||
<AJAX>1</AJAX>
|
||||
<AUTOSUBSCRIBE>1</AUTOSUBSCRIBE>
|
||||
<TRACKFORUMS>0</TRACKFORUMS>
|
||||
<TIMEMODIFIED>1268662284</TIMEMODIFIED>
|
||||
<ROLES>
|
||||
<ROLE>
|
||||
<TYPE>needed</TYPE>
|
||||
</ROLE>
|
||||
</ROLES>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
<ROLES_ASSIGNMENTS>
|
||||
</ROLES_ASSIGNMENTS>
|
||||
</USER>
|
||||
</USERS>
|
||||
<GRADEBOOK>
|
||||
<GRADE_CATEGORIES>
|
||||
<GRADE_CATEGORY>
|
||||
<ID>90</ID>
|
||||
<PARENT>$@NULL@$</PARENT>
|
||||
<FULLNAME>?</FULLNAME>
|
||||
<AGGREGATION>11</AGGREGATION>
|
||||
<KEEPHIGH>0</KEEPHIGH>
|
||||
<DROPLOW>0</DROPLOW>
|
||||
<AGGREGATEONLYGRADED>1</AGGREGATEONLYGRADED>
|
||||
<AGGREGATEOUTCOMES>0</AGGREGATEOUTCOMES>
|
||||
<AGGREGATESUBCATS>0</AGGREGATESUBCATS>
|
||||
<TIMECREATED>1299774068</TIMECREATED>
|
||||
<TIMEMODIFIED>1299774068</TIMEMODIFIED>
|
||||
</GRADE_CATEGORY>
|
||||
</GRADE_CATEGORIES>
|
||||
<GRADE_ITEMS>
|
||||
<GRADE_ITEM>
|
||||
<ID>410</ID>
|
||||
<CATEGORYID>$@NULL@$</CATEGORYID>
|
||||
<ITEMNAME>$@NULL@$</ITEMNAME>
|
||||
<ITEMTYPE>course</ITEMTYPE>
|
||||
<ITEMMODULE>$@NULL@$</ITEMMODULE>
|
||||
<ITEMINSTANCE>90</ITEMINSTANCE>
|
||||
<ITEMNUMBER>$@NULL@$</ITEMNUMBER>
|
||||
<ITEMINFO>$@NULL@$</ITEMINFO>
|
||||
<IDNUMBER>$@NULL@$</IDNUMBER>
|
||||
<CALCULATION>$@NULL@$</CALCULATION>
|
||||
<GRADETYPE>1</GRADETYPE>
|
||||
<GRADEMAX>100.00000</GRADEMAX>
|
||||
<GRADEMIN>0.00000</GRADEMIN>
|
||||
<SCALEID>$@NULL@$</SCALEID>
|
||||
<OUTCOMEID>$@NULL@$</OUTCOMEID>
|
||||
<GRADEPASS>0.00000</GRADEPASS>
|
||||
<MULTFACTOR>1.00000</MULTFACTOR>
|
||||
<PLUSFACTOR>0.00000</PLUSFACTOR>
|
||||
<AGGREGATIONCOEF>1.00000</AGGREGATIONCOEF>
|
||||
<DISPLAY>0</DISPLAY>
|
||||
<DECIMALS>$@NULL@$</DECIMALS>
|
||||
<HIDDEN>0</HIDDEN>
|
||||
<LOCKED>0</LOCKED>
|
||||
<LOCKTIME>0</LOCKTIME>
|
||||
<NEEDSUPDATE>0</NEEDSUPDATE>
|
||||
<TIMECREATED>1299774068</TIMECREATED>
|
||||
<TIMEMODIFIED>1299774068</TIMEMODIFIED>
|
||||
</GRADE_ITEM>
|
||||
</GRADE_ITEMS>
|
||||
</GRADEBOOK>
|
||||
<MODULES>
|
||||
<MOD>
|
||||
<ID>57</ID>
|
||||
<MODTYPE>forum</MODTYPE>
|
||||
<TYPE>news</TYPE>
|
||||
<NAME>News forum</NAME>
|
||||
<INTRO>General news and announcements</INTRO>
|
||||
<ASSESSED>0</ASSESSED>
|
||||
<ASSESSTIMESTART>0</ASSESSTIMESTART>
|
||||
<ASSESSTIMEFINISH>0</ASSESSTIMEFINISH>
|
||||
<MAXBYTES>0</MAXBYTES>
|
||||
<SCALE>0</SCALE>
|
||||
<FORCESUBSCRIBE>1</FORCESUBSCRIBE>
|
||||
<TRACKINGTYPE>1</TRACKINGTYPE>
|
||||
<RSSTYPE>0</RSSTYPE>
|
||||
<RSSARTICLES>0</RSSARTICLES>
|
||||
<TIMEMODIFIED>1299773780</TIMEMODIFIED>
|
||||
<WARNAFTER>0</WARNAFTER>
|
||||
<BLOCKAFTER>0</BLOCKAFTER>
|
||||
<BLOCKPERIOD>0</BLOCKPERIOD>
|
||||
</MOD>
|
||||
</MODULES>
|
||||
<FORMATDATA>
|
||||
</FORMATDATA>
|
||||
</COURSE>
|
||||
</MOODLE_BACKUP>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,463 +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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for the moodle1 converter
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup-convert
|
||||
* @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/backup/converter/moodle1/lib.php');
|
||||
|
||||
class moodle1_converter_test extends UnitTestCase {
|
||||
|
||||
public static $includecoverage = array();
|
||||
|
||||
/** @var string the name of the directory containing the unpacked Moodle 1.9 backup */
|
||||
protected $tempdir;
|
||||
|
||||
public function setUp() {
|
||||
global $CFG;
|
||||
|
||||
$this->tempdir = convert_helper::generate_id('simpletest');
|
||||
check_dir_exists("$CFG->dataroot/temp/backup/$this->tempdir/course_files/sub1");
|
||||
check_dir_exists("$CFG->dataroot/temp/backup/$this->tempdir/moddata/unittest/4/7");
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/moodle.xml",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/moodle.xml"
|
||||
);
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/course_files/file1.gif"
|
||||
);
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/course_files/sub1/file2.gif"
|
||||
);
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/moddata/unittest/4/file1.gif"
|
||||
);
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/moddata/unittest/4/icon.gif"
|
||||
);
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/icon.gif",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/moddata/unittest/4/7/icon.gif"
|
||||
);
|
||||
}
|
||||
|
||||
public function tearDown() {
|
||||
global $CFG;
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) {
|
||||
fulldelete("$CFG->dataroot/temp/backup/$this->tempdir");
|
||||
}
|
||||
}
|
||||
|
||||
public function test_detect_format() {
|
||||
$detected = moodle1_converter::detect_format($this->tempdir);
|
||||
$this->assertEqual(backup::FORMAT_MOODLE1, $detected);
|
||||
}
|
||||
|
||||
public function test_convert_factory() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$this->assertIsA($converter, 'moodle1_converter');
|
||||
}
|
||||
|
||||
public function test_stash_storage_not_created() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$this->expectException('moodle1_convert_storage_exception');
|
||||
$converter->set_stash('tempinfo', 12);
|
||||
}
|
||||
|
||||
public function test_stash_requiring_empty_stash() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->create_stash_storage();
|
||||
$converter->set_stash('tempinfo', 12);
|
||||
$this->expectException('moodle1_convert_empty_storage_exception');
|
||||
try {
|
||||
$converter->get_stash('anothertempinfo');
|
||||
|
||||
} catch (moodle1_convert_empty_storage_exception $e) {
|
||||
// we must drop the storage here so we are able to re-create it in the next test
|
||||
$converter->drop_stash_storage();
|
||||
throw new moodle1_convert_empty_storage_exception('rethrowing');
|
||||
}
|
||||
}
|
||||
|
||||
public function test_stash_storage() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->create_stash_storage();
|
||||
|
||||
// no implicit stashes
|
||||
$stashes = $converter->get_stash_names();
|
||||
$this->assertIsA($stashes, 'array');
|
||||
$this->assertTrue(empty($stashes));
|
||||
|
||||
// test stashes without itemid
|
||||
$converter->set_stash('tempinfo1', 12);
|
||||
$converter->set_stash('tempinfo2', array('a' => 2, 'b' => 3));
|
||||
$stashes = $converter->get_stash_names();
|
||||
$this->assertIsA($stashes, 'array');
|
||||
$this->assertEqual(2, count($stashes));
|
||||
$this->assertTrue(in_array('tempinfo1', $stashes));
|
||||
$this->assertTrue(in_array('tempinfo2', $stashes));
|
||||
$this->assertIdentical(12, $converter->get_stash('tempinfo1'));
|
||||
$this->assertIdentical(array('a' => 2, 'b' => 3), $converter->get_stash('tempinfo2'));
|
||||
|
||||
// overwriting a stashed value is allowed
|
||||
$converter->set_stash('tempinfo1', '13');
|
||||
$this->assertNotIdentical(13, $converter->get_stash('tempinfo1'));
|
||||
$this->assertIdentical('13', $converter->get_stash('tempinfo1'));
|
||||
|
||||
// repeated reading is allowed
|
||||
$this->assertIdentical('13', $converter->get_stash('tempinfo1'));
|
||||
|
||||
// storing empty array
|
||||
$converter->set_stash('empty_array_stash', array());
|
||||
$restored = $converter->get_stash('empty_array_stash');
|
||||
//$this->assertIsA($restored, 'array'); // todo return null now, this needs MDL-27713 to be fixed, then uncomment
|
||||
$this->assertTrue(empty($restored));
|
||||
|
||||
// test stashes with itemid
|
||||
$converter->set_stash('tempinfo', 'Hello', 1);
|
||||
$converter->set_stash('tempinfo', 'World', 2);
|
||||
$this->assertIdentical('Hello', $converter->get_stash('tempinfo', 1));
|
||||
$this->assertIdentical('World', $converter->get_stash('tempinfo', 2));
|
||||
|
||||
// test get_stash_itemids()
|
||||
$ids = $converter->get_stash_itemids('course_fileref');
|
||||
$this->assertIsA($ids, 'array');
|
||||
$this->assertTrue(empty($ids));
|
||||
|
||||
$converter->set_stash('course_fileref', null, 34);
|
||||
$converter->set_stash('course_fileref', null, 52);
|
||||
$ids = $converter->get_stash_itemids('course_fileref');
|
||||
$this->assertEqual(2, count($ids));
|
||||
$this->assertTrue(in_array(34, $ids));
|
||||
$this->assertTrue(in_array(52, $ids));
|
||||
|
||||
$converter->drop_stash_storage();
|
||||
}
|
||||
|
||||
public function test_get_stash_or_default() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->create_stash_storage();
|
||||
|
||||
$this->assertTrue(is_null($converter->get_stash_or_default('stashname')));
|
||||
$this->assertTrue(is_null($converter->get_stash_or_default('stashname', 7)));
|
||||
$this->assertTrue('default' === $converter->get_stash_or_default('stashname', 0, 'default'));
|
||||
$this->assertTrue(array('foo', 'bar') === $converter->get_stash_or_default('stashname', 42, array('foo', 'bar')));
|
||||
|
||||
//$converter->set_stash('stashname', 0);
|
||||
//$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
|
||||
|
||||
//$converter->set_stash('stashname', '');
|
||||
//$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
|
||||
|
||||
//$converter->set_stash('stashname', array());
|
||||
//$this->assertFalse(is_null($converter->get_stash_or_default('stashname'))); // todo returns true now, this needs MDL-27713 to be fixed
|
||||
|
||||
$converter->set_stash('stashname', 42);
|
||||
$this->assertTrue(42 === $converter->get_stash_or_default('stashname'));
|
||||
$this->assertTrue(is_null($converter->get_stash_or_default('stashname', 1)));
|
||||
$this->assertTrue(42 === $converter->get_stash_or_default('stashname', 0, 61));
|
||||
|
||||
$converter->set_stash('stashname', array(42 => (object)array('id' => 42)), 18);
|
||||
$stashed = $converter->get_stash_or_default('stashname', 18, 1984);
|
||||
$this->assertIsA($stashed, 'array');
|
||||
$this->assertTrue(is_object($stashed[42]));
|
||||
$this->assertTrue($stashed[42]->id === 42);
|
||||
|
||||
$converter->drop_stash_storage();
|
||||
}
|
||||
|
||||
public function test_get_contextid() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
|
||||
// stash storage must be created in advance
|
||||
$converter->create_stash_storage();
|
||||
|
||||
// ids are generated on the first call
|
||||
$id1 = $converter->get_contextid(CONTEXT_BLOCK, 10);
|
||||
$id2 = $converter->get_contextid(CONTEXT_BLOCK, 11);
|
||||
$id3 = $converter->get_contextid(CONTEXT_MODULE, 10);
|
||||
|
||||
$this->assertNotEqual($id1, $id2);
|
||||
$this->assertNotEqual($id1, $id3);
|
||||
$this->assertNotEqual($id2, $id3);
|
||||
|
||||
// and then re-used if called with the same params
|
||||
$this->assertEqual($id1, $converter->get_contextid(CONTEXT_BLOCK, 10));
|
||||
$this->assertEqual($id2, $converter->get_contextid(CONTEXT_BLOCK, 11));
|
||||
$this->assertEqual($id3, $converter->get_contextid(CONTEXT_MODULE, 10));
|
||||
|
||||
// for system and course level, the instance is irrelevant
|
||||
// as we need only one system and one course
|
||||
$id1 = $converter->get_contextid(CONTEXT_COURSE);
|
||||
$id2 = $converter->get_contextid(CONTEXT_COURSE, 10);
|
||||
$id3 = $converter->get_contextid(CONTEXT_COURSE, 14);
|
||||
|
||||
$this->assertEqual($id1, $id2);
|
||||
$this->assertEqual($id1, $id3);
|
||||
|
||||
$id1 = $converter->get_contextid(CONTEXT_SYSTEM);
|
||||
$id2 = $converter->get_contextid(CONTEXT_SYSTEM, 11);
|
||||
$id3 = $converter->get_contextid(CONTEXT_SYSTEM, 15);
|
||||
|
||||
$this->assertEqual($id1, $id2);
|
||||
$this->assertEqual($id1, $id3);
|
||||
|
||||
$converter->drop_stash_storage();
|
||||
}
|
||||
|
||||
public function test_get_nextid() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
|
||||
$id1 = $converter->get_nextid();
|
||||
$id2 = $converter->get_nextid();
|
||||
$id3 = $converter->get_nextid();
|
||||
|
||||
$this->assertTrue(0 < $id1);
|
||||
$this->assertTrue($id1 < $id2);
|
||||
$this->assertTrue($id2 < $id3);
|
||||
}
|
||||
|
||||
public function test_migrate_file() {
|
||||
// set-up the file manager
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->create_stash_storage();
|
||||
$contextid = $converter->get_contextid(CONTEXT_MODULE, 32);
|
||||
$fileman = $converter->get_file_manager($contextid, 'mod_unittest', 'testarea');
|
||||
// this fileman has not converted anything yet
|
||||
$fileids = $fileman->get_fileids();
|
||||
$this->assertIsA($fileids, 'array');
|
||||
$this->assertEqual(0, count($fileids));
|
||||
// try to migrate a non-existing directory
|
||||
$returned = $fileman->migrate_directory('not/existing/directory');
|
||||
$this->assertIsA($returned, 'array');
|
||||
$this->assertEqual(0, count($returned));
|
||||
$fileids = $fileman->get_fileids();
|
||||
$this->assertIsA($fileids, 'array');
|
||||
$this->assertEqual(0, count($fileids));
|
||||
// migrate a single file
|
||||
$fileman->itemid = 4;
|
||||
$fileman->migrate_file('moddata/unittest/4/icon.gif');
|
||||
$this->assertTrue(is_file($converter->get_workdir_path().'/files/4e/4ea114b0558f53e3af8dd9afc0e0810a95c2a724'));
|
||||
// get the file id
|
||||
$fileids = $fileman->get_fileids();
|
||||
$this->assertIsA($fileids, 'array');
|
||||
$this->assertEqual(1, count($fileids));
|
||||
// migrate another single file into another file area
|
||||
$fileman->filearea = 'anotherarea';
|
||||
$fileman->itemid = 7;
|
||||
$fileman->migrate_file('moddata/unittest/4/7/icon.gif', '/', 'renamed.gif');
|
||||
// get the file records
|
||||
$filerecordids = $converter->get_stash_itemids('files');
|
||||
foreach ($filerecordids as $filerecordid) {
|
||||
$filerecord = $converter->get_stash('files', $filerecordid);
|
||||
$this->assertEqual('4ea114b0558f53e3af8dd9afc0e0810a95c2a724', $filerecord['contenthash']);
|
||||
$this->assertEqual($contextid, $filerecord['contextid']);
|
||||
$this->assertEqual('mod_unittest', $filerecord['component']);
|
||||
if ($filerecord['filearea'] === 'testarea') {
|
||||
$this->assertEqual(4, $filerecord['itemid']);
|
||||
$this->assertEqual('icon.gif', $filerecord['filename']);
|
||||
}
|
||||
}
|
||||
// explicitly clear the list of migrated files
|
||||
$this->assertTrue(count($fileman->get_fileids()) > 0);
|
||||
$fileman->reset_fileids();
|
||||
$this->assertTrue(count($fileman->get_fileids()) == 0);
|
||||
$converter->drop_stash_storage();
|
||||
}
|
||||
|
||||
public function test_convert_path() {
|
||||
$path = new convert_path('foo_bar', '/ROOT/THINGS/FOO/BAR');
|
||||
$this->assertEqual('foo_bar', $path->get_name());
|
||||
$this->assertEqual('/ROOT/THINGS/FOO/BAR', $path->get_path());
|
||||
$this->assertEqual('process_foo_bar', $path->get_processing_method());
|
||||
$this->assertEqual('on_foo_bar_start', $path->get_start_method());
|
||||
$this->assertEqual('on_foo_bar_end', $path->get_end_method());
|
||||
}
|
||||
|
||||
public function test_convert_path_implicit_recipes() {
|
||||
$path = new convert_path('foo_bar', '/ROOT/THINGS/FOO/BAR');
|
||||
$data = array(
|
||||
'ID' => 76,
|
||||
'ELOY' => 'stronk7',
|
||||
'MARTIN' => 'moodler',
|
||||
'EMPTY' => null,
|
||||
);
|
||||
// apply default recipes (converting keys to lowercase)
|
||||
$data = $path->apply_recipes($data);
|
||||
$this->assertEqual(4, count($data));
|
||||
$this->assertEqual(76, $data['id']);
|
||||
$this->assertEqual('stronk7', $data['eloy']);
|
||||
$this->assertEqual('moodler', $data['martin']);
|
||||
$this->assertIdentical(null, $data['empty']);
|
||||
}
|
||||
|
||||
public function test_convert_path_explicit_recipes() {
|
||||
$path = new convert_path(
|
||||
'foo_bar', '/ROOT/THINGS/FOO/BAR',
|
||||
array(
|
||||
'newfields' => array(
|
||||
'david' => 'mudrd8mz',
|
||||
'petr' => 'skodak',
|
||||
),
|
||||
'renamefields' => array(
|
||||
'empty' => 'nothing',
|
||||
),
|
||||
'dropfields' => array(
|
||||
'id'
|
||||
),
|
||||
)
|
||||
);
|
||||
$data = array(
|
||||
'ID' => 76,
|
||||
'ELOY' => 'stronk7',
|
||||
'MARTIN' => 'moodler',
|
||||
'EMPTY' => null,
|
||||
);
|
||||
$data = $path->apply_recipes($data);
|
||||
|
||||
$this->assertEqual(5, count($data));
|
||||
$this->assertFalse(array_key_exists('id', $data));
|
||||
$this->assertEqual('stronk7', $data['eloy']);
|
||||
$this->assertEqual('moodler', $data['martin']);
|
||||
$this->assertEqual('mudrd8mz', $data['david']);
|
||||
$this->assertEqual('skodak', $data['petr']);
|
||||
$this->assertIdentical(null, $data['nothing']);
|
||||
}
|
||||
|
||||
public function test_grouped_data_on_nongrouped_convert_path() {
|
||||
// prepare some grouped data
|
||||
$data = array(
|
||||
'ID' => 77,
|
||||
'NAME' => 'Pale lagers',
|
||||
'BEERS' => array(
|
||||
array(
|
||||
'BEER' => array(
|
||||
'ID' => 67,
|
||||
'NAME' => 'Pilsner Urquell',
|
||||
)
|
||||
),
|
||||
array(
|
||||
'BEER' => array(
|
||||
'ID' => 34,
|
||||
'NAME' => 'Heineken',
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// declare a non-grouped path
|
||||
$path = new convert_path('beer_style', '/ROOT/BEER_STYLES/BEER_STYLE');
|
||||
|
||||
// an attempt to apply recipes throws exception because we do not expect grouped data
|
||||
$this->expectException('convert_path_exception');
|
||||
$data = $path->apply_recipes($data);
|
||||
}
|
||||
|
||||
public function test_grouped_convert_path_with_recipes() {
|
||||
// prepare some grouped data
|
||||
$data = array(
|
||||
'ID' => 77,
|
||||
'NAME' => 'Pale lagers',
|
||||
'BEERS' => array(
|
||||
array(
|
||||
'BEER' => array(
|
||||
'ID' => 67,
|
||||
'NAME' => 'Pilsner Urquell',
|
||||
)
|
||||
),
|
||||
array(
|
||||
'BEER' => array(
|
||||
'ID' => 34,
|
||||
'NAME' => 'Heineken',
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// implict recipes work for grouped data if the path is declared as grouped
|
||||
$path = new convert_path('beer_style', '/ROOT/BEER_STYLES/BEER_STYLE', array(), true);
|
||||
$data = $path->apply_recipes($data);
|
||||
$this->assertEqual('Heineken', $data['beers'][1]['beer']['name']);
|
||||
|
||||
// an attempt to provide explicit recipes on grouped elements throws exception
|
||||
$this->expectException('convert_path_exception');
|
||||
$path = new convert_path(
|
||||
'beer_style', '/ROOT/BEER_STYLES/BEER_STYLE',
|
||||
array(
|
||||
'renamefields' => array(
|
||||
'name' => 'beername', // note this is confusing recipe because the 'name' is used for both
|
||||
// beer-style name ('Pale lagers') and beer name ('Pilsner Urquell')
|
||||
)
|
||||
), true);
|
||||
}
|
||||
|
||||
public function test_referenced_course_files() {
|
||||
|
||||
$text = 'This is a text containing links to file.php
|
||||
as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif" /><a href="$@FILEPHP@$$@SLASH@$pics$@SLASH@$news.gif$@FORCEDOWNLOAD@$">download image</a><br />
|
||||
<br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />';
|
||||
|
||||
$files = moodle1_converter::find_referenced_files($text);
|
||||
$this->assertIsA($files, 'array');
|
||||
$this->assertEqual(2, count($files));
|
||||
$this->assertTrue(in_array('/pics/news.gif', $files));
|
||||
$this->assertTrue(in_array('/MANUAL.DOC', $files));
|
||||
|
||||
$text = moodle1_converter::rewrite_filephp_usage($text, array('/pics/news.gif', '/another/file/notused.txt'), $files);
|
||||
$this->assertEqual($text, 'This is a text containing links to file.php
|
||||
as it is parsed from the backup file. <br /><br /><img border="0" width="110" vspace="0" hspace="0" height="92" title="News" alt="News" src="@@PLUGINFILE@@/pics/news.gif" /><a href="@@PLUGINFILE@@/pics/news.gif?forcedownload=1">download image</a><br />
|
||||
<br /><a href=\'$@FILEPHP@$$@SLASH@$MANUAL.DOC$@FORCEDOWNLOAD@$\'>download manual</a><br />');
|
||||
}
|
||||
|
||||
public function test_question_bank_conversion() {
|
||||
global $CFG;
|
||||
|
||||
copy(
|
||||
"$CFG->dirroot/backup/converter/moodle1/simpletest/files/questions.xml",
|
||||
"$CFG->dataroot/temp/backup/$this->tempdir/moodle.xml"
|
||||
);
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->convert();
|
||||
}
|
||||
|
||||
public function test_convert_run_convert() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$converter->convert();
|
||||
}
|
||||
|
||||
public function test_inforef_manager() {
|
||||
$converter = convert_factory::get_converter('moodle1', $this->tempdir);
|
||||
$inforef = $converter->get_inforef_manager('unittest');
|
||||
$inforef->add_ref('file', 45);
|
||||
$inforef->add_refs('file', array(46, 47));
|
||||
// todo test the write_refs() via some dummy xml_writer
|
||||
$this->expectException('coding_exception');
|
||||
$inforef->add_ref('unknown_referenced_item_name', 76);
|
||||
}
|
||||
}
|
||||
@@ -72,8 +72,10 @@ class backup_course_task extends backup_task {
|
||||
// annotating some bits, tags and module restrictions
|
||||
$this->add_step(new backup_course_structure_step('course_info', 'course.xml'));
|
||||
|
||||
// Generate the enrolment file
|
||||
$this->add_step(new backup_enrolments_structure_step('course_enrolments', 'enrolments.xml'));
|
||||
// Generate the enrolment file (conditionally, prevent it in any IMPORT/HUB operation)
|
||||
if ($this->plan->get_mode() != backup::MODE_IMPORT && $this->plan->get_mode() != backup::MODE_HUB) {
|
||||
$this->add_step(new backup_enrolments_structure_step('course_enrolments', 'enrolments.xml'));
|
||||
}
|
||||
|
||||
// Annotate all the groups and groupings belonging to the course
|
||||
$this->add_step(new backup_annotate_course_groups_and_groupings('annotate_course_groups'));
|
||||
|
||||
@@ -111,7 +111,8 @@ abstract class backup_qtype_plugin extends backup_plugin {
|
||||
// Define the elements
|
||||
$options = new backup_nested_element('numerical_options');
|
||||
$option = new backup_nested_element('numerical_option', array('id'), array(
|
||||
'showunits', 'unitsleft', 'unitgradingtype', 'unitpenalty'));
|
||||
'instructions', 'instructionsformat', 'showunits', 'unitsleft',
|
||||
'unitgradingtype', 'unitpenalty'));
|
||||
|
||||
// Build the tree
|
||||
$element->add_child($options);
|
||||
|
||||
@@ -174,76 +174,78 @@ abstract class backup_questions_activity_structure_step extends backup_activity_
|
||||
|
||||
/**
|
||||
* Attach to $element (usually attempts) the needed backup structures
|
||||
* for question_usages and all the associated data.
|
||||
* for question_states for a given question_attempt
|
||||
*/
|
||||
protected function add_question_usages($element, $usageidname) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/question/engine/lib.php');
|
||||
|
||||
protected function add_question_attempts_states($element, $questionattemptname) {
|
||||
// Check $element is one nested_backup_element
|
||||
if (! $element instanceof backup_nested_element) {
|
||||
throw new backup_step_exception('question_states_bad_parent_element', $element);
|
||||
}
|
||||
if (! $element->get_final_element($usageidname)) {
|
||||
throw new backup_step_exception('question_states_bad_question_attempt_element', $usageidname);
|
||||
// Check that the $questionattemptname is final element in $element
|
||||
if (! $element->get_final_element($questionattemptname)) {
|
||||
throw new backup_step_exception('question_states_bad_question_attempt_element', $questionattemptname);
|
||||
}
|
||||
|
||||
$quba = new backup_nested_element('question_usage', array('id'),
|
||||
array('component', 'preferredbehaviour'));
|
||||
// TODO: Some day we should stop these "encrypted" state->answers and
|
||||
// TODO: delegate to qtypes plugin to proper XML writting the needed info on each question
|
||||
|
||||
$qas = new backup_nested_element('question_attempts');
|
||||
$qa = new backup_nested_element('question_attempt', array('id'), array(
|
||||
'slot', 'behaviour', 'questionid', 'maxmark', 'minfraction',
|
||||
'flagged', 'questionsummary', 'rightanswer', 'responsesummary',
|
||||
'timemodified'));
|
||||
// TODO: Should be doing here some introspection in the "answer" element, based on qtype,
|
||||
// TODO: to know which real questions are being used (for randoms and other qtypes...)
|
||||
// TODO: Not needed if consistency is guaranteed, but it isn't right now :-(
|
||||
|
||||
$steps = new backup_nested_element('steps');
|
||||
$step = new backup_nested_element('step', array('id'), array(
|
||||
'sequencenumber', 'state', 'fraction', 'timecreated', 'userid'));
|
||||
|
||||
$response = new backup_nested_element('response');
|
||||
$variable = new backup_nested_element('variable', null, array('name', 'value'));
|
||||
// Define the elements
|
||||
$states = new backup_nested_element('states');
|
||||
$state = new backup_nested_element('state', array('id'), array(
|
||||
'question', 'seq_number', 'answer', 'timestamp',
|
||||
'event', 'grade', 'raw_grade', 'penalty'));
|
||||
|
||||
// Build the tree
|
||||
$element->add_child($quba);
|
||||
$quba->add_child($qas);
|
||||
$qas->add_child($qa);
|
||||
$qa->add_child($steps);
|
||||
$steps->add_child($step);
|
||||
$step->add_child($response);
|
||||
$response->add_child($variable);
|
||||
$element->add_child($states);
|
||||
$states->add_child($state);
|
||||
|
||||
// Set the sources
|
||||
$quba->set_source_table('question_usages',
|
||||
array('id' => '../' . $usageidname));
|
||||
$qa->set_source_sql('
|
||||
SELECT *
|
||||
FROM {question_attempts}
|
||||
WHERE questionusageid = :questionusageid
|
||||
ORDER BY slot',
|
||||
array('questionusageid' => backup::VAR_PARENTID));
|
||||
$step->set_source_sql('
|
||||
SELECT *
|
||||
FROM {question_attempt_steps}
|
||||
WHERE questionattemptid = :questionattemptid
|
||||
ORDER BY sequencenumber',
|
||||
array('questionattemptid' => backup::VAR_PARENTID));
|
||||
$variable->set_source_table('question_attempt_step_data',
|
||||
array('attemptstepid' => backup::VAR_PARENTID));
|
||||
$state->set_source_table('question_states', array('attempt' => '../../' . $questionattemptname));
|
||||
|
||||
// Annotate ids
|
||||
$qa->annotate_ids('question', 'questionid');
|
||||
$step->annotate_ids('user', 'userid');
|
||||
$state->annotate_ids('question', 'question');
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach to $element (usually attempts) the needed backup structures
|
||||
* for question_sessions for a given question_attempt
|
||||
*/
|
||||
protected function add_question_attempts_sessions($element, $questionattemptname) {
|
||||
// Check $element is one nested_backup_element
|
||||
if (! $element instanceof backup_nested_element) {
|
||||
throw new backup_step_exception('question_sessions_bad_parent_element', $element);
|
||||
}
|
||||
// Check that the $questionattemptname is final element in $element
|
||||
if (! $element->get_final_element($questionattemptname)) {
|
||||
throw new backup_step_exception('question_sessions_bad_question_attempt_element', $questionattemptname);
|
||||
}
|
||||
|
||||
// Define the elements
|
||||
$sessions = new backup_nested_element('sessions');
|
||||
$session = new backup_nested_element('session', array('id'), array(
|
||||
'questionid', 'newest', 'newgraded', 'sumpenalty',
|
||||
'manualcomment', 'manualcommentformat', 'flagged'));
|
||||
|
||||
// Build the tree
|
||||
$element->add_child($sessions);
|
||||
$sessions->add_child($session);
|
||||
|
||||
// Set the sources
|
||||
$session->set_source_table('question_sessions', array('attemptid' => '../../' . $questionattemptname));
|
||||
|
||||
// Annotate ids
|
||||
$session->annotate_ids('question', 'questionid');
|
||||
|
||||
// Annotate files
|
||||
$fileareas = question_engine::get_all_response_file_areas();
|
||||
foreach ($fileareas as $filearea) {
|
||||
$step->annotate_files('question', $filearea, 'id');
|
||||
}
|
||||
// Note: question_sessions haven't files associated. On purpose manualcomment is lacking
|
||||
// support for them, so we don't need to annotated them here.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* backup structure step in charge of calculating the categories to be
|
||||
* included in backup, based in the context being backuped (module/course)
|
||||
@@ -319,8 +321,9 @@ class backup_module_structure_step extends backup_structure_step {
|
||||
// attach format plugin structure to $module element, only one allowed
|
||||
$this->add_plugin_structure('format', $module, false);
|
||||
|
||||
// attach plagiarism plugin structure to $module element, only one allowed
|
||||
$this->add_plugin_structure('plagiarism', $module, false);
|
||||
// attach plagiarism plugin structure to $module element, there can be potentially
|
||||
// many plagiarism plugins storing information about this course
|
||||
$this->add_plugin_structure('plagiarism', $module, true);
|
||||
|
||||
// Define the tree
|
||||
$module->add_child($availinfo);
|
||||
@@ -421,8 +424,9 @@ class backup_course_structure_step extends backup_structure_step {
|
||||
// course reports can save course data if required
|
||||
$this->add_plugin_structure('coursereport', $course, true);
|
||||
|
||||
// attach plagiarism plugin structure to $course element, only one allowed
|
||||
$this->add_plugin_structure('plagiarism', $course, false);
|
||||
// attach plagiarism plugin structure to $course element, there can be potentially
|
||||
// many plagiarism plugins storing information about this course
|
||||
$this->add_plugin_structure('plagiarism', $course, true);
|
||||
|
||||
// Build the tree
|
||||
|
||||
@@ -1694,25 +1698,19 @@ class backup_questions_structure_step extends backup_structure_step {
|
||||
|
||||
$question = new backup_nested_element('question', array('id'), array(
|
||||
'parent', 'name', 'questiontext', 'questiontextformat',
|
||||
'generalfeedback', 'generalfeedbackformat', 'defaultmark', 'penalty',
|
||||
'generalfeedback', 'generalfeedbackformat', 'defaultgrade', 'penalty',
|
||||
'qtype', 'length', 'stamp', 'version',
|
||||
'hidden', 'timecreated', 'timemodified', 'createdby', 'modifiedby'));
|
||||
|
||||
// attach qtype plugin structure to $question element, only one allowed
|
||||
$this->add_plugin_structure('qtype', $question, false);
|
||||
|
||||
$qhints = new backup_nested_element('question_hints');
|
||||
|
||||
$qhint = new backup_nested_element('question_hint', array('id'), array(
|
||||
'hint', 'hintformat', 'shownumcorrect', 'clearwrong', 'options'));
|
||||
|
||||
// Build the tree
|
||||
|
||||
$qcategories->add_child($qcategory);
|
||||
$qcategory->add_child($questions);
|
||||
|
||||
$questions->add_child($question);
|
||||
$question->add_child($qhints);
|
||||
$qhints->add_child($qhint);
|
||||
|
||||
// Define the sources
|
||||
|
||||
@@ -1726,13 +1724,6 @@ class backup_questions_structure_step extends backup_structure_step {
|
||||
|
||||
$question->set_source_table('question', array('category' => backup::VAR_PARENTID));
|
||||
|
||||
$qhint->set_source_sql('
|
||||
SELECT *
|
||||
FROM {question_hints}
|
||||
WHERE questionid = :questionid
|
||||
ORDER BY id',
|
||||
array('questionid' => backup::VAR_PARENTID));
|
||||
|
||||
// don't need to annotate ids nor files
|
||||
// (already done by {@link backup_annotate_all_question_files}
|
||||
|
||||
|
||||
@@ -69,8 +69,10 @@ class restore_course_task extends restore_task {
|
||||
// Restore course role assignments and overrides (internally will observe the role_assignments setting)
|
||||
$this->add_step(new restore_ras_and_caps_structure_step('course_ras_and_caps', 'roles.xml'));
|
||||
|
||||
// Restore course enrolments (plugins and membership)
|
||||
$this->add_step(new restore_enrolments_structure_step('course_enrolments', 'enrolments.xml'));
|
||||
// Restore course enrolments (plugins and membership). Conditionally prevented for any IMPORT/HUB operation
|
||||
if ($this->plan->get_mode() != backup::MODE_IMPORT && $this->plan->get_mode() != backup::MODE_HUB) {
|
||||
$this->add_step(new restore_enrolments_structure_step('course_enrolments', 'enrolments.xml'));
|
||||
}
|
||||
|
||||
// Restore course filters (conditionally)
|
||||
if ($this->get_setting_value('filters')) {
|
||||
|
||||
@@ -115,23 +115,6 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
$newquestionid = $this->get_new_parentid('question');
|
||||
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
|
||||
|
||||
// In the past, there were some sloppily rounded fractions around. Fix them up.
|
||||
$changes = array(
|
||||
'-0.66666' => '-0.6666667',
|
||||
'-0.33333' => '-0.3333333',
|
||||
'-0.16666' => '-0.1666667',
|
||||
'-0.142857' => '-0.1428571',
|
||||
'0.11111' => '0.1111111',
|
||||
'0.142857' => '0.1428571',
|
||||
'0.16666' => '0.1666667',
|
||||
'0.33333' => '0.3333333',
|
||||
'0.333333' => '0.3333333',
|
||||
'0.66666' => '0.6666667',
|
||||
);
|
||||
if (array_key_exists($data->fraction, $changes)) {
|
||||
$data->fraction = $changes[$data->fraction];
|
||||
}
|
||||
|
||||
// If the question has been created by restore, we need to create its question_answers too
|
||||
if ($questioncreated) {
|
||||
// Adjust some columns
|
||||
@@ -315,21 +298,9 @@ abstract class restore_qtype_plugin extends restore_plugin {
|
||||
}
|
||||
|
||||
/**
|
||||
* Do any re-coding necessary in the student response.
|
||||
* @param int $questionid the new id of the question
|
||||
* @param int $sequencenumber of the step within the qusetion attempt.
|
||||
* @param array the response data from the backup.
|
||||
* @return array the recoded response.
|
||||
* Decode one question_states for this qtype (default impl)
|
||||
*/
|
||||
public function recode_response($questionid, $sequencenumber, array $response) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode legacy question_states.answer for this qtype. Used when restoring
|
||||
* 2.0 attempt data.
|
||||
*/
|
||||
public function recode_legacy_state_answer($state) {
|
||||
public function recode_state_answer($state) {
|
||||
// By default, return answer unmodified, qtypes needing recode will override this
|
||||
return $state->answer;
|
||||
}
|
||||
|
||||
@@ -146,18 +146,12 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
|
||||
$data->courseid = $this->get_courseid();
|
||||
|
||||
//manual grade items store category id in categoryid
|
||||
if ($data->itemtype=='manual') {
|
||||
// manual grade items store category id in categoryid
|
||||
$data->categoryid = $this->get_mappingid('grade_category', $data->categoryid, NULL);
|
||||
} else if ($data->itemtype=='course') {
|
||||
// course grade item stores their category id in iteminstance
|
||||
$coursecat = grade_category::fetch_course_category($this->get_courseid());
|
||||
$data->iteminstance = $coursecat->id;
|
||||
} else if ($data->itemtype=='category') {
|
||||
// category grade items store their category id in iteminstance
|
||||
} //course and category grade items store their category id in iteminstance
|
||||
else if ($data->itemtype=='course' || $data->itemtype=='category') {
|
||||
$data->iteminstance = $this->get_mappingid('grade_category', $data->iteminstance, NULL);
|
||||
} else {
|
||||
throw new restore_step_exception('unexpected_grade_item_type', $data->itemtype);
|
||||
}
|
||||
|
||||
$data->scaleid = $this->get_mappingid('scale', $data->scaleid, NULL);
|
||||
@@ -242,7 +236,6 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
//get the already created course level grade category
|
||||
$category = new stdclass();
|
||||
$category->courseid = $this->get_courseid();
|
||||
$category->parent = null;
|
||||
|
||||
$coursecategory = $DB->get_record('grade_categories', (array)$category);
|
||||
if (!empty($coursecategory)) {
|
||||
@@ -307,16 +300,12 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
|
||||
//if this is an activity grade item that needs to be put back in its correct category
|
||||
if (!empty($grade_item_backup->parentitemid)) {
|
||||
$oldcategoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid, null);
|
||||
if (!is_null($oldcategoryid)) {
|
||||
$updateobj->categoryid = $oldcategoryid;
|
||||
$DB->update_record('grade_items', $updateobj);
|
||||
}
|
||||
$updateobj->categoryid = $this->get_mappingid('grade_category', $grade_item_backup->parentitemid);
|
||||
} else {
|
||||
//mark course and category items as needing to be recalculated
|
||||
$updateobj->needsupdate=1;
|
||||
$DB->update_record('grade_items', $updateobj);
|
||||
}
|
||||
$DB->update_record('grade_items', $updateobj);
|
||||
}
|
||||
}
|
||||
$rs->close();
|
||||
@@ -324,7 +313,8 @@ class restore_gradebook_structure_step extends restore_structure_step {
|
||||
// We need to update the calculations for calculated grade items that may reference old
|
||||
// grade item ids using ##gi\d+##.
|
||||
// $mappings can be empty, use 0 if so (won't match ever)
|
||||
list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED, 'param', true, 0);
|
||||
$mappings = !empty($mappings) ? $mappings : array(0);
|
||||
list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED);
|
||||
$sql = "SELECT gi.id, gi.calculation
|
||||
FROM {grade_items} gi
|
||||
WHERE gi.id {$sql} AND
|
||||
@@ -1291,6 +1281,28 @@ class restore_ras_and_caps_structure_step extends restore_structure_step {
|
||||
*/
|
||||
class restore_enrolments_structure_step extends restore_structure_step {
|
||||
|
||||
/**
|
||||
* Conditionally decide if this step should be executed.
|
||||
*
|
||||
* This function checks the following parameter:
|
||||
*
|
||||
* 1. the course/enrolments.xml file exists
|
||||
*
|
||||
* @return bool true is safe to execute, false otherwise
|
||||
*/
|
||||
protected function execute_condition() {
|
||||
|
||||
// Check it is included in the backup
|
||||
$fullpath = $this->task->get_taskbasepath();
|
||||
$fullpath = rtrim($fullpath, '/') . '/' . $this->filename;
|
||||
if (!file_exists($fullpath)) {
|
||||
// Not found, can't restore enrolments info
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function define_structure() {
|
||||
|
||||
$paths = array();
|
||||
@@ -1749,7 +1761,7 @@ class restore_course_logs_structure_step extends restore_structure_step {
|
||||
/**
|
||||
* Conditionally decide if this step should be executed.
|
||||
*
|
||||
* This function checks the following four parameters:
|
||||
* This function checks the following parameter:
|
||||
*
|
||||
* 1. the course/logs.xml file exists
|
||||
*
|
||||
@@ -2203,7 +2215,6 @@ class restore_module_structure_step extends restore_structure_step {
|
||||
* - Activity includes completion info (file_exists)
|
||||
*/
|
||||
class restore_userscompletion_structure_step extends restore_structure_step {
|
||||
private $done = array();
|
||||
|
||||
/**
|
||||
* To conditionally decide if this step must be executed
|
||||
@@ -2248,33 +2259,7 @@ class restore_userscompletion_structure_step extends restore_structure_step {
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
// Check we didn't already insert one for this cmid and userid
|
||||
// (there aren't supposed to be duplicates in that field, but
|
||||
// it was possible until MDL-28021 was fixed).
|
||||
$key = $data->coursemoduleid . ',' . $data->userid;
|
||||
if (array_key_exists($key, $this->done)) {
|
||||
// Find the existing record
|
||||
$existing = $DB->get_record('course_modules_completion', array(
|
||||
'coursemoduleid' => $data->coursemoduleid,
|
||||
'userid' => $data->userid), 'id, timemodified');
|
||||
// Update it to these new values, but only if the time is newer
|
||||
if ($existing->timemodified < $data->timemodified) {
|
||||
$data->id = $existing->id;
|
||||
$DB->update_record('course_modules_completion', $data);
|
||||
}
|
||||
} else {
|
||||
// Normal entry where it doesn't exist already
|
||||
$DB->insert_record('course_modules_completion', $data);
|
||||
// Remember this entry
|
||||
$this->done[$key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
// This gets called once per activity (according to my testing).
|
||||
// Clearing the array isn't strictly required, but avoids using
|
||||
// unnecessary memory.
|
||||
$this->done = array();
|
||||
$DB->insert_record('course_modules_completion', $data);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2371,13 +2356,11 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
|
||||
$category = new restore_path_element('question_category', '/question_categories/question_category');
|
||||
$question = new restore_path_element('question', '/question_categories/question_category/questions/question');
|
||||
$hint = new restore_path_element('question_hint',
|
||||
'/question_categories/question_category/questions/question/question_hints/question_hint');
|
||||
|
||||
// Apply for 'qtype' plugins optional paths at question level
|
||||
$this->add_plugin_structure('qtype', $question);
|
||||
|
||||
return array($category, $question, $hint);
|
||||
return array($category, $question);
|
||||
}
|
||||
|
||||
protected function process_question_category($data) {
|
||||
@@ -2430,17 +2413,6 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
// we have loaded qcatids there for all parsed questions
|
||||
$data->category = $this->get_mappingid('question_category', $questionmapping->parentitemid);
|
||||
|
||||
// In the past, there were some very sloppy values of penalty. Fix them.
|
||||
if ($data->penalty >= 0.33 && $data->penalty <= 0.34) {
|
||||
$data->penalty = 0.3333333;
|
||||
}
|
||||
if ($data->penalty >= 0.66 && $data->penalty <= 0.67) {
|
||||
$data->penalty = 0.6666667;
|
||||
}
|
||||
if ($data->penalty >= 1) {
|
||||
$data->penalty = 1;
|
||||
}
|
||||
|
||||
$data->timecreated = $this->apply_date_offset($data->timecreated);
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
@@ -2470,47 +2442,6 @@ class restore_create_categories_and_questions extends restore_structure_step {
|
||||
// step will be in charge of restoring all the question files
|
||||
}
|
||||
|
||||
protected function process_question_hint($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Detect if the question is created or mapped
|
||||
$oldquestionid = $this->get_old_parentid('question');
|
||||
$newquestionid = $this->get_new_parentid('question');
|
||||
$questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
|
||||
|
||||
// If the question has been created by restore, we need to create its question_answers too
|
||||
if ($questioncreated) {
|
||||
// Adjust some columns
|
||||
$data->questionid = $newquestionid;
|
||||
// Insert record
|
||||
$newitemid = $DB->insert_record('question_hints', $data);
|
||||
|
||||
// The question existed, we need to map the existing question_hints
|
||||
} else {
|
||||
// Look in question_hints by hint text matching
|
||||
$sql = 'SELECT id
|
||||
FROM {question_hints}
|
||||
WHERE questionid = ?
|
||||
AND ' . $DB->sql_compare_text('hint', 255) . ' = ' . $DB->sql_compare_text('?', 255);
|
||||
$params = array($newquestionid, $data->hint);
|
||||
$newitemid = $DB->get_field_sql($sql, $params);
|
||||
// If we haven't found the newitemid, something has gone really wrong, question in DB
|
||||
// is missing hints, exception
|
||||
if (!$newitemid) {
|
||||
$info = new stdClass();
|
||||
$info->filequestionid = $oldquestionid;
|
||||
$info->dbquestionid = $newquestionid;
|
||||
$info->hint = $data->hint;
|
||||
throw new restore_step_exception('error_question_hint_missing_in_db', $info);
|
||||
}
|
||||
}
|
||||
// Create mapping (I'm not sure if this is really needed?)
|
||||
$this->set_mapping('question_hint', $oldid, $newitemid);
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
global $DB;
|
||||
|
||||
@@ -2631,12 +2562,8 @@ class restore_create_question_files extends restore_execution_step {
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'generalfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true);
|
||||
// Add qtype dependent files
|
||||
$components = backup_qtype_plugin::get_components_and_fileareas($question->qtype);
|
||||
foreach ($components as $component => $fileareas) {
|
||||
@@ -2657,16 +2584,12 @@ class restore_create_question_files extends restore_execution_step {
|
||||
* (like the quiz module), to support qtype plugins, states and sessions
|
||||
*/
|
||||
abstract class restore_questions_activity_structure_step extends restore_activity_structure_step {
|
||||
/** @var array question_attempt->id to qtype. */
|
||||
protected $qtypes = array();
|
||||
/** @var array question_attempt->id to questionid. */
|
||||
protected $newquestionids = array();
|
||||
|
||||
/**
|
||||
* Attach below $element (usually attempts) the needed restore_path_elements
|
||||
* to restore question_usages and all they contain.
|
||||
* to restore question_states
|
||||
*/
|
||||
protected function add_question_usages($element, &$paths) {
|
||||
protected function add_question_attempts_states($element, &$paths) {
|
||||
// Check $element is restore_path_element
|
||||
if (! $element instanceof restore_path_element) {
|
||||
throw new restore_step_exception('element_must_be_restore_path_element', $element);
|
||||
@@ -2675,124 +2598,70 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
if (!is_array($paths)) {
|
||||
throw new restore_step_exception('paths_must_be_array', $paths);
|
||||
}
|
||||
$paths[] = new restore_path_element('question_usage',
|
||||
$element->get_path() . '/question_usage');
|
||||
$paths[] = new restore_path_element('question_attempt',
|
||||
$element->get_path() . '/question_usage/question_attempts/question_attempt');
|
||||
$paths[] = new restore_path_element('question_attempt_step',
|
||||
$element->get_path() . '/question_usage/question_attempts/question_attempt/steps/step',
|
||||
true);
|
||||
$paths[] = new restore_path_element('question_attempt_step_data',
|
||||
$element->get_path() . '/question_usage/question_attempts/question_attempt/steps/step/response/variable');
|
||||
$paths[] = new restore_path_element('question_state', $element->get_path() . '/states/state');
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_usages
|
||||
* Attach below $element (usually attempts) the needed restore_path_elements
|
||||
* to restore question_sessions
|
||||
*/
|
||||
protected function process_question_usage($data) {
|
||||
global $DB;
|
||||
|
||||
// Clear our caches.
|
||||
$this->qtypes = array();
|
||||
$this->newquestionids = array();
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
$oldcontextid = $this->get_task()->get_old_contextid();
|
||||
$data->contextid = $this->get_mappingid('context', $this->task->get_old_contextid());
|
||||
|
||||
// Everything ready, insert (no mapping needed)
|
||||
$newitemid = $DB->insert_record('question_usages', $data);
|
||||
|
||||
$this->inform_new_usage_id($newitemid);
|
||||
|
||||
$this->set_mapping('question_usage', $oldid, $newitemid, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* When process_question_usage creates the new usage, it calls this method
|
||||
* to let the activity link to the new usage. For example, the quiz uses
|
||||
* this method to set quiz_attempts.uniqueid to the new usage id.
|
||||
* @param integer $newusageid
|
||||
*/
|
||||
abstract protected function inform_new_usage_id($newusageid);
|
||||
|
||||
/**
|
||||
* Process question_attempts
|
||||
*/
|
||||
protected function process_question_attempt($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
$question = $this->get_mapping('question', $data->questionid);
|
||||
|
||||
$data->questionusageid = $this->get_new_parentid('question_usage');
|
||||
$data->questionid = $question->newitemid;
|
||||
$data->timemodified = $this->apply_date_offset($data->timemodified);
|
||||
|
||||
$newitemid = $DB->insert_record('question_attempts', $data);
|
||||
|
||||
$this->set_mapping('question_attempt', $oldid, $newitemid);
|
||||
$this->qtypes[$newitemid] = $question->info->qtype;
|
||||
$this->newquestionids[$newitemid] = $data->questionid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process question_attempt_steps
|
||||
*/
|
||||
protected function process_question_attempt_step($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Pull out the response data.
|
||||
$response = array();
|
||||
if (!empty($data->response['variable'])) {
|
||||
foreach ($data->response['variable'] as $variable) {
|
||||
$response[$variable['name']] = $variable['value'];
|
||||
}
|
||||
protected function add_question_attempts_sessions($element, &$paths) {
|
||||
// Check $element is restore_path_element
|
||||
if (! $element instanceof restore_path_element) {
|
||||
throw new restore_step_exception('element_must_be_restore_path_element', $element);
|
||||
}
|
||||
unset($data->response);
|
||||
// Check $paths is one array
|
||||
if (!is_array($paths)) {
|
||||
throw new restore_step_exception('paths_must_be_array', $paths);
|
||||
}
|
||||
$paths[] = new restore_path_element('question_session', $element->get_path() . '/sessions/session');
|
||||
}
|
||||
|
||||
$data->questionattemptid = $this->get_new_parentid('question_attempt');
|
||||
$data->timecreated = $this->apply_date_offset($data->timecreated);
|
||||
$data->userid = $this->get_mappingid('user', $data->userid);
|
||||
/**
|
||||
* Process question_states
|
||||
*/
|
||||
protected function process_question_state($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// Get complete question mapping, we'll need info
|
||||
$question = $this->get_mapping('question', $data->question);
|
||||
|
||||
// In the quiz_attempt mapping we are storing uniqueid
|
||||
// and not id, so this gets the correct question_attempt to point to
|
||||
$data->attempt = $this->get_new_parentid('quiz_attempt');
|
||||
$data->question = $question->newitemid;
|
||||
$data->answer = $this->restore_recode_answer($data, $question->info->qtype); // Delegate recoding of answer
|
||||
$data->timestamp= $this->apply_date_offset($data->timestamp);
|
||||
|
||||
// Everything ready, insert and create mapping (needed by question_sessions)
|
||||
$newitemid = $DB->insert_record('question_attempt_steps', $data);
|
||||
$this->set_mapping('question_attempt_step', $oldid, $newitemid, true);
|
||||
|
||||
// Now process the response data.
|
||||
$response = $this->questions_recode_response_data(
|
||||
$this->qtypes[$data->questionattemptid],
|
||||
$this->newquestionids[$data->questionattemptid],
|
||||
$data->sequencenumber, $response);
|
||||
foreach ($response as $name => $value) {
|
||||
$row = new stdClass();
|
||||
$row->attemptstepid = $newitemid;
|
||||
$row->name = $name;
|
||||
$row->value = $value;
|
||||
$DB->insert_record('question_attempt_step_data', $row, false);
|
||||
}
|
||||
$newitemid = $DB->insert_record('question_states', $data);
|
||||
$this->set_mapping('question_state', $oldid, $newitemid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recode the respones data for a particular step of an attempt at at particular question.
|
||||
* @param string $qtype the question type.
|
||||
* @param int $newquestionid the question id.
|
||||
* @param int $sequencenumber the sequence number.
|
||||
* @param array $response the response data to recode.
|
||||
* Process question_sessions
|
||||
*/
|
||||
public function questions_recode_response_data(
|
||||
$qtype, $newquestionid, $sequencenumber, array $response) {
|
||||
$qtyperestorer = $this->get_qtype_restorer($qtype);
|
||||
if ($qtyperestorer) {
|
||||
$response = $qtyperestorer->recode_response($newquestionid, $sequencenumber, $response);
|
||||
}
|
||||
return $response;
|
||||
protected function process_question_session($data) {
|
||||
global $DB;
|
||||
|
||||
$data = (object)$data;
|
||||
$oldid = $data->id;
|
||||
|
||||
// In the quiz_attempt mapping we are storing uniqueid
|
||||
// and not id, so this gets the correct question_attempt to point to
|
||||
$data->attemptid = $this->get_new_parentid('quiz_attempt');
|
||||
$data->questionid = $this->get_mappingid('question', $data->questionid);
|
||||
$data->newest = $this->get_mappingid('question_state', $data->newest);
|
||||
$data->newgraded = $this->get_mappingid('question_state', $data->newgraded);
|
||||
|
||||
// Everything ready, insert (no mapping needed)
|
||||
$newitemid = $DB->insert_record('question_sessions', $data);
|
||||
|
||||
// Note: question_sessions haven't files associated. On purpose manualcomment is lacking
|
||||
// support for them, so we don't need to handle them here.
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2815,195 +2684,25 @@ abstract class restore_questions_activity_structure_step extends restore_activit
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restore_qtype_plugin subclass for a specific question type.
|
||||
* @param string $qtype e.g. multichoice.
|
||||
* @return restore_qtype_plugin instance.
|
||||
* Given one question_states record, return the answer
|
||||
* recoded pointing to all the restored stuff
|
||||
*/
|
||||
protected function get_qtype_restorer($qtype) {
|
||||
public function restore_recode_answer($state, $qtype) {
|
||||
// Build one static cache to store {@link restore_qtype_plugin}
|
||||
// while we are needing them, just to save zillions of instantiations
|
||||
// or using static stuff that will break our nice API
|
||||
static $qtypeplugins = array();
|
||||
|
||||
// If we haven't the corresponding restore_qtype_plugin for current qtype
|
||||
// instantiate it and add to cache
|
||||
if (!isset($qtypeplugins[$qtype])) {
|
||||
$classname = 'restore_qtype_' . $qtype . '_plugin';
|
||||
if (class_exists($classname)) {
|
||||
$qtypeplugins[$qtype] = new $classname('qtype', $qtype, $this);
|
||||
} else {
|
||||
$qtypeplugins[$qtype] = null;
|
||||
$qtypeplugins[$qtype] = false;
|
||||
}
|
||||
}
|
||||
return $qtypeplugins[$qtype];
|
||||
}
|
||||
|
||||
protected function after_execute() {
|
||||
parent::after_execute();
|
||||
|
||||
// Restore any files belonging to responses.
|
||||
foreach (question_engine::get_all_response_file_areas() as $filearea) {
|
||||
$this->add_related_files('question', $filearea, 'question_attempt_step');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach below $element (usually attempts) the needed restore_path_elements
|
||||
* to restore question attempt data from Moodle 2.0.
|
||||
*
|
||||
* When using this method, the parent element ($element) must be defined with
|
||||
* $grouped = true. Then, in that elements process method, you must call
|
||||
* {@link process_legacy_attempt_data()} with the groupded data. See, for
|
||||
* example, the usage of this method in {@link restore_quiz_activity_structure_step}.
|
||||
* @param restore_path_element $element the parent element. (E.g. a quiz attempt.)
|
||||
* @param array $paths the paths array that is being built to describe the
|
||||
* structure.
|
||||
*/
|
||||
protected function add_legacy_question_attempt_data($element, &$paths) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/question/engine/upgrade/upgradelib.php');
|
||||
|
||||
// Check $element is restore_path_element
|
||||
if (!($element instanceof restore_path_element)) {
|
||||
throw new restore_step_exception('element_must_be_restore_path_element', $element);
|
||||
}
|
||||
// Check $paths is one array
|
||||
if (!is_array($paths)) {
|
||||
throw new restore_step_exception('paths_must_be_array', $paths);
|
||||
}
|
||||
|
||||
$paths[] = new restore_path_element('question_state',
|
||||
$element->get_path() . '/states/state');
|
||||
$paths[] = new restore_path_element('question_session',
|
||||
$element->get_path() . '/sessions/session');
|
||||
}
|
||||
|
||||
protected function get_attempt_upgrader() {
|
||||
if (empty($this->attemptupgrader)) {
|
||||
$this->attemptupgrader = new question_engine_attempt_upgrader();
|
||||
$this->attemptupgrader->prepare_to_restore();
|
||||
}
|
||||
return $this->attemptupgrader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the attempt data defined by {@link add_legacy_question_attempt_data()}.
|
||||
* @param object $data contains all the grouped attempt data ot process.
|
||||
* @param pbject $quiz data about the activity the attempts belong to. Required
|
||||
* fields are (basically this only works for the quiz module):
|
||||
* oldquestions => list of question ids in this activity - using old ids.
|
||||
* preferredbehaviour => the behaviour to use for questionattempts.
|
||||
*/
|
||||
protected function process_legacy_quiz_attempt_data($data, $quiz) {
|
||||
global $DB;
|
||||
$upgrader = $this->get_attempt_upgrader();
|
||||
|
||||
$data = (object)$data;
|
||||
|
||||
$layout = explode(',', $data->layout);
|
||||
$newlayout = $layout;
|
||||
|
||||
// Convert each old question_session into a question_attempt.
|
||||
$qas = array();
|
||||
foreach (explode(',', $quiz->oldquestions) as $questionid) {
|
||||
if ($questionid == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newquestionid = $this->get_mappingid('question', $questionid);
|
||||
if (!$newquestionid) {
|
||||
throw new restore_step_exception('questionattemptreferstomissingquestion',
|
||||
$questionid, $questionid);
|
||||
}
|
||||
|
||||
$question = $upgrader->load_question($newquestionid, $quiz->id);
|
||||
|
||||
foreach ($layout as $key => $qid) {
|
||||
if ($qid == $questionid) {
|
||||
$newlayout[$key] = $newquestionid;
|
||||
}
|
||||
}
|
||||
|
||||
list($qsession, $qstates) = $this->find_question_session_and_states(
|
||||
$data, $questionid);
|
||||
|
||||
if (empty($qsession) || empty($qstates)) {
|
||||
throw new restore_step_exception('questionattemptdatamissing',
|
||||
$questionid, $questionid);
|
||||
}
|
||||
|
||||
list($qsession, $qstates) = $this->recode_legacy_response_data(
|
||||
$question, $qsession, $qstates);
|
||||
|
||||
$data->layout = implode(',', $newlayout);
|
||||
$qas[$newquestionid] = $upgrader->convert_question_attempt(
|
||||
$quiz, $data, $question, $qsession, $qstates);
|
||||
}
|
||||
|
||||
// Now create a new question_usage.
|
||||
$usage = new stdClass();
|
||||
$usage->component = 'mod_quiz';
|
||||
$usage->contextid = $this->get_mappingid('context', $this->task->get_old_contextid());
|
||||
$usage->preferredbehaviour = $quiz->preferredbehaviour;
|
||||
$usage->id = $DB->insert_record('question_usages', $usage);
|
||||
|
||||
$this->inform_new_usage_id($usage->id);
|
||||
|
||||
$data->uniqueid = $usage->id;
|
||||
$upgrader->save_usage($quiz->preferredbehaviour, $data, $qas, $quiz->questions);
|
||||
}
|
||||
|
||||
protected function find_question_session_and_states($data, $questionid) {
|
||||
$qsession = null;
|
||||
foreach ($data->sessions['session'] as $session) {
|
||||
if ($session['questionid'] == $questionid) {
|
||||
$qsession = (object) $session;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$qstates = array();
|
||||
foreach ($data->states['state'] as $state) {
|
||||
if ($state['question'] == $questionid) {
|
||||
// It would be natural to use $state['seq_number'] as the array-key
|
||||
// here, but it seems that buggy behaviour in 2.0 and early can
|
||||
// mean that that is not unique, so we use id, which is guaranteed
|
||||
// to be unique.
|
||||
$qstates[$state['id']] = (object) $state;
|
||||
}
|
||||
}
|
||||
ksort($qstates);
|
||||
$qstates = array_values($qstates);
|
||||
|
||||
return array($qsession, $qstates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recode any ids in the response data
|
||||
* @param object $question the question data
|
||||
* @param object $qsession the question sessions.
|
||||
* @param array $qstates the question states.
|
||||
*/
|
||||
protected function recode_legacy_response_data($question, $qsession, $qstates) {
|
||||
$qsession->questionid = $question->id;
|
||||
|
||||
foreach ($qstates as &$state) {
|
||||
$state->question = $question->id;
|
||||
$state->answer = $this->restore_recode_legacy_answer($state, $question->qtype);
|
||||
}
|
||||
|
||||
return array($qsession, $qstates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recode the legacy answer field.
|
||||
* @param object $state the state to recode the answer of.
|
||||
* @param string $qtype the question type.
|
||||
*/
|
||||
public function restore_recode_legacy_answer($state, $qtype) {
|
||||
$restorer = $this->get_qtype_restorer($qtype);
|
||||
if ($restorer) {
|
||||
return $restorer->recode_legacy_state_answer($state);
|
||||
} else {
|
||||
return $state->answer;
|
||||
}
|
||||
return !empty($qtypeplugins[$qtype]) ? $qtypeplugins[$qtype]->recode_state_answer($state) : $state->answer;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-7
@@ -5,7 +5,7 @@ require_once('../config.php');
|
||||
require_once($CFG->dirroot . '/backup/util/includes/restore_includes.php');
|
||||
|
||||
$contextid = required_param('contextid', PARAM_INT);
|
||||
$stage = optional_param('stage', restore_ui::STAGE_CONFIRM, PARAM_INT);
|
||||
$stage = optional_param('stage', restore_ui::STAGE_CONFIRM, PARAM_INT);
|
||||
|
||||
list($context, $course, $cm) = get_context_info_array($contextid);
|
||||
|
||||
@@ -30,15 +30,9 @@ if ($stage & restore_ui::STAGE_CONFIRM + restore_ui::STAGE_DESTINATION) {
|
||||
}
|
||||
}
|
||||
if ($rc) {
|
||||
// check if the format conversion must happen first
|
||||
if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
|
||||
$rc->convert();
|
||||
}
|
||||
|
||||
$restore = new restore_ui($rc, array('contextid'=>$context->id));
|
||||
}
|
||||
}
|
||||
|
||||
$outcome = $restore->process();
|
||||
if (!$restore->is_independent()) {
|
||||
if ($restore->get_stage() == restore_ui::STAGE_PROCESS && !$restore->requires_substage()) {
|
||||
|
||||
@@ -102,45 +102,31 @@ abstract class backup_check {
|
||||
// Note: all the checks along the function MUST be performed for $userid, that
|
||||
// is the user who "requested" the course backup, not current $USER at all!!
|
||||
|
||||
// First of all, check the main backup[course|section|activity] principal caps
|
||||
// Lacking the corresponding one makes this to break with exception always
|
||||
// First of all, decide which caps/contexts are we going to check
|
||||
// for common backups (general, automated...) based exclusively
|
||||
// in the type (course, section, activity). And store them into
|
||||
// one capability => context array structure
|
||||
$typecapstocheck = array();
|
||||
switch ($type) {
|
||||
case backup::TYPE_1COURSE :
|
||||
$DB->get_record('course', array('id' => $id), '*', MUST_EXIST); // course exists
|
||||
if (!has_capability('moodle/backup:backupcourse', $coursectx, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = 'moodle/backup:backupcourse';
|
||||
throw new backup_controller_exception('backup_user_missing_capability', $a);
|
||||
}
|
||||
$typecapstocheck['moodle/backup:backupcourse'] = $coursectx;
|
||||
break;
|
||||
case backup::TYPE_1SECTION :
|
||||
$DB->get_record('course_sections', array('course' => $courseid, 'id' => $id), '*', MUST_EXIST); // sec exists
|
||||
if (!has_capability('moodle/backup:backupsection', $coursectx, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = 'moodle/backup:backupsection';
|
||||
throw new backup_controller_exception('backup_user_missing_capability', $a);
|
||||
}
|
||||
$typecapstocheck['moodle/backup:backupsection'] = $coursectx;
|
||||
break;
|
||||
case backup::TYPE_1ACTIVITY :
|
||||
get_coursemodule_from_id(null, $id, $courseid, false, MUST_EXIST); // cm exists
|
||||
$modulectx = get_context_instance(CONTEXT_MODULE, $id);
|
||||
if (!has_capability('moodle/backup:backupactivity', $modulectx, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->cmid = $id;
|
||||
$a->capability = 'moodle/backup:backupactivity';
|
||||
throw new backup_controller_exception('backup_user_missing_capability', $a);
|
||||
}
|
||||
$typecapstocheck['moodle/backup:backupactivity'] = $modulectx;
|
||||
break;
|
||||
default :
|
||||
print_error('unknownbackuptype');
|
||||
throw new backup_controller_exception('backup_unknown_backup_type', $type);
|
||||
}
|
||||
|
||||
// Now, if backup mode is hub or import, check userid has permissions for those modes
|
||||
// other modes will perform common checks only (backupxxxx capabilities in $typecapstocheck)
|
||||
switch ($mode) {
|
||||
case backup::MODE_HUB:
|
||||
if (!has_capability('moodle/backup:backuptargethub', $coursectx, $userid)) {
|
||||
@@ -160,6 +146,18 @@ abstract class backup_check {
|
||||
throw new backup_controller_exception('backup_user_missing_capability', $a);
|
||||
}
|
||||
break;
|
||||
// Common backup (general, automated...), let's check all the $typecapstocheck
|
||||
// capability => context pairs
|
||||
default:
|
||||
foreach ($typecapstocheck as $capability => $context) {
|
||||
if (!has_capability($capability, $context, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = $capability;
|
||||
throw new backup_controller_exception('backup_user_missing_capability', $a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, enforce 'moodle/backup:userinfo' to 'users' setting, applying changes if allowed,
|
||||
@@ -219,15 +217,19 @@ abstract class backup_check {
|
||||
}
|
||||
|
||||
// Check the user has the ability to configure the backup. If not then we need
|
||||
// to lock all settings by permission so that no changes can be made.
|
||||
$hasconfigcap = has_capability('moodle/backup:configure', $coursectx, $userid);
|
||||
if (!$hasconfigcap) {
|
||||
$settings = $backup_controller->get_plan()->get_settings();
|
||||
foreach ($settings as $setting) {
|
||||
if ($setting->get_name()=='filename') {
|
||||
continue;
|
||||
// to lock all settings by permission so that no changes can be made. This does
|
||||
// not apply to the import facility, where the activities must be always enabled
|
||||
// to be able to pick them
|
||||
if ($mode != backup::MODE_IMPORT) {
|
||||
$hasconfigcap = has_capability('moodle/backup:configure', $coursectx, $userid);
|
||||
if (!$hasconfigcap) {
|
||||
$settings = $backup_controller->get_plan()->get_settings();
|
||||
foreach ($settings as $setting) {
|
||||
if ($setting->get_name() == 'filename') {
|
||||
continue;
|
||||
}
|
||||
$setting->set_status(base_setting::LOCKED_BY_PERMISSION);
|
||||
}
|
||||
$setting->set_status(base_setting::LOCKED_BY_PERMISSION);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,41 +68,27 @@ abstract class restore_check {
|
||||
// Note: all the checks along the function MUST be performed for $userid, that
|
||||
// is the user who "requested" the course restore, not current $USER at all!!
|
||||
|
||||
// First of all, check the main restore[course|section|activity] principal caps
|
||||
// Lacking the corresponding one makes this to break with exception always
|
||||
// First of all, decide which caps/contexts are we going to check
|
||||
// for common backups (general, automated...) based exclusively
|
||||
// in the type (course, section, activity). And store them into
|
||||
// one capability => context array structure
|
||||
$typecapstocheck = array();
|
||||
switch ($type) {
|
||||
case backup::TYPE_1COURSE :
|
||||
if (!has_capability('moodle/restore:restorecourse', $coursectx, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = 'moodle/restore:restorecourse';
|
||||
throw new restore_controller_exception('restore_user_missing_capability', $a);
|
||||
}
|
||||
$typecapstocheck['moodle/restore:restorecourse'] = $coursectx;
|
||||
break;
|
||||
case backup::TYPE_1SECTION :
|
||||
if (!has_capability('moodle/restore:restoresection', $coursectx, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = 'moodle/restore:restoresection';
|
||||
throw new restore_controller_exception('restore_user_missing_capability', $a);
|
||||
}
|
||||
$typecapstocheck['moodle/restore:restoresection'] = $coursectx;
|
||||
break;
|
||||
case backup::TYPE_1ACTIVITY :
|
||||
if (!has_capability('moodle/restore:restoreactivity', $coursectx, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = 'moodle/restore:restoreactivity';
|
||||
throw new restore_controller_exception('restore_user_missing_capability', $a);
|
||||
}
|
||||
$typecapstocheck['moodle/restore:restoreactivity'] = $coursectx;
|
||||
break;
|
||||
default :
|
||||
print_error('unknownrestoretype');
|
||||
throw new restore_controller_exception('restore_unknown_restore_type', $type);
|
||||
}
|
||||
|
||||
// Now, if restore mode is hub or import, check userid has permissions for those modes
|
||||
// other modes will perform common checks only (restorexxxx capabilities in $typecapstocheck)
|
||||
switch ($mode) {
|
||||
case backup::MODE_HUB:
|
||||
if (!has_capability('moodle/restore:restoretargethub', $coursectx, $userid)) {
|
||||
@@ -122,6 +108,18 @@ abstract class restore_check {
|
||||
throw new restore_controller_exception('restore_user_missing_capability', $a);
|
||||
}
|
||||
break;
|
||||
// Common backup (general, automated...), let's check all the $typecapstocheck
|
||||
// capability => context pairs
|
||||
default:
|
||||
foreach ($typecapstocheck as $capability => $context) {
|
||||
if (!has_capability($capability, $context, $userid)) {
|
||||
$a = new stdclass();
|
||||
$a->userid = $userid;
|
||||
$a->courseid = $courseid;
|
||||
$a->capability = $capability;
|
||||
throw new restore_controller_exception('restore_user_missing_capability', $a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now, enforce 'moodle/restore:userinfo' to 'users' setting, applying changes if allowed,
|
||||
@@ -158,12 +156,16 @@ abstract class restore_check {
|
||||
}
|
||||
|
||||
// Check the user has the ability to configure the restore. If not then we need
|
||||
// to lock all settings by permission so that no changes can be made.
|
||||
$hasconfigcap = has_capability('moodle/restore:configure', $coursectx, $userid);
|
||||
if (!$hasconfigcap) {
|
||||
$settings = $restore_controller->get_plan()->get_settings();
|
||||
foreach ($settings as $setting) {
|
||||
$setting->set_status(base_setting::LOCKED_BY_PERMISSION);
|
||||
// to lock all settings by permission so that no changes can be made. This does
|
||||
// not apply to the import facility, where all the activities (picked on backup)
|
||||
// are restored automatically without restore UI
|
||||
if ($mode != backup::MODE_IMPORT) {
|
||||
$hasconfigcap = has_capability('moodle/restore:configure', $coursectx, $userid);
|
||||
if (!$hasconfigcap) {
|
||||
$settings = $restore_controller->get_plan()->get_settings();
|
||||
foreach ($settings as $setting) {
|
||||
$setting->set_status(base_setting::LOCKED_BY_PERMISSION);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -401,12 +401,40 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
return $DB->get_record('course', array('id' => $courseid), 'fullname, shortname, startdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default values for the settings in a backup operation
|
||||
*
|
||||
* Based on the mode of the backup it will delegate the process to
|
||||
* other methods like {@link apply_general_config_defaults} ...
|
||||
* to get proper defaults loaded
|
||||
*
|
||||
* @param backup_controller $controller
|
||||
*/
|
||||
public static function apply_config_defaults(backup_controller $controller) {
|
||||
// Based on the mode of the backup (general, automated, import, hub...)
|
||||
// decide the action to perform to get defaults loaded
|
||||
$mode = $controller->get_mode();
|
||||
|
||||
switch ($mode) {
|
||||
case backup::MODE_GENERAL:
|
||||
// Load the general defaults
|
||||
self::apply_general_config_defaults($controller);
|
||||
break;
|
||||
case backup::MODE_AUTOMATED:
|
||||
// TODO: Move the loading from automatic stuff to here
|
||||
break;
|
||||
default:
|
||||
// Nothing to do for other modes (IMPORT/HUB...). Some day we
|
||||
// can define defaults (admin UI...) for them if we want to
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller settings default values from the backup config.
|
||||
*
|
||||
* @param backup_controller $controller
|
||||
*/
|
||||
public static function apply_general_config_defaults(backup_controller $controller) {
|
||||
private static function apply_general_config_defaults(backup_controller $controller) {
|
||||
$settings = array(
|
||||
// Config name => Setting name
|
||||
'backup_general_users' => 'users',
|
||||
|
||||
@@ -1,60 +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/>.
|
||||
|
||||
/**
|
||||
* @package core
|
||||
* @subpackage backup-convert
|
||||
* @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Factory class to create new instances of backup converters
|
||||
*/
|
||||
abstract class convert_factory {
|
||||
|
||||
/**
|
||||
* Instantinates the given converter operating on a given directory
|
||||
*
|
||||
* @throws coding_exception
|
||||
* @param $name The converter name
|
||||
* @param $tempdir The temp directory to operate on
|
||||
* @param base_logger|null if the conversion should be logged, use this logger
|
||||
* @return base_converter
|
||||
*/
|
||||
public static function get_converter($name, $tempdir, $logger = null) {
|
||||
global $CFG;
|
||||
|
||||
$name = clean_param($name, PARAM_SAFEDIR);
|
||||
|
||||
$classfile = "$CFG->dirroot/backup/converter/$name/lib.php";
|
||||
$classname = "{$name}_converter";
|
||||
|
||||
if (!file_exists($classfile)) {
|
||||
throw new coding_exception("Converter factory error: class file not found $classfile");
|
||||
}
|
||||
require_once($classfile);
|
||||
|
||||
if (!class_exists($classname)) {
|
||||
throw new coding_exception("Converter factory error: class not found $classname");
|
||||
}
|
||||
|
||||
return new $classname($tempdir, $logger);
|
||||
}
|
||||
}
|
||||
@@ -123,14 +123,24 @@ abstract class backup_cron_automated_helper {
|
||||
$backupcourse = $DB->get_record('backup_courses', array('courseid'=>$course->id));
|
||||
}
|
||||
|
||||
// Skip courses that do not yet need backup
|
||||
$skipped = !(($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY);
|
||||
// Skip backup of unavailable courses that have remained unmodified in a month
|
||||
$skipped = false;
|
||||
if (empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) { //Hidden + unmodified last month
|
||||
$backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
|
||||
$DB->update_record('backup_courses', $backupcourse);
|
||||
mtrace('Skipping unchanged course '.$course->fullname);
|
||||
$skipped = true;
|
||||
} else if (($backupcourse->nextstarttime >= 0 && $backupcourse->nextstarttime < $now) || $rundirective == self::RUN_IMMEDIATELY) {
|
||||
if (!$skipped && empty($course->visible) && ($now - $course->timemodified) > 31*24*60*60) { //Hidden + settings were unmodified last month
|
||||
//Check log if there were any modifications to the course content
|
||||
$sqlwhere = "course=:courseid AND time>:time AND ". $DB->sql_like('action', ':action', false, true, true);
|
||||
$params = array('courseid' => $course->id, 'time' => $now-31*24*60*60, 'action' => '%view%');
|
||||
$logexists = $DB->record_exists_select('log', $sqlwhere, $params);
|
||||
if (!$logexists) {
|
||||
$backupcourse->laststatus = backup_cron_automated_helper::BACKUP_STATUS_SKIPPED;
|
||||
$backupcourse->nextstarttime = $nextstarttime;
|
||||
$DB->update_record('backup_courses', $backupcourse);
|
||||
mtrace('Skipping unchanged course '.$course->fullname);
|
||||
$skipped = true;
|
||||
}
|
||||
}
|
||||
//Now we backup every non-skipped course
|
||||
if (!$skipped) {
|
||||
mtrace('Backing up '.$course->fullname, '...');
|
||||
|
||||
//We have to send a email because we have included at least one backup
|
||||
@@ -312,7 +322,7 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
$settings = array(
|
||||
'users' => 'backup_auto_users',
|
||||
'role_assignments' => 'backup_auto_users',
|
||||
'role_assignments' => 'backup_auto_role_assignments',
|
||||
'user_files' => 'backup_auto_user_files',
|
||||
'activities' => 'backup_auto_activities',
|
||||
'blocks' => 'backup_auto_blocks',
|
||||
|
||||
@@ -214,10 +214,8 @@ abstract class backup_general_helper extends backup_helper {
|
||||
* generated or no. Behavior of various parts of restore are
|
||||
* dependent of this.
|
||||
*
|
||||
* Backups created natively in 2.0 and later declare the hashed
|
||||
* site identifier. Backups created by conversion from a 1.9
|
||||
* backup do not declare such identifier, so there is a fallback
|
||||
* to wwwroot comparison. See MDL-16614.
|
||||
* Use site_identifier (hashed) and fallback to wwwroot, thought
|
||||
* any 2.0 backup should have the former. See MDL-16614
|
||||
*/
|
||||
public static function backup_is_samesite($info) {
|
||||
global $CFG;
|
||||
@@ -230,34 +228,50 @@ abstract class backup_general_helper extends backup_helper {
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects the format of the given unpacked backup directory
|
||||
* Given one temp/backup/xxx dir, detect its format
|
||||
*
|
||||
* @param string $tempdir the name of the backup directory
|
||||
* @return string one of backup::FORMAT_xxx constants
|
||||
* TODO: Move harcoded detection here to delegated classes under backup/format (moodle1, imscc..)
|
||||
* conversion code will be there too.
|
||||
*/
|
||||
public static function detect_backup_format($tempdir) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');
|
||||
$filepath = $CFG->dataroot . '/temp/backup/' . $tempdir . '/moodle_backup.xml';
|
||||
|
||||
if (convert_helper::detect_moodle2_format($tempdir)) {
|
||||
return backup::FORMAT_MOODLE;
|
||||
// Does tempdir exist and is dir
|
||||
if (!is_dir(dirname($filepath))) {
|
||||
throw new backup_helper_exception('tmp_backup_directory_not_found', dirname($filepath));
|
||||
}
|
||||
|
||||
// see if a converter can identify the format
|
||||
$converters = convert_helper::available_converters();
|
||||
foreach ($converters as $name) {
|
||||
$classname = "{$name}_converter";
|
||||
if (!class_exists($classname)) {
|
||||
throw new coding_exception("available_converters() is supposed to load
|
||||
converter classes but class $classname not found");
|
||||
}
|
||||
|
||||
$detected = call_user_func($classname .'::detect_format', $tempdir);
|
||||
if (!empty($detected)) {
|
||||
return $detected;
|
||||
// First look for MOODLE (moodle2) format
|
||||
if (file_exists($filepath)) { // Looks promising, lets load some information
|
||||
$handle = fopen ($filepath, "r");
|
||||
$first_chars = fread($handle,200);
|
||||
$status = fclose ($handle);
|
||||
// Check if it has the required strings
|
||||
if (strpos($first_chars,'<?xml version="1.0" encoding="UTF-8"?>') !== false &&
|
||||
strpos($first_chars,'<moodle_backup>') !== false &&
|
||||
strpos($first_chars,'<information>') !== false) {
|
||||
return backup::FORMAT_MOODLE;
|
||||
}
|
||||
}
|
||||
|
||||
// Then look for MOODLE1 (moodle1) format
|
||||
$filepath = $CFG->dataroot . '/temp/backup/' . $tempdir . '/moodle.xml';
|
||||
if (file_exists($filepath)) { // Looks promising, lets load some information
|
||||
$handle = fopen ($filepath, "r");
|
||||
$first_chars = fread($handle,200);
|
||||
$status = fclose ($handle);
|
||||
// Check if it has the required strings
|
||||
if (strpos($first_chars,'<?xml version="1.0" encoding="UTF-8"?>') !== false &&
|
||||
strpos($first_chars,'<MOODLE_BACKUP>') !== false &&
|
||||
strpos($first_chars,'<INFO>') !== false) {
|
||||
return backup::FORMAT_MOODLE1;
|
||||
}
|
||||
}
|
||||
|
||||
// Other formats
|
||||
|
||||
// Arrived here, unknown format
|
||||
return backup::FORMAT_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,340 +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/>.
|
||||
|
||||
/**
|
||||
* Provides {@link convert_helper} and {@link convert_helper_exception} classes
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup-convert
|
||||
* @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/backup/util/includes/convert_includes.php');
|
||||
|
||||
/**
|
||||
* Provides various functionality via its static methods
|
||||
*/
|
||||
abstract class convert_helper {
|
||||
|
||||
/**
|
||||
* @param string $entropy
|
||||
* @return string random identifier
|
||||
*/
|
||||
public static function generate_id($entropy) {
|
||||
return md5(time() . '-' . $entropy . '-' . random_string(20));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of all available converters and loads their classes
|
||||
*
|
||||
* Converter must be installed as a directory in backup/converter/ and its
|
||||
* method is_available() must return true to get to the list.
|
||||
*
|
||||
* @see base_converter::is_available()
|
||||
* @return array of strings
|
||||
*/
|
||||
public static function available_converters() {
|
||||
global $CFG;
|
||||
|
||||
$converters = array();
|
||||
$plugins = get_list_of_plugins('backup/converter');
|
||||
foreach ($plugins as $name) {
|
||||
$classfile = "$CFG->dirroot/backup/converter/$name/lib.php";
|
||||
$classname = "{$name}_converter";
|
||||
|
||||
if (!file_exists($classfile)) {
|
||||
throw new convert_helper_exception('converter_classfile_not_found', $classfile);
|
||||
}
|
||||
require_once($classfile);
|
||||
|
||||
if (!class_exists($classname)) {
|
||||
throw new convert_helper_exception('converter_classname_not_found', $classname);
|
||||
}
|
||||
|
||||
if (call_user_func($classname .'::is_available')) {
|
||||
$converters[] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
return $converters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects if the given folder contains an unpacked moodle2 backup
|
||||
*
|
||||
* @param string $tempdir the name of the backup directory
|
||||
* @return boolean true if moodle2 format detected, false otherwise
|
||||
*/
|
||||
public static function detect_moodle2_format($tempdir) {
|
||||
global $CFG;
|
||||
|
||||
$dirpath = $CFG->dataroot . '/temp/backup/' . $tempdir;
|
||||
$filepath = $dirpath . '/moodle_backup.xml';
|
||||
|
||||
if (!is_dir($dirpath)) {
|
||||
throw new convert_helper_exception('tmp_backup_directory_not_found', $dirpath);
|
||||
}
|
||||
|
||||
if (!file_exists($filepath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$handle = fopen($filepath, 'r');
|
||||
$firstchars = fread($handle, 200);
|
||||
$status = fclose($handle);
|
||||
|
||||
if (strpos($firstchars,'<?xml version="1.0" encoding="UTF-8"?>') !== false and
|
||||
strpos($firstchars,'<moodle_backup>') !== false and
|
||||
strpos($firstchars,'<information>') !== false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given directory with the backup into moodle2 format
|
||||
*
|
||||
* @param string $tempdir The directory to convert
|
||||
* @param string $format The current format, if already detected
|
||||
* @param base_logger|null if the conversion should be logged, use this logger
|
||||
* @throws convert_helper_exception
|
||||
* @return bool false if unable to find the conversion path, true otherwise
|
||||
*/
|
||||
public static function to_moodle2_format($tempdir, $format = null, $logger = null) {
|
||||
|
||||
if (is_null($format)) {
|
||||
$format = backup_general_helper::detect_backup_format($tempdir);
|
||||
}
|
||||
|
||||
// get the supported conversion paths from all available converters
|
||||
$converters = self::available_converters();
|
||||
$descriptions = array();
|
||||
foreach ($converters as $name) {
|
||||
$classname = "{$name}_converter";
|
||||
if (!class_exists($classname)) {
|
||||
throw new convert_helper_exception('class_not_loaded', $classname);
|
||||
}
|
||||
if ($logger instanceof base_logger) {
|
||||
backup_helper::log('available converter', backup::LOG_DEBUG, $classname, 1, false, $logger);
|
||||
}
|
||||
$descriptions[$name] = call_user_func($classname .'::description');
|
||||
}
|
||||
|
||||
// choose the best conversion path for the given format
|
||||
$path = self::choose_conversion_path($format, $descriptions);
|
||||
|
||||
if (empty($path)) {
|
||||
if ($logger instanceof base_logger) {
|
||||
backup_helper::log('unable to find the conversion path', backup::LOG_ERROR, null, 0, false, $logger);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($logger instanceof base_logger) {
|
||||
backup_helper::log('conversion path established', backup::LOG_INFO,
|
||||
implode(' => ', array_merge($path, array('moodle2'))), 0, false, $logger);
|
||||
}
|
||||
|
||||
foreach ($path as $name) {
|
||||
if ($logger instanceof base_logger) {
|
||||
backup_helper::log('running converter', backup::LOG_INFO, $name, 0, false, $logger);
|
||||
}
|
||||
$converter = convert_factory::get_converter($name, $tempdir, $logger);
|
||||
$converter->convert();
|
||||
}
|
||||
|
||||
// make sure we ended with moodle2 format
|
||||
if (!self::detect_moodle2_format($tempdir)) {
|
||||
throw new convert_helper_exception('conversion_failed');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts an inforef into the conversion temp table
|
||||
*/
|
||||
public static function set_inforef($contextid) {
|
||||
global $DB;
|
||||
}
|
||||
|
||||
public static function get_inforef($contextid) {
|
||||
}
|
||||
|
||||
/// end of public API //////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Choose the best conversion path for the given format
|
||||
*
|
||||
* Given the source format and the list of available converters and their properties,
|
||||
* this methods picks the most effective way how to convert the source format into
|
||||
* the target moodle2 format. The method returns a list of converters that should be
|
||||
* called, in order.
|
||||
*
|
||||
* This implementation uses Dijkstra's algorithm to find the shortest way through
|
||||
* the oriented graph.
|
||||
*
|
||||
* @see http://en.wikipedia.org/wiki/Dijkstra's_algorithm
|
||||
* @author David Mudrak <david@moodle.com>
|
||||
* @param string $format the source backup format, one of backup::FORMAT_xxx
|
||||
* @param array $descriptions list of {@link base_converter::description()} indexed by the converter name
|
||||
* @return array ordered list of converter names to call (may be empty if not reachable)
|
||||
*/
|
||||
protected static function choose_conversion_path($format, array $descriptions) {
|
||||
|
||||
// construct an oriented graph of conversion paths. backup formats are nodes
|
||||
// and the the converters are edges of the graph.
|
||||
$paths = array(); // [fromnode][tonode] => converter
|
||||
foreach ($descriptions as $converter => $description) {
|
||||
$from = $description['from'];
|
||||
$to = $description['to'];
|
||||
$cost = $description['cost'];
|
||||
|
||||
if (is_null($from) or $from === backup::FORMAT_UNKNOWN or
|
||||
is_null($to) or $to === backup::FORMAT_UNKNOWN or
|
||||
is_null($cost) or $cost <= 0) {
|
||||
throw new convert_helper_exception('invalid_converter_description', $converter);
|
||||
}
|
||||
|
||||
if (!isset($paths[$from][$to])) {
|
||||
$paths[$from][$to] = $converter;
|
||||
} else {
|
||||
// if there are two converters available for the same conversion
|
||||
// path, choose the one with the lowest cost. if there are more
|
||||
// available converters with the same cost, the chosen one is
|
||||
// undefined (depends on the order of processing)
|
||||
if ($descriptions[$paths[$from][$to]]['cost'] > $cost) {
|
||||
$paths[$from][$to] = $converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($paths)) {
|
||||
// no conversion paths available
|
||||
return array();
|
||||
}
|
||||
|
||||
// now use Dijkstra's algorithm and find the shortest conversion path
|
||||
|
||||
$dist = array(); // list of nodes and their distances from the source format
|
||||
$prev = array(); // list of previous nodes in optimal path from the source format
|
||||
foreach ($paths as $fromnode => $tonodes) {
|
||||
$dist[$fromnode] = null; // infinitive distance, can't be reached
|
||||
$prev[$fromnode] = null; // unknown
|
||||
foreach ($tonodes as $tonode => $converter) {
|
||||
$dist[$tonode] = null; // infinitive distance, can't be reached
|
||||
$prev[$tonode] = null; // unknown
|
||||
}
|
||||
}
|
||||
|
||||
if (!array_key_exists($format, $dist)) {
|
||||
return array();
|
||||
} else {
|
||||
$dist[$format] = 0;
|
||||
}
|
||||
|
||||
$queue = array_flip(array_keys($dist));
|
||||
while (!empty($queue)) {
|
||||
// find the node with the smallest distance from the source in the queue
|
||||
// in the first iteration, this will find the original format node itself
|
||||
$closest = null;
|
||||
foreach ($queue as $node => $undefined) {
|
||||
if (is_null($dist[$node])) {
|
||||
continue;
|
||||
}
|
||||
if (is_null($closest) or ($dist[$node] < $dist[$closest])) {
|
||||
$closest = $node;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($closest) or is_null($dist[$closest])) {
|
||||
// all remaining nodes are inaccessible from source
|
||||
break;
|
||||
}
|
||||
|
||||
if ($closest === backup::FORMAT_MOODLE) {
|
||||
// bingo we can break now
|
||||
break;
|
||||
}
|
||||
|
||||
unset($queue[$closest]);
|
||||
|
||||
// visit all neighbors and update distances to them eventually
|
||||
|
||||
if (!isset($paths[$closest])) {
|
||||
continue;
|
||||
}
|
||||
$neighbors = array_keys($paths[$closest]);
|
||||
// keep just neighbors that are in the queue yet
|
||||
foreach ($neighbors as $ix => $neighbor) {
|
||||
if (!array_key_exists($neighbor, $queue)) {
|
||||
unset($neighbors[$ix]);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($neighbors as $neighbor) {
|
||||
// the alternative distance to the neighbor if we went thru the
|
||||
// current $closest node
|
||||
$alt = $dist[$closest] + $descriptions[$paths[$closest][$neighbor]]['cost'];
|
||||
|
||||
if (is_null($dist[$neighbor]) or $alt < $dist[$neighbor]) {
|
||||
// we found a shorter way to the $neighbor, remember it
|
||||
$dist[$neighbor] = $alt;
|
||||
$prev[$neighbor] = $closest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_null($dist[backup::FORMAT_MOODLE])) {
|
||||
// unable to find a conversion path, the target format not reachable
|
||||
return array();
|
||||
}
|
||||
|
||||
// reconstruct the optimal path from the source format to the target one
|
||||
$conversionpath = array();
|
||||
$target = backup::FORMAT_MOODLE;
|
||||
while (isset($prev[$target])) {
|
||||
array_unshift($conversionpath, $paths[$prev[$target]][$target]);
|
||||
$target = $prev[$target];
|
||||
}
|
||||
|
||||
return $conversionpath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* General convert_helper related exception
|
||||
*
|
||||
* @author David Mudrak <david@moodle.com>
|
||||
*/
|
||||
class convert_helper_exception extends moodle_exception {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $errorcode key for the corresponding error string
|
||||
* @param object $a extra words and phrases that might be required in the error string
|
||||
* @param string $debuginfo optional debugging information
|
||||
*/
|
||||
public function __construct($errorcode, $a = null, $debuginfo = null) {
|
||||
parent::__construct($errorcode, '', '', $a, $debuginfo);
|
||||
}
|
||||
}
|
||||
@@ -53,12 +53,4 @@ class restore_inforef_parser_processor extends grouped_parser_processor {
|
||||
$itemid = $data['tags']['id'];
|
||||
restore_dbops::set_backup_ids_record($this->restoreid, $itemname, $itemid);
|
||||
}
|
||||
|
||||
protected function notify_path_start($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected function notify_path_end($path) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,14 +51,6 @@ class restore_moodlexml_parser_processor extends grouped_parser_processor {
|
||||
$this->accumchunks[] = $data;
|
||||
}
|
||||
|
||||
protected function notify_path_start($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected function notify_path_end($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
public function get_all_chunks() {
|
||||
return $this->accumchunks;
|
||||
}
|
||||
|
||||
@@ -75,14 +75,6 @@ class restore_questions_parser_processor extends grouped_parser_processor {
|
||||
}
|
||||
}
|
||||
|
||||
protected function notify_path_start($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected function notify_path_end($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide NULL decoding
|
||||
*/
|
||||
|
||||
@@ -55,14 +55,6 @@ class restore_roles_parser_processor extends grouped_parser_processor {
|
||||
}
|
||||
}
|
||||
|
||||
protected function notify_path_start($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected function notify_path_end($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide NULL decoding
|
||||
*/
|
||||
|
||||
@@ -102,12 +102,4 @@ class restore_structure_parser_processor extends grouped_parser_processor {
|
||||
protected function dispatch_chunk($data) {
|
||||
$this->step->process($data);
|
||||
}
|
||||
|
||||
protected function notify_path_start($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected function notify_path_end($path) {
|
||||
// nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,14 +66,6 @@ class restore_users_parser_processor extends grouped_parser_processor {
|
||||
}
|
||||
}
|
||||
|
||||
protected function notify_path_start($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
protected function notify_path_end($path) {
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide NULL decoding
|
||||
*/
|
||||
|
||||
@@ -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/>.
|
||||
|
||||
/**
|
||||
* Unit tests for backup/util/helper/convert_helper.class.php
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup-convert
|
||||
* @copyright 2011 David Mudrak <david@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');
|
||||
|
||||
/**
|
||||
* Provides access to the protected methods we need to test
|
||||
*/
|
||||
class testable_convert_helper extends convert_helper {
|
||||
|
||||
public static function choose_conversion_path($format, array $descriptions) {
|
||||
return parent::choose_conversion_path($format, $descriptions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the test methods
|
||||
*/
|
||||
class convert_helper_test extends UnitTestCase {
|
||||
|
||||
public static $includecoverage = array();
|
||||
|
||||
public function test_choose_conversion_path() {
|
||||
|
||||
// no converters available
|
||||
$descriptions = array();
|
||||
$path = testable_convert_helper::choose_conversion_path(backup::FORMAT_MOODLE1, $descriptions);
|
||||
$this->assertEqual($path, array());
|
||||
|
||||
// missing source and/or targets
|
||||
$descriptions = array(
|
||||
// some custom converter
|
||||
'exporter' => array(
|
||||
'from' => backup::FORMAT_MOODLE1,
|
||||
'to' => 'some_custom_format',
|
||||
'cost' => 10,
|
||||
),
|
||||
// another custom converter
|
||||
'converter' => array(
|
||||
'from' => 'yet_another_crazy_custom_format',
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 10,
|
||||
),
|
||||
);
|
||||
$path = testable_convert_helper::choose_conversion_path(backup::FORMAT_MOODLE1, $descriptions);
|
||||
$this->assertEqual($path, array());
|
||||
|
||||
$path = testable_convert_helper::choose_conversion_path('some_other_custom_format', $descriptions);
|
||||
$this->assertEqual($path, array());
|
||||
|
||||
// single step conversion
|
||||
$path = testable_convert_helper::choose_conversion_path('yet_another_crazy_custom_format', $descriptions);
|
||||
$this->assertEqual($path, array('converter'));
|
||||
|
||||
// no conversion needed - this is supposed to be detected by the caller
|
||||
$path = testable_convert_helper::choose_conversion_path(backup::FORMAT_MOODLE, $descriptions);
|
||||
$this->assertEqual($path, array());
|
||||
|
||||
// two alternatives
|
||||
$descriptions = array(
|
||||
// standard moodle 1.9 -> 2.x converter
|
||||
'moodle1' => array(
|
||||
'from' => backup::FORMAT_MOODLE1,
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 10,
|
||||
),
|
||||
// alternative moodle 1.9 -> 2.x converter
|
||||
'alternative' => array(
|
||||
'from' => backup::FORMAT_MOODLE1,
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 8,
|
||||
)
|
||||
);
|
||||
$path = testable_convert_helper::choose_conversion_path(backup::FORMAT_MOODLE1, $descriptions);
|
||||
$this->assertEqual($path, array('alternative'));
|
||||
|
||||
// complex case
|
||||
$descriptions = array(
|
||||
// standard moodle 1.9 -> 2.x converter
|
||||
'moodle1' => array(
|
||||
'from' => backup::FORMAT_MOODLE1,
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 10,
|
||||
),
|
||||
// alternative moodle 1.9 -> 2.x converter
|
||||
'alternative' => array(
|
||||
'from' => backup::FORMAT_MOODLE1,
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 8,
|
||||
),
|
||||
// custom converter from 1.9 -> custom 'CFv1' format
|
||||
'cc1' => array(
|
||||
'from' => backup::FORMAT_MOODLE1,
|
||||
'to' => 'CFv1',
|
||||
'cost' => 2,
|
||||
),
|
||||
// custom converter from custom 'CFv1' format -> moodle 2.0 format
|
||||
'cc2' => array(
|
||||
'from' => 'CFv1',
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 5,
|
||||
),
|
||||
// custom converter from CFv1 -> CFv2 format
|
||||
'cc3' => array(
|
||||
'from' => 'CFv1',
|
||||
'to' => 'CFv2',
|
||||
'cost' => 2,
|
||||
),
|
||||
// custom converter from CFv2 -> moodle 2.0 format
|
||||
'cc4' => array(
|
||||
'from' => 'CFv2',
|
||||
'to' => backup::FORMAT_MOODLE,
|
||||
'cost' => 2,
|
||||
),
|
||||
);
|
||||
|
||||
// ask the helper to find the most effective way
|
||||
$path = testable_convert_helper::choose_conversion_path(backup::FORMAT_MOODLE1, $descriptions);
|
||||
$this->assertEqual($path, array('cc1', 'cc3', 'cc4'));
|
||||
}
|
||||
}
|
||||
@@ -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/>.
|
||||
|
||||
/**
|
||||
* Makes sure that all general code needed by backup-convert code is included
|
||||
*
|
||||
* @package core
|
||||
* @subpackage backup-convert
|
||||
* @copyright 2011 Mark Nielsen <mark@moodlerooms.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
require_once($CFG->dirroot . '/backup/util/interfaces/loggable.class.php'); // converters are loggable
|
||||
require_once($CFG->dirroot . '/backup/util/interfaces/checksumable.class.php'); // req by backup.class.php
|
||||
require_once($CFG->dirroot . '/backup/backup.class.php'); // provides backup::FORMAT_xxx constants
|
||||
require_once($CFG->dirroot . '/backup/util/helper/convert_helper.class.php');
|
||||
require_once($CFG->dirroot . '/backup/util/factories/convert_factory.class.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
@@ -140,14 +140,16 @@ abstract class base_ui {
|
||||
/**
|
||||
* Displays the UI for the backup!
|
||||
*
|
||||
* @throws base_ui_exception
|
||||
* @return string HTML code
|
||||
* Note: The UI makes use of mforms (ewww!) thus it will automatically print
|
||||
* out the result rather than returning a string of HTML like other parts of Moodle
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function display() {
|
||||
if ($this->progress < self::PROGRESS_SAVED) {
|
||||
throw new base_ui_exception('backupsavebeforedisplay');
|
||||
}
|
||||
return $this->stage->display();
|
||||
$this->stage->display();
|
||||
}
|
||||
/**
|
||||
* Gets all backup tasks from the controller
|
||||
@@ -304,4 +306,4 @@ abstract class base_ui {
|
||||
/**
|
||||
* Backup user interface exception. Modelled off the backup_exception class
|
||||
*/
|
||||
class base_ui_exception extends backup_exception {}
|
||||
class base_ui_exception extends backup_exception {}
|
||||
@@ -108,29 +108,17 @@ abstract class base_ui_stage {
|
||||
final public function get_uniqueid() {
|
||||
return $this->ui->get_uniqueid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the stage.
|
||||
*
|
||||
* By default this involves instantiating the form for the stage and the calling
|
||||
* it to display.
|
||||
*
|
||||
* @return string HTML code to display
|
||||
* it to display. Remember this is a moodleform instance so it will print
|
||||
* rather than return.
|
||||
*/
|
||||
public function display() {
|
||||
|
||||
$form = $this->initialise_stage_form();
|
||||
// a nasty hack follows to work around the sad fact that moodle quickforms
|
||||
// do not allow to actually return the HTML content, just to echo it
|
||||
flush();
|
||||
ob_start();
|
||||
$form->display();
|
||||
$output = ob_get_contents();
|
||||
ob_end_clean();
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the stage.
|
||||
*
|
||||
@@ -156,4 +144,4 @@ abstract class base_ui_stage {
|
||||
public function is_first_stage() {
|
||||
return $this->stage == 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -158,4 +158,13 @@ class import_ui_stage_final extends backup_ui_stage_final {}
|
||||
/**
|
||||
* Extends the restore course search to search for import courses.
|
||||
*/
|
||||
class import_course_search extends restore_course_search {}
|
||||
class import_course_search extends restore_course_search {
|
||||
/**
|
||||
* Sets up any access restrictions for the courses to be displayed in the search.
|
||||
*
|
||||
* This will typically call $this->require_capability().
|
||||
*/
|
||||
protected function setup_restrictions() {
|
||||
$this->require_capability('moodle/backup:backuptargetimport');
|
||||
}
|
||||
}
|
||||
|
||||
+22
-48
@@ -157,60 +157,17 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the general information about a backup file with non-standard format
|
||||
*
|
||||
* @param moodle_url $nextstageurl URL to send user to
|
||||
* @param array $details basic info about the file (format, type)
|
||||
* @return string HTML code to display
|
||||
*/
|
||||
public function backup_details_nonstandard($nextstageurl, array $details) {
|
||||
|
||||
$html = html_writer::start_tag('div', array('class' => 'backup-restore nonstandardformat'));
|
||||
$html .= html_writer::start_tag('div', array('class' => 'backup-section'));
|
||||
$html .= $this->output->heading(get_string('backupdetails', 'backup'), 2, 'header');
|
||||
$html .= $this->output->box(get_string('backupdetailsnonstandardinfo', 'backup'), 'noticebox');
|
||||
$html .= $this->backup_detail_pair(
|
||||
get_string('backupformat', 'backup'),
|
||||
get_string('backupformat'.$details['format'], 'backup'));
|
||||
$html .= $this->backup_detail_pair(
|
||||
get_string('backuptype', 'backup'),
|
||||
get_string('backuptype'.$details['type'], 'backup'));
|
||||
$html .= html_writer::end_tag('div');
|
||||
$html .= $this->output->single_button($nextstageurl, get_string('continue'), 'post');
|
||||
$html .= html_writer::end_tag('div');
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the general information about a backup file with unknown format
|
||||
*
|
||||
* @param moodle_url $nextstageurl URL to send user to
|
||||
* @return string HTML code to display
|
||||
*/
|
||||
public function backup_details_unknown(moodle_url $nextstageurl) {
|
||||
|
||||
$html = html_writer::start_tag('div', array('class' => 'unknownformat'));
|
||||
$html .= $this->output->heading(get_string('errorinvalidformat', 'backup'), 2, 'notifyproblem');
|
||||
$html .= html_writer::tag('div', get_string('errorinvalidformatinfo', 'backup'), array('class' => 'notifyproblem'));
|
||||
$html .= $this->output->single_button($nextstageurl, get_string('continue'), 'post');
|
||||
$html .= html_writer::end_tag('div');
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a course selector for restore
|
||||
*
|
||||
* @param moodle_url $nextstageurl
|
||||
* @param bool $wholecourse true if we are restoring whole course (as with backup::TYPE_1COURSE), false otherwise
|
||||
* @param stdClass $details
|
||||
* @param restore_category_search $categories
|
||||
* @param restore_course_search $courses
|
||||
* @param int $currentcourse
|
||||
* @return string
|
||||
*/
|
||||
public function course_selector(moodle_url $nextstageurl, $wholecourse = true, restore_category_search $categories = null, restore_course_search $courses=null, $currentcourse = null) {
|
||||
public function course_selector(moodle_url $nextstageurl, $details, restore_category_search $categories = null, restore_course_search $courses=null, $currentcourse = null) {
|
||||
global $CFG;
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
|
||||
@@ -224,7 +181,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$hasrestoreoption = false;
|
||||
|
||||
$html = html_writer::start_tag('div', array('class'=>'backup-course-selector backup-restore'));
|
||||
if ($wholecourse && !empty($categories) && ($categories->get_count() > 0 || $categories->get_search())) {
|
||||
if ($details->type == backup::TYPE_1COURSE && !empty($categories) && ($categories->get_count() > 0 || $categories->get_search())) {
|
||||
// New course
|
||||
$hasrestoreoption = true;
|
||||
$html .= $form;
|
||||
@@ -237,7 +194,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$html .= html_writer::end_tag('form');
|
||||
}
|
||||
|
||||
if ($wholecourse && !empty($currentcourse)) {
|
||||
if ($details->type == backup::TYPE_1COURSE && !empty($currentcourse)) {
|
||||
// Current course
|
||||
$hasrestoreoption = true;
|
||||
$html .= $form;
|
||||
@@ -257,7 +214,7 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$html .= $form;
|
||||
$html .= html_writer::start_tag('div', array('class'=>'bcs-existing-course backup-section'));
|
||||
$html .= $this->output->heading(get_string('restoretoexistingcourse', 'backup'), 2, array('class'=>'header'));
|
||||
if ($wholecourse) {
|
||||
if ($details->type == backup::TYPE_1COURSE) {
|
||||
$html .= $this->backup_detail_input(get_string('restoretoexistingcourseadding', 'backup'), 'radio', 'target', backup::TARGET_EXISTING_ADDING, array('checked'=>'checked'));
|
||||
$html .= $this->backup_detail_input(get_string('restoretoexistingcoursedeleting', 'backup'), 'radio', 'target', backup::TARGET_EXISTING_DELETING);
|
||||
$html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
|
||||
@@ -661,6 +618,23 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$output .= html_writer::end_tag('div');
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function invalid_format($format) {
|
||||
$html = html_writer::start_tag('div', array('class'=>'invalidformat'));
|
||||
$html .= html_writer::tag('h2', get_string('errorinvalidformat', 'backup'), array('class'=>'notifyproblem'));
|
||||
if ($format == 'moodle1') {
|
||||
// Moodle 1.x backups
|
||||
$icon = $this->output->help_icon('errormoodle1format', 'backup');
|
||||
$message = get_string('errormoodle1formatdesc', 'backup').' '.$icon;
|
||||
|
||||
} else {
|
||||
// Totally unknown format
|
||||
$message = get_string('errorinvalidformatdesc', 'backup');
|
||||
}
|
||||
$html .= html_writer::tag('div', $message, array('class'=>'notifyproblem'));
|
||||
$html .= html_writer::end_tag('div');
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -252,19 +252,17 @@ class restore_ui extends base_ui {
|
||||
}
|
||||
/**
|
||||
* Displays this stage
|
||||
*
|
||||
* @param core_backup_renderer $renderer
|
||||
* @return string HTML code to echo
|
||||
*/
|
||||
public function display($renderer) {
|
||||
if ($this->progress < self::PROGRESS_SAVED) {
|
||||
throw new base_ui_exception('backupsavebeforedisplay');
|
||||
}
|
||||
return $this->stage->display($renderer);
|
||||
$this->stage->display($renderer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* restore user interface exception. Modelled off the restore_exception class
|
||||
*/
|
||||
class restore_ui_exception extends base_ui_exception {}
|
||||
class restore_ui_exception extends base_ui_exception {}
|
||||
@@ -226,10 +226,18 @@ class restore_course_search extends restore_search_base {
|
||||
*/
|
||||
public function __construct(array $config=array(), $currentcouseid = null) {
|
||||
parent::__construct($config);
|
||||
$this->require_capability('moodle/restore:restorecourse');
|
||||
$this->setup_restrictions();
|
||||
$this->currentcourseid = $currentcouseid;
|
||||
$this->includecurrentcourse = false;
|
||||
}
|
||||
/**
|
||||
* Sets up any access restrictions for the courses to be displayed in the search.
|
||||
*
|
||||
* This will typically call $this->require_capability().
|
||||
*/
|
||||
protected function setup_restrictions() {
|
||||
$this->require_capability('moodle/restore:restorecourse');
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @global moodle_database $DB
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
|
||||
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
@@ -170,39 +171,17 @@ class restore_ui_stage_confirm extends restore_ui_independent_stage {
|
||||
$fb = get_file_packer();
|
||||
return ($fb->extract_to_pathname("$CFG->dataroot/temp/backup/".$this->filename, "$CFG->dataroot/temp/backup/$this->filepath/"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the confirmation stage screen
|
||||
*
|
||||
* @param core_backup_renderer $renderer renderer instance to use
|
||||
* @return string HTML code
|
||||
*/
|
||||
public function display($renderer) {
|
||||
|
||||
$prevstageurl = new moodle_url('/backup/restorefile.php', array('contextid' => $this->contextid));
|
||||
$nextstageurl = new moodle_url('/backup/restore.php', array(
|
||||
'contextid' => $this->contextid,
|
||||
'filepath' => $this->filepath,
|
||||
'stage' => restore_ui::STAGE_DESTINATION));
|
||||
|
||||
// TODO: Remove this when backup formats are better supported
|
||||
$format = backup_general_helper::detect_backup_format($this->filepath);
|
||||
|
||||
if ($format === backup::FORMAT_UNKNOWN) {
|
||||
// unknown format - we can't do anything here
|
||||
return $renderer->backup_details_unknown($prevstageurl);
|
||||
|
||||
} else if ($format !== backup::FORMAT_MOODLE) {
|
||||
// non-standard format to be converted
|
||||
$details = array('format' => $format, 'type' => backup::TYPE_1COURSE); // todo type to be returned by a converter
|
||||
return $renderer->backup_details_nonstandard($nextstageurl, $details);
|
||||
|
||||
} else {
|
||||
// standard MBZ backup, let us get information from it and display
|
||||
$this->details = backup_general_helper::get_backup_information($this->filepath);
|
||||
return $renderer->backup_details($this->details, $nextstageurl);
|
||||
if ($format !== 'moodle2') {
|
||||
return $renderer->invalid_format($format);
|
||||
}
|
||||
}
|
||||
|
||||
$this->details = backup_general_helper::get_backup_information($this->filepath);
|
||||
return $renderer->backup_details($this->details, new moodle_url('/backup/restore.php', array('contextid'=>$this->contextid, 'filepath'=>$this->filepath, 'stage'=>restore_ui::STAGE_DESTINATION)));
|
||||
}
|
||||
public function get_stage_name() {
|
||||
return get_string('restorestage'.restore_ui::STAGE_CONFIRM, 'backup');
|
||||
}
|
||||
@@ -219,6 +198,7 @@ class restore_ui_stage_confirm extends restore_ui_independent_stage {
|
||||
class restore_ui_stage_destination extends restore_ui_independent_stage {
|
||||
protected $contextid;
|
||||
protected $filepath = null;
|
||||
protected $details;
|
||||
protected $courseid = null;
|
||||
protected $target = backup::TARGET_NEW_COURSE;
|
||||
protected $coursesearch = null;
|
||||
@@ -255,48 +235,29 @@ class restore_ui_stage_destination extends restore_ui_independent_stage {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the destination stage screen
|
||||
*
|
||||
* @param core_backup_renderer $renderer renderer instance to use
|
||||
* @return string HTML code
|
||||
* @global moodle_database $DB
|
||||
* @param core_backup_renderer $renderer
|
||||
* @return string
|
||||
*/
|
||||
public function display($renderer) {
|
||||
global $DB, $USER, $PAGE;
|
||||
|
||||
$format = backup_general_helper::detect_backup_format($this->filepath);
|
||||
|
||||
if ($format === backup::FORMAT_MOODLE) {
|
||||
// standard Moodle 2 format, let use get the type of the backup
|
||||
$details = backup_general_helper::get_backup_information($this->filepath);
|
||||
if ($details->type === backup::TYPE_1COURSE) {
|
||||
$wholecourse = true;
|
||||
} else {
|
||||
$wholecourse = false;
|
||||
}
|
||||
|
||||
} else {
|
||||
// non-standard format to be converted. We assume it contains the
|
||||
// whole course for now. However, in the future there might be a callback
|
||||
// to the installed converters
|
||||
$wholecourse = true;
|
||||
if ($format !== 'moodle2') {
|
||||
return $renderer->invalid_format($format);
|
||||
}
|
||||
|
||||
$nextstageurl = new moodle_url('/backup/restore.php', array(
|
||||
'contextid' => $this->contextid,
|
||||
'filepath' => $this->filepath,
|
||||
'stage' => restore_ui::STAGE_SETTINGS));
|
||||
$this->details = backup_general_helper::get_backup_information($this->filepath);
|
||||
$url = new moodle_url('/backup/restore.php', array('contextid'=>$this->contextid, 'filepath'=>$this->filepath, 'stage'=>restore_ui::STAGE_SETTINGS));
|
||||
|
||||
$context = get_context_instance_by_id($this->contextid);
|
||||
$currentcourse = ($context->contextlevel == CONTEXT_COURSE && has_capability('moodle/restore:restorecourse', $context))?$context->instanceid:false;
|
||||
|
||||
if ($context->contextlevel == CONTEXT_COURSE and has_capability('moodle/restore:restorecourse', $context)) {
|
||||
$currentcourse = $context->instanceid;
|
||||
} else {
|
||||
$currentcourse = false;
|
||||
}
|
||||
|
||||
return $renderer->course_selector($nextstageurl, $wholecourse, $this->categorysearch, $this->coursesearch, $currentcourse);
|
||||
$html = $renderer->course_selector($url, $this->details, $this->categorysearch, $this->coursesearch, $currentcourse);
|
||||
return $html;
|
||||
}
|
||||
|
||||
public function get_stage_name() {
|
||||
return get_string('restorestage'.restore_ui::STAGE_DESTINATION, 'backup');
|
||||
}
|
||||
@@ -603,6 +564,7 @@ class restore_ui_stage_review extends restore_ui_stage {
|
||||
class restore_ui_stage_process extends restore_ui_stage {
|
||||
|
||||
const SUBSTAGE_NONE = 0;
|
||||
const SUBSTAGE_CONVERT = 1;
|
||||
const SUBSTAGE_PRECHECKS = 2;
|
||||
|
||||
protected $substage = 0;
|
||||
@@ -630,16 +592,20 @@ class restore_ui_stage_process extends restore_ui_stage {
|
||||
|
||||
// First decide whether a substage is needed
|
||||
$rc = $this->ui->get_controller();
|
||||
if ($rc->get_status() == backup::STATUS_SETTING_UI) {
|
||||
$rc->finish_ui();
|
||||
}
|
||||
if ($rc->get_status() == backup::STATUS_NEED_PRECHECK) {
|
||||
if (!$rc->precheck_executed()) {
|
||||
$rc->execute_precheck(true);
|
||||
if ($rc->get_status() == backup::STATUS_REQUIRE_CONV) {
|
||||
$this->substage = self::SUBSTAGE_CONVERT;
|
||||
} else {
|
||||
if ($rc->get_status() == backup::STATUS_SETTING_UI) {
|
||||
$rc->finish_ui();
|
||||
}
|
||||
$results = $rc->get_precheck_results();
|
||||
if (!empty($results)) {
|
||||
$this->substage = self::SUBSTAGE_PRECHECKS;
|
||||
if ($rc->get_status() == backup::STATUS_NEED_PRECHECK) {
|
||||
if (!$rc->precheck_executed()) {
|
||||
$rc->execute_precheck(true);
|
||||
}
|
||||
$results = $rc->get_precheck_results();
|
||||
if (!empty($results)) {
|
||||
$this->substage = self::SUBSTAGE_PRECHECKS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,52 +635,37 @@ class restore_ui_stage_process extends restore_ui_stage {
|
||||
protected function initialise_stage_form() {
|
||||
throw new backup_ui_exception('backup_ui_must_execute_first');
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the process stage screen
|
||||
*
|
||||
* @param core_backup_renderer $renderer renderer instance to use
|
||||
* @return string HTML code
|
||||
* should NEVER be called... throws an exception
|
||||
*/
|
||||
public function display($renderer) {
|
||||
global $PAGE;
|
||||
|
||||
$html = '';
|
||||
$haserrors = false;
|
||||
$url = new moodle_url($PAGE->url, array(
|
||||
'restore' => $this->get_uniqueid(),
|
||||
'stage' => restore_ui::STAGE_PROCESS,
|
||||
'substage' => $this->substage,
|
||||
'sesskey' => sesskey()));
|
||||
$html .= html_writer::start_tag('form', array(
|
||||
'action' => $url->out_omit_querystring(),
|
||||
'class' => 'backup-restore',
|
||||
'method' => 'post'));
|
||||
foreach ($url->params() as $name => $value) {
|
||||
$html .= html_writer::empty_tag('input', array(
|
||||
'type' => 'hidden',
|
||||
'name' => $name,
|
||||
'value' => $value));
|
||||
$url = new moodle_url($PAGE->url, array('restore'=>$this->get_uniqueid(), 'stage'=>restore_ui::STAGE_PROCESS, 'substage'=>$this->substage, 'sesskey'=>sesskey()));
|
||||
echo html_writer::start_tag('form', array('action'=>$url->out_omit_querystring(), 'class'=>'backup-restore', 'method'=>'post'));
|
||||
foreach ($url->params() as $name=>$value) {
|
||||
echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$name, 'value'=>$value));
|
||||
}
|
||||
switch ($this->substage) {
|
||||
case self::SUBSTAGE_CONVERT :
|
||||
echo '<h2>Need to show the conversion screens here</h2>';
|
||||
break;
|
||||
case self::SUBSTAGE_PRECHECKS :
|
||||
$results = $this->ui->get_controller()->get_precheck_results();
|
||||
$info = $this->ui->get_controller()->get_info();
|
||||
$haserrors = (!empty($results['errors']));
|
||||
$html .= $renderer->precheck_notices($results);
|
||||
echo $renderer->precheck_notices($results);
|
||||
if (!empty($info->role_mappings->mappings)) {
|
||||
$context = get_context_instance(CONTEXT_COURSE, $this->ui->get_controller()->get_courseid());
|
||||
$assignableroles = get_assignable_roles($context, ROLENAME_ALIAS, false);
|
||||
$html .= $renderer->role_mappings($info->role_mappings->mappings, $assignableroles);
|
||||
echo $renderer->role_mappings($info->role_mappings->mappings, $assignableroles);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new restore_ui_exception('backup_ui_must_execute_first');
|
||||
}
|
||||
$html .= $renderer->substage_buttons($haserrors);
|
||||
$html .= html_writer::end_tag('form');
|
||||
|
||||
return $html;
|
||||
echo $renderer->substage_buttons($haserrors);
|
||||
echo html_writer::end_tag('form');
|
||||
}
|
||||
|
||||
public function has_sub_stages() {
|
||||
@@ -744,24 +695,20 @@ class restore_ui_stage_complete extends restore_ui_stage_process {
|
||||
parent::__construct($ui, $params);
|
||||
$this->stage = restore_ui::STAGE_COMPLETE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the completed backup stage.
|
||||
*
|
||||
* Currently this just envolves redirecting to the file browser with an
|
||||
* appropriate message.
|
||||
*
|
||||
* @global core_renderer $OUTPUT
|
||||
* @param core_backup_renderer $renderer
|
||||
*/
|
||||
public function display(core_backup_renderer $renderer) {
|
||||
|
||||
$html = '';
|
||||
$html .= $renderer->box_start();
|
||||
$html .= $renderer->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
|
||||
$html .= $renderer->continue_button(new moodle_url('/course/view.php', array(
|
||||
'id' => $this->get_ui()->get_controller()->get_courseid())), 'get');
|
||||
$html .= $renderer->box_end();
|
||||
|
||||
return $html;
|
||||
global $OUTPUT;
|
||||
echo $OUTPUT->box_start();
|
||||
echo $OUTPUT->notification(get_string('restoreexecutionsuccess', 'backup'), 'notifysuccess');
|
||||
echo $renderer->continue_button(new moodle_url('/course/view.php', array('id'=>$this->get_ui()->get_controller()->get_courseid())), 'get');
|
||||
echo $OUTPUT->box_end();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,23 +71,9 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
}
|
||||
|
||||
/**
|
||||
* The parser fires this each time one path is going to be parsed
|
||||
*
|
||||
* @param string $path xml path which parsing has started
|
||||
*/
|
||||
public function before_path($path) {
|
||||
if (!$this->grouped_parent_exists($path)) {
|
||||
parent::before_path($path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The parser fires this each time one path has been parsed
|
||||
*
|
||||
* @param string $path xml path which parsing has ended
|
||||
* Dispatch grouped chunks safely once their end tag happens
|
||||
*/
|
||||
public function after_path($path) {
|
||||
// Have finished one grouped path, dispatch it
|
||||
if ($this->path_is_grouped($path)) {
|
||||
// Any accumulated information must be in
|
||||
// currentdata, properly built
|
||||
@@ -96,11 +82,6 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
// TODO: If running under DEBUG_DEVELOPER notice about >1MB grouped chunks
|
||||
$this->dispatch_chunk($data);
|
||||
}
|
||||
// Normal notification of path end
|
||||
// Only if path is selected and not child of grouped
|
||||
if (!$this->grouped_parent_exists($path)) {
|
||||
parent::after_path($path);
|
||||
}
|
||||
}
|
||||
|
||||
// Protected API starts here
|
||||
@@ -130,6 +111,23 @@ abstract class grouped_parser_processor extends simplified_parser_processor {
|
||||
return in_array($path, $this->groupedpaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that will look for any
|
||||
* parent for the given path, returning it if found,
|
||||
* false if not
|
||||
*/
|
||||
protected function processed_parent_exists($path) {
|
||||
$parentpath = progressive_parser::dirname($path);
|
||||
while ($parentpath != '/') {
|
||||
if ($this->path_is_selected($parentpath)) {
|
||||
return $parentpath;
|
||||
}
|
||||
$parentpath = progressive_parser::dirname($parentpath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Function that will look for any grouped
|
||||
* parent for the given path, returning it if found,
|
||||
|
||||
@@ -41,14 +41,12 @@ abstract class simplified_parser_processor extends progressive_parser_processor
|
||||
protected $paths; // array of paths we are interested on
|
||||
protected $parentpaths; // array of parent paths of the $paths
|
||||
protected $parentsinfo; // array of parent attributes to be added as child tags
|
||||
protected $startendinfo;// array (stack) of startend information
|
||||
|
||||
public function __construct(array $paths = array()) {
|
||||
public function __construct(array $paths) {
|
||||
parent::__construct();
|
||||
$this->paths = array();
|
||||
$this->parentpaths = array();
|
||||
$this->parentsinfo = array();
|
||||
$this->startendinfo = array();
|
||||
// Add paths and parentpaths. We are looking for attributes there
|
||||
foreach ($paths as $key => $path) {
|
||||
$this->add_path($path);
|
||||
@@ -65,16 +63,6 @@ abstract class simplified_parser_processor extends progressive_parser_processor
|
||||
*/
|
||||
abstract protected function dispatch_chunk($data);
|
||||
|
||||
/**
|
||||
* Get one selected path and notify about start
|
||||
*/
|
||||
abstract protected function notify_path_start($path);
|
||||
|
||||
/**
|
||||
* Get one selected path and notify about end
|
||||
*/
|
||||
abstract protected function notify_path_end($path);
|
||||
|
||||
/**
|
||||
* Get one chunk of parsed data and make it simpler
|
||||
* adding attributes as tags and delegating to
|
||||
@@ -97,10 +85,6 @@ abstract class simplified_parser_processor extends progressive_parser_processor
|
||||
|
||||
// If the path is a registered one, let's process it
|
||||
if ($this->path_is_selected($path)) {
|
||||
|
||||
// Send all the pending notify_path_start/end() notifications
|
||||
$this->process_pending_startend_notifications($path, 'start');
|
||||
|
||||
// First of all, look for attributes available at parentsinfo
|
||||
// in order to get them available as normal tags
|
||||
if (isset($this->parentsinfo[$parentpath][$tag]['attrs'])) {
|
||||
@@ -152,86 +136,11 @@ abstract class simplified_parser_processor extends progressive_parser_processor
|
||||
} else {
|
||||
$this->chunks--; // Chunk skipped
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* The parser fires this each time one path is going to be parsed
|
||||
*
|
||||
* @param string $path xml path which parsing has started
|
||||
*/
|
||||
public function before_path($path) {
|
||||
if ($this->path_is_selected($path)) {
|
||||
$this->startendinfo[] = array('path' => $path, 'action' => 'start');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The parser fires this each time one path has been parsed
|
||||
*
|
||||
* @param string $path xml path which parsing has ended
|
||||
*/
|
||||
public function after_path($path) {
|
||||
$toprocess = false;
|
||||
// If the path being closed matches (same or parent) the first path in the stack
|
||||
// we process pending startend notifications until one matching end is found
|
||||
if ($element = reset($this->startendinfo)) {
|
||||
$elepath = $element['path'];
|
||||
$eleaction = $element['action'];
|
||||
if (strpos($elepath, $path) === 0) {
|
||||
$toprocess = true;
|
||||
}
|
||||
|
||||
// Also, if the stack of startend notifications is empty, we can process current end
|
||||
// path safely
|
||||
} else {
|
||||
$toprocess = true;
|
||||
}
|
||||
if ($this->path_is_selected($path)) {
|
||||
$this->startendinfo[] = array('path' => $path, 'action' => 'end');
|
||||
}
|
||||
// Send all the pending startend notifications if decided to do so
|
||||
if ($toprocess) {
|
||||
$this->process_pending_startend_notifications($path, 'end');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Protected API starts here
|
||||
|
||||
/**
|
||||
* Adjust start/end til finding one match start/end path (included)
|
||||
*
|
||||
* This will trigger all the pending {@see notify_path_start} and
|
||||
* {@see notify_path_end} calls for one given path and action
|
||||
*
|
||||
* @param string path the path to look for as limit
|
||||
* @param string action the action to look for as limit
|
||||
*/
|
||||
protected function process_pending_startend_notifications($path, $action) {
|
||||
|
||||
// Iterate until one matching path and action is found (or the array is empty)
|
||||
$elecount = count($this->startendinfo);
|
||||
$elematch = false;
|
||||
while ($elecount > 0 && !$elematch) {
|
||||
$element = array_shift($this->startendinfo);
|
||||
$elecount--;
|
||||
$elepath = $element['path'];
|
||||
$eleaction = $element['action'];
|
||||
|
||||
if ($elepath == $path && $eleaction == $action) {
|
||||
$elematch = true;
|
||||
}
|
||||
|
||||
if ($eleaction == 'start') {
|
||||
$this->notify_path_start($elepath);
|
||||
} else {
|
||||
$this->notify_path_end($elepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected function postprocess_chunk($data) {
|
||||
$this->dispatch_chunk($data);
|
||||
}
|
||||
@@ -243,18 +152,4 @@ abstract class simplified_parser_processor extends progressive_parser_processor
|
||||
protected function path_is_selected_parent($path) {
|
||||
return in_array($path, $this->parentpaths);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first selected parent if available or false
|
||||
*/
|
||||
protected function selected_parent_exists($path) {
|
||||
$parentpath = progressive_parser::dirname($path);
|
||||
while ($parentpath != '/') {
|
||||
if ($this->path_is_selected($parentpath)) {
|
||||
return $parentpath;
|
||||
}
|
||||
$parentpath = progressive_parser::dirname($parentpath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<MOODLE_BACKUP>
|
||||
<COURSE ID="100">
|
||||
<SECTIONS>
|
||||
<SECTION>
|
||||
<ID>200</ID>
|
||||
<MODS>
|
||||
<MOD>
|
||||
<ID>300</ID>
|
||||
<ROLES_OVERRIDES>
|
||||
</ROLES_OVERRIDES>
|
||||
</MOD>
|
||||
<MOD />
|
||||
<MOD />
|
||||
<MOD ID="400" />
|
||||
<MOD>
|
||||
<ID>500</ID>
|
||||
</MOD>
|
||||
<MOD />
|
||||
<MOD />
|
||||
</MODS>
|
||||
</SECTION>
|
||||
</SECTIONS>
|
||||
</COURSE>
|
||||
</MOODLE_BACKUP>
|
||||
@@ -307,103 +307,6 @@ class progressive_parser_test extends UnitTestCase {
|
||||
$this->assertEqual(count($tags), 2);
|
||||
$this->assertEqual($tags['name'], 4);
|
||||
$this->assertEqual($tags['value'], 5);
|
||||
|
||||
// Now check start notifications
|
||||
$snotifs = $pr->get_start_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 12);
|
||||
// Check first, sixth and last notifications
|
||||
$this->assertEqual($snotifs[0], '/activity');
|
||||
$this->assertEqual($snotifs[5], '/activity/glossary/entries/entry');
|
||||
$this->assertEqual($snotifs[11], '/activity/glossary/othertest');
|
||||
|
||||
// Now check end notifications
|
||||
$enotifs = $pr->get_end_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 12);
|
||||
// Check first, sixth and last notifications
|
||||
$this->assertEqual($enotifs[0], '/activity/glossary/entries/entry/aliases/alias');
|
||||
$this->assertEqual($enotifs[5], '/activity/glossary/entries/entry/ratings/rating');
|
||||
$this->assertEqual($enotifs[11], '/activity');
|
||||
|
||||
// Check start and end notifications are balanced
|
||||
sort($snotifs);
|
||||
sort($enotifs);
|
||||
$this->assertEqual($snotifs, $enotifs);
|
||||
|
||||
// Now verify that the start/process/end order is correct
|
||||
$allnotifs = $pr->get_all_notifications();
|
||||
$this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
|
||||
// Check integrity of the notifications
|
||||
$errcount = $this->helper_check_notifications_order_integrity($allnotifs);
|
||||
$this->assertEqual($errcount, 0); // No errors found, plz
|
||||
}
|
||||
|
||||
/**
|
||||
* test how the simplified processor and the order of start/process/end events happens
|
||||
* with one real fragment of one backup 1.9 file, where some problems
|
||||
* were found by David, hence we honor him in the name of the test ;-)
|
||||
*/
|
||||
function test_simplified_david_backup19_file_fragment() {
|
||||
global $CFG;
|
||||
// Instantiate progressive_parser
|
||||
$pp = new progressive_parser();
|
||||
// Instantiate grouped_parser_processor
|
||||
$pr = new mock_simplified_parser_processor();
|
||||
// Add interesting paths
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE');
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
|
||||
$this->assertTrue($pr instanceof progressive_parser_processor);
|
||||
// Assign processor to parser
|
||||
$pp->set_processor($pr);
|
||||
// Set file from fixtures
|
||||
$pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test5.xml');
|
||||
// Process the file
|
||||
$pp->process();
|
||||
|
||||
// Get all the simplified chunks and perform various validations
|
||||
$chunks = $pr->get_chunks();
|
||||
$this->assertEqual(count($chunks), 3); // Only 3, because 7 (COURSE, ROLES_OVERRIDES and 5 MOD) are empty, aka no chunk
|
||||
|
||||
// Now check start notifications
|
||||
$snotifs = $pr->get_start_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 10); // Start tags are dispatched for empties (ROLES_OVERRIDES)
|
||||
// Check first and last notifications
|
||||
$this->assertEqual($snotifs[0], '/MOODLE_BACKUP/COURSE');
|
||||
$this->assertEqual($snotifs[1], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
|
||||
$this->assertEqual($snotifs[2], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($snotifs[3], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
|
||||
$this->assertEqual($snotifs[7], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($snotifs[8], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($snotifs[9], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
|
||||
// Now check end notifications
|
||||
$enotifs = $pr->get_end_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 10); // End tags are dispatched for empties (ROLES_OVERRIDES)
|
||||
// Check first, and last notifications
|
||||
$this->assertEqual($enotifs[0], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
|
||||
$this->assertEqual($enotifs[1], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($enotifs[2], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($enotifs[3], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($enotifs[7], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$this->assertEqual($enotifs[8], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
|
||||
$this->assertEqual($enotifs[9], '/MOODLE_BACKUP/COURSE');
|
||||
|
||||
// Check start and end notifications are balanced
|
||||
sort($snotifs);
|
||||
sort($enotifs);
|
||||
$this->assertEqual($snotifs, $enotifs);
|
||||
|
||||
// Now verify that the start/process/end order is correct
|
||||
$allnotifs = $pr->get_all_notifications();
|
||||
$this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
|
||||
// Check integrity of the notifications
|
||||
$errcount = $this->helper_check_notifications_order_integrity($allnotifs);
|
||||
$this->assertEqual($errcount, 0); // No errors found, plz
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -551,148 +454,6 @@ class progressive_parser_test extends UnitTestCase {
|
||||
$this->assertEqual(count($othertest[0]), 2);
|
||||
$this->assertEqual($othertest[0]['name'], 4);
|
||||
$this->assertEqual($othertest[0]['value'], 5);
|
||||
|
||||
// Now check start notifications
|
||||
$snotifs = $pr->get_start_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 2);
|
||||
// Check first and last notifications
|
||||
$this->assertEqual($snotifs[0], '/activity');
|
||||
$this->assertEqual($snotifs[1], '/activity/glossary');
|
||||
|
||||
// Now check end notifications
|
||||
$enotifs = $pr->get_end_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 2);
|
||||
// Check first, and last notifications
|
||||
$this->assertEqual($enotifs[0], '/activity/glossary');
|
||||
$this->assertEqual($enotifs[1], '/activity');
|
||||
|
||||
// Check start and end notifications are balanced
|
||||
sort($snotifs);
|
||||
sort($enotifs);
|
||||
$this->assertEqual($snotifs, $enotifs);
|
||||
|
||||
// Now verify that the start/process/end order is correct
|
||||
$allnotifs = $pr->get_all_notifications();
|
||||
$this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
|
||||
// Check integrity of the notifications
|
||||
$errcount = $this->helper_check_notifications_order_integrity($allnotifs);
|
||||
$this->assertEqual($errcount, 0); // No errors found, plz
|
||||
}
|
||||
|
||||
/**
|
||||
* test how the grouped processor and the order of start/process/end events happens
|
||||
* with one real fragment of one backup 1.9 file, where some problems
|
||||
* were found by David, hence we honor him in the name of the test ;-)
|
||||
*/
|
||||
function test_grouped_david_backup19_file_fragment() {
|
||||
global $CFG;
|
||||
// Instantiate progressive_parser
|
||||
$pp = new progressive_parser();
|
||||
// Instantiate grouped_parser_processor
|
||||
$pr = new mock_grouped_parser_processor();
|
||||
// Add interesting paths
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE');
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION', true);
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD');
|
||||
$pr->add_path('/MOODLE_BACKUP/COURSE/SECTIONS/SECTION/MODS/MOD/ROLES_OVERRIDES');
|
||||
$this->assertTrue($pr instanceof progressive_parser_processor);
|
||||
// Assign processor to parser
|
||||
$pp->set_processor($pr);
|
||||
// Set file from fixtures
|
||||
$pp->set_file($CFG->dirroot . '/backup/util/xml/parser/simpletest/fixtures/test5.xml');
|
||||
// Process the file
|
||||
$pp->process();
|
||||
|
||||
// Get all the simplified chunks and perform various validations
|
||||
$chunks = $pr->get_chunks();
|
||||
$this->assertEqual(count($chunks), 1); // Only 1, the SECTION one
|
||||
|
||||
// Now check start notifications
|
||||
$snotifs = $pr->get_start_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 2);
|
||||
// Check first and last notifications
|
||||
$this->assertEqual($snotifs[0], '/MOODLE_BACKUP/COURSE');
|
||||
$this->assertEqual($snotifs[1], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
|
||||
|
||||
// Now check end notifications
|
||||
$enotifs = $pr->get_end_notifications();
|
||||
// Check we have received the correct number of notifications
|
||||
$this->assertEqual(count($snotifs), 2); // End tags are dispatched for empties (ROLES_OVERRIDES)
|
||||
// Check first, and last notifications
|
||||
$this->assertEqual($enotifs[0], '/MOODLE_BACKUP/COURSE/SECTIONS/SECTION');
|
||||
$this->assertEqual($enotifs[1], '/MOODLE_BACKUP/COURSE');
|
||||
|
||||
// Check start and end notifications are balanced
|
||||
sort($snotifs);
|
||||
sort($enotifs);
|
||||
$this->assertEqual($snotifs, $enotifs);
|
||||
|
||||
// Now verify that the start/process/end order is correct
|
||||
$allnotifs = $pr->get_all_notifications();
|
||||
$this->assertEqual(count($allnotifs), count($snotifs) + count($enotifs) + count($chunks)); // The count
|
||||
// Check integrity of the notifications
|
||||
$errcount = $this->helper_check_notifications_order_integrity($allnotifs);
|
||||
$this->assertEqual($errcount, 0); // No errors found, plz
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function that given one array of ordered start/process/end notifications will
|
||||
* check it of integrity like:
|
||||
* - process only happens if start is the previous notification
|
||||
* - end only happens if dispatch is the previous notification
|
||||
* - start only happen with level > than last one and if there is no already started like that
|
||||
*
|
||||
* @param array $notifications ordered array of notifications with format [start|process|end]:path
|
||||
* @return int number of integrity problems found (errors)
|
||||
*/
|
||||
function helper_check_notifications_order_integrity($notifications) {
|
||||
$numerrors = 0;
|
||||
$notifpile = array('pilebase' => 'start');
|
||||
$lastnotif = 'start:pilebase';
|
||||
foreach ($notifications as $notif) {
|
||||
|
||||
$lastpiletype = end($notifpile);
|
||||
$lastpilepath = key($notifpile);
|
||||
$lastpilelevel = strlen(preg_replace('/[^\/]/', '', $lastpilepath));
|
||||
|
||||
$lastnotiftype = preg_replace('/:.*/', '', $lastnotif);
|
||||
$lastnotifpath = preg_replace('/.*:/', '', $lastnotif);
|
||||
$lastnotiflevel = strlen(preg_replace('/[^\/]/', '', $lastnotifpath));
|
||||
|
||||
$notiftype = preg_replace('/:.*/', '', $notif);
|
||||
$notifpath = preg_replace('/.*:/', '', $notif);
|
||||
$notiflevel = strlen(preg_replace('/[^\/]/', '', $notifpath));
|
||||
|
||||
switch ($notiftype) {
|
||||
case 'process':
|
||||
if ($lastnotifpath != $notifpath or $lastnotiftype != 'start') {
|
||||
$numerrors++; // Only start for same path from last notification is allowed before process
|
||||
}
|
||||
$notifpile[$notifpath] = 'process'; // Update the status in the pile
|
||||
break;
|
||||
case 'end':
|
||||
if ($lastpilepath != $notifpath or ($lastpiletype != 'process' and $lastpiletype != 'start')) {
|
||||
$numerrors++; // Only process and start for same path from last pile is allowed before end
|
||||
}
|
||||
unset($notifpile[$notifpath]); // Delete from the pile
|
||||
break;
|
||||
case 'start':
|
||||
if (array_key_exists($notifpath, $notifpile) or $notiflevel <= $lastpilelevel) {
|
||||
$numerrors++; // Only non existing in pile and with level > last pile is allowed on start
|
||||
}
|
||||
$notifpile[$notifpath] = 'start'; // Add to the pile
|
||||
break;
|
||||
default:
|
||||
$numerrors++; // Incorrect type of notification => error
|
||||
}
|
||||
// Update lastnotif
|
||||
$lastnotif = $notif;
|
||||
}
|
||||
return $numerrors;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -765,40 +526,14 @@ class mock_parser_processor extends progressive_parser_processor {
|
||||
class mock_simplified_parser_processor extends simplified_parser_processor {
|
||||
|
||||
private $chunksarr = array(); // To accumulate the found chunks
|
||||
private $startarr = array(); // To accumulate all the notified path starts
|
||||
private $endarr = array(); // To accumulate all the notified path ends
|
||||
private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way
|
||||
|
||||
public function dispatch_chunk($data) {
|
||||
$this->chunksarr[] = $data;
|
||||
$this->allnotif[] = 'process:' . $data['path'];
|
||||
}
|
||||
|
||||
public function notify_path_start($path) {
|
||||
$this->startarr[] = $path;
|
||||
$this->allnotif[] = 'start:' . $path;
|
||||
}
|
||||
|
||||
public function notify_path_end($path) {
|
||||
$this->endarr[] = $path;
|
||||
$this->allnotif[] = 'end:' . $path;
|
||||
}
|
||||
|
||||
public function get_chunks() {
|
||||
return $this->chunksarr;
|
||||
}
|
||||
|
||||
public function get_start_notifications() {
|
||||
return $this->startarr;
|
||||
}
|
||||
|
||||
public function get_end_notifications() {
|
||||
return $this->endarr;
|
||||
}
|
||||
|
||||
public function get_all_notifications() {
|
||||
return $this->allnotif;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -807,38 +542,12 @@ class mock_simplified_parser_processor extends simplified_parser_processor {
|
||||
class mock_grouped_parser_processor extends grouped_parser_processor {
|
||||
|
||||
private $chunksarr = array(); // To accumulate the found chunks
|
||||
private $startarr = array(); // To accumulate all the notified path starts
|
||||
private $endarr = array(); // To accumulate all the notified path ends
|
||||
private $allnotif = array(); // To accumulate all the notified and dispatched events in an ordered way
|
||||
|
||||
public function dispatch_chunk($data) {
|
||||
$this->chunksarr[] = $data;
|
||||
$this->allnotif[] = 'process:' . $data['path'];
|
||||
}
|
||||
|
||||
public function notify_path_start($path) {
|
||||
$this->startarr[] = $path;
|
||||
$this->allnotif[] = 'start:' . $path;
|
||||
}
|
||||
|
||||
public function notify_path_end($path) {
|
||||
$this->endarr[] = $path;
|
||||
$this->allnotif[] = 'end:' . $path;
|
||||
}
|
||||
|
||||
public function get_chunks() {
|
||||
return $this->chunksarr;
|
||||
}
|
||||
|
||||
public function get_start_notifications() {
|
||||
return $this->startarr;
|
||||
}
|
||||
|
||||
public function get_end_notifications() {
|
||||
return $this->endarr;
|
||||
}
|
||||
|
||||
public function get_all_notifications() {
|
||||
return $this->allnotif;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ class block_calendar_month extends block_base {
|
||||
if ($this->content !== NULL) {
|
||||
return $this->content;
|
||||
}
|
||||
// Reset the session variables
|
||||
calendar_session_vars($this->page->course);
|
||||
|
||||
$this->content = new stdClass;
|
||||
$this->content->text = '';
|
||||
@@ -27,30 +29,52 @@ class block_calendar_month extends block_base {
|
||||
// [pj] To me it looks like this if would never be needed, but Penny added it
|
||||
// when committing the /my/ stuff. Reminder to discuss and learn what it's about.
|
||||
// It definitely needs SOME comment here!
|
||||
$courseid = $this->page->course->id;
|
||||
$issite = ($courseid == SITEID);
|
||||
$courseshown = $this->page->course->id;
|
||||
|
||||
if ($issite) {
|
||||
if ($courseshown == SITEID) {
|
||||
// Being displayed at site level. This will cause the filter to fall back to auto-detecting
|
||||
// the list of courses it will be grabbing events from.
|
||||
$filtercourse = calendar_get_default_courses();
|
||||
$filtercourse = NULL;
|
||||
$groupeventsfrom = NULL;
|
||||
$SESSION->cal_courses_shown = calendar_get_default_courses(true);
|
||||
calendar_set_referring_course(0);
|
||||
|
||||
} else {
|
||||
// Forcibly filter events to include only those from the particular course we are in.
|
||||
$filtercourse = array($courseid => $this->page->course);
|
||||
$filtercourse = array($courseshown => $this->page->course);
|
||||
$groupeventsfrom = array($courseshown => 1);
|
||||
}
|
||||
|
||||
list($courses, $group, $user) = calendar_set_filters($filtercourse);
|
||||
if ($issite) {
|
||||
// We 'll need this later
|
||||
calendar_set_referring_course($courseshown);
|
||||
|
||||
// MDL-9059, set to show this course when admins go into a course, then unset it.
|
||||
if ($this->page->course->id != SITEID && !isset($SESSION->cal_courses_shown[$this->page->course->id]) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) {
|
||||
$courseset = true;
|
||||
$SESSION->cal_courses_shown[$this->page->course->id] = $this->page->course;
|
||||
}
|
||||
|
||||
// Be VERY careful with the format for default courses arguments!
|
||||
// Correct formatting is [courseid] => 1 to be concise with moodlelib.php functions.
|
||||
calendar_set_filters($courses, $group, $user, $filtercourse, $groupeventsfrom, false);
|
||||
if ($courseshown == SITEID) {
|
||||
// For the front page
|
||||
$this->content->text .= calendar_top_controls('frontpage', array('id' => $courseid, 'm' => $cal_m, 'y' => $cal_y));
|
||||
$this->content->text .= calendar_top_controls('frontpage', array('id' => $courseshown, 'm' => $cal_m, 'y' => $cal_y));
|
||||
$this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y);
|
||||
// No filters for now
|
||||
|
||||
} else {
|
||||
// For any other course
|
||||
$this->content->text .= calendar_top_controls('course', array('id' => $courseid, 'm' => $cal_m, 'y' => $cal_y));
|
||||
$this->content->text .= calendar_top_controls('course', array('id' => $courseshown, 'm' => $cal_m, 'y' => $cal_y));
|
||||
$this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y);
|
||||
$this->content->text .= '<h3 class="eventskey">'.get_string('eventskey', 'calendar').'</h3>';
|
||||
$this->content->text .= '<div class="filters">'.calendar_filter_controls($this->page->url).'</div>';
|
||||
$this->content->text .= '<div class="filters">'.calendar_filter_controls('course', '', $this->page->course).'</div>';
|
||||
|
||||
}
|
||||
|
||||
// MDL-9059, unset this so that it doesn't stay in session
|
||||
if (!empty($courseset)) {
|
||||
unset($SESSION->cal_courses_shown[$this->page->course->id]);
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
|
||||
@@ -15,12 +15,14 @@ class block_calendar_upcoming extends block_base {
|
||||
if ($this->content !== NULL) {
|
||||
return $this->content;
|
||||
}
|
||||
// Reset the session variables
|
||||
calendar_session_vars($this->page->course);
|
||||
$this->content = new stdClass;
|
||||
$this->content->text = '';
|
||||
|
||||
$filtercourse = array();
|
||||
if (empty($this->instance)) { // Overrides: use no course at all
|
||||
$courseshown = false;
|
||||
$filtercourse = array();
|
||||
$this->content->footer = '';
|
||||
|
||||
} else {
|
||||
@@ -29,7 +31,8 @@ class block_calendar_upcoming extends block_base {
|
||||
'/calendar/view.php?view=upcoming&course='.$courseshown.'">'.
|
||||
get_string('gotocalendar', 'calendar').'</a>...</div>';
|
||||
$context = get_context_instance(CONTEXT_COURSE, $courseshown);
|
||||
if (has_any_capability(array('moodle/calendar:manageentries', 'moodle/calendar:manageownentries'), $context)) {
|
||||
if (has_capability('moodle/calendar:manageentries', $context) ||
|
||||
has_capability('moodle/calendar:manageownentries', $context)) {
|
||||
$this->content->footer .= '<div class="newevent"><a href="'.$CFG->wwwroot.
|
||||
'/calendar/event.php?action=new&course='.$courseshown.'">'.
|
||||
get_string('newevent', 'calendar').'</a>...</div>';
|
||||
@@ -37,34 +40,36 @@ class block_calendar_upcoming extends block_base {
|
||||
if ($courseshown == SITEID) {
|
||||
// Being displayed at site level. This will cause the filter to fall back to auto-detecting
|
||||
// the list of courses it will be grabbing events from.
|
||||
$filtercourse = calendar_get_default_courses();
|
||||
$filtercourse = NULL;
|
||||
$groupeventsfrom = NULL;
|
||||
$SESSION->cal_courses_shown = calendar_get_default_courses(true);
|
||||
calendar_set_referring_course(0);
|
||||
} else {
|
||||
// Forcibly filter events to include only those from the particular course we are in.
|
||||
$filtercourse = array($courseshown => $this->page->course);
|
||||
$filtercourse = array($courseshown => $this->page->course);
|
||||
$groupeventsfrom = array($courseshown => 1);
|
||||
}
|
||||
}
|
||||
|
||||
list($courses, $group, $user) = calendar_set_filters($filtercourse);
|
||||
// We 'll need this later
|
||||
calendar_set_referring_course($courseshown);
|
||||
|
||||
$defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
|
||||
if (isset($CFG->calendar_lookahead)) {
|
||||
$defaultlookahead = intval($CFG->calendar_lookahead);
|
||||
}
|
||||
$lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead);
|
||||
// Be VERY careful with the format for default courses arguments!
|
||||
// Correct formatting is [courseid] => 1 to be concise with moodlelib.php functions.
|
||||
|
||||
$defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS;
|
||||
if (isset($CFG->calendar_maxevents)) {
|
||||
$defaultmaxevents = intval($CFG->calendar_maxevents);
|
||||
}
|
||||
$maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents);
|
||||
$events = calendar_get_upcoming($courses, $group, $user, $lookahead, $maxevents);
|
||||
calendar_set_filters($courses, $group, $user, $filtercourse, $groupeventsfrom, false);
|
||||
$events = calendar_get_upcoming($courses, $group, $user,
|
||||
get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS),
|
||||
get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS));
|
||||
|
||||
if (!empty($this->instance)) {
|
||||
$this->content->text = calendar_get_block_upcoming($events, 'view.php?view=day&course='.$courseshown.'&');
|
||||
$this->content->text = calendar_get_block_upcoming($events,
|
||||
'view.php?view=day&course='.$courseshown.'&');
|
||||
}
|
||||
|
||||
if (empty($this->content->text)) {
|
||||
$this->content->text = '<div class="post">'. get_string('noupcomingevents', 'calendar').'</div>';
|
||||
$this->content->text = '<div class="post">'.
|
||||
get_string('noupcomingevents', 'calendar').'</div>';
|
||||
}
|
||||
|
||||
return $this->content;
|
||||
|
||||
@@ -73,8 +73,6 @@ function xmldb_block_community_upgrade($oldversion) {
|
||||
upgrade_block_savepoint(true, 2010042701, 'community');
|
||||
}
|
||||
|
||||
// Moodle v2.1.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -155,10 +155,12 @@ class community_hub_search_form extends moodleform {
|
||||
array('class' => 'hubscreenshot'));
|
||||
$hubdescriptiontext = html_writer::tag('span', format_text($hub['description'], FORMAT_PLAIN),
|
||||
array('class' => 'hubdescription'));
|
||||
$additionaldesc = get_string('sites', 'block_community') . ': ' . $hub['sites'] . ' - ' .
|
||||
get_string('courses', 'block_community') . ': ' . $hub['courses'];
|
||||
$hubdescriptiontext .= html_writer::tag('span', $additionaldesc,
|
||||
array('class' => 'hubadditionaldesc'));
|
||||
if (isset($hub['enrollablecourses'])) { //check needed to avoid warnings for Moodle version < 2011081700
|
||||
$additionaldesc = get_string('enrollablecourses', 'block_community') . ': ' . $hub['enrollablecourses'] . ' - ' .
|
||||
get_string('downloadablecourses', 'block_community') . ': ' . $hub['downloadablecourses'];
|
||||
$hubdescriptiontext .= html_writer::tag('span', $additionaldesc,
|
||||
array('class' => 'hubadditionaldesc'));
|
||||
}
|
||||
if ($hub['trusted']) {
|
||||
$hubtrusted = get_string('hubtrusted', 'block_community');
|
||||
$hubdescriptiontext .= html_writer::tag('span',
|
||||
|
||||
@@ -49,6 +49,7 @@ $string['donotrestore'] = 'No';
|
||||
$string['dorestore'] = 'Yes';
|
||||
$string['download'] = 'Download';
|
||||
$string['downloadable'] = 'courses I can download';
|
||||
$string['downloadablecourses'] = 'Downloadable courses';
|
||||
$string['downloadconfirmed'] = 'The backup has been saved in your private files {$a}';
|
||||
$string['downloaded'] = '...finished.';
|
||||
$string['downloadingcourse'] = 'Downloading course';
|
||||
@@ -61,8 +62,9 @@ $string['enroldownload_help'] = 'Some courses listed in the selected hub are bei
|
||||
|
||||
Others are course templates provided for you to download and use on your own Moodle site.';
|
||||
$string['enrollable'] = 'courses I can enrol in';
|
||||
$string['errorcourselisting'] = 'An error occured when retrieving the course listing from the selected hub, please try again later. ({$a})';
|
||||
$string['errorhublisting'] = 'An error occured when retrieving the hub listing from Moodle.org, please try again later. ({$a})';
|
||||
$string['enrollablecourses'] = 'Enrollable courses';
|
||||
$string['errorcourselisting'] = 'An error occurred when retrieving the course listing from the selected hub, please try again later. ({$a})';
|
||||
$string['errorhublisting'] = 'An error occurred when retrieving the hub listing from Moodle.org, please try again later. ({$a})';
|
||||
$string['fileinfo'] = 'Language: {$a->lang} - License: {$a->license} - Time updated: {$a->timeupdated}';
|
||||
$string['hub'] = 'hub';
|
||||
$string['hubnottrusted'] = 'Not trusted';
|
||||
|
||||
+4
-88
@@ -66,75 +66,7 @@ M.core_dock.init = function(Y) {
|
||||
// Give the dock item class the event properties/methods
|
||||
Y.augment(this.item, Y.EventTarget);
|
||||
Y.augment(this, Y.EventTarget, true);
|
||||
/**
|
||||
* A 'dock:actionkey' Event.
|
||||
* The event consists of the left arrow, right arrow, enter and space keys.
|
||||
* More keys can be mapped to action meanings.
|
||||
* actions: collapse , expand, toggle, enter.
|
||||
*
|
||||
* This event is subscribed to by dockitems.
|
||||
* The on() method to subscribe allows specifying the desired trigger actions as JSON.
|
||||
*
|
||||
* This event can also be delegated if needed.
|
||||
* Todo: This could be centralised, a similar Event is defined in blocks/navigation/yui/navigation/navigation.js
|
||||
*/
|
||||
Y.Event.define("dock:actionkey", {
|
||||
// Webkit and IE repeat keydown when you hold down arrow keys.
|
||||
// Opera links keypress to page scroll; others keydown.
|
||||
// Firefox prevents page scroll via preventDefault() on either
|
||||
// keydown or keypress.
|
||||
_event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress',
|
||||
|
||||
_keys: {
|
||||
//arrows
|
||||
'37': 'collapse',
|
||||
'39': 'expand',
|
||||
//(@todo: lrt/rtl/M.core_dock.cfg.orientation decision to assign arrow to meanings)
|
||||
'32': 'toggle',
|
||||
'13': 'enter'
|
||||
},
|
||||
|
||||
_keyHandler: function (e, notifier, args) {
|
||||
if (!args.actions) {
|
||||
var actObj = {collapse:true, expand:true, toggle:true, enter:true};
|
||||
} else {
|
||||
var actObj = args.actions;
|
||||
}
|
||||
if (this._keys[e.keyCode] && actObj[this._keys[e.keyCode]]) {
|
||||
e.action = this._keys[e.keyCode];
|
||||
notifier.fire(e);
|
||||
}
|
||||
},
|
||||
|
||||
on: function (node, sub, notifier) {
|
||||
// subscribe to _event and ask keyHandler to handle with given args[0] (the desired actions).
|
||||
if (sub.args == null) {
|
||||
//no actions given
|
||||
sub._detacher = node.on(this._event, this._keyHandler,this, notifier, {actions:false});
|
||||
} else {
|
||||
sub._detacher = node.on(this._event, this._keyHandler,this, notifier, sub.args[0]);
|
||||
}
|
||||
},
|
||||
|
||||
detach: function (node, sub, notifier) {
|
||||
//detach our _detacher handle of the subscription made in on()
|
||||
sub._detacher.detach();
|
||||
},
|
||||
|
||||
delegate: function (node, sub, notifier, filter) {
|
||||
// subscribe to _event and ask keyHandler to handle with given args[0] (the desired actions).
|
||||
if (sub.args == null) {
|
||||
//no actions given
|
||||
sub._delegateDetacher = node.delegate(this._event, this._keyHandler,filter, this, notifier, {actions:false});
|
||||
} else {
|
||||
sub._delegateDetacher = node.delegate(this._event, this._keyHandler,filter, this, notifier, sub.args[0]);
|
||||
}
|
||||
},
|
||||
|
||||
detachDelegate: function (node, sub, notifier) {
|
||||
sub._delegateDetacher.detach();
|
||||
}
|
||||
});
|
||||
// Publish the events the dock has
|
||||
this.publish('dock:beforedraw', {prefix:'dock'});
|
||||
this.publish('dock:beforeshow', {prefix:'dock'});
|
||||
@@ -193,10 +125,9 @@ M.core_dock.init = function(Y) {
|
||||
|
||||
// Add a removeall button
|
||||
// Must set the image src seperatly of we get an error with XML strict headers
|
||||
var removeall = Y.Node.create('<img alt="'+M.str.block.undockall+'" title="'+M.str.block.undockall+'" tabindex="0"/>');
|
||||
var removeall = Y.Node.create('<img alt="'+M.str.block.undockall+'" title="'+M.str.block.undockall+'" />');
|
||||
removeall.setAttribute('src',this.cfg.removeallicon);
|
||||
removeall.on('removeall|click', this.remove_all, this);
|
||||
removeall.on('dock:actionkey', this.remove_all, this, {actions:{enter:true}});
|
||||
this.nodes.buttons.appendChild(Y.Node.create('<div class="'+css.controls+'"></div>').append(removeall));
|
||||
|
||||
// Create a manager for the height of the tabs. Once set this can be forgotten about
|
||||
@@ -659,7 +590,7 @@ M.core_dock.resetFirstItem = function() {
|
||||
* @function
|
||||
* @return {boolean}
|
||||
*/
|
||||
M.core_dock.remove_all = function(e) {
|
||||
M.core_dock.remove_all = function() {
|
||||
for (var i in this.items) {
|
||||
this.remove(i);
|
||||
}
|
||||
@@ -909,10 +840,9 @@ M.core_dock.genericblock.prototype = {
|
||||
}, this);
|
||||
// Add a close icon
|
||||
// Must set the image src seperatly of we get an error with XML strict headers
|
||||
var closeicon = Y.Node.create('<span class="hidepanelicon" tabindex="0"><img alt="" style="width:11px;height:11px;cursor:pointer;" /></span>');
|
||||
var closeicon = Y.Node.create('<span class="hidepanelicon"><img alt="" style="width:11px;height:11px;cursor:pointer;" /></span>');
|
||||
closeicon.one('img').setAttribute('src', M.util.image_url('t/dockclose', 'moodle'));
|
||||
closeicon.on('forceclose|click', this.hide, this);
|
||||
closeicon.on('dock:actionkey',this.hide, this, {actions:{enter:true,toggle:true}});
|
||||
this.commands.append(closeicon);
|
||||
}, dockitem);
|
||||
// Register an event so that when it is removed we can put it back as a block
|
||||
@@ -1025,8 +955,7 @@ M.core_dock.item.prototype = {
|
||||
|
||||
this.nodes.docktitle = Y.Node.create('<div id="dock_item_'+this.id+'_title" class="'+css.dockedtitle+'"></div>');
|
||||
this.nodes.docktitle.append(this.title);
|
||||
this.nodes.dockitem = Y.Node.create('<div id="dock_item_'+this.id+'" class="'+css.dockeditem+'" tabindex="0"></div>');
|
||||
this.nodes.dockitem.on('dock:actionkey', this.toggle, this);
|
||||
this.nodes.dockitem = Y.Node.create('<div id="dock_item_'+this.id+'" class="'+css.dockeditem+'"></div>');
|
||||
if (M.core_dock.count === 1) {
|
||||
this.nodes.dockitem.addClass('firstdockitem');
|
||||
}
|
||||
@@ -1070,19 +999,6 @@ M.core_dock.item.prototype = {
|
||||
M.core_dock.getPanel().hide();
|
||||
this.fire('dockeditem:hidecomplete');
|
||||
},
|
||||
/**
|
||||
* A toggle between calling show and hide functions based on css.activeitem
|
||||
* Applies rules to key press events (dock:actionkey)
|
||||
* @param {Event} e
|
||||
*/
|
||||
toggle : function(e) {
|
||||
var css = M.core_dock.css;
|
||||
if (this.nodes.docktitle.hasClass(css.activeitem) && !(e.type == 'dock:actionkey' && e.action=='expand')) {
|
||||
this.hide();
|
||||
} else if (!this.nodes.docktitle.hasClass(css.activeitem) && !(e.type == 'dock:actionkey' && e.action=='collapse')) {
|
||||
this.show();
|
||||
}
|
||||
},
|
||||
/**
|
||||
* This function removes the node and destroys it's bits
|
||||
* @param {Event} e
|
||||
|
||||
+23
-70
@@ -32,7 +32,6 @@ if (!defined('MOODLE_INTERNAL')) {
|
||||
}
|
||||
|
||||
require_once($CFG->libdir . '/formslib.php');
|
||||
require_once($CFG->libdir . '/blocklib.php');
|
||||
|
||||
/**
|
||||
* The base class form used by blocks/edit.php to edit block instance configuration.
|
||||
@@ -90,84 +89,40 @@ class block_edit_form extends moodleform {
|
||||
$parentcontext = get_context_instance_by_id($this->block->instance->parentcontextid);
|
||||
$mform->addElement('hidden', 'bui_parentcontextid', $parentcontext->id);
|
||||
|
||||
$mform->addElement('static', 'bui_homecontext', get_string('createdat', 'block'), print_context_name($parentcontext));
|
||||
$mform->addHelpButton('bui_homecontext', 'createdat', 'block');
|
||||
|
||||
// parse pagetype patterns
|
||||
$bits = explode('-', $this->page->pagetype);
|
||||
|
||||
$contextoptions = array();
|
||||
if ( ($parentcontext->contextlevel == CONTEXT_COURSE && $parentcontext->instanceid == SITEID) ||
|
||||
($parentcontext->contextlevel == CONTEXT_SYSTEM)) { // Home page
|
||||
if ($bits[0] == 'tag' || $bits[0] == 'admin') {
|
||||
// tag and admin pages always use system context
|
||||
// the contexts options don't make differences, so we use
|
||||
// page type patterns only
|
||||
$mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_ENTIRE_SITE);
|
||||
} else {
|
||||
$contextoptions[BUI_CONTEXTS_FRONTPAGE_ONLY] = get_string('showonfrontpageonly', 'block');
|
||||
$contextoptions[BUI_CONTEXTS_FRONTPAGE_SUBS] = get_string('showonfrontpageandsubs', 'block');
|
||||
$contextoptions[BUI_CONTEXTS_ENTIRE_SITE] = get_string('showonentiresite', 'block');
|
||||
$mform->addElement('select', 'bui_contexts', get_string('contexts', 'block'), $contextoptions);
|
||||
$mform->addHelpButton('bui_contexts', 'contexts', 'block');
|
||||
}
|
||||
} else if ($parentcontext->contextlevel == CONTEXT_COURSE) {
|
||||
// 0 means display on current context only, not child contexts
|
||||
// but if course managers select mod-* as pagetype patterns, block system will overwrite this option
|
||||
// to 1 (display on current context and child contexts)
|
||||
$mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_CURRENT);
|
||||
} else if ($parentcontext->contextlevel == CONTEXT_MODULE or $parentcontext->contextlevel == CONTEXT_USER) {
|
||||
// module context doesn't have child contexts, so display in current context only
|
||||
$mform->addElement('hidden', 'bui_contexts', BUI_CONTEXTS_CURRENT);
|
||||
($parentcontext->contextlevel == CONTEXT_SYSTEM)) { // Home page
|
||||
$contextoptions[0] = get_string('showonfrontpageonly', 'block');
|
||||
$contextoptions[1] = get_string('showonfrontpageandsubs', 'block');
|
||||
$contextoptions[2] = get_string('showonentiresite', 'block');
|
||||
} else {
|
||||
$parentcontextname = print_context_name($parentcontext);
|
||||
$contextoptions[BUI_CONTEXTS_CURRENT] = get_string('showoncontextonly', 'block', $parentcontextname);
|
||||
$contextoptions[BUI_CONTEXTS_CURRENT_SUBS] = get_string('showoncontextandsubs', 'block', $parentcontextname);
|
||||
$mform->addElement('select', 'bui_contexts', get_string('contexts', 'block'), $contextoptions);
|
||||
$contextoptions[0] = get_string('showoncontextonly', 'block', $parentcontextname);
|
||||
$contextoptions[1] = get_string('showoncontextandsubs', 'block', $parentcontextname);
|
||||
}
|
||||
$mform->addElement('select', 'bui_contexts', get_string('contexts', 'block'), $contextoptions);
|
||||
|
||||
$displaypagetypewarning = false;
|
||||
if ($this->page->pagetype == 'site-index') { // No need for pagetype list on home page
|
||||
$pagetypelist = array('*'=>get_string('page-x', 'pagetype'));
|
||||
$pagetypelist = array('*');
|
||||
} else {
|
||||
// Generate pagetype patterns by callbacks
|
||||
$pagetypelist = generate_page_type_patterns($this->page->pagetype, $parentcontext, $this->page->context);
|
||||
if (!array_key_exists($this->block->instance->pagetypepattern, $pagetypelist)) {
|
||||
// Pushing block's existing page type pattern
|
||||
$pagetypestringname = 'page-'.str_replace('*', 'x', $this->block->instance->pagetypepattern);
|
||||
if (get_string_manager()->string_exists($pagetypestringname, 'pagetype')) {
|
||||
$pagetypelist[$this->block->instance->pagetypepattern] = get_string($pagetypestringname, 'pagetype');
|
||||
} else {
|
||||
//as a last resort we could put the page type pattern in the select box
|
||||
//however this causes mod-data-view to be added if the only option available is mod-data-*
|
||||
// so we are just showing a warning to users about their prev setting being reset
|
||||
$displaypagetypewarning = true;
|
||||
}
|
||||
$pagetypelist = matching_page_type_patterns($this->page->pagetype);
|
||||
}
|
||||
$pagetypeoptions = array();
|
||||
foreach ($pagetypelist as $pagetype) { // Find human-readable names for the pagetypes
|
||||
$pagetypeoptions[$pagetype] = $pagetype;
|
||||
$pagetypestringname = 'page-'.str_replace('*', 'x',$pagetype); // Better names MDL-21375
|
||||
if (get_string_manager()->string_exists($pagetypestringname, 'pagetype')) {
|
||||
$pagetypeoptions[$pagetype] .= ' (' . get_string($pagetypestringname, 'pagetype') . ')';
|
||||
}
|
||||
}
|
||||
|
||||
// hide page type pattern select box if there is only one choice
|
||||
if (count($pagetypelist) > 1) {
|
||||
if ($displaypagetypewarning) {
|
||||
$mform->addElement('static', 'pagetypewarning', '', get_string('pagetypewarning','block'));
|
||||
}
|
||||
|
||||
$mform->addElement('select', 'bui_pagetypepattern', get_string('restrictpagetypes', 'block'), $pagetypelist);
|
||||
} else {
|
||||
$value = array_pop(array_keys($pagetypelist));
|
||||
$mform->addElement('hidden', 'bui_pagetypepattern', $value);
|
||||
}
|
||||
$mform->addElement('select', 'bui_pagetypepattern', get_string('restrictpagetypes', 'block'), $pagetypeoptions);
|
||||
|
||||
if ($this->page->subpage) {
|
||||
if ($parentcontext->contextlevel == CONTEXT_USER) {
|
||||
$mform->addElement('hidden', 'bui_subpagepattern', '%@NULL@%');
|
||||
} else {
|
||||
$subpageoptions = array(
|
||||
'%@NULL@%' => get_string('anypagematchingtheabove', 'block'),
|
||||
$this->page->subpage => get_string('thisspecificpage', 'block', $this->page->subpage),
|
||||
);
|
||||
$mform->addElement('select', 'bui_subpagepattern', get_string('subpages', 'block'), $subpageoptions);
|
||||
}
|
||||
$subpageoptions = array(
|
||||
'%@NULL@%' => get_string('anypagematchingtheabove', 'block'),
|
||||
$this->page->subpage => get_string('thisspecificpage', 'block', $this->page->subpage),
|
||||
);
|
||||
$mform->addElement('select', 'bui_subpagepattern', get_string('subpages', 'block'), $subpageoptions);
|
||||
}
|
||||
|
||||
$defaultregionoptions = $regionoptions;
|
||||
@@ -176,10 +131,8 @@ class block_edit_form extends moodleform {
|
||||
$defaultregionoptions[$defaultregion] = $defaultregion;
|
||||
}
|
||||
$mform->addElement('select', 'bui_defaultregion', get_string('defaultregion', 'block'), $defaultregionoptions);
|
||||
$mform->addHelpButton('bui_defaultregion', 'defaultregion', 'block');
|
||||
|
||||
$mform->addElement('select', 'bui_defaultweight', get_string('defaultweight', 'block'), $weightoptions);
|
||||
$mform->addHelpButton('bui_defaultweight', 'defaultweight', 'block');
|
||||
|
||||
// Where this block is positioned on this page.
|
||||
$mform->addElement('header', 'whereheader', get_string('onthispage', 'block'));
|
||||
@@ -229,7 +182,7 @@ class block_edit_form extends moodleform {
|
||||
|
||||
$systemcontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
if ($defaults->parentcontextid == $systemcontext->id) {
|
||||
$defaults->bui_contexts = BUI_CONTEXTS_ENTIRE_SITE; // System-wide and sticky
|
||||
$defaults->bui_contexts = 2; // System-wide and sticky
|
||||
} else {
|
||||
$defaults->bui_contexts = $defaults->bui_showinsubcontexts;
|
||||
}
|
||||
|
||||
@@ -62,7 +62,14 @@ class block_html extends block_base {
|
||||
if (isset($this->config->text)) {
|
||||
// rewrite url
|
||||
$this->config->text = file_rewrite_pluginfile_urls($this->config->text, 'pluginfile.php', $this->context->id, 'block_html', 'content', NULL);
|
||||
$this->content->text = format_text($this->config->text, $this->config->format, $filteropt);
|
||||
// Default to FORMAT_HTML which is what will have been used before the
|
||||
// editor was properly implemented for the block.
|
||||
$format = FORMAT_HTML;
|
||||
// Check to see if the format has been properly set on the config
|
||||
if (isset($this->config->format)) {
|
||||
$format = $this->config->format;
|
||||
}
|
||||
$this->content->text = format_text($this->config->text, $format, $filteropt);
|
||||
} else {
|
||||
$this->content->text = '';
|
||||
}
|
||||
|
||||
@@ -63,8 +63,5 @@ function xmldb_block_html_upgrade($oldversion) {
|
||||
upgrade_block_savepoint(true, 2010071900, 'html');
|
||||
}
|
||||
|
||||
// Moodle v2.1.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,11 +57,24 @@ class block_html_edit_form extends block_edit_form {
|
||||
} else {
|
||||
$text = '';
|
||||
}
|
||||
|
||||
if (!$this->block->user_can_edit() && !empty($this->block->config->title)) {
|
||||
// If a title has been set but the user cannot edit it format it nicely
|
||||
$title = $this->block->config->title;
|
||||
$defaults->config_title = format_string($title, true, $this->page->context);
|
||||
// Remove the title from the config so that parent::set_data doesn't set it.
|
||||
unset($this->block->config->title);
|
||||
}
|
||||
|
||||
// have to delete text here, otherwise parent::set_data will empty content
|
||||
// of editor
|
||||
unset($this->block->config->text);
|
||||
parent::set_data($defaults);
|
||||
// restore $text
|
||||
$this->block->config->text = $text;
|
||||
if (isset($title)) {
|
||||
// Reset the preserved title
|
||||
$this->block->config->title = $title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +72,5 @@ function xmldb_block_navigation_upgrade($oldversion, $block) {
|
||||
upgrade_block_savepoint(true, 2010091400, 'navigation');
|
||||
}
|
||||
|
||||
// Moodle v2.1.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -52,7 +52,6 @@ class block_navigation_renderer extends plugin_renderer_base {
|
||||
$attributes['class'] = 'dimmed_text';
|
||||
}
|
||||
if (is_string($item->action) || empty($item->action) || ($item->type === navigation_node::TYPE_CATEGORY && empty($options['linkcategories']))) {
|
||||
$attributes['tabindex'] = '0'; //add tab support to span but still maintain character stream sequence.
|
||||
$content = html_writer::tag('span', $content, $attributes);
|
||||
} else if ($item->action instanceof action_link) {
|
||||
//TODO: to be replaced with something else
|
||||
|
||||
+8
-108
@@ -1,74 +1,5 @@
|
||||
YUI.add('moodle-block_navigation-navigation', function(Y){
|
||||
|
||||
/**
|
||||
* A 'actionkey' Event to help with Y.delegate().
|
||||
* The event consists of the left arrow, right arrow, enter and space keys.
|
||||
* More keys can be mapped to action meanings.
|
||||
* actions: collapse , expand, toggle, enter.
|
||||
*
|
||||
* This event is delegated to branches in the navigation tree.
|
||||
* The on() method to subscribe allows specifying the desired trigger actions as JSON.
|
||||
*
|
||||
* Todo: This could be centralised, a similar Event is defined in blocks/dock.js
|
||||
*/
|
||||
Y.Event.define("actionkey", {
|
||||
// Webkit and IE repeat keydown when you hold down arrow keys.
|
||||
// Opera links keypress to page scroll; others keydown.
|
||||
// Firefox prevents page scroll via preventDefault() on either
|
||||
// keydown or keypress.
|
||||
_event: (Y.UA.webkit || Y.UA.ie) ? 'keydown' : 'keypress',
|
||||
|
||||
_keys: {
|
||||
//arrows
|
||||
'37': 'collapse',
|
||||
'39': 'expand',
|
||||
//(@todo: lrt/rtl/M.core_dock.cfg.orientation decision to assign arrow to meanings)
|
||||
'32': 'toggle',
|
||||
'13': 'enter'
|
||||
},
|
||||
|
||||
_keyHandler: function (e, notifier, args) {
|
||||
if (!args.actions) {
|
||||
var actObj = {collapse:true, expand:true, toggle:true, enter:true};
|
||||
} else {
|
||||
var actObj = args.actions;
|
||||
}
|
||||
if (this._keys[e.keyCode] && actObj[this._keys[e.keyCode]]) {
|
||||
e.action = this._keys[e.keyCode];
|
||||
notifier.fire(e);
|
||||
}
|
||||
},
|
||||
|
||||
on: function (node, sub, notifier) {
|
||||
// subscribe to _event and ask keyHandler to handle with given args[0] (the desired actions).
|
||||
if (sub.args == null) {
|
||||
//no actions given
|
||||
sub._detacher = node.on(this._event, this._keyHandler,this, notifier, {actions:false});
|
||||
} else {
|
||||
sub._detacher = node.on(this._event, this._keyHandler,this, notifier, sub.args[0]);
|
||||
}
|
||||
},
|
||||
|
||||
detach: function (node, sub, notifier) {
|
||||
//detach our _detacher handle of the subscription made in on()
|
||||
sub._detacher.detach();
|
||||
},
|
||||
|
||||
delegate: function (node, sub, notifier, filter) {
|
||||
// subscribe to _event and ask keyHandler to handle with given args[0] (the desired actions).
|
||||
if (sub.args == null) {
|
||||
//no actions given
|
||||
sub._delegateDetacher = node.delegate(this._event, this._keyHandler,filter, this, notifier, {actions:false});
|
||||
} else {
|
||||
sub._delegateDetacher = node.delegate(this._event, this._keyHandler,filter, this, notifier, sub.args[0]);
|
||||
}
|
||||
},
|
||||
|
||||
detachDelegate: function (node, sub, notifier) {
|
||||
sub._delegateDetacher.detach();
|
||||
}
|
||||
});
|
||||
|
||||
var EXPANSIONLIMIT_EVERYTHING = 0,
|
||||
EXPANSIONLIMIT_COURSE = 20,
|
||||
EXPANSIONLIMIT_SECTION = 30,
|
||||
@@ -105,7 +36,6 @@ TREE.prototype = {
|
||||
// Delegate event to toggle expansion
|
||||
var self = this;
|
||||
Y.delegate('click', function(e){self.toggleExpansion(e);}, node.one('.block_tree'), '.tree_item.branch');
|
||||
Y.delegate('actionkey', function(e){self.toggleExpansion(e);}, node.one('.block_tree'), '.tree_item.branch');
|
||||
|
||||
// Gather the expandable branches ready for initialisation.
|
||||
var expansions = [];
|
||||
@@ -141,8 +71,8 @@ TREE.prototype = {
|
||||
// First check if they managed to click on the li iteslf, then find the closest
|
||||
// LI ancestor and use that
|
||||
|
||||
if (e.target.test('a') && (e.keyCode == 0 || e.keyCode == 13)) {
|
||||
// A link has been clicked (or keypress is 'enter') don't fire any more events just do the default.
|
||||
if (e.target.test('a')) {
|
||||
// A link has been clicked don't fire any more events just do the default.
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
@@ -158,21 +88,7 @@ TREE.prototype = {
|
||||
|
||||
// Toggle expand/collapse providing its not a root level branch.
|
||||
if (!target.hasClass('depth_1')) {
|
||||
if (e.type == 'actionkey') {
|
||||
switch (e.action) {
|
||||
case 'expand' :
|
||||
target.removeClass('collapsed');
|
||||
break;
|
||||
case 'collapse' :
|
||||
target.addClass('collapsed');
|
||||
break;
|
||||
default :
|
||||
target.toggleClass('collapsed');
|
||||
}
|
||||
e.halt();
|
||||
} else {
|
||||
target.toggleClass('collapsed');
|
||||
}
|
||||
target.toggleClass('collapsed');
|
||||
}
|
||||
|
||||
// If the accordian feature has been enabled collapse all siblings.
|
||||
@@ -236,10 +152,9 @@ BRANCH.prototype = {
|
||||
*/
|
||||
node : null,
|
||||
/**
|
||||
* A reference to the ajax load event handlers when created.
|
||||
* A reference to the ajax load event handle when created.
|
||||
*/
|
||||
event_ajaxload : null,
|
||||
event_ajaxload_actionkey : null,
|
||||
/**
|
||||
* Initialises the branch when it is first created.
|
||||
*/
|
||||
@@ -278,13 +193,8 @@ BRANCH.prototype = {
|
||||
|
||||
var isbranch = (this.get('expandable') || this.get('haschildren'));
|
||||
var branchli = Y.Node.create('<li></li>');
|
||||
var link = this.get('link');
|
||||
var branchp = Y.Node.create('<p class="tree_item"></p>').setAttribute('id', this.get('id'));
|
||||
if (!link) {
|
||||
//add tab focus if not link (so still one focus per menu node).
|
||||
// it was suggested to have 2 foci. one for the node and one for the link in MDL-27428.
|
||||
branchp.setAttribute('tabindex', '0');
|
||||
}
|
||||
|
||||
if (isbranch) {
|
||||
branchli.addClass('collapsed').addClass('contains_branch');
|
||||
branchp.addClass('branch');
|
||||
@@ -310,6 +220,7 @@ BRANCH.prototype = {
|
||||
}
|
||||
}
|
||||
|
||||
var link = this.get('link');
|
||||
if (!link) {
|
||||
if (branchicon) {
|
||||
branchp.appendChild(branchicon);
|
||||
@@ -342,7 +253,6 @@ BRANCH.prototype = {
|
||||
}
|
||||
if (this.get('expandable')) {
|
||||
this.event_ajaxload = this.node.on('ajaxload|click', this.ajaxLoad, this);
|
||||
this.event_ajaxload_actionkey = this.node.on('actionkey', this.ajaxLoad, this);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
@@ -364,16 +274,7 @@ BRANCH.prototype = {
|
||||
* request made here.
|
||||
*/
|
||||
ajaxLoad : function(e) {
|
||||
if (e.type == 'actionkey' && e.action != 'enter') {
|
||||
e.halt();
|
||||
} else {
|
||||
e.stopPropagation();
|
||||
}
|
||||
if (e.type = 'actionkey' && e.action == 'enter' && e.target.test('A')) {
|
||||
this.event_ajaxload_actionkey.detach();
|
||||
this.event_ajaxload.detach();
|
||||
return true; // no ajaxLoad for enter
|
||||
}
|
||||
e.stopPropagation();
|
||||
|
||||
if (this.node.hasClass('loadingbranch')) {
|
||||
return true;
|
||||
@@ -406,7 +307,6 @@ BRANCH.prototype = {
|
||||
ajaxProcessResponse : function(tid, outcome) {
|
||||
this.node.removeClass('loadingbranch');
|
||||
this.event_ajaxload.detach();
|
||||
this.event_ajaxload_actionkey.detach();
|
||||
try {
|
||||
var object = Y.JSON.parse(outcome.responseText);
|
||||
if (object.children && object.children.length > 0) {
|
||||
@@ -555,4 +455,4 @@ M.block_navigation = M.block_navigation || {
|
||||
}
|
||||
};
|
||||
|
||||
}, '@VERSION@', {requires:['base', 'core_dock', 'io', 'node', 'dom', 'event-custom', 'event-delegate', 'json-parse']});
|
||||
}, '@VERSION@', {requires:['base', 'core_dock', 'io', 'node', 'dom', 'event-custom', 'event-delegate', 'json-parse']});
|
||||
@@ -140,7 +140,9 @@ class feed_edit_form extends moodleform {
|
||||
return $url;
|
||||
}
|
||||
|
||||
return $rss->subscribe_url();
|
||||
// return URL without quoting..
|
||||
$discoveredurl = new moodle_url($rss->subscribe_url());
|
||||
return $discoveredurl->out(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ class block_search extends block_base {
|
||||
'<form id="searchquery" method="get" action="'. $CFG->wwwroot .'/search/query.php"><div>'
|
||||
. '<label for="block_search_q">' . get_string('searchmoodle', 'block_search') . '</label>'
|
||||
. '<input id="block_search_q" type="text" name="query_string" />'
|
||||
. '<input id="block_instance_id" type="hidden" name="block_instanceid" value="' . $this->instance->id . '"/>'
|
||||
. '<input type="submit" value="' . s(get_string('go', 'block_search')) . '" />'
|
||||
. '</div></form>';
|
||||
|
||||
|
||||
@@ -72,8 +72,5 @@ function xmldb_block_settings_upgrade($oldversion, $block) {
|
||||
upgrade_block_savepoint(true, 2010091400, 'settings');
|
||||
}
|
||||
|
||||
// Moodle v2.1.0 release upgrade line
|
||||
// Put any upgrade step following this
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1028,18 +1028,3 @@ function blog_comment_validate($comment_param) {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of page types
|
||||
* @param string $pagetype current page type
|
||||
* @param stdClass $parentcontext Block's parent context
|
||||
* @param stdClass $currentcontext Current context of block
|
||||
*/
|
||||
function blog_page_type_list($pagetype, $parentcontext, $currentcontext) {
|
||||
return array(
|
||||
'*'=>get_string('page-x', 'pagetype'),
|
||||
'blog-*'=>get_string('page-blog-x', 'blog'),
|
||||
'blog-index'=>get_string('page-blog-index', 'blog'),
|
||||
'blog-edit'=>get_string('page-blog-edit', 'blog')
|
||||
);
|
||||
}
|
||||
|
||||
+70
-50
@@ -55,43 +55,26 @@ require_login();
|
||||
|
||||
$action = optional_param('action', 'new', PARAM_ALPHA);
|
||||
$eventid = optional_param('id', 0, PARAM_INT);
|
||||
$courseid = optional_param('courseid', SITEID, PARAM_INT);
|
||||
$courseid = optional_param('course', $courseid, PARAM_INT);
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT);
|
||||
$cal_y = optional_param('cal_y', 0, PARAM_INT);
|
||||
$cal_m = optional_param('cal_m', 0, PARAM_INT);
|
||||
$cal_d = optional_param('cal_d', 0, PARAM_INT);
|
||||
|
||||
$url = new moodle_url('/calendar/event.php', array('action' => $action));
|
||||
if ($eventid != 0) {
|
||||
$url->param('id', $eventid);
|
||||
}
|
||||
if ($courseid != SITEID) {
|
||||
$url->param('course', $courseid);
|
||||
}
|
||||
if ($cal_y !== 0) {
|
||||
$url->param('cal_y', $cal_y);
|
||||
}
|
||||
if ($cal_m !== 0) {
|
||||
$url->param('cal_m', $cal_m);
|
||||
}
|
||||
if ($cal_d !== 0) {
|
||||
$url->param('cal_d', $cal_d);
|
||||
if ($courseid === 0) {
|
||||
$courseid = optional_param('course', 0, PARAM_INT);
|
||||
}
|
||||
|
||||
$url = new moodle_url('/calendar/event.php', array('action'=>$action));
|
||||
if ($eventid !== 0) $url->param('id', $eventid);
|
||||
if ($courseid !== 0) $url->param('course', $courseid);
|
||||
if ($cal_y !== 0) $url->param('cal_y', $cal_y);
|
||||
if ($cal_m !== 0) $url->param('cal_m', $cal_m);
|
||||
if ($cal_d !== 0) $url->param('cal_d', $cal_d);
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
|
||||
$PAGE->set_pagelayout('standard');
|
||||
|
||||
if ($courseid != SITEID && !empty($courseid)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
$courses = array($course->id => $course);
|
||||
$issite = false;
|
||||
} else {
|
||||
$course = get_site();
|
||||
$courses = calendar_get_default_courses();
|
||||
$issite = true;
|
||||
}
|
||||
require_login($course, false);
|
||||
|
||||
if ($action === 'delete' && $eventid > 0) {
|
||||
if ($action === 'delete' && $eventid>0) {
|
||||
$deleteurl = new moodle_url('/calendar/delete.php', array('id'=>$eventid));
|
||||
if ($courseid > 0) {
|
||||
$deleteurl->param('course', $courseid);
|
||||
@@ -99,10 +82,56 @@ if ($action === 'delete' && $eventid > 0) {
|
||||
redirect($deleteurl);
|
||||
}
|
||||
|
||||
$viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php');
|
||||
$viewcalendarurl->params($PAGE->url->params());
|
||||
$viewcalendarurl->remove_params(array('id','action'));
|
||||
|
||||
$now = usergetdate(time());
|
||||
|
||||
if (isguestuser()) {
|
||||
// Guests cannot do anything with events
|
||||
redirect(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$courseid)));
|
||||
}
|
||||
|
||||
$focus = '';
|
||||
|
||||
$site = get_site();
|
||||
|
||||
calendar_session_vars();
|
||||
|
||||
// If a course has been supplied in the URL, change the filters to show that one
|
||||
$courseexists = false;
|
||||
if ($courseid > 0) {
|
||||
if ($courseid == SITEID) {
|
||||
// If coming from the site page, show all courses
|
||||
$SESSION->cal_courses_shown = calendar_get_default_courses(true);
|
||||
calendar_set_referring_course(0);
|
||||
} else if ($DB->record_exists('course', array('id'=>$courseid))) {
|
||||
$courseexists = true;
|
||||
// Otherwise show just this one
|
||||
$SESSION->cal_courses_shown = $courseid;
|
||||
calendar_set_referring_course($SESSION->cal_courses_shown);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($SESSION->cal_course_referer)) {
|
||||
// TODO: This is part of the Great $course Hack in Moodle. Replace it at some point.
|
||||
$course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer));
|
||||
} else {
|
||||
$course = $site;
|
||||
}
|
||||
|
||||
require_login($course, false);
|
||||
|
||||
$calendar = new calendar_information($cal_d, $cal_m, $cal_y);
|
||||
$calendar->prepare_for_view($course, $courses);
|
||||
$calendar->courseid = $courseid;
|
||||
|
||||
$strcalendar = get_string('calendar', 'calendar');
|
||||
$link = clone($viewcalendarurl);
|
||||
$link->param('view', 'upcoming');
|
||||
|
||||
$formoptions = new stdClass;
|
||||
|
||||
if ($eventid !== 0) {
|
||||
$title = get_string('editevent', 'calendar');
|
||||
$event = calendar_event::load($eventid);
|
||||
@@ -119,13 +148,13 @@ if ($eventid !== 0) {
|
||||
}
|
||||
} else {
|
||||
$title = get_string('newevent', 'calendar');
|
||||
calendar_get_allowed_types($formoptions->eventtypes, $course);
|
||||
calendar_get_allowed_types($formoptions->eventtypes, $USER->id);
|
||||
$event = new stdClass();
|
||||
$event->action = $action;
|
||||
$event->course = $courseid;
|
||||
$event->timeduration = 0;
|
||||
if ($formoptions->eventtypes->courses) {
|
||||
if (!$issite) {
|
||||
if ($courseexists) {
|
||||
$event->courseid = $courseid;
|
||||
$event->eventtype = 'course';
|
||||
} else {
|
||||
@@ -136,7 +165,6 @@ if ($eventid !== 0) {
|
||||
if($cal_y && $cal_m && $cal_d && checkdate($cal_m, $cal_d, $cal_y)) {
|
||||
$event->timestart = make_timestamp($cal_y, $cal_m, $cal_d, 0, 0, 0);
|
||||
} else if($cal_y && $cal_m && checkdate($cal_m, 1, $cal_y)) {
|
||||
$now = usergetdate(time());
|
||||
if($cal_y == $now['year'] && $cal_m == $now['mon']) {
|
||||
$event->timestart = make_timestamp($cal_y, $cal_m, $now['mday'], 0, 0, 0);
|
||||
} else {
|
||||
@@ -165,31 +193,23 @@ if ($data) {
|
||||
}
|
||||
|
||||
$event->update($data);
|
||||
|
||||
$params = array(
|
||||
'view' => 'day',
|
||||
'cal_d' => date('j', $event->timestart),
|
||||
'cal_m' => date('n', $event->timestart),
|
||||
'cal_y' => date('y', $event->timestart),
|
||||
);
|
||||
$eventurl = new moodle_url('/calendar/view.php', $params);
|
||||
if (!empty($event->courseid) && $event->courseid != SITEID) {
|
||||
$eventurl = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'day'));
|
||||
if (!empty($event->courseid)) {
|
||||
$eventurl->param('course', $event->courseid);
|
||||
}
|
||||
$eventurl->param('cal_d', date('j', $event->timestart));
|
||||
$eventurl->param('cal_m', date('n', $event->timestart));
|
||||
$eventurl->param('cal_y', date('Y', $event->timestart));
|
||||
$eventurl->set_anchor('event_'.$event->id);
|
||||
redirect($eventurl);
|
||||
}
|
||||
|
||||
$viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php', $PAGE->url->params());
|
||||
$viewcalendarurl->remove_params(array('id', 'action'));
|
||||
$viewcalendarurl->param('view', 'upcoming');
|
||||
$strcalendar = get_string('calendar', 'calendar');
|
||||
|
||||
$PAGE->navbar->add($strcalendar, $viewcalendarurl);
|
||||
$PAGE->navbar->add($strcalendar, $link);
|
||||
$PAGE->navbar->add($title);
|
||||
$PAGE->set_title($course->shortname.': '.$strcalendar.': '.$title);
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$title);
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
|
||||
calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users);
|
||||
$renderer = $PAGE->get_renderer('core_calendar');
|
||||
$calendar->add_sidecalendar_blocks($renderer);
|
||||
|
||||
|
||||
+49
-31
@@ -49,27 +49,17 @@
|
||||
require_once('../config.php');
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
//require_once($CFG->libdir.'/bennu/bennu.inc.php');
|
||||
|
||||
if (empty($CFG->enablecalendarexport)) {
|
||||
die('no export');
|
||||
}
|
||||
|
||||
$courseid = optional_param('course', SITEID, PARAM_INT);
|
||||
$action = optional_param('action', '', PARAM_ALPHA);
|
||||
$day = optional_param('cal_d', 0, PARAM_INT);
|
||||
$mon = optional_param('cal_m', 0, PARAM_INT);
|
||||
$yr = optional_param('cal_y', 0, PARAM_INT);
|
||||
|
||||
if ($courseid != SITEID && !empty($courseid)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid));
|
||||
$courses = array($course->id => $course);
|
||||
$issite = false;
|
||||
if ($courseid = optional_param('course', 0, PARAM_INT)) {
|
||||
$course = $DB->get_record('course', array('id'=>$courseid));
|
||||
} else {
|
||||
$course = get_site();
|
||||
$courses = calendar_get_default_courses();
|
||||
$issite = true;
|
||||
$course = NULL;
|
||||
}
|
||||
require_course_login($course);
|
||||
|
||||
$url = new moodle_url('/calendar/export.php');
|
||||
if ($action !== '') {
|
||||
@@ -89,22 +79,57 @@ if ($course !== NULL) {
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
|
||||
$calendar = new calendar_information($day, $mon, $yr);
|
||||
$calendar->prepare_for_view($course, $courses);
|
||||
require_login($course);
|
||||
if (!$course) {
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
|
||||
}
|
||||
|
||||
if (empty($CFG->enablecalendarexport)) {
|
||||
die('no export');
|
||||
}
|
||||
|
||||
$site = get_site();
|
||||
|
||||
// Initialize the session variables
|
||||
calendar_session_vars();
|
||||
|
||||
$pagetitle = get_string('export', 'calendar');
|
||||
$navlinks = array();
|
||||
$now = usergetdate(time());
|
||||
|
||||
// Print title and header
|
||||
if ($issite) {
|
||||
if (!empty($courseid) && $course->id != SITEID) {
|
||||
$PAGE->navbar->add($course->shortname, new moodle_url('/course/view.php', array('id'=>$course->id)));
|
||||
}
|
||||
|
||||
$calendar = new calendar_information($day, $mon, $yr);
|
||||
$calendar->courseid = $courseid;
|
||||
|
||||
|
||||
if(!checkdate($mon, $day, $yr)) {
|
||||
$day = intval($now['mday']);
|
||||
$mon = intval($now['mon']);
|
||||
$yr = intval($now['year']);
|
||||
}
|
||||
$time = make_timestamp($yr, $mon, $day);
|
||||
|
||||
if (!isloggedin() or isguestuser()) {
|
||||
$defaultcourses = calendar_get_default_courses();
|
||||
calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users, $defaultcourses, $defaultcourses);
|
||||
} else {
|
||||
calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users);
|
||||
}
|
||||
|
||||
$strcalendar = get_string('calendar', 'calendar');
|
||||
$prefsbutton = calendar_preferences_button();
|
||||
|
||||
// Print title and header
|
||||
$link = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$calendar->courseid));
|
||||
$PAGE->navbar->add(get_string('calendar', 'calendar'), calendar_get_link_href($link, $now['mday'], $now['mon'], $now['year']));
|
||||
$PAGE->navbar->add($pagetitle);
|
||||
|
||||
$PAGE->set_title($course->shortname.': '.get_string('calendar', 'calendar').': '.$pagetitle);
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_button(calendar_preferences_button($course));
|
||||
$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$pagetitle);
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
$PAGE->set_button($prefsbutton);
|
||||
$PAGE->set_pagelayout('standard');
|
||||
|
||||
$renderer = $PAGE->get_renderer('core_calendar');
|
||||
@@ -114,26 +139,19 @@ echo $OUTPUT->header();
|
||||
echo $renderer->start_layout();
|
||||
switch($action) {
|
||||
case 'advanced':
|
||||
// Why nothing?
|
||||
break;
|
||||
break;
|
||||
case '':
|
||||
default:
|
||||
$weekend = CALENDAR_DEFAULT_WEEKEND;
|
||||
if (isset($CFG->calendar_weekend)) {
|
||||
$weekend = intval($CFG->calendar_weekend);
|
||||
}
|
||||
$username = $USER->username;
|
||||
$authtoken = sha1($USER->username . $USER->password . $CFG->calendar_exportsalt);
|
||||
// Let's populate some vars to let "common tasks" be somewhat smart...
|
||||
// If today it's weekend, give the "next week" option
|
||||
$allownextweek = $weekend & (1 << $now['wday']);
|
||||
$allownextweek = CALENDAR_WEEKEND & (1 << $now['wday']);
|
||||
// If it's the last week of the month, give the "next month" option
|
||||
$allownextmonth = calendar_days_in_month($now['mon'], $now['year']) - $now['mday'] < 7;
|
||||
// If today it's weekend but tomorrow it isn't, do NOT give the "this week" option
|
||||
$allowthisweek = !(($weekend & (1 << $now['wday'])) && !($weekend & (1 << (($now['wday'] + 1) % 7))));
|
||||
$allowthisweek = !((CALENDAR_WEEKEND & (1 << $now['wday'])) && !(CALENDAR_WEEKEND & (1 << (($now['wday'] + 1) % 7))));
|
||||
echo $renderer->basic_export_form($allowthisweek, $allownextweek, $allownextmonth, $username, $authtoken);
|
||||
break;
|
||||
}
|
||||
|
||||
echo $renderer->complete_layout();
|
||||
echo $OUTPUT->footer();
|
||||
|
||||
+299
-229
@@ -45,29 +45,20 @@ define('CALENDAR_DEFAULT_STARTING_WEEKDAY', 1);
|
||||
// This is a packed bitfield: day X is "weekend" if $field & (1 << X) is true
|
||||
// Default value = 65 = 64 + 1 = 2^6 + 2^0 = Saturday & Sunday
|
||||
define('CALENDAR_DEFAULT_WEEKEND', 65);
|
||||
define('CALENDAR_UPCOMING_DAYS', isset($CFG->calendar_lookahead) ? intval($CFG->calendar_lookahead) : CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD);
|
||||
define('CALENDAR_UPCOMING_MAXEVENTS', isset($CFG->calendar_maxevents) ? intval($CFG->calendar_maxevents) : CALENDAR_DEFAULT_UPCOMING_MAXEVENTS);
|
||||
define('CALENDAR_WEEKEND', isset($CFG->calendar_weekend) ? intval($CFG->calendar_weekend) : CALENDAR_DEFAULT_WEEKEND);
|
||||
define('CALENDAR_URL', $CFG->wwwroot.'/calendar/');
|
||||
define('CALENDAR_TF_24', '%H:%M');
|
||||
define('CALENDAR_TF_12', '%I:%M %p');
|
||||
|
||||
define('CALENDAR_EVENT_GLOBAL', 1);
|
||||
define('CALENDAR_EVENT_COURSE', 2);
|
||||
define('CALENDAR_EVENT_GROUP', 4);
|
||||
define('CALENDAR_EVENT_USER', 8);
|
||||
|
||||
/**
|
||||
* CALENDAR_STARTING_WEEKDAY has since been deprecated please call calendar_get_starting_weekday() instead
|
||||
* @deprecated
|
||||
*/
|
||||
define('CALENDAR_STARTING_WEEKDAY', CALENDAR_DEFAULT_STARTING_WEEKDAY);
|
||||
|
||||
/**
|
||||
* Return the days of the week
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function calendar_get_days() {
|
||||
return array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
|
||||
}
|
||||
$CALENDARDAYS = array('sunday','monday','tuesday','wednesday','thursday','friday','saturday');
|
||||
|
||||
/**
|
||||
* Gets the first day of the week
|
||||
@@ -206,7 +197,8 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
|
||||
calendar_events_by_day($events, $m, $y, $eventsbyday, $durationbyday, $typesbyday, $courses);
|
||||
|
||||
//Accessibility: added summary and <abbr> elements.
|
||||
$days_title = calendar_get_days();
|
||||
///global $CALENDARDAYS; appears to be broken.
|
||||
$days_title = array('sunday','monday','tuesday','wednesday','thursday','friday','saturday');
|
||||
|
||||
$summary = get_string('calendarheading', 'calendar', userdate(make_timestamp($y, $m), get_string('strftimemonthyear')));
|
||||
$summary = get_string('tabledata', 'access', $summary);
|
||||
@@ -232,11 +224,6 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
|
||||
$content .= '<td class="dayblank"> </td>'."\n";
|
||||
}
|
||||
|
||||
$weekend = CALENDAR_DEFAULT_WEEKEND;
|
||||
if (isset($CFG->calendar_weekend)) {
|
||||
$weekend = intval($CFG->calendar_weekend);
|
||||
}
|
||||
|
||||
// Now display all the calendar
|
||||
for($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
|
||||
if($dayweek > $display->maxwday) {
|
||||
@@ -247,7 +234,7 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
|
||||
|
||||
// Reset vars
|
||||
$cell = '';
|
||||
if ($weekend & (1 << ($dayweek % 7))) {
|
||||
if(CALENDAR_WEEKEND & (1 << ($dayweek % 7))) {
|
||||
// Weekend. This is true no matter what the exact range is.
|
||||
$class = 'weekend day';
|
||||
} else {
|
||||
@@ -678,7 +665,7 @@ function calendar_get_events($tstart, $tend, $users, $groups, $courses, $withdur
|
||||
}
|
||||
|
||||
function calendar_top_controls($type, $data) {
|
||||
global $CFG;
|
||||
global $CFG, $CALENDARDAYS;
|
||||
$content = '';
|
||||
if(!isset($data['d'])) {
|
||||
$data['d'] = 1;
|
||||
@@ -799,12 +786,11 @@ function calendar_top_controls($type, $data) {
|
||||
$content .= html_writer::end_tag('div')."\n";
|
||||
break;
|
||||
case 'day':
|
||||
$days = calendar_get_days();
|
||||
$data['d'] = $date['mday']; // Just for convenience
|
||||
$prevdate = usergetdate(make_timestamp($data['y'], $data['m'], $data['d'] - 1));
|
||||
$nextdate = usergetdate(make_timestamp($data['y'], $data['m'], $data['d'] + 1));
|
||||
$prevname = calendar_wday_name($days[$prevdate['wday']]);
|
||||
$nextname = calendar_wday_name($days[$nextdate['wday']]);
|
||||
$prevname = calendar_wday_name($CALENDARDAYS[$prevdate['wday']]);
|
||||
$nextname = calendar_wday_name($CALENDARDAYS[$nextdate['wday']]);
|
||||
$prevlink = calendar_get_link_previous($prevname, 'view.php?view=day'.$courseid.'&', $prevdate['mday'], $prevdate['mon'], $prevdate['year']);
|
||||
$nextlink = calendar_get_link_next($nextname, 'view.php?view=day'.$courseid.'&', $nextdate['mday'], $nextdate['mon'], $nextdate['year']);
|
||||
|
||||
@@ -828,61 +814,79 @@ function calendar_top_controls($type, $data) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
function calendar_filter_controls(moodle_url $returnurl) {
|
||||
global $CFG, $USER, $OUTPUT;
|
||||
function calendar_filter_controls($type, $vars = NULL, $course = NULL, $courses = NULL) {
|
||||
global $CFG, $SESSION, $USER, $OUTPUT;
|
||||
|
||||
$groupevents = true;
|
||||
$getvars = '';
|
||||
|
||||
$id = optional_param( 'id',0,PARAM_INT );
|
||||
|
||||
$seturl = new moodle_url('/calendar/set.php', array('return' => $returnurl));
|
||||
switch($type) {
|
||||
case 'event':
|
||||
case 'upcoming':
|
||||
case 'day':
|
||||
case 'month':
|
||||
$getvars = '&from='.$type;
|
||||
break;
|
||||
case 'course':
|
||||
if ($id > 0) {
|
||||
$getvars = '&from=course&id='.$id;
|
||||
} else {
|
||||
$getvars = '&from=course';
|
||||
}
|
||||
if (isset($course->groupmode) and $course->groupmode == NOGROUPS and $course->groupmodeforce) {
|
||||
$groupevents = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!empty($vars)) {
|
||||
$getvars .= '&'.$vars;
|
||||
}
|
||||
|
||||
$content = '<table>';
|
||||
|
||||
$content .= '<tr>';
|
||||
|
||||
$seturl->param('var', 'showglobal');
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
|
||||
$content .= '<td class="eventskey calendar_event_global" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hideglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
|
||||
if($SESSION->cal_show_global) {
|
||||
$content .= '<td class="eventskey calendar_event_global" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showglobal'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showglobal'.$getvars.'" title="'.get_string('tt_hideglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
|
||||
} else {
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showglobal'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showglobal'.$getvars.'" title="'.get_string('tt_showglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
|
||||
}
|
||||
if($SESSION->cal_show_course) {
|
||||
$content .= '<td class="eventskey calendar_event_course" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidecourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showcourses'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showcourses'.$getvars.'" title="'.get_string('tt_hidecourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
|
||||
} else {
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_showcourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showcourses'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showcourses'.$getvars.'" title="'.get_string('tt_showcourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
|
||||
|
||||
}
|
||||
|
||||
$seturl->param('var', 'showcourses');
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
|
||||
$content .= '<td class="eventskey calendar_event_course" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidecourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hidecourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
|
||||
} else {
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_showcourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showcourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
|
||||
}
|
||||
|
||||
if (isloggedin() && !isguestuser()) {
|
||||
$content .= "</tr>\n<tr>";
|
||||
|
||||
if ($groupevents) {
|
||||
if($groupevents) {
|
||||
// This course MIGHT have group events defined, so show the filter
|
||||
$seturl->param('var', 'showgroups');
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_GROUP)) {
|
||||
$content .= '<td class="eventskey calendar_event_group" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidegroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hidegroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
|
||||
if($SESSION->cal_show_groups) {
|
||||
$content .= '<td class="eventskey calendar_event_group" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidegroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showgroups'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showgroups'.$getvars.'" title="'.get_string('tt_hidegroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
|
||||
} else {
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showgroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showgroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showgroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showgroups'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showgroups'.$getvars.'" title="'.get_string('tt_showgroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
|
||||
}
|
||||
} else {
|
||||
// This course CANNOT have group events, so lose the filter
|
||||
$content .= '<td style="width: 11px;"></td><td> </td>'."\n";
|
||||
}
|
||||
|
||||
$seturl->param('var', 'showuser');
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_USER)) {
|
||||
$content .= '<td class="eventskey calendar_event_user" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hideuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
|
||||
if($SESSION->cal_show_user) {
|
||||
$content .= '<td class="eventskey calendar_event_user" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showuser'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showuser'.$getvars.'" title="'.get_string('tt_hideuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
|
||||
} else {
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
|
||||
$content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
|
||||
$content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showuser'.$getvars."'".'" /></td>';
|
||||
$content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showuser'.$getvars.'" title="'.get_string('tt_showuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
|
||||
}
|
||||
}
|
||||
$content .= "</tr>\n</table>\n";
|
||||
@@ -1200,89 +1204,212 @@ function calendar_get_course_cached(&$coursecache, $courseid) {
|
||||
return $coursecache[$courseid];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the courses to load events for, the
|
||||
*
|
||||
* @global moodle_database $DB
|
||||
* @param array $courseeventsfrom An array of courses to load calendar events for
|
||||
* @param bool $ignorefilters
|
||||
* @return array An array of courses, groups, and user to load calendar events for based upon filters
|
||||
*/
|
||||
function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false) {
|
||||
global $USER, $CFG, $DB;
|
||||
function calendar_session_vars($course=null) {
|
||||
global $SESSION, $USER;
|
||||
|
||||
// For backwards compatability we have to check whether the courses array contains
|
||||
// just id's in which case we need to load course objects.
|
||||
$coursestoload = array();
|
||||
foreach ($courseeventsfrom as $id => $something) {
|
||||
if (!is_object($something)) {
|
||||
$coursestoload[] = $id;
|
||||
unset($courseeventsfrom[$id]);
|
||||
if(!isset($SESSION->cal_course_referer)) {
|
||||
$SESSION->cal_course_referer = 0;
|
||||
}
|
||||
if(!isset($SESSION->cal_show_global)) {
|
||||
$SESSION->cal_show_global = true;
|
||||
}
|
||||
if(!isset($SESSION->cal_show_groups)) {
|
||||
$SESSION->cal_show_groups = true;
|
||||
}
|
||||
if(!isset($SESSION->cal_show_course)) {
|
||||
$SESSION->cal_show_course = true;
|
||||
}
|
||||
if(!isset($SESSION->cal_show_user)) {
|
||||
$SESSION->cal_show_user = true;
|
||||
}
|
||||
if ($course !== null) {
|
||||
// speedup hack for calendar related blocks
|
||||
if(isset($course->coursenode)) {
|
||||
// coursenode has been set up, which seems to break things further down the line.
|
||||
// Use a clone of $course with coursenode removed.
|
||||
$course = clone $course;
|
||||
unset($course->coursenode);
|
||||
}
|
||||
$SESSION->cal_courses_shown = array($course->id => $course);
|
||||
} else {
|
||||
$SESSION->cal_courses_shown = calendar_get_default_courses(true);
|
||||
}
|
||||
if(empty($SESSION->cal_users_shown)) {
|
||||
// The empty() instead of !isset() here makes a whole world of difference,
|
||||
// as it will automatically change to the user's id when the user first logs
|
||||
// in. With !isset(), it would never do that.
|
||||
$SESSION->cal_users_shown = isloggedin() ? $USER->id : false;
|
||||
} else if(is_numeric($SESSION->cal_users_shown) && isloggedin() && $SESSION->cal_users_shown != $USER->id) {
|
||||
// Follow the white rabbit, for example if a teacher logs in as a student
|
||||
$SESSION->cal_users_shown = $USER->id;
|
||||
}
|
||||
}
|
||||
|
||||
function calendar_set_referring_course($courseid) {
|
||||
global $SESSION;
|
||||
$SESSION->cal_course_referer = intval($courseid);
|
||||
}
|
||||
|
||||
function calendar_set_filters(&$courses, &$group, &$user, $courseeventsfrom = NULL, $groupeventsfrom = NULL, $ignorefilters = false) {
|
||||
global $SESSION, $USER, $CFG, $DB;
|
||||
|
||||
// Insidious bug-wannabe: setting $SESSION->cal_courses_shown to $course->id would cause
|
||||
// the code to function incorrectly UNLESS we convert it to an integer. One case where
|
||||
// PHP's loose type system works against us.
|
||||
if(is_string($SESSION->cal_courses_shown)) {
|
||||
$SESSION->cal_courses_shown = intval($SESSION->cal_courses_shown);
|
||||
}
|
||||
if($courseeventsfrom === NULL) {
|
||||
$courseeventsfrom = $SESSION->cal_courses_shown;
|
||||
}
|
||||
|
||||
// MDL-9059, $courseeventsfrom can be an int, or an array of ints, or an array of course objects
|
||||
// convert all to array of objects
|
||||
// we probably should do some clean up and make sure that session is set to use the proper form
|
||||
if (is_int($courseeventsfrom)) { // case of an int, e.g. calendar view page
|
||||
$c = array();
|
||||
$c[$courseeventsfrom] = $DB->get_record('course', array('id'=>$courseeventsfrom));
|
||||
$courseeventsfrom = $c;
|
||||
} else if (is_array($courseeventsfrom)) { // case of an array of ints, e.g. course home page
|
||||
foreach ($courseeventsfrom as $i=>$courseid) { // TODO: this seems wrong, the array is often constructed as [courseid] => 1 ???
|
||||
if (is_int($courseid)) {
|
||||
$courseeventsfrom[$i] = $DB->get_record('course', array('id'=>$courseid));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!empty($coursestoload)) {
|
||||
// TODO remove this in 2.2
|
||||
debugging('calendar_set_filters now preferes an array of course objects with preloaded contexts', DEBUG_DEVELOPER);
|
||||
$courseeventsfrom = array_merge($courseeventsfrom, $DB->get_records_list('course', 'id', $coursestoload));
|
||||
|
||||
if($groupeventsfrom === NULL) {
|
||||
$groupeventsfrom = $SESSION->cal_courses_shown;
|
||||
}
|
||||
|
||||
$courses = array();
|
||||
$user = false;
|
||||
$group = false;
|
||||
|
||||
$isloggedin = isloggedin();
|
||||
|
||||
if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
|
||||
$courses = array_keys($courseeventsfrom);
|
||||
if(($SESSION->cal_show_course && $SESSION->cal_show_global) || $ignorefilters) {
|
||||
if(is_int($courseeventsfrom)) {
|
||||
$courses = array(SITEID, $courseeventsfrom);
|
||||
}
|
||||
else if(is_array($courseeventsfrom)) {
|
||||
$courses = array_keys($courseeventsfrom);
|
||||
$courses[] = SITEID;
|
||||
}
|
||||
}
|
||||
if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
|
||||
$courses[] = SITEID;
|
||||
else if($SESSION->cal_show_course) {
|
||||
if(is_int($courseeventsfrom)) {
|
||||
$courses = array($courseeventsfrom);
|
||||
}
|
||||
else if(is_array($courseeventsfrom)) {
|
||||
$courses = array_keys($courseeventsfrom);
|
||||
}
|
||||
$courses = array_diff($courses, array(SITEID));
|
||||
}
|
||||
$courses = array_unique($courses);
|
||||
sort($courses);
|
||||
else if($SESSION->cal_show_global) {
|
||||
$courses = array(SITEID);
|
||||
}
|
||||
else {
|
||||
$courses = false;
|
||||
}
|
||||
//BUG 6130 clean $courses array as SESSION has bad entries.
|
||||
// [pj] TODO: See if this has to do with my new change in get_default_courses and can be taken out
|
||||
if (is_array($courses)) {
|
||||
foreach ($courses as $index => $value) {
|
||||
if (empty($value)) unset($courses[$index]);
|
||||
}
|
||||
|
||||
if (!empty($courses) && in_array(SITEID, $courses)) {
|
||||
// Sort courses for consistent colour highlighting
|
||||
// Effectively ignoring SITEID as setting as last course id
|
||||
$key = array_search(SITEID, $courses);
|
||||
unset($courses[$key]);
|
||||
$courses[] = SITEID;
|
||||
if ($key !== false) {
|
||||
unset($courses[$key]);
|
||||
sort($courses);
|
||||
$courses[] = SITEID;
|
||||
} else {
|
||||
sort($courses);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ignorefilters || ($isloggedin && calendar_show_event_type(CALENDAR_EVENT_USER))) {
|
||||
$user = $USER->id;
|
||||
if($SESSION->cal_show_user || $ignorefilters) {
|
||||
// This doesn't work for arrays yet (maybe someday it will)
|
||||
$user = $SESSION->cal_users_shown;
|
||||
}
|
||||
else {
|
||||
$user = false;
|
||||
}
|
||||
if($SESSION->cal_show_groups || $ignorefilters) {
|
||||
if(is_int($groupeventsfrom)) {
|
||||
$groupcourses = array($groupeventsfrom);
|
||||
}
|
||||
else if(is_array($groupeventsfrom)) {
|
||||
$groupcourses = array_keys($groupeventsfrom);
|
||||
}
|
||||
|
||||
if (!empty($courseeventsfrom) && (calendar_show_event_type(CALENDAR_EVENT_GROUP) || $ignorefilters)) {
|
||||
|
||||
if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', get_system_context())) {
|
||||
// XXX TODO: not sure how to replace $CFG->calendar_adminseesall
|
||||
if(has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM)) && !empty($CFG->calendar_adminseesall)) {
|
||||
$group = true;
|
||||
} else if ($isloggedin) {
|
||||
$groupids = array();
|
||||
}
|
||||
else {
|
||||
$grouparray = array();
|
||||
|
||||
// We already have the courses to examine in $courses
|
||||
// For each course...
|
||||
foreach ($courseeventsfrom as $courseid => $course) {
|
||||
|
||||
foreach($groupcourses as $courseid) {
|
||||
|
||||
if (!isset($courseeventsfrom[$courseid]->context)) { // SHOULD be set MDL-11221
|
||||
if (is_object($courseeventsfrom[$courseid])) {
|
||||
$courseeventsfrom[$courseid]->context = get_context_instance(CONTEXT_COURSE, $courseid);
|
||||
}
|
||||
}
|
||||
|
||||
// If the user is an editing teacher in there,
|
||||
if (!empty($USER->groupmember[$course->id])) {
|
||||
// We've already cached the users groups for this course so we can just use that
|
||||
$groupids = array_merge($groupids, $USER->groupmember[$course->id]);
|
||||
} else if (($course->groupmode != NOGROUPS || !$course->groupmodeforce) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, $course->id))) {
|
||||
if (isloggedin() && isset($courseeventsfrom[$courseid]->context) && has_capability('moodle/calendar:manageentries', $courseeventsfrom[$courseid]->context)) {
|
||||
// If this course has groups, show events from all of them
|
||||
$coursegroups = groups_get_user_groups($course->id, $USER->id);
|
||||
$groupids = array_merge($groupids, $coursegroups['0']);
|
||||
if(is_int($groupeventsfrom)) {
|
||||
if (is_object($courseeventsfrom[$courseid])) { // SHOULD be set MDL-11221
|
||||
$courserecord = $courseeventsfrom[$courseid];
|
||||
} else {
|
||||
$courserecord = $DB->get_record('course', array('id'=>$courseid));
|
||||
}
|
||||
$courserecord = $DB->get_record('course', array('id'=>$courseid));
|
||||
if ($courserecord->groupmode != NOGROUPS || !$courserecord->groupmodeforce) {
|
||||
$groupids[] = $courseid;
|
||||
}
|
||||
}
|
||||
else if(isset($SESSION->cal_courses_shown[$courseid]) && ($SESSION->cal_courses_shown[$courseid]->groupmode != NOGROUPS || !$SESSION->cal_courses_shown[$courseid]->groupmodeforce)) {
|
||||
$groupids[] = $courseid;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise (not editing teacher) show events from the group he is a member of
|
||||
else if(isset($USER->groupmember[$courseid])) {
|
||||
//changed to 2D array
|
||||
foreach ($USER->groupmember[$courseid] as $groupid){
|
||||
$grouparray[] = $groupid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($groupids)) {
|
||||
$group = $groupids;
|
||||
$sql = "SELECT *
|
||||
FROM {groups}
|
||||
WHERE courseid IN (".implode(',', $groupids).')';
|
||||
|
||||
if ($grouprecords = $DB->get_records_sql($sql, null)) {
|
||||
foreach ($grouprecords as $grouprecord) {
|
||||
$grouparray[] = $grouprecord->id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(empty($grouparray)) {
|
||||
$group = false;
|
||||
}
|
||||
else {
|
||||
$group = $grouparray;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (empty($courses)) {
|
||||
$courses = false;
|
||||
}
|
||||
|
||||
return array($courses, $group, $user);
|
||||
}
|
||||
else {
|
||||
$group = false;
|
||||
}
|
||||
}
|
||||
|
||||
function calendar_edit_event_allowed($event) {
|
||||
@@ -1327,32 +1454,23 @@ function calendar_edit_event_allowed($event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default courses to display on the calendar when there isn't a specific
|
||||
* course to display.
|
||||
*
|
||||
* @global moodle_database $DB
|
||||
* @return array Array of courses to display
|
||||
*/
|
||||
function calendar_get_default_courses() {
|
||||
global $CFG, $DB;
|
||||
function calendar_get_default_courses($ignoreref = false) {
|
||||
global $USER, $CFG, $SESSION, $DB;
|
||||
|
||||
if(!empty($SESSION->cal_course_referer) && !$ignoreref) {
|
||||
return array($SESSION->cal_course_referer => 1);
|
||||
}
|
||||
|
||||
if (!isloggedin()) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$courses = array();
|
||||
if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) {
|
||||
list ($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
|
||||
$sql = "SELECT c.* $select
|
||||
FROM {course} c
|
||||
JOIN {event} e ON e.courseid = c.id
|
||||
$join";
|
||||
$courses = $DB->get_records_sql($sql, null, 0, 20);
|
||||
foreach ($courses as $course) {
|
||||
context_instance_preload($course);
|
||||
if (has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) {
|
||||
if (!empty($CFG->calendar_adminseesall)) {
|
||||
$courses = $DB->get_records_sql('SELECT id, 1 FROM {course}');
|
||||
return $courses;
|
||||
}
|
||||
return $courses;
|
||||
}
|
||||
|
||||
$courses = enrol_get_my_courses();
|
||||
@@ -1360,15 +1478,17 @@ function calendar_get_default_courses() {
|
||||
return $courses;
|
||||
}
|
||||
|
||||
function calendar_preferences_button(stdClass $course) {
|
||||
global $OUTPUT;
|
||||
function calendar_preferences_button() {
|
||||
global $CFG, $USER;
|
||||
|
||||
// Guests have no preferences
|
||||
if (!isloggedin() || isguestuser()) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return $OUTPUT->single_button(new moodle_url('/calendar/preferences.php', array('course' => $course->id)), get_string("preferences", "calendar"));
|
||||
return "<form method=\"get\" ".
|
||||
" action=\"$CFG->wwwroot/calendar/preferences.php\">".
|
||||
"<div><input type=\"submit\" value=\"".get_string("preferences", "calendar")." ...\" /></div></form>";
|
||||
}
|
||||
|
||||
function calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime=0) {
|
||||
@@ -1468,93 +1588,61 @@ function calendar_print_month_selector($name, $selected) {
|
||||
echo html_writer::select($months, $name, $selected, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if the requested type of event should be shown for the given user.
|
||||
*
|
||||
* @param CALENDAR_EVENT_GLOBAL|CALENDAR_EVENT_COURSE|CALENDAR_EVENT_GROUP|CALENDAR_EVENT_USER $type
|
||||
* The type to check the display for (default is to display all)
|
||||
* @param stdClass|int|null $user The user to check for - by default the current user
|
||||
* @return bool True if the tyep should be displayed false otherwise
|
||||
*/
|
||||
function calendar_show_event_type($type, $user = null) {
|
||||
$default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER;
|
||||
if (get_user_preferences('calendar_persistflt', 0, $user) === 0) {
|
||||
global $SESSION;
|
||||
if (!isset($SESSION->calendarshoweventtype)) {
|
||||
$SESSION->calendarshoweventtype = $default;
|
||||
}
|
||||
return $SESSION->calendarshoweventtype & $type;
|
||||
} else {
|
||||
return get_user_preferences('calendar_savedflt', $default, $user) & $type;
|
||||
function calendar_get_filters_status() {
|
||||
global $SESSION;
|
||||
|
||||
$status = 0;
|
||||
if($SESSION->cal_show_global) {
|
||||
$status += 1;
|
||||
}
|
||||
if($SESSION->cal_show_course) {
|
||||
$status += 2;
|
||||
}
|
||||
if($SESSION->cal_show_groups) {
|
||||
$status += 4;
|
||||
}
|
||||
if($SESSION->cal_show_user) {
|
||||
$status += 8;
|
||||
}
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the display of the event type given $display.
|
||||
* If $display = true the event type will be shown.
|
||||
* If $display = false the event type will NOT be shown.
|
||||
* If $display = null the current value will be toggled and saved.
|
||||
*
|
||||
* @param CALENDAR_EVENT_GLOBAL|CALENDAR_EVENT_COURSE|CALENDAR_EVENT_GROUP|CALENDAR_EVENT_USER $type
|
||||
* @param true|false|null $display
|
||||
* @param stdClass|int|null $user
|
||||
*/
|
||||
function calendar_set_event_type_display($type, $display = null, $user = null) {
|
||||
$persist = get_user_preferences('calendar_persistflt', 0, $user);
|
||||
$default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER;
|
||||
if ($persist === 0) {
|
||||
global $SESSION;
|
||||
if (!isset($SESSION->calendarshoweventtype)) {
|
||||
$SESSION->calendarshoweventtype = $default;
|
||||
}
|
||||
$preference = $SESSION->calendarshoweventtype;
|
||||
} else {
|
||||
$preference = get_user_preferences('calendar_savedflt', $default, $user);
|
||||
}
|
||||
$current = $preference & $type;
|
||||
if ($display === null) {
|
||||
$display = !$current;
|
||||
}
|
||||
if ($display && !$current) {
|
||||
$preference += $type;
|
||||
} else if (!$display && $current) {
|
||||
$preference -= $type;
|
||||
}
|
||||
if ($persist === 0) {
|
||||
$SESSION->calendarshoweventtype = $preference;
|
||||
} else {
|
||||
if ($preference == $default) {
|
||||
unset_user_preference('calendar_savedflt', $user);
|
||||
} else {
|
||||
set_user_preference('calendar_savedflt', $preference, $user);
|
||||
}
|
||||
function calendar_set_filters_status($packed_bitfield) {
|
||||
global $SESSION, $USER;
|
||||
|
||||
if (!isloggedin()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$SESSION->cal_show_global = ($packed_bitfield & 1);
|
||||
$SESSION->cal_show_course = ($packed_bitfield & 2);
|
||||
$SESSION->cal_show_groups = ($packed_bitfield & 4);
|
||||
$SESSION->cal_show_user = ($packed_bitfield & 8);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function calendar_get_allowed_types(&$allowed, $course = null) {
|
||||
global $USER, $CFG, $DB;
|
||||
$allowed->user = has_capability('moodle/calendar:manageownentries', get_system_context());
|
||||
function calendar_get_allowed_types(&$allowed) {
|
||||
global $USER, $CFG, $SESSION, $DB;
|
||||
$sitecontext = get_context_instance(CONTEXT_SYSTEM);
|
||||
$allowed->user = has_capability('moodle/calendar:manageownentries', $sitecontext);
|
||||
$allowed->groups = false; // This may change just below
|
||||
$allowed->courses = false; // This may change just below
|
||||
$allowed->site = has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, SITEID));
|
||||
|
||||
if (!empty($course)) {
|
||||
if (!is_object($course)) {
|
||||
$course = $DB->get_record('course', array('id' => $course), '*', MUST_EXIST);
|
||||
}
|
||||
if ($course->id != SITEID) {
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
|
||||
if(!empty($SESSION->cal_course_referer) && $SESSION->cal_course_referer != SITEID) {
|
||||
$course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer));
|
||||
$coursecontext = get_context_instance(CONTEXT_COURSE, $SESSION->cal_course_referer);
|
||||
|
||||
if (has_capability('moodle/calendar:manageentries', $coursecontext)) {
|
||||
$allowed->courses = array($course->id => 1);
|
||||
if(has_capability('moodle/calendar:manageentries', $coursecontext)) {
|
||||
$allowed->courses = array($course->id => 1);
|
||||
|
||||
if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
|
||||
$allowed->groups = groups_get_all_groups($course->id);
|
||||
}
|
||||
} else if (has_capability('moodle/calendar:managegroupentries', $coursecontext)) {
|
||||
if($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
|
||||
$allowed->groups = groups_get_all_groups($course->id);
|
||||
}
|
||||
if($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
|
||||
$allowed->groups = groups_get_all_groups($SESSION->cal_course_referer);
|
||||
}
|
||||
} else if(has_capability('moodle/calendar:managegroupentries', $coursecontext)) {
|
||||
if($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
|
||||
$allowed->groups = groups_get_all_groups($SESSION->cal_course_referer, $USER->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1565,11 +1653,8 @@ function calendar_get_allowed_types(&$allowed, $course = null) {
|
||||
* used to print the "New Event" button
|
||||
* @return bool
|
||||
*/
|
||||
function calendar_user_can_add_event($course) {
|
||||
if (!isloggedin() || isguestuser()) {
|
||||
return false;
|
||||
}
|
||||
calendar_get_allowed_types($allowed, $course);
|
||||
function calendar_user_can_add_event() {
|
||||
calendar_get_allowed_types($allowed);
|
||||
return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->site);
|
||||
}
|
||||
|
||||
@@ -2375,21 +2460,6 @@ class calendar_information {
|
||||
$this->year = $year;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param stdClass $course
|
||||
* @param array $coursestoload An array of courses [$course->id => $course]
|
||||
* @param type $ignorefilters
|
||||
*/
|
||||
public function prepare_for_view(stdClass $course, array $coursestoload, $ignorefilters = false) {
|
||||
$this->courseid = $course->id;
|
||||
$this->course = $course;
|
||||
list($courses, $group, $user) = calendar_set_filters($coursestoload, $ignorefilters);
|
||||
$this->courses = $courses;
|
||||
$this->groups = $group;
|
||||
$this->users = $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the date for the calendar is correct and either sets it to now
|
||||
* or throws a moodle_exception if not
|
||||
|
||||
+22
-26
@@ -6,41 +6,37 @@ require_once('../config.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
require_once($CFG->dirroot.'/calendar/preferences_form.php');
|
||||
|
||||
$courseid = required_param('course', PARAM_INT);
|
||||
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
|
||||
$course = $site = get_site();
|
||||
if (!empty($SESSION->cal_course_referer)) {
|
||||
$course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer), '*', MUST_EXIST);
|
||||
}
|
||||
|
||||
$PAGE->set_url('/calendar/preferences.php', array('id' => $courseid));
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_url('/calendar/preferences.php');
|
||||
|
||||
require_login($course);
|
||||
|
||||
if ($courseid == SITEID) {
|
||||
$viewurl = new moodle_url('/calendar/view.php', array('view' => 'month'));
|
||||
if ($course->id != SITEID) {
|
||||
require_login($course);
|
||||
} else {
|
||||
$viewurl = new moodle_url('/calendar/view.php', array('view' => 'month', 'course' => $courseid));
|
||||
require_login();
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
|
||||
}
|
||||
navigation_node::override_active_url($viewurl);
|
||||
// Initialize the session variables
|
||||
calendar_session_vars();
|
||||
|
||||
$defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
|
||||
if (isset($CFG->calendar_lookahead)) {
|
||||
$defaultlookahead = intval($CFG->calendar_lookahead);
|
||||
}
|
||||
$defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS;
|
||||
if (isset($CFG->calendar_maxevents)) {
|
||||
$defaultmaxevents = intval($CFG->calendar_maxevents);
|
||||
}
|
||||
|
||||
$prefs = new stdClass;
|
||||
$prefs->timeformat = get_user_preferences('calendar_timeformat', '');
|
||||
$prefs->startwday = get_user_preferences('calendar_startwday', calendar_get_starting_weekday());
|
||||
$prefs->maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents);
|
||||
$prefs->lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead);
|
||||
$prefs->maxevents = get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS);
|
||||
$prefs->lookahead = get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS);
|
||||
$prefs->persistflt = get_user_preferences('calendar_persistflt', 0);
|
||||
|
||||
$form = new calendar_preferences_form();
|
||||
$form = new calendar_preferences_form($PAGE->url);
|
||||
$form->set_data($prefs);
|
||||
|
||||
if ($data = $form->get_data() && confirm_sesskey()) {
|
||||
if ($form->is_cancelled()) {
|
||||
redirect($viewurl);
|
||||
} else if ($form->is_submitted() && $form->is_validated() && confirm_sesskey()) {
|
||||
$data = $form->get_data();
|
||||
if ($data->timeformat != CALENDAR_TF_12 && $data->timeformat != CALENDAR_TF_24) {
|
||||
$data->timeformat = '';
|
||||
}
|
||||
@@ -61,17 +57,17 @@ if ($data = $form->get_data() && confirm_sesskey()) {
|
||||
}
|
||||
|
||||
set_user_preference('calendar_persistflt', intval($data->persistflt));
|
||||
redirect($viewurl, get_string('changessaved'), 1);
|
||||
redirect(new moodle_url('/calendar/view.php', array('course'=>$course->id)), get_string('changessaved'), 1);
|
||||
exit;
|
||||
}
|
||||
|
||||
$strcalendar = get_string('calendar', 'calendar');
|
||||
$strpreferences = get_string('calendarpreferences', 'calendar');
|
||||
|
||||
$PAGE->navbar->add($strpreferences, new moodle_url('/calendar/view.php'));
|
||||
$PAGE->navbar->add($strpreferences);
|
||||
$PAGE->set_pagelayout('admin');
|
||||
$PAGE->set_title("$course->shortname: $strcalendar: $strpreferences");
|
||||
$PAGE->set_heading($course->fullname);
|
||||
$PAGE->set_title("$site->shortname: $strcalendar: $strpreferences");
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading($strpreferences);
|
||||
|
||||
+54
-54
@@ -137,7 +137,8 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
* @return string
|
||||
*/
|
||||
public function fake_block_filters($courseid, $day, $month, $year, $view, $courses) {
|
||||
return html_writer::tag('div', calendar_filter_controls($this->page->url), array('class'=>'calendar_filters filters'));
|
||||
$getvars = 'id='.$courseid.'&cal_d='.$day.'&cal_m='.$month.'&cal_y='.$year;
|
||||
return html_writer::tag('div', calendar_filter_controls($view, $getvars, NULL, $courses), array('class'=>'calendar_filters filters'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -215,21 +216,16 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
* @param calendar_information $calendar
|
||||
* @return string
|
||||
*/
|
||||
public function show_day(calendar_information $calendar, moodle_url $returnurl = null) {
|
||||
|
||||
if ($returnurl === null) {
|
||||
$returnurl = $this->page->url;
|
||||
}
|
||||
|
||||
public function show_day(calendar_information $calendar) {
|
||||
$calendar->checkdate();
|
||||
$events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, 1, 100, $calendar->timestamp_today());
|
||||
|
||||
$output = html_writer::start_tag('div', array('class'=>'header'));
|
||||
if (calendar_user_can_add_event($calendar->course)) {
|
||||
$output .= $this->add_event_button($calendar->course->id, $calendar->day, $calendar->month, $calendar->year);
|
||||
if (!isguestuser() && isloggedin() && calendar_user_can_add_event()) {
|
||||
$output .= $this->add_event_button($calendar->courseid, $calendar->day, $calendar->month, $calendar->year);
|
||||
}
|
||||
//$output .= html_writer::tag('label', get_string('dayview', 'calendar'), array('for'=>'cal_course_flt_jump'));
|
||||
$output .= $this->course_filter_selector($returnurl, get_string('dayview', 'calendar'));
|
||||
$output .= $this->course_filter_selector(array('from'=>'day', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year), get_string('dayview', 'calendar'));
|
||||
$output .= html_writer::end_tag('div');
|
||||
// Controls
|
||||
$output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid, 'd' => $calendar->day, 'm' => $calendar->month, 'y' => $calendar->year)), array('class'=>'controls'));
|
||||
@@ -349,15 +345,12 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
/**
|
||||
* Displays a month in detail
|
||||
*
|
||||
* @global array $CALENDARDAYS
|
||||
* @param calendar_information $calendar
|
||||
* @return string
|
||||
*/
|
||||
public function show_month_detailed(calendar_information $calendar, moodle_url $returnurl = null) {
|
||||
global $CFG;
|
||||
|
||||
if (empty($returnurl)) {
|
||||
$returnurl = $this->page->url;
|
||||
}
|
||||
public function show_month_detailed(calendar_information $calendar) {
|
||||
global $CALENDARDAYS;
|
||||
|
||||
$date = usergetdate(time());
|
||||
|
||||
@@ -403,16 +396,14 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
calendar_events_by_day($events, $calendar->month, $calendar->year, $eventsbyday, $durationbyday, $typesbyday, $calendar->courses);
|
||||
|
||||
$output = html_writer::start_tag('div', array('class'=>'header'));
|
||||
if (calendar_user_can_add_event($calendar->course)) {
|
||||
$output .= $this->add_event_button($calendar->course->id, null, $calendar->month, $calendar->year);
|
||||
if(!isguestuser() && isloggedin() && calendar_user_can_add_event()) {
|
||||
$output .= $this->add_event_button($calendar->courseid, null, $calendar->month, $calendar->year);
|
||||
}
|
||||
$output .= get_string('detailedmonthview', 'calendar').': '.$this->course_filter_selector($returnurl);
|
||||
$output .= get_string('detailedmonthview', 'calendar').': '.$this->course_filter_selector(array('from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
|
||||
$output .= html_writer::end_tag('div', array('class'=>'header'));
|
||||
// Controls
|
||||
$output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, 'm' => $calendar->month, 'y' => $calendar->year)), array('class'=>'controls'));
|
||||
|
||||
$days = calendar_get_days();
|
||||
|
||||
$table = new html_table();
|
||||
$table->attributes = array('class'=>'calendarmonth calendartable');
|
||||
$table->data = array();
|
||||
@@ -423,7 +414,7 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
for($i = $display->minwday; $i <= $display->maxwday; ++$i) {
|
||||
// This uses the % operator to get the correct weekday no matter what shift we have
|
||||
// applied to the $display->minwday : $display->maxwday range from the default 0 : 6
|
||||
$cell = new html_table_cell(get_string($days[$i % 7], 'calendar'));
|
||||
$cell = new html_table_cell(get_string($CALENDARDAYS[$i % 7], 'calendar'));
|
||||
$cell->header = true;
|
||||
$header->cells[] = $cell;
|
||||
}
|
||||
@@ -432,7 +423,29 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
$week = 1;
|
||||
$dayweek = $startwday;
|
||||
|
||||
// Create an array of all the week days.
|
||||
$wdays = array(0 => '<strong>'. get_string('sunday', 'calendar'). '</strong>',
|
||||
1 => '<strong>'. get_string('monday', 'calendar'). '</strong>',
|
||||
2 => '<strong>'. get_string('tuesday', 'calendar'). '</strong>',
|
||||
3 => '<strong>'. get_string('wednesday', 'calendar'). '</strong>',
|
||||
4 => '<strong>'. get_string('thursday', 'calendar'). '</strong>',
|
||||
5 => '<strong>'. get_string('friday', 'calendar'). '</strong>',
|
||||
6 => '<strong>'. get_string('saturday', 'calendar'). '</strong>');
|
||||
|
||||
// Loop only if the day offset is greater than 0.
|
||||
// This loop involves shifting the days around until the desired start day
|
||||
// is at the start of the array.
|
||||
$daycount = 0;
|
||||
while ($display->minwday > $daycount++) {
|
||||
$wdays_end = array_shift($wdays);
|
||||
array_push($wdays, $wdays_end);
|
||||
}
|
||||
|
||||
// Now we set the (modified) array to the table header to be displayed.
|
||||
$table->head = $wdays;
|
||||
|
||||
$row = new html_table_row(array());
|
||||
|
||||
// Paddding (the first week may have blank days in the beginning)
|
||||
for($i = $display->minwday; $i < $startwday; ++$i) {
|
||||
$cell = new html_table_cell(' ');
|
||||
@@ -441,11 +454,6 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
// Now display all the calendar
|
||||
$weekend = CALENDAR_DEFAULT_WEEKEND;
|
||||
if (isset($CFG->calendar_weekend)) {
|
||||
$weekend = intval($CFG->calendar_weekend);
|
||||
}
|
||||
|
||||
for ($calendar->day = 1; $calendar->day <= $display->maxdays; ++$calendar->day, ++$dayweek) {
|
||||
if($dayweek > $display->maxwday) {
|
||||
// We need to change week (table row)
|
||||
@@ -461,7 +469,7 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
|
||||
$cellclasses = array();
|
||||
|
||||
if ($weekend & (1 << ($dayweek % 7))) {
|
||||
if(CALENDAR_WEEKEND & (1 << ($dayweek % 7))) {
|
||||
// Weekend. This is true no matter what the exact range is.
|
||||
$cellclasses[] = 'weekend';
|
||||
}
|
||||
@@ -546,20 +554,16 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
* @param calendar_information $calendar
|
||||
* @return string
|
||||
*/
|
||||
protected function filter_selection_table(calendar_information $calendar, moodle_url $returnurl = null) {
|
||||
protected function filter_selection_table(calendar_information $calendar) {
|
||||
global $SESSION;
|
||||
|
||||
if ($returnurl === null) {
|
||||
$returnurl = $this->page->url;
|
||||
}
|
||||
|
||||
$output = html_writer::start_tag('div', array('class'=>'filters'));
|
||||
$output .= html_writer::start_tag('table');
|
||||
$output .= html_writer::start_tag('tr');
|
||||
|
||||
// Global events
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var' => 'showglobal', 'return' => $returnurl));
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showglobal', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
|
||||
if($SESSION->cal_show_global) {
|
||||
$output .= html_writer::tag('td', '', array('class'=>'calendar_event_global', 'style'=>'width:8px;'));
|
||||
$output .= html_writer::tag('td', html_writer::tag('strong', get_string('globalevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
|
||||
} else {
|
||||
@@ -568,8 +572,8 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
// Course events
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showcourses', 'return' => $returnurl));
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showcourses', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
|
||||
if(!empty($SESSION->cal_show_course)) {
|
||||
$output .= html_writer::tag('td', '', array('class'=>'calendar_event_course', 'style'=>'width:8px;'));
|
||||
$output .= html_writer::tag('td', html_writer::tag('strong', get_string('courseevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
|
||||
} else {
|
||||
@@ -581,8 +585,8 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
if(isloggedin() && !isguestuser()) {
|
||||
$output .= html_writer::start_tag('tr');
|
||||
// Group events
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showgroups', 'return' => $returnurl));
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_GROUP)) {
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showgroups', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
|
||||
if($SESSION->cal_show_groups) {
|
||||
$output .= html_writer::tag('td', '', array('class'=>'calendar_event_group', 'style'=>'width:8px;'));
|
||||
$output .= html_writer::tag('td', html_writer::tag('strong', get_string('groupevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
|
||||
} else {
|
||||
@@ -590,8 +594,8 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
$output .= html_writer::tag('td', html_writer::tag('strong', get_string('groupevents', 'calendar')).' '.get_string('hidden', 'calendar').' ('.html_writer::link($link, get_string('clickshow', 'calendar')).')');
|
||||
}
|
||||
// User events
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showuser', 'return' => $returnurl));
|
||||
if (calendar_show_event_type(CALENDAR_EVENT_USER)) {
|
||||
$link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showuser', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
|
||||
if($SESSION->cal_show_user) {
|
||||
$output .= html_writer::tag('td', '', array('class'=>'calendar_event_user', 'style'=>'width:8px;'));
|
||||
$output .= html_writer::tag('td', html_writer::tag('strong', get_string('userevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
|
||||
} else {
|
||||
@@ -613,20 +617,15 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
* @param int $maxevents
|
||||
* @return string
|
||||
*/
|
||||
public function show_upcoming_events(calendar_information $calendar, $futuredays, $maxevents, moodle_url $returnurl = null) {
|
||||
|
||||
if ($returnurl === null) {
|
||||
$returnurl = $this->page->url;
|
||||
}
|
||||
|
||||
public function show_upcoming_events(calendar_information $calendar, $futuredays, $maxevents) {
|
||||
$events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, $futuredays, $maxevents);
|
||||
|
||||
$output = html_writer::start_tag('div', array('class'=>'header'));
|
||||
if (calendar_user_can_add_event($calendar->course)) {
|
||||
$output .= $this->add_event_button($calendar->course->id);
|
||||
if (!isguestuser() && isloggedin() && calendar_user_can_add_event()) {
|
||||
$output .= $this->add_event_button($calendar->courseid);
|
||||
}
|
||||
$output .= html_writer::tag('label', get_string('upcomingevents', 'calendar'), array('for'=>'cal_course_flt_jump'));
|
||||
$output .= $this->course_filter_selector($returnurl);
|
||||
$output .= $this->course_filter_selector(array('from'=>'upcoming'));
|
||||
$output .= html_writer::end_tag('div');
|
||||
|
||||
if ($events) {
|
||||
@@ -652,7 +651,7 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
* @param array $getvars
|
||||
* @return string
|
||||
*/
|
||||
protected function course_filter_selector(moodle_url $returnurl, $label=null) {
|
||||
protected function course_filter_selector(array $getvars = array(), $label=null) {
|
||||
global $USER, $SESSION, $CFG;
|
||||
|
||||
if (!isloggedin() or isguestuser()) {
|
||||
@@ -673,12 +672,13 @@ class core_calendar_renderer extends plugin_renderer_base {
|
||||
$courseoptions[$course->id] = format_string($course->shortname);
|
||||
}
|
||||
|
||||
if ($this->page->course->id !== SITEID) {
|
||||
$selected = $this->page->course->id;
|
||||
if (is_numeric($SESSION->cal_courses_shown)) {
|
||||
$selected = $SESSION->cal_courses_shown;
|
||||
} else {
|
||||
$selected = '';
|
||||
}
|
||||
$select = new single_select(new moodle_url(CALENDAR_URL.'set.php', array('return' => $returnurl, 'var' => 'setcourse')), 'id', $courseoptions, $selected, null);
|
||||
$getvars['var'] = 'setcourse';
|
||||
$select = new single_select(new moodle_url(CALENDAR_URL.'set.php', $getvars), 'id', $courseoptions, $selected, null);
|
||||
$select->class = 'cal_courses_flt';
|
||||
if ($label !== null) {
|
||||
$select->label = $label;
|
||||
|
||||
+97
-16
@@ -41,26 +41,107 @@
|
||||
require_once('../config.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
|
||||
$return = required_param('return', PARAM_URL);
|
||||
$from = required_param('from', PARAM_ALPHA);
|
||||
$var = required_param('var', PARAM_ALPHA);
|
||||
$id = optional_param('id', 0, PARAM_INT);
|
||||
$cal_d = optional_param('cal_d', 0, PARAM_INT);
|
||||
$cal_m = optional_param('cal_m', 0, PARAM_INT);
|
||||
$cal_y = optional_param('cal_y', 0, PARAM_INT);
|
||||
$action = optional_param('action', '', PARAM_ALPHA);
|
||||
$type = optional_param('type', '', PARAM_ALPHA);
|
||||
|
||||
$url = new moodle_url('/calendar/set.php', array('return'=>$return,'var'=>$var));
|
||||
$url = new moodle_url('/calendar/set.php', array('from'=>$from,'var'=>$var));
|
||||
if ($id !== 0) {
|
||||
$url->param('id', $id);
|
||||
}
|
||||
if ($cal_d !== 0) {
|
||||
$url->param('cal_d', $cal_d);
|
||||
}
|
||||
if ($cal_m !== 0) {
|
||||
$url->param('cal_m', $cal_m);
|
||||
}
|
||||
if ($cal_y !== 0) {
|
||||
$url->param('cal_y', $cal_y);
|
||||
}
|
||||
if ($action !== 0) {
|
||||
$url->param('action', $action);
|
||||
}
|
||||
if ($type !== 0) {
|
||||
$url->param('type', $type);
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
|
||||
|
||||
switch($var) {
|
||||
case 'showgroups':
|
||||
calendar_set_event_type_display(CALENDAR_EVENT_GROUP);
|
||||
break;
|
||||
case 'showcourses':
|
||||
calendar_set_event_type_display(CALENDAR_EVENT_COURSE);
|
||||
break;
|
||||
case 'showglobal':
|
||||
calendar_set_event_type_display(CALENDAR_EVENT_GLOBAL);
|
||||
break;
|
||||
case 'showuser':
|
||||
calendar_set_event_type_display(CALENDAR_EVENT_USER);
|
||||
break;
|
||||
// Initialize the session variables
|
||||
calendar_session_vars();
|
||||
|
||||
// Ensure course id passed if relevant
|
||||
// Required due to changes in view/lib.php mainly (calendar_session_vars())
|
||||
$courseid = '';
|
||||
if (!empty($id)) {
|
||||
$courseid = '&course='.$id;
|
||||
}
|
||||
|
||||
redirect($return);
|
||||
switch($var) {
|
||||
case 'setuser':
|
||||
// Not implemented yet (or possibly at all)
|
||||
break;
|
||||
case 'setcourse':
|
||||
$id = intval($id);
|
||||
if($id == 0) {
|
||||
$SESSION->cal_courses_shown = array();
|
||||
calendar_set_referring_course(0);
|
||||
}
|
||||
else if($id == 1) {
|
||||
$SESSION->cal_courses_shown = calendar_get_default_courses(true);
|
||||
calendar_set_referring_course(0);
|
||||
}
|
||||
else {
|
||||
if($DB->get_record('course', array('id'=>$id)) === false) {
|
||||
// There is no such course
|
||||
$SESSION->cal_courses_shown = array();
|
||||
calendar_set_referring_course(0);
|
||||
}
|
||||
else {
|
||||
calendar_set_referring_course($id);
|
||||
$SESSION->cal_courses_shown = $id;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'showgroups':
|
||||
$SESSION->cal_show_groups = !$SESSION->cal_show_groups;
|
||||
set_user_preference('calendar_savedflt', calendar_get_filters_status());
|
||||
break;
|
||||
case 'showcourses':
|
||||
$SESSION->cal_show_course = !$SESSION->cal_show_course;
|
||||
set_user_preference('calendar_savedflt', calendar_get_filters_status());
|
||||
break;
|
||||
case 'showglobal':
|
||||
$SESSION->cal_show_global = !$SESSION->cal_show_global;
|
||||
set_user_preference('calendar_savedflt', calendar_get_filters_status());
|
||||
break;
|
||||
case 'showuser':
|
||||
$SESSION->cal_show_user = !$SESSION->cal_show_user;
|
||||
set_user_preference('calendar_savedflt', calendar_get_filters_status());
|
||||
break;
|
||||
}
|
||||
|
||||
switch($from) {
|
||||
case 'event':
|
||||
redirect(CALENDAR_URL.'event.php?action='.$action.'&type='.$type.'&id='.intval($id));
|
||||
break;
|
||||
case 'month':
|
||||
redirect(CALENDAR_URL.'view.php?view=month'.$courseid.'&cal_d='.$cal_d.'&cal_m='.$cal_m.'&cal_y='.$cal_y);
|
||||
break;
|
||||
case 'upcoming':
|
||||
redirect(CALENDAR_URL.'view.php?view=upcoming'.$courseid);
|
||||
break;
|
||||
case 'day':
|
||||
redirect(CALENDAR_URL.'view.php?view=day'.$courseid.'&cal_d='.$cal_d.'&cal_m='.$cal_m.'&cal_y='.$cal_y);
|
||||
break;
|
||||
case 'course':
|
||||
redirect($CFG->wwwroot.'/course/view.php?id='.intval($id));
|
||||
break;
|
||||
default:
|
||||
|
||||
}
|
||||
+62
-30
@@ -44,14 +44,16 @@ require_once('../config.php');
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
require_once($CFG->dirroot.'/calendar/lib.php');
|
||||
|
||||
$courseid = optional_param('course', SITEID, PARAM_INT);
|
||||
$courseid = optional_param('course', 0, PARAM_INT);
|
||||
$view = optional_param('view', 'upcoming', PARAM_ALPHA);
|
||||
$day = optional_param('cal_d', 0, PARAM_INT);
|
||||
$mon = optional_param('cal_m', 0, PARAM_INT);
|
||||
$yr = optional_param('cal_y', 0, PARAM_INT);
|
||||
|
||||
$site = get_site();
|
||||
|
||||
$url = new moodle_url('/calendar/view.php');
|
||||
if ($courseid != SITEID) {
|
||||
if ($courseid !== 0) {
|
||||
$url->param('course', $courseid);
|
||||
}
|
||||
if ($view !== 'upcoming') {
|
||||
@@ -68,27 +70,34 @@ if ($yr !== 0) {
|
||||
}
|
||||
$PAGE->set_url($url);
|
||||
|
||||
if ($courseid != SITEID && !empty($courseid)) {
|
||||
$course = $DB->get_record('course', array('id' => $courseid));
|
||||
$courses = array($course->id => $course);
|
||||
$issite = false;
|
||||
navigation_node::override_active_url(new moodle_url('/course/view.php', array('id' => $course->id)));
|
||||
//TODO: the courseid handling in /calendar/ is a bloody mess!!!
|
||||
|
||||
if ($courseid && $courseid != SITEID) {
|
||||
require_login($courseid);
|
||||
} else if ($CFG->forcelogin) {
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
|
||||
require_login();
|
||||
} else {
|
||||
$course = get_site();
|
||||
$courses = calendar_get_default_courses();
|
||||
$issite = true;
|
||||
$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
|
||||
}
|
||||
require_course_login($course);
|
||||
|
||||
$calendar = new calendar_information($day, $mon, $yr);
|
||||
$calendar->prepare_for_view($course, $courses);
|
||||
$calendar->courseid = $courseid;
|
||||
|
||||
// Initialize the session variables
|
||||
calendar_session_vars();
|
||||
|
||||
//add_to_log($course->id, "course", "view", "view.php?id=$course->id", "$course->id");
|
||||
$now = usergetdate(time());
|
||||
$pagetitle = '';
|
||||
|
||||
$strcalendar = get_string('calendar', 'calendar');
|
||||
|
||||
if (!checkdate($mon, $day, $yr)) {
|
||||
$link = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$courseid)),
|
||||
$now['mday'], $now['mon'], $now['year']);
|
||||
$PAGE->navbar->add($strcalendar, $link);
|
||||
|
||||
if(!checkdate($mon, $day, $yr)) {
|
||||
$day = intval($now['mday']);
|
||||
$mon = intval($now['mon']);
|
||||
$yr = intval($now['year']);
|
||||
@@ -108,12 +117,47 @@ switch($view) {
|
||||
$pagetitle = get_string('upcomingevents', 'calendar');
|
||||
break;
|
||||
}
|
||||
// If a course has been supplied in the URL, change the filters to show that one
|
||||
if (!empty($courseid)) {
|
||||
if ($course = $DB->get_record('course', array('id'=>$courseid))) {
|
||||
if ($course->id == SITEID) {
|
||||
// If coming from the home page, show all courses
|
||||
$SESSION->cal_courses_shown = calendar_get_default_courses(true);
|
||||
calendar_set_referring_course(0);
|
||||
|
||||
} else {
|
||||
// Otherwise show just this one
|
||||
$SESSION->cal_courses_shown = $course->id;
|
||||
calendar_set_referring_course($SESSION->cal_courses_shown);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$course = null;
|
||||
}
|
||||
if (!isloggedin() or isguestuser()) {
|
||||
$defaultcourses = calendar_get_default_courses();
|
||||
calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users, $defaultcourses, $defaultcourses);
|
||||
} else {
|
||||
calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users);
|
||||
}
|
||||
// Let's see if we are supposed to provide a referring course link
|
||||
// but NOT for the "main page" course
|
||||
if ($SESSION->cal_course_referer != SITEID &&
|
||||
($shortname = $DB->get_field('course', 'shortname', array('id'=>$SESSION->cal_course_referer))) !== false) {
|
||||
require_login(); //TODO: very wrong!!
|
||||
if (empty($course)) {
|
||||
$course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer)); // Useful to have around
|
||||
}
|
||||
}
|
||||
|
||||
$strcalendar = get_string('calendar', 'calendar');
|
||||
$prefsbutton = calendar_preferences_button();
|
||||
|
||||
// Print title and header
|
||||
$PAGE->set_pagelayout('standard');
|
||||
$PAGE->set_title("$course->shortname: $strcalendar: $pagetitle");
|
||||
$PAGE->set_title("$site->shortname: $strcalendar: $pagetitle");
|
||||
$PAGE->set_heading($COURSE->fullname);
|
||||
$PAGE->set_button(calendar_preferences_button($course));
|
||||
$PAGE->set_button($prefsbutton);
|
||||
$PAGE->set_pagelayout('standard');
|
||||
|
||||
$renderer = $PAGE->get_renderer('core_calendar');
|
||||
$calendar->add_sidecalendar_blocks($renderer, true, $view);
|
||||
@@ -130,18 +174,7 @@ switch($view) {
|
||||
echo $renderer->show_month_detailed($calendar);
|
||||
break;
|
||||
case 'upcoming':
|
||||
$defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
|
||||
if (isset($CFG->calendar_lookahead)) {
|
||||
$defaultlookahead = intval($CFG->calendar_lookahead);
|
||||
}
|
||||
$lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead);
|
||||
|
||||
$defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS;
|
||||
if (isset($CFG->calendar_maxevents)) {
|
||||
$defaultmaxevents = intval($CFG->calendar_maxevents);
|
||||
}
|
||||
$maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents);
|
||||
echo $renderer->show_upcoming_events($calendar, $lookahead, $maxevents);
|
||||
echo $renderer->show_upcoming_events($calendar, get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS), get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -151,12 +184,11 @@ if (!empty($CFG->enablecalendarexport)) {
|
||||
echo $OUTPUT->single_button(new moodle_url('export.php', array('course'=>$courseid)), get_string('exportcalendar', 'calendar'));
|
||||
if (isloggedin()) {
|
||||
$authtoken = sha1($USER->username . $USER->password . $CFG->calendar_exportsalt);
|
||||
$link = new moodle_url('/calendar/export_execute.php', array('preset_what'=>'all', 'prest_time'=>'recentupcoming', 'username'=>$USER->username, 'authtoken'=>$authtoken));
|
||||
$link = new moodle_url('/calendar/export_execute.php', array('preset_what'=>'all', 'preset_time'=>'recentupcoming', 'username'=>$USER->username, 'authtoken'=>$authtoken));
|
||||
$icon = html_writer::empty_tag('img', array('src'=>$OUTPUT->pix_url('i/ical'), 'height'=>'14', 'width'=>'36', 'alt'=>get_string('ical', 'calendar'), 'title'=>get_string('quickdownloadcalendar', 'calendar')));
|
||||
echo html_writer::tag('a', $icon, array('href'=>$link));
|
||||
}
|
||||
}
|
||||
|
||||
echo $OUTPUT->container_end();
|
||||
echo html_writer::end_tag('div');
|
||||
echo $renderer->complete_layout();
|
||||
|
||||
@@ -62,8 +62,6 @@ $PAGE->set_heading($COURSE->fullname);
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('assignto', 'cohort', format_string($cohort->name)));
|
||||
|
||||
echo $OUTPUT->notification(get_string('removeuserwarning', 'core_cohort'));
|
||||
|
||||
// Get the user_selector we will need.
|
||||
$potentialuserselector = new cohort_candidate_selector('addselect', array('cohortid'=>$cohort->id));
|
||||
$existinguserselector = new cohort_existing_selector('removeselect', array('cohortid'=>$cohort->id));
|
||||
|
||||
+2
-2
@@ -94,12 +94,12 @@ if ($delete and $cohort->id) {
|
||||
$editoroptions = array('maxfiles'=>0, 'context'=>$context);
|
||||
if ($cohort->id) {
|
||||
// edit existing
|
||||
$cohort = file_prepare_standard_editor($cohort, 'description', $editoroptions);
|
||||
$cohort = file_prepare_standard_editor($cohort, 'description', $editoroptions, $context);
|
||||
$strheading = get_string('editcohort', 'cohort');
|
||||
|
||||
} else {
|
||||
// add new
|
||||
$cohort = file_prepare_standard_editor($cohort, 'description', $editoroptions);
|
||||
$cohort = file_prepare_standard_editor($cohort, 'description', $editoroptions, $context);
|
||||
$strheading = get_string('addcohort', 'cohort');
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user