Compare commits
706 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ddadff9655 | |||
| 1e13288d77 | |||
| 60ae7e9e3e | |||
| 1541440ddc | |||
| 552f77e155 | |||
| 34bf5fa890 | |||
| f3bdb845c4 | |||
| 6e4c10f987 | |||
| df5fd3cd97 | |||
| 0cc57751e4 | |||
| ebbff90562 | |||
| 982c8524dd | |||
| 390645bd44 | |||
| 59be24cc60 | |||
| 64e07a390e | |||
| 19cd96e561 | |||
| 0bd6dee49f | |||
| d5cfda4734 | |||
| b7c42f0d7e | |||
| 333db4598d | |||
| a5580bc618 | |||
| dea12fe893 | |||
| bb5b3ee263 | |||
| 6e1fdb0951 | |||
| 69866e0377 | |||
| 2b51c3212a | |||
| 99772c2ba1 | |||
| 861822dc1b | |||
| e5d4b3d409 | |||
| 34b17698c4 | |||
| c8ec7b8a53 | |||
| d63f2a10bc | |||
| 4e29893160 | |||
| a1cd496b31 | |||
| a6d8e2b35e | |||
| df27344e9a | |||
| 0628d17bfa | |||
| 44e3a9bdc6 | |||
| c34a0a0acb | |||
| 4c9103a485 | |||
| ae376d3b2f | |||
| 14a2ef282b | |||
| ab39338705 | |||
| 6c4e723d6b | |||
| 892eb5d190 | |||
| f0640eb7d2 | |||
| 60f1480cdc | |||
| 53ed4016e6 | |||
| 76d6b7a9b4 | |||
| 97c36ae969 | |||
| 8e2d62e5e2 | |||
| 8d42b3ceb5 | |||
| b5570e07ca | |||
| d5ee2634bd | |||
| cc2ef7a505 | |||
| 49f1a64cb0 | |||
| bf7c584ffe | |||
| fa74d00ca6 | |||
| 124aa2558a | |||
| 8e321075bd | |||
| 9a72e79050 | |||
| ea254fc7dd | |||
| 514a13e431 | |||
| a9568d3d7f | |||
| 269695f48b | |||
| 9dc8c0f8b1 | |||
| 4b4fb1ce8b | |||
| 4157b01343 | |||
| 98af233a16 | |||
| 3312fc1ed5 | |||
| f45e49f01b | |||
| b463508597 | |||
| 7464e1b39d | |||
| 1c5d2aefd1 | |||
| 910043d965 | |||
| f29d5f891a | |||
| 1d9c8d95f2 | |||
| d489ecd1eb | |||
| fd72531964 | |||
| ebb8098668 | |||
| 911ab1a334 | |||
| fc86ba1b68 | |||
| 24d7efcec3 | |||
| 66dbc14778 | |||
| ec5fda6d6f | |||
| cb86d02348 | |||
| 8faaca0ea2 | |||
| b16e3e2217 | |||
| 881af32789 | |||
| 2cb77a22ff | |||
| 68305e513b | |||
| fe845dd3c2 | |||
| 135efed7f1 | |||
| 2a8877376a | |||
| 26929ce1a7 | |||
| 3e15af69de | |||
| a69107e549 | |||
| 0f9d61091b | |||
| f09f95fefa | |||
| 4e6eb5b8be | |||
| 8b50f60a64 | |||
| 25da4fa204 | |||
| c8c0aa21e4 | |||
| 0eef41f639 | |||
| 0a88b33a6a | |||
| d79710afde | |||
| 829eb491e0 | |||
| f460295a58 | |||
| de25146b0a | |||
| 432785d430 | |||
| ad94c5efb4 | |||
| e3a51bcd28 | |||
| e2aa68b154 | |||
| 618704b6a5 | |||
| f55eb23bde | |||
| 59829c0511 | |||
| dcc5d2df3d | |||
| 3395def1fa | |||
| 60177550ee | |||
| 756d8f1171 | |||
| edafa7ce90 | |||
| 61560c2b72 | |||
| b8d5bd3da0 | |||
| 3b7336fff2 | |||
| 82e46ef9ea | |||
| e95c5eed2c | |||
| aec0fcdb6e | |||
| 4b3814f85e | |||
| 151b3a299b | |||
| 9408170cb3 | |||
| e11cf87496 | |||
| 81c65c089a | |||
| 934a342fef | |||
| b483b31dab | |||
| 82b7d129d7 | |||
| a672c8337f | |||
| 63edba375c | |||
| 530da41f30 | |||
| 0a94ca9765 | |||
| a17f12e801 | |||
| 0faeeeea27 | |||
| c750f3de63 | |||
| af8ef3b1da | |||
| 1a68d6e7e1 | |||
| cb51189dce | |||
| f9a93a6aab | |||
| 2b6526e717 | |||
| 86a42029e3 | |||
| 278c04a414 | |||
| db6c4fc975 | |||
| 23f1bddc01 | |||
| 7051114f00 | |||
| ceea52abf6 | |||
| 1285dadea3 | |||
| e26695f647 | |||
| 25c302c393 | |||
| b7dda99c5e | |||
| 8238f53d71 | |||
| b6c2f9333c | |||
| f707b67259 | |||
| c15f312ff0 | |||
| 8f73f2a160 | |||
| 822ba7d3d8 | |||
| c1b4e91098 | |||
| 8e349b6d67 | |||
| 9d4a316732 | |||
| b6e158c52f | |||
| 8dd43942d3 | |||
| 0eddbe018e | |||
| bdfa413c98 | |||
| faf858b6d4 | |||
| ee483e0520 | |||
| 73ae7da37b | |||
| 4bdc10db61 | |||
| 5d839b02c2 | |||
| 3000cb1ee2 | |||
| 8be9386bdc | |||
| 4325b460cc | |||
| 216da8ebb0 | |||
| 71591d7822 | |||
| a7f445318d | |||
| 753493ae11 | |||
| f73bb3a21a | |||
| e89b812518 | |||
| 4fe1c7647c | |||
| 3c1814cac7 | |||
| 765ba4ce1e | |||
| 2d1ac616e8 | |||
| 23bf420120 | |||
| 5175bb487e | |||
| 198c28cda2 | |||
| 2b413491e3 | |||
| 98311522ed | |||
| 0a346972f3 | |||
| 54021dcedb | |||
| abeb9d6544 | |||
| 2c28f42bae | |||
| f5b49d8004 | |||
| c02b2fc931 | |||
| 3390644156 | |||
| fcb1e8a9c2 | |||
| cedd791b19 | |||
| 072e93e26e | |||
| f249f9f41a | |||
| d53cc3da71 | |||
| 1d3c72cafd | |||
| 4f3ed071d4 | |||
| 9de849779c | |||
| 67c5420a1f | |||
| 7dfed7234c | |||
| 3b80e3f77a | |||
| 2d43ffd1a9 | |||
| 899c251521 | |||
| 1bbe91bf16 | |||
| 924cc85e08 | |||
| 0ea2c043bc | |||
| a164b026c7 | |||
| 475cf8be48 | |||
| aea298fc35 | |||
| ca0074bf89 | |||
| c4dd3d8dbf | |||
| f754b93fb0 | |||
| 5414931209 | |||
| f320b2b391 | |||
| 170007b939 | |||
| cd60515114 | |||
| e9f88e7793 | |||
| 5199fcd7cb | |||
| 00d4919e69 | |||
| e14bbecd57 | |||
| 9e32e3befc | |||
| 695553b1a5 | |||
| c081554c0c | |||
| b73aaa678c | |||
| 47c938a31b | |||
| bad139d09d | |||
| 3a8a3bc3f9 | |||
| e8b0dadd6b | |||
| 4b2a23e36f | |||
| 294629be5f | |||
| 2e8d176e27 | |||
| d8d64eef11 | |||
| 997be8cd2d | |||
| 6958e7ebb0 | |||
| a3f41f5840 | |||
| f7a54f619a | |||
| 7bc4ca8b88 | |||
| 1980338f38 | |||
| d7bd06bfde | |||
| a74dd5b58c | |||
| 8ed407023d | |||
| fef6a23626 | |||
| 46ca4a9099 | |||
| 9df4af3757 | |||
| 4a77758f38 | |||
| 803d739f4a | |||
| 22ffc39685 | |||
| daf2f76125 | |||
| 760bce86ea | |||
| 8fec45ebf0 | |||
| 23aab8e694 | |||
| e87c4986dd | |||
| a62cfc3245 | |||
| 01865c55bd | |||
| e9b7ea41c4 | |||
| c82fa0c8ad | |||
| bab46e77d7 | |||
| 6aff5581f6 | |||
| 5cefb82acb | |||
| 9a24fe056e | |||
| e60ca92e1d | |||
| 522cbb467c | |||
| d7a9bd9da7 | |||
| 1aefe49544 | |||
| 42f05b95c6 | |||
| 90e35c8929 | |||
| 674ce27e1b | |||
| 8bbc71406d | |||
| e946e06322 | |||
| c50968f185 | |||
| 85cd13b837 | |||
| ff12f87c62 | |||
| 0257a401f7 | |||
| 9d9aef2fb0 | |||
| 4a8103d97b | |||
| 571516003b | |||
| 82d84457a0 | |||
| cfaf9dc5a7 | |||
| 23dab427de | |||
| d25049c0fc | |||
| 00e1213a81 | |||
| 021ee71b69 | |||
| 64ced100cc | |||
| 4c2f38ace1 | |||
| b440662be2 | |||
| 2d8c7cccd9 | |||
| 6d00d81b84 | |||
| 61fdbd038e | |||
| 72d8a0a12e | |||
| 5c74e0daca | |||
| 4a46fd643f | |||
| 60770bb0a7 | |||
| 62a1434588 | |||
| 20af9d3c0f | |||
| 7bf7ef3919 | |||
| f8a6c3d6f0 | |||
| 6499a17d78 | |||
| 8ecc049f7f | |||
| 68299e6154 | |||
| 48bdbf5a4a | |||
| 648bf857d3 | |||
| 166e18d7cb | |||
| 2c78623121 | |||
| 89b8ba6dba | |||
| 5c8ef12940 | |||
| d1ff9b957a | |||
| 077703b235 | |||
| 980903e56a | |||
| d830bd9a33 | |||
| 8f2db3c1a1 | |||
| 666248c264 | |||
| 1f8eb08428 | |||
| ada0205360 | |||
| 20c80d9e2f | |||
| fc22f80e9c | |||
| bdf5ae0e92 | |||
| fadff0062a | |||
| 849c19022c | |||
| 0076ac2d1c | |||
| 792fb3ea61 | |||
| 15dcd5a535 | |||
| 8ce2f33f9e | |||
| dcf8e1f5d8 | |||
| ca13549a89 | |||
| 20e563e825 | |||
| 0174a0a57f | |||
| 7047adfdbe | |||
| 47de7aac75 | |||
| 739d227c58 | |||
| 74556525de | |||
| 9d8348e13f | |||
| bbc12d9cb5 | |||
| 4637ad6f7e | |||
| 40d52d4067 | |||
| 68170f0b01 | |||
| a5ac47089e | |||
| 7d6e6ffceb | |||
| 0057543e5e | |||
| 07d9521c49 | |||
| 4ee23c10bb | |||
| 37648d141f | |||
| 3fd99e0ff6 | |||
| 2d47c45485 | |||
| f214d6e69a | |||
| e0cd470f1d | |||
| 5e44d5abaa | |||
| dba2527290 | |||
| 0b7cbdb0e6 | |||
| 92e7886965 | |||
| 7b414e6258 | |||
| 880c2fb8ba | |||
| e68af16896 | |||
| a2a8e3edf9 | |||
| 333c9cd9df | |||
| 5d4923ffcc | |||
| 2ce17661e8 | |||
| dc22f74419 | |||
| f7adf8a010 | |||
| 92267ed9fe | |||
| d520b92579 | |||
| 83f78c7c5e | |||
| 78e6292f47 | |||
| e666c72330 | |||
| db1cf750bd | |||
| 2522a179b0 | |||
| 30e2727e72 | |||
| faa963ba9a | |||
| 3bbb37741f | |||
| d0dd8d33bb | |||
| 824303bada | |||
| cb49ea51eb | |||
| c1f759ab50 | |||
| d183fbaf60 | |||
| 0d0552d430 | |||
| 55ab8ab731 | |||
| f50f41c507 | |||
| 86573d4ee6 | |||
| 548e5ecd1b | |||
| 695dc96b0e | |||
| 7345a2af94 | |||
| 2479cecad9 | |||
| de55ebff23 | |||
| 157e5a9f9c | |||
| b7860604f7 | |||
| eba3393014 | |||
| 16266791a0 | |||
| 2427ceef62 | |||
| 3e9dfd7f62 | |||
| dc9363a651 | |||
| 5c1049f72b | |||
| 125ca896df | |||
| 65684fa600 | |||
| c7b0eeee8e | |||
| dbf541f8e1 | |||
| 5636246c95 | |||
| 15e7db4e1d | |||
| 50ca770bc6 | |||
| 21d1577972 | |||
| 9d5a2e6f1c | |||
| 004659a6d0 | |||
| 47042403ca | |||
| fc463d34e8 | |||
| 188c45aef6 | |||
| 76b320818a | |||
| e0e6a127fa | |||
| b1e4d8b119 | |||
| 80fa42a001 | |||
| 63de1463f8 | |||
| 1510a9d6a1 | |||
| 4fdbb24243 | |||
| 32b48768d4 | |||
| a23eb149a8 | |||
| f0a38fd4c0 | |||
| 1b25b037dc | |||
| e7acf36d0d | |||
| 75c74acfa1 | |||
| 2df40c4f90 | |||
| 3f3ecc0311 | |||
| 20ab72d496 | |||
| f208379c9f | |||
| d61f480fb6 | |||
| 45ddf2980a | |||
| d57563edd6 | |||
| a095ad50c1 | |||
| 905050d73e | |||
| d20d8938a7 | |||
| e1d76a33e3 | |||
| 8fc9105a7a | |||
| 07a50c2f29 | |||
| f87c073039 | |||
| 28b751b244 | |||
| 9663e6f8a5 | |||
| 13f327b533 | |||
| e7b7b7fd8e | |||
| 90db0fb726 | |||
| fd554631f8 | |||
| 8bf65f15dd | |||
| ca0678bd96 | |||
| 9f6a3aee95 | |||
| 08c9c27c01 | |||
| 9b6218949a | |||
| 05dd6551bd | |||
| 5f8a991828 | |||
| d7b83310a7 | |||
| a25529102c | |||
| 883656ceb8 | |||
| c005cb8947 | |||
| 827fbc4515 | |||
| f8840f947c | |||
| 41b20b6e18 | |||
| 0e96add931 | |||
| 196c818a91 | |||
| 8791ab3304 | |||
| fc06491c75 | |||
| b70337b38c | |||
| 08f2855d64 | |||
| eb4b4c7ba0 | |||
| 23c3ce59ff | |||
| 87aa044351 | |||
| fa5cfedf4e | |||
| 89c7782a91 | |||
| e17dc7bcfa | |||
| 64f2725233 | |||
| 6e5c445714 | |||
| 95ef465948 | |||
| 0d893ad97b | |||
| 1110aed46a | |||
| 86fdc9dd64 | |||
| d66cfec3f0 | |||
| 677267791a | |||
| 8e9115725e | |||
| 179515b4de | |||
| 871c0ec7c5 | |||
| e7bc2568a6 | |||
| 9fca4525dc | |||
| 5fd16a3761 | |||
| af21acd472 | |||
| 272878cab9 | |||
| 38083d7ff3 | |||
| 86af5cb87c | |||
| fde80766e2 | |||
| 2f3c3abc1f | |||
| 871a036c74 | |||
| eb6e5390c9 | |||
| ac86e96914 | |||
| 66f93d133a | |||
| ae527646a1 | |||
| 0034fd8816 | |||
| 4c3f6d562f | |||
| b2d285491c | |||
| 4d7544a3a0 | |||
| 1d20e997a0 | |||
| a9af7d94e1 | |||
| 3a6f3f906a | |||
| 8beb255c10 | |||
| c800196f03 | |||
| 7a684b732c | |||
| 82358535df | |||
| 6637cf27b9 | |||
| 874db754ce | |||
| 7aa0860eca | |||
| 807c670765 | |||
| 36cef83e08 | |||
| 877ce4a64d | |||
| a5a3c48851 | |||
| 464280a23d | |||
| afce57cbea | |||
| 6e3438036a | |||
| 0d7ed311f8 | |||
| 52878b707a | |||
| 3616569d45 | |||
| a6afe639ca | |||
| 200862ff6e | |||
| 7de5920dd8 | |||
| ed94a2affd | |||
| e2f577e074 | |||
| 0ad0ddd1ea | |||
| 9a5044fa5c | |||
| 7c3e7cdae9 | |||
| acfc4c0b4d | |||
| 65f3549893 | |||
| 50df05ef78 | |||
| 322a1fa453 | |||
| 15601a33d9 | |||
| 42a1546bf8 | |||
| 0babaf208d | |||
| 9514d99333 | |||
| b51ee5ac52 | |||
| 2f4815a05b | |||
| 1a997d4b11 | |||
| d03434111a | |||
| 888d681014 | |||
| 2dbb5e22f7 | |||
| 49c4454cec | |||
| 19a43c48bf | |||
| 4532c861e1 | |||
| 1132d30d1f | |||
| 6e415f6a59 | |||
| a42f023698 | |||
| 18c31e25b6 | |||
| 6a46c626d6 | |||
| 321a4a90ab | |||
| bc389ac7c8 | |||
| 54c9783e5c | |||
| 646021e728 | |||
| 56f23662b1 | |||
| e002c90dab | |||
| 94ba162660 | |||
| b24571ea7d | |||
| d160b700e8 | |||
| 33f29f5adc | |||
| c5549ab475 | |||
| 1ec46dca1d | |||
| a8b6eaa3c4 | |||
| 25f6bc111d | |||
| 7874aa6eb7 | |||
| addeb650b9 | |||
| c3131a4ac2 | |||
| d60e4f6684 | |||
| cd2297972b | |||
| 7c399a1ba0 | |||
| 1b308f725a | |||
| 47235557d2 | |||
| 5abf0019f5 | |||
| 7ec197fd64 | |||
| 967d16dd52 | |||
| 5b4b64fc58 | |||
| 362598367c | |||
| 43b611f566 | |||
| 9832d18ab5 | |||
| 201d502a9b | |||
| 53bdea7476 | |||
| 1a49438ade | |||
| 4fb94f7f96 | |||
| 5638eb7c35 | |||
| 543ef5fa7c | |||
| c27601c459 | |||
| 6c66c20107 | |||
| 7221132d11 | |||
| c38626b055 | |||
| 7d99d3e9c4 | |||
| 529d4cdbc6 | |||
| cd07fceed1 | |||
| 26ae6e5792 | |||
| 217613ab21 | |||
| c017cc5ca9 | |||
| 03966a4ec0 | |||
| b1cb63b24f | |||
| ec373efd6d | |||
| 4a9dcf3f17 | |||
| f01e4739fd | |||
| 7d5774aaa2 | |||
| 7a562bf521 | |||
| 0c11e7ed30 | |||
| a33bc20d2e | |||
| e3353f92fc | |||
| 28e5ece329 | |||
| 239db05eec | |||
| 4fc9f74029 | |||
| e679a371ef | |||
| af8bd4de8e | |||
| 1cbfc11612 | |||
| bf75a73cc5 | |||
| 97dc7bfc0b | |||
| f60c23a781 | |||
| 2b0b60631d | |||
| 51a6bf7f1a | |||
| 2a6cc872ff | |||
| 350e34d177 | |||
| 67f6ebacff | |||
| e77dcc602d | |||
| aa1d665a3a | |||
| 2b0ea3051d | |||
| fa496d3fe1 | |||
| fa4ff1bd10 | |||
| 43f39c235f | |||
| 0e46c03356 | |||
| 940269660f | |||
| 4c2ba6794b | |||
| 7d14ae30e9 | |||
| 8ffb738721 | |||
| cf1cf9499f | |||
| d18bc9dc02 | |||
| 17f8fb7f3e | |||
| 969c26def0 | |||
| cbaad47bf2 | |||
| 9ccd8759ea | |||
| 5b26aca437 | |||
| 2e0b5708f1 | |||
| ce400f61e6 | |||
| 8257e19b7a | |||
| 8e73bb6328 | |||
| 2fa8db79cc | |||
| 1ad0beaf4f | |||
| 60802ff32e | |||
| b29da693b6 | |||
| 709f70145f | |||
| 9d14dcd64e | |||
| da14c5dff1 | |||
| d38ef5cfe0 | |||
| e6e58c7a92 | |||
| eba90af0d3 | |||
| 14f40dcc9c | |||
| 8758f4464f | |||
| 9fb8de4cd1 | |||
| 0720ecb621 | |||
| 6ae3b201cc | |||
| 056b54ff63 | |||
| 6a7348df5c | |||
| fc36e18fb1 | |||
| 3febb9e672 | |||
| ed065ceb93 | |||
| 26143abeaf | |||
| 9b3b40c1ab | |||
| b7acb1f0e8 | |||
| c7f36a87b3 | |||
| ba05f573ca | |||
| 967fe8ef0d | |||
| 4e37becc19 | |||
| 60b664a624 | |||
| b52ea3664e | |||
| 9bbe953b68 | |||
| 5389652d3c | |||
| 247946725c | |||
| 649356958e | |||
| 19602ce718 | |||
| d355d1f796 | |||
| 449693fc43 | |||
| 2538062907 | |||
| ada3d03f67 | |||
| e505b12188 | |||
| 9a6a761e1c | |||
| a9d792433f | |||
| fa58e13891 | |||
| 015f49d0d3 | |||
| 70dce3f450 | |||
| 3d5413d89a | |||
| 2c638ccb24 | |||
| 5016d9f4b7 | |||
| 9814a667ba | |||
| 5be375c379 | |||
| c5d0fcbf1f | |||
| 3414e35610 | |||
| c16cb40555 | |||
| 33c4973c67 | |||
| 72fcbcd444 | |||
| 167136718e | |||
| 7d80ee4455 | |||
| 49b427eda0 | |||
| 5fe214d9d8 | |||
| f6d6df37b6 | |||
| c8097f88a5 | |||
| cbeee0a46e | |||
| 2be96ee2d1 | |||
| a661cc9113 | |||
| 9b9226fc98 |
@@ -142,14 +142,14 @@ function print_auth_lock_options($auth, $user_fields, $helptext, $retrieveopts,
|
||||
$fieldname = $field;
|
||||
if ($fieldname === 'lang') {
|
||||
$fieldname = get_string('language');
|
||||
} elseif (preg_match('/^(.+?)(\d+)$/', $fieldname, $matches)) {
|
||||
$fieldname = get_string($matches[1]) . ' ' . $matches[2];
|
||||
} elseif ($fieldname == 'url') {
|
||||
$fieldname = get_string('webpage');
|
||||
} elseif (!empty($customfields) && in_array($field, $customfields)) {
|
||||
// If custom field then pick name from database.
|
||||
$fieldshortname = str_replace('profile_field_', '', $fieldname);
|
||||
$fieldname = $customfieldname[$fieldshortname]->name;
|
||||
} elseif (preg_match('/^(.+?)(\d+)$/', $fieldname, $matches)) {
|
||||
$fieldname = get_string($matches[1]) . ' ' . $matches[2];
|
||||
} elseif ($fieldname == 'url') {
|
||||
$fieldname = get_string('webpage');
|
||||
} else {
|
||||
$fieldname = get_string($fieldname);
|
||||
}
|
||||
|
||||
+18
-19
@@ -97,27 +97,26 @@ foreach ($settingspage->children as $childpage) {
|
||||
$outputhtml .= $OUTPUT->heading(html_writer::link($childpage->url, $childpage->visiblename), 3);
|
||||
} else if ($childpage instanceof admin_settingpage) {
|
||||
$outputhtml .= $OUTPUT->heading(html_writer::link(new moodle_url('/'.$CFG->admin.'/settings.php', array('section' => $childpage->name)), $childpage->visiblename), 3);
|
||||
// If its a settings page and has settings lets display them.
|
||||
if (!empty($childpage->settings)) {
|
||||
$outputhtml .= html_writer::start_tag('fieldset', array('class' => 'adminsettings'));
|
||||
foreach ($childpage->settings as $setting) {
|
||||
if (empty($setting->nosave)) {
|
||||
$savebutton = true;
|
||||
}
|
||||
$fullname = $setting->get_full_name();
|
||||
if (array_key_exists($fullname, $adminroot->errors)) {
|
||||
$data = $adminroot->errors[$fullname]->data;
|
||||
} else {
|
||||
$data = $setting->get_setting();
|
||||
}
|
||||
$outputhtml .= html_writer::tag('div', '<!-- -->', array('class' => 'clearer'));
|
||||
$outputhtml .= $setting->output_html($data);
|
||||
}
|
||||
$outputhtml .= html_writer::end_tag('fieldset');
|
||||
}
|
||||
} else if ($childpage instanceof admin_category) {
|
||||
$outputhtml .= $OUTPUT->heading(html_writer::link(new moodle_url('/'.$CFG->admin.'/category.php', array('category' => $childpage->name)), get_string('admincategory', 'admin', $childpage->visiblename)), 3);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (!empty($childpage->settings)) {
|
||||
$outputhtml .= html_writer::start_tag('fieldset', array('class' => 'adminsettings'));
|
||||
foreach ($childpage->settings as $setting) {
|
||||
if (empty($setting->nosave)) {
|
||||
$savebutton = true;
|
||||
}
|
||||
$fullname = $setting->get_full_name();
|
||||
if (array_key_exists($fullname, $adminroot->errors)) {
|
||||
$data = $adminroot->errors[$fullname]->data;
|
||||
} else {
|
||||
$data = $setting->get_setting();
|
||||
}
|
||||
$outputhtml .= html_writer::tag('div', '<!-- -->', array('class' => 'clearer'));
|
||||
$outputhtml .= $setting->output_html($data);
|
||||
}
|
||||
$outputhtml .= html_writer::end_tag('fieldset');
|
||||
}
|
||||
}
|
||||
if ($savebutton) {
|
||||
|
||||
@@ -201,17 +201,9 @@ if (defined('COMPONENT_CLASSLOADER')) {
|
||||
require($CFG->dirroot.'/version.php');
|
||||
$CFG->target_release = $release;
|
||||
|
||||
$_SESSION = array();
|
||||
$_SESSION['SESSION'] = new stdClass();
|
||||
$_SESSION['SESSION']->lang = $CFG->lang;
|
||||
$_SESSION['USER'] = new stdClass();
|
||||
$_SESSION['USER']->id = 0;
|
||||
$_SESSION['USER']->mnethostid = 1;
|
||||
|
||||
\core\session\manager::init_empty_session();
|
||||
global $SESSION;
|
||||
global $USER;
|
||||
$SESSION = &$_SESSION['SESSION'];
|
||||
$USER = &$_SESSION['USER'];
|
||||
|
||||
global $COURSE;
|
||||
$COURSE = new stdClass();
|
||||
|
||||
@@ -102,7 +102,7 @@ if ($contents = load_environment_xml()) {
|
||||
}
|
||||
|
||||
// Get the results of the environment check.
|
||||
list($envstatus, $environment_results) = check_moodle_environment($version);
|
||||
list($envstatus, $environment_results) = check_moodle_environment($version, ENV_SELECT_NEWER);
|
||||
|
||||
// Display the page.
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
+12
-6
@@ -382,9 +382,6 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
if (!$PAGE->headerprinted) {
|
||||
// means core upgrade or installation was not already done
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
if (!$confirmplugins) {
|
||||
$strplugincheck = get_string('plugincheck');
|
||||
|
||||
@@ -402,6 +399,9 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
redirect($PAGE->url);
|
||||
}
|
||||
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
|
||||
$deployer = \core\update\deployer::instance();
|
||||
if ($deployer->enabled()) {
|
||||
$deployer->initialize($PAGE->url, $PAGE->url);
|
||||
@@ -425,6 +425,8 @@ if (!$cache and moodle_needs_upgrading()) {
|
||||
// Make sure plugin dependencies are always checked.
|
||||
$failed = array();
|
||||
if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
|
||||
/** @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
$reloadurl = new moodle_url('/admin/index.php', array('cache' => 0));
|
||||
echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
|
||||
die();
|
||||
@@ -591,10 +593,14 @@ $availableupdatesfetch = $updateschecker->get_last_timefetched();
|
||||
$buggyiconvnomb = (!function_exists('mb_convert_encoding') and @iconv('UTF-8', 'UTF-8//IGNORE', '100'.chr(130).'€') !== '100€');
|
||||
//check if the site is registered on Moodle.org
|
||||
$registered = $DB->count_records('registration_hubs', array('huburl' => HUB_MOODLEORGHUBURL, 'confirmed' => 1));
|
||||
// Check if there are any cache warnings.
|
||||
$cachewarnings = cache_helper::warnings();
|
||||
|
||||
admin_externalpage_setup('adminnotifications');
|
||||
|
||||
/* @var core_admin_renderer $output */
|
||||
$output = $PAGE->get_renderer('core', 'admin');
|
||||
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
|
||||
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
|
||||
$registered);
|
||||
|
||||
echo $output->admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed, $cronoverdue, $dbproblems,
|
||||
$maintenancemode, $availableupdates, $availableupdatesfetch, $buggyiconvnomb,
|
||||
$registered, $cachewarnings);
|
||||
|
||||
+26
-7
@@ -303,12 +303,13 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* @param bool $buggyiconvnomb warn iconv problems
|
||||
* @param array|null $availableupdates array of \core\update\info objects or null
|
||||
* @param int|null $availableupdatesfetch timestamp of the most recent updates fetch or null (unknown)
|
||||
* @param string[] $cachewarnings An array containing warnings from the Cache API.
|
||||
*
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function admin_notifications_page($maturity, $insecuredataroot, $errorsdisplayed,
|
||||
$cronoverdue, $dbproblems, $maintenancemode, $availableupdates, $availableupdatesfetch,
|
||||
$buggyiconvnomb, $registered) {
|
||||
$buggyiconvnomb, $registered, array $cachewarnings = array()) {
|
||||
global $CFG;
|
||||
$output = '';
|
||||
|
||||
@@ -321,6 +322,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$output .= $this->cron_overdue_warning($cronoverdue);
|
||||
$output .= $this->db_problems($dbproblems);
|
||||
$output .= $this->maintenance_mode_warning($maintenancemode);
|
||||
$output .= $this->cache_warnings($cachewarnings);
|
||||
$output .= $this->registration_warning($registered);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -583,6 +585,19 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
return $this->warning($dbproblems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders cache warnings if there are any.
|
||||
*
|
||||
* @param string[] $cachewarnings
|
||||
* @return string
|
||||
*/
|
||||
public function cache_warnings(array $cachewarnings) {
|
||||
if (!count($cachewarnings)) {
|
||||
return '';
|
||||
}
|
||||
return join("\n", array_map(array($this, 'warning'), $cachewarnings));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an appropriate message if the site in in maintenance mode.
|
||||
* @param bool $maintenancemode
|
||||
@@ -1355,7 +1370,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
* configuration and how it suits Moodle needs.
|
||||
*
|
||||
* @param boolean $result final result of the check (true/false)
|
||||
* @param array $environment_results array of results gathered
|
||||
* @param environment_results[] $environment_results array of results gathered
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function environment_check_table($result, $environment_results) {
|
||||
@@ -1367,9 +1382,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
get_string('name'),
|
||||
get_string('info'),
|
||||
get_string('report'),
|
||||
get_string('plugin'),
|
||||
get_string('status'),
|
||||
);
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign status', 'leftalign report', 'centeralign info');
|
||||
$servertable->colclasses = array('centeralign name', 'centeralign info', 'leftalign report', 'leftalign plugin', 'centeralign status');
|
||||
$servertable->attributes['class'] = 'admintable environmenttable generaltable';
|
||||
$servertable->id = 'serverstatus';
|
||||
|
||||
@@ -1379,9 +1395,10 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$othertable->head = array(
|
||||
get_string('info'),
|
||||
get_string('report'),
|
||||
get_string('plugin'),
|
||||
get_string('status'),
|
||||
);
|
||||
$othertable->colclasses = array('aligncenter info', 'alignleft report', 'aligncenter status');
|
||||
$othertable->colclasses = array('aligncenter info', 'alignleft report', 'alignleft plugin', 'aligncenter status');
|
||||
$othertable->attributes['class'] = 'admintable environmenttable generaltable';
|
||||
$othertable->id = 'otherserverstatus';
|
||||
|
||||
@@ -1397,6 +1414,7 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
$type = $environment_result->getPart();
|
||||
$info = $environment_result->getInfo();
|
||||
$status = $environment_result->getStatus();
|
||||
$plugin = $environment_result->getPluginName();
|
||||
$error_code = $environment_result->getErrorCode();
|
||||
// Process Report field
|
||||
$rec = new stdClass();
|
||||
@@ -1473,7 +1491,8 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
if (!empty($info)){
|
||||
$linkparts[] = $info;
|
||||
}
|
||||
if (empty($CFG->docroot)) {
|
||||
// Plugin environments do not have docs pages yet.
|
||||
if (empty($CFG->docroot) or $environment_result->plugin) {
|
||||
$report = get_string($stringtouse, 'admin', $rec);
|
||||
} else {
|
||||
$report = $this->doc_link(join($linkparts, '/'), get_string($stringtouse, 'admin', $rec));
|
||||
@@ -1499,9 +1518,9 @@ class core_admin_renderer extends plugin_renderer_base {
|
||||
|
||||
// Add the row to the table
|
||||
if ($environment_result->getPart() == 'custom_check'){
|
||||
$otherdata[$messagetype][] = array ($info, $report, $status);
|
||||
$otherdata[$messagetype][] = array ($info, $report, $plugin, $status);
|
||||
} else {
|
||||
$serverdata[$messagetype][] = array ($type, $info, $report, $status);
|
||||
$serverdata[$messagetype][] = array ($type, $info, $report, $plugin, $status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ if ($roleid) {
|
||||
// Show UI for assigning a particular role to users.
|
||||
// Print a warning if we are assigning system roles.
|
||||
if ($context->contextlevel == CONTEXT_SYSTEM) {
|
||||
echo $OUTPUT->box(get_string('globalroleswarning', 'core_role'));
|
||||
echo $OUTPUT->notification(get_string('globalroleswarning', 'core_role'));
|
||||
}
|
||||
|
||||
// Print the form.
|
||||
@@ -251,7 +251,7 @@ if ($roleid) {
|
||||
|
||||
// Print a warning if we are assigning system roles.
|
||||
if ($context->contextlevel == CONTEXT_SYSTEM) {
|
||||
echo $OUTPUT->box(get_string('globalroleswarning', 'core_role'));
|
||||
echo $OUTPUT->notification(get_string('globalroleswarning', 'core_role'));
|
||||
}
|
||||
|
||||
// Print instruction.
|
||||
|
||||
@@ -74,8 +74,16 @@ abstract class core_role_capability_table_base {
|
||||
public function display() {
|
||||
if (count($this->capabilities) > self::NUM_CAPS_FOR_SEARCH) {
|
||||
global $PAGE;
|
||||
$PAGE->requires->strings_for_js(array('filter', 'clear'), 'moodle');
|
||||
$PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, $this->context->id));
|
||||
$jsmodule = array(
|
||||
'name' => 'rolescapfilter',
|
||||
'fullpath' => '/admin/roles/module.js',
|
||||
'strings' => array(
|
||||
array('filter', 'moodle'),
|
||||
array('clear', 'moodle'), ),
|
||||
'requires' => array('node', 'cookie', 'escape')
|
||||
);
|
||||
$PAGE->requires->js_init_call('M.core_role.init_cap_table_filter', array($this->id, $this->context->id), false,
|
||||
$jsmodule);
|
||||
}
|
||||
echo '<table class="' . implode(' ', $this->classes) . '" id="' . $this->id . '">' . "\n<thead>\n";
|
||||
echo '<tr><th class="name" align="left" scope="col">' . get_string('capability', 'core_role') . '</th>';
|
||||
|
||||
@@ -75,7 +75,8 @@ switch ($action) {
|
||||
$a->id = $roleid;
|
||||
$a->name = $roles[$roleid]->name;
|
||||
$a->shortname = $roles[$roleid]->shortname;
|
||||
$a->count = $DB->count_records('role_assignments', array('roleid'=>$roleid));
|
||||
$a->count = $DB->count_records_select('role_assignments',
|
||||
'roleid = ?', array($roleid), 'COUNT(DISTINCT userid)');
|
||||
|
||||
$formcontinue = new single_button(new moodle_url($baseurl, $optionsyes), get_string('yes'));
|
||||
$formcancel = new single_button(new moodle_url($baseurl), get_string('no'), 'get');
|
||||
|
||||
@@ -51,7 +51,7 @@ M.core_role.init_cap_table_filter = function(Y, tableid, contextid) {
|
||||
marginRight : 'auto'
|
||||
});
|
||||
// Create the capability search input.
|
||||
this.input = Y.Node.create('<input type="text" id="'+this.table.get('id')+'capabilitysearch" value="'+filtervalue+'" />');
|
||||
this.input = Y.Node.create('<input type="text" id="'+this.table.get('id')+'capabilitysearch" value="'+Y.Escape.html(filtervalue)+'" />');
|
||||
// Create a label for the search input.
|
||||
this.label = Y.Node.create('<label for="'+this.input.get('id')+'">'+M.str.moodle.filter+' </label>');
|
||||
// Create a clear button to clear the input.
|
||||
|
||||
@@ -139,7 +139,6 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
array(
|
||||
'context' => $context,
|
||||
'objectid' => $roleid,
|
||||
'courseid' => $courseid
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@@ -80,7 +80,8 @@ class behat_admin extends behat_base {
|
||||
// Single element settings.
|
||||
try {
|
||||
$fieldxpath = "//*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]" .
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for]";
|
||||
"[@id=//label[contains(normalize-space(.), $label)]/@for or " .
|
||||
"@id=//span[contains(normalize-space(.), $label)]/preceding-sibling::label[1]/@for]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath, $exception);
|
||||
|
||||
$formfieldtypenode = $this->find('xpath', $fieldxpath . "/ancestor::div[@class='form-setting']" .
|
||||
@@ -89,7 +90,7 @@ class behat_admin extends behat_base {
|
||||
} catch (ElementNotFoundException $e) {
|
||||
|
||||
// Multi element settings, interacting only the first one.
|
||||
$fieldxpath = "//descendant::label[.= $label]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
$fieldxpath = "//*[label[.= $label]|span[.= $label]]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' form-item ')]" .
|
||||
"/descendant::div[@class='form-group']/descendant::*[self::input | self::textarea | self::select][not(./@type = 'submit' or ./@type = 'image' or ./@type = 'hidden')]";
|
||||
$fieldnode = $this->find('xpath', $fieldxpath);
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
@core @core_admin
|
||||
Feature: Set admin settings value
|
||||
In order to set admin settings value
|
||||
As an admin
|
||||
I need to set admin setting value and verify it is applied
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname | category |
|
||||
| Course fullname | C_shortname | 0 |
|
||||
And I log in as "admin"
|
||||
And I should see "Course fullname"
|
||||
And I should not see "C_shortname Course fullname"
|
||||
|
||||
Scenario: set admin value with full name
|
||||
Given I set the following administration settings values:
|
||||
| Display extended course names | 1 |
|
||||
When I press "Save changes"
|
||||
And I am on homepage
|
||||
Then I should see "C_shortname Course fullname"
|
||||
|
||||
Scenario: set admin value with short name
|
||||
Given I set the following administration settings values:
|
||||
| courselistshortnames | 1 |
|
||||
When I press "Save changes"
|
||||
And I am on homepage
|
||||
Then I should see "C_shortname Course fullname"
|
||||
@@ -27,6 +27,11 @@ require_once($CFG->libdir.'/adminlib.php');
|
||||
require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php');
|
||||
require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
|
||||
|
||||
// This page usually takes an exceedingly long time to load, so we need to
|
||||
// increase the time limit. At present it takes about a minute on some
|
||||
// systems, but let's allow room for expansion.
|
||||
set_time_limit(300);
|
||||
|
||||
$filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
|
||||
$type = optional_param('type', false, PARAM_ALPHAEXT);
|
||||
$component = optional_param('component', '', PARAM_ALPHAEXT);
|
||||
|
||||
@@ -233,3 +233,25 @@ Feature: Set up contextual data for tests
|
||||
And the "members" select box should contain "Student 1"
|
||||
And I select "Group 2 (1)" from "groups"
|
||||
And the "members" select box should contain "Student 2"
|
||||
|
||||
Scenario: Add cohorts with data generator
|
||||
Given the following "categories" exist:
|
||||
| name | category | idnumber |
|
||||
| Cat 1 | 0 | CAT1 |
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber |
|
||||
| System cohort 1 | CH01 |
|
||||
And the following "cohorts" exist:
|
||||
| name | idnumber | contextlevel | reference |
|
||||
| System cohort 2 | CH02 | System | |
|
||||
| Cohort in category 1 | CH1 | Category | CAT1 |
|
||||
When I log in as "admin"
|
||||
And I navigate to "Cohorts" node in "Site administration > Users > Accounts"
|
||||
Then I should see "System cohort 1"
|
||||
And I should see "System cohort 2"
|
||||
And I should not see "Cohort in category"
|
||||
And I follow "Courses"
|
||||
And I follow "Cat 1"
|
||||
And I follow "Cohorts"
|
||||
And I should see "Cohort in category 1"
|
||||
And I should not see "System cohort"
|
||||
|
||||
@@ -36,6 +36,10 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
* @var array Number of sections in course
|
||||
*/
|
||||
private static $paramsections = array(1, 10, 100, 500, 1000, 2000);
|
||||
/**
|
||||
* @var array Number of assignments in course
|
||||
*/
|
||||
private static $paramassignments = array(1, 10, 100, 500, 1000, 2000);
|
||||
/**
|
||||
* @var array Number of Page activities in course
|
||||
*/
|
||||
@@ -179,6 +183,7 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
// Make course.
|
||||
$this->course = $this->create_course();
|
||||
$this->create_users();
|
||||
$this->create_assignments();
|
||||
$this->create_pages();
|
||||
$this->create_small_files();
|
||||
$this->create_big_files();
|
||||
@@ -318,6 +323,26 @@ class tool_generator_course_backend extends tool_generator_backend {
|
||||
$this->end_log();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a number of Assignment activities.
|
||||
*/
|
||||
private function create_assignments() {
|
||||
// Set up generator.
|
||||
$assigngenerator = $this->generator->get_plugin_generator('mod_assign');
|
||||
|
||||
// Create assignments.
|
||||
$number = self::$paramassignments[$this->size];
|
||||
$this->log('createassignments', $number, true);
|
||||
for ($i = 0; $i < $number; $i++) {
|
||||
$record = array('course' => $this->course);
|
||||
$options = array('section' => $this->get_target_section());
|
||||
$assigngenerator->create_instance($record, $options);
|
||||
$this->dot($i, $number);
|
||||
}
|
||||
|
||||
$this->end_log();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a number of Page activities.
|
||||
*/
|
||||
|
||||
@@ -71,6 +71,7 @@ $string['pluginname'] = 'Development data generator';
|
||||
$string['progress_checkaccounts'] = 'Checking user accounts ({$a})';
|
||||
$string['progress_coursecompleted'] = 'Course completed ({$a}s)';
|
||||
$string['progress_createaccounts'] = 'Creating user accounts ({$a->from} - {$a->to})';
|
||||
$string['progress_createassignments'] = 'Creating assignments ({$a})';
|
||||
$string['progress_createbigfiles'] = 'Creating big files ({$a})';
|
||||
$string['progress_createcourse'] = 'Creating course {$a}';
|
||||
$string['progress_createforum'] = 'Creating forum ({$a} posts)';
|
||||
|
||||
@@ -669,7 +669,7 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
|
||||
if ($doupdate or $existinguser->password !== $oldpw) {
|
||||
// We want only users that were really updated.
|
||||
user_update_user($existinguser, false);
|
||||
user_update_user($existinguser, false, false);
|
||||
|
||||
$upt->track('status', $struserupdated);
|
||||
$usersupdated++;
|
||||
@@ -687,6 +687,9 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger event.
|
||||
\core\event\user_updated::create_from_userid($existinguser->id)->trigger();
|
||||
|
||||
} else {
|
||||
// no user information changed
|
||||
$upt->track('status', $struseruptodate);
|
||||
@@ -800,7 +803,7 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
$upt->track('password', '-', 'normal', false);
|
||||
}
|
||||
|
||||
$user->id = user_create_user($user, false);
|
||||
$user->id = user_create_user($user, false, false);
|
||||
$upt->track('username', html_writer::link(new moodle_url('/user/profile.php', array('id'=>$user->id)), s($user->username)), 'normal', false);
|
||||
|
||||
// pre-process custom profile menu fields data from csv file
|
||||
@@ -815,6 +818,9 @@ if ($formdata = $mform2->is_cancelled()) {
|
||||
set_user_preference('create_password', 1, $user);
|
||||
}
|
||||
|
||||
// Trigger event.
|
||||
\core\event\user_created::create_from_userid($user->id)->trigger();
|
||||
|
||||
$upt->track('status', $struseradded);
|
||||
$upt->track('id', $user->id, 'normal', false);
|
||||
$usersnew++;
|
||||
|
||||
+260
-348
@@ -63,7 +63,7 @@ if (!defined('E_USER_DEPRECATED')) {
|
||||
/**
|
||||
* phpCAS version. accessible for the user by phpCAS::getVersion().
|
||||
*/
|
||||
define('PHPCAS_VERSION', '1.3.2');
|
||||
define('PHPCAS_VERSION', '1.3.3');
|
||||
|
||||
/**
|
||||
* @addtogroup public
|
||||
@@ -78,6 +78,10 @@ define("CAS_VERSION_1_0", '1.0');
|
||||
* CAS version 2.0
|
||||
*/
|
||||
define("CAS_VERSION_2_0", '2.0');
|
||||
/**
|
||||
* CAS version 3.0
|
||||
*/
|
||||
define("CAS_VERSION_3_0", '3.0');
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// SAML defines
|
||||
@@ -318,18 +322,6 @@ class phpCAS
|
||||
if (is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
|
||||
}
|
||||
if (gettype($server_version) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');
|
||||
}
|
||||
if (gettype($server_hostname) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');
|
||||
}
|
||||
if (gettype($server_port) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');
|
||||
}
|
||||
if (gettype($server_uri) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');
|
||||
}
|
||||
|
||||
// store where the initializer is called from
|
||||
$dbg = debug_backtrace();
|
||||
@@ -341,10 +333,14 @@ class phpCAS
|
||||
);
|
||||
|
||||
// initialize the object $_PHPCAS_CLIENT
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, false, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, false, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -370,18 +366,6 @@ class phpCAS
|
||||
if (is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error(self::$_PHPCAS_INIT_CALL['method'] . '() has already been called (at ' . self::$_PHPCAS_INIT_CALL['file'] . ':' . self::$_PHPCAS_INIT_CALL['line'] . ')');
|
||||
}
|
||||
if (gettype($server_version) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_version (should be `string\')');
|
||||
}
|
||||
if (gettype($server_hostname) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_hostname (should be `string\')');
|
||||
}
|
||||
if (gettype($server_port) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $server_port (should be `integer\')');
|
||||
}
|
||||
if (gettype($server_uri) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $server_uri (should be `string\')');
|
||||
}
|
||||
|
||||
// store where the initialzer is called from
|
||||
$dbg = debug_backtrace();
|
||||
@@ -393,10 +377,14 @@ class phpCAS
|
||||
);
|
||||
|
||||
// initialize the object $_PHPCAS_CLIENT
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, true, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT = new CAS_Client(
|
||||
$server_version, true, $server_hostname, $server_port, $server_uri,
|
||||
$changeSessionID
|
||||
);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -636,13 +624,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setLang($lang)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setLang($lang);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($lang) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $lang (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setLang($lang);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -682,13 +670,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setHTMLHeader($header)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setHTMLHeader($header);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($header) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $header (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setHTMLHeader($header);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -700,13 +688,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setHTMLFooter($footer)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($footer) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $footer (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setHTMLFooter($footer);
|
||||
}
|
||||
|
||||
/** @} */
|
||||
@@ -729,19 +717,13 @@ class phpCAS
|
||||
public static function setPGTStorage($storage)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setPGTStorage($storage);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
|
||||
}
|
||||
if ( !($storage instanceof CAS_PGTStorage) ) {
|
||||
phpCAS :: error('type mismatched for parameter $storage (should be a CAS_PGTStorage `object\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setPGTStorage($storage);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -766,25 +748,13 @@ class phpCAS
|
||||
$password='', $table='', $driver_options=null
|
||||
) {
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
|
||||
}
|
||||
if (gettype($username) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $username (should be `string\')');
|
||||
}
|
||||
if (gettype($password) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $password (should be `string\')');
|
||||
}
|
||||
if (gettype($table) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $table (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageDb($dsn_or_pdo, $username, $password, $table, $driver_options);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -799,19 +769,13 @@ class phpCAS
|
||||
public static function setPGTStorageFile($path = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called before ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() (called at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ')');
|
||||
}
|
||||
if (gettype($path) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $path (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setPGTStorageFile($path);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
/** @} */
|
||||
@@ -836,23 +800,13 @@ class phpCAS
|
||||
public static function getProxiedService ($type)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
if (gettype($type) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $type (should be `string\')');
|
||||
}
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
$res = self::$_PHPCAS_CLIENT->getProxiedService($type);
|
||||
try {
|
||||
$res = self::$_PHPCAS_CLIENT->getProxiedService($type);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
return $res;
|
||||
@@ -872,20 +826,13 @@ class phpCAS
|
||||
*/
|
||||
public static function initializeProxiedService (CAS_ProxiedService $proxiedService)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->initializeProxiedService($proxiedService);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -906,23 +853,13 @@ class phpCAS
|
||||
public static function serviceWeb($url, & $err_code, & $output)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
$res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
|
||||
try {
|
||||
$res = self::$_PHPCAS_CLIENT->serviceWeb($url, $err_code, $output);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
|
||||
phpCAS :: traceEnd($res);
|
||||
return $res;
|
||||
@@ -950,28 +887,14 @@ class phpCAS
|
||||
public static function serviceMail($url, $service, $flags, & $err_code, & $err_msg, & $pt)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after the programmer is sure the user has been authenticated (by calling ' . __CLASS__ . '::checkAuthentication() or ' . __CLASS__ . '::forceAuthentication()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
if (gettype($flags) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $flags (should be `integer\')');
|
||||
try {
|
||||
$res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
|
||||
$res = self::$_PHPCAS_CLIENT->serviceMail($url, $service, $flags, $err_code, $err_msg, $pt);
|
||||
|
||||
phpCAS :: traceEnd($res);
|
||||
return $res;
|
||||
}
|
||||
@@ -998,13 +921,13 @@ class phpCAS
|
||||
*/
|
||||
public static function setCacheTimesForAuthRecheck($n)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($n) != 'integer') {
|
||||
phpCAS :: error('type mismatched for parameter $n (should be `integer\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setCacheTimesForAuthRecheck($n);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1028,9 +951,7 @@ class phpCAS
|
||||
*/
|
||||
public static function setPostAuthenticateCallback ($function, array $additionalArgs = array())
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
self::$_PHPCAS_CLIENT->setPostAuthenticateCallback($function, $additionalArgs);
|
||||
}
|
||||
@@ -1051,9 +972,7 @@ class phpCAS
|
||||
*/
|
||||
public static function setSingleSignoutCallback ($function, array $additionalArgs = array())
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
self::$_PHPCAS_CLIENT->setSingleSignoutCallback($function, $additionalArgs);
|
||||
}
|
||||
@@ -1071,9 +990,7 @@ class phpCAS
|
||||
public static function checkAuthentication()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
$auth = self::$_PHPCAS_CLIENT->checkAuthentication();
|
||||
|
||||
@@ -1094,16 +1011,13 @@ class phpCAS
|
||||
public static function forceAuthentication()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
|
||||
phpCAS::_validateClientExists();
|
||||
$auth = self::$_PHPCAS_CLIENT->forceAuthentication();
|
||||
|
||||
// store where the authentication has been checked and the result
|
||||
self::$_PHPCAS_CLIENT->markAuthenticationCall($auth);
|
||||
|
||||
/* if (!$auth) {
|
||||
/* if (!$auth) {
|
||||
phpCAS :: trace('user is not authenticated, redirecting to the CAS server');
|
||||
self::$_PHPCAS_CLIENT->forceAuthentication();
|
||||
} else {
|
||||
@@ -1122,9 +1036,8 @@ class phpCAS
|
||||
public static function renewAuthentication()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
$auth = self::$_PHPCAS_CLIENT->renewAuthentication();
|
||||
|
||||
// store where the authentication has been checked and the result
|
||||
@@ -1143,9 +1056,7 @@ class phpCAS
|
||||
public static function isAuthenticated()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
// call the isAuthenticated method of the $_PHPCAS_CLIENT object
|
||||
$auth = self::$_PHPCAS_CLIENT->isAuthenticated();
|
||||
@@ -1166,9 +1077,8 @@ class phpCAS
|
||||
*/
|
||||
public static function isSessionAuthenticated()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
return (self::$_PHPCAS_CLIENT->isSessionAuthenticated());
|
||||
}
|
||||
|
||||
@@ -1176,65 +1086,56 @@ class phpCAS
|
||||
* This method returns the CAS user's login name.
|
||||
*
|
||||
* @return string the login name of the authenticated user
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
* */
|
||||
public static function getUser()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->getUser();
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer attributes about the authenticated user.
|
||||
*
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getAttributes()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->getAttributes();
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer true if there are attributes for the authenticated user.
|
||||
*
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function hasAttributes()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->hasAttributes();
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->hasAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1243,21 +1144,18 @@ class phpCAS
|
||||
* @param string $key attribute name
|
||||
*
|
||||
* @return bool
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*/
|
||||
public static function hasAttribute($key)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->hasAttribute($key);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->hasAttribute($key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1266,21 +1164,18 @@ class phpCAS
|
||||
* @param string $key attribute name
|
||||
*
|
||||
* @return mixed string for a single value or an array if multiple values exist.
|
||||
* @warning should not be called only after phpCAS::forceAuthentication()
|
||||
* @warning should only be called after phpCAS::forceAuthentication()
|
||||
* or phpCAS::checkAuthentication().
|
||||
*/
|
||||
public static function getAttribute($key)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
return self::$_PHPCAS_CLIENT->getAttribute($key);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCalled()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::forceAuthentication() or ' . __CLASS__ . '::isAuthenticated()');
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->wasAuthenticationCallSuccessful()) {
|
||||
phpCAS :: error('authentication was checked (by ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerMethod() . '() at ' . self::$_PHPCAS_CLIENT->getAuthenticationCallerFile() . ':' . self::$_PHPCAS_CLIENT->getAuthenticationCallerLine() . ') but the method returned false');
|
||||
}
|
||||
return self::$_PHPCAS_CLIENT->getAttribute($key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1293,9 +1188,8 @@ class phpCAS
|
||||
*/
|
||||
public static function handleLogoutRequests($check_client = true, $allowed_clients = false)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
return (self::$_PHPCAS_CLIENT->handleLogoutRequests($check_client, $allowed_clients));
|
||||
}
|
||||
|
||||
@@ -1307,9 +1201,8 @@ class phpCAS
|
||||
*/
|
||||
public static function getServerLoginURL()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
return self::$_PHPCAS_CLIENT->getServerLoginURL();
|
||||
}
|
||||
|
||||
@@ -1324,13 +1217,14 @@ class phpCAS
|
||||
public static function setServerLoginURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerLoginURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string`)');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerLoginURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1345,13 +1239,14 @@ class phpCAS
|
||||
public static function setServerServiceValidateURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string`)');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerServiceValidateURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1366,13 +1261,14 @@ class phpCAS
|
||||
public static function setServerProxyValidateURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string`)');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerProxyValidateURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1386,13 +1282,14 @@ class phpCAS
|
||||
public static function setServerSamlValidateURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after' . __CLASS__ . '::client()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be`string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerSamlValidateURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1404,9 +1301,8 @@ class phpCAS
|
||||
*/
|
||||
public static function getServerLogoutURL()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should not be called before ' . __CLASS__ . '::client() or ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
return self::$_PHPCAS_CLIENT->getServerLogoutURL();
|
||||
}
|
||||
|
||||
@@ -1421,17 +1317,14 @@ class phpCAS
|
||||
public static function setServerLogoutURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error(
|
||||
'this method should only be called after' . __CLASS__ . '::client()'
|
||||
);
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error(
|
||||
'type mismatched for parameter $url (should be `string`)'
|
||||
);
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setServerLogoutURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1446,9 +1339,8 @@ class phpCAS
|
||||
public static function logout($params = "")
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
$parsedParams = array ();
|
||||
if ($params != "") {
|
||||
if (is_string($params)) {
|
||||
@@ -1480,9 +1372,8 @@ class phpCAS
|
||||
public static function logoutWithRedirectService($service)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_string($service)) {
|
||||
phpCAS :: error('type mismatched for parameter $service (should be `string\')');
|
||||
}
|
||||
@@ -1532,9 +1423,8 @@ class phpCAS
|
||||
{
|
||||
trigger_error('Function deprecated for cas servers >= 3.3.5.1', E_USER_DEPRECATED);
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (!is_string($service)) {
|
||||
phpCAS :: error('type mismatched for parameter $service (should be `string\')');
|
||||
}
|
||||
@@ -1563,16 +1453,14 @@ class phpCAS
|
||||
public static function setFixedCallbackURL($url = '')
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setCallbackURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (!self::$_PHPCAS_CLIENT->isProxy()) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setCallbackURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1587,13 +1475,14 @@ class phpCAS
|
||||
public static function setFixedServiceURL($url)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setURL($url);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($url) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $url (should be `string\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setURL($url);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1604,9 +1493,7 @@ class phpCAS
|
||||
*/
|
||||
public static function getServiceURL()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateProxyExists();
|
||||
return (self::$_PHPCAS_CLIENT->getURL());
|
||||
}
|
||||
|
||||
@@ -1621,13 +1508,13 @@ class phpCAS
|
||||
*/
|
||||
public static function retrievePT($target_service, & $err_code, & $err_msg)
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
try {
|
||||
return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($target_service) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $target_service(should be `string\')');
|
||||
}
|
||||
return (self::$_PHPCAS_CLIENT->retrievePT($target_service, $err_code, $err_msg));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1642,16 +1529,14 @@ class phpCAS
|
||||
public static function setCasServerCACert($cert, $validate_cn = true)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if (gettype($cert) != 'string') {
|
||||
phpCAS :: error('type mismatched for parameter $cert (should be `string\')');
|
||||
}
|
||||
if (gettype($validate_cn) != 'boolean') {
|
||||
phpCAS :: error('type mismatched for parameter $validate_cn (should be `boolean\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->setCasServerCACert($cert, $validate_cn);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
|
||||
@@ -1663,9 +1548,8 @@ class phpCAS
|
||||
public static function setNoCasServerValidation()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
phpCAS :: trace('You have configured no validation of the legitimacy of the cas server. This is not recommended for production use.');
|
||||
self::$_PHPCAS_CLIENT->setNoCasServerValidation();
|
||||
phpCAS :: traceEnd();
|
||||
@@ -1684,9 +1568,8 @@ class phpCAS
|
||||
public static function setNoClearTicketsFromUrl()
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
self::$_PHPCAS_CLIENT->setNoClearTicketsFromUrl();
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
@@ -1705,9 +1588,8 @@ class phpCAS
|
||||
public static function setExtraCurlOption($key, $value)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
self::$_PHPCAS_CLIENT->setExtraCurlOption($key, $value);
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
@@ -1751,11 +1633,11 @@ class phpCAS
|
||||
public static function allowProxyChain(CAS_ProxyChain_Interface $proxy_chain)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
}
|
||||
if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0) {
|
||||
phpCAS :: error('this method can only be used with the cas 2.0 protool');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
if (self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_2_0
|
||||
&& self::$_PHPCAS_CLIENT->getServerVersion() !== CAS_VERSION_3_0) {
|
||||
phpCAS :: error('this method can only be used with the cas 2.0/3.0 protocols');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->getAllowedProxyChains()->allowProxyChain($proxy_chain);
|
||||
phpCAS :: traceEnd();
|
||||
@@ -1772,9 +1654,7 @@ class phpCAS
|
||||
*/
|
||||
public static function getProxies ()
|
||||
{
|
||||
if ( !is_object(self::$_PHPCAS_CLIENT) ) {
|
||||
phpCAS::error('this method should only be called after '.__CLASS__.'::client()');
|
||||
}
|
||||
phpCAS::_validateProxyExists();
|
||||
|
||||
return(self::$_PHPCAS_CLIENT->getProxies());
|
||||
}
|
||||
@@ -1795,13 +1675,14 @@ class phpCAS
|
||||
{
|
||||
phpCAS::traceBegin();
|
||||
phpCAS::log('rebroadcastNodeUrl:'.$rebroadcastNodeUrl);
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
if ( !(bool)preg_match("/^(http|https):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i", $rebroadcastNodeUrl)) {
|
||||
phpCAS::error('type mismatched for parameter $rebroadcastNodeUrl (should be `url\')');
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastNode($rebroadcastNodeUrl);
|
||||
|
||||
phpCAS::traceEnd();
|
||||
}
|
||||
|
||||
@@ -1816,14 +1697,45 @@ class phpCAS
|
||||
public static function addRebroadcastHeader($header)
|
||||
{
|
||||
phpCAS :: traceBegin();
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
phpCAS :: error('this method should only be called after ' . __CLASS__ . '::client() or' . __CLASS__ . '::proxy()');
|
||||
phpCAS::_validateClientExists();
|
||||
|
||||
try {
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
|
||||
} catch (Exception $e) {
|
||||
phpCAS :: error(get_class($e) . ': ' . $e->getMessage());
|
||||
}
|
||||
self::$_PHPCAS_CLIENT->addRebroadcastHeader($header);
|
||||
|
||||
phpCAS :: traceEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a client already exists
|
||||
*
|
||||
* @throws CAS_OutOfSequenceBeforeClientException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function _validateClientExists()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
throw new CAS_OutOfSequenceBeforeClientException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks of a proxy client aready exists
|
||||
*
|
||||
* @throws CAS_OutOfSequenceBeforeProxyException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function _validateProxyExists()
|
||||
{
|
||||
if (!is_object(self::$_PHPCAS_CLIENT)) {
|
||||
throw new CAS_OutOfSequenceBeforeProxyException();
|
||||
}
|
||||
}
|
||||
}
|
||||
// ########################################################################
|
||||
// DOCUMENTATION
|
||||
// ########################################################################
|
||||
|
||||
@@ -74,7 +74,7 @@ implements CAS_Exception
|
||||
printf(
|
||||
$lang->getYouWereNotAuthenticated(),
|
||||
htmlentities($client->getURL()),
|
||||
$_SERVER['SERVER_ADMIN']
|
||||
isset($_SERVER['SERVER_ADMIN']) ? $_SERVER['SERVER_ADMIN']:''
|
||||
);
|
||||
phpCAS::trace('CAS URL: '.$cas_url);
|
||||
phpCAS::trace('Authentication failure: '.$failure);
|
||||
@@ -89,6 +89,7 @@ implements CAS_Exception
|
||||
phpCAS::trace('Reason: CAS error');
|
||||
break;
|
||||
case CAS_VERSION_2_0:
|
||||
case CAS_VERSION_3_0:
|
||||
if ( empty($err_code) ) {
|
||||
phpCAS::trace('Reason: no CAS error');
|
||||
} else {
|
||||
|
||||
@@ -25,35 +25,39 @@ function CAS_autoload($class)
|
||||
{
|
||||
// Static to hold the Include Path to CAS
|
||||
static $include_path;
|
||||
// Setup the include path if it's not already set from a previous call
|
||||
if (!$include_path) {
|
||||
$include_path = dirname(dirname(__FILE__));
|
||||
}
|
||||
// Check only for CAS classes
|
||||
if (substr($class, 0, 4) !== 'CAS_') {
|
||||
return false;
|
||||
}
|
||||
// Declare local variable to store the expected full path to the file
|
||||
$file_path = $include_path . '/' . str_replace('_', '/', $class) . '.php';
|
||||
// Setup the include path if it's not already set from a previous call
|
||||
if (empty($include_path)) {
|
||||
$include_path = array(dirname(dirname(__FILE__)), dirname(dirname(__FILE__)) . '/../test/' );
|
||||
}
|
||||
|
||||
$fp = @fopen($file_path, 'r', true);
|
||||
if ($fp) {
|
||||
fclose($fp);
|
||||
include $file_path;
|
||||
if (!class_exists($class, false) && !interface_exists($class, false)) {
|
||||
die(
|
||||
new Exception(
|
||||
'Class ' . $class . ' was not present in ' .
|
||||
$file_path .
|
||||
' [CAS_autoload]'
|
||||
)
|
||||
);
|
||||
// Declare local variable to store the expected full path to the file
|
||||
|
||||
foreach ($include_path as $path) {
|
||||
$file_path = $path . '/' . str_replace('_', '/', $class) . '.php';
|
||||
$fp = @fopen($file_path, 'r', true);
|
||||
if ($fp) {
|
||||
fclose($fp);
|
||||
include $file_path;
|
||||
if (!class_exists($class, false) && !interface_exists($class, false)) {
|
||||
die(
|
||||
new Exception(
|
||||
'Class ' . $class . ' was not present in ' .
|
||||
$file_path .
|
||||
' [CAS_autoload]'
|
||||
)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
$e = new Exception(
|
||||
'Class ' . $class . ' could not be loaded from ' .
|
||||
$file_path . ', file does not exist (Path="'
|
||||
. $include_path .'") [CAS_autoload]'
|
||||
. implode(':', $include_path) .'") [CAS_autoload]'
|
||||
);
|
||||
$trace = $e->getTrace();
|
||||
if (isset($trace[2]) && isset($trace[2]['function'])
|
||||
@@ -71,9 +75,13 @@ function CAS_autoload($class)
|
||||
|
||||
// set up __autoload
|
||||
if (function_exists('spl_autoload_register')) {
|
||||
if (!(spl_autoload_functions()) || !in_array('CAS_autoload', spl_autoload_functions())) {
|
||||
if (!(spl_autoload_functions())
|
||||
|| !in_array('CAS_autoload', spl_autoload_functions())
|
||||
) {
|
||||
spl_autoload_register('CAS_autoload');
|
||||
if (function_exists('__autoload') && !in_array('__autoload', spl_autoload_functions())) {
|
||||
if (function_exists('__autoload')
|
||||
&& !in_array('__autoload', spl_autoload_functions())
|
||||
) {
|
||||
// __autoload() was being used, but now would be ignored, add
|
||||
// it to the autoload stack
|
||||
spl_autoload_register('__autoload');
|
||||
|
||||
+571
-137
File diff suppressed because it is too large
Load Diff
@@ -161,7 +161,9 @@ class CAS_CookieJar
|
||||
protected function parseCookieHeader ($line, $defaultDomain)
|
||||
{
|
||||
if (!$defaultDomain) {
|
||||
throw new CAS_InvalidArgumentException('$defaultDomain was not provided.');
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'$defaultDomain was not provided.'
|
||||
);
|
||||
}
|
||||
|
||||
// Set our default values
|
||||
@@ -315,10 +317,14 @@ class CAS_CookieJar
|
||||
protected function cookieMatchesTarget ($cookie, $target)
|
||||
{
|
||||
if (!is_array($target)) {
|
||||
throw new CAS_InvalidArgumentException('$target must be an array of URL attributes as generated by parse_url().');
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'$target must be an array of URL attributes as generated by parse_url().'
|
||||
);
|
||||
}
|
||||
if (!isset($target['host'])) {
|
||||
throw new CAS_InvalidArgumentException('$target must be an array of URL attributes as generated by parse_url().');
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'$target must be an array of URL attributes as generated by parse_url().'
|
||||
);
|
||||
}
|
||||
|
||||
// Verify that the scheme matches
|
||||
@@ -352,15 +358,17 @@ class CAS_CookieJar
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the cookie host doesn't begin with '.', the host must case-insensitive
|
||||
// match exactly
|
||||
// If the cookie host doesn't begin with '.',
|
||||
// the host must case-insensitive match exactly
|
||||
if (strcasecmp($target['host'], $cookie['domain']) !== 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Verify that the port matches
|
||||
if (isset($cookie['ports']) && !in_array($target['port'], $cookie['ports'])) {
|
||||
if (isset($cookie['ports'])
|
||||
&& !in_array($target['port'], $cookie['ports'])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ class CAS_Languages_German implements CAS_Languages_LanguageInterface
|
||||
*/
|
||||
public function getYouWereNotAuthenticated()
|
||||
{
|
||||
return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontkatieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>';
|
||||
return '<p>Sie wurden nicht angemeldet.</p><p>Um es erneut zu versuchen klicken Sie <a href="%s">hier</a>.</p><p>Wenn das Problem bestehen bleibt, kontaktieren Sie den <a href="mailto:%s">Administrator</a> dieser Seite.</p>';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,4 +113,4 @@ class CAS_Languages_German implements CAS_Languages_LanguageInterface
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeAuthenticationCallException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines Exceptions that should be thrown when the sequence of
|
||||
* operations is invalid. In this case it should be thrown when an
|
||||
* authentication call has not yet happened.
|
||||
*
|
||||
* @class CAS_OutOfSequenceBeforeAuthenticationCallException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_OutOfSequenceBeforeAuthenticationCallException
|
||||
extends CAS_OutOfSequenceException
|
||||
implements CAS_Exception
|
||||
{
|
||||
/**
|
||||
* Return standard error meessage
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
parent::__construct('An authentication call hasn\'t happened yet.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeClientException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines Exceptions that should be thrown when the sequence of
|
||||
* operations is invalid. In this case it should be thrown when the client() or
|
||||
* proxy() call has not yet happened and no client or proxy object exists.
|
||||
*
|
||||
* @class CAS_OutOfSequenceBeforeClientException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_OutOfSequenceBeforeClientException
|
||||
extends CAS_OutOfSequenceException
|
||||
implements CAS_Exception
|
||||
{
|
||||
/**
|
||||
* Return standard error message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
parent::__construct(
|
||||
'this method cannot be called before phpCAS::client() or phpCAS::proxy()'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/OutOfSequenceBeforeProxyException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class defines Exceptions that should be thrown when the sequence of
|
||||
* operations is invalid. In this case it should be thrown when the proxy() call
|
||||
* has not yet happened and no proxy object exists.
|
||||
*
|
||||
* @class CAS_OutOfSequenceBeforeProxyException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Joachim Fritschi <jfritschi@freenet.de>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_OutOfSequenceBeforeProxyException
|
||||
extends CAS_OutOfSequenceException
|
||||
implements CAS_Exception
|
||||
{
|
||||
|
||||
/**
|
||||
* Return standard error message
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct ()
|
||||
{
|
||||
parent::__construct(
|
||||
'this method cannot be called before phpCAS::proxy()'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,9 @@ abstract class CAS_PGTStorage_AbstractStorage
|
||||
{
|
||||
phpCAS::traceBegin();
|
||||
if ( !$cas_parent->isProxy() ) {
|
||||
phpCAS::error('defining PGT storage makes no sense when not using a CAS proxy');
|
||||
phpCAS::error(
|
||||
'defining PGT storage makes no sense when not using a CAS proxy'
|
||||
);
|
||||
}
|
||||
phpCAS::traceEnd();
|
||||
}
|
||||
|
||||
@@ -135,8 +135,10 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
* @param string $driver_options any driver options to use when
|
||||
* connecting to the database
|
||||
*/
|
||||
public function __construct($cas_parent, $dsn_or_pdo, $username='', $password='', $table='', $driver_options=null)
|
||||
{
|
||||
public function __construct(
|
||||
$cas_parent, $dsn_or_pdo, $username='', $password='', $table='',
|
||||
$driver_options=null
|
||||
) {
|
||||
phpCAS::traceBegin();
|
||||
// call the ancestor's constructor
|
||||
parent::__construct($cas_parent);
|
||||
@@ -188,7 +190,10 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
// create the PDO object if it doesn't exist already
|
||||
if (!($this->_pdo instanceof PDO)) {
|
||||
try {
|
||||
$this->_pdo = new PDO($this->_dsn, $this->_username, $this->_password, $this->_driver_options);
|
||||
$this->_pdo = new PDO(
|
||||
$this->_dsn, $this->_username, $this->_password,
|
||||
$this->_driver_options
|
||||
);
|
||||
}
|
||||
catch(PDOException $e) {
|
||||
phpCAS::error('Database connection error: ' . $e->getMessage());
|
||||
@@ -247,23 +252,28 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
*/
|
||||
protected function createTableSql()
|
||||
{
|
||||
return 'CREATE TABLE ' . $this->_getTable() . ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';
|
||||
return 'CREATE TABLE ' . $this->_getTable()
|
||||
. ' (pgt_iou VARCHAR(255) NOT NULL PRIMARY KEY, pgt VARCHAR(255) NOT NULL)';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the query used to store a pgt
|
||||
*
|
||||
* @return the store PGT SQL, :pgt and :pgt_iou are the bind params contained in the query
|
||||
* @return the store PGT SQL, :pgt and :pgt_iou are the bind params contained
|
||||
* in the query
|
||||
*/
|
||||
protected function storePgtSql()
|
||||
{
|
||||
return 'INSERT INTO ' . $this->_getTable() . ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';
|
||||
return 'INSERT INTO ' . $this->_getTable()
|
||||
. ' (pgt_iou, pgt) VALUES (:pgt_iou, :pgt)';
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the query used to retrieve a pgt. the first column of the first row should contain the pgt
|
||||
* This method returns the query used to retrieve a pgt. the first column
|
||||
* of the first row should contain the pgt
|
||||
*
|
||||
* @return the retrieve PGT SQL, :pgt_iou is the only bind param contained in the query
|
||||
* @return the retrieve PGT SQL, :pgt_iou is the only bind param contained
|
||||
* in the query
|
||||
*/
|
||||
protected function retrievePgtSql()
|
||||
{
|
||||
@@ -273,7 +283,8 @@ class CAS_PGTStorage_Db extends CAS_PGTStorage_AbstractStorage
|
||||
/**
|
||||
* This method returns the query used to delete a pgt.
|
||||
*
|
||||
* @return the delete PGT SQL, :pgt_iou is the only bind param contained in the query
|
||||
* @return the delete PGT SQL, :pgt_iou is the only bind param contained in
|
||||
* the query
|
||||
*/
|
||||
protected function deletePgtSql()
|
||||
{
|
||||
|
||||
@@ -55,15 +55,20 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
*
|
||||
* @return void
|
||||
* @throws InvalidArgumentException If the $proxyTicket is invalid.
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has already been initialized/set.
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has
|
||||
* already been initialized/set.
|
||||
*/
|
||||
public function setProxyTicket ($proxyTicket)
|
||||
{
|
||||
if (empty($proxyTicket)) {
|
||||
throw new CAS_InvalidArgumentException("Trying to initialize with an empty proxy ticket.");
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'Trying to initialize with an empty proxy ticket.'
|
||||
);
|
||||
}
|
||||
if (!empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException('Already initialized, cannot change the proxy ticket.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Already initialized, cannot change the proxy ticket.'
|
||||
);
|
||||
}
|
||||
$this->_proxyTicket = $proxyTicket;
|
||||
}
|
||||
@@ -78,7 +83,9 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
protected function getProxyTicket ()
|
||||
{
|
||||
if (empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException('No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'No proxy ticket yet. Call $this->initializeProxyTicket() to aquire the proxy ticket.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_proxyTicket;
|
||||
@@ -105,7 +112,9 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
public function setCasClient (CAS_Client $casClient)
|
||||
{
|
||||
if (!empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException('Already initialized, cannot change the CAS_Client.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Already initialized, cannot change the CAS_Client.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->_casClient = $casClient;
|
||||
@@ -124,7 +133,9 @@ implements CAS_ProxiedService, CAS_ProxiedService_Testable
|
||||
protected function initializeProxyTicket()
|
||||
{
|
||||
if (!empty($this->_proxyTicket)) {
|
||||
throw new CAS_OutOfSequenceException('Already initialized, cannot initialize again.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Already initialized, cannot initialize again.'
|
||||
);
|
||||
}
|
||||
// Allow usage of a particular CAS_Client for unit testing.
|
||||
if (empty($this->_casClient)) {
|
||||
|
||||
@@ -38,9 +38,8 @@
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
abstract class CAS_ProxiedService_Http_Abstract
|
||||
extends CAS_ProxiedService_Abstract
|
||||
implements CAS_ProxiedService_Http
|
||||
abstract class CAS_ProxiedService_Http_Abstract extends
|
||||
CAS_ProxiedService_Abstract implements CAS_ProxiedService_Http
|
||||
{
|
||||
/**
|
||||
* The HTTP request mechanism talking to the target service.
|
||||
@@ -64,8 +63,9 @@ implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct (CAS_Request_RequestInterface $requestHandler, CAS_CookieJar $cookieJar)
|
||||
{
|
||||
public function __construct(CAS_Request_RequestInterface $requestHandler,
|
||||
CAS_CookieJar $cookieJar
|
||||
) {
|
||||
$this->requestHandler = $requestHandler;
|
||||
$this->_cookieJar = $cookieJar;
|
||||
}
|
||||
@@ -82,10 +82,12 @@ implements CAS_ProxiedService_Http
|
||||
* @return string
|
||||
* @throws Exception If no service url is available.
|
||||
*/
|
||||
public function getServiceUrl ()
|
||||
public function getServiceUrl()
|
||||
{
|
||||
if (empty($this->_url)) {
|
||||
throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->setUrl($url).');
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
'No URL set via ' . get_class($this) . '->setUrl($url).'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_url;
|
||||
@@ -93,7 +95,7 @@ implements CAS_ProxiedService_Http
|
||||
|
||||
/*********************************************************
|
||||
* Configure the Request
|
||||
*********************************************************/
|
||||
*********************************************************/
|
||||
|
||||
/**
|
||||
* Set the URL of the Request
|
||||
@@ -103,10 +105,12 @@ implements CAS_ProxiedService_Http
|
||||
* @return void
|
||||
* @throws CAS_OutOfSequenceException If called after the Request has been sent.
|
||||
*/
|
||||
public function setUrl ($url)
|
||||
public function setUrl($url)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot set the URL, request already sent.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the URL, request already sent.'
|
||||
);
|
||||
}
|
||||
if (!is_string($url)) {
|
||||
throw new CAS_InvalidArgumentException('$url must be a string.');
|
||||
@@ -117,7 +121,7 @@ implements CAS_ProxiedService_Http
|
||||
|
||||
/*********************************************************
|
||||
* 2. Send the Request
|
||||
*********************************************************/
|
||||
*********************************************************/
|
||||
|
||||
/**
|
||||
* Perform the request.
|
||||
@@ -132,10 +136,12 @@ implements CAS_ProxiedService_Http
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the
|
||||
* request to the target service.
|
||||
*/
|
||||
public function send ()
|
||||
public function send()
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot send, request already sent.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot send, request already sent.'
|
||||
);
|
||||
}
|
||||
|
||||
phpCAS::traceBegin();
|
||||
@@ -144,9 +150,9 @@ implements CAS_ProxiedService_Http
|
||||
$this->initializeProxyTicket();
|
||||
$url = $this->getServiceUrl();
|
||||
if (strstr($url, '?') === false) {
|
||||
$url = $url.'?ticket='.$this->getProxyTicket();
|
||||
$url = $url . '?ticket=' . $this->getProxyTicket();
|
||||
} else {
|
||||
$url = $url.'&ticket='.$this->getProxyTicket();
|
||||
$url = $url . '&ticket=' . $this->getProxyTicket();
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -199,7 +205,7 @@ implements CAS_ProxiedService_Http
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the
|
||||
* request to the target service.
|
||||
*/
|
||||
protected function makeRequest ($url)
|
||||
protected function makeRequest($url)
|
||||
{
|
||||
// Verify that we are not in a redirect loop
|
||||
$this->_numRequests++;
|
||||
@@ -220,9 +226,10 @@ implements CAS_ProxiedService_Http
|
||||
$this->populateRequest($request);
|
||||
|
||||
// Perform the request.
|
||||
phpCAS::trace('Performing proxied service request to \''.$url.'\'');
|
||||
phpCAS::trace('Performing proxied service request to \'' . $url . '\'');
|
||||
if (!$request->send()) {
|
||||
$message = 'Could not perform proxied service request to URL`'.$url.'\'. '.$request->getErrorMessage();
|
||||
$message = 'Could not perform proxied service request to URL`'
|
||||
. $url . '\'. ' . $request->getErrorMessage();
|
||||
phpCAS::trace($message);
|
||||
throw new CAS_ProxiedService_Exception($message);
|
||||
}
|
||||
@@ -231,8 +238,9 @@ implements CAS_ProxiedService_Http
|
||||
$this->_cookieJar->storeCookies($url, $request->getResponseHeaders());
|
||||
|
||||
// Follow any redirects
|
||||
if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())) {
|
||||
phpCAS :: trace('Found redirect:'.$redirectUrl);
|
||||
if ($redirectUrl = $this->getRedirectUrl($request->getResponseHeaders())
|
||||
) {
|
||||
phpCAS::trace('Found redirect:' . $redirectUrl);
|
||||
$this->makeRequest($redirectUrl);
|
||||
} else {
|
||||
|
||||
@@ -249,7 +257,9 @@ implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract protected function populateRequest (CAS_Request_RequestInterface $request);
|
||||
abstract protected function populateRequest(
|
||||
CAS_Request_RequestInterface $request
|
||||
);
|
||||
|
||||
/**
|
||||
* Answer a redirect URL if a redirect header is found, otherwise null.
|
||||
@@ -258,11 +268,12 @@ implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return string or null
|
||||
*/
|
||||
protected function getRedirectUrl (array $responseHeaders)
|
||||
protected function getRedirectUrl(array $responseHeaders)
|
||||
{
|
||||
// Check for the redirect after authentication
|
||||
foreach ($responseHeaders as $header) {
|
||||
if (preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)) {
|
||||
if ( preg_match('/^(Location:|URI:)\s*([^\s]+.*)$/', $header, $matches)
|
||||
) {
|
||||
return trim(array_pop($matches));
|
||||
}
|
||||
}
|
||||
@@ -271,14 +282,14 @@ implements CAS_ProxiedService_Http
|
||||
|
||||
/*********************************************************
|
||||
* 3. Access the response
|
||||
*********************************************************/
|
||||
*********************************************************/
|
||||
|
||||
/**
|
||||
* Answer true if our request has been sent yet.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasBeenSent ()
|
||||
protected function hasBeenSent()
|
||||
{
|
||||
return ($this->_numRequests > 0);
|
||||
}
|
||||
@@ -289,10 +300,12 @@ implements CAS_ProxiedService_Http
|
||||
* @return array An array of header strings.
|
||||
* @throws CAS_OutOfSequenceException If called before the Request has been sent.
|
||||
*/
|
||||
public function getResponseHeaders ()
|
||||
public function getResponseHeaders()
|
||||
{
|
||||
if (!$this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access response, request not sent yet.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_responseHeaders;
|
||||
@@ -304,10 +317,12 @@ implements CAS_ProxiedService_Http
|
||||
* @return int
|
||||
* @throws CAS_OutOfSequenceException If called before the Request has been sent.
|
||||
*/
|
||||
public function getResponseStatusCode ()
|
||||
public function getResponseStatusCode()
|
||||
{
|
||||
if (!$this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access response, request not sent yet.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_responseStatusCode;
|
||||
@@ -319,10 +334,12 @@ implements CAS_ProxiedService_Http
|
||||
* @return string
|
||||
* @throws CAS_OutOfSequenceException If called before the Request has been sent.
|
||||
*/
|
||||
public function getResponseBody ()
|
||||
public function getResponseBody()
|
||||
{
|
||||
if (!$this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot access response, request not sent yet.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access response, request not sent yet.'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_responseBody;
|
||||
@@ -334,7 +351,7 @@ implements CAS_ProxiedService_Http
|
||||
*
|
||||
* @return array An array containing cookies. E.g. array('name' => 'val');
|
||||
*/
|
||||
public function getCookies ()
|
||||
public function getCookies()
|
||||
{
|
||||
return $this->_cookieJar->getCookies($this->getServiceUrl());
|
||||
}
|
||||
|
||||
@@ -32,30 +32,31 @@
|
||||
*
|
||||
* Usage Example:
|
||||
*
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_GET);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
*
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format (shouldn't happen)
|
||||
* // or CAS server failure (unlikely) so lets just stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format
|
||||
* // (shouldn't happen) or CAS server failure (unlikely)
|
||||
* // so lets just stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
*
|
||||
* @class CAS_ProxiedService_Http_Get
|
||||
* @category Authentication
|
||||
|
||||
@@ -32,32 +32,33 @@
|
||||
*
|
||||
* Usage Example:
|
||||
*
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->setContentType('text/xml');
|
||||
* $service->setBody(''<?xml version="1.0"?'.'><methodCall><methodName>example.search</methodName></methodCall>');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
* try {
|
||||
* $service = phpCAS::getProxiedService(PHPCAS_PROXIED_SERVICE_HTTP_POST);
|
||||
* $service->setUrl('http://www.example.com/path/');
|
||||
* $service->setContentType('text/xml');
|
||||
* $service->setBody('<?xml version="1.0"?'.'><methodCall><methodName>example.search</methodName></methodCall>');
|
||||
* $service->send();
|
||||
* if ($service->getResponseStatusCode() == 200)
|
||||
* return $service->getResponseBody();
|
||||
* else
|
||||
* // The service responded with an error code 404, 500, etc.
|
||||
* throw new Exception('The service responded with an error.');
|
||||
*
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format (shouldn't happen)
|
||||
* // or CAS server failure (unlikely) so lets just stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
* } catch (CAS_ProxyTicketException $e) {
|
||||
* if ($e->getCode() == PHPCAS_SERVICE_PT_FAILURE)
|
||||
* return "Your login has timed out. You need to log in again.";
|
||||
* else
|
||||
* // Other proxy ticket errors are from bad request format
|
||||
* // (shouldn't happen) or CAS server failure (unlikely) so lets just
|
||||
* // stop if we hit those.
|
||||
* throw $e;
|
||||
* } catch (CAS_ProxiedService_Exception $e) {
|
||||
* // Something prevented the service request from being sent or received.
|
||||
* // We didn't even get a valid error response (404, 500, etc), so this
|
||||
* // might be caused by a network error or a DNS resolution failure.
|
||||
* // We could handle it in some way, but for now we will just stop.
|
||||
* throw $e;
|
||||
* }
|
||||
*
|
||||
* @class CAS_ProxiedService_Http_Post
|
||||
* @category Authentication
|
||||
@@ -95,7 +96,9 @@ extends CAS_ProxiedService_Http_Abstract
|
||||
public function setContentType ($contentType)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot set the content type, request already sent.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the content type, request already sent.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->_contentType = $contentType;
|
||||
@@ -112,7 +115,9 @@ extends CAS_ProxiedService_Http_Abstract
|
||||
public function setBody ($body)
|
||||
{
|
||||
if ($this->hasBeenSent()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot set the body, request already sent.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the body, request already sent.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->_body = $body;
|
||||
@@ -128,7 +133,10 @@ extends CAS_ProxiedService_Http_Abstract
|
||||
protected function populateRequest (CAS_Request_RequestInterface $request)
|
||||
{
|
||||
if (empty($this->_contentType) && !empty($this->_body)) {
|
||||
throw new CAS_ProxiedService_Exception("If you pass a POST body, you must specify a content type via ".get_class($this).'->setContentType($contentType).');
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
"If you pass a POST body, you must specify a content type via "
|
||||
.get_class($this).'->setContentType($contentType).'
|
||||
);
|
||||
}
|
||||
|
||||
$request->makePost();
|
||||
|
||||
@@ -79,7 +79,9 @@ extends CAS_ProxiedService_Abstract
|
||||
public function getServiceUrl ()
|
||||
{
|
||||
if (empty($this->_url)) {
|
||||
throw new CAS_ProxiedService_Exception('No URL set via '.get_class($this).'->getServiceUrl($url).');
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
'No URL set via '.get_class($this).'->getServiceUrl($url).'
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_url;
|
||||
@@ -100,7 +102,9 @@ extends CAS_ProxiedService_Abstract
|
||||
public function setServiceUrl ($url)
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot set the URL, stream already opened.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the URL, stream already opened.'
|
||||
);
|
||||
}
|
||||
if (!is_string($url) || !strlen($url)) {
|
||||
throw new CAS_InvalidArgumentException('Invalid url.');
|
||||
@@ -127,7 +131,9 @@ extends CAS_ProxiedService_Abstract
|
||||
public function setMailbox ($mailbox)
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot set the mailbox, stream already opened.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set the mailbox, stream already opened.'
|
||||
);
|
||||
}
|
||||
if (!is_string($mailbox) || !strlen($mailbox)) {
|
||||
throw new CAS_InvalidArgumentException('Invalid mailbox.');
|
||||
@@ -155,7 +161,9 @@ extends CAS_ProxiedService_Abstract
|
||||
public function setOptions ($options)
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot set options, stream already opened.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot set options, stream already opened.'
|
||||
);
|
||||
}
|
||||
if (!is_int($options)) {
|
||||
throw new CAS_InvalidArgumentException('Invalid options.');
|
||||
@@ -178,14 +186,19 @@ extends CAS_ProxiedService_Abstract
|
||||
* PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE
|
||||
* PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE
|
||||
* PHPCAS_SERVICE_PT_FAILURE
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the request to the target service. */
|
||||
* @throws CAS_ProxiedService_Exception If there is a failure sending the
|
||||
* request to the target service.
|
||||
*/
|
||||
public function open ()
|
||||
{
|
||||
if ($this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Stream already opened.');
|
||||
}
|
||||
if (empty($this->_mailbox)) {
|
||||
throw new CAS_ProxiedService_Exception('You must specify a mailbox via '.get_class($this).'->setMailbox($mailbox)');
|
||||
throw new CAS_ProxiedService_Exception(
|
||||
'You must specify a mailbox via '.get_class($this)
|
||||
.'->setMailbox($mailbox)'
|
||||
);
|
||||
}
|
||||
|
||||
phpCAS::traceBegin();
|
||||
@@ -193,13 +206,16 @@ extends CAS_ProxiedService_Abstract
|
||||
// Get our proxy ticket and append it to our URL.
|
||||
$this->initializeProxyTicket();
|
||||
phpCAS::trace('opening IMAP mailbox `'.$this->_mailbox.'\'...');
|
||||
$this->_stream = @imap_open($this->_mailbox, $this->_username, $this->getProxyTicket(), $this->_options);
|
||||
$this->_stream = @imap_open(
|
||||
$this->_mailbox, $this->_username, $this->getProxyTicket(),
|
||||
$this->_options
|
||||
);
|
||||
if ($this->_stream) {
|
||||
phpCAS::trace('ok');
|
||||
} else {
|
||||
phpCAS::trace('could not open mailbox');
|
||||
// @todo add localization integration.
|
||||
$message = 'IMAP Error: '.$url.' '. var_export(imap_errors(), true);
|
||||
$message = 'IMAP Error: '.$this->_url.' '. var_export(imap_errors(), true);
|
||||
phpCAS::trace($message);
|
||||
throw new CAS_ProxiedService_Exception($message);
|
||||
}
|
||||
@@ -236,7 +252,9 @@ extends CAS_ProxiedService_Abstract
|
||||
public function getStream ()
|
||||
{
|
||||
if (!$this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot access stream, not opened yet.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access stream, not opened yet.'
|
||||
);
|
||||
}
|
||||
return $this->_stream;
|
||||
}
|
||||
@@ -252,7 +270,9 @@ extends CAS_ProxiedService_Abstract
|
||||
public function getImapProxyTicket ()
|
||||
{
|
||||
if (!$this->hasBeenOpened()) {
|
||||
throw new CAS_OutOfSequenceException('Cannot access errors, stream not opened yet.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot access errors, stream not opened yet.'
|
||||
);
|
||||
}
|
||||
return $this->getProxyTicket();
|
||||
}
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
* This interface defines methods that allow proxy-authenticated service handlers
|
||||
* to be tested in unit tests.
|
||||
*
|
||||
* Classes implementing this interface SHOULD store the CAS_Client passed and initialize
|
||||
* themselves with that client rather than via the static phpCAS method. For example:
|
||||
* Classes implementing this interface SHOULD store the CAS_Client passed and
|
||||
* initialize themselves with that client rather than via the static phpCAS
|
||||
* method. For example:
|
||||
*
|
||||
* / **
|
||||
* * Fetch our proxy ticket.
|
||||
@@ -65,7 +66,8 @@ interface CAS_ProxiedService_Testable
|
||||
* @param CAS_Client $casClient Cas client object
|
||||
*
|
||||
* @return void
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has already been initialized/set.
|
||||
* @throws CAS_OutOfSequenceException If called after a proxy ticket has
|
||||
* already been initialized/set.
|
||||
*/
|
||||
public function setCasClient (CAS_Client $casClient);
|
||||
|
||||
|
||||
@@ -59,7 +59,8 @@ implements CAS_ProxyChain_Interface
|
||||
*/
|
||||
public function __construct(array $chain)
|
||||
{
|
||||
$this->chain = array_values($chain); // Ensure that we have an indexed array
|
||||
// Ensure that we have an indexed array
|
||||
$this->chain = array_values($chain);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,17 +79,25 @@ implements CAS_ProxyChain_Interface
|
||||
$proxy_url = $list[$i];
|
||||
if (preg_match('/^\/.*\/[ixASUXu]*$/s', $search)) {
|
||||
if (preg_match($search, $proxy_url)) {
|
||||
phpCAS::trace("Found regexp " . $search . " matching " . $proxy_url);
|
||||
phpCAS::trace(
|
||||
"Found regexp " . $search . " matching " . $proxy_url
|
||||
);
|
||||
} else {
|
||||
phpCAS::trace("No regexp match " . $search . " != " . $proxy_url);
|
||||
phpCAS::trace(
|
||||
"No regexp match " . $search . " != " . $proxy_url
|
||||
);
|
||||
$mismatch = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (strncasecmp($search, $proxy_url, strlen($search)) == 0) {
|
||||
phpCAS::trace("Found string " . $search . " matching " . $proxy_url);
|
||||
phpCAS::trace(
|
||||
"Found string " . $search . " matching " . $proxy_url
|
||||
);
|
||||
} else {
|
||||
phpCAS::trace("No match " . $search . " != " . $proxy_url);
|
||||
phpCAS::trace(
|
||||
"No match " . $search . " != " . $proxy_url
|
||||
);
|
||||
$mismatch = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,10 @@ implements CAS_Exception
|
||||
PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE,
|
||||
);
|
||||
if (!in_array($code, $ptCodes)) {
|
||||
trigger_error('Invalid code '.$code.' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.');
|
||||
trigger_error(
|
||||
'Invalid code '.$code
|
||||
.' passed. Must be one of PHPCAS_SERVICE_PT_FAILURE, PHPCAS_SERVICE_PT_NO_SERVER_RESPONSE, or PHPCAS_SERVICE_PT_BAD_SERVER_RESPONSE.'
|
||||
);
|
||||
}
|
||||
|
||||
parent::__construct($message, $code);
|
||||
|
||||
@@ -68,7 +68,9 @@ implements CAS_Request_RequestInterface
|
||||
public function setUrl ($url)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->url = $url;
|
||||
@@ -86,7 +88,9 @@ implements CAS_Request_RequestInterface
|
||||
public function addCookie ($name, $value)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->cookies[$name] = $value;
|
||||
@@ -105,7 +109,9 @@ implements CAS_Request_RequestInterface
|
||||
public function addCookies (array $cookies)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->cookies = array_merge($this->cookies, $cookies);
|
||||
@@ -122,7 +128,9 @@ implements CAS_Request_RequestInterface
|
||||
public function addHeader ($header)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->headers[] = $header;
|
||||
@@ -139,7 +147,9 @@ implements CAS_Request_RequestInterface
|
||||
public function addHeaders (array $headers)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->headers = array_merge($this->headers, $headers);
|
||||
@@ -154,7 +164,9 @@ implements CAS_Request_RequestInterface
|
||||
public function makePost ()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
$this->isPost = true;
|
||||
@@ -171,10 +183,14 @@ implements CAS_Request_RequestInterface
|
||||
public function setPostBody ($body)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
if (!$this->isPost) {
|
||||
throw new CAS_OutOfSequenceException('Cannot add a POST body to a GET request, use makePost() first.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Cannot add a POST body to a GET request, use makePost() first.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->postBody = $body;
|
||||
@@ -192,7 +208,9 @@ implements CAS_Request_RequestInterface
|
||||
public function setSslCaCert ($caCertPath,$validate_cn=true)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
$this->caCertPath = $caCertPath;
|
||||
$this->validateCN = $validate_cn;
|
||||
@@ -211,10 +229,14 @@ implements CAS_Request_RequestInterface
|
||||
public function send ()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot send again.'
|
||||
);
|
||||
}
|
||||
if (is_null($this->url) || !$this->url) {
|
||||
throw new CAS_OutOfSequenceException('A url must be specified via setUrl() before the request can be sent.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'A url must be specified via setUrl() before the request can be sent.'
|
||||
);
|
||||
}
|
||||
$this->_sent = true;
|
||||
return $this->sendRequest();
|
||||
@@ -288,7 +310,9 @@ implements CAS_Request_RequestInterface
|
||||
public function getResponseHeaders ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
return $this->_responseHeaders;
|
||||
}
|
||||
@@ -302,11 +326,19 @@ implements CAS_Request_RequestInterface
|
||||
public function getResponseStatusCode ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
if (!preg_match('/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/', $this->_responseHeaders[0], $matches)) {
|
||||
throw new CAS_Request_Exception("Bad response, no status code was found in the first line.");
|
||||
if (!preg_match(
|
||||
'/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/',
|
||||
$this->_responseHeaders[0], $matches
|
||||
)
|
||||
) {
|
||||
throw new CAS_Request_Exception(
|
||||
'Bad response, no status code was found in the first line.'
|
||||
);
|
||||
}
|
||||
|
||||
return intval($matches[1]);
|
||||
@@ -321,7 +353,9 @@ implements CAS_Request_RequestInterface
|
||||
public function getResponseBody ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
return $this->_responseBody;
|
||||
@@ -336,7 +370,9 @@ implements CAS_Request_RequestInterface
|
||||
public function getErrorMessage ()
|
||||
{
|
||||
if (!$this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has not been sent yet. Cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has not been sent yet. Cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
return $this->_errorMessage;
|
||||
}
|
||||
|
||||
@@ -64,10 +64,14 @@ implements CAS_Request_MultiRequestInterface
|
||||
public function addRequest (CAS_Request_RequestInterface $request)
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
if (!$request instanceof CAS_Request_CurlRequest) {
|
||||
throw new CAS_InvalidArgumentException('As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.');
|
||||
throw new CAS_InvalidArgumentException(
|
||||
'As a CAS_Request_CurlMultiRequest, I can only work with CAS_Request_CurlRequest objects.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->_requests[] = $request;
|
||||
@@ -81,7 +85,9 @@ implements CAS_Request_MultiRequestInterface
|
||||
public function getNumRequests()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot '.__METHOD__);
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot '.__METHOD__
|
||||
);
|
||||
}
|
||||
return count($this->_requests);
|
||||
}
|
||||
@@ -100,10 +106,14 @@ implements CAS_Request_MultiRequestInterface
|
||||
public function send ()
|
||||
{
|
||||
if ($this->_sent) {
|
||||
throw new CAS_OutOfSequenceException('Request has already been sent cannot send again.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'Request has already been sent cannot send again.'
|
||||
);
|
||||
}
|
||||
if (!count($this->_requests)) {
|
||||
throw new CAS_OutOfSequenceException('At least one request must be added via addRequest() before the multi-request can be sent.');
|
||||
throw new CAS_OutOfSequenceException(
|
||||
'At least one request must be added via addRequest() before the multi-request can be sent.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->_sent = true;
|
||||
|
||||
@@ -75,7 +75,9 @@ implements CAS_Request_RequestInterface
|
||||
$buf = curl_exec($ch);
|
||||
if ( $buf === false ) {
|
||||
phpCAS::trace('curl_exec() failed');
|
||||
$this->storeErrorMessage('CURL error #'.curl_errno($ch).': '.curl_error($ch));
|
||||
$this->storeErrorMessage(
|
||||
'CURL error #'.curl_errno($ch).': '.curl_error($ch)
|
||||
);
|
||||
$res = false;
|
||||
} else {
|
||||
$this->storeResponseBody($buf);
|
||||
@@ -120,7 +122,7 @@ implements CAS_Request_RequestInterface
|
||||
if ($this->validateCN) {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
|
||||
} else {
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
}
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
|
||||
curl_setopt($ch, CURLOPT_CAINFO, $this->caCertPath);
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Licensed to Jasig under one or more contributor license
|
||||
* agreements. See the NOTICE file distributed with this work for
|
||||
* additional information regarding copyright ownership.
|
||||
*
|
||||
* Jasig licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* PHP Version 5
|
||||
*
|
||||
* @file CAS/InvalidArgumentException.php
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Adam Franco <afranco@middlebury.edu>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
|
||||
/**
|
||||
* Exception that denotes invalid arguments were passed.
|
||||
*
|
||||
* @class CAS_InvalidArgumentException
|
||||
* @category Authentication
|
||||
* @package PhpCAS
|
||||
* @author Adam Franco <afranco@middlebury.edu>
|
||||
* @license http://www.apache.org/licenses/LICENSE-2.0 Apache License 2.0
|
||||
* @link https://wiki.jasig.org/display/CASC/phpCAS
|
||||
*/
|
||||
class CAS_TypeMismatchException
|
||||
extends CAS_InvalidArgumentException
|
||||
{
|
||||
/**
|
||||
* Constructor, provides a nice message.
|
||||
*
|
||||
* @param mixed $argument Argument
|
||||
* @param string $argumentName Argument Name
|
||||
* @param string $type Type
|
||||
* @param string $message Error Message
|
||||
* @param integer $code Code
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct (
|
||||
$argument, $argumentName, $type, $message = '', $code = 0
|
||||
) {
|
||||
if (is_object($argument)) {
|
||||
$foundType = get_class($argument).' object';
|
||||
} else {
|
||||
$foundType = gettype($argument);
|
||||
}
|
||||
|
||||
parent::__construct(
|
||||
'type mismatched for parameter '
|
||||
. $argumentName . ' (should be \'' . $type .' \'), '
|
||||
. $foundType . ' given. ' . $message, $code
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,5 +1,5 @@
|
||||
Description of phpCAS 1.3.2 library import
|
||||
Description of phpCAS 1.3.3 library import
|
||||
|
||||
* downloaded from http://downloads.jasig.org/cas-clients/php/current/
|
||||
|
||||
iarenaza
|
||||
merrill
|
||||
|
||||
+39
-25
@@ -111,6 +111,26 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the multi-authentication setting is used, check for the param before connecting to CAS.
|
||||
if ($this->config->multiauth) {
|
||||
$authCAS = optional_param('authCAS', '', PARAM_RAW);
|
||||
if ($authCAS == 'NOCAS') {
|
||||
return;
|
||||
}
|
||||
// Show authentication form for multi-authentication.
|
||||
// Test pgtIou parameter for proxy mode (https connection in background from CAS server to the php server).
|
||||
if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
|
||||
$PAGE->set_url('/login/index.php');
|
||||
$PAGE->navbar->add($CASform);
|
||||
$PAGE->set_title("$site->fullname: $CASform");
|
||||
$PAGE->set_heading($site->fullname);
|
||||
echo $OUTPUT->header();
|
||||
include($CFG->dirroot.'/auth/cas/cas_form.html');
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Connection to CAS server
|
||||
$this->connectCAS();
|
||||
|
||||
@@ -134,27 +154,6 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->config->multiauth) {
|
||||
$authCAS = optional_param('authCAS', '', PARAM_RAW);
|
||||
if ($authCAS == 'NOCAS') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Show authentication form for multi-authentication
|
||||
// test pgtIou parameter for proxy mode (https connection
|
||||
// in background from CAS server to the php server)
|
||||
if ($authCAS != 'CAS' && !isset($_GET['pgtIou'])) {
|
||||
$PAGE->set_url('/login/index.php');
|
||||
$PAGE->navbar->add($CASform);
|
||||
$PAGE->set_title("$site->fullname: $CASform");
|
||||
$PAGE->set_heading($site->fullname);
|
||||
echo $OUTPUT->header();
|
||||
include($CFG->dirroot.'/auth/cas/cas_form.html');
|
||||
echo $OUTPUT->footer();
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
// Force CAS authentication (if needed).
|
||||
if (!phpCAS::isAuthenticated()) {
|
||||
phpCAS::setLang($this->config->language);
|
||||
@@ -167,12 +166,27 @@ class auth_plugin_cas extends auth_plugin_ldap {
|
||||
*
|
||||
*/
|
||||
function prelogout_hook() {
|
||||
global $CFG;
|
||||
global $CFG, $USER, $DB;
|
||||
|
||||
if (!empty($this->config->logoutcas)) {
|
||||
$backurl = $CFG->wwwroot;
|
||||
if (!empty($this->config->logoutcas) && $USER->auth == $this->authtype) {
|
||||
$backurl = !empty($this->config->logout_return_url) ? $this->config->logout_return_url : $CFG->wwwroot;
|
||||
$this->connectCAS();
|
||||
phpCAS::logoutWithURL($backurl);
|
||||
// Note: Hack to stable versions to trigger the event before it redirect to CAS logout.
|
||||
$sid = session_id();
|
||||
$event = \core\event\user_loggedout::create(
|
||||
array(
|
||||
'userid' => $USER->id,
|
||||
'objectid' => $USER->id,
|
||||
'other' => array('sessionid' => $sid),
|
||||
)
|
||||
);
|
||||
if ($session = $DB->get_record('sessions', array('sid' => $sid))) {
|
||||
$event->add_record_snapshot('sessions', $session);
|
||||
}
|
||||
\core\session\manager::terminate_current();
|
||||
$event->trigger();
|
||||
|
||||
phpCAS::logoutWithRedirectService($backurl);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<location>CAS</location>
|
||||
<name>CAS</name>
|
||||
<license>BSD</license>
|
||||
<version>1.3.2</version>
|
||||
<version>1.3.3</version>
|
||||
<licenseversion></licenseversion>
|
||||
</library>
|
||||
</libraries>
|
||||
|
||||
@@ -384,6 +384,10 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
if ($old_user = $DB->get_record('user', array('username'=>$username, 'deleted'=>0, 'suspended'=>1, 'mnethostid'=>$CFG->mnet_localhost_id, 'auth'=>$this->authtype))) {
|
||||
$DB->set_field('user', 'suspended', 0, array('id'=>$old_user->id));
|
||||
$trace->output(get_string('auth_dbreviveduser', 'auth_db', array('name'=>$username, 'id'=>$old_user->id)), 1);
|
||||
|
||||
// Trigger user_updated event.
|
||||
\core\event\user_updated::create_from_userid($old_user->id)->trigger();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -410,6 +414,10 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
}
|
||||
try {
|
||||
$id = $DB->insert_record ('user', $user); // it is truly a new user
|
||||
|
||||
// Trigger user_created event.
|
||||
\core\event\user_created::create_from_userid($id)->trigger();
|
||||
|
||||
$trace->output(get_string('auth_dbinsertuser', 'auth_db', array('name'=>$user->username, 'id'=>$id)), 1);
|
||||
} catch (moodle_exception $e) {
|
||||
$trace->output(get_string('auth_dbinsertusererror', 'auth_db', $user->username), 1);
|
||||
@@ -547,6 +555,9 @@ class auth_plugin_db extends auth_plugin_base {
|
||||
}
|
||||
if ($updated) {
|
||||
$DB->set_field('user', 'timemodified', time(), array('id'=>$userid));
|
||||
|
||||
// Trigger user_updated event.
|
||||
\core\event\user_updated::create_from_userid($userid)->trigger();
|
||||
}
|
||||
return $DB->get_record('user', array('id'=>$userid, 'deleted'=>0));
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
class auth_db_testcase extends advanced_testcase {
|
||||
|
||||
protected function init_auth_database() {
|
||||
public function init_auth_database() {
|
||||
global $DB, $CFG;
|
||||
require_once("$CFG->dirroot/auth/db/auth.php");
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
<?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/>.
|
||||
|
||||
/**
|
||||
* Events tests.
|
||||
*
|
||||
* @package auth_db
|
||||
* @category test
|
||||
* @copyright 2014 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->dirroot . '/auth/db/tests/db_test.php');
|
||||
|
||||
class auth_db_events_testcase extends advanced_testcase {
|
||||
|
||||
/**
|
||||
* Test set up.
|
||||
*/
|
||||
public function setUp() {
|
||||
$this->resetAfterTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the locations in the auth_db API that create a user trigger the user_created event.
|
||||
*/
|
||||
public function test_user_created() {
|
||||
global $DB;
|
||||
|
||||
$this->preventResetByRollback();
|
||||
|
||||
// Initialise the database.
|
||||
$authdbtestcase = new auth_db_testcase();
|
||||
$authdbtestcase->init_auth_database();
|
||||
|
||||
$auth = get_auth_plugin('db');
|
||||
$auth->db_init();
|
||||
|
||||
// Add a user to the auth_db_users table - we will then call sync_users to
|
||||
// deal with the record here. In this case it will create the user.
|
||||
$user = new stdClass();
|
||||
$user->name = 'mark';
|
||||
$user->pass = 'password123';
|
||||
$user->email = 'what@legend.com';
|
||||
$user->id = $DB->insert_record('auth_db_users', $user);
|
||||
|
||||
// Run sync_users and capture the user_created event.
|
||||
$sink = $this->redirectEvents();
|
||||
$trace = new null_progress_trace();
|
||||
$auth->sync_users($trace, false);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Check that there is only one event.
|
||||
$this->assertEquals(1, count($events));
|
||||
|
||||
// Get the event.
|
||||
$event = array_pop($events);
|
||||
|
||||
// Test that the user created event was triggered - no need to test the other
|
||||
// details of the event as that is done extensively in other unit tests.
|
||||
$this->assertInstanceOf('\core\event\user_created', $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that the locations in the auth_db API that update a user trigger the user_updated event.
|
||||
*/
|
||||
public function test_user_updated() {
|
||||
global $CFG, $DB;
|
||||
|
||||
$this->preventResetByRollback();
|
||||
|
||||
// Initialise the database.
|
||||
$authdbtestcase = new auth_db_testcase();
|
||||
$authdbtestcase->init_auth_database();
|
||||
|
||||
$auth = get_auth_plugin('db');
|
||||
$auth->db_init();
|
||||
|
||||
// Add a suspended user.
|
||||
$user = array();
|
||||
$user['username'] = 'mark';
|
||||
$user['suspended'] = '1';
|
||||
$user['mnethostid'] = $CFG->mnet_localhost_id;
|
||||
$user['auth'] = 'db';
|
||||
$this->getDataGenerator()->create_user($user);
|
||||
|
||||
// Add a user to the auth_db_users table - we will then call sync_users to
|
||||
// deal with the record here. In this case it will un-suspend the user.
|
||||
$user = new stdClass();
|
||||
$user->name = 'mark';
|
||||
$user->pass = 'password123';
|
||||
$user->email = 'what@legend.com';
|
||||
$user->id = $DB->insert_record('auth_db_users', $user);
|
||||
|
||||
// Set the config to remove the suspension on the user.
|
||||
set_config('removeuser', AUTH_REMOVEUSER_SUSPEND, 'auth/db');
|
||||
$auth->config->removeuser = AUTH_REMOVEUSER_SUSPEND;
|
||||
|
||||
// Run sync_users and capture the user_updated event.
|
||||
$sink = $this->redirectEvents();
|
||||
$trace = new null_progress_trace();
|
||||
$auth->sync_users($trace, false);
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Check that there is only one event.
|
||||
$this->assertEquals(1, count($events));
|
||||
|
||||
// Get the event.
|
||||
$event = array_pop($events);
|
||||
|
||||
// Test that the user updated event was triggered - no need to test the other
|
||||
// details of the event as that is done extensively in other unit tests.
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
|
||||
// Run sync_users and capture the user_updated event.
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->update_user_record('mark');
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Check that there is only one event.
|
||||
$this->assertEquals(1, count($events));
|
||||
|
||||
// Get the event.
|
||||
$event = array_pop($events);
|
||||
|
||||
// Test that the user updated event was triggered - no need to test the other
|
||||
// details of the event as that is done extensively in other unit tests.
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -94,11 +94,14 @@ class auth_plugin_email extends auth_plugin_base {
|
||||
$user->calendartype = $CFG->calendartype;
|
||||
}
|
||||
|
||||
$user->id = user_create_user($user, false);
|
||||
$user->id = user_create_user($user, false, false);
|
||||
|
||||
// Save any custom profile field information.
|
||||
profile_save_data($user);
|
||||
|
||||
// Trigger event.
|
||||
\core\event\user_created::create_from_userid($user->id)->trigger();
|
||||
|
||||
if (! send_confirmation_email($user)) {
|
||||
print_error('auth_emailnoemail','auth_email');
|
||||
}
|
||||
|
||||
+4
-2
@@ -551,7 +551,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
print_error('auth_ldap_create_error', 'auth_ldap');
|
||||
}
|
||||
|
||||
$user->id = user_create_user($user, false);
|
||||
$user->id = user_create_user($user, false, false);
|
||||
|
||||
// Save any custom profile field information
|
||||
profile_save_data($user);
|
||||
@@ -564,6 +564,8 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
|
||||
$user = $DB->get_record('user', array('id'=>$user->id));
|
||||
|
||||
\core\event\user_created::create_from_userid($user->id)->trigger();
|
||||
|
||||
if (! send_confirmation_email($user)) {
|
||||
print_error('noemail', 'auth_ldap');
|
||||
}
|
||||
@@ -1027,7 +1029,7 @@ class auth_plugin_ldap extends auth_plugin_base {
|
||||
}
|
||||
}
|
||||
}
|
||||
user_update_user($newuser, false);
|
||||
user_update_user($newuser, false, false);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -125,7 +125,7 @@ $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";
|
||||
$string['nouserentriestorevive'] = "No user entries to be revived\n";
|
||||
$string['nouserstobeadded'] = "No users to be added\n";
|
||||
$string['nouserstobeadded'] = 'No user entries to be added';
|
||||
$string['ntlmsso_attempting'] = 'Attempting Single Sign On via NTLM...';
|
||||
$string['ntlmsso_failed'] = 'Auto-login failed, try the normal login page...';
|
||||
$string['ntlmsso_isdisabled'] = 'NTLM SSO is disabled.';
|
||||
|
||||
@@ -279,6 +279,142 @@ class auth_ldap_plugin_testcase extends advanced_testcase {
|
||||
$this->assertEventLegacyLogData($expectedlog, $event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test logging in via LDAP calls a user_loggedin event.
|
||||
*/
|
||||
public function test_ldap_user_signup() {
|
||||
global $CFG, $DB;
|
||||
|
||||
// User to create.
|
||||
$user = array(
|
||||
'username' => 'usersignuptest1',
|
||||
'password' => 'Moodle2014!',
|
||||
'idnumber' => 'idsignuptest1',
|
||||
'firstname' => 'First Name User Test 1',
|
||||
'lastname' => 'Last Name User Test 1',
|
||||
'middlename' => 'Middle Name User Test 1',
|
||||
'lastnamephonetic' => '最後のお名前のテスト一号',
|
||||
'firstnamephonetic' => 'お名前のテスト一号',
|
||||
'alternatename' => 'Alternate Name User Test 1',
|
||||
'email' => 'usersignuptest1@email.com',
|
||||
'description' => 'This is a description for user 1',
|
||||
'city' => 'Perth',
|
||||
'country' => 'au',
|
||||
'mnethostid' => $CFG->mnet_localhost_id,
|
||||
'auth' => 'ldap'
|
||||
);
|
||||
|
||||
if (!extension_loaded('ldap')) {
|
||||
$this->markTestSkipped('LDAP extension is not loaded.');
|
||||
}
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
require_once($CFG->dirroot.'/auth/ldap/auth.php');
|
||||
require_once($CFG->libdir.'/ldaplib.php');
|
||||
|
||||
if (!defined('TEST_AUTH_LDAP_HOST_URL') or !defined('TEST_AUTH_LDAP_BIND_DN') or !defined('TEST_AUTH_LDAP_BIND_PW') or !defined('TEST_AUTH_LDAP_DOMAIN')) {
|
||||
$this->markTestSkipped('External LDAP test server not configured.');
|
||||
}
|
||||
|
||||
// Make sure we can connect the server.
|
||||
$debuginfo = '';
|
||||
if (!$connection = ldap_connect_moodle(TEST_AUTH_LDAP_HOST_URL, 3, 'rfc2307', TEST_AUTH_LDAP_BIND_DN, TEST_AUTH_LDAP_BIND_PW, LDAP_DEREF_NEVER, $debuginfo, false)) {
|
||||
$this->markTestSkipped('Can not connect to LDAP test server: '.$debuginfo);
|
||||
}
|
||||
|
||||
$this->enable_plugin();
|
||||
|
||||
// Create new empty test container.
|
||||
$topdn = 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN;
|
||||
|
||||
$this->recursive_delete($connection, TEST_AUTH_LDAP_DOMAIN, 'dc=moodletest');
|
||||
|
||||
$o = array();
|
||||
$o['objectClass'] = array('dcObject', 'organizationalUnit');
|
||||
$o['dc'] = 'moodletest';
|
||||
$o['ou'] = 'MOODLETEST';
|
||||
if (!ldap_add($connection, 'dc=moodletest,'.TEST_AUTH_LDAP_DOMAIN, $o)) {
|
||||
$this->markTestSkipped('Can not create test LDAP container.');
|
||||
}
|
||||
|
||||
// Create a few users.
|
||||
$o = array();
|
||||
$o['objectClass'] = array('organizationalUnit');
|
||||
$o['ou'] = 'users';
|
||||
ldap_add($connection, 'ou='.$o['ou'].','.$topdn, $o);
|
||||
|
||||
// Configure the plugin a bit.
|
||||
set_config('host_url', TEST_AUTH_LDAP_HOST_URL, 'auth/ldap');
|
||||
set_config('start_tls', 0, 'auth/ldap');
|
||||
set_config('ldap_version', 3, 'auth/ldap');
|
||||
set_config('ldapencoding', 'utf-8', 'auth/ldap');
|
||||
set_config('pagesize', '2', 'auth/ldap');
|
||||
set_config('bind_dn', TEST_AUTH_LDAP_BIND_DN, 'auth/ldap');
|
||||
set_config('bind_pw', TEST_AUTH_LDAP_BIND_PW, 'auth/ldap');
|
||||
set_config('user_type', 'rfc2307', 'auth/ldap');
|
||||
set_config('contexts', 'ou=users,'.$topdn, 'auth/ldap');
|
||||
set_config('search_sub', 0, 'auth/ldap');
|
||||
set_config('opt_deref', LDAP_DEREF_NEVER, 'auth/ldap');
|
||||
set_config('user_attribute', 'cn', 'auth/ldap');
|
||||
set_config('memberattribute', 'memberuid', 'auth/ldap');
|
||||
set_config('memberattribute_isdn', 0, 'auth/ldap');
|
||||
set_config('creators', 'cn=creators,'.$topdn, 'auth/ldap');
|
||||
set_config('removeuser', AUTH_REMOVEUSER_KEEP, 'auth/ldap');
|
||||
|
||||
set_config('field_map_email', 'mail', 'auth/ldap');
|
||||
set_config('field_updatelocal_email', 'oncreate', 'auth/ldap');
|
||||
set_config('field_updateremote_email', '0', 'auth/ldap');
|
||||
set_config('field_lock_email', 'unlocked', 'auth/ldap');
|
||||
|
||||
set_config('field_map_firstname', 'givenName', 'auth/ldap');
|
||||
set_config('field_updatelocal_firstname', 'oncreate', 'auth/ldap');
|
||||
set_config('field_updateremote_firstname', '0', 'auth/ldap');
|
||||
set_config('field_lock_firstname', 'unlocked', 'auth/ldap');
|
||||
|
||||
set_config('field_map_lastname', 'sn', 'auth/ldap');
|
||||
set_config('field_updatelocal_lastname', 'oncreate', 'auth/ldap');
|
||||
set_config('field_updateremote_lastname', '0', 'auth/ldap');
|
||||
set_config('field_lock_lastname', 'unlocked', 'auth/ldap');
|
||||
set_config('passtype', 'md5', 'auth/ldap');
|
||||
set_config('create_context', 'ou=users,'.$topdn, 'auth/ldap');
|
||||
|
||||
$this->assertEquals(2, $DB->count_records('user'));
|
||||
$this->assertEquals(0, $DB->count_records('role_assignments'));
|
||||
|
||||
/** @var auth_plugin_ldap $auth */
|
||||
$auth = get_auth_plugin('ldap');
|
||||
|
||||
$sink = $this->redirectEvents();
|
||||
$auth->user_signup((object)$user, false);
|
||||
$this->assertDebuggingCalled('Not sending email due to $CFG->noemailever config setting');
|
||||
$events = $sink->get_events();
|
||||
$sink->close();
|
||||
|
||||
// Verify 2 events get generated.
|
||||
$this->assertCount(2, $events);
|
||||
|
||||
// Get record from db.
|
||||
$dbuser = $DB->get_record('user', array('username' => $user['username']));
|
||||
$user['id'] = $dbuser->id;
|
||||
|
||||
// Last event is user_created.
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\user_created', $event);
|
||||
$this->assertEquals($user['id'], $event->objectid);
|
||||
$this->assertEquals('user_created', $event->get_legacy_eventname());
|
||||
$this->assertEquals(context_user::instance($user['id']), $event->get_context());
|
||||
$expectedlogdata = array(SITEID, 'user', 'add', '/view.php?id='.$event->objectid, fullname($dbuser));
|
||||
$this->assertEventLegacyLogData($expectedlogdata, $event);
|
||||
|
||||
// First event is user_password_updated.
|
||||
$event = array_pop($events);
|
||||
$this->assertInstanceOf('\core\event\user_updated', $event);
|
||||
|
||||
// Delete user which we just created.
|
||||
ldap_delete($connection, 'cn='.$user['username'].',ou=users,'.$topdn);
|
||||
}
|
||||
|
||||
protected function create_ldap_user($connection, $topdn, $i) {
|
||||
$o = array();
|
||||
$o['objectClass'] = array('inetOrgPerson', 'organizationalPerson', 'person', 'posixAccount');
|
||||
|
||||
@@ -40,9 +40,13 @@
|
||||
if (!empty($_SERVER[$pluginconfig->user_attribute])) { // Shibboleth auto-login
|
||||
$frm = new stdClass();
|
||||
$frm->username = strtolower($_SERVER[$pluginconfig->user_attribute]);
|
||||
$frm->password = substr(base64_encode($_SERVER[$pluginconfig->user_attribute]),0,8);
|
||||
// The random password consists of the first 8 letters of the base 64 encoded user ID
|
||||
// This password is never used unless the user account is converted to manual
|
||||
// The password is never actually used, but needs to be passed to the functions 'user_login' and
|
||||
// 'authenticate_user_login'. Shibboleth returns true for the function 'prevent_local_password', which is
|
||||
// used when setting the password in 'update_internal_user_password'. When 'prevent_local_password'
|
||||
// returns true, the password is set to 'not cached' (AUTH_PASSWORD_NOT_CACHED) in the Moodle DB. However,
|
||||
// rather than setting the password to a hard-coded value, we will generate one each time, in case there are
|
||||
// changes to the Shibboleth plugin and it is actually used.
|
||||
$frm->password = generate_password(8);
|
||||
|
||||
/// Check if the user has actually submitted login data to us
|
||||
|
||||
|
||||
@@ -28,8 +28,7 @@
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* create the temp dir where backup/restore will happen,
|
||||
* delete old directories and create temp ids table
|
||||
* Create the temp dir where backup/restore will happen and create temp ids table.
|
||||
*/
|
||||
class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
|
||||
@@ -38,7 +37,6 @@ class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
$progress->start_progress('Deleting backup directories');
|
||||
backup_helper::check_and_create_backup_dir($this->get_backupid());// Create backup temp dir
|
||||
backup_helper::clear_backup_dir($this->get_backupid(), $progress); // Empty temp dir, just in case
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60), $progress); // Delete > 4 hours temp dirs
|
||||
backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table
|
||||
backup_controller_dbops::create_backup_ids_temp_table($this->get_backupid()); // Create ids temp table
|
||||
$progress->end_progress();
|
||||
@@ -46,11 +44,11 @@ class create_and_clean_temp_stuff extends backup_execution_step {
|
||||
}
|
||||
|
||||
/**
|
||||
* delete the temp dir used by backup/restore (conditionally),
|
||||
* delete old directories and drop tem ids table. Note we delete
|
||||
* Delete the temp dir used by backup/restore (conditionally),
|
||||
* delete old directories and drop temp ids table. Note we delete
|
||||
* the directory but not the corresponding log file that will be
|
||||
* there for, at least, 4 hours - only delete_old_backup_dirs()
|
||||
* deletes log files (for easier access to them)
|
||||
* there for, at least, 1 week - only delete_old_backup_dirs() or cron
|
||||
* deletes log files (for easier access to them).
|
||||
*/
|
||||
class drop_and_clean_temp_stuff extends backup_execution_step {
|
||||
|
||||
@@ -60,7 +58,7 @@ class drop_and_clean_temp_stuff extends backup_execution_step {
|
||||
global $CFG;
|
||||
|
||||
backup_controller_dbops::drop_backup_ids_temp_table($this->get_backupid()); // Drop ids temp table
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60)); // Delete > 4 hours temp dirs
|
||||
backup_helper::delete_old_backup_dirs(strtotime('-1 week')); // Delete > 1 week old temp dirs.
|
||||
// Delete temp dir conditionally:
|
||||
// 1) If $CFG->keeptempdirectoriesonbackup is not enabled
|
||||
// 2) If backup temp dir deletion has been marked to be avoided
|
||||
|
||||
@@ -159,7 +159,7 @@ class backup_xml_transformer extends xml_contenttransformer {
|
||||
// Add the module ones. Each module supporting moodle2 backups MUST have it
|
||||
$mods = core_component::get_plugin_list('mod');
|
||||
foreach ($mods as $mod => $moddir) {
|
||||
if (plugin_supports('mod', $mod, FEATURE_BACKUP_MOODLE2)) {
|
||||
if (plugin_supports('mod', $mod, FEATURE_BACKUP_MOODLE2) && class_exists('backup_' . $mod . '_activity_task')) {
|
||||
$encoders['backup_' . $mod . '_activity_task'] = 'encode_content_links';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class restore_drop_and_clean_temp_stuff extends restore_execution_step {
|
||||
restore_controller_dbops::drop_restore_temp_tables($this->get_restoreid()); // Drop ids temp table
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress('Deleting backup dir');
|
||||
backup_helper::delete_old_backup_dirs(time() - (4 * 60 * 60), $progress); // Delete > 4 hours temp dirs
|
||||
backup_helper::delete_old_backup_dirs(strtotime('-1 week'), $progress); // Delete > 1 week old temp dirs.
|
||||
if (empty($CFG->keeptempdirectoriesonbackup)) { // Conditionally
|
||||
backup_helper::delete_backup_dir($this->task->get_tempdir(), $progress); // Empty restore dir
|
||||
}
|
||||
@@ -1401,11 +1401,14 @@ class restore_course_structure_step extends restore_structure_step {
|
||||
$data->fullname = $fullname;
|
||||
$data->shortname= $shortname;
|
||||
|
||||
// Only allow the idnumber to be set if the user has permission and the idnumber is not already in use by
|
||||
// another course on this site.
|
||||
$context = context::instance_by_id($this->task->get_contextid());
|
||||
if (has_capability('moodle/course:changeidnumber', $context, $this->task->get_userid())) {
|
||||
$data->idnumber = '';
|
||||
if (!empty($data->idnumber) && has_capability('moodle/course:changeidnumber', $context, $this->task->get_userid()) &&
|
||||
$this->task->is_samesite() && !$DB->record_exists('course', array('idnumber' => $data->idnumber))) {
|
||||
// Do not reset idnumber.
|
||||
} else {
|
||||
unset($data->idnumber);
|
||||
$data->idnumber = '';
|
||||
}
|
||||
|
||||
// Any empty value for course->hiddensections will lead to 0 (default, show collapsed).
|
||||
@@ -2537,7 +2540,14 @@ class restore_course_logs_structure_step extends restore_structure_step {
|
||||
|
||||
// If we have data, insert it, else something went wrong in the restore_logs_processor
|
||||
if ($data) {
|
||||
$DB->insert_record('log', $data);
|
||||
if (empty($data->url)) {
|
||||
$data->url = '';
|
||||
}
|
||||
if (empty($data->info)) {
|
||||
$data->info = '';
|
||||
}
|
||||
add_to_log($data->course, $data->module, $data->action, $data->url, $data->info,
|
||||
$data->cmid, $data->userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2575,7 +2585,14 @@ class restore_activity_logs_structure_step extends restore_course_logs_structure
|
||||
|
||||
// If we have data, insert it, else something went wrong in the restore_logs_processor
|
||||
if ($data) {
|
||||
$DB->insert_record('log', $data);
|
||||
if (empty($data->url)) {
|
||||
$data->url = '';
|
||||
}
|
||||
if (empty($data->info)) {
|
||||
$data->info = '';
|
||||
}
|
||||
add_to_log($data->course, $data->module, $data->action, $data->url, $data->info,
|
||||
$data->cmid, $data->userid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3558,13 +3575,16 @@ class restore_move_module_questions_categories extends restore_execution_step {
|
||||
* Execution step that will create all the question/answers/qtype-specific files for the restored
|
||||
* questions. It must be executed after {@link restore_move_module_questions_categories}
|
||||
* because only then each question is in its final category and only then the
|
||||
* context can be determined
|
||||
*
|
||||
* TODO: Improve this. Instead of looping over each question, it can be reduced to
|
||||
* be done by contexts (this will save a huge ammount of queries)
|
||||
* contexts can be determined.
|
||||
*/
|
||||
class restore_create_question_files extends restore_execution_step {
|
||||
|
||||
/** @var array Question-type specific component items cache. */
|
||||
private $qtypecomponentscache = array();
|
||||
|
||||
/**
|
||||
* Preform the restore_create_question_files step.
|
||||
*/
|
||||
protected function define_execution() {
|
||||
global $DB;
|
||||
|
||||
@@ -3572,60 +3592,93 @@ class restore_create_question_files extends restore_execution_step {
|
||||
$progress = $this->task->get_progress();
|
||||
$progress->start_progress($this->get_name(), core_backup_progress::INDETERMINATE);
|
||||
|
||||
// Let's process only created questions
|
||||
$questionsrs = $DB->get_recordset_sql("SELECT bi.itemid, bi.newitemid, bi.parentitemid, q.qtype
|
||||
// Parentitemids of question_createds in backup_ids_temp are the category it is in.
|
||||
// MUST use a recordset, as there is no unique key in the first (or any) column.
|
||||
$catqtypes = $DB->get_recordset_sql("SELECT DISTINCT bi.parentitemid AS categoryid, q.qtype as qtype
|
||||
FROM {backup_ids_temp} bi
|
||||
JOIN {question} q ON q.id = bi.newitemid
|
||||
WHERE bi.backupid = ?
|
||||
AND bi.itemname = 'question_created'", array($this->get_restoreid()));
|
||||
foreach ($questionsrs as $question) {
|
||||
// Report progress for each question.
|
||||
$progress->progress();
|
||||
AND bi.itemname = 'question_created'
|
||||
ORDER BY categoryid ASC", array($this->get_restoreid()));
|
||||
|
||||
// Get question_category mapping, it contains the target context for the question
|
||||
if (!$qcatmapping = restore_dbops::get_backup_ids_record($this->get_restoreid(), 'question_category', $question->parentitemid)) {
|
||||
// Something went really wrong, cannot find the question_category for the question
|
||||
debugging('Error fetching target context for question', DEBUG_DEVELOPER);
|
||||
continue;
|
||||
}
|
||||
// Calculate source and target contexts
|
||||
$oldctxid = $qcatmapping->info->contextid;
|
||||
$newctxid = $qcatmapping->parentitemid;
|
||||
$currentcatid = -1;
|
||||
foreach ($catqtypes as $categoryid => $row) {
|
||||
$qtype = $row->qtype;
|
||||
|
||||
// Add common question files (question and question_answer ones)
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'questiontext',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
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, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'correctfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'partiallycorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'incorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', $question->itemid, $newctxid, true, $progress);
|
||||
// Check if we are in a new category.
|
||||
if ($currentcatid !== $categoryid) {
|
||||
// Report progress for each category.
|
||||
$progress->progress();
|
||||
|
||||
// Add qtype dependent files
|
||||
$components = backup_qtype_plugin::get_components_and_fileareas($question->qtype);
|
||||
foreach ($components as $component => $fileareas) {
|
||||
foreach ($fileareas as $filearea => $mapping) {
|
||||
// Use itemid only if mapping is question_created
|
||||
$itemid = ($mapping == 'question_created') ? $question->itemid : null;
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea,
|
||||
$oldctxid, $this->task->get_userid(), $mapping, $itemid, $newctxid, true, $progress);
|
||||
if (!$qcatmapping = restore_dbops::get_backup_ids_record($this->get_restoreid(),
|
||||
'question_category', $categoryid)) {
|
||||
// Something went really wrong, cannot find the question_category for the question_created records.
|
||||
debugging('Error fetching target context for question', DEBUG_DEVELOPER);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate source and target contexts.
|
||||
$oldctxid = $qcatmapping->info->contextid;
|
||||
$newctxid = $qcatmapping->parentitemid;
|
||||
|
||||
$this->send_common_files($oldctxid, $newctxid, $progress);
|
||||
$currentcatid = $categoryid;
|
||||
}
|
||||
|
||||
$this->send_qtype_files($qtype, $oldctxid, $newctxid, $progress);
|
||||
}
|
||||
$questionsrs->close();
|
||||
$catqtypes->close();
|
||||
$progress->end_progress();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the common question files to a new context.
|
||||
*
|
||||
* @param int $oldctxid Old context id.
|
||||
* @param int $newctxid New context id.
|
||||
* @param \core\progress $progress Progress object to use.
|
||||
*/
|
||||
private function send_common_files($oldctxid, $newctxid, $progress) {
|
||||
// Add common question files (question and question_answer ones).
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'questiontext',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'generalfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answer',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'answerfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_answer', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'hint',
|
||||
$oldctxid, $this->task->get_userid(), 'question_hint', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'correctfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'partiallycorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), 'question', 'incorrectfeedback',
|
||||
$oldctxid, $this->task->get_userid(), 'question_created', null, $newctxid, true, $progress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the question type specific files to a new context.
|
||||
*
|
||||
* @param text $qtype The qtype name to send.
|
||||
* @param int $oldctxid Old context id.
|
||||
* @param int $newctxid New context id.
|
||||
* @param \core\progress $progress Progress object to use.
|
||||
*/
|
||||
private function send_qtype_files($qtype, $oldctxid, $newctxid, $progress) {
|
||||
if (!isset($this->qtypecomponentscache[$qtype])) {
|
||||
$this->qtypecomponentscache[$qtype] = backup_qtype_plugin::get_components_and_fileareas($qtype);
|
||||
}
|
||||
$components = $this->qtypecomponentscache[$qtype];
|
||||
foreach ($components as $component => $fileareas) {
|
||||
foreach ($fileareas as $filearea => $mapping) {
|
||||
restore_dbops::send_files_to_pool($this->get_basepath(), $this->get_restoreid(), $component, $filearea,
|
||||
$oldctxid, $this->task->get_userid(), $mapping, null, $newctxid, true, $progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to restore aliases and references to external files.
|
||||
|
||||
@@ -555,7 +555,8 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
self::apply_general_config_defaults($controller);
|
||||
break;
|
||||
case backup::MODE_AUTOMATED:
|
||||
// TODO: Move the loading from automatic stuff to here
|
||||
// Load the automated defaults.
|
||||
self::apply_auto_config_defaults($controller);
|
||||
break;
|
||||
default:
|
||||
// Nothing to do for other modes (IMPORT/HUB...). Some day we
|
||||
@@ -563,6 +564,43 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller settings default values from the automated backup config.
|
||||
*
|
||||
* @param backup_controller $controller
|
||||
*/
|
||||
private static function apply_auto_config_defaults(backup_controller $controller) {
|
||||
$settings = array(
|
||||
// Config name => Setting name.
|
||||
'backup_auto_users' => 'users',
|
||||
'backup_auto_role_assignments' => 'role_assignments',
|
||||
'backup_auto_activities' => 'activities',
|
||||
'backup_auto_blocks' => 'blocks',
|
||||
'backup_auto_filters' => 'filters',
|
||||
'backup_auto_comments' => 'comments',
|
||||
'backup_auto_badges' => 'badges',
|
||||
'backup_auto_userscompletion' => 'userscompletion',
|
||||
'backup_auto_logs' => 'logs',
|
||||
'backup_auto_histories' => 'grade_histories',
|
||||
'backup_auto_questionbank' => 'questionbank'
|
||||
);
|
||||
$plan = $controller->get_plan();
|
||||
foreach ($settings as $config => $settingname) {
|
||||
$value = get_config('backup', $config);
|
||||
if ($value === false) {
|
||||
// The setting is not set.
|
||||
$controller->log('Could not find a value for the config ' . $config, BACKUP::LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
if ($plan->setting_exists($settingname)) {
|
||||
$setting = $plan->get_setting($settingname);
|
||||
$setting->set_value($value);
|
||||
} else {
|
||||
$controller->log('Unknown setting: ' . $settingname, BACKUP::LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the controller settings default values from the backup config.
|
||||
*
|
||||
@@ -591,6 +629,7 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
// Ignore this because the config has not been set. get_config
|
||||
// returns false if a setting doesn't exist, '0' is returned when
|
||||
// the configuration is set to false.
|
||||
$controller->log('Could not find a value for the config ' . $config, BACKUP::LOG_DEBUG);
|
||||
continue;
|
||||
}
|
||||
$locked = (get_config('backup', $config.'_locked') == true);
|
||||
@@ -602,6 +641,8 @@ abstract class backup_controller_dbops extends backup_dbops {
|
||||
$setting->set_status(base_setting::LOCKED_BY_CONFIG);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$controller->log('Unknown setting: ' . $setting, BACKUP::LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +103,18 @@ abstract class backup_structure_dbops extends backup_dbops {
|
||||
}
|
||||
}
|
||||
|
||||
public static function annotate_files($backupid, $contextid, $component, $filearea, $itemid) {
|
||||
/**
|
||||
* Adds backup id database record for all files in the given file area.
|
||||
*
|
||||
* @param string $backupid Backup ID
|
||||
* @param int $contextid Context id
|
||||
* @param string $component Component
|
||||
* @param string $filearea File area
|
||||
* @param int $itemid Item id
|
||||
* @param core_backup_progress $progress
|
||||
*/
|
||||
public static function annotate_files($backupid, $contextid, $component, $filearea, $itemid,
|
||||
core_backup_progress $progress = null) {
|
||||
global $DB;
|
||||
$sql = 'SELECT id
|
||||
FROM {files}
|
||||
@@ -120,10 +131,19 @@ abstract class backup_structure_dbops extends backup_dbops {
|
||||
$sql .= ' AND itemid = ?';
|
||||
$params[] = $itemid;
|
||||
}
|
||||
if ($progress) {
|
||||
$progress->start_progress('');
|
||||
}
|
||||
$rs = $DB->get_recordset_sql($sql, $params);
|
||||
foreach ($rs as $record) {
|
||||
if ($progress) {
|
||||
$progress->progress();
|
||||
}
|
||||
self::insert_backup_ids_record($backupid, 'file', $record->id);
|
||||
}
|
||||
if ($progress) {
|
||||
$progress->end_progress();
|
||||
}
|
||||
$rs->close();
|
||||
}
|
||||
|
||||
|
||||
@@ -1019,7 +1019,7 @@ abstract class restore_dbops {
|
||||
// Even if a file has been deleted since the backup was made, the file metadata will remain in the
|
||||
// files table, and the file will not be moved to the trashdir.
|
||||
// Files are not cleared from the files table by cron until several days after deletion.
|
||||
if ($foundfiles = $DB->get_records('files', array('contenthash' => $file->contenthash))) {
|
||||
if ($foundfiles = $DB->get_records('files', array('contenthash' => $file->contenthash), '', '*', 0, 1)) {
|
||||
// Only grab one of the foundfiles - the file content should be the same for all entries.
|
||||
$foundfile = reset($foundfiles);
|
||||
$fs->create_file_from_storedfile($file_record, $foundfile->id);
|
||||
|
||||
@@ -391,27 +391,6 @@ abstract class backup_cron_automated_helper {
|
||||
|
||||
try {
|
||||
|
||||
$settings = array(
|
||||
'users' => 'backup_auto_users',
|
||||
'role_assignments' => 'backup_auto_role_assignments',
|
||||
'activities' => 'backup_auto_activities',
|
||||
'blocks' => 'backup_auto_blocks',
|
||||
'filters' => 'backup_auto_filters',
|
||||
'comments' => 'backup_auto_comments',
|
||||
'badges' => 'backup_auto_badges',
|
||||
'completion_information' => 'backup_auto_userscompletion',
|
||||
'logs' => 'backup_auto_logs',
|
||||
'histories' => 'backup_auto_histories',
|
||||
'questionbank' => 'backup_auto_questionbank'
|
||||
);
|
||||
foreach ($settings as $setting => $configsetting) {
|
||||
if ($bc->get_plan()->setting_exists($setting)) {
|
||||
if (isset($config->{$configsetting})) {
|
||||
$bc->get_plan()->get_setting($setting)->set_value($config->{$configsetting});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set the default filename.
|
||||
$format = $bc->get_format();
|
||||
$type = $bc->get_type();
|
||||
|
||||
@@ -89,11 +89,11 @@ class restore_logs_processor {
|
||||
}
|
||||
// Arrived here log is empty, no rule was able to perform the conversion, log the problem
|
||||
if (empty($newlog)) {
|
||||
self::$task->log('Log module-action "' . $keyname . ' process problem. Not restored', backup::LOG_DEBUG);
|
||||
self::$task->log('Log module-action "' . $keyname . '" process problem. Not restored', backup::LOG_DEBUG);
|
||||
}
|
||||
|
||||
} else { // Action not found log the problem
|
||||
self::$task->log('Log module-action "' . $keyname . ' unknown. Not restored', backup::LOG_DEBUG);
|
||||
self::$task->log('Log module-action "' . $keyname . '" unknown. Not restored', backup::LOG_DEBUG);
|
||||
$newlog = false;
|
||||
|
||||
}
|
||||
|
||||
@@ -167,18 +167,21 @@ class restore_plan extends base_plan implements loggable {
|
||||
parent::execute();
|
||||
$this->controller->set_status(backup::STATUS_FINISHED_OK);
|
||||
|
||||
// Trigger a course restored event.
|
||||
$event = \core\event\course_restored::create(array(
|
||||
'objectid' => $this->get_courseid(),
|
||||
'userid' => $this->get_userid(),
|
||||
'context' => context_course::instance($this->get_courseid()),
|
||||
'other' => array('type' => $this->controller->get_type(),
|
||||
'target' => $this->controller->get_target(),
|
||||
'mode' => $this->controller->get_mode(),
|
||||
'operation' => $this->controller->get_operation(),
|
||||
'samesite' => $this->controller->is_samesite())
|
||||
));
|
||||
$event->trigger();
|
||||
// Check if we are restoring a course.
|
||||
if ($this->controller->get_type() === backup::TYPE_1COURSE) {
|
||||
// Trigger a course restored event.
|
||||
$event = \core\event\course_restored::create(array(
|
||||
'objectid' => $this->get_courseid(),
|
||||
'userid' => $this->get_userid(),
|
||||
'context' => context_course::instance($this->get_courseid()),
|
||||
'other' => array('type' => $this->controller->get_type(),
|
||||
'target' => $this->controller->get_target(),
|
||||
'mode' => $this->controller->get_mode(),
|
||||
'operation' => $this->controller->get_operation(),
|
||||
'samesite' => $this->controller->is_samesite())
|
||||
));
|
||||
$event->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -86,7 +86,7 @@ class backup_structure_processor extends base_processor {
|
||||
foreach ($area as $filearea => $info) {
|
||||
$contextid = !is_null($info->contextid) ? $info->contextid : $this->get_var(backup::VAR_CONTEXTID);
|
||||
$itemid = !is_null($info->element) ? $info->element->get_value() : null;
|
||||
backup_structure_dbops::annotate_files($backupid, $contextid, $component, $filearea, $itemid);
|
||||
backup_structure_dbops::annotate_files($backupid, $contextid, $component, $filearea, $itemid, $this->progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,7 +139,8 @@ class base_setting_ui {
|
||||
* @param string $label
|
||||
*/
|
||||
public function set_label($label) {
|
||||
if ((string)$label === '' || $label !== clean_param($label, PARAM_TEXT)) {
|
||||
$label = (string)$label;
|
||||
if ($label === '' || $label !== clean_param($label, PARAM_TEXT)) {
|
||||
throw new base_setting_ui_exception('setting_invalid_ui_label');
|
||||
}
|
||||
$this->label = $label;
|
||||
|
||||
@@ -244,9 +244,20 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
global $CFG, $PAGE;
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
|
||||
// These variables are used to check if the form using this function was submitted.
|
||||
$target = optional_param('target', false, PARAM_INT);
|
||||
$targetid = optional_param('targetid', null, PARAM_INT);
|
||||
|
||||
// Check if they submitted the form but did not provide all the data we need.
|
||||
$missingdata = false;
|
||||
if ($target and is_null($targetid)) {
|
||||
$missingdata = true;
|
||||
}
|
||||
|
||||
$nextstageurl->param('sesskey', sesskey());
|
||||
|
||||
$form = html_writer::start_tag('form', array('method'=>'post', 'action'=>$nextstageurl->out_omit_querystring()));
|
||||
$form = html_writer::start_tag('form', array('method' => 'post', 'action' => $nextstageurl->out_omit_querystring(),
|
||||
'class' => 'mform'));
|
||||
foreach ($nextstageurl->params() as $key=>$value) {
|
||||
$form .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>$key, 'value'=>$value));
|
||||
}
|
||||
@@ -261,7 +272,16 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
$html .= html_writer::start_tag('div', array('class'=>'bcs-new-course backup-section'));
|
||||
$html .= $this->output->heading(get_string('restoretonewcourse', 'backup'), 2, array('class'=>'header'));
|
||||
$html .= $this->backup_detail_input(get_string('restoretonewcourse', 'backup'), 'radio', 'target', backup::TARGET_NEW_COURSE, array('checked'=>'checked'));
|
||||
$html .= $this->backup_detail_pair(get_string('selectacategory', 'backup'), $this->render($categories));
|
||||
$selectacategoryhtml = $this->backup_detail_pair(get_string('selectacategory', 'backup'), $this->render($categories));
|
||||
// Display the category selection as required if the form was submitted but this data was not supplied.
|
||||
if ($missingdata && $target == backup::TARGET_NEW_COURSE) {
|
||||
$html .= html_writer::span(get_string('required'), 'error');
|
||||
$html .= html_writer::start_tag('fieldset', array('class' => 'error'));
|
||||
$html .= $selectacategoryhtml;
|
||||
$html .= html_writer::end_tag('fieldset');
|
||||
} else {
|
||||
$html .= $selectacategoryhtml;
|
||||
}
|
||||
$html .= $this->backup_detail_pair('', html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('continue'))));
|
||||
$html .= html_writer::end_tag('div');
|
||||
$html .= html_writer::end_tag('form');
|
||||
@@ -290,13 +310,21 @@ class core_backup_renderer extends plugin_renderer_base {
|
||||
if ($wholecourse) {
|
||||
$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));
|
||||
} else {
|
||||
// We only allow restore adding to existing for now. Enforce it here.
|
||||
$html .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'target', 'value'=>backup::TARGET_EXISTING_ADDING));
|
||||
$courses->invalidate_results(); // Clean list of courses
|
||||
$courses->set_include_currentcourse(); // Show current course in the list
|
||||
$html .= $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
|
||||
}
|
||||
$selectacoursehtml = $this->backup_detail_pair(get_string('selectacourse', 'backup'), $this->render($courses));
|
||||
// Display the course selection as required if the form was submitted but this data was not supplied.
|
||||
if ($missingdata && $target == backup::TARGET_EXISTING_ADDING) {
|
||||
$html .= html_writer::span(get_string('required'), 'error');
|
||||
$html .= html_writer::start_tag('fieldset', array('class' => 'error'));
|
||||
$html .= $selectacoursehtml;
|
||||
$html .= html_writer::end_tag('fieldset');
|
||||
} else {
|
||||
$html .= $selectacoursehtml;
|
||||
}
|
||||
$html .= $this->backup_detail_pair('', html_writer::empty_tag('input', array('type'=>'submit', 'value'=>get_string('continue'))));
|
||||
$html .= html_writer::end_tag('div');
|
||||
|
||||
@@ -18,7 +18,7 @@ Feature: Backup Moodle courses
|
||||
@javascript
|
||||
Scenario: Backup a course providing options
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
Then I should see "Restore"
|
||||
And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
|
||||
And I should see "URL of backup"
|
||||
@@ -27,11 +27,11 @@ Feature: Backup Moodle courses
|
||||
@javascript
|
||||
Scenario: Backup a course with default options
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Include calendar events | 0 |
|
||||
| Include course logs | 1 |
|
||||
| setting_section_section_5_userinfo | 0 |
|
||||
| setting_section_section_5_included | 0 |
|
||||
| Initial | Include calendar events | 0 |
|
||||
| Initial | Include course logs | 1 |
|
||||
| Schema | setting_section_section_5_userinfo | 0 |
|
||||
| Schema | setting_section_section_5_included | 0 |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
Then I should see "Restore"
|
||||
And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
|
||||
And I should not see "Section 3"
|
||||
@@ -44,17 +44,17 @@ Feature: Backup Moodle courses
|
||||
@javascript
|
||||
Scenario: Backup a course without blocks
|
||||
When I backup "Course 1" course using this options:
|
||||
| id_setting_root_blocks | 0 |
|
||||
| 1 | setting_root_blocks | 0 |
|
||||
Then I should see "Course backup area"
|
||||
|
||||
@javascript
|
||||
Scenario: Backup selecting just one section
|
||||
When I backup "Course 2" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| setting_section_section_2_userinfo | 0 |
|
||||
| setting_section_section_2_included | 0 |
|
||||
| setting_section_section_4_userinfo | 0 |
|
||||
| setting_section_section_4_included | 0 |
|
||||
| Schema | setting_section_section_2_userinfo | 0 |
|
||||
| Schema | setting_section_section_2_userinfo | 0 |
|
||||
| Schema | setting_section_section_4_included | 0 |
|
||||
| Schema | setting_section_section_4_included | 0 |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
Then I should see "Course backup area"
|
||||
And I click on "Restore" "link" in the "test_backup.mbz" "table_row"
|
||||
And I should not see "Section 2"
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_base.php');
|
||||
require_once(__DIR__ . '/../../../../../lib/behat/behat_field_manager.php');
|
||||
require_once(__DIR__ . '/../../../../../lib/tests/behat/behat_navigation.php');
|
||||
|
||||
use Behat\Gherkin\Node\TableNode as TableNode,
|
||||
Behat\Mink\Exception\ElementNotFoundException as ElementNotFoundException,
|
||||
@@ -42,6 +43,19 @@ use Behat\Gherkin\Node\TableNode as TableNode,
|
||||
*/
|
||||
class behat_backup extends behat_base {
|
||||
|
||||
/**
|
||||
* Follow a link like 'Backup' or 'Import', where the link name comes from
|
||||
* a language string, in the settings nav block of a course.
|
||||
* @param string $langstring the lang string to look for. E.g. 'backup' or 'import'.
|
||||
* @param string $component (optional) second argument to {@link get_string}.
|
||||
*/
|
||||
protected function navigate_to_course_settings_link($langstring, $component = '') {
|
||||
$behatnavigation = new behat_navigation();
|
||||
$behatnavigation->setMink($this->getMink());
|
||||
$behatnavigation->i_navigate_to_node_in(get_string($langstring, $component),
|
||||
get_string('courseadministration'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Backups the specified course using the provided options. If you are interested in restoring this backup would be useful to provide a 'Filename' option.
|
||||
*
|
||||
@@ -50,34 +64,31 @@ class behat_backup extends behat_base {
|
||||
* @param TableNode $options Backup options or false if no options provided
|
||||
*/
|
||||
public function i_backup_course_using_this_options($backupcourse, $options = false) {
|
||||
|
||||
// We can not use other steps here as we don't know where the provided data
|
||||
// table elements are used, and we need to catch exceptions contantly.
|
||||
|
||||
// Go to homepage.
|
||||
$this->getSession()->visit($this->locate_path('/'));
|
||||
$this->wait();
|
||||
|
||||
// Click the course link.
|
||||
$this->find_link($backupcourse)->click();
|
||||
$this->wait();
|
||||
|
||||
// Click the backup link.
|
||||
$this->find_link(get_string('backup'))->click();
|
||||
$this->navigate_to_course_settings_link('backup');
|
||||
$this->wait();
|
||||
|
||||
// Initial settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Initial"));
|
||||
$this->find_button(get_string('backupstage1action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Schema settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
|
||||
$this->find_button(get_string('backupstage2action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Confirmation and review, backup filename can also be specified.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Confirmation"));
|
||||
$this->find_button(get_string('backupstage4action', 'backup'))->press();
|
||||
|
||||
// Waiting for it to finish.
|
||||
@@ -113,7 +124,7 @@ class behat_backup extends behat_base {
|
||||
$this->wait();
|
||||
|
||||
// Click the import link.
|
||||
$this->find_link(get_string('import'))->click();
|
||||
$this->navigate_to_course_settings_link('import');
|
||||
$this->wait();
|
||||
|
||||
// Select the course.
|
||||
@@ -132,12 +143,12 @@ class behat_backup extends behat_base {
|
||||
$this->wait();
|
||||
|
||||
// Initial settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Initial"));
|
||||
$this->find_button(get_string('importbackupstage1action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Schema settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
|
||||
$this->find_button(get_string('importbackupstage2action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
@@ -303,12 +314,12 @@ class behat_backup extends behat_base {
|
||||
// table elements are used, and we need to catch exceptions contantly.
|
||||
|
||||
// Settings.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Settings"));
|
||||
$this->find_button(get_string('restorestage4action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
// Schema.
|
||||
$this->fill_backup_restore_form($options);
|
||||
$this->fill_backup_restore_form($this->get_step_options($options, "Schema"));
|
||||
$this->find_button(get_string('restorestage8action', 'backup'))->press();
|
||||
$this->wait();
|
||||
|
||||
@@ -341,23 +352,50 @@ class behat_backup extends behat_base {
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for the page to be loaded and the JS ready.
|
||||
$this->wait();
|
||||
|
||||
// If we find any of the provided options in the current form we should set the value.
|
||||
$datahash = $options->getRowsHash();
|
||||
foreach ($datahash as $locator => $value) {
|
||||
|
||||
try {
|
||||
$field = behat_field_manager::get_form_field_from_label($locator, $this);
|
||||
$field->set_value($value);
|
||||
|
||||
} catch (ElementNotFoundException $e) {
|
||||
// Next provided option then, this one should be part of another page's fields.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the options specific to this step of the backup/restore process.
|
||||
*
|
||||
* @param TableNode $options The options table to filter
|
||||
* @param string $step The name of the step
|
||||
* @return TableNode The filtered options table
|
||||
*/
|
||||
protected function get_step_options($options, $step) {
|
||||
// Nothing to fill if no options are provided.
|
||||
if (!$options) {
|
||||
return;
|
||||
}
|
||||
|
||||
$pageoptions = clone $options;
|
||||
|
||||
$rows = $options->getRows();
|
||||
$newrows = array();
|
||||
foreach ($rows as $k => $data) {
|
||||
if (count($data) !== 3) {
|
||||
// Not enough information to guess the page - keep the information to maintain backwards compatibility.
|
||||
$newrows[] = $data;
|
||||
continue;
|
||||
} else if ($data[0] == $step) {
|
||||
unset($data[0]);
|
||||
$newrows[] = $data;
|
||||
}
|
||||
}
|
||||
$pageoptions->setRows($newrows);
|
||||
return $pageoptions;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits until the DOM and the page Javascript code is ready.
|
||||
*
|
||||
|
||||
@@ -25,7 +25,7 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a course in another existing course
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
|
||||
Then I should see "Course 2"
|
||||
And I should see "Community finder" in the "Community finder" "block"
|
||||
@@ -34,9 +34,9 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a course in a new course
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into a new course using this options:
|
||||
| Course name | Course 1 restored in a new course |
|
||||
| Schema | Course name | Course 1 restored in a new course |
|
||||
Then I should see "Course 1 restored in a new course"
|
||||
And I should see "Community finder" in the "Community finder" "block"
|
||||
And I should see "Test forum name"
|
||||
@@ -50,12 +50,12 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a backup into the same course
|
||||
When I backup "Course 3" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
|
||||
| setting_section_section_3_included | 0 |
|
||||
| setting_section_section_3_userinfo | 0 |
|
||||
| setting_section_section_5_included | 0 |
|
||||
| setting_section_section_5_userinfo | 0 |
|
||||
| Schema | setting_section_section_3_included | 0 |
|
||||
| Schema | setting_section_section_3_userinfo | 0 |
|
||||
| Schema | setting_section_section_5_included | 0 |
|
||||
| Schema | setting_section_section_5_userinfo | 0 |
|
||||
Then I should see "Course 2"
|
||||
And I should see "Test assign name"
|
||||
And I should not see "Test database name"
|
||||
@@ -63,15 +63,15 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a backup into the same course removing it's contents before that
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I follow "Course 1"
|
||||
And I add a "Forum" to section "1" and I fill the form with:
|
||||
| Forum name | Test forum post backup name |
|
||||
| Description | Test forum post backup description |
|
||||
And I follow "Restore"
|
||||
And I merge "test_backup.mbz" backup into the current course after deleting it's contents using this options:
|
||||
| setting_section_section_5_userinfo | 0 |
|
||||
| setting_section_section_5_included | 0 |
|
||||
| Schema | setting_section_section_8_userinfo | 0 |
|
||||
| Schema | setting_section_section_8_included | 0 |
|
||||
Then I should see "Course 1"
|
||||
And I should not see "Section 3"
|
||||
And I should not see "Test forum post backup name"
|
||||
@@ -81,7 +81,7 @@ Feature: Restore Moodle 2 course backups
|
||||
@javascript
|
||||
Scenario: Restore a backup into a new course changing the course format afterwards
|
||||
Given I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
When I restore "test_backup.mbz" backup into a new course using this options:
|
||||
Then I should see "Topic 1"
|
||||
And I should see "Test forum name"
|
||||
@@ -117,9 +117,9 @@ Feature: Restore Moodle 2 course backups
|
||||
And I hide section "3"
|
||||
And I hide section "7"
|
||||
When I backup "Course 1" course using this options:
|
||||
| Filename | test_backup.mbz |
|
||||
| Confirmation | Filename | test_backup.mbz |
|
||||
And I restore "test_backup.mbz" backup into "Course 2" course using this options:
|
||||
| Overwrite course configuration | Yes |
|
||||
| Schema | Overwrite course configuration | Yes |
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I expand all fieldsets
|
||||
Then the "id_format" field should match "Topics format" value
|
||||
|
||||
+1
-1
@@ -120,7 +120,7 @@ if (count($acceptedroles) > 1) {
|
||||
}
|
||||
} else {
|
||||
// User has to be an admin or the one with the required role.
|
||||
$users = get_role_users($acceptedroles[0], $context, false, 'u.id', 'u.id ASC');
|
||||
$users = get_role_users($acceptedroles[0], $context, true, 'u.id', 'u.id ASC');
|
||||
$usersids = array_keys($users);
|
||||
if (!$isadmin && !in_array($USER->id, $usersids)) {
|
||||
echo $OUTPUT->header();
|
||||
|
||||
+10
-1
@@ -52,7 +52,16 @@ $PAGE->set_title(get_string('issuedbadge', 'badges'));
|
||||
if (isloggedin()) {
|
||||
$PAGE->set_heading($badge->badgeclass['name']);
|
||||
$PAGE->navbar->add($badge->badgeclass['name']);
|
||||
$url = new moodle_url('/badges/mybadges.php');
|
||||
if ($badge->recipient->id == $USER->id) {
|
||||
$url = new moodle_url('/badges/mybadges.php');
|
||||
} else {
|
||||
$url = new moodle_url($CFG->wwwroot);
|
||||
}
|
||||
navigation_node::override_active_url($url);
|
||||
} else {
|
||||
$PAGE->set_heading($badge->badgeclass['name']);
|
||||
$PAGE->navbar->add($badge->badgeclass['name']);
|
||||
$url = new moodle_url($CFG->wwwroot);
|
||||
navigation_node::override_active_url($url);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ class edit_details_form extends moodleform {
|
||||
$mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client');
|
||||
|
||||
$mform->addElement('textarea', 'description', get_string('description', 'badges'), 'wrap="virtual" rows="8" cols="70"');
|
||||
$mform->setType('description', PARAM_CLEANHTML);
|
||||
$mform->setType('description', PARAM_NOTAGS);
|
||||
$mform->addRule('description', null, 'required');
|
||||
|
||||
$str = $action == 'new' ? get_string('badgeimage', 'badges') : get_string('newimage', 'badges');
|
||||
|
||||
@@ -82,6 +82,14 @@ $badge = new external_badge($badge, $userid);
|
||||
|
||||
$PAGE->set_pagelayout('base');
|
||||
$PAGE->set_title(get_string('issuedbadge', 'badges'));
|
||||
$PAGE->set_heading(s($badge->issued->assertion->badge->name));
|
||||
$PAGE->navbar->add(s($badge->issued->assertion->badge->name));
|
||||
if (isloggedin() && $USER->id == $userid) {
|
||||
$url = new moodle_url('/badges/mybadges.php');
|
||||
} else {
|
||||
$url = new moodle_url($CFG->wwwroot);
|
||||
}
|
||||
navigation_node::override_active_url($url);
|
||||
|
||||
echo $OUTPUT->header();
|
||||
|
||||
|
||||
+18
-16
@@ -41,7 +41,7 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
$bname = $badge->name;
|
||||
$imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false);
|
||||
} else {
|
||||
$bname = $badge->assertion->badge->name;
|
||||
$bname = s($badge->assertion->badge->name);
|
||||
$imageurl = $badge->imageUrl;
|
||||
}
|
||||
|
||||
@@ -420,47 +420,48 @@ class core_badges_renderer extends plugin_renderer_base {
|
||||
}
|
||||
|
||||
$datatable->data[] = array($this->output->heading(get_string('issuerdetails', 'badges'), 3), '');
|
||||
$datatable->data[] = array(get_string('issuername', 'badges'), $issuer->name);
|
||||
$datatable->data[] = array(get_string('issuername', 'badges'), s($issuer->name));
|
||||
$datatable->data[] = array(get_string('issuerurl', 'badges'),
|
||||
html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin)));
|
||||
html_writer::tag('a', s($issuer->origin), array('href' => $issuer->origin)));
|
||||
if (isset($issuer->contact)) {
|
||||
$datatable->data[] = array(get_string('contact', 'badges'), obfuscate_mailto($issuer->contact));
|
||||
}
|
||||
$datatable->data[] = array($this->output->heading(get_string('badgedetails', 'badges'), 3), '');
|
||||
$datatable->data[] = array(get_string('name'), $assertion->badge->name);
|
||||
$datatable->data[] = array(get_string('description', 'badges'), $assertion->badge->description);
|
||||
$datatable->data[] = array(get_string('name'), s($assertion->badge->name));
|
||||
$datatable->data[] = array(get_string('description', 'badges'), s($assertion->badge->description));
|
||||
$datatable->data[] = array(get_string('bcriteria', 'badges'),
|
||||
html_writer::tag('a', $assertion->badge->criteria, array('href' => $assertion->badge->criteria)));
|
||||
html_writer::tag('a', s($assertion->badge->criteria), array('href' => $assertion->badge->criteria)));
|
||||
$datatable->data[] = array($this->output->heading(get_string('issuancedetails', 'badges'), 3), '');
|
||||
if (isset($assertion->issued_on)) {
|
||||
$datatable->data[] = array(get_string('dateawarded', 'badges'), $assertion->issued_on);
|
||||
$issuedate = !strtotime($assertion->issued_on) ? s($assertion->issued_on) : strtotime($assertion->issued_on);
|
||||
$datatable->data[] = array(get_string('dateawarded', 'badges'), userdate($issuedate));
|
||||
}
|
||||
if (isset($assertion->badge->expire)) {
|
||||
if (isset($assertion->expires)) {
|
||||
$today_date = date('Y-m-d');
|
||||
$today = strtotime($today_date);
|
||||
$expiration = strtotime($assertion->badge->expire);
|
||||
$expiration = !strtotime($assertion->expires) ? s($assertion->expires) : strtotime($assertion->expires);
|
||||
if ($expiration < $today) {
|
||||
$cell = new html_table_cell($assertion->badge->expire . get_string('warnexpired', 'badges'));
|
||||
$cell = new html_table_cell(userdate($expiration) . get_string('warnexpired', 'badges'));
|
||||
$cell->attributes = array('class' => 'notifyproblem warning');
|
||||
$datatable->data[] = array(get_string('expirydate', 'badges'), $cell);
|
||||
|
||||
$image = html_writer::start_tag('div', array('class' => 'badge'));
|
||||
$image .= html_writer::empty_tag('img', array('src' => $issued['badge']['image']));
|
||||
$image .= html_writer::empty_tag('img', array('src' => $issued->imageUrl));
|
||||
$image .= html_writer::start_tag('span', array('class' => 'expired'))
|
||||
. $this->output->pix_icon('i/expired',
|
||||
get_string('expireddate', 'badges', $assertion->badge->expire),
|
||||
get_string('expireddate', 'badges', userdate($expiration)),
|
||||
'moodle',
|
||||
array('class' => 'expireimage'))
|
||||
. html_writer::end_tag('span');
|
||||
$image .= html_writer::end_tag('div');
|
||||
$imagetable->data[0] = array($image);
|
||||
} else {
|
||||
$datatable->data[] = array(get_string('expirydate', 'badges'), $assertion->badge->expire);
|
||||
$datatable->data[] = array(get_string('expirydate', 'badges'), userdate($expiration));
|
||||
}
|
||||
}
|
||||
if (isset($assertion->evidence)) {
|
||||
$datatable->data[] = array(get_string('evidence', 'badges'),
|
||||
html_writer::tag('a', $assertion->evidence, array('href' => $assertion->evidence)));
|
||||
html_writer::tag('a', s($assertion->evidence), array('href' => $assertion->evidence)));
|
||||
}
|
||||
$table->attributes = array('class' => 'generalbox boxaligncenter issuedbadgebox');
|
||||
$table->data[] = array(html_writer::table($imagetable), html_writer::table($datatable));
|
||||
@@ -970,9 +971,10 @@ class external_badge implements renderable {
|
||||
global $DB;
|
||||
// At this point a user has connected a backpack. So, we are going to get
|
||||
// their backpack email rather than their account email.
|
||||
$user = $DB->get_record_sql('SELECT u.lastname, u.firstname, b.email
|
||||
$namefields = get_all_user_name_fields(true, 'u');
|
||||
$user = $DB->get_record_sql("SELECT {$namefields}, b.email
|
||||
FROM {user} u INNER JOIN {badge_backpack} b ON u.id = b.userid
|
||||
WHERE userid = :userid', array('userid' => $recipient), IGNORE_MISSING);
|
||||
WHERE userid = :userid", array('userid' => $recipient), IGNORE_MISSING);
|
||||
|
||||
$this->issued = $badge;
|
||||
$this->recipient = $user;
|
||||
|
||||
@@ -318,11 +318,11 @@ class block_course_overview_renderer extends plugin_renderer_base {
|
||||
$plural = 's';
|
||||
if ($msgcount > 0) {
|
||||
$output .= get_string('youhavemessages', 'block_course_overview', $msgcount);
|
||||
} else {
|
||||
$output .= get_string('youhavenomessages', 'block_course_overview');
|
||||
if ($msgcount == 1) {
|
||||
$plural = '';
|
||||
}
|
||||
} else {
|
||||
$output .= get_string('youhavenomessages', 'block_course_overview');
|
||||
}
|
||||
$output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview'));
|
||||
$output .= $this->output->box_end();
|
||||
|
||||
@@ -25,19 +25,19 @@ Feature: Course summary block used in a course
|
||||
Scenario: Student can view course summary
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then "block_course_summary" "block" should exist
|
||||
And I should see "Proved the course summary block works!" in the "block_course_summary" "block"
|
||||
Then "Course/site summary" "block" should exist
|
||||
And I should see "Proved the course summary block works!" in the "Course/site summary" "block"
|
||||
|
||||
Scenario: Teacher can see an edit icon when edit mode is on and follow it to the course edit page
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
Then I should see "Proved the course summary block works!" in the "block_course_summary" "block"
|
||||
And I click on "Edit" "link" in the "block_course_summary" "block"
|
||||
Then I should see "Proved the course summary block works!" in the "Course/site summary" "block"
|
||||
And I click on "Edit" "link" in the "Course/site summary" "block"
|
||||
Then I should see "Edit course settings" in the "h2" "css_element"
|
||||
|
||||
Scenario: Teacher can not see edit icon when edit mode is off
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "Proved the course summary block works!" in the "block_course_summary" "block"
|
||||
And "Edit" "link" should not exist in the "block_course_summary" "block"
|
||||
Then I should see "Proved the course summary block works!" in the "Course/site summary" "block"
|
||||
And "Edit" "link" should not exist in the "Course/site summary" "block"
|
||||
|
||||
@@ -15,19 +15,19 @@ Feature: Course summary block used on the frontpage
|
||||
|
||||
Scenario: Guest can view site summary
|
||||
When I am on homepage
|
||||
Then "block_course_summary" "block" should exist
|
||||
And I should see "Proved the summary block works!" in the "block_course_summary" "block"
|
||||
Then "Course/site summary" "block" should exist
|
||||
And I should see "Proved the summary block works!" in the "Course/site summary" "block"
|
||||
|
||||
Scenario: Admin can see an edit icon when edit mode is on and follow it to the front page settings
|
||||
When I log in as "admin"
|
||||
And I am on homepage
|
||||
And I follow "Turn editing on"
|
||||
Then I should see "Proved the summary block works!" in the "block_course_summary" "block"
|
||||
And I click on "Edit" "link" in the "block_course_summary" "block"
|
||||
Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
|
||||
And I click on "Edit" "link" in the "Course/site summary" "block"
|
||||
Then I should see "Front page settings" in the "h2" "css_element"
|
||||
|
||||
Scenario: Admin can not see edit icon when edit mode is off
|
||||
When I log in as "teacher1"
|
||||
When I log in as "admin"
|
||||
And I am on homepage
|
||||
Then I should see "Proved the summary block works!" in the "block_course_summary" "block"
|
||||
And "Edit" "link" should not exist in the "block_course_summary" "block"
|
||||
Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
|
||||
And "Edit" "link" should not exist in the "Course/site summary" "block"
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
@block @block_glossary_random
|
||||
Feature: Random glossary entry block is used in a course
|
||||
In order to show the entries from glossary
|
||||
As a teacher
|
||||
I can add the random glossary entry to a course page
|
||||
|
||||
Background:
|
||||
Given the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| student1 | Sam1 | Student1 | student1@test.com |
|
||||
| teacher1 | Terry1 | Teacher1 | teacher1@test.com |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| student1 | C1 | student |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
|
||||
Scenario: Student can not see the block if it is not configured
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Random glossary entry" block
|
||||
Then I should see "Please configure this block using the edit icon" in the "block_glossary_random" "block"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And "block_glossary_random" "block" should not exist
|
||||
And I log out
|
||||
|
||||
Scenario: View random (last) entry in the glossary with auto approval
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | defaultapproval |
|
||||
| glossary | GlossaryAuto | Test glossary description | C1 | glossary1 | 1 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Random glossary entry" block
|
||||
And I configure the "block_glossary_random" block
|
||||
And I set the following fields to these values:
|
||||
| Title | AutoGlossaryblock |
|
||||
| Take entries from this glossary | GlossaryAuto |
|
||||
| How a new entry is chosen | Last modified entry |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
|
||||
And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Concept1 |
|
||||
| Definition | Definition1 |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I should see "Concept1" in the "AutoGlossaryblock" "block"
|
||||
And I should see "Definition1" in the "AutoGlossaryblock" "block"
|
||||
And I should not see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
|
||||
And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Concept2 |
|
||||
| Definition | Definition2 |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
# Only the last entry appears in the block
|
||||
And I should not see "Concept1" in the "AutoGlossaryblock" "block"
|
||||
And I should not see "Definition1" in the "AutoGlossaryblock" "block"
|
||||
And I should see "Concept2" in the "AutoGlossaryblock" "block"
|
||||
And I should see "Definition2" in the "AutoGlossaryblock" "block"
|
||||
And I click on "View all entries" "link" in the "AutoGlossaryblock" "block"
|
||||
And I should see "GlossaryAuto" in the "#page-header .navbar" "css_element"
|
||||
And I should see "Concept1" in the "#region-main" "css_element"
|
||||
And I should see "Concept2" in the "#region-main" "css_element"
|
||||
And I log out
|
||||
|
||||
Scenario: View random (last) entry in the glossary with manual approval
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber | defaultapproval |
|
||||
| glossary | GlossaryManual | Test glossary description | C1 | glossary2 | 0 |
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "Random glossary entry" block
|
||||
And I configure the "block_glossary_random" block
|
||||
And I set the following fields to these values:
|
||||
| Title | ManualGlossaryblock |
|
||||
| Take entries from this glossary | GlossaryManual |
|
||||
| How a new entry is chosen | Last modified entry |
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
When I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
Then I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
|
||||
And I click on "Add a new entry" "link" in the "ManualGlossaryblock" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Concept1 |
|
||||
| Definition | Definition1 |
|
||||
And I press "Save changes"
|
||||
And I follow "Course 1"
|
||||
And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
|
||||
And I follow "GlossaryManual"
|
||||
And I follow "Waiting approval"
|
||||
And I follow "Approve"
|
||||
And I follow "Course 1"
|
||||
And I should see "Concept1" in the "ManualGlossaryblock" "block"
|
||||
And I should see "Definition1" in the "ManualGlossaryblock" "block"
|
||||
And I log out
|
||||
@@ -0,0 +1,26 @@
|
||||
@block @block_glossary_random
|
||||
Feature: Random glossary entry block can be added to the frontpage
|
||||
In order to show the entries from glossary on the frontpage
|
||||
As a teacher
|
||||
I can add the random glossary entry to the frontpage
|
||||
|
||||
Scenario: Admin can add random glossary block to the frontpage
|
||||
Given the following "activities" exist:
|
||||
| activity | name | intro | course | idnumber |
|
||||
| glossary | Tips and Tricks | Frontpage glossary description | Acceptance test site | glossary0 |
|
||||
And I log in as "admin"
|
||||
And I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "Random glossary entry" block
|
||||
And I configure the "block_glossary_random" block
|
||||
And I set the following fields to these values:
|
||||
| Title | Tip of the day |
|
||||
| Take entries from this glossary | Tips and Tricks |
|
||||
And I press "Save changes"
|
||||
And I click on "Add a new entry" "link" in the "Tip of the day" "block"
|
||||
And I set the following fields to these values:
|
||||
| Concept | Never come late |
|
||||
| Definition | Come in time for your classes |
|
||||
And I press "Save changes"
|
||||
When I log out
|
||||
Then I should see "Never come late" in the "Tip of the day" "block"
|
||||
And I should see "Come in time for your classes" in the "Tip of the day" "block"
|
||||
@@ -0,0 +1,38 @@
|
||||
@block @block_html @core_block
|
||||
Feature: Adding and configuring HTML blocks
|
||||
In order to have custom blocks on a page
|
||||
As admin
|
||||
I need to be able to create, configure and change HTML blocks
|
||||
|
||||
@javascript
|
||||
Scenario: Configuring the HTML block with Javascript on
|
||||
Given I log in as "admin"
|
||||
When I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Static text without a header"
|
||||
And I press "Save changes"
|
||||
Then I should not see "(new HTML block)"
|
||||
And I configure the "block_html" block
|
||||
And I set the field "Block title" to "The HTML block header"
|
||||
And I set the field "Content" to "Static text with a header"
|
||||
And I press "Save changes"
|
||||
And "block_html" "block" should exist
|
||||
And "The HTML block header" "block" should exist
|
||||
And I should see "Static text with a header" in the "The HTML block header" "block"
|
||||
|
||||
Scenario: Configuring the HTML block with Javascript off
|
||||
Given I log in as "admin"
|
||||
When I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Static text without a header"
|
||||
And I press "Save changes"
|
||||
Then I should not see "(new HTML block)"
|
||||
And I configure the "block_html" block
|
||||
And I set the field "Block title" to "The HTML block header"
|
||||
And I set the field "Content" to "Static text with a header"
|
||||
And I press "Save changes"
|
||||
And "block_html" "block" should exist
|
||||
And "The HTML block header" "block" should exist
|
||||
And I should see "Static text with a header" in the "The HTML block header" "block"
|
||||
@@ -0,0 +1,36 @@
|
||||
@block @block_html
|
||||
Feature: HTML blocks in a course
|
||||
In order to have one or multiple HTML blocks in a course
|
||||
As a teacher
|
||||
I need to be able to create and change such blocks
|
||||
|
||||
Scenario: Adding HTML block in a course
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Terry1 | Teacher1 | teacher@asd.com |
|
||||
| student1 | Sam1 | Student1 | student1@asd.com |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname |
|
||||
| Course 1 | C1 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
| student1 | C1 | student |
|
||||
When I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
And I turn editing mode on
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "First block content"
|
||||
And I set the field "Block title" to "First block header"
|
||||
And I press "Save changes"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Second block content"
|
||||
And I set the field "Block title" to "Second block header"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
And I log in as "student1"
|
||||
And I follow "Course 1"
|
||||
And I should see "First block content" in the "First block header" "block"
|
||||
And I should see "Second block content" in the "Second block header" "block"
|
||||
@@ -0,0 +1,41 @@
|
||||
@block @block_html
|
||||
Feature: Adding and configuring HTML blocks
|
||||
In order to have one or multiple HTML blocks on a page
|
||||
As admin
|
||||
I need to be able to create, configure and change HTML blocks
|
||||
|
||||
Background:
|
||||
Given I log in as "admin"
|
||||
When I click on "Turn editing on" "link" in the "Administration" "block"
|
||||
And I add the "HTML" block
|
||||
|
||||
Scenario: Other users can not see HTML block that has not been configured
|
||||
Then "(new HTML block)" "block" should exist
|
||||
And I log out
|
||||
And "(new HTML block)" "block" should not exist
|
||||
And "block_html" "block" should not exist
|
||||
|
||||
Scenario: Other users can see HTML block that has been configured even when it has no header
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Content" to "Static text without a header"
|
||||
And I press "Save changes"
|
||||
Then I should not see "(new HTML block)"
|
||||
And I log out
|
||||
And I am on homepage
|
||||
And "block_html" "block" should exist
|
||||
And I should see "Static text without a header" in the "block_html" "block"
|
||||
And I should not see "(new HTML block)"
|
||||
|
||||
Scenario: Adding multiple instances of HTML block on a page
|
||||
And I configure the "block_html" block
|
||||
And I set the field "Block title" to "The HTML block header"
|
||||
And I set the field "Content" to "Static text with a header"
|
||||
And I press "Save changes"
|
||||
And I add the "HTML" block
|
||||
And I configure the "(new HTML block)" block
|
||||
And I set the field "Block title" to "The second HTML block header"
|
||||
And I set the field "Content" to "Second block contents"
|
||||
And I press "Save changes"
|
||||
And I log out
|
||||
Then I should see "Static text with a header" in the "The HTML block header" "block"
|
||||
And I should see "Second block contents" in the "The second HTML block header" "block"
|
||||
@@ -0,0 +1,190 @@
|
||||
@block @block_navigation
|
||||
Feature: Expand the courses nodes within the navigation block
|
||||
In order to navigate the site
|
||||
As an anonymous user, a guest, a student, and an admin
|
||||
I need to expand the courses node in the navigation block and check the display of courses and categories.
|
||||
|
||||
Background:
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@local.host |
|
||||
| student1 | Student | 1 | student1@local.host |
|
||||
And the following "categories" exist:
|
||||
| name | category | idnumber | visible |
|
||||
| cat1 | 0 | cat1 | 1 |
|
||||
| cat2 | 0 | cat2 | 1 |
|
||||
| cat21 | cat2 | cat21 | 1 |
|
||||
| cat211 | cat21 | cat211 | 1 |
|
||||
| cat3 | 0 | cat3 | 0 |
|
||||
And the following "courses" exist:
|
||||
| fullname | shortname | category | visible |
|
||||
| Course 1 | c1 | cat1 | 1 |
|
||||
| Course 2 | c2 | cat2 | 1 |
|
||||
| Course 3 | c3 | cat21 | 1 |
|
||||
| Course 4 | c4 | cat211 | 1 |
|
||||
| Course 5 | c5 | cat211 | 0 |
|
||||
| Course 6 | c6 | cat211 | 0 |
|
||||
| Course 7 | c7 | cat3 | 1 |
|
||||
| Course 8 | c8 | cat3 | 0 |
|
||||
And the following "course enrolments" exist:
|
||||
| user | course | role |
|
||||
| teacher1 | c1 | teacher |
|
||||
| teacher1 | c3 | teacher |
|
||||
| teacher1 | c5 | teacher |
|
||||
| student1 | c1 | student |
|
||||
| student1 | c2 | student |
|
||||
| student1 | c4 | student |
|
||||
And I log in as "admin"
|
||||
And I follow "Course 2"
|
||||
And I turn editing mode on
|
||||
And I click on "Edit settings" "link" in the "Administration" "block"
|
||||
And I set the following fields to these values:
|
||||
| Allow guest access | Yes |
|
||||
And I press "Save changes"
|
||||
And I set the following administration settings values:
|
||||
| Show all courses | 1 |
|
||||
And I log out
|
||||
|
||||
@javascript
|
||||
Scenario: As an anonymous user I expand the courses node to see courses.
|
||||
When I should see "You are not logged in." in the ".logininfo" "css_element"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should not see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And navigation node "c1" should not be expandable
|
||||
And navigation node "c2" should not be expandable
|
||||
And navigation node "c3" should not be expandable
|
||||
And navigation node "c4" should not be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As the admin user I expand the courses and category nodes to see courses.
|
||||
When I log in as "admin"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I expand "cat3" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should see "c5" in the "Navigation" "block"
|
||||
And I should see "c6" in the "Navigation" "block"
|
||||
And I should see "c7" in the "Navigation" "block"
|
||||
And I should see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should be expandable
|
||||
And navigation node "c4" should be expandable
|
||||
And navigation node "c5" should be expandable
|
||||
And navigation node "c6" should be expandable
|
||||
And navigation node "c7" should be expandable
|
||||
And navigation node "c8" should be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As teacher1 I expand the courses and category nodes to see courses.
|
||||
When I log in as "teacher1"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And I should not see "c7" in the "Navigation" "block"
|
||||
And I should not see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should be expandable
|
||||
And navigation node "c4" should not be expandable
|
||||
And navigation node "c5" should be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As student1 I expand the courses and category nodes to see courses.
|
||||
When I log in as "student1"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should not see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And I should not see "c7" in the "Navigation" "block"
|
||||
And I should not see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should not be expandable
|
||||
And navigation node "c4" should be expandable
|
||||
|
||||
@javascript
|
||||
Scenario: As guest I expand the courses and category nodes to see courses.
|
||||
When I log in as "guest"
|
||||
And I should see "Home" in the "Navigation" "block"
|
||||
And I should see "Courses" in the "Navigation" "block"
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should not see "cat3" in the "Navigation" "block"
|
||||
And I expand "cat1" node
|
||||
And I expand "cat2" node
|
||||
And I should see "cat21" in the "Navigation" "block"
|
||||
And I expand "cat21" node
|
||||
And I should see "cat211" in the "Navigation" "block"
|
||||
And I expand "cat211" node
|
||||
Then I should see "c1" in the "Navigation" "block"
|
||||
And I should see "c2" in the "Navigation" "block"
|
||||
And I should see "c3" in the "Navigation" "block"
|
||||
And I should see "c4" in the "Navigation" "block"
|
||||
And I should not see "c5" in the "Navigation" "block"
|
||||
And I should not see "c6" in the "Navigation" "block"
|
||||
And I should not see "c7" in the "Navigation" "block"
|
||||
And I should not see "c8" in the "Navigation" "block"
|
||||
And navigation node "c1" should not be expandable
|
||||
And navigation node "c2" should be expandable
|
||||
And navigation node "c3" should not be expandable
|
||||
And navigation node "c4" should not be expandable
|
||||
@@ -66,3 +66,34 @@ Feature: View my courses in navigation block
|
||||
And I expand "cat33" node
|
||||
And I should see "c331" in the "Navigation" "block"
|
||||
And I should not see "c332" in the "Navigation" "block"
|
||||
|
||||
@javascript
|
||||
Scenario: I can expand categories and courses as guest
|
||||
Given I set the following administration settings values:
|
||||
| Show my course categories | 1 |
|
||||
| Show all courses | 1 |
|
||||
And I log out
|
||||
And I expand "Courses" node
|
||||
And I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should see "cat3" in the "Navigation" "block"
|
||||
And I should not see "cat31" in the "Navigation" "block"
|
||||
And I should not see "cat32" in the "Navigation" "block"
|
||||
And I should not see "cat331" in the "Navigation" "block"
|
||||
And I should not see "c1" in the "Navigation" "block"
|
||||
And I should not see "c2" in the "Navigation" "block"
|
||||
And I should not see "c31" in the "Navigation" "block"
|
||||
And I should not see "c32" in the "Navigation" "block"
|
||||
When I expand "cat3" node
|
||||
And I expand "cat31" node
|
||||
And I expand "cat1" node
|
||||
Then I should see "cat1" in the "Navigation" "block"
|
||||
And I should see "cat2" in the "Navigation" "block"
|
||||
And I should see "cat3" in the "Navigation" "block"
|
||||
And I should see "cat31" in the "Navigation" "block"
|
||||
And I should see "cat32" in the "Navigation" "block"
|
||||
And I should not see "cat331" in the "Navigation" "block"
|
||||
And I should see "c1" in the "Navigation" "block"
|
||||
And I should not see "c2" in the "Navigation" "block"
|
||||
And I should see "c31" in the "Navigation" "block"
|
||||
And I should not see "c32" in the "Navigation" "block"
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
@block @block_news_items
|
||||
Feature: Latest news block displays the course latest news
|
||||
In order to be aware of the course news
|
||||
As a user
|
||||
I need to see the latest news in the main course page
|
||||
|
||||
@javascript
|
||||
Scenario: Latest course news are displayed and can be configured
|
||||
Given the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| teacher1 | Teacher | 1 | teacher1@asd.com |
|
||||
And I log in as "admin"
|
||||
And I create a course with:
|
||||
| Course full name | Course 1 |
|
||||
| Course short name | C1 |
|
||||
| News items to show | 5 |
|
||||
And I enrol "Teacher 1" user as "Teacher"
|
||||
And I log out
|
||||
And I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
When I add a new topic to "News forum" forum with:
|
||||
| Subject | Discussion One |
|
||||
| Message | Not important |
|
||||
And I add a new topic to "News forum" forum with:
|
||||
| Subject | Discussion Two |
|
||||
| Message | Not important |
|
||||
And I add a new topic to "News forum" forum with:
|
||||
| Subject | Discussion Three |
|
||||
| Message | Not important |
|
||||
And I follow "Course 1"
|
||||
Then I should see "Discussion One" in the "Latest news" "block"
|
||||
And I should see "Discussion Two" in the "Latest news" "block"
|
||||
And I should see "Discussion Three" in the "Latest news" "block"
|
||||
And I follow "Edit settings"
|
||||
And I set the following fields to these values:
|
||||
| News items to show | 2 |
|
||||
And I press "Save changes"
|
||||
And I should not see "Discussion One" in the "Latest news" "block"
|
||||
And I should see "Discussion Two" in the "Latest news" "block"
|
||||
And I should see "Discussion Three" in the "Latest news" "block"
|
||||
And I follow "Edit settings"
|
||||
And I set the following fields to these values:
|
||||
| News items to show | 0 |
|
||||
And I press "Save changes"
|
||||
And "Latest news" "block" should not exist
|
||||
@@ -62,9 +62,10 @@ class block_private_files extends block_base {
|
||||
$renderer = $this->page->get_renderer('block_private_files');
|
||||
$this->content->text = $renderer->private_files_tree();
|
||||
if (has_capability('moodle/user:manageownfiles', $this->context)) {
|
||||
$this->content->text .= $OUTPUT->single_button(new moodle_url('/user/files.php', array('returnurl'=>$PAGE->url->out())), get_string('myfilesmanage'), 'get');
|
||||
$this->content->footer = html_writer::link(
|
||||
new moodle_url('/user/files.php', array('returnurl' => $PAGE->url->out())),
|
||||
get_string('myfilesmanage') . '...');
|
||||
}
|
||||
$this->content->footer = '';
|
||||
|
||||
}
|
||||
return $this->content;
|
||||
|
||||
@@ -2,4 +2,9 @@
|
||||
.block_private_files .content table {
|
||||
table-layout: fixed;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.block_private_files .content .footer {
|
||||
padding: 10px 0 0;
|
||||
margin-top: .5em;
|
||||
}
|
||||
|
||||
@@ -83,13 +83,13 @@ class behat_blocks extends behat_base {
|
||||
public function i_open_the_blocks_action_menu($blockname) {
|
||||
|
||||
if (!$this->running_javascript()) {
|
||||
throw new DriverException('Blocks action menu not available when Javascript is disabled');
|
||||
// Action menu does not need to be open if Javascript is off.
|
||||
return;
|
||||
}
|
||||
|
||||
// If it is already opened we do nothing.
|
||||
$blocknode = $this->get_block_node($blockname);
|
||||
$classes = array_flip(explode(' ', $blocknode->getAttribute('class')));
|
||||
if (!empty($classes['action-menu-shown'])) {
|
||||
$blocknode = $this->get_text_selector_node('block', $blockname);
|
||||
if ($blocknode->hasClass('action-menu-shown')) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -97,18 +97,18 @@ class behat_blocks extends behat_base {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the DOM node of the block from <div>.
|
||||
* Clicks on Configure block for specified block. Page must be in editing mode.
|
||||
*
|
||||
* @throws ElementNotFoundException Thrown by behat_base::find
|
||||
* @param string $blockname The block name
|
||||
* @return NodeElement
|
||||
* Argument block_name may be either the name of the block or CSS class of the block.
|
||||
*
|
||||
* @Given /^I configure the "(?P<block_name_string>(?:[^"]|\\")*)" block$/
|
||||
* @param string $blockname
|
||||
*/
|
||||
protected function get_block_node($blockname) {
|
||||
|
||||
$blockname = $this->getSession()->getSelectorsHandler()->xpathLiteral($blockname);
|
||||
$xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' block ')][contains(., $blockname)]";
|
||||
|
||||
return $this->find('xpath', $xpath);
|
||||
public function i_configure_the_block($blockname) {
|
||||
// Note that since $blockname may be either block name or CSS class, we can not use the exact label of "Configure" link.
|
||||
return array(
|
||||
new Given('I open the "'.$this->escape($blockname).'" blocks action menu'),
|
||||
new Given('I click on "Configure" "link" in the "'.$this->escape($blockname).'" "block"')
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ Feature: Add and configure blocks throughout the site
|
||||
As a manager
|
||||
I need to set and configure blocks throughout the site
|
||||
|
||||
@javascript
|
||||
Scenario: Add and configure a block throughtout the site
|
||||
Given the following "courses" exists:
|
||||
| fullname | shortname | category |
|
||||
@@ -18,8 +17,7 @@ Feature: Add and configure blocks throughout the site
|
||||
And I log in as "manager1"
|
||||
And I follow "Turn editing on"
|
||||
And I add the "Comments" block
|
||||
And I open the "Comments" blocks action menu
|
||||
And I follow "Configure Comments block"
|
||||
And I configure the "Comments" block
|
||||
And I fill the moodle form with:
|
||||
| Page contexts | Display throughout the entire site |
|
||||
And I press "Save changes"
|
||||
@@ -27,8 +25,7 @@ Feature: Add and configure blocks throughout the site
|
||||
Then I should see "Comments" in the "Comments" "block"
|
||||
And I should see "Save comment" in the "Comments" "block"
|
||||
And I am on homepage
|
||||
And I open the "Comments" blocks action menu
|
||||
And I follow "Configure Comments block"
|
||||
And I configure the "Comments" block
|
||||
And I fill the moodle form with:
|
||||
| Default weight | -10 (first) |
|
||||
And I press "Save changes"
|
||||
|
||||
@@ -39,19 +39,16 @@ Feature: Block appearances
|
||||
And I follow "Course 1"
|
||||
And I follow "Turn editing on"
|
||||
And I add the "Comments" block
|
||||
And I open the "Comments" blocks action menu
|
||||
And I follow "Configure Comments block"
|
||||
And I configure the "Comments" block
|
||||
And I fill the moodle form with:
|
||||
| Display on page types | Any page |
|
||||
And I press "Save changes"
|
||||
|
||||
@javascript
|
||||
Scenario: Block settings can be modified so that a block apprears on any page
|
||||
When I follow "Test survey name"
|
||||
Then I should see "Comments" in the "Comments" "block"
|
||||
And I follow "Course 1"
|
||||
And I open the "Comments" blocks action menu
|
||||
And I follow "Configure Comments block"
|
||||
And I configure the "Comments" block
|
||||
And I fill the moodle form with:
|
||||
| Display on page types | Any course page |
|
||||
And I press "Save changes"
|
||||
@@ -59,11 +56,9 @@ Feature: Block appearances
|
||||
And I follow "Test survey name"
|
||||
And I should not see "Comments"
|
||||
|
||||
@javascript
|
||||
Scenario: Block settings can be modified so that a block can be hidden or moved
|
||||
When I follow "Test book name"
|
||||
And I open the "Comments" blocks action menu
|
||||
And I follow "Configure Comments block"
|
||||
And I configure the "Comments" block
|
||||
And I fill the moodle form with:
|
||||
| Visible | No |
|
||||
And I press "Save changes"
|
||||
@@ -72,8 +67,7 @@ Feature: Block appearances
|
||||
Then I should not see "Comments"
|
||||
And I expand "Course administration" node
|
||||
And I follow "Turn editing on"
|
||||
And I open the "Comments" blocks action menu
|
||||
And I follow "Configure Comments block"
|
||||
And I configure the "Comments" block
|
||||
And I fill the moodle form with:
|
||||
| Visible | Yes |
|
||||
| Region | Right |
|
||||
|
||||
@@ -15,7 +15,6 @@ Feature: Allowed blocks controls
|
||||
| user | course | role |
|
||||
| teacher1 | C1 | editingteacher |
|
||||
|
||||
@javascript
|
||||
Scenario: Blocks can be added with the default permissions
|
||||
Given I log in as "teacher1"
|
||||
And I follow "Course 1"
|
||||
|
||||
@@ -4,7 +4,6 @@ Feature: The context of a block can always be returned to it's original state.
|
||||
As an admin
|
||||
I need to be able to return the block to original state
|
||||
|
||||
@javascript
|
||||
Scenario: Add and configure a block to display on every page and revert back
|
||||
Given the following "courses" exists:
|
||||
| fullname | shortname | category |
|
||||
@@ -15,8 +14,7 @@ Feature: The context of a block can always be returned to it's original state.
|
||||
And I add the "Tags" block
|
||||
Then I should see "Tags" in the "Tags" "block"
|
||||
And I click on "Participants" "link" in the "//li[p/span[contains(normalize-space(string(.)), 'Current course')]]" "xpath_element"
|
||||
And I open the "Tags" blocks action menu
|
||||
And I follow "Configure Tags block"
|
||||
And I configure the "Tags" block
|
||||
And I fill the moodle form with:
|
||||
| Display on page types | Any page |
|
||||
And I press "Save changes"
|
||||
@@ -25,8 +23,7 @@ Feature: The context of a block can always be returned to it's original state.
|
||||
| Assignment name | Assignment1 |
|
||||
| Description | Description |
|
||||
And I follow "Assignment1"
|
||||
And I open the "Tags" blocks action menu
|
||||
And I follow "Configure Tags block"
|
||||
And I configure the "Tags" block
|
||||
And I fill the moodle form with:
|
||||
| Display on page types | Any assignment module page |
|
||||
And I press "Save changes"
|
||||
@@ -41,8 +38,7 @@ Feature: The context of a block can always be returned to it's original state.
|
||||
| Description | Description |
|
||||
And I follow "Assignment2"
|
||||
And I should see "Tags" in the "Tags" "block"
|
||||
And I open the "Tags" blocks action menu
|
||||
And I follow "Configure Tags block"
|
||||
And I configure the "Tags" block
|
||||
And I fill the moodle form with:
|
||||
| Display on page types | Any page |
|
||||
And I press "Save changes"
|
||||
|
||||
+20
-21
@@ -31,8 +31,12 @@ include_once('locallib.php');
|
||||
$action = required_param('action', PARAM_ALPHA);
|
||||
$id = optional_param('entryid', 0, PARAM_INT);
|
||||
$confirm = optional_param('confirm', 0, PARAM_BOOL);
|
||||
$modid = optional_param('modid', 0, PARAM_INT); // To associate the entry with a module instance
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT); // To associate the entry with a course
|
||||
$modid = optional_param('modid', 0, PARAM_INT); // To associate the entry with a module instance.
|
||||
$courseid = optional_param('courseid', 0, PARAM_INT); // To associate the entry with a course.
|
||||
|
||||
if ($action == 'edit') {
|
||||
$id = required_param('entryid', PARAM_INT);
|
||||
}
|
||||
|
||||
$PAGE->set_url('/blog/edit.php', array('action' => $action, 'entryid' => $id, 'confirm' => $confirm, 'modid' => $modid, 'courseid' => $courseid));
|
||||
|
||||
@@ -41,6 +45,20 @@ if (!empty($id) && $action == 'add') {
|
||||
$id = null;
|
||||
}
|
||||
|
||||
// Blogs are always in system context.
|
||||
$sitecontext = context_system::instance();
|
||||
$PAGE->set_context($sitecontext);
|
||||
|
||||
require_login($courseid);
|
||||
|
||||
if (empty($CFG->enableblogs)) {
|
||||
print_error('blogdisable', 'blog');
|
||||
}
|
||||
|
||||
if (isguestuser()) {
|
||||
print_error('noguestentry', 'blog');
|
||||
}
|
||||
|
||||
$returnurl = new moodle_url('/blog/index.php');
|
||||
|
||||
if (!empty($courseid) && empty($modid)) {
|
||||
@@ -54,27 +72,8 @@ if (!empty($modid)) {
|
||||
$returnurl->param('courseid', $courseid);
|
||||
}
|
||||
|
||||
// Blogs are always in system context.
|
||||
$sitecontext = context_system::instance();
|
||||
$PAGE->set_context($sitecontext);
|
||||
|
||||
|
||||
$blogheaders = blog_get_headers();
|
||||
|
||||
require_login($courseid);
|
||||
|
||||
if ($action == 'edit') {
|
||||
$id = required_param('entryid', PARAM_INT);
|
||||
}
|
||||
|
||||
if (empty($CFG->enableblogs)) {
|
||||
print_error('blogdisable', 'blog');
|
||||
}
|
||||
|
||||
if (isguestuser()) {
|
||||
print_error('noguestentry', 'blog');
|
||||
}
|
||||
|
||||
if (!has_capability('moodle/blog:create', $sitecontext) && !has_capability('moodle/blog:manageentries', $sitecontext)) {
|
||||
print_error('cannoteditentryorblog');
|
||||
}
|
||||
|
||||
@@ -79,12 +79,15 @@ if ($externalblogform->is_cancelled()){
|
||||
$newexternal->description = (empty($data->description)) ? $rss->get_description() : $data->description;
|
||||
$newexternal->userid = $USER->id;
|
||||
$newexternal->url = $data->url;
|
||||
$newexternal->filtertags = $data->filtertags;
|
||||
$newexternal->filtertags = (!empty($data->filtertags)) ? $data->filtertags : null;
|
||||
$newexternal->timemodified = time();
|
||||
|
||||
$newexternal->id = $DB->insert_record('blog_external', $newexternal);
|
||||
blog_sync_external_entries($newexternal);
|
||||
tag_set('blog_external', $newexternal->id, explode(',', $data->autotags));
|
||||
if ($CFG->usetags) {
|
||||
$autotags = (!empty($data->autotags)) ? $data->autotags : null;
|
||||
tag_set('blog_external', $newexternal->id, explode(',', $autotags));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
@@ -98,12 +101,14 @@ if ($externalblogform->is_cancelled()){
|
||||
$external->description = (empty($data->description)) ? $rss->get_description() : $data->description;
|
||||
$external->userid = $USER->id;
|
||||
$external->url = $data->url;
|
||||
$external->filtertags = $data->filtertags;
|
||||
$external->filtertags = (!empty($data->filtertags)) ? $data->filtertags : null;
|
||||
$external->timemodified = time();
|
||||
|
||||
$DB->update_record('blog_external', $external);
|
||||
tag_set('blog_external', $external->id, explode(',', $data->autotags));
|
||||
|
||||
if ($CFG->usetags) {
|
||||
$autotags = (!empty($data->autotags)) ? $data->autotags : null;
|
||||
tag_set('blog_external', $external->id, explode(',', $autotags));
|
||||
}
|
||||
} else {
|
||||
print_error('wrongexternalid', 'blog');
|
||||
}
|
||||
|
||||
@@ -118,7 +118,9 @@ class blog_edit_external_form extends moodleform {
|
||||
if ($id = $mform->getElementValue('id')) {
|
||||
$mform->setDefault('autotags', implode(',', tag_get_tags_array('blog_external', $id)));
|
||||
$mform->freeze('url');
|
||||
$mform->freeze('filtertags');
|
||||
if ($mform->elementExists('filtertags')) {
|
||||
$mform->freeze('filtertags');
|
||||
}
|
||||
// TODO change the filtertags element to a multiple select, using the tags of the external blog
|
||||
// Use $rss->get_channel_tags()
|
||||
}
|
||||
|
||||
+13
-13
@@ -34,10 +34,6 @@ foreach ($url_params as $var => $val) {
|
||||
}
|
||||
$PAGE->set_url('/blog/index.php', $url_params);
|
||||
|
||||
if (empty($CFG->enableblogs)) {
|
||||
print_error('blogdisable', 'blog');
|
||||
}
|
||||
|
||||
//correct tagid if a text tag is provided as a param
|
||||
if (!empty($tag)) {
|
||||
if ($tagrec = $DB->get_record('tag', array('name' => $tag))) {
|
||||
@@ -47,15 +43,6 @@ if (!empty($tag)) {
|
||||
}
|
||||
}
|
||||
|
||||
// add courseid if modid or groupid is specified: This is used for navigation and title
|
||||
if (!empty($modid) && empty($courseid)) {
|
||||
$courseid = $DB->get_field('course_modules', 'course', array('id'=>$modid));
|
||||
}
|
||||
|
||||
if (!empty($groupid) && empty($courseid)) {
|
||||
$courseid = $DB->get_field('groups', 'courseid', array('id'=>$groupid));
|
||||
}
|
||||
|
||||
$sitecontext = context_system::instance();
|
||||
// Blogs are always in system context.
|
||||
$PAGE->set_context($sitecontext);
|
||||
@@ -84,6 +71,19 @@ if ($CFG->bloglevel == BLOG_GLOBAL_LEVEL) {
|
||||
print_error('blogdisable', 'blog');
|
||||
}
|
||||
|
||||
if (empty($CFG->enableblogs)) {
|
||||
print_error('blogdisable', 'blog');
|
||||
}
|
||||
|
||||
// Add courseid if modid or groupid is specified: This is used for navigation and title.
|
||||
if (!empty($modid) && empty($courseid)) {
|
||||
$courseid = $DB->get_field('course_modules', 'course', array('id' => $modid));
|
||||
}
|
||||
|
||||
if (!empty($groupid) && empty($courseid)) {
|
||||
$courseid = $DB->get_field('groups', 'courseid', array('id' => $groupid));
|
||||
}
|
||||
|
||||
|
||||
if (!$userid && has_capability('moodle/blog:view', $sitecontext) && $CFG->bloglevel > BLOG_USER_LEVEL) {
|
||||
if ($entryid) {
|
||||
|
||||
+5
-3
@@ -181,9 +181,11 @@ function blog_sync_external_entries($externalblog) {
|
||||
$filtertags = array_map('trim', $filtertags);
|
||||
$filtertags = array_map('strtolower', $filtertags);
|
||||
|
||||
foreach ($categories as $category) {
|
||||
if (in_array(trim(strtolower($category->term)), $filtertags)) {
|
||||
$containsfiltertag = true;
|
||||
if (!empty($categories)) {
|
||||
foreach ($categories as $category) {
|
||||
if (in_array(trim(strtolower($category->term)), $filtertags)) {
|
||||
$containsfiltertag = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Vendored
+4
@@ -246,3 +246,7 @@ The following snippet illustates how to configure the three core cache stores th
|
||||
define('TEST_CACHESTORE_MEMCACHE_TESTSERVERS', '127.0.0.1:11211');
|
||||
define('TEST_CACHESTORE_MEMCACHED_TESTSERVERS', '127.0.0.1:11211');
|
||||
define('TEST_CACHESTORE_MONGODB_TESTSERVER', 'mongodb://localhost:27017');
|
||||
|
||||
Please be aware that if you are using Memcache or Memcached it is recommended to use dedicated Memcached servers.
|
||||
When caches get purged the memcached servers you have configured get purged, any data stored within them whether it belongs to Moodle or not will be removed.
|
||||
If you are using Memcached for sessions as well as caching/testing and caches get purged your sessions will be removed prematurely and users will be need to start again.
|
||||
|
||||
Vendored
+12
-9
@@ -52,7 +52,7 @@ $locks = cache_administration_helper::get_lock_summaries();
|
||||
|
||||
$title = new lang_string('cacheadmin', 'cache');
|
||||
$mform = null;
|
||||
$notification = null;
|
||||
$notifications = array();
|
||||
$notifysuccess = true;
|
||||
|
||||
if (!empty($action) && confirm_sesskey()) {
|
||||
@@ -110,10 +110,10 @@ if (!empty($action) && confirm_sesskey()) {
|
||||
|
||||
if (!array_key_exists($store, $stores)) {
|
||||
$notifysuccess = false;
|
||||
$notification = get_string('invalidstore', 'cache');
|
||||
$notifications[] = array(get_string('invalidstore', 'cache'), false);
|
||||
} else if ($stores[$store]['mappings'] > 0) {
|
||||
$notifysuccess = false;
|
||||
$notification = get_string('deletestorehasmappings', 'cache');
|
||||
$notifications[] = array(get_string('deletestorehasmappings', 'cache'), false);
|
||||
}
|
||||
|
||||
if ($notifysuccess) {
|
||||
@@ -250,10 +250,10 @@ if (!empty($action) && confirm_sesskey()) {
|
||||
$confirm = optional_param('confirm', false, PARAM_BOOL);
|
||||
if (!array_key_exists($lock, $locks)) {
|
||||
$notifysuccess = false;
|
||||
$notification = get_string('invalidlock', 'cache');
|
||||
$notifications[] = array(get_string('invalidlock', 'cache'), false);
|
||||
} else if ($locks[$lock]['uses'] > 0) {
|
||||
$notifysuccess = false;
|
||||
$notification = get_string('deletelockhasuses', 'cache');
|
||||
$notifications[] = array(get_string('deletelockhasuses', 'cache'), false);
|
||||
}
|
||||
if ($notifysuccess) {
|
||||
if (!$confirm) {
|
||||
@@ -280,6 +280,12 @@ if (!empty($action) && confirm_sesskey()) {
|
||||
}
|
||||
}
|
||||
|
||||
// Add cache store warnings to the list of notifications.
|
||||
// Obviously as these are warnings they are show as failures.
|
||||
foreach (cache_helper::warnings($stores) as $warning) {
|
||||
$notifications[] = array($warning, false);
|
||||
}
|
||||
|
||||
$PAGE->set_title($title);
|
||||
$PAGE->set_heading($SITE->fullname);
|
||||
/* @var core_cache_renderer $renderer */
|
||||
@@ -287,10 +293,7 @@ $renderer = $PAGE->get_renderer('core_cache');
|
||||
|
||||
echo $renderer->header();
|
||||
echo $renderer->heading($title);
|
||||
|
||||
if (!is_null($notification)) {
|
||||
echo $renderer->notification($notification, ($notifysuccess)?'notifysuccess' : 'notifyproblem');
|
||||
}
|
||||
echo $renderer->notifications($notifications);
|
||||
|
||||
if ($mform instanceof moodleform) {
|
||||
$mform->display();
|
||||
|
||||
Vendored
+26
-1
@@ -718,7 +718,8 @@ class cache_helper {
|
||||
return $stores;
|
||||
} else {
|
||||
$stores = self::get_cache_stores($definition);
|
||||
if (count($stores) === 0) {
|
||||
// If mappingsonly is set, having 0 stores is ok.
|
||||
if ((count($stores) === 0) && (!$definition->is_for_mappings_only())) {
|
||||
// No suitable stores we found for the definition. We need to come up with a sensible default.
|
||||
// If this has happened we can be sure that the user has mapped custom stores to either the
|
||||
// mode of the definition. The first alternative to try is the system default for the mode.
|
||||
@@ -734,4 +735,28 @@ class cache_helper {
|
||||
}
|
||||
return $stores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of warnings from the cache API.
|
||||
*
|
||||
* The warning returned here are for things like conflicting store instance configurations etc.
|
||||
* These get shown on the admin notifications page for example.
|
||||
*
|
||||
* @param array|null $stores An array of stores to get warnings for, or null for all.
|
||||
* @return string[]
|
||||
*/
|
||||
public static function warnings(array $stores = null) {
|
||||
global $CFG;
|
||||
if ($stores === null) {
|
||||
require_once($CFG->dirroot.'/cache/locallib.php');
|
||||
$stores = cache_administration_helper::get_store_instance_summaries();
|
||||
}
|
||||
$warnings = array();
|
||||
foreach ($stores as $store) {
|
||||
if (!empty($store['warnings'])) {
|
||||
$warnings = array_merge($warnings, $store['warnings']);
|
||||
}
|
||||
}
|
||||
return $warnings;
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+12
@@ -338,4 +338,16 @@ abstract class cache_store implements cache_store_interface {
|
||||
// Any stores that have an issue with this will need to override the create_clone method.
|
||||
return clone($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be overridden to return any warnings this store instance should make to the admin.
|
||||
*
|
||||
* This should be used to notify things like configuration conflicts etc.
|
||||
* The warnings returned here will be displayed on the cache configuration screen.
|
||||
*
|
||||
* @return string[] An array of warning strings from the store instance.
|
||||
*/
|
||||
public function get_warnings() {
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-1
@@ -709,7 +709,8 @@ abstract class cache_administration_helper extends cache_helper {
|
||||
'nativelocking' => ($store instanceof cache_is_lockable),
|
||||
'keyawareness' => ($store instanceof cache_is_key_aware),
|
||||
'searchable' => ($store instanceof cache_is_searchable)
|
||||
)
|
||||
),
|
||||
'warnings' => $store->get_warnings()
|
||||
);
|
||||
if (empty($details['default'])) {
|
||||
$return[$name] = $record;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user