Compare commits
1110 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 635ebcb9be | |||
| 33f7a8477d | |||
| 646194e013 | |||
| 425fcf36eb | |||
| 31fd05ebca | |||
| 495b4ed9e0 | |||
| 87c904cc96 | |||
| 792599a42f | |||
| 03c65c8eec | |||
| 14aeb55c14 | |||
| 7ddbc83731 | |||
| 17533c57d3 | |||
| 433668e202 | |||
| 9edcc0c903 | |||
| 7610ee5f8b | |||
| eab9be4ef7 | |||
| f747f69c62 | |||
| e48a030aab | |||
| e07985439a | |||
| 620f21d7d7 | |||
| 4a13047d5d | |||
| 446a480f21 | |||
| b56f8c8fb3 | |||
| e207b1f1e1 | |||
| 296c24f829 | |||
| c5e88ef69f | |||
| 2a7e493c74 | |||
| e14d3fd379 | |||
| fd3540f92d | |||
| fa43cfd58f | |||
| 711afe8bb7 | |||
| 23525300bb | |||
| b9d7f0c5a5 | |||
| 3d76614a78 | |||
| de0e6f3179 | |||
| 39edb9b7e2 | |||
| a638488eb7 | |||
| a2a539f7db | |||
| 6768bb4793 | |||
| 19c2841576 | |||
| 71aa248a4e | |||
| eeaef5ac5c | |||
| bea50f4562 | |||
| ff337457f8 | |||
| 8d33488923 | |||
| 32a6a49077 | |||
| b93ea7c69b | |||
| 640be73a66 | |||
| 32ae88fc81 | |||
| a4c9c3bfd9 | |||
| 182107286c | |||
| a7e939e71f | |||
| 83d05bd01c | |||
| 9fb10ea004 | |||
| c916df0d13 | |||
| 99a63a3cdb | |||
| ad52c0f033 | |||
| 6d18d32356 | |||
| 75f0f1f4ee | |||
| 425a9f6a34 | |||
| 1d5f7ae822 | |||
| 49b5ddf850 | |||
| 3f7a93e0c9 | |||
| b449b8762b | |||
| 13e555f50b | |||
| 48c809a797 | |||
| 55c7f72d8e | |||
| 8612113fc0 | |||
| 69b0c7cf09 | |||
| 72ad9f51c1 | |||
| 37a97a2e7c | |||
| 5f4eaef4a2 | |||
| 44f5c3a34f | |||
| a33ae696a2 | |||
| 2705efb809 | |||
| 20fb27f7e1 | |||
| c8e20cf64b | |||
| 648d631151 | |||
| 27c0c4d64e | |||
| 52cf559536 | |||
| c9b0362c62 | |||
| 11e5bdf556 | |||
| 3d0be3836c | |||
| 2bc33e0115 | |||
| 8576d9c67e | |||
| 3accecd504 | |||
| a0651f4383 | |||
| 9452d5fd09 | |||
| 1f40d726de | |||
| 2699611ba3 | |||
| d9121b4684 | |||
| 132ec1702c | |||
| 43795f0007 | |||
| b1fa06bfe8 | |||
| 4dc22b6ce4 | |||
| a4e3127704 | |||
| d4ab60f8af | |||
| 883277125a | |||
| 2678e23c7d | |||
| 8edfc0ffdd | |||
| ff961abaab | |||
| b2414c1ab8 | |||
| 9dde86d591 | |||
| b4ce4fbdef | |||
| 4285484c1b | |||
| 2fd299ebfc | |||
| f545f293b1 | |||
| 4dc94d1e0b | |||
| b058b1e345 | |||
| dfa1e73ddf | |||
| b745c0ae90 | |||
| f2efff5411 | |||
| 390f56a64d | |||
| 04c623f19c | |||
| 633d88c8c4 | |||
| 9ef5890636 | |||
| bc9fd04a36 | |||
| 185c5d78f1 | |||
| 3ea9963166 | |||
| ab40822a98 | |||
| dffce76e29 | |||
| d1e02f506c | |||
| 40a9da5ee0 | |||
| 5e18d13178 | |||
| 3b982b80f5 | |||
| 1cada5aeb5 | |||
| 1dfca6836d | |||
| dbbdd16bb9 | |||
| 64719586dc | |||
| 63d010f78f | |||
| e97a01c75c | |||
| 65ae43918d | |||
| 21c635f61a | |||
| 6cc747bf76 | |||
| af2693af76 | |||
| d95fc0210e | |||
| 74362fba23 | |||
| 00de509478 | |||
| 1b5139889c | |||
| 112502cf18 | |||
| d976fbe4de | |||
| 47474d31d6 | |||
| 1db7f808c9 | |||
| 762cca145f | |||
| 840a95ba62 | |||
| e18d8da872 | |||
| 65dc5eaeee | |||
| 4f81e06d3d | |||
| 6b74b75b6f | |||
| 98e53b3d74 | |||
| a1f01f9d5c | |||
| f5d8cb0275 | |||
| 0d8b65caea | |||
| 70285991bb | |||
| a336eaa4a1 | |||
| fdefe993b7 | |||
| ba0e72a1c1 | |||
| c5710277a5 | |||
| b6ec364156 | |||
| 6b07ee83eb | |||
| 5cd2d568e3 | |||
| 9c89a56d8d | |||
| 9ba7664f78 | |||
| 4b87a5c2d3 | |||
| 7e0c1fac36 | |||
| 8cdfba42d5 | |||
| e8dd56786b | |||
| 2a9309ea38 | |||
| c732ee6eb2 | |||
| ee2f2dfda0 | |||
| 9d6b38a1c1 | |||
| f0699afb6e | |||
| f6490a897a | |||
| ce8f5c167c | |||
| b4d5658d45 | |||
| d485c3da97 | |||
| 5f242aa3f6 | |||
| 1214082997 | |||
| 1a56e6693a | |||
| c6b7f20dab | |||
| 5cc55ad6e2 | |||
| a55fedab0a | |||
| ab8b0f4ebb | |||
| a57d3f7eba | |||
| f5a1e41569 | |||
| 0e12f14a4a | |||
| 3e25b71d9e | |||
| 63de9e6691 | |||
| 8c79977a23 | |||
| 52f05612ad | |||
| b9ea85d29d | |||
| c5a0da6aa5 | |||
| 266aa3423b | |||
| 7ea87638f7 | |||
| b96b372400 | |||
| fcb8f0d417 | |||
| 6e3c4854b9 | |||
| ba24deffc9 | |||
| aa7fd7bb2b | |||
| e7a6a29e59 | |||
| c43efbbfc4 | |||
| adedc9b64b | |||
| d0787e92fe | |||
| ffe9953c43 | |||
| 99a9f1ab87 | |||
| 7def26a489 | |||
| 73d77083ae | |||
| b2a1f67fb4 | |||
| 3a0d617b14 | |||
| ce0c72d9f8 | |||
| cb966ac70b | |||
| 6c40f32c2a | |||
| cce32f406f | |||
| 610ff91a9d | |||
| a76ffe8daf | |||
| 45f39158ba | |||
| d7b5d73e62 | |||
| 780a9632f0 | |||
| 603b6c73f7 | |||
| 1b66c42c9b | |||
| 5175fb5188 | |||
| b260769799 | |||
| 4495fd05c4 | |||
| 923653f2b5 | |||
| 083320002b | |||
| 3052c7311f | |||
| 3af7958940 | |||
| c7498cec03 | |||
| abe4ec6524 | |||
| e3a8b4ac78 | |||
| 365dffe2db | |||
| 259fbcb8f0 | |||
| 381157ac5d | |||
| f993e96547 | |||
| 734f75b3ad | |||
| 7ef066f396 | |||
| 23bb0e3ac3 | |||
| 2dea4a1d70 | |||
| 07bdd138cc | |||
| ee9f91b5cf | |||
| db3f21429e | |||
| 2b750843c5 | |||
| bd81507ecb | |||
| 033692d7ee | |||
| 23146cb12a | |||
| 04b9607741 | |||
| ea7fb32fb9 | |||
| 2cd64dd540 | |||
| 2a058cdbcc | |||
| 37860b4015 | |||
| 0f056b1702 | |||
| aa5588bbd3 | |||
| 0e392b398c | |||
| 5914690ad8 | |||
| 33c5c41a31 | |||
| c4aa9095f2 | |||
| 8d3c798c6c | |||
| 79ce586c8b | |||
| 8fba03c05d | |||
| 245591c31f | |||
| 8fb8fc00b4 | |||
| 50b05d25f5 | |||
| c04ee7bdc7 | |||
| 75d218d2e3 | |||
| 4efa2c9f57 | |||
| 630a44358f | |||
| f7015d521b | |||
| 860c8c1002 | |||
| a2120d1c6b | |||
| fc3f9dfeae | |||
| cf64c0243c | |||
| ca9f53738b | |||
| 8d2e466e34 | |||
| ec46d65bb4 | |||
| 164f22aa50 | |||
| cc50003e3e | |||
| 8698deb469 | |||
| 738e4f5c46 | |||
| 2fdcb9164a | |||
| 7404a1f93d | |||
| c8b8b28e9b | |||
| 5bd2571395 | |||
| c0cd157e60 | |||
| ac2f9b172c | |||
| c854ea8a35 | |||
| 9bd865d259 | |||
| b8e4a73c3b | |||
| 2d55dda662 | |||
| 63192f3a65 | |||
| 29b2458ef3 | |||
| 1e6de161e6 | |||
| 508886b1ad | |||
| 3ab0879a99 | |||
| 4baecfe833 | |||
| 727f62d418 | |||
| 68c4255a51 | |||
| 187af3e361 | |||
| c6f29a50d6 | |||
| d07212c89b | |||
| 28c55320a1 | |||
| cb0dd70434 | |||
| fd58017e97 | |||
| 928d92fce4 | |||
| 09408b898e | |||
| d1b05332c5 | |||
| 3612f18f3f | |||
| 836b0f39c2 | |||
| 1b01386673 | |||
| 2a09f02afb | |||
| ee95434cea | |||
| 86852f9815 | |||
| 9aa44c40ce | |||
| da331b7408 | |||
| caad0afed8 | |||
| 0230bedeb6 | |||
| bd6aa51397 | |||
| 9b85bc0e64 | |||
| fe08e7fc2f | |||
| 4ad96b49e7 | |||
| 9a1bb4a2dd | |||
| 2044d1b5db | |||
| 2c05eda899 | |||
| c39f902ed5 | |||
| b7dc052cb2 | |||
| 0c77114cd5 | |||
| 222a5237b0 | |||
| de55cb8392 | |||
| df164ee618 | |||
| 21b0687a57 | |||
| 9310efa280 | |||
| a41b55a9e6 | |||
| af2d8a4755 | |||
| 0852200861 | |||
| d48e339b81 | |||
| f955955ad8 | |||
| 9b6d498cf7 | |||
| 62d365573f | |||
| 9042a23de7 | |||
| b9eaaa0f29 | |||
| 04bf011fcd | |||
| f3b7a8a581 | |||
| 5d62902684 | |||
| f79d046a87 | |||
| 82d645a0f7 | |||
| a8936de638 | |||
| a765f36d24 | |||
| 737d7d6712 | |||
| 4d8ed22206 | |||
| 6b691eb461 | |||
| 046da1a8ce | |||
| ca7abd6c78 | |||
| 06dc76496d | |||
| 452688b2bb | |||
| 7cc0f2a514 | |||
| a2251fe062 | |||
| 3d0684eac0 | |||
| a8fafaa194 | |||
| 2b8a6e532e | |||
| d497659f1f | |||
| 0cafeac6eb | |||
| 4516305f3c | |||
| 04c8390a4f | |||
| 2877b7bda4 | |||
| fc94d92b37 | |||
| 84171c6b98 | |||
| c137854e01 | |||
| 3ff88bc4fa | |||
| fe9f5b224a | |||
| 45f2cc9a20 | |||
| 4b54edf660 | |||
| f1c680c7e2 | |||
| 36108df4d0 | |||
| 1bc9d1d9c3 | |||
| b5cbe63a4e | |||
| 4882df43bd | |||
| 51ad21302a | |||
| 010893a73a | |||
| cb03178d99 | |||
| 361fa8836b | |||
| 194ebb57b9 | |||
| 5effe5015e | |||
| 32e6604cf7 | |||
| b2cedf6380 | |||
| 9fc5ee897f | |||
| e8e8053063 | |||
| c635ec67d0 | |||
| 750370d148 | |||
| 2c6daa2918 | |||
| e33c877605 | |||
| ee2943b9fb | |||
| a3b03988b3 | |||
| 85e73df3c8 | |||
| a17a11d50b | |||
| 6d5f7c4293 | |||
| cc32e73235 | |||
| 92ef4d8055 | |||
| e57e2f5b5f | |||
| 0b4efe4eeb | |||
| c250fa560e | |||
| 6eeae52333 | |||
| c38c18fed8 | |||
| 0af47963c6 | |||
| b017e8690a | |||
| 916e442ee4 | |||
| ecae9c47b7 | |||
| 836a99128f | |||
| 6ead98a51d | |||
| abefbc7581 | |||
| 365addedf4 | |||
| 7cc12211e1 | |||
| f9b7e1b7fa | |||
| 44f5439a2c | |||
| 8a9680e75c | |||
| ae0991bc67 | |||
| 0caaaa500c | |||
| 36c66e676a | |||
| 33c5f3fcc7 | |||
| 47f6924ac3 | |||
| a14baeb111 | |||
| 5b4d8ed6f3 | |||
| 25ea4003f9 | |||
| 30cef671dc | |||
| 250e627b1d | |||
| 45b8daa18c | |||
| 5b00501d21 | |||
| 06e5350c43 | |||
| ba530061a0 | |||
| 89ae3bc143 | |||
| 484afccf89 | |||
| 3951f59d09 | |||
| 2589ec8367 | |||
| a6aeada197 | |||
| cd8c998ebf | |||
| 2a9e32e8fd | |||
| 603724ddd6 | |||
| 902cfc5a22 | |||
| 2cb544591b | |||
| db7aa99b85 | |||
| 031ceccf5d | |||
| 7127706c43 | |||
| d078ef8f5e | |||
| 289b9743c5 | |||
| eda9ba07f4 | |||
| 1157c11d89 | |||
| 6815092b62 | |||
| 876753cb54 | |||
| b374dcf2c2 | |||
| f7cfa507d7 | |||
| 5df0013406 | |||
| 30d08bfae1 | |||
| b0ae03b220 | |||
| ffb9849745 | |||
| cc55107da3 | |||
| 6c4ee40b96 | |||
| c637c517b8 | |||
| cdf6249a41 | |||
| d9540bcfc5 | |||
| 1b1b5c047c | |||
| fa5b9e5689 | |||
| 6948d70b75 | |||
| 3f9b022ae4 | |||
| aeb417d3d8 | |||
| bcfc7b2507 | |||
| 990ab7f87f | |||
| 861198eec9 | |||
| c26df8da6f | |||
| 7c32365bd3 | |||
| b5aefdce04 | |||
| adfb7cfaa4 | |||
| 0a88ba05c8 | |||
| bf6ba727a4 | |||
| 9ee295d49e | |||
| 1e02d85fca | |||
| 7173b44b4f | |||
| 69f6edadb3 | |||
| d1dc2331f8 | |||
| bb2f3a1732 | |||
| 4b29d7ba2e | |||
| d503deb8c5 | |||
| 0859b92aaf | |||
| b409740da5 | |||
| a888e0564c | |||
| fef96e8b43 | |||
| 429522a0bc | |||
| e9b2261aab | |||
| 02adb6e112 | |||
| 695d26434c | |||
| 00d408e6bc | |||
| 0498161367 | |||
| 63159702e3 | |||
| 545a873af2 | |||
| db268c6805 | |||
| 2967075c1f | |||
| 4761e4bd43 | |||
| a27dccd0d9 | |||
| 6b8bfc2e2d | |||
| 5b15218174 | |||
| 0d3d4693b4 | |||
| a19de645e4 | |||
| f0a53ea9c0 | |||
| fbcabc94f2 | |||
| de9a27db10 | |||
| d494b061f3 | |||
| ebc8443e70 | |||
| 48ee59b94e | |||
| 560dcad90a | |||
| 7498b2f994 | |||
| df4f92197a | |||
| 13b1191aad | |||
| adaec42982 | |||
| b6d5b7d603 | |||
| 93d7cf4dc3 | |||
| e9f2546c2a | |||
| 007c4d5862 | |||
| f3621aa743 | |||
| 46cf4398a0 | |||
| 1599f493fa | |||
| 894cfb2e85 | |||
| b5d79ebb74 | |||
| 1cc8367fa9 | |||
| 7e5087ae7d | |||
| d6f9909bec | |||
| 0c42596dc8 | |||
| 7deae8ea37 | |||
| 03aa7fd06b | |||
| 54ba547c8c | |||
| c1172b6823 | |||
| a91d531db2 | |||
| dd0d4e872f | |||
| 9b4da4c8f8 | |||
| cfc81d0e84 | |||
| 265fd6b91c | |||
| 00e10deecb | |||
| 46e67e4a92 | |||
| 520a7f238d | |||
| 3c41871e59 | |||
| 038b4300ba | |||
| 8cf9c1ba97 | |||
| 958d7940f2 | |||
| a3f7ef7002 | |||
| e2d806f5d9 | |||
| 7a47d63b48 | |||
| 596c4ac329 | |||
| 8ad8a3239a | |||
| c0fa011cc3 | |||
| 4648a8c103 | |||
| 2df05da7fc | |||
| 87947871d1 | |||
| 87fee572ff | |||
| 36eb340c11 | |||
| aa929e8091 | |||
| e00c0fc447 | |||
| 2ebfbd5d08 | |||
| 567be2aecf | |||
| 6a6ac99c34 | |||
| 7137c57ac9 | |||
| d68b4d97f6 | |||
| 89f7a3ec63 | |||
| 96a62b57fb | |||
| 7092a9ccbb | |||
| e9ea9b5e1b | |||
| fd1efb29ec | |||
| cf4781153e | |||
| 03fc0c868c | |||
| 46687429fb | |||
| ce7aa43aa7 | |||
| ebed142cd5 | |||
| dced287c1c | |||
| 76e5304233 | |||
| d162aba14a | |||
| bcd426092c | |||
| 387398b044 | |||
| 62ed7e0a53 | |||
| 635b8bd82e | |||
| f2071379fc | |||
| ec075f5807 | |||
| 566986201f | |||
| a9947cda48 | |||
| eb8875066c | |||
| dca90e6316 | |||
| 2a47b384d2 | |||
| 29e5872a0f | |||
| df31fafec5 | |||
| 5f28f279e0 | |||
| 828dc64035 | |||
| 1d9e445a42 | |||
| 271b0691e2 | |||
| cf46df441a | |||
| 1aa137e9da | |||
| 042eb47c17 | |||
| a6556d0195 | |||
| 0b74164a8e | |||
| 807b32fb0d | |||
| 62be1b1267 | |||
| aec017e933 | |||
| bda3fbc698 | |||
| 85ae7e764f | |||
| c744e47665 | |||
| 3daa624627 | |||
| 3727ef54aa | |||
| 5615f9590b | |||
| 9a7894df76 | |||
| e084ddeb41 | |||
| f8760b34b8 | |||
| 6734420c6f | |||
| fd795e14c6 | |||
| f2d105d8b9 | |||
| 9d95c04ab6 | |||
| d622f76393 | |||
| d8af1aaf7b | |||
| c93193c5c8 | |||
| 62c4713593 | |||
| d4fc82dae1 | |||
| d4058bd81f | |||
| bc824ba66a | |||
| e3ef3dfb32 | |||
| 4201286038 | |||
| 7509724e35 | |||
| e333ad2b23 | |||
| a8eeabb73d | |||
| b06620f56e | |||
| a41e32c068 | |||
| 3baf326498 | |||
| 8ea9627d51 | |||
| 957feefb2e | |||
| e8524963dd | |||
| 5b0a8c0668 | |||
| 5d931d1146 | |||
| 40b7659078 | |||
| 0427ecc7f4 | |||
| 11560a5451 | |||
| 879c77c68d | |||
| e71dd3008d | |||
| 597c888d36 | |||
| 5bef77c0fb | |||
| 89b85bcf4b | |||
| 694d252ce5 | |||
| 7efc06429c | |||
| ef4c02f759 | |||
| 452a0a43b0 | |||
| ad188fab70 | |||
| b47f9e87f1 | |||
| c3ccf3a609 | |||
| 60bbede408 | |||
| dddc308167 | |||
| 0751aff31f | |||
| a2ea20de70 | |||
| 5919dca5d5 | |||
| 3bfa1be60c | |||
| 8d38cf3c44 | |||
| a3a9ab069a | |||
| da908501e5 | |||
| 995ed22401 | |||
| c9cd4c721c | |||
| c059c14d7a | |||
| 7493426e25 | |||
| 04c9771978 | |||
| 9c8b5cd97e | |||
| 8bb447065c | |||
| 1d0299af89 | |||
| 5b8beceea8 | |||
| e4568520a9 | |||
| 1733e876c4 | |||
| cbba628eaf | |||
| c958422317 | |||
| c2d0e255df | |||
| e096890400 | |||
| 6a9277a712 | |||
| ec4b1c8f70 | |||
| 2d336fde73 | |||
| 1af904435a | |||
| ac3bec5d9e | |||
| 7da60e9937 | |||
| eba5fc84c0 | |||
| 71d8736e7e | |||
| ae1ff4c39a | |||
| f9f998e823 | |||
| e10fc26729 | |||
| 0d6999292c | |||
| 3e7681d4d2 | |||
| c838b8a381 | |||
| 96a279499b | |||
| a3f0b7a37f | |||
| ec87b951d5 | |||
| 2e033b3bb6 | |||
| d8721197b7 | |||
| 4a05b0ea31 | |||
| 7b2f03ba50 | |||
| 005d3e7d64 | |||
| 12f8638223 | |||
| 137b0754d6 | |||
| 7d1e9cfd72 | |||
| 663fc4f954 | |||
| 845595b01b | |||
| 2fca8f3444 | |||
| 9324ab8e0e | |||
| d01a39e0c6 | |||
| 73bd0137e3 | |||
| e6faf73f4f | |||
| e3f9e8c842 | |||
| 7a38726b26 | |||
| a475f72d50 | |||
| 36cadf39e9 | |||
| 9f301f8cc6 | |||
| e7c5d1f4f3 | |||
| a559ef9f90 | |||
| b45f6e0393 | |||
| 91ee948b4e | |||
| c1ed910a51 | |||
| b99ff6c981 | |||
| 81021f5821 | |||
| 29724b352b | |||
| be83302b14 | |||
| 83d7ea9ef1 | |||
| 95024442de | |||
| 69f54b5f22 | |||
| 3404f95b2e | |||
| e56738481b | |||
| cb59dc353b | |||
| d1b75eac08 | |||
| 1f7651d0e3 | |||
| 7414b3596e | |||
| a995c9557c | |||
| 55f06a7ca6 | |||
| e921dca9d6 | |||
| 9ad813d990 | |||
| 9fba3fa673 | |||
| 8fabd4e4ed | |||
| 564d92bed7 | |||
| d73dd47e7b | |||
| 95f103ccc2 | |||
| a00278892a | |||
| 196357f6c3 | |||
| 7a736344f9 | |||
| a36824e796 | |||
| 6e2dc64001 | |||
| 68d5acbe48 | |||
| a6b9ceef7b | |||
| c21b232a33 | |||
| 0ace2fdae7 | |||
| dfb2a31f26 | |||
| 5da3541584 | |||
| ef86d2f1f1 | |||
| be98425956 | |||
| 61d1f87611 | |||
| 8de579083c | |||
| 6a6b82d1e8 | |||
| 598d66ac7f | |||
| ac090c05ae | |||
| 527ef10cda | |||
| a10a6d1af8 | |||
| 7640908781 | |||
| 766cf56a3f | |||
| 73714c7cef | |||
| 0485c20331 | |||
| d104ea1b57 | |||
| 41c952a2fa | |||
| 6c09a58baf | |||
| b101e25e7a | |||
| 8d2c5029af | |||
| 8c97e367a2 | |||
| 6423914f01 | |||
| 3b25214433 | |||
| 35a8c5e980 | |||
| 64031777d8 | |||
| 102bf058bc | |||
| 7f51e01be7 | |||
| cb3ac17f43 | |||
| 8dc5092763 | |||
| 4e6bdd1fc7 | |||
| f741861014 | |||
| 5e4a23ea84 | |||
| ea54997bb7 | |||
| da4f51fe2c | |||
| fc9aa1d231 | |||
| ac43b40f33 | |||
| 77201f3805 | |||
| 81f7754a45 | |||
| 2f9360ac08 | |||
| c23be1fd96 | |||
| 1c7bb623f1 | |||
| 75de4e4e67 | |||
| ded940a757 | |||
| b80415b34e | |||
| 2ecc978591 | |||
| de13f7e361 | |||
| 319f257ee5 | |||
| 14d40697b2 | |||
| 6e6b1beffd | |||
| e22de5c9a0 | |||
| 1eea4dab33 | |||
| 0af4b3da82 | |||
| def651d98e | |||
| 83518de981 | |||
| 6d87174cc1 | |||
| 2da18d4500 | |||
| a03f5420fa | |||
| 9af9c3fe77 | |||
| 9cedf5da4c | |||
| d50396ce68 | |||
| f7d4080472 | |||
| 4ab14484ba | |||
| e24ff1b92b | |||
| 0c05cbc9db | |||
| a0f662c114 | |||
| 975d84f3d0 | |||
| c0b708b1f4 | |||
| d93ca26181 | |||
| cf8a0728d8 | |||
| ea24e43c90 | |||
| 75e747a2d2 | |||
| be398a4616 | |||
| 84bd89f00b | |||
| a1c2352dca | |||
| b6ec42334b | |||
| 56fb570267 | |||
| 510d8b9dda | |||
| d8e4895daa | |||
| c20cd907b0 | |||
| c72b4f40bd | |||
| f8d09a9ac3 | |||
| 906d675dca | |||
| 860ef73fab | |||
| ec6158792a | |||
| f1b3105202 | |||
| a399a8766d | |||
| 7f103724f3 | |||
| 3ebb213916 | |||
| 97536086c0 | |||
| 98ecf0e824 | |||
| 5fb11a77e7 | |||
| d7c72dc279 | |||
| 0853f8da85 | |||
| 32d36d66c9 | |||
| 2aef75a70a | |||
| fc21d10192 | |||
| c6bd94532d | |||
| 2c8c88e4b8 | |||
| 9f7347a4f5 | |||
| 13e5590efa | |||
| 77bffa69fd | |||
| 763f8796e0 | |||
| 3be13f57cf | |||
| a65ca205de | |||
| c8e08b8ef8 | |||
| 683d793460 | |||
| d430efa7ab | |||
| 31a5363387 | |||
| ef20f228ec | |||
| c828c6ede3 | |||
| bc08feaa08 | |||
| ef9ce720b2 | |||
| 4c3d2c10ac | |||
| 0db781b59f | |||
| c94eb4328f | |||
| 47ab187780 | |||
| 020cc54da7 | |||
| dd0a18cf5b | |||
| f726ec740a | |||
| db79b95d22 | |||
| bac2b7643f | |||
| 11449688ba | |||
| b080ebf697 | |||
| 0b0784d40c | |||
| bfb36cac7c | |||
| dd2a1207f4 | |||
| 58b3ce749e | |||
| 6c693ff7b1 | |||
| 3e1120612b | |||
| 8d06d39a62 | |||
| f64d4c9272 | |||
| b2f6620d80 | |||
| 812d38878c | |||
| da7fea47c6 | |||
| 95df864d01 | |||
| eaa36a248c | |||
| ca7fe6854b | |||
| 1be3af1e31 | |||
| b8bcb3820a | |||
| 571849f211 | |||
| c8bcbdb3e1 | |||
| 32c187f023 | |||
| dda9519e5e | |||
| 91ff702cf2 | |||
| f7f269aa79 | |||
| 71ddaf04b9 | |||
| 0d34b203d5 | |||
| 34975183d2 | |||
| 545a156942 | |||
| f9d5b28372 | |||
| 8df7812165 | |||
| d1ac2f11d1 | |||
| 5d681c18fe | |||
| a66d651c07 | |||
| e541995e01 | |||
| 6ee17dad03 | |||
| e8d924cd2c | |||
| 6e1316cb95 | |||
| f2442b25f6 | |||
| bfb8912518 | |||
| fa2ea78bda | |||
| 300d3ff09b | |||
| e6337b8f14 | |||
| 39d45ba4b0 | |||
| 2be785ace3 | |||
| 5e2d991fab | |||
| 536cb4caf1 | |||
| 27745ea141 | |||
| 5289c55740 | |||
| 791773fc8a | |||
| 1989a44d4f | |||
| 6b3de00e08 | |||
| 3179b2794b | |||
| 1da27e6c2b | |||
| bea6031de1 | |||
| 3608242b25 | |||
| 5602701645 | |||
| a909b7904e | |||
| 6e0af6827e | |||
| 51ff861e44 | |||
| aa092ab3f3 | |||
| aaaace8dd3 | |||
| 44012398bf | |||
| f18c557fb4 | |||
| 1249761ecd | |||
| db6da95421 | |||
| 8473601f03 | |||
| 8b00e72bf6 | |||
| ac2c3ff321 | |||
| 7300686f34 | |||
| 7e288f657b | |||
| ca44094a37 | |||
| c72b6d7ae5 | |||
| 99c880a4c9 | |||
| 1b1abce7da | |||
| fbc10be381 | |||
| 61f2647b62 | |||
| a5bea7fc59 | |||
| 00cf20a8d0 | |||
| b20bb7a5a2 | |||
| b9be5c2561 | |||
| 56281d64b0 | |||
| 024a4ed8d0 | |||
| 789927a043 | |||
| cc0ad0b089 | |||
| a94f3b6211 | |||
| 1340cc0b2e | |||
| c8aedb381b | |||
| a82c5c332a | |||
| 19869e6d5f | |||
| 861d4a1b22 | |||
| b722bce2ed | |||
| 0c19307fa3 | |||
| 97556de447 | |||
| bd12cb3ae5 | |||
| ceb561c113 | |||
| 14c0e9e149 | |||
| 1d6587bb6b | |||
| a2a925fd7a | |||
| 29ef529c57 | |||
| 30fe0ecaf4 | |||
| 64692e0041 | |||
| f1039a18e4 | |||
| ea805a7af8 | |||
| 350bea7798 | |||
| f9977a9fd8 | |||
| ea4f89701c | |||
| f3bfe0177d | |||
| 5dc80c55b2 | |||
| 14d5c9bee5 | |||
| 1c08921f55 | |||
| 01bd247831 | |||
| a1c39171a5 | |||
| bb430ddacd | |||
| 2fdb485203 | |||
| 1e8b82f5df | |||
| 23b6cf1c24 | |||
| c63f8bc3bd | |||
| c9d55a4a5e | |||
| 9ae962492a | |||
| d404970c74 | |||
| 66bf667100 | |||
| 65980e8c76 | |||
| a2b5b13432 | |||
| c5d1439422 | |||
| 7ffb3cfb7f | |||
| df1cfaba28 | |||
| 5e9f4559b6 | |||
| 4bbb0441a6 | |||
| 4cf1d7d9a4 | |||
| a6a3ddca75 | |||
| 27cfa85d3a | |||
| a9e1e7b634 | |||
| 09f50da821 | |||
| 9f5f920c81 | |||
| 93bdfc8915 | |||
| d91019c9fe | |||
| bc99a6f6c0 | |||
| 463c3cf1d5 | |||
| 1e1d7ce1cd | |||
| dfaebd8f5c | |||
| 0dfe8c08b9 | |||
| 0dbebaf12e | |||
| 72097c3ebc | |||
| 5d0aced9a7 | |||
| 2f00fa0791 | |||
| 0689b928c2 | |||
| 3907ea435a | |||
| 09c19512d9 | |||
| 212b86d8f6 | |||
| a86b831735 | |||
| a11d924736 | |||
| 59c844eb8f | |||
| d0c5357625 | |||
| 7aabf459ea | |||
| 309f337461 | |||
| a17759f759 | |||
| 2374a7a167 | |||
| 086a0811cb | |||
| 427fff0c53 | |||
| f9a0d91299 | |||
| 4351bd8b50 | |||
| da8dc72908 | |||
| 2c96188775 | |||
| d3f9e13eae | |||
| 82455136bb | |||
| f6e354314b | |||
| b7fedb664b | |||
| 25f91cc0da | |||
| 23141e1e8c | |||
| d5bde0d8df | |||
| cc5ca0b5fe | |||
| 0cb9cc6840 | |||
| d38d7b1ff4 | |||
| 2d87f933d5 | |||
| a734a0cff7 | |||
| d0ace55d03 | |||
| 3fda0308ac | |||
| d796b2afc1 | |||
| f95cfc2ee0 | |||
| b17dcd2b56 | |||
| 197ab6357f | |||
| e485c471cb | |||
| f00e8b4efc | |||
| d45ba48b37 | |||
| c8807c3798 | |||
| b3e3855931 | |||
| 82c2560822 | |||
| f466bc7cfb | |||
| b77521cbc5 | |||
| 58b91fe6a0 | |||
| a95fbff597 | |||
| 80ee18ee95 | |||
| f467b8cb6c | |||
| 6146a0576c | |||
| 73df3ec0de | |||
| d24e4834aa | |||
| 38593ea36c | |||
| aea1a03453 | |||
| 1568e5f19c | |||
| 8dff47db78 | |||
| 987e48733a | |||
| a95c129116 | |||
| 72ff03f142 | |||
| f4574b6014 | |||
| 2dde71abb3 | |||
| e55593fc34 | |||
| 1c6346233e | |||
| 00e316b5bd | |||
| 1b232f3214 | |||
| aa1ded5f1a | |||
| e5a20f0c1b | |||
| 9d701cabf6 | |||
| c6c522da04 | |||
| 2251f39fcf | |||
| 01b4e8d59c | |||
| bfd8e96f71 | |||
| e7b84b1637 | |||
| b8ac74a05d | |||
| 38624b1e59 | |||
| a699d9e1de | |||
| cda7a66ec8 | |||
| 36a5313336 | |||
| fedcdcfcd5 | |||
| 11964401c8 | |||
| 48202cfa09 | |||
| 8cac3e9c5c | |||
| 25c481b3ca | |||
| ac5142443a | |||
| 44360d83aa | |||
| 021cb817d4 | |||
| f4f91fba78 | |||
| dec5e8ad6c | |||
| 4321c8d24e | |||
| 6cb3fcf9ad | |||
| e5878554bd | |||
| 44c8c4b5b8 | |||
| 6b254e1a20 | |||
| a00ceb24e1 | |||
| c587632ea0 | |||
| 8f2c662f27 | |||
| dc06e303fc | |||
| dbf38fbeb8 | |||
| 97ffed5ee7 | |||
| 8b49d2d377 | |||
| 6513097d38 | |||
| d1bf2c0ad7 | |||
| 59152cbe80 | |||
| 027f76af96 | |||
| eece4c194a |
@@ -14,6 +14,7 @@ syntax: glob
|
||||
obj/
|
||||
[Rr]elease*/
|
||||
_ReSharper*/
|
||||
_NCrunch_*/
|
||||
*.ncrunchsolution
|
||||
*.ncrunchsolution.user
|
||||
*.ncrunchproject
|
||||
@@ -43,6 +44,7 @@ src\Umbraco.Web.UI\[Mm]acro[Ss]cripts\*
|
||||
src\Umbraco.Web.UI\[Xx]slt\*
|
||||
src\Umbraco.Web.UI\[Ii]mages\*
|
||||
src\Umbraco.Web.UI\[Ss]cripts\*
|
||||
src\Umbraco.Web.UI\Web.*.config.transformed
|
||||
|
||||
umbraco\presentation\umbraco\plugins\uComponents\uComponentsInstaller.ascx
|
||||
umbraco\presentation\packages\uComponents\MultiNodePicker\CustomTreeService.asmx
|
||||
|
||||
@@ -22,4 +22,10 @@ f6da531fbb4c251ff61d314e2a7effb13c71e74a Release-4.10.0
|
||||
73711b806a4044dbf0d7d7c095ddfdda23b09932 Release-4.11.2
|
||||
77db220b89e166b3c0736ed321ecfd6416cddbcd Release-4.11.2.1
|
||||
54cde33b809dcb3a1f7e7ae0d5375f6dd0d89c8d Release-4.11.2.2
|
||||
ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta
|
||||
ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta
|
||||
56015ac26f5ab60e3c61b1d09075297b660afa07 Release-6.0.0-RC
|
||||
1719fbd857f28b376639ac2aa0abada0ef2e7560 Release-6.0.0
|
||||
e02f5aebb87e3f07d27376647756caa9762931d8 Release-4.11.4
|
||||
14338b0ab1738fbd8987677ecdb9a73d79fc229d release-4.11.6
|
||||
b247b35d821144849f551e02da8ba719f91d5fb0 Release-6.0.2
|
||||
aed55cba29009ad3db48880a7cfb66407ce9805f release-6.0.3
|
||||
|
||||
+4
-2
@@ -1,6 +1,6 @@
|
||||
@ECHO OFF
|
||||
SET release=6.0.0
|
||||
SET comment=RC
|
||||
SET release=6.1.0
|
||||
SET comment=beta
|
||||
SET version=%release%
|
||||
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
@@ -16,6 +16,8 @@ echo This file is only here so that the containing folder will be included in th
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\media\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\scripts\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\usercontrols\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\Partials\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\Views\MacroPartials\dummy.txt
|
||||
echo This file is only here so that the containing folder will be included in the NuGet package, it is safe to delete. > .\_BuildOutput\WebApp\xslt\dummy.txt
|
||||
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
|
||||
+239
-152
@@ -1,189 +1,276 @@
|
||||
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
<!--
|
||||
****************************************************
|
||||
INCLUDES
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<PropertyGroup>
|
||||
<MSBuildCommunityTasksPath>..\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
|
||||
<UmbracoMSBuildTasksPath>..\UmbracoMSBuildTasks</UmbracoMSBuildTasksPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
|
||||
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
|
||||
<PropertyGroup>
|
||||
<MSBuildCommunityTasksPath>..\MSBuildCommunityTasks</MSBuildCommunityTasksPath>
|
||||
<UmbracoMSBuildTasksPath>..\UmbracoMSBuildTasks</UmbracoMSBuildTasksPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
<Import Project="..\tools\UmbracoMSBuildTasks\Umbraco.MSBuild.Tasks.Targets" />
|
||||
<Import Project="..\tools\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets" />
|
||||
|
||||
<UsingTask TaskName="GenerateHash" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
|
||||
<ParameterGroup>
|
||||
<InputFiles ParameterType="Microsoft.Build.Framework.ITaskItem[]" Required="true" />
|
||||
<OutputFile ParameterType="System.String" Required="true" />
|
||||
</ParameterGroup>
|
||||
<Task>
|
||||
<Using Namespace="System.IO" />
|
||||
<Using Namespace="System.Linq" />
|
||||
<Using Namespace="System.Security.Cryptography" />
|
||||
<Code Type="Fragment" Language="cs">
|
||||
<![CDATA[
|
||||
using (var ms = new MemoryStream())
|
||||
{
|
||||
foreach (var item in InputFiles)
|
||||
{
|
||||
string path = item.ItemSpec;
|
||||
|
||||
using (FileStream stream = new FileStream(path, FileMode.Open))
|
||||
{
|
||||
using (var cryptoProvider = new SHA1CryptoServiceProvider())
|
||||
{
|
||||
|
||||
var fileHash = cryptoProvider.ComputeHash(stream);
|
||||
|
||||
using (TextWriter w = new StreamWriter(OutputFile, false))
|
||||
{
|
||||
w.WriteLine(string.Join("", fileHash.Select(b => b.ToString("x2"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</Code>
|
||||
</Task>
|
||||
</UsingTask>
|
||||
|
||||
|
||||
<!--
|
||||
****************************************************
|
||||
VARIABLES
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<!-- NB: BUILD_NUMBER is passed in by the build server -->
|
||||
<PropertyGroup Condition="'$(BUILD_NUMBER)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_NUMBER)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_COMMENT)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_COMMENT)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BuildConfiguration>Release</BuildConfiguration>
|
||||
<BuildFolder>_BuildOutput\</BuildFolder>
|
||||
<BuildZipFileName>UmbracoCms$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileName>
|
||||
<BuildZipFileNameBin>UmbracoCms.AllBinaries$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameBin>
|
||||
<BuildZipFileNameWebPi>UmbracoCms.WebPI$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameWebPi>
|
||||
<IncludeSymbols>False</IncludeSymbols>
|
||||
<BuildFolderRelativeToProjects>..\..\build\$(BuildFolder)</BuildFolderRelativeToProjects>
|
||||
<BuildFolderAbsolutePath>$(MSBuildProjectDirectory)\$(BuildFolder)</BuildFolderAbsolutePath>
|
||||
<SolutionBinFolder>$(BuildFolder)bin\</SolutionBinFolder>
|
||||
<WebAppFolder>$(BuildFolder)WebApp\</WebAppFolder>
|
||||
<WebPiFolder>$(BuildFolder)WebPi\</WebPiFolder>
|
||||
<SolutionBinFolderRelativeToProjects>$(BuildFolderRelativeToProjects)bin\</SolutionBinFolderRelativeToProjects>
|
||||
<SolutionBinFolderAbsolutePath>$(BuildFolderAbsolutePath)bin\</SolutionBinFolderAbsolutePath>
|
||||
<WebAppFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebApp\</WebAppFolderRelativeToProjects>
|
||||
<WebAppFolderAbsolutePath>$(BuildFolderAbsolutePath)WebApp\</WebAppFolderAbsolutePath>
|
||||
<WebPiFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebPi\</WebPiFolderRelativeToProjects>
|
||||
<WebPiFolderAbsolutePath>$(BuildFolderAbsolutePath)WebPi\</WebPiFolderAbsolutePath>
|
||||
</PropertyGroup>
|
||||
<!-- NB: BUILD_NUMBER is passed in by the build server -->
|
||||
<PropertyGroup Condition="'$(BUILD_NUMBER)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_NUMBER)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(BUILD_RELEASE)'!='' AND '$(BUILD_COMMENT)'!=''">
|
||||
<DECIMAL_BUILD_NUMBER>.$(BUILD_RELEASE)-$(BUILD_COMMENT)</DECIMAL_BUILD_NUMBER>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<SystemFolders Include="$(WebAppFolder)App_Plugins" />
|
||||
<SystemFolders Include="$(WebAppFolder)App_Code" />
|
||||
<SystemFolders Include="$(WebAppFolder)App_Data" />
|
||||
<SystemFolders Include="$(WebAppFolder)media" />
|
||||
<SystemFolders Include="$(WebAppFolder)masterpages" />
|
||||
<SystemFolders Include="$(WebAppFolder)scripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)css" />
|
||||
<SystemFolders Include="$(WebAppFolder)macroScripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)xslt" />
|
||||
<SystemFolders Include="$(WebAppFolder)usercontrols" />
|
||||
<SystemFolders Include="$(WebAppFolder)Views" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<BuildConfiguration>Release</BuildConfiguration>
|
||||
<BuildFolder>_BuildOutput\</BuildFolder>
|
||||
<BuildZipFileName>UmbracoCms$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileName>
|
||||
<BuildZipFileNameBin>UmbracoCms.AllBinaries$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameBin>
|
||||
<BuildZipFileNameWebPi>UmbracoCms.WebPI$(DECIMAL_BUILD_NUMBER).zip</BuildZipFileNameWebPi>
|
||||
<IncludeSymbols>False</IncludeSymbols>
|
||||
<BuildFolderRelativeToProjects>..\..\build\$(BuildFolder)</BuildFolderRelativeToProjects>
|
||||
<BuildFolderAbsolutePath>$(MSBuildProjectDirectory)\$(BuildFolder)</BuildFolderAbsolutePath>
|
||||
<SolutionBinFolder>$(BuildFolder)bin\</SolutionBinFolder>
|
||||
<WebAppFolder>$(BuildFolder)WebApp\</WebAppFolder>
|
||||
<WebPiFolder>$(BuildFolder)WebPi\</WebPiFolder>
|
||||
<SolutionBinFolderRelativeToProjects>$(BuildFolderRelativeToProjects)bin\</SolutionBinFolderRelativeToProjects>
|
||||
<SolutionBinFolderAbsolutePath>$(BuildFolderAbsolutePath)bin\</SolutionBinFolderAbsolutePath>
|
||||
<WebAppFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebApp\</WebAppFolderRelativeToProjects>
|
||||
<WebAppFolderAbsolutePath>$(BuildFolderAbsolutePath)WebApp\</WebAppFolderAbsolutePath>
|
||||
<WebPiFolderRelativeToProjects>$(BuildFolderRelativeToProjects)WebPi\</WebPiFolderRelativeToProjects>
|
||||
<WebPiFolderAbsolutePath>$(BuildFolderAbsolutePath)WebPi\</WebPiFolderAbsolutePath>
|
||||
<ExaminePDFPath>$(BuildFolderAbsolutePath)UmbracoExamine.PDF\</ExaminePDFPath>
|
||||
<ExamineAzurePath>$(BuildFolderAbsolutePath)UmbracoExamine.Azure\</ExamineAzurePath>
|
||||
<ExaminePDFAzurePath>$(BuildFolderAbsolutePath)UmbracoExamine.PDF.Azure\</ExaminePDFAzurePath>
|
||||
</PropertyGroup>
|
||||
|
||||
<!--
|
||||
<ItemGroup>
|
||||
<SystemFolders Include="$(WebAppFolder)App_Plugins" />
|
||||
<SystemFolders Include="$(WebAppFolder)App_Code" />
|
||||
<SystemFolders Include="$(WebAppFolder)App_Data" />
|
||||
<SystemFolders Include="$(WebAppFolder)Media" />
|
||||
<SystemFolders Include="$(WebAppFolder)Masterpages" />
|
||||
<SystemFolders Include="$(WebAppFolder)Scripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)Css" />
|
||||
<SystemFolders Include="$(WebAppFolder)MacroScripts" />
|
||||
<SystemFolders Include="$(WebAppFolder)Xslt" />
|
||||
<SystemFolders Include="$(WebAppFolder)UserControls" />
|
||||
<SystemFolders Include="$(WebAppFolder)Views" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
****************************************************
|
||||
TARGETS
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<Target Name="Build" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Build finished" />
|
||||
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
|
||||
<Message Text="Build finished" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Deleting $(BuildFolder)" Importance="high" />
|
||||
<RemoveDir Directories="$(BuildFolder)" />
|
||||
<Message Text="Finished deleting $(BuildFolder)" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebPiApp" DependsOnTargets="ZipWebApp" >
|
||||
<!-- Clean folders -->
|
||||
<RemoveDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)umbraco" />
|
||||
|
||||
<!-- Copy fresh built umbraco files -->
|
||||
<Exec Command="xcopy %22$(WebAppFolderAbsolutePath)*%22 %22$(WebPiFolderAbsolutePath)umbraco%22 /S /E /Y /I" />
|
||||
|
||||
<!-- Copy Web Pi template files -->
|
||||
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
|
||||
<ItemGroup>
|
||||
<WebPiFiles Include="..\src\WebPi\**\*.*" />
|
||||
<WebPiFile Include="$(BuildZipFileNameWebPi)" />
|
||||
</ItemGroup>
|
||||
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
|
||||
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
|
||||
</Target>
|
||||
|
||||
<Copy SourceFiles="@(WebPiFiles)"
|
||||
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Deleting $(BuildFolder)" Importance="high" />
|
||||
<RemoveDir Directories="$(BuildFolder)" />
|
||||
<Message Text="Finished deleting $(BuildFolder)" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<!-- Zip the files -->
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
|
||||
<Message Text="Starting to zip to $(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
<Target Name="ZipWebPiApp" DependsOnTargets="ZipWebApp" >
|
||||
<!-- Clean folders -->
|
||||
<RemoveDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)" />
|
||||
<MakeDir Directories="$(WebPiFolder)umbraco" />
|
||||
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22" />
|
||||
|
||||
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
</Target>
|
||||
<!-- Copy fresh built umbraco files -->
|
||||
<Exec Command="xcopy %22$(WebAppFolderAbsolutePath)*%22 %22$(WebPiFolderAbsolutePath)umbraco%22 /S /E /Y /I" />
|
||||
|
||||
<Target Name="CreateSystemFolders" DependsOnTargets="CopyLibraries" Inputs="@(SystemFolders)" Outputs="%(Identity).Dummy">
|
||||
<MakeDir Directories="@(SystemFolders)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyLibraries" DependsOnTargets="OffsetTimestamps" >
|
||||
<!-- Copy SQL CE -->
|
||||
<ItemGroup>
|
||||
<SQLCE4Files
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
|
||||
<!-- Copy Web Pi template files -->
|
||||
<ItemGroup>
|
||||
<WebPiFiles Include="..\src\WebPi\**\*.*" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(WebPiFiles)"
|
||||
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
|
||||
|
||||
<!-- Zip the files -->
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
|
||||
</Target>
|
||||
|
||||
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
|
||||
<Message Text="Starting to zip to $(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameBin)%22 %22$(SolutionBinFolderAbsolutePath)*%22" />
|
||||
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileName)%22 %22$(WebAppFolderAbsolutePath)*%22" />
|
||||
|
||||
<Message Text="Finished zipping to build\$(BuildFolder)\$(buildDate)-$(BuildZipFileName)" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CreateSystemFolders" DependsOnTargets="CopyLibraries" Inputs="@(SystemFolders)" Outputs="%(Identity).Dummy">
|
||||
<MakeDir Directories="@(SystemFolders)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CopyLibraries" DependsOnTargets="OffsetTimestamps" >
|
||||
<!-- Copy SQL CE -->
|
||||
<ItemGroup>
|
||||
<SQLCE4Files
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
|
||||
/>
|
||||
</ItemGroup>
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(SolutionBinFolder)%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(SolutionBinFolder)%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
</Target>
|
||||
<Copy SourceFiles="@(SQLCE4Files)"
|
||||
DestinationFiles="@(SQLCE4Files->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
|
||||
<!-- Offset the modified timestamps on all umbraco dlls, as WebResources break if date is in the future, which, due to timezone offsets can happen. -->
|
||||
<Target Name="OffsetTimestamps" DependsOnTargets="CopyTransformedWebConfig">
|
||||
<CreateItem Include="$(BuildFolder)**\umbraco.*.dll">
|
||||
<Output TaskParameter="Include" ItemName="FilesToOffsetTimestamp" />
|
||||
</CreateItem>
|
||||
<Message Text="Starting to offset timestamps" Importance="high" />
|
||||
<Umbraco.MSBuild.Tasks.TimestampOffset Files="@(FilesToOffsetTimestamp)" Offset="-11" />
|
||||
<Message Text="Finished offsetting timestamps" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy the transformed web.config file to the root -->
|
||||
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyXmlDocumentation">
|
||||
<ItemGroup>
|
||||
<WebConfigFile Include="..\src\Umbraco.Web.UI\web.$(BuildConfiguration).Config.transformed" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(WebConfigFile)"
|
||||
DestinationFiles="$(WebAppFolder)Web.config"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy the xml documentation to the bin folder -->
|
||||
<Target Name="CopyXmlDocumentation" DependsOnTargets="CompileProjects">
|
||||
<ItemGroup>
|
||||
<XmlDocumentationFiles Include="$(SolutionBinFolder)*.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(XmlDocumentationFiles)"
|
||||
DestinationFiles="@(XmlDocumentationFiles->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Message Text="CopyXmlDocumentation" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileProjects" DependsOnTargets="SetVersionNumber">
|
||||
<Message Text="Compiling web project to build\$(BuildFolder)" Importance="high" />
|
||||
<!-- For UseWPP_CopyWebApplication=True see http://stackoverflow.com/questions/1983575/copywebapplication-with-web-config-transformations -->
|
||||
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath)" Targets="Clean;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
</Target>
|
||||
|
||||
<!-- DONE -->
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
<!-- Offset the modified timestamps on all umbraco dlls, as WebResources break if date is in the future, which, due to timezone offsets can happen. -->
|
||||
<Target Name="OffsetTimestamps" DependsOnTargets="CopyTransformedWebConfig">
|
||||
<CreateItem Include="$(BuildFolder)**\umbraco.*.dll">
|
||||
<Output TaskParameter="Include" ItemName="FilesToOffsetTimestamp" />
|
||||
</CreateItem>
|
||||
<Message Text="Starting to offset timestamps" Importance="high" />
|
||||
<Umbraco.MSBuild.Tasks.TimestampOffset Files="@(FilesToOffsetTimestamp)" Offset="-11" />
|
||||
<Message Text="Finished offsetting timestamps" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<!-- Copy the transformed web.config file to the root -->
|
||||
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyXmlDocumentation">
|
||||
<ItemGroup>
|
||||
<WebConfigFile Include="..\src\Umbraco.Web.UI\web.$(BuildConfiguration).Config.transformed" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(WebConfigFile)"
|
||||
DestinationFiles="$(WebAppFolder)Web.config"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
<!-- Copy the xml documentation to the bin folder -->
|
||||
<Target Name="CopyXmlDocumentation" DependsOnTargets="CompileProjects">
|
||||
<ItemGroup>
|
||||
<XmlDocumentationFiles Include="$(SolutionBinFolder)*.xml" />
|
||||
</ItemGroup>
|
||||
|
||||
<Copy SourceFiles="@(XmlDocumentationFiles)"
|
||||
DestinationFiles="@(XmlDocumentationFiles->'$(WebAppFolder)bin\%(RecursiveDir)%(Filename)%(Extension)')"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Message Text="CopyXmlDocumentation" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileProjects" DependsOnTargets="CompileExternalExamineProjects">
|
||||
|
||||
<Message Text="Compiling web project to build\$(BuildFolder)" Importance="high" />
|
||||
<!-- For UseWPP_CopyWebApplication=True see http://stackoverflow.com/questions/1983575/copywebapplication-with-web-config-transformations -->
|
||||
<!-- Build the Umbraco.Web.UI project -->
|
||||
<MSBuild Projects="..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);UseWPP_CopyWebApplication=True;PipelineDependsOnBuild=False;OutDir=$(SolutionBinFolderAbsolutePath);WebProjectOutputDir=$(WebAppFolderAbsolutePath)" Targets="Clean;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
|
||||
<!-- DONE -->
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileExternalExamineProjects" DependsOnTargets="SetVersionNumber">
|
||||
<Message Text="Building externally shipped examine projects" Importance="high" />
|
||||
|
||||
<!-- First remove old files from the examine builds -->
|
||||
<ItemGroup>
|
||||
<FilesToDeleteBeforeBuild Include="$(ExaminePDFPath)*;$(ExamineAzurePath)*"/>
|
||||
</ItemGroup>
|
||||
<Delete Files="@(FilesToDeleteBeforeBuild)" />
|
||||
<!--
|
||||
Build the UmbracoExamine.PDF.Azure library ... this builds the 3 projects that we want to bundle separately so no need to build each one separately .
|
||||
We'll just build this one and then manually copy the DLLs to where we want them.
|
||||
-->
|
||||
<MSBuild Projects="..\src\UmbracoExamine.PDF.Azure\UmbracoExamine.PDF.Azure.csproj" Properties="WarningLevel=0;Configuration=$(BuildConfiguration);PipelineDependsOnBuild=False;OutDir=$(ExaminePDFAzurePath);" Targets="Clean;Build;" BuildInParallel="False" ToolsVersion="4.0" UnloadProjectsOnCompletion="False">
|
||||
</MSBuild>
|
||||
<ItemGroup>
|
||||
<ExaminePDFFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.pdf;$(ExaminePDFAzurePath)**\UmbracoExamine.PDF.xml;$(ExaminePDFAzurePath)**\itextsharp.dll" />
|
||||
<ExamineAzureFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.pdb;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.xml" />
|
||||
<ExaminePDFAzureFiles Include="$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.dll;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.pdb;$(ExaminePDFAzurePath)**\UmbracoExamine.Azure.PDF.xml" />
|
||||
</ItemGroup>
|
||||
<!-- Now copy the built files to their correct deployment folders-->
|
||||
<Copy SourceFiles="@(ExaminePDFFiles)"
|
||||
DestinationFolder="$(ExaminePDFPath)"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<Copy SourceFiles="@(ExamineAzureFiles)"
|
||||
DestinationFolder="$(ExamineAzurePath)"
|
||||
OverwriteReadOnlyFiles="true"
|
||||
SkipUnchangedFiles="false" />
|
||||
<!-- Then just delete the files we don't want to ship in the UmbracoExamine.Azure.PDF folder -->
|
||||
<ItemGroup>
|
||||
<FilesToDeleteAfterBuild Include="$(ExaminePDFAzurePath)*" Exclude="$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.dll;$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.pdb;$(ExaminePDFAzurePath)UmbracoExamine.PDF.Azure.xml"/>
|
||||
</ItemGroup>
|
||||
<Delete Files="@(FilesToDeleteAfterBuild)" />
|
||||
</Target>
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
|
||||
<FileUpdate
|
||||
<FileUpdate
|
||||
Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="(\d+)\.(\d+)\.(\d+)(.(\d+))?"
|
||||
ReplacementText="$(BUILD_RELEASE)"/>
|
||||
@@ -191,5 +278,5 @@
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="CurrentComment { get { return "([a-zA-Z]+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
</Target>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -16,7 +16,7 @@
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[4.0.20710.0]" />
|
||||
<dependency id="ServiceStack.Text" version="3.9.21" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="4.0.20710.0" />
|
||||
<dependency id="Microsoft.AspNet.Mvc.FixedDisplayModes" version="1.0.0" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
@@ -68,7 +68,5 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.XmlSerializers.dll" target="lib\umbraco.XmlSerializers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="Content\bin\amd64" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="Content\bin\x86" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -15,11 +15,13 @@
|
||||
<language>en-US</language>
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="$version$" />
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\config\*.config" target="Content\config" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\amd64\**" target="Content\bin\amd64" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\x86\**" target="Content\bin\x86" />
|
||||
<file src="..\_BuildOutput\WebApp\config\*.config" target="Content\config" />
|
||||
<file src="..\_BuildOutput\WebApp\css\**" target="Content\css" />
|
||||
<file src="..\_BuildOutput\WebApp\macroScripts\**" target="Content\macroScripts" />
|
||||
<file src="..\_BuildOutput\WebApp\masterpages\**" target="Content\masterpages" />
|
||||
|
||||
@@ -21,4 +21,7 @@ if ($project) {
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
$umbracoFilesPath = Join-Path $rootPath "UmbracoFiles\*"
|
||||
Copy-Item $umbracoFilesPath $projectDestinationPath -recurse -force
|
||||
|
||||
# Open readme.txt file
|
||||
$DTE.ItemOperations.OpenFile($toolsPath + '\Readme.txt')
|
||||
}
|
||||
@@ -21,29 +21,44 @@ echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\U
|
||||
echo Removing plugin cache files
|
||||
del ..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*
|
||||
|
||||
echo Removing cache files and examine index
|
||||
del ..\src\Umbraco.Web.UI\App_Data\TEMP\*.*
|
||||
|
||||
echo Removing log files
|
||||
del ..\src\Umbraco.Web.UI\App_Data\Logs\*.*
|
||||
|
||||
echo Removing packages
|
||||
del ..\src\Umbraco.Web.UI\App_Data\packages\*.*
|
||||
|
||||
echo Removing previews
|
||||
del ..\src\Umbraco.Web.UI\App_Data\preview\*.*
|
||||
|
||||
echo Removing app code files (typically added by starterkits)
|
||||
del ..\src\Umbraco.Web.UI\App_Code\*.*
|
||||
|
||||
echo Removing xslt files
|
||||
del ..\src\Umbraco.Web.UI\Xslt\*.*
|
||||
del ..\src\Umbraco.Web.UI\xslt\*.*
|
||||
|
||||
echo Removing user control files
|
||||
del ..\src\Umbraco.Web.UI\UserControls\*.*
|
||||
|
||||
echo Removing masterpage files
|
||||
del ..\src\Umbraco.Web.UI\masterpages\*.*
|
||||
|
||||
echo Removing view files
|
||||
del ..\src\Umbraco.Web.UI\Views\*.*
|
||||
|
||||
echo Removing razor files
|
||||
del ..\src\Umbraco.Web.UI\MacroScripts\*.*
|
||||
del ..\src\Umbraco.Web.UI\macroScripts\*.*
|
||||
|
||||
echo Removing media files
|
||||
del ..\src\Umbraco.Web.UI\Media\*.*
|
||||
del ..\src\Umbraco.Web.UI\media\*.*
|
||||
|
||||
echo Removing script files
|
||||
del ..\src\Umbraco.Web.UI\Scripts\*.*
|
||||
del ..\src\Umbraco.Web.UI\scripts\*.*
|
||||
|
||||
echo Removing css files
|
||||
del ..\src\Umbraco.Web.UI\Css\*.*
|
||||
del ..\src\Umbraco.Web.UI\css\*.*
|
||||
|
||||
echo "Umbraco install reverted to clean install"
|
||||
pause
|
||||
@@ -64,29 +79,44 @@ echo ^<?xml version="1.0" encoding="utf-8"?^>^<packages^>^</packages^> >..\src\U
|
||||
echo Removing plugin cache files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\PluginCache\*.*) DO DEL %%A
|
||||
|
||||
echo Removing cache files and examine index
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\TEMP\*.*) DO DEL %%A
|
||||
|
||||
echo Removing log files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\Logs\*.*) DO DEL %%A
|
||||
|
||||
echo Removing packages
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\packages\*.*) DO DEL %%A
|
||||
|
||||
echo Removing previews
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Data\preview\*.*) DO DEL %%A
|
||||
|
||||
echo Removing app code files (typically added by starterkits)
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\App_Code\*.*) DO DEL %%A
|
||||
|
||||
echo Removing xslt files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Xslt\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\xslt\*.*) DO DEL %%A
|
||||
|
||||
echo Removing masterpage files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\masterpages\*.*) DO DEL %%A
|
||||
|
||||
echo Removing user control files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\UserControls\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\usercontrols\*.*) DO DEL %%A
|
||||
|
||||
echo Removing view files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Views\*.*) DO DEL %%A
|
||||
|
||||
echo Removing razor files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\MacroScripts\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\macroScripts\*.*) DO DEL %%A
|
||||
|
||||
echo Removing media files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Media\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\media\*.*) DO DEL %%A
|
||||
|
||||
echo Removing script files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Scripts\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\scripts\*.*) DO DEL %%A
|
||||
|
||||
echo Removing css files
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\Css\*.*) DO DEL %%A
|
||||
FOR %%A IN (..\src\Umbraco.Web.UI\css\*.*) DO DEL %%A
|
||||
|
||||
echo "Umbraco install reverted to clean install"
|
||||
pause
|
||||
|
||||
@@ -50,35 +50,90 @@ namespace SqlCE4Umbraco
|
||||
/// </summary>
|
||||
internal void ClearDatabase()
|
||||
{
|
||||
// drop constraints before tables to avoid exceptions
|
||||
// looping on try/catching exceptions was not really nice
|
||||
|
||||
// http://stackoverflow.com/questions/536350/drop-all-the-tables-stored-procedures-triggers-constriants-and-all-the-depend
|
||||
|
||||
var localConnection = new SqlCeConnection(ConnectionString);
|
||||
if (System.IO.File.Exists(ReplaceDataDirectory(localConnection.Database)))
|
||||
{
|
||||
var tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.tables where TABLE_TYPE <> 'VIEW'"))
|
||||
List<string> tables;
|
||||
|
||||
// drop foreign keys
|
||||
// SQL may need "where constraint_catalog=DB_NAME() and ..."
|
||||
tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' order by table_name"))
|
||||
{
|
||||
while (reader.Read())
|
||||
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
|
||||
}
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name"))
|
||||
{
|
||||
tables.Add(reader.GetString("TABLE_NAME"));
|
||||
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
|
||||
}
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
// SQL may need "[dbo].[table]"
|
||||
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
while(tables.Any())
|
||||
// drop primary keys
|
||||
// SQL may need "where constraint_catalog=DB_NAME() and ..."
|
||||
tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' order by table_name"))
|
||||
{
|
||||
for (var i = 0; i < tables.Count; i++)
|
||||
{
|
||||
var dropTable = "DROP TABLE " + tables[i];
|
||||
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ExecuteNonQuery(dropTable);
|
||||
tables.Remove(tables[i]);
|
||||
}
|
||||
catch (SqlHelperException ex)
|
||||
{
|
||||
//this will occur because there is no cascade option, so we just wanna try the next one
|
||||
}
|
||||
foreach (var table in tables)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'PRIMARY KEY' and table_name = '" + table + "' order by constraint_name"))
|
||||
{
|
||||
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
|
||||
}
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
// SQL may need "[dbo].[table]"
|
||||
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
// drop tables
|
||||
tables = new List<string>();
|
||||
using (var reader = ExecuteReader("select table_name from information_schema.tables where table_type <> 'VIEW' order by table_name"))
|
||||
{
|
||||
while (reader.Read()) tables.Add(reader.GetString("table_name").Trim());
|
||||
}
|
||||
|
||||
foreach (var table in tables)
|
||||
{
|
||||
ExecuteNonQuery("drop table [" + table + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Drops all foreign keys on a table.
|
||||
/// </summary>
|
||||
/// <param name="table">The name of the table.</param>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal void DropForeignKeys(string table)
|
||||
{
|
||||
var constraints = new List<string>();
|
||||
using (var reader = ExecuteReader("select constraint_name from information_schema.table_constraints where constraint_type = 'FOREIGN KEY' and table_name = '" + table + "' order by constraint_name"))
|
||||
{
|
||||
while (reader.Read()) constraints.Add(reader.GetString("constraint_name").Trim());
|
||||
}
|
||||
foreach (var constraint in constraints)
|
||||
{
|
||||
// SQL may need "[dbo].[table]"
|
||||
ExecuteNonQuery("alter table [" + table + "] drop constraint [" + constraint + "]");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +149,9 @@ namespace SqlCE4Umbraco
|
||||
var dataDirectory = AppDomain.CurrentDomain.GetData("DataDirectory") as string;
|
||||
if (!string.IsNullOrEmpty(dataDirectory))
|
||||
{
|
||||
path = path.Replace("|DataDirectory|", dataDirectory + System.IO.Path.DirectorySeparatorChar);
|
||||
path = path.Contains(@"|\")
|
||||
? path.Replace("|DataDirectory|", dataDirectory)
|
||||
: path.Replace("|DataDirectory|", dataDirectory + System.IO.Path.DirectorySeparatorChar);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,14 +9,14 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// A resolver to return all IAction objects
|
||||
/// </summary>
|
||||
internal sealed class ActionsResolver : ManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
internal sealed class ActionsResolver : LazyManyObjectsResolverBase<ActionsResolver, IAction>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal ActionsResolver(IEnumerable<Type> packageActions)
|
||||
internal ActionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions)
|
||||
{
|
||||
|
||||
@@ -34,9 +34,9 @@ namespace Umbraco.Core
|
||||
}
|
||||
|
||||
protected override IEnumerable<IAction> CreateInstances()
|
||||
{
|
||||
{
|
||||
var actions = new List<IAction>();
|
||||
var foundIActions = PluginManager.Current.ResolveActions();
|
||||
var foundIActions = InstanceTypes;
|
||||
foreach (var type in foundIActions)
|
||||
{
|
||||
IAction typeInstance;
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
|
||||
@@ -15,33 +18,53 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// one per AppDomain, represents the global Umbraco application
|
||||
/// </remarks>
|
||||
public class ApplicationContext
|
||||
public class ApplicationContext : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
internal ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
:this()
|
||||
: this(dbContext, serviceContext, true)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <param name="enableCache"></param>
|
||||
internal ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, bool enableCache)
|
||||
: this(enableCache)
|
||||
{
|
||||
if (dbContext == null) throw new ArgumentNullException("dbContext");
|
||||
if (serviceContext == null) throw new ArgumentNullException("serviceContext");
|
||||
|
||||
_databaseContext = dbContext;
|
||||
_services = serviceContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Empty constructor normally reserved for unit tests when a DatabaseContext or a ServiceContext is not
|
||||
/// necessarily required or needs to be set after construction.
|
||||
/// </summary>
|
||||
internal ApplicationContext()
|
||||
{
|
||||
//create a new application cache from the HttpRuntime.Cache
|
||||
ApplicationCache = HttpRuntime.Cache == null
|
||||
? new CacheHelper(new Cache())
|
||||
: new CacheHelper(HttpRuntime.Cache);
|
||||
internal ApplicationContext() : this(true)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor used to specify if we will enable application cache or not
|
||||
/// </summary>
|
||||
/// <param name="enableCache"></param>
|
||||
internal ApplicationContext(bool enableCache)
|
||||
{
|
||||
//create a new application cache from the HttpRuntime.Cache
|
||||
ApplicationCache = HttpRuntime.Cache == null
|
||||
? new CacheHelper(new System.Web.Caching.Cache(), enableCache)
|
||||
: new CacheHelper(HttpRuntime.Cache, enableCache);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Singleton accessor
|
||||
/// </summary>
|
||||
@@ -186,5 +209,54 @@ namespace Umbraco.Core
|
||||
}
|
||||
internal set { _services = value; }
|
||||
}
|
||||
|
||||
|
||||
private volatile bool _disposed;
|
||||
private readonly ReaderWriterLockSlim _disposalLocker = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// This will dispose and reset all resources used to run the application
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// IMPORTANT: Never dispose this object if you require the Umbraco application to run, disposing this object
|
||||
/// is generally used for unit testing and when your application is shutting down after you have booted Umbraco.
|
||||
/// </remarks>
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
// Only operate if we haven't already disposed
|
||||
if (_disposed) return;
|
||||
|
||||
using (new WriteLock(_disposalLocker))
|
||||
{
|
||||
// Check again now we're inside the lock
|
||||
if (_disposed) return;
|
||||
|
||||
//clear the cache
|
||||
if (ApplicationCache != null)
|
||||
{
|
||||
ApplicationCache.ClearAllCache();
|
||||
}
|
||||
//reset all resolvers
|
||||
ResolverCollection.ResetAll();
|
||||
//reset resolution itself (though this should be taken care of by resetting any of the resolvers above)
|
||||
Resolution.Reset();
|
||||
|
||||
//reset the instance objects
|
||||
this.ApplicationCache = null;
|
||||
if (_databaseContext != null) //need to check the internal field here
|
||||
{
|
||||
if (DatabaseContext.Database != null)
|
||||
{
|
||||
DatabaseContext.Database.Dispose();
|
||||
}
|
||||
}
|
||||
this.DatabaseContext = null;
|
||||
this.Services = null;
|
||||
this._isReady = false; //set the internal field
|
||||
|
||||
// Indicate that the instance has been disposed.
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A plugin type that allows developers to execute code during the Umbraco bootup process
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Allows you to override the methods that you would like to execute code for: ApplicationInitialized, ApplicationStarting, ApplicationStarted.
|
||||
///
|
||||
/// By default none of these methods will execute if the Umbraco application is not configured or if the Umbraco database is not configured, however
|
||||
/// if you need these methods to execute even if either of these are not configured you can override the properties:
|
||||
/// ExecuteWhenApplicationNotConfigured and ExecuteWhenDatabaseNotConfigured
|
||||
/// </remarks>
|
||||
public abstract class ApplicationEventHandler : IApplicationEventHandler
|
||||
{
|
||||
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationInitialized(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationStarting(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
if (ShouldExecute(applicationContext))
|
||||
{
|
||||
ApplicationStarted(umbracoApplication, applicationContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable method to execute when the ApplicationContext is created and other static objects that require initialization have been setup
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected virtual void ApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OVerridable method to execute when All resolvers have been initialized but resolution is not frozen so they can be modified in this method
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected virtual void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridable method to execute when Bootup is completed, this allows you to perform any other bootup logic required for the application.
|
||||
/// Resolution is frozen so now they can be used to resolve instances.
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
protected virtual void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determine if the methods should execute based on the configuration status of the application.
|
||||
/// </summary>
|
||||
/// <param name="applicationContext"></param>
|
||||
/// <returns></returns>
|
||||
private bool ShouldExecute(ApplicationContext applicationContext)
|
||||
{
|
||||
if (applicationContext.IsConfigured && applicationContext.DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!applicationContext.IsConfigured && ExecuteWhenApplicationNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!applicationContext.DatabaseContext.IsDatabaseConfigured && ExecuteWhenDatabaseNotConfigured)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag to determine if the overridable methods for this class will execute even if the
|
||||
/// Umbraco application is not configured
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// An Umbraco Application is not configured when it requires a new install or upgrade. When the latest version in the
|
||||
/// assembly does not match the version in the config.
|
||||
/// </remarks>
|
||||
protected virtual bool ExecuteWhenApplicationNotConfigured
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A flag to determine if the overridable methods for this class will execute even if the
|
||||
/// Umbraco database is not configured
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The Umbraco database is not configured when we cannot connect to the database or when the database tables are not installed.
|
||||
/// </remarks>
|
||||
protected virtual bool ExecuteWhenDatabaseNotConfigured
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constants storing cache keys used in caching
|
||||
/// </summary>
|
||||
public static class CacheKeys
|
||||
{
|
||||
public const string ApplicationTreeCacheKey = "ApplicationTreeCache";
|
||||
public const string ApplicationsCacheKey = "ApplicationCache";
|
||||
|
||||
public const string UserTypeCacheKey = "UserTypeCache";
|
||||
|
||||
public const string ContentItemCacheKey = "contentItem";
|
||||
|
||||
public const string MediaCacheKey = "UL_GetMedia";
|
||||
|
||||
public const string MacroXsltCacheKey = "macroXslt_";
|
||||
public const string MacroCacheKey = "UmbracoMacroCache";
|
||||
public const string MacroHtmlCacheKey = "macroHtml_";
|
||||
public const string MacroControlCacheKey = "macroControl_";
|
||||
public const string MacroHtmlDateAddedCacheKey = "macroHtml_DateAdded_";
|
||||
public const string MacroControlDateAddedCacheKey = "macroControl_DateAdded_";
|
||||
|
||||
public const string MemberLibraryCacheKey = "UL_GetMember";
|
||||
public const string MemberBusinessLogicCacheKey = "MemberCacheItem_";
|
||||
|
||||
public const string TemplateFrontEndCacheKey = "template";
|
||||
public const string TemplateBusinessLogicCacheKey = "UmbracoTemplateCache";
|
||||
|
||||
public const string UserContextCacheKey = "UmbracoUserContext";
|
||||
public const string UserContextTimeoutCacheKey = "UmbracoUserContextTimeout";
|
||||
public const string UserCacheKey = "UmbracoUser";
|
||||
|
||||
public const string ContentTypeCacheKey = "UmbracoContentType";
|
||||
|
||||
public const string ContentTypePropertiesCacheKey = "ContentType_PropertyTypes_Content:";
|
||||
|
||||
public const string PropertyTypeCacheKey = "UmbracoPropertyTypeCache";
|
||||
|
||||
public const string LanguageCacheKey = "UmbracoLanguageCache";
|
||||
|
||||
public const string DomainCacheKey = "UmbracoDomainList";
|
||||
|
||||
public const string StylesheetCacheKey = "UmbracoStylesheet";
|
||||
public const string StylesheetPropertyCacheKey = "UmbracoStylesheetProperty";
|
||||
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Web.Caching;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// An abstract class for implementing a cache helper
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// THIS MUST REMAIN INTERNAL UNTIL WE STREAMLINE HOW ALL CACHE IS HANDLED, WE NEED TO SUPPORT HTTP RUNTIME CACHE, IN MEMORY CACHE, ETC...
|
||||
/// </remarks>
|
||||
internal abstract class CacheProviderBase
|
||||
{
|
||||
public abstract void ClearAllCache();
|
||||
public abstract void ClearCacheItem(string key);
|
||||
public abstract void ClearCacheObjectTypes(string typeName);
|
||||
public abstract void ClearCacheObjectTypes<T>();
|
||||
public abstract void ClearCacheByKeySearch(string keyStartsWith);
|
||||
public abstract void ClearCacheByKeyExpression(string regexString);
|
||||
public abstract IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith);
|
||||
public abstract T GetCacheItem<T>(string cacheKey);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
public abstract void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for cache refreshers to inherit from that ensures the correct events are raised
|
||||
/// when cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
public abstract class CacheRefresherBase<TInstanceType> : ICacheRefresher
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
/// <summary>
|
||||
/// An event that is raised when cache is updated on an individual server
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This event will fire on each server configured for an Umbraco project whenever a cache refresher
|
||||
/// is updated.
|
||||
/// </remarks>
|
||||
public static event TypedEventHandler<TInstanceType, CacheRefresherEventArgs> CacheUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Raises the event
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="args"></param>
|
||||
protected static void OnCacheUpdated(TInstanceType sender, CacheRefresherEventArgs args)
|
||||
{
|
||||
if (CacheUpdated != null)
|
||||
{
|
||||
CacheUpdated(sender, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the real instance of the object ('this') for use in strongly typed events
|
||||
/// </summary>
|
||||
protected abstract TInstanceType Instance { get; }
|
||||
|
||||
public abstract Guid UniqueIdentifier { get; }
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public virtual void RefreshAll()
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(null, MessageType.RefreshAll));
|
||||
}
|
||||
|
||||
public virtual void Refresh(int id)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById));
|
||||
}
|
||||
|
||||
public virtual void Remove(int id)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RemoveById));
|
||||
}
|
||||
|
||||
public virtual void Refresh(Guid id)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(id, MessageType.RefreshById));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Umbraco.Core.Sync;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Event args for cache refresher updates
|
||||
/// </summary>
|
||||
public class CacheRefresherEventArgs : EventArgs
|
||||
{
|
||||
public CacheRefresherEventArgs(object msgObject, MessageType type)
|
||||
{
|
||||
MessageType = type;
|
||||
MessageObject = msgObject;
|
||||
}
|
||||
public object MessageObject { get; private set; }
|
||||
public MessageType MessageType { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A CacheProvider that wraps the logic of the HttpRuntime.Cache
|
||||
/// </summary>
|
||||
internal class HttpRuntimeCacheProvider : CacheProviderBase
|
||||
{
|
||||
private readonly System.Web.Caching.Cache _cache;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
public HttpRuntimeCacheProvider(System.Web.Caching.Cache cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears everything in umbraco's runtime cache, which means that not only
|
||||
/// umbraco content is removed, but also other cache items from pages running in
|
||||
/// the same application / website. Use with care :-)
|
||||
/// </summary>
|
||||
public override void ClearAllCache()
|
||||
{
|
||||
var cacheEnumerator = _cache.GetEnumerator();
|
||||
while (cacheEnumerator.MoveNext())
|
||||
{
|
||||
_cache.Remove(cacheEnumerator.Key.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache with the given key
|
||||
/// </summary>
|
||||
/// <param name="key">Key</param>
|
||||
public override void ClearCacheItem(string key)
|
||||
{
|
||||
// NH 10 jan 2012
|
||||
// Patch by the always wonderful Stéphane Gay to avoid cache null refs
|
||||
lock (Locker)
|
||||
{
|
||||
if (_cache[key] == null) return;
|
||||
_cache.Remove(key); ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type name as the
|
||||
/// input parameter. (using [object].GetType())
|
||||
/// </summary>
|
||||
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
|
||||
public override void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (_cache[c.Key.ToString()] != null
|
||||
&& _cache[c.Key.ToString()].GetType().ToString().InvariantEquals(typeName))
|
||||
{
|
||||
_cache.Remove(c.Key.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<CacheHelper>("Cache clearing error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type specified
|
||||
/// </summary>
|
||||
public override void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (_cache[c.Key.ToString()] != null
|
||||
&& _cache[c.Key.ToString()].GetType() == typeof(T))
|
||||
{
|
||||
_cache.Remove(c.Key.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LogHelper.Error<CacheHelper>("Cache clearing error", e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that starts with the key passed.
|
||||
/// </summary>
|
||||
/// <param name="keyStartsWith">The start of the key</param>
|
||||
public override void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (c.Key is string && ((string)c.Key).InvariantStartsWith(keyStartsWith))
|
||||
{
|
||||
ClearCacheItem((string)c.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that have a key that matches the regular expression
|
||||
/// </summary>
|
||||
/// <param name="regexString"></param>
|
||||
public override void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
foreach (DictionaryEntry c in _cache)
|
||||
{
|
||||
if (c.Key is string && Regex.IsMatch(((string)c.Key), regexString))
|
||||
{
|
||||
ClearCacheItem((string)c.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return (from DictionaryEntry c in _cache
|
||||
where c.Key is string && ((string)c.Key).InvariantStartsWith(keyStartsWith)
|
||||
select c.Value.TryConvertTo<T>()
|
||||
into attempt
|
||||
where attempt.Success
|
||||
select attempt.Result).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
var result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
return default(TT);
|
||||
}
|
||||
return result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, CacheItemPriority.Normal, null, null, null, getCacheItem, Locker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan? timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, null, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan? timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, CacheItemPriority.Normal, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, null, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public override TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem, Locker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <param name="syncLock"></param>
|
||||
/// <returns></returns>
|
||||
private TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency, TimeSpan? timeout, Func<TT> getCacheItem, object syncLock)
|
||||
{
|
||||
var result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
lock (syncLock)
|
||||
{
|
||||
result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
result = getCacheItem();
|
||||
if (result != null)
|
||||
{
|
||||
//we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it.
|
||||
_cache.Insert(cacheKey, result, cacheDependency,
|
||||
timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value),
|
||||
TimeSpan.Zero, priority, refreshAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.TryConvertTo<TT>().Result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
InsertCacheItem(cacheKey, priority, null, null, null, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
InsertCacheItem(cacheKey, priority, null, null, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
InsertCacheItem(cacheKey, priority, null, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public override void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
object result = getCacheItem();
|
||||
if (result != null)
|
||||
{
|
||||
//we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it.
|
||||
_cache.Insert(cacheKey, result, cacheDependency,
|
||||
timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value),
|
||||
TimeSpan.Zero, priority, refreshAction);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly type cache refresher that is able to refresh cache of real instances of objects as well as IDs
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// This is much better for performance when we're not running in a load balanced environment so we can refresh the cache
|
||||
/// against a already resolved object instead of looking the object back up by id.
|
||||
/// </remarks>
|
||||
interface ICacheRefresher<T> : ICacheRefresher
|
||||
{
|
||||
void Refresh(T instance);
|
||||
void Remove(T instance);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A cache refresher that supports refreshing or removing cache based on a custom Json payload
|
||||
/// </summary>
|
||||
interface IJsonCacheRefresher : ICacheRefresher
|
||||
{
|
||||
/// <summary>
|
||||
/// Refreshes, clears, etc... any cache based on the information provided in the json
|
||||
/// </summary>
|
||||
/// <param name="jsonPayload"></param>
|
||||
void Refresh(string jsonPayload);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for json cache refreshers that ensures the correct events are raised when
|
||||
/// cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
public abstract class JsonCacheRefresherBase<TInstanceType> : CacheRefresherBase<TInstanceType>, IJsonCacheRefresher
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
|
||||
public virtual void Refresh(string jsonPayload)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(jsonPayload, MessageType.RefreshByJson));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Caching;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
internal class NullCacheProvider : CacheProviderBase
|
||||
{
|
||||
public override void ClearAllCache()
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheItem(string key)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
}
|
||||
|
||||
public override void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return Enumerable.Empty<T>();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey)
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override T GetCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
return getCacheItem();
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
|
||||
public override void InsertCacheItem<T>(string cacheKey, CacheItemPriority priority, CacheItemRemovedCallback refreshAction, CacheDependency cacheDependency, TimeSpan? timeout, Func<T> getCacheItem)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
using Umbraco.Core.Sync;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for cache refreshers to inherit from that ensures the correct events are raised
|
||||
/// when cache refreshing occurs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TInstanceType">The real cache refresher type, this is used for raising strongly typed events</typeparam>
|
||||
/// <typeparam name="TEntityType">The entity type that this refresher can update cache for</typeparam>
|
||||
public abstract class TypedCacheRefresherBase<TInstanceType, TEntityType> : CacheRefresherBase<TInstanceType>, ICacheRefresher<TEntityType>
|
||||
where TInstanceType : ICacheRefresher
|
||||
{
|
||||
public virtual void Refresh(TEntityType instance)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(instance, MessageType.RefreshByInstance));
|
||||
}
|
||||
|
||||
public virtual void Remove(TEntityType instance)
|
||||
{
|
||||
OnCacheUpdated(Instance, new CacheRefresherEventArgs(instance, MessageType.RemoveByInstance));
|
||||
}
|
||||
}
|
||||
}
|
||||
+311
-77
@@ -3,8 +3,10 @@ using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -16,29 +18,33 @@ namespace Umbraco.Core
|
||||
/// <remarks>
|
||||
/// This class may be opened publicly at some point but needs a review of what is absoletely necessary.
|
||||
/// </remarks>
|
||||
public class CacheHelper
|
||||
public class CacheHelper //: CacheProviderBase
|
||||
{
|
||||
private readonly Cache _cache;
|
||||
private readonly bool _enableCache;
|
||||
private readonly HttpRuntimeCacheProvider _httpCache;
|
||||
private readonly NullCacheProvider _nullCache = new NullCacheProvider();
|
||||
|
||||
public CacheHelper(System.Web.Caching.Cache cache)
|
||||
: this(cache, true)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Clears everything in umbraco's runtime cache, which means that not only
|
||||
/// umbraco content is removed, but also other cache items from pages running in
|
||||
/// the same application / website. Use with care :-)
|
||||
/// </summary>
|
||||
internal CacheHelper(System.Web.Caching.Cache cache, bool enableCache)
|
||||
{
|
||||
_httpCache = new HttpRuntimeCacheProvider(cache);
|
||||
_enableCache = enableCache;
|
||||
}
|
||||
|
||||
public void ClearAllCache()
|
||||
{
|
||||
var cacheEnumerator = _cache.GetEnumerator();
|
||||
while (cacheEnumerator.MoveNext())
|
||||
{
|
||||
_cache.Remove(cacheEnumerator.Key.ToString());
|
||||
}
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearAllCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearAllCache();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,12 +53,13 @@ namespace Umbraco.Core
|
||||
/// <param name="key">Key</param>
|
||||
public void ClearCacheItem(string key)
|
||||
{
|
||||
// NH 10 jan 2012
|
||||
// Patch by the always wonderful Stéphane Gay to avoid cache null refs
|
||||
lock (Locker)
|
||||
if (!_enableCache)
|
||||
{
|
||||
if (_cache[key] == null) return;
|
||||
_cache.Remove(key);;
|
||||
_nullCache.ClearCacheItem(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheItem(key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,54 +71,191 @@ namespace Umbraco.Core
|
||||
/// <param name="typeName">The name of the System.Type which should be cleared from cache ex "System.Xml.XmlDocument"</param>
|
||||
public void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
try
|
||||
if (!_enableCache)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
foreach (var c in from DictionaryEntry c in _cache where _cache[c.Key.ToString()] != null && _cache[c.Key.ToString()].GetType().ToString() == typeName select c)
|
||||
{
|
||||
_cache.Remove(c.Key.ToString());
|
||||
}
|
||||
}
|
||||
_nullCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
LogHelper.Error<CacheHelper>("Cache clearing error", e);
|
||||
_httpCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all objects in the System.Web.Cache with the System.Type specified
|
||||
/// </summary>
|
||||
public void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that starts with the key passed.
|
||||
/// </summary>
|
||||
/// <param name="keyStartsWith">The start of the key</param>
|
||||
public void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all cache items that have a key that matches the regular expression
|
||||
/// </summary>
|
||||
/// <param name="regexString"></param>
|
||||
public void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
foreach (var c in from DictionaryEntry c in _cache where c.Key is string && ((string)c.Key).StartsWith(keyStartsWith) select c)
|
||||
{
|
||||
ClearCacheItem((string)c.Key);
|
||||
}
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a cache item by key, does not update the cache if it isn't there.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with all of the default parameters
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, null, timeout, getCacheItem);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, CacheItemPriority.Normal, refreshAction, timeout, getCacheItem);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, null, timeout, getCacheItem);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache with the specified absolute expiration date (from NOW)
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
@@ -119,46 +263,136 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return GetCacheItem(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem, Locker);
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used only for legacy purposes as I did not want to change all of the locking to one lock found on this object,
|
||||
/// however, the reason this is used for legacy purposes is because I see zero reason to use different sync locks, just the one
|
||||
/// lock (Locker) on this class should be sufficient.
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <param name="syncLock"></param>
|
||||
/// <returns></returns>
|
||||
internal TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency, TimeSpan timeout, Func<TT> getCacheItem, object syncLock)
|
||||
{
|
||||
var result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
lock (syncLock)
|
||||
{
|
||||
result = _cache.Get(cacheKey);
|
||||
if (result == null)
|
||||
{
|
||||
result = getCacheItem();
|
||||
if (result != null)
|
||||
{
|
||||
//we use Insert instead of add if for some crazy reason there is now a cache with the cache key in there, it will just overwrite it.
|
||||
_cache.Insert(cacheKey, result, cacheDependency, DateTime.Now.Add(timeout), TimeSpan.Zero, priority, refreshAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return (TT)result;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets (and adds if necessary) an item from the cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TT"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
/// <returns></returns>
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
return _nullCache.GetCacheItem<TT>(cacheKey, priority, null, cacheDependency, null, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
return _httpCache.GetCacheItem<TT>(cacheKey, priority, null, cacheDependency, null, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inserts an item into the cache, if it already exists in the cache it will be replaced
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="priority"></param>
|
||||
/// <param name="refreshAction"></param>
|
||||
/// <param name="cacheDependency"></param>
|
||||
/// <param name="timeout">This will set an absolute expiration from now until the timeout</param>
|
||||
/// <param name="getCacheItem"></param>
|
||||
public void InsertCacheItem<T>(string cacheKey,
|
||||
CacheItemPriority priority,
|
||||
CacheItemRemovedCallback refreshAction,
|
||||
CacheDependency cacheDependency,
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
if (!_enableCache)
|
||||
{
|
||||
_nullCache.InsertCacheItem<T>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
else
|
||||
{
|
||||
_httpCache.InsertCacheItem<T>(cacheKey, priority, refreshAction, cacheDependency, timeout, getCacheItem);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
internal CacheRefreshersResolver(IEnumerable<Type> refreshers)
|
||||
internal CacheRefreshersResolver(Func<IEnumerable<Type>> refreshers)
|
||||
: base(refreshers)
|
||||
{
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureIdsAreTracked();
|
||||
EnsureIsInitialized();
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to add a Friendly Name string with an UmbracoObjectType enum value
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.All, AllowMultiple = false, Inherited = false)]
|
||||
internal class FriendlyNameAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// friendly name value
|
||||
/// </summary>
|
||||
private readonly string _friendlyName;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the FriendlyNameAttribute class
|
||||
/// Sets the friendly name value
|
||||
/// </summary>
|
||||
/// <param name="friendlyName">attribute value</param>
|
||||
public FriendlyNameAttribute(string friendlyName)
|
||||
{
|
||||
this._friendlyName = friendlyName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the friendly name
|
||||
/// </summary>
|
||||
/// <returns>string of friendly name</returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return this._friendlyName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute to associate a GUID string and Type with an UmbracoObjectType Enum value
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
|
||||
internal class UmbracoObjectTypeAttribute : Attribute
|
||||
{
|
||||
public UmbracoObjectTypeAttribute(string objectId)
|
||||
{
|
||||
ObjectId = new Guid(objectId);
|
||||
}
|
||||
|
||||
public UmbracoObjectTypeAttribute(string objectId, Type modelType)
|
||||
{
|
||||
ObjectId = new Guid(objectId);
|
||||
ModelType = modelType;
|
||||
}
|
||||
|
||||
public Guid ObjectId { get; private set; }
|
||||
|
||||
public Type ModelType { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// A thread-safe representation of a <see cref="HashSet{T}"/>.
|
||||
/// Enumerating this collection is thread-safe and will only operate on a clone that is generated before returning the enumerator.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[Serializable]
|
||||
public class ConcurrentHashSet<T> : ICollection<T>
|
||||
{
|
||||
private readonly HashSet<T> _innerSet = new HashSet<T>();
|
||||
private readonly ReaderWriterLockSlim _instanceLocker = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>1</filterpriority>
|
||||
public IEnumerator<T> GetEnumerator()
|
||||
{
|
||||
return GetThreadSafeClone().GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through a collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the first occurrence of a specific object from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> was successfully removed from the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false. This method also returns false if <paramref name="item"/> is not found in the original <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to remove from the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public bool Remove(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
return _innerSet.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The number of elements contained in the <see cref="T:System.Collections.ICollection"/>.
|
||||
/// </returns>
|
||||
/// <filterpriority>2</filterpriority>
|
||||
public int Count
|
||||
{
|
||||
get { return GetThreadSafeClone().Count; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if the <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only; otherwise, false.
|
||||
/// </returns>
|
||||
public bool IsReadOnly
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds an item to the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <param name="item">The object to add to the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param><exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only.</exception>
|
||||
public void Add(T item)
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to add an item to the collection
|
||||
/// </summary>
|
||||
/// <param name="item"></param>
|
||||
/// <returns></returns>
|
||||
public bool TryAdd(T item)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
if (clone.Contains(item)) return false;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
//double check
|
||||
if (_innerSet.Contains(item)) return false;
|
||||
_innerSet.Add(item);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes all items from the <see cref="T:System.Collections.Generic.ICollection`1"/>.
|
||||
/// </summary>
|
||||
/// <exception cref="T:System.NotSupportedException">The <see cref="T:System.Collections.Generic.ICollection`1"/> is read-only. </exception>
|
||||
public void Clear()
|
||||
{
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
_innerSet.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the <see cref="T:System.Collections.Generic.ICollection`1"/> contains a specific value.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true if <paramref name="item"/> is found in the <see cref="T:System.Collections.Generic.ICollection`1"/>; otherwise, false.
|
||||
/// </returns>
|
||||
/// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.ICollection`1"/>.</param>
|
||||
public bool Contains(T item)
|
||||
{
|
||||
return GetThreadSafeClone().Contains(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/> to an <see cref="T:System.Array"/>, starting at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from the <see cref="T:System.Collections.Concurrent.IProducerConsumerCollection`1"/>. The array must have zero-based indexing.</param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins.</param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is a null reference (Nothing in Visual Basic).</exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero.</exception><exception cref="T:System.ArgumentException"><paramref name="index"/> is equal to or greater than the length of the <paramref name="array"/> -or- The number of elements in the source <see cref="T:System.Collections.Concurrent.ConcurrentQueue`1"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>.</exception>
|
||||
public void CopyTo(T[] array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
clone.CopyTo(array, index);
|
||||
}
|
||||
|
||||
private HashSet<T> GetThreadSafeClone()
|
||||
{
|
||||
HashSet<T> clone = null;
|
||||
using (new WriteLock(_instanceLocker))
|
||||
{
|
||||
clone = new HashSet<T>(_innerSet, _innerSet.Comparer);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies the elements of the <see cref="T:System.Collections.ICollection"/> to an <see cref="T:System.Array"/>, starting at a particular <see cref="T:System.Array"/> index.
|
||||
/// </summary>
|
||||
/// <param name="array">The one-dimensional <see cref="T:System.Array"/> that is the destination of the elements copied from <see cref="T:System.Collections.ICollection"/>. The <see cref="T:System.Array"/> must have zero-based indexing. </param><param name="index">The zero-based index in <paramref name="array"/> at which copying begins. </param><exception cref="T:System.ArgumentNullException"><paramref name="array"/> is null. </exception><exception cref="T:System.ArgumentOutOfRangeException"><paramref name="index"/> is less than zero. </exception><exception cref="T:System.ArgumentException"><paramref name="array"/> is multidimensional.-or- The number of elements in the source <see cref="T:System.Collections.ICollection"/> is greater than the available space from <paramref name="index"/> to the end of the destination <paramref name="array"/>. </exception><exception cref="T:System.ArgumentException">The type of the source <see cref="T:System.Collections.ICollection"/> cannot be cast automatically to the type of the destination <paramref name="array"/>. </exception><filterpriority>2</filterpriority>
|
||||
public void CopyTo(Array array, int index)
|
||||
{
|
||||
var clone = GetThreadSafeClone();
|
||||
Array.Copy(clone.ToArray(), 0, array, index, clone.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// A case-insensitive configuration converter for enumerations.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the enumeration.</typeparam>
|
||||
internal class CaseInsensitiveEnumConfigConverter<T> : ConfigurationConverterBase
|
||||
where T : struct
|
||||
{
|
||||
public override object ConvertFrom(ITypeDescriptorContext ctx, CultureInfo ci, object data)
|
||||
{
|
||||
if (data == null)
|
||||
throw new ArgumentNullException("data");
|
||||
|
||||
//return Enum.Parse(typeof(T), (string)data, true);
|
||||
|
||||
T value;
|
||||
if (Enum.TryParse((string)data, true, out value))
|
||||
return value;
|
||||
|
||||
throw new Exception(string.Format("\"{0}\" is not valid {1} value. Valid values are: {2}.",
|
||||
data, typeof(T).Name,
|
||||
string.Join(", ", Enum.GetValues(typeof(T)).Cast<T>())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates the configuration key for a section or a group.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal sealed class ConfigurationKeyAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfigurationKeyAttribute"/> class with a configuration key.
|
||||
/// </summary>
|
||||
/// <param name="configurationKey">The configurationkey.</param>
|
||||
public ConfigurationKeyAttribute(string configurationKey)
|
||||
{
|
||||
ConfigurationKey = configurationKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the configuration key.
|
||||
/// </summary>
|
||||
public string ConfigurationKey { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -28,24 +28,58 @@ namespace Umbraco.Core.Configuration
|
||||
#region Private static fields
|
||||
|
||||
private static Version _version;
|
||||
private static string _reservedUrlsCache;
|
||||
private static readonly object Locker = new object();
|
||||
//make this volatile so that we can ensure thread safety with a double check lock
|
||||
private static volatile string _reservedUrlsCache;
|
||||
private static string _reservedPathsCache;
|
||||
private static StartsWithContainer _reservedList = new StartsWithContainer();
|
||||
private static string _reservedPaths;
|
||||
private static string _reservedUrls;
|
||||
//ensure the built on (non-changeable) reserved paths are there at all times
|
||||
private const string StaticReservedPaths = "~/app_plugins/,~/install/,";
|
||||
private const string StaticReservedUrls = "~/config/splashes/booting.aspx,~/install/default.aspx,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
|
||||
/// </summary>
|
||||
private static void ResetInternal()
|
||||
{
|
||||
_reservedUrlsCache = null;
|
||||
_reservedPaths = null;
|
||||
_reservedUrls = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets settings that were set programmatically, to their initial values.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static void Reset()
|
||||
{
|
||||
ResetInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved urls from web.config.
|
||||
/// </summary>
|
||||
/// <value>The reserved urls.</value>
|
||||
public static string ReservedUrls
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedUrls"]
|
||||
: string.Empty;
|
||||
{
|
||||
if (_reservedUrls == null)
|
||||
{
|
||||
var urls = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedUrls")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedUrls"]
|
||||
: string.Empty;
|
||||
|
||||
//ensure the built on (non-changeable) reserved paths are there at all times
|
||||
_reservedUrls = StaticReservedUrls + urls;
|
||||
}
|
||||
return _reservedUrls;
|
||||
}
|
||||
internal set { _reservedUrls = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -56,10 +90,25 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedPaths"]
|
||||
: string.Empty;
|
||||
if (_reservedPaths == null)
|
||||
{
|
||||
var reservedPaths = StaticReservedPaths;
|
||||
//always add the umbraco path to the list
|
||||
if (ConfigurationManager.AppSettings.ContainsKey("umbracoPath")
|
||||
&& !ConfigurationManager.AppSettings["umbracoPath"].IsNullOrWhiteSpace())
|
||||
{
|
||||
reservedPaths += ConfigurationManager.AppSettings["umbracoPath"].EnsureEndsWith(',');
|
||||
}
|
||||
|
||||
var allPaths = ConfigurationManager.AppSettings.ContainsKey("umbracoReservedPaths")
|
||||
? ConfigurationManager.AppSettings["umbracoReservedPaths"]
|
||||
: string.Empty;
|
||||
|
||||
_reservedPaths = reservedPaths + allPaths;
|
||||
}
|
||||
return _reservedPaths;
|
||||
}
|
||||
internal set { _reservedPaths = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -114,6 +163,9 @@ namespace Umbraco.Core.Configuration
|
||||
/// This will return the MVC area that we will route all custom routes through like surface controllers, etc...
|
||||
/// We will use the 'Path' (default ~/umbraco) to create it but since it cannot contain '/' and people may specify a path of ~/asdf/asdf/admin
|
||||
/// we will convert the '/' to '-' and use that as the path. its a bit lame but will work.
|
||||
///
|
||||
/// We also make sure that the virtual directory (SystemDirectories.Root) is stripped off first, otherwise we'd end up with something
|
||||
/// like "MyVirtualDirectory-Umbraco" instead of just "Umbraco".
|
||||
/// </remarks>
|
||||
internal static string UmbracoMvcArea
|
||||
{
|
||||
@@ -123,7 +175,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
throw new InvalidOperationException("Cannot create an MVC Area path without the umbracoPath specified");
|
||||
}
|
||||
return Path.TrimStart('~').TrimStart('/').Replace('/', '-').Trim();
|
||||
return Path.TrimStart(SystemDirectories.Root).TrimStart('~').TrimStart('/').Replace('/', '-').Trim().ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +222,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
if (value.ToLower().Contains("SQLCE4Umbraco.SqlCEHelper".ToLower()))
|
||||
{
|
||||
ApplicationContext.Current.DatabaseContext.ConfigureDatabaseConnection();
|
||||
ApplicationContext.Current.DatabaseContext.ConfigureEmbeddedDatabaseConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -201,6 +253,7 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a setting into the configuration file.
|
||||
/// </summary>
|
||||
@@ -531,6 +584,16 @@ namespace Umbraco.Core.Configuration
|
||||
return context.Request.Path.ToLower().IndexOf(SystemDirectories.Umbraco.ToLower() + "/liveediting.aspx") > -1;
|
||||
}
|
||||
|
||||
public static bool RequestIsInUmbracoApplication(HttpContextBase context)
|
||||
{
|
||||
return context.Request.Path.ToLower().IndexOf(IOHelper.ResolveUrl(SystemDirectories.Umbraco).ToLower()) > -1;
|
||||
}
|
||||
|
||||
public static bool RequestIsLiveEditRedirector(HttpContextBase context)
|
||||
{
|
||||
return context.Request.Path.ToLower().IndexOf(SystemDirectories.Umbraco.ToLower() + "/liveediting.aspx") > -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether umbraco should force a secure (https) connection to the backoffice.
|
||||
/// </summary>
|
||||
@@ -622,38 +685,42 @@ namespace Umbraco.Core.Configuration
|
||||
/// </returns>
|
||||
public static bool IsReservedPathOrUrl(string url)
|
||||
{
|
||||
// check if GlobalSettings.ReservedPaths and GlobalSettings.ReservedUrls are unchanged
|
||||
if (!object.ReferenceEquals(_reservedPathsCache, GlobalSettings.ReservedPaths)
|
||||
|| !object.ReferenceEquals(_reservedUrlsCache, GlobalSettings.ReservedUrls))
|
||||
if (_reservedUrlsCache == null)
|
||||
{
|
||||
// store references to strings to determine changes
|
||||
_reservedPathsCache = GlobalSettings.ReservedPaths;
|
||||
_reservedUrlsCache = GlobalSettings.ReservedUrls;
|
||||
|
||||
string _root = SystemDirectories.Root.Trim().ToLower();
|
||||
|
||||
// add URLs and paths to a new list
|
||||
StartsWithContainer _newReservedList = new StartsWithContainer();
|
||||
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
lock (Locker)
|
||||
{
|
||||
//resolves the url to support tilde chars
|
||||
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
|
||||
if (reservedUrlTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedUrlTrimmed);
|
||||
if (_reservedUrlsCache == null)
|
||||
{
|
||||
// store references to strings to determine changes
|
||||
_reservedPathsCache = GlobalSettings.ReservedPaths;
|
||||
_reservedUrlsCache = GlobalSettings.ReservedUrls;
|
||||
|
||||
string _root = SystemDirectories.Root.Trim().ToLower();
|
||||
|
||||
// add URLs and paths to a new list
|
||||
StartsWithContainer _newReservedList = new StartsWithContainer();
|
||||
foreach (string reservedUrl in _reservedUrlsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
//resolves the url to support tilde chars
|
||||
string reservedUrlTrimmed = IOHelper.ResolveUrl(reservedUrl).Trim().ToLower();
|
||||
if (reservedUrlTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedUrlTrimmed);
|
||||
}
|
||||
|
||||
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
bool trimEnd = !reservedPath.EndsWith("/");
|
||||
//resolves the url to support tilde chars
|
||||
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
|
||||
|
||||
if (reservedPathTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
|
||||
}
|
||||
|
||||
// use the new list from now on
|
||||
_reservedList = _newReservedList;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string reservedPath in _reservedPathsCache.Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
bool trimEnd = !reservedPath.EndsWith("/");
|
||||
//resolves the url to support tilde chars
|
||||
string reservedPathTrimmed = IOHelper.ResolveUrl(reservedPath).Trim().ToLower();
|
||||
|
||||
if (reservedPathTrimmed.Length > 0)
|
||||
_newReservedList.Add(reservedPathTrimmed + (reservedPathTrimmed.EndsWith("/") ? "" : "/"));
|
||||
}
|
||||
|
||||
// use the new list from now on
|
||||
_reservedList = _newReservedList;
|
||||
}
|
||||
|
||||
//The url should be cleaned up before checking:
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.InfrastructureSettings
|
||||
{
|
||||
public class Infrastructure : ConfigurationSection
|
||||
{
|
||||
private const string InfrastructureSectionName = "umbraco/infrastructure";
|
||||
|
||||
public static Infrastructure Instance
|
||||
{
|
||||
get { return (Infrastructure) ConfigurationManager.GetSection(InfrastructureSectionName); }
|
||||
}
|
||||
|
||||
#region RepositoriesSection Property
|
||||
|
||||
internal const string RepositoriesPropertyName = "repositories";
|
||||
|
||||
[ConfigurationProperty(RepositoriesPropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public Repositories Repositories
|
||||
{
|
||||
get { return ((Repositories)base[RepositoriesPropertyName]); }
|
||||
set { base[RepositoriesPropertyName] = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region PublishingStrategy Property
|
||||
|
||||
internal const string PublishingStrategyPropertyName = "publishingStrategy";
|
||||
|
||||
[ConfigurationProperty(PublishingStrategyPropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public PublishingProvider PublishingStrategy
|
||||
{
|
||||
get { return ((PublishingProvider)base[PublishingStrategyPropertyName]); }
|
||||
set { base[PublishingStrategyPropertyName] = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class Repositories : ConfigurationElement
|
||||
{
|
||||
[ConfigurationProperty("", IsDefaultCollection = true, IsRequired = true)]
|
||||
public RepositoryElementCollection Repository
|
||||
{
|
||||
get { return ((RepositoryElementCollection)(base[""])); }
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(Repository), CollectionType = ConfigurationElementCollectionType.BasicMapAlternate, AddItemName = RepositoryPropertyName)]
|
||||
public class RepositoryElementCollection : ConfigurationElementCollection
|
||||
{
|
||||
internal const string RepositoryPropertyName = "repository";
|
||||
|
||||
public override ConfigurationElementCollectionType CollectionType
|
||||
{
|
||||
get
|
||||
{
|
||||
return ConfigurationElementCollectionType.BasicMapAlternate;
|
||||
}
|
||||
}
|
||||
|
||||
protected override string ElementName
|
||||
{
|
||||
get
|
||||
{
|
||||
return RepositoryPropertyName;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool IsElementName(string elementName)
|
||||
{
|
||||
return elementName == RepositoryPropertyName;
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((Repository)element).InterfaceShortTypeName;
|
||||
}
|
||||
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new Repository();
|
||||
}
|
||||
|
||||
#region Indexer
|
||||
|
||||
public Repository this[int index]
|
||||
{
|
||||
get { return (Repository)base.BaseGet(index); }
|
||||
}
|
||||
|
||||
public Repository this[string interfaceShortTypeName]
|
||||
{
|
||||
get { return (Repository)base.BaseGet(interfaceShortTypeName); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Add
|
||||
|
||||
public void Add(Repository repository)
|
||||
{
|
||||
BaseAdd(repository);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Remove
|
||||
|
||||
public void Remove(Repository repository)
|
||||
{
|
||||
BaseRemove(repository);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region GetItem
|
||||
|
||||
public Repository GetItemAt(int index)
|
||||
{
|
||||
return (Repository)BaseGet(index);
|
||||
}
|
||||
|
||||
public Repository GetItemByKey(string interfaceShortTypeName)
|
||||
{
|
||||
return (Repository)BaseGet(interfaceShortTypeName);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool ContainsKey(string interfaceShortName)
|
||||
{
|
||||
bool result = false;
|
||||
object[] keys = this.BaseGetAllKeys();
|
||||
foreach (object key in keys)
|
||||
{
|
||||
if ((string)key == interfaceShortName)
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public class Repository : ConfigurationElement
|
||||
{
|
||||
internal const string InterfaceShortTypeNamePropertyName = "interfaceShortTypeName";
|
||||
|
||||
[ConfigurationPropertyAttribute(InterfaceShortTypeNamePropertyName, IsRequired = true, IsKey = true, IsDefaultCollection = false)]
|
||||
public string InterfaceShortTypeName
|
||||
{
|
||||
get { return (string) base[InterfaceShortTypeNamePropertyName]; }
|
||||
set { base[InterfaceShortTypeNamePropertyName] = value; }
|
||||
}
|
||||
|
||||
internal const string RepositoryFullTypeNamePropertyName = "repositoryFullTypeName";
|
||||
|
||||
[ConfigurationPropertyAttribute(RepositoryFullTypeNamePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public string RepositoryFullTypeName
|
||||
{
|
||||
get { return (string)base[RepositoryFullTypeNamePropertyName]; }
|
||||
set { base[RepositoryFullTypeNamePropertyName] = value; }
|
||||
}
|
||||
|
||||
internal const string CacheProviderFullTypeNamePropertyName = "cacheProviderFullTypeName";
|
||||
|
||||
[ConfigurationPropertyAttribute(CacheProviderFullTypeNamePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public string CacheProviderFullTypeName
|
||||
{
|
||||
get { return (string)base[CacheProviderFullTypeNamePropertyName]; }
|
||||
set { base[CacheProviderFullTypeNamePropertyName] = value; }
|
||||
}
|
||||
}
|
||||
|
||||
public class PublishingProvider : ConfigurationElement
|
||||
{
|
||||
internal const string TypePropertyName = "type";
|
||||
|
||||
[ConfigurationPropertyAttribute(TypePropertyName, IsRequired = true, IsKey = false, IsDefaultCollection = false)]
|
||||
public string Type
|
||||
{
|
||||
get { return (string)base[TypePropertyName]; }
|
||||
set { base[TypePropertyName] = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
{
|
||||
// note - still must work on how to support read-only and ResetSection for collections
|
||||
// note - still must work on how to spread config over files (aka DeepConfig in v5)
|
||||
|
||||
/// <summary>
|
||||
/// Represents an Umbraco section within the configuration file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>The requirement for these sections is to be read-only.</para>
|
||||
/// <para>However for unit tests purposes it is internally possible to override some values, and
|
||||
/// then calling <c>>ResetSection</c> should cancel these changes and bring the section back to
|
||||
/// what it was originally.</para>
|
||||
/// <para>The <c>UmbracoSettings.For{T}</c> method will return a section, either one that
|
||||
/// is in the configuration file, or a section that was created with default values.</para>
|
||||
/// </remarks>
|
||||
internal abstract class UmbracoConfigurationSection : ConfigurationSection
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the section actually is in the configuration file.
|
||||
/// </summary>
|
||||
protected bool IsPresent { get { return ElementInformation.IsPresent; } }
|
||||
|
||||
/// <summary>
|
||||
/// Resets settings that were set programmatically, to their initial values.
|
||||
/// </summary>
|
||||
/// <remarks>>To be used in unit tests.</remarks>
|
||||
internal protected virtual void ResetSection()
|
||||
{ }
|
||||
}
|
||||
}
|
||||
@@ -6,9 +6,11 @@ using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Caching;
|
||||
using System.Xml;
|
||||
using System.Configuration;
|
||||
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
|
||||
namespace Umbraco.Core.Configuration
|
||||
@@ -20,22 +22,48 @@ namespace Umbraco.Core.Configuration
|
||||
|
||||
//TODO: Re-enable logging !!!!
|
||||
|
||||
//TODO: We need to convert this to a real section, it's currently using HttpRuntime.Cache to detect cahnges, this is real poor, especially in a console app
|
||||
|
||||
/// <summary>
|
||||
/// The UmbracoSettings Class contains general settings information for the entire Umbraco instance based on information from the /config/umbracoSettings.config file
|
||||
/// </summary>
|
||||
internal class UmbracoSettings
|
||||
{
|
||||
/// <summary>
|
||||
private static bool GetKeyValue(string key, bool defaultValue)
|
||||
{
|
||||
bool value;
|
||||
string stringValue = GetKey(key);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
return defaultValue;
|
||||
if (bool.TryParse(stringValue, out value))
|
||||
return value;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private static int GetKeyValue(string key, int defaultValue)
|
||||
{
|
||||
int value;
|
||||
string stringValue = GetKey(key);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(stringValue))
|
||||
return defaultValue;
|
||||
if (int.TryParse(stringValue, out value))
|
||||
return value;
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
|
||||
/// </summary>
|
||||
internal static void ResetSetters()
|
||||
private static void ResetInternal()
|
||||
{
|
||||
_addTrailingSlash = null;
|
||||
_forceSafeAliases = null;
|
||||
_useLegacySchema = null;
|
||||
_useDomainPrefixes = null;
|
||||
_umbracoLibraryCacheDuration = null;
|
||||
SettingsFilePath = null;
|
||||
SettingsFilePath = null;
|
||||
}
|
||||
|
||||
internal const string TempFriendlyXmlChildContainerNodename = ""; // "children";
|
||||
@@ -126,11 +154,32 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
EnsureSettingsDocument();
|
||||
|
||||
string attrName = null;
|
||||
var pos = key.IndexOf('@');
|
||||
if (pos > 0)
|
||||
{
|
||||
attrName = key.Substring(pos + 1);
|
||||
key = key.Substring(0, pos - 1);
|
||||
}
|
||||
|
||||
var node = UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode(key);
|
||||
if (node == null || node.FirstChild == null || node.FirstChild.Value == null)
|
||||
return string.Empty;
|
||||
return node.FirstChild.Value;
|
||||
}
|
||||
if (node == null)
|
||||
return string.Empty;
|
||||
|
||||
if (pos < 0)
|
||||
{
|
||||
if (node.FirstChild == null || node.FirstChild.Value == null)
|
||||
return string.Empty;
|
||||
return node.FirstChild.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var attr = node.Attributes[attrName];
|
||||
if (attr == null)
|
||||
return string.Empty;
|
||||
return attr.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the media library will create new directories in the /media directory.
|
||||
@@ -203,6 +252,7 @@ namespace Umbraco.Core.Configuration
|
||||
return value != null ? value.Attributes["assembly"].Value : "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the type of an external logger that can be used to store log items in 3rd party systems
|
||||
/// </summary>
|
||||
@@ -351,24 +401,13 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_useDomainPrefixes.HasValue)
|
||||
return _useDomainPrefixes.Value;
|
||||
bool result;
|
||||
if (bool.TryParse(GetKey("/settings/requestHandler/useDomainPrefixes"), out result))
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// default: false
|
||||
return _useDomainPrefixes ?? GetKeyValue("/settings/requestHandler/useDomainPrefixes", false);
|
||||
}
|
||||
// for unit tests only
|
||||
internal set
|
||||
{
|
||||
_useDomainPrefixes = value;
|
||||
// for unit tests only
|
||||
_useDomainPrefixes = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -382,31 +421,14 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (GlobalSettings.UseDirectoryUrls)
|
||||
{
|
||||
if (_addTrailingSlash.HasValue)
|
||||
return _addTrailingSlash.Value;
|
||||
bool result;
|
||||
if (bool.TryParse(GetKey("/settings/requestHandler/addTrailingSlash"), out result))
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// default: false
|
||||
return GlobalSettings.UseDirectoryUrls
|
||||
&& (_addTrailingSlash ?? GetKeyValue("/settings/requestHandler/addTrailingSlash", false));
|
||||
}
|
||||
// for unit tests only
|
||||
internal set
|
||||
{
|
||||
_addTrailingSlash = value;
|
||||
// for unit tests only
|
||||
_addTrailingSlash = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -484,7 +506,7 @@ namespace Umbraco.Core.Configuration
|
||||
private static IEnumerable<RazorDataTypeModelStaticMappingItem> _razorDataTypeModelStaticMapping;
|
||||
private static readonly ReaderWriterLockSlim Lock = new ReaderWriterLockSlim();
|
||||
|
||||
public static IEnumerable<RazorDataTypeModelStaticMappingItem> RazorDataTypeModelStaticMapping
|
||||
internal static IEnumerable<RazorDataTypeModelStaticMappingItem> RazorDataTypeModelStaticMapping
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -623,31 +645,33 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_forceSafeAliases.HasValue)
|
||||
return _forceSafeAliases.Value;
|
||||
|
||||
string forceSafeAlias = GetKey("/settings/content/ForceSafeAliases");
|
||||
if (String.IsNullOrEmpty(forceSafeAlias))
|
||||
return true;
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return bool.Parse(forceSafeAlias);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// default: true
|
||||
return _forceSafeAliases ?? GetKeyValue("/settings/content/ForceSafeAliases", true);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
//used for unit testing
|
||||
// used for unit testing
|
||||
_forceSafeAliases = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether to try to skip IIS custom errors.
|
||||
/// </summary>
|
||||
[UmbracoWillObsolete("Use UmbracoSettings.For<WebRouting>.TrySkipIisCustomErrors instead.")]
|
||||
internal static bool TrySkipIisCustomErrors
|
||||
{
|
||||
get { return GetKeyValue("/settings/web.routing/@trySkipIisCustomErrors", false); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether internal redirect preserves the template.
|
||||
/// </summary>
|
||||
[UmbracoWillObsolete("Use UmbracoSettings.For<WebRouting>.InternalRedirectPerservesTemplate instead.")]
|
||||
internal static bool InternalRedirectPreservesTemplate
|
||||
{
|
||||
get { return GetKeyValue("/settings/web.routing/@internalRedirectPreservesTemplate", false); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed image file types.
|
||||
@@ -677,26 +701,14 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_umbracoLibraryCacheDuration.HasValue)
|
||||
return _umbracoLibraryCacheDuration.Value;
|
||||
|
||||
string libraryCacheDuration = GetKey("/settings/content/UmbracoLibraryCacheDuration");
|
||||
if (String.IsNullOrEmpty(libraryCacheDuration))
|
||||
return 1800;
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return int.Parse(libraryCacheDuration);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return 1800;
|
||||
}
|
||||
}
|
||||
|
||||
// default: 1800
|
||||
return _umbracoLibraryCacheDuration ?? GetKeyValue("/settings/content/UmbracoLibraryCacheDuration", 1800);
|
||||
}
|
||||
internal set { _umbracoLibraryCacheDuration = value; }
|
||||
internal set
|
||||
{
|
||||
// for unit tests only
|
||||
_umbracoLibraryCacheDuration = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1052,27 +1064,12 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_useLegacySchema.HasValue)
|
||||
return _useLegacySchema.Value;
|
||||
|
||||
string value = GetKey("/settings/content/UseLegacyXmlSchema");
|
||||
bool result;
|
||||
if (!string.IsNullOrEmpty(value) && bool.TryParse(value, out result))
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//default. TODO: When we change this to a real config section we won't have to worry about parse errors
|
||||
// and should handle defaults with unit tests properly.
|
||||
return false;
|
||||
}
|
||||
// default: true
|
||||
return _useLegacySchema ?? GetKeyValue("/settings/content/UseLegacyXmlSchema", false);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
//used for unit testing
|
||||
// used for unit testing
|
||||
_useLegacySchema = value;
|
||||
}
|
||||
}
|
||||
@@ -1219,8 +1216,83 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
return _defaultRenderingEngine.Value;
|
||||
}
|
||||
//internal set
|
||||
//{
|
||||
// _defaultRenderingEngine = value;
|
||||
// var node = UmbracoSettingsXmlDoc.DocumentElement.SelectSingleNode("/settings/templates/defaultRenderingEngine");
|
||||
// node.InnerText = value.ToString();
|
||||
//}
|
||||
}
|
||||
|
||||
private static MacroErrorBehaviour? _macroErrorBehaviour;
|
||||
|
||||
/// <summary>
|
||||
/// This configuration setting defines how to handle macro errors:
|
||||
/// - Inline - Show error within macro as text (default and current Umbraco 'normal' behavior)
|
||||
/// - Silent - Suppress error and hide macro
|
||||
/// - Throw - Throw an exception and invoke the global error handler (if one is defined, if not you'll get a YSOD)
|
||||
/// </summary>
|
||||
/// <value>MacroErrorBehaviour enum defining how to handle macro errors.</value>
|
||||
public static MacroErrorBehaviour MacroErrorBehaviour
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_macroErrorBehaviour == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var behaviour = MacroErrorBehaviour.Inline;
|
||||
var value = GetKey("/settings/content/MacroErrors");
|
||||
if (value != null)
|
||||
{
|
||||
Enum<MacroErrorBehaviour>.TryParse(value, true, out behaviour);
|
||||
}
|
||||
_macroErrorBehaviour = behaviour;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<UmbracoSettings>("Could not load /settings/content/MacroErrors from umbracosettings.config", ex);
|
||||
_macroErrorBehaviour = MacroErrorBehaviour.Inline;
|
||||
}
|
||||
}
|
||||
return _macroErrorBehaviour.Value;
|
||||
}
|
||||
}
|
||||
|
||||
private static IconPickerBehaviour? _iconPickerBehaviour;
|
||||
|
||||
/// <summary>
|
||||
/// This configuration setting defines how to show icons in the document type editor.
|
||||
/// - ShowDuplicates - Show duplicates in files and sprites. (default and current Umbraco 'normal' behaviour)
|
||||
/// - HideSpriteDuplicates - Show files on disk and hide duplicates from the sprite
|
||||
/// - HideFileDuplicates - Show files in the sprite and hide duplicates on disk
|
||||
/// </summary>
|
||||
/// <value>MacroErrorBehaviour enum defining how to show icons in the document type editor.</value>
|
||||
public static IconPickerBehaviour IconPickerBehaviour
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_iconPickerBehaviour == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var behaviour = IconPickerBehaviour.ShowDuplicates;
|
||||
var value = GetKey("/settings/content/DocumentTypeIconList");
|
||||
if (value != null)
|
||||
{
|
||||
Enum<IconPickerBehaviour>.TryParse(value, true, out behaviour);
|
||||
}
|
||||
_iconPickerBehaviour = behaviour;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<UmbracoSettings>("Could not load /settings/content/DocumentTypeIconList from umbracosettings.config", ex);
|
||||
_iconPickerBehaviour = IconPickerBehaviour.ShowDuplicates;
|
||||
}
|
||||
}
|
||||
return _iconPickerBehaviour.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration regarding webservices
|
||||
@@ -1405,6 +1477,80 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Extensible settings
|
||||
|
||||
/// <summary>
|
||||
/// Resets settings that were set programmatically, to their initial values.
|
||||
/// </summary>
|
||||
/// <remarks>To be used in unit tests.</remarks>
|
||||
internal static void Reset()
|
||||
{
|
||||
ResetInternal();
|
||||
|
||||
using (new WriteLock(SectionsLock))
|
||||
{
|
||||
foreach (var section in Sections.Values)
|
||||
section.ResetSection();
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ReaderWriterLockSlim SectionsLock = new ReaderWriterLockSlim();
|
||||
private static readonly Dictionary<Type, UmbracoConfigurationSection> Sections = new Dictionary<Type, UmbracoConfigurationSection>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the specified UmbracoConfigurationSection.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the UmbracoConfigurationSectiont.</typeparam>
|
||||
/// <returns>The UmbracoConfigurationSection of the specified type.</returns>
|
||||
internal static T For<T>()
|
||||
where T : UmbracoConfigurationSection, new()
|
||||
{
|
||||
var sectionType = typeof (T);
|
||||
using (new WriteLock(SectionsLock))
|
||||
{
|
||||
if (Sections.ContainsKey(sectionType)) return Sections[sectionType] as T;
|
||||
|
||||
var attr = sectionType.GetCustomAttribute<ConfigurationKeyAttribute>(false);
|
||||
if (attr == null)
|
||||
throw new InvalidOperationException(string.Format("Type \"{0}\" is missing attribute ConfigurationKeyAttribute.", sectionType.FullName));
|
||||
|
||||
var sectionKey = attr.ConfigurationKey;
|
||||
if (string.IsNullOrWhiteSpace(sectionKey))
|
||||
throw new InvalidOperationException(string.Format("Type \"{0}\" ConfigurationKeyAttribute value is null or empty.", sectionType.FullName));
|
||||
|
||||
var section = GetSection(sectionType, sectionKey);
|
||||
|
||||
Sections[sectionType] = section;
|
||||
return section as T;
|
||||
}
|
||||
}
|
||||
|
||||
private static UmbracoConfigurationSection GetSection(Type sectionType, string key)
|
||||
{
|
||||
if (!sectionType.Inherits<UmbracoConfigurationSection>())
|
||||
throw new ArgumentException(string.Format(
|
||||
"Type \"{0}\" does not inherit from UmbracoConfigurationSection.", sectionType.FullName), "sectionType");
|
||||
|
||||
var section = ConfigurationManager.GetSection(key);
|
||||
|
||||
if (section != null && section.GetType() != sectionType)
|
||||
throw new InvalidCastException(string.Format("Section at key \"{0}\" is of type \"{1}\" and not \"{2}\".",
|
||||
key, section.GetType().FullName, sectionType.FullName));
|
||||
|
||||
if (section != null) return section as UmbracoConfigurationSection;
|
||||
|
||||
section = Activator.CreateInstance(sectionType) as UmbracoConfigurationSection;
|
||||
|
||||
if (section == null)
|
||||
throw new NullReferenceException(string.Format(
|
||||
"Activator failed to create an instance of type \"{0}\" for key\"{1}\" and returned null.",
|
||||
sectionType.FullName, key));
|
||||
|
||||
return section as UmbracoConfigurationSection;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("6.0.0");
|
||||
private static readonly Version Version = new Version("6.1.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "RC"; } }
|
||||
public static string CurrentComment { get { return "beta"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the alias identifiers for Umbraco's core application sections.
|
||||
/// </summary>
|
||||
public static class Applications
|
||||
{
|
||||
/// <summary>
|
||||
/// Application alias for the content section.
|
||||
/// </summary>
|
||||
public const string Content = "content";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the developer section.
|
||||
/// </summary>
|
||||
public const string Developer = "developer";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the media section.
|
||||
/// </summary>
|
||||
public const string Media = "media";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the members section.
|
||||
/// </summary>
|
||||
public const string Members = "member";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the settings section.
|
||||
/// </summary>
|
||||
public const string Settings = "settings";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the translation section.
|
||||
/// </summary>
|
||||
public const string Translation = "translation";
|
||||
|
||||
/// <summary>
|
||||
/// Application alias for the users section.
|
||||
/// </summary>
|
||||
public const string Users = "users";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for property-type alias conventions that are used within the Umbraco core.
|
||||
/// </summary>
|
||||
public static class Conventions
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants for Umbraco Content property aliases.
|
||||
/// </summary>
|
||||
public static class Content
|
||||
{
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url (internal) redirect.
|
||||
/// </summary>
|
||||
public const string InternalRedirectId = "umbracoInternalRedirectId";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's navigational hide, (not actually used in core code).
|
||||
/// </summary>
|
||||
public const string NaviHide = "umbracoNaviHide";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url redirect.
|
||||
/// </summary>
|
||||
public const string Redirect = "umbracoRedirect";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url alias.
|
||||
/// </summary>
|
||||
public const string UrlAlias = "umbracoUrlAlias";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Content's Url name.
|
||||
/// </summary>
|
||||
public const string UrlName = "umbracoUrlName";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constants for Umbraco Media property aliases.
|
||||
/// </summary>
|
||||
public static class Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Property alias for the Media's file name.
|
||||
/// </summary>
|
||||
public const string File = "umbracoFile";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's width.
|
||||
/// </summary>
|
||||
public const string Width = "umbracoWidth";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's height.
|
||||
/// </summary>
|
||||
public const string Height = "umbracoHeight";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's file size (in bytes).
|
||||
/// </summary>
|
||||
public const string Bytes = "umbracoBytes";
|
||||
|
||||
/// <summary>
|
||||
/// Property alias for the Media's file extension.
|
||||
/// </summary>
|
||||
public const string Extension = "umbracoExtension";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines the alias identifiers for Umbraco media types.
|
||||
/// </summary>
|
||||
public static class MediaTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// MediaType alias for a file.
|
||||
/// </summary>
|
||||
public const string File = "File";
|
||||
|
||||
/// <summary>
|
||||
/// MediaType alias for a folder.
|
||||
/// </summary>
|
||||
public const string Folder = "Folder";
|
||||
|
||||
/// <summary>
|
||||
/// MediaType alias for an image.
|
||||
/// </summary>
|
||||
public const string Image = "Image";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constants for Umbraco URLs/Querystrings.
|
||||
/// </summary>
|
||||
public static class Url
|
||||
{
|
||||
/// <summary>
|
||||
/// Querystring parameter name used for Umbraco's alternative template functionality.
|
||||
/// </summary>
|
||||
public const string AltTemplate = "altTemplate";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco object types as constants for easy centralized access/management.
|
||||
/// </summary>
|
||||
public static class ObjectTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Guid for a Content Item object.
|
||||
/// </summary>
|
||||
public const string ContentItem = "10E2B09F-C28B-476D-B77A-AA686435E44A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Content Item Type object.
|
||||
/// </summary>
|
||||
public const string ContentItemType = "7A333C54-6F43-40A4-86A2-18688DC7E532";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Content Recycle Bin.
|
||||
/// </summary>
|
||||
public const string ContentRecycleBin = "01BB7FF2-24DC-4C0C-95A2-C24EF72BBAC8";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a DataType object.
|
||||
/// </summary>
|
||||
public const string DataType = "30A2A501-1978-4DDB-A57B-F7EFED43BA3C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document Type object.
|
||||
/// </summary>
|
||||
public const string DocumentType = "A2CB7800-F571-4787-9638-BC48539A0EFB";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media object.
|
||||
/// </summary>
|
||||
public const string Media = "B796F64C-1F99-4FFB-B886-4BF4BC011A9C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Media Recycle Bin.
|
||||
/// </summary>
|
||||
public const string MediaRecycleBin = "CF3D8E34-1C1C-41e9-AE56-878B57B32113";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Media Type object.
|
||||
/// </summary>
|
||||
public const string MediaType = "4EA4382B-2F5A-4C2B-9587-AE9B3CF3602E";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member object.
|
||||
/// </summary>
|
||||
public const string Member = "39EB0F98-B348-42A1-8662-E7EB18487560";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Group object.
|
||||
/// </summary>
|
||||
public const string MemberGroup = "366E63B9-880F-4E13-A61C-98069B029728";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Member Type object.
|
||||
/// </summary>
|
||||
public const string MemberType = "9B5416FB-E72F-45A9-A07B-5A9A2709CE43";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Stylesheet object.
|
||||
/// </summary>
|
||||
public const string Stylesheet = "9F68DA4F-A3A8-44C2-8226-DCBD125E4840";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the System Root.
|
||||
/// </summary>
|
||||
public const string SystemRoot = "EA7D8624-4CFE-4578-A871-24AA946BF34D";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Template object.
|
||||
/// </summary>
|
||||
public const string Template = "6FBDE604-4178-42CE-A10B-8A2600A2F07D";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,186 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco Property Editors as constants for easy centralized access/management.
|
||||
/// </summary>
|
||||
public static class PropertyEditors
|
||||
{
|
||||
/// <summary>
|
||||
/// Guid for the Checkbox list datatype.
|
||||
/// </summary>
|
||||
public const string CheckBoxList = "B4471851-82B6-4C75-AFA4-39FA9C6A75E9";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Color Picker datatype.
|
||||
/// </summary>
|
||||
public const string ColorPicker = "F8D60F68-EC59-4974-B43B-C46EB5677985";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Content Picker datatype.
|
||||
/// </summary>
|
||||
public const string ContentPicker = "158AA029-24ED-4948-939E-C3DA209E5FBA";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Date datatype.
|
||||
/// </summary>
|
||||
public const string Date = "23E93522-3200-44E2-9F29-E61A6FCBB79A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Date/Time datatype.
|
||||
/// </summary>
|
||||
public const string DateTime = "B6FB1622-AFA5-4BBF-A3CC-D9672A442222";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dictionary Picker datatype.
|
||||
/// </summary>
|
||||
public const string DictionaryPicker = "17B70066-F764-407D-AB05-3717F1E1C513";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list datatype.
|
||||
/// </summary>
|
||||
public const string DropDownList = "A74EA9C9-8E18-4D2A-8CF6-73C6206C5DA6";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list multiple datatype.
|
||||
/// </summary>
|
||||
public const string DropDownListMultiple = "928639ED-9C73-4028-920C-1E55DBB68783";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list multiple, publish keys datatype.
|
||||
/// </summary>
|
||||
public const string DropdownlistMultiplePublishKeys = "928639AA-9C73-4028-920C-1E55DBB68783";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Dropdown list, publishing keys datatype.
|
||||
/// </summary>
|
||||
public const string DropdownlistPublishingKeys = "A74EA9E1-8E18-4D2A-8CF6-73C6206C5DA6";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Folder browser datatype.
|
||||
/// </summary>
|
||||
public const string FolderBrowser = "CCCD4AE9-F399-4ED2-8038-2E88D19E810C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Image Cropper datatype.
|
||||
/// </summary>
|
||||
public const string ImageCropper = "7A2D436C-34C2-410F-898F-4A23B3D79F54";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Integer datatype.
|
||||
/// </summary>
|
||||
public const string Integer = "1413AFCB-D19A-4173-8E9A-68288D2A73B8";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Macro Container datatype.
|
||||
/// </summary>
|
||||
public const string MacroContainer = "474FCFF8-9D2D-11DE-ABC6-AD7A56D89593";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Media Picker datatype.
|
||||
/// </summary>
|
||||
public const string MediaPicker = "EAD69342-F06D-4253-83AC-28000225583B";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Member Picker datatype.
|
||||
/// </summary>
|
||||
public const string MemberPicker = "39F533E4-0551-4505-A64B-E0425C5CE775";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multi-Node Tree Picker datatype
|
||||
/// </summary>
|
||||
public const string MultiNodeTreePicker = "7E062C13-7C41-4AD9-B389-41D88AEEF87C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Multiple Textstring datatype.
|
||||
/// </summary>
|
||||
public const string MultipleTextstring = "5359AD0B-06CC-4182-92BD-0A9117448D3F";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the No edit datatype.
|
||||
/// </summary>
|
||||
public const string NoEdit = "6C738306-4C17-4D88-B9BD-6546F3771597";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Picker Relations datatype.
|
||||
/// </summary>
|
||||
public const string PickerRelations = "83396FF2-2E39-4A90-9066-17F5F3989374";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Radiobutton list datatype.
|
||||
/// </summary>
|
||||
public const string RadioButtonList = "A52C7C1C-C330-476E-8605-D63D3B84B6A6";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Related Links datatype.
|
||||
/// </summary>
|
||||
public const string RelatedLinks = "71B8AD1A-8DC2-425C-B6B8-FAA158075E63";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Slider datatype.
|
||||
/// </summary>
|
||||
public const string Slider = "29E790E6-26B3-438A-B21F-908663A0B19E";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Tags datatype.
|
||||
/// </summary>
|
||||
public const string Tags = "4023E540-92F5-11DD-AD8B-0800200C9A66";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Textbox datatype.
|
||||
/// </summary>
|
||||
public const string Textbox = "EC15C1E5-9D90-422A-AA52-4F7622C63BEA";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Textbox multiple datatype.
|
||||
/// </summary>
|
||||
public const string TextboxMultiple = "67DB8357-EF57-493E-91AC-936D305E0F2A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the TinyMCE v3 wysiwyg datatype.
|
||||
/// </summary>
|
||||
public const string TinyMCEv3 = "5E9B75AE-FACE-41C8-B47E-5F4B0FD82F83";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the TinyMCE wysiwyg (deprecated, upgrade to tinymce v3!) datatype.
|
||||
/// </summary>
|
||||
public const string TinyMCE = "83722133-F80C-4273-BDB6-1BEFAA04A612";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the True/False (Ja/Nej) datatype.
|
||||
/// </summary>
|
||||
public const string TrueFalse = "38B352C1-E9F8-4FD8-9324-9A2EAB06D97A";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Ultimate Picker datatype.
|
||||
/// </summary>
|
||||
public const string UltimatePicker = "CDBF0B5D-5CB2-445F-BC12-FCAAEC07CF2C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the UltraSimpleEditor datatype.
|
||||
/// </summary>
|
||||
public const string UltraSimpleEditor = "60B7DABF-99CD-41EB-B8E9-4D2E669BBDE9";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Umbraco Usercontrol Wrapper datatype.
|
||||
/// </summary>
|
||||
public const string UmbracoUserControlWrapper = "D15E1281-E456-4B24-AA86-1DDA3E4299D5";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the Upload field datatype.
|
||||
/// </summary>
|
||||
public const string UploadField = "5032A6E6-69E3-491D-BB28-CD31CD11086C";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the XPath CheckBoxList datatype.
|
||||
/// </summary>
|
||||
public const string XPathCheckBoxList = "34451D92-D270-49BA-8C7F-EE55BFEEE1CB";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for the XPath DropDownList datatype.
|
||||
/// </summary>
|
||||
public const string XPathDropDownList = "173A96AE-00ED-4A7C-9F76-4B53D4A0A1B9";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public static partial class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the identifiers for Umbraco system nodes.
|
||||
/// </summary>
|
||||
public static class System
|
||||
{
|
||||
/// <summary>
|
||||
/// The integer identifier for global system root node.
|
||||
/// </summary>
|
||||
public const int Root = -1;
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for content's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinContent = -20;
|
||||
|
||||
/// <summary>
|
||||
/// The integer identifier for media's recycle bin.
|
||||
/// </summary>
|
||||
public const int RecycleBinMedia = -21;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Constants all the identifiers within the Umbraco core.
|
||||
/// </summary>
|
||||
public static partial class Constants
|
||||
{
|
||||
// generic constants can go here
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
@@ -9,10 +7,15 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSix;
|
||||
using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Macros;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Sync;
|
||||
using Umbraco.Core.Strings;
|
||||
using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -30,10 +33,21 @@ namespace Umbraco.Core
|
||||
private bool _isInitialized = false;
|
||||
private bool _isStarted = false;
|
||||
private bool _isComplete = false;
|
||||
|
||||
private readonly UmbracoApplicationBase _umbracoApplication;
|
||||
protected ApplicationContext ApplicationContext { get; private set; }
|
||||
|
||||
public virtual IBootManager Initialize()
|
||||
protected UmbracoApplicationBase UmbracoApplication
|
||||
{
|
||||
get { return _umbracoApplication; }
|
||||
}
|
||||
|
||||
public CoreBootManager(UmbracoApplicationBase umbracoApplication)
|
||||
{
|
||||
if (umbracoApplication == null) throw new ArgumentNullException("umbracoApplication");
|
||||
_umbracoApplication = umbracoApplication;
|
||||
}
|
||||
|
||||
public virtual IBootManager Initialize()
|
||||
{
|
||||
if (_isInitialized)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
@@ -49,22 +63,59 @@ namespace Umbraco.Core
|
||||
new PetaPocoUnitOfWorkProvider(dbFactory),
|
||||
new FileUnitOfWorkProvider(),
|
||||
new PublishingStrategy());
|
||||
|
||||
//create the ApplicationContext
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext);
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize();
|
||||
CreateApplicationContext(dbContext, serviceContext);
|
||||
|
||||
InitializeApplicationEventsResolver();
|
||||
|
||||
InitializeResolvers();
|
||||
|
||||
//initialize the DatabaseContext
|
||||
dbContext.Initialize();
|
||||
|
||||
//now we need to call the initialize methods
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationInitialized(UmbracoApplication, ApplicationContext));
|
||||
|
||||
_isInitialized = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates and assigns the application context singleton
|
||||
/// </summary>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
protected virtual void CreateApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext)
|
||||
{
|
||||
//create the ApplicationContext
|
||||
ApplicationContext = ApplicationContext.Current = new ApplicationContext(dbContext, serviceContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Special method to initialize the ApplicationEventsResolver and any modifications required for it such
|
||||
/// as adding custom types to the resolver.
|
||||
/// </summary>
|
||||
protected virtual void InitializeApplicationEventsResolver()
|
||||
{
|
||||
//find and initialize the application startup handlers, we need to initialize this resolver here because
|
||||
//it is a special resolver where they need to be instantiated first before any other resolvers in order to bind to
|
||||
//events and to call their events during bootup.
|
||||
//ApplicationStartupHandler.RegisterHandlers();
|
||||
//... and set the special flag to let us resolve before frozen resolution
|
||||
ApplicationEventsResolver.Current = new ApplicationEventsResolver(
|
||||
PluginManager.Current.ResolveApplicationStartupHandlers())
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
//add custom types here that are internal
|
||||
ApplicationEventsResolver.Current.AddType<PublishedContentHelper>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fires after initialization and calls the callback to allow for customizations to occur
|
||||
/// Fires after initialization and calls the callback to allow for customizations to occur &
|
||||
/// Ensure that the OnApplicationStarting methods of the IApplicationEvents are called
|
||||
/// </summary>
|
||||
/// <param name="afterStartup"></param>
|
||||
/// <returns></returns>
|
||||
@@ -73,10 +124,14 @@ namespace Umbraco.Core
|
||||
if (_isStarted)
|
||||
throw new InvalidOperationException("The boot manager has already been initialized");
|
||||
|
||||
if (afterStartup != null)
|
||||
{
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarting(UmbracoApplication, ApplicationContext));
|
||||
|
||||
if (afterStartup != null)
|
||||
{
|
||||
afterStartup(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isStarted = true;
|
||||
|
||||
@@ -93,68 +148,89 @@ namespace Umbraco.Core
|
||||
if (_isComplete)
|
||||
throw new InvalidOperationException("The boot manager has already been completed");
|
||||
|
||||
//freeze resolution to not allow Resolvers to be modified
|
||||
Resolution.Freeze();
|
||||
FreezeResolution();
|
||||
|
||||
//stop the timer and log the output
|
||||
_timer.Dispose();
|
||||
|
||||
if (afterComplete != null)
|
||||
{
|
||||
afterComplete(ApplicationContext.Current);
|
||||
}
|
||||
//call OnApplicationStarting of each application events handler
|
||||
ApplicationEventsResolver.Current.ApplicationEventHandlers
|
||||
.ForEach(x => x.OnApplicationStarted(UmbracoApplication, ApplicationContext));
|
||||
|
||||
//Now, startup all of our legacy startup handler
|
||||
ApplicationEventsResolver.Current.InstantiateLegacyStartupHanlders();
|
||||
|
||||
if (afterComplete != null)
|
||||
{
|
||||
afterComplete(ApplicationContext.Current);
|
||||
}
|
||||
|
||||
_isComplete = true;
|
||||
|
||||
// we're ready to serve content!
|
||||
ApplicationContext.IsReady = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Freeze resolution to not allow Resolvers to be modified
|
||||
/// </summary>
|
||||
protected virtual void FreezeResolution()
|
||||
{
|
||||
Resolution.Freeze();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create the resolvers
|
||||
/// </summary>
|
||||
protected virtual void InitializeResolvers()
|
||||
{
|
||||
//by default we'll use the standard configuration based sync
|
||||
ServerRegistrarResolver.Current = new ServerRegistrarResolver(
|
||||
new ConfigServerRegistrar());
|
||||
|
||||
//by default (outside of the web) we'll use the default server messenger without
|
||||
//supplying a username/password, this will automatically disable distributed calls
|
||||
// .. we'll override this in the WebBootManager
|
||||
ServerMessengerResolver.Current = new ServerMessengerResolver(
|
||||
new DefaultServerMessenger());
|
||||
|
||||
MappingResolver.Current = new MappingResolver(
|
||||
() => PluginManager.Current.ResolveAssignedMapperTypes());
|
||||
|
||||
RepositoryResolver.Current = new RepositoryResolver(
|
||||
new RepositoryFactory());
|
||||
|
||||
SqlSyntaxProvidersResolver.Current = new SqlSyntaxProvidersResolver(
|
||||
new[] { typeof(MySqlSyntaxProvider), typeof(SqlCeSyntaxProvider), typeof(SqlServerSyntaxProvider) })
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
|
||||
CacheRefreshersResolver.Current = new CacheRefreshersResolver(
|
||||
PluginManager.Current.ResolveCacheRefreshers());
|
||||
() => PluginManager.Current.ResolveCacheRefreshers());
|
||||
|
||||
DataTypesResolver.Current = new DataTypesResolver(
|
||||
PluginManager.Current.ResolveDataTypes());
|
||||
() => PluginManager.Current.ResolveDataTypes());
|
||||
|
||||
MacroFieldEditorsResolver.Current = new MacroFieldEditorsResolver(
|
||||
PluginManager.Current.ResolveMacroRenderings());
|
||||
() => PluginManager.Current.ResolveMacroRenderings());
|
||||
|
||||
PackageActionsResolver.Current = new PackageActionsResolver(
|
||||
PluginManager.Current.ResolvePackageActions());
|
||||
() => PluginManager.Current.ResolvePackageActions());
|
||||
|
||||
ActionsResolver.Current = new ActionsResolver(
|
||||
PluginManager.Current.ResolveActions());
|
||||
() => PluginManager.Current.ResolveActions());
|
||||
|
||||
MacroPropertyTypeResolver.Current = new MacroPropertyTypeResolver(
|
||||
PluginManager.Current.ResolveMacroPropertyTypes());
|
||||
|
||||
//TODO: Y U NO WORK?
|
||||
//MigrationResolver.Current = new MigrationResolver(
|
||||
// PluginManager.Current.ResolveMigrationTypes());
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(
|
||||
() => PluginManager.Current.ResolveMigrationTypes());
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(new List<Type>
|
||||
{
|
||||
typeof (MigrationsVersionFourNineZero.RemoveUmbracoAppConstraints),
|
||||
typeof (DeleteAppTables),
|
||||
typeof (EnsureAppsTreesUpdated),
|
||||
typeof (MoveMasterContentTypeData),
|
||||
typeof (NewCmsContentType2ContentTypeTable),
|
||||
typeof (RemoveMasterContentTypeColumn),
|
||||
typeof (RenameCmsTabTable),
|
||||
typeof (RenameTabIdColumn),
|
||||
typeof (UpdateCmsContentTypeAllowedContentTypeTable),
|
||||
typeof (UpdateCmsContentTypeTable),
|
||||
typeof (UpdateCmsContentVersionTable),
|
||||
typeof (UpdateCmsPropertyTypeGroupTable)
|
||||
});
|
||||
|
||||
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
@@ -162,6 +238,18 @@ namespace Umbraco.Core
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<DatePickerPropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<TinyMcePropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<YesNoPropertyEditorValueConverter>();
|
||||
}
|
||||
|
||||
// this is how we'd switch over to DefaultShortStringHelper _and_ still use
|
||||
// UmbracoSettings UrlReplaceCharacters...
|
||||
//ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
// new DefaultShortStringHelper().WithConfig(DefaultShortStringHelper.ApplyUrlReplaceCharacters));
|
||||
|
||||
// use the Legacy one for now
|
||||
ShortStringHelperResolver.Current = new ShortStringHelperResolver(
|
||||
new LegacyShortStringHelper());
|
||||
|
||||
UrlSegmentProviderResolver.Current = new UrlSegmentProviderResolver(
|
||||
typeof (DefaultUrlSegmentProvider));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Core
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="dataTypes"></param>
|
||||
internal DataTypesResolver(IEnumerable<Type> dataTypes)
|
||||
internal DataTypesResolver(Func<IEnumerable<Type>> dataTypes)
|
||||
: base(dataTypes)
|
||||
{
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureIdsAreTracked();
|
||||
EnsureIsInitialized();
|
||||
return Values;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
using Umbraco.Core.Persistence.Migrations.Initial;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -21,14 +22,15 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
public class DatabaseContext
|
||||
{
|
||||
private readonly IDatabaseFactory _factory;
|
||||
private bool _configured;
|
||||
private readonly IDatabaseFactory _factory;
|
||||
private bool _configured;
|
||||
private string _connectionString;
|
||||
private string _providerName;
|
||||
private DatabaseSchemaResult _result;
|
||||
|
||||
internal DatabaseContext(IDatabaseFactory factory)
|
||||
internal DatabaseContext(IDatabaseFactory factory)
|
||||
{
|
||||
_factory = factory;
|
||||
_factory = factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -107,10 +109,10 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Configure a ConnectionString for the embedded database.
|
||||
/// </summary>
|
||||
public void ConfigureDatabaseConnection()
|
||||
public void ConfigureEmbeddedDatabaseConnection()
|
||||
{
|
||||
const string providerName = "System.Data.SqlServerCe.4.0";
|
||||
const string connectionString = "Datasource=|DataDirectory|Umbraco.sdf";
|
||||
const string connectionString = @"Data Source=|DataDirectory|\Umbraco.sdf";
|
||||
|
||||
SaveConnectionString(connectionString, providerName);
|
||||
|
||||
@@ -149,14 +151,14 @@ namespace Umbraco.Core
|
||||
{
|
||||
string connectionString;
|
||||
string providerName = "System.Data.SqlClient";
|
||||
if(databaseProvider.ToLower().Contains("mysql"))
|
||||
if (databaseProvider.ToLower().Contains("mysql"))
|
||||
{
|
||||
providerName = "MySql.Data.MySqlClient";
|
||||
connectionString = string.Format("Server={0}; Database={1};Uid={2};Pwd={3}", server, databaseName, user, password);
|
||||
}
|
||||
else if(databaseProvider.ToLower().Contains("azure"))
|
||||
else if (databaseProvider.ToLower().Contains("azure"))
|
||||
{
|
||||
connectionString = string.Format("Server=tcp:{0}.database.windows.net;Database={1};User ID={2}@{0};Password={3}", server, databaseName, user, password);
|
||||
connectionString = BuildAzureConnectionString(server, databaseName, user, password);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -167,6 +169,52 @@ namespace Umbraco.Core
|
||||
Initialize(providerName);
|
||||
}
|
||||
|
||||
internal string BuildAzureConnectionString(string server, string databaseName, string user, string password)
|
||||
{
|
||||
if (server.Contains(".") && ServerStartsWithTcp(server) == false)
|
||||
server = string.Format("tcp:{0}", server);
|
||||
|
||||
if (server.Contains(".") == false && ServerStartsWithTcp(server))
|
||||
{
|
||||
string serverName = server.Contains(",")
|
||||
? server.Substring(0, server.IndexOf(",", StringComparison.Ordinal))
|
||||
: server;
|
||||
|
||||
var portAddition = string.Empty;
|
||||
|
||||
if (server.Contains(","))
|
||||
portAddition = server.Substring(server.IndexOf(",", StringComparison.Ordinal));
|
||||
|
||||
server = string.Format("{0}.database.windows.net{1}", serverName, portAddition);
|
||||
}
|
||||
|
||||
if (ServerStartsWithTcp(server) == false)
|
||||
server = string.Format("tcp:{0}.database.windows.net", server);
|
||||
|
||||
if (server.Contains(",") == false)
|
||||
server = string.Format("{0},1433", server);
|
||||
|
||||
if (user.Contains("@") == false)
|
||||
{
|
||||
var userDomain = server;
|
||||
|
||||
if (ServerStartsWithTcp(server))
|
||||
userDomain = userDomain.Substring(userDomain.IndexOf(":", StringComparison.Ordinal) + 1);
|
||||
|
||||
if (userDomain.Contains("."))
|
||||
userDomain = userDomain.Substring(0, userDomain.IndexOf(".", StringComparison.Ordinal));
|
||||
|
||||
user = string.Format("{0}@{1}", user, userDomain);
|
||||
}
|
||||
|
||||
return string.Format("Server={0};Database={1};User ID={2};Password={3}", server, databaseName, user, password);
|
||||
}
|
||||
|
||||
private static bool ServerStartsWithTcp(string server)
|
||||
{
|
||||
return server.ToLower().StartsWith("tcp:".ToLower());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the connection string as a proper .net ConnectionString and the legacy AppSettings key/value.
|
||||
/// </summary>
|
||||
@@ -204,7 +252,7 @@ namespace Umbraco.Core
|
||||
// Update connectionString if it exists, or else create a new appSetting for the given key and value
|
||||
var setting = connectionstrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == GlobalSettings.UmbracoConnectionName);
|
||||
if (setting == null)
|
||||
connectionstrings.Add(new XElement("add",
|
||||
connectionstrings.Add(new XElement("add",
|
||||
new XAttribute("name", GlobalSettings.UmbracoConnectionName),
|
||||
new XAttribute("connectionString", connectionStringSettings),
|
||||
new XAttribute("providerName", providerName)));
|
||||
@@ -216,7 +264,7 @@ namespace Umbraco.Core
|
||||
|
||||
xml.Save(fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Configured new ConnectionString: " + connectionString);
|
||||
LogHelper.Info<DatabaseContext>("Configured a new ConnectionString using the '" + providerName + "' provider.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -230,7 +278,8 @@ namespace Umbraco.Core
|
||||
/// </remarks>
|
||||
internal void Initialize()
|
||||
{
|
||||
if (ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName] != null)
|
||||
var databaseSettings = ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName];
|
||||
if (databaseSettings != null && string.IsNullOrWhiteSpace(databaseSettings.ConnectionString) == false && string.IsNullOrWhiteSpace(databaseSettings.ProviderName) == false)
|
||||
{
|
||||
var providerName = "System.Data.SqlClient";
|
||||
if (!string.IsNullOrEmpty(ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ProviderName))
|
||||
@@ -239,23 +288,46 @@ namespace Umbraco.Core
|
||||
|
||||
_connectionString =
|
||||
ConfigurationManager.ConnectionStrings[GlobalSettings.UmbracoConnectionName].ConnectionString;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if (providerName.StartsWith("MySql"))
|
||||
Initialize(providerName);
|
||||
}
|
||||
else if (ConfigurationManager.AppSettings.ContainsKey(GlobalSettings.UmbracoConnectionName) && string.IsNullOrEmpty(ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName]) == false)
|
||||
{
|
||||
//A valid connectionstring does not exist, but the legacy appSettings key was found, so we'll reconfigure the conn.string.
|
||||
var legacyConnString = ConfigurationManager.AppSettings[GlobalSettings.UmbracoConnectionName];
|
||||
if (legacyConnString.ToLowerInvariant().Contains("sqlce4umbraco"))
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = MySqlSyntax.Provider;
|
||||
ConfigureEmbeddedDatabaseConnection();
|
||||
}
|
||||
else if (providerName.Contains("SqlServerCe"))
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("tcp:"))
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
|
||||
//Must be sql azure
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
Initialize("System.Data.SqlClient");
|
||||
}
|
||||
else if (legacyConnString.ToLowerInvariant().Contains("datalayer=mysql"))
|
||||
{
|
||||
//Must be MySql
|
||||
|
||||
//Need to strip the datalayer part off
|
||||
var connectionStringWithoutDatalayer = string.Empty;
|
||||
foreach (var variable in legacyConnString.Split(';').Where(x => x.ToLowerInvariant().StartsWith("datalayer") == false))
|
||||
connectionStringWithoutDatalayer = string.Format("{0}{1};", connectionStringWithoutDatalayer, variable);
|
||||
|
||||
SaveConnectionString(connectionStringWithoutDatalayer, "MySql.Data.MySqlClient");
|
||||
Initialize("MySql.Data.MySqlClient");
|
||||
}
|
||||
else
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlServerSyntax.Provider;
|
||||
//Must be sql
|
||||
SaveConnectionString(legacyConnString, "System.Data.SqlClient");
|
||||
Initialize("System.Data.SqlClient");
|
||||
}
|
||||
|
||||
_configured = true;
|
||||
//Remove the legacy connection string, so we don't end up in a loop if something goes wrong.
|
||||
GlobalSettings.RemoveSetting(GlobalSettings.UmbracoConnectionName);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -265,50 +337,136 @@ namespace Umbraco.Core
|
||||
|
||||
internal void Initialize(string providerName)
|
||||
{
|
||||
if (providerName.StartsWith("MySql"))
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = MySqlSyntax.Provider;
|
||||
}
|
||||
else if (providerName.Contains("SqlServerCe"))
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlCeSyntax.Provider;
|
||||
}
|
||||
else
|
||||
{
|
||||
SyntaxConfig.SqlSyntaxProvider = SqlServerSyntax.Provider;
|
||||
}
|
||||
_providerName = providerName;
|
||||
|
||||
_configured = true;
|
||||
try
|
||||
{
|
||||
SqlSyntaxContext.SqlSyntaxProvider =
|
||||
SqlSyntaxProvidersResolver.Current.GetByProviderNameOrDefault(providerName);
|
||||
|
||||
_configured = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_configured = false;
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Initialization of the DatabaseContext failed with following error: " + e.Message);
|
||||
LogHelper.Info<DatabaseContext>(e.StackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
internal DatabaseSchemaResult ValidateDatabaseSchema()
|
||||
{
|
||||
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
|
||||
return new DatabaseSchemaResult();
|
||||
|
||||
if (_result == null)
|
||||
{
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
var dbSchema = new DatabaseSchemaCreation(database);
|
||||
_result = dbSchema.ValidateSchema();
|
||||
}
|
||||
return _result;
|
||||
}
|
||||
|
||||
internal Result CreateDatabaseSchemaAndDataOrUpgrade()
|
||||
{
|
||||
if (_configured == false || (string.IsNullOrEmpty(_connectionString) || string.IsNullOrEmpty(ProviderName)))
|
||||
{
|
||||
return new Result{Message = "Database configuration is invalid", Success = false, Percentage = "10"};
|
||||
return new Result
|
||||
{
|
||||
Message =
|
||||
"Database configuration is invalid. Please check that the entered database exists and that the provided username and password has write access to the database.",
|
||||
Success = false,
|
||||
Percentage = "10"
|
||||
};
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: Started");
|
||||
|
||||
var message = string.Empty;
|
||||
|
||||
var database = new UmbracoDatabase(_connectionString, ProviderName);
|
||||
//If Configuration Status is empty its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus))
|
||||
var supportsCaseInsensitiveQueries = SqlSyntaxContext.SqlSyntaxProvider.SupportsCaseInsensitiveQueries(database);
|
||||
if (supportsCaseInsensitiveQueries == false)
|
||||
{
|
||||
database.CreateDatabaseSchema();
|
||||
message = "<p> </p><p>The database you're trying to use does not support case insensitive queries. <br />We currently do not support these types of databases.</p>" +
|
||||
"<p>You can fix this by changing the following two settings in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
|
||||
return new Result { Message = message, Success = false, Percentage = "15" };
|
||||
}
|
||||
else if (supportsCaseInsensitiveQueries == null)
|
||||
{
|
||||
message = "<p> </p><p>Warning! Could not check if your database type supports case insensitive queries. <br />We currently do not support these databases that do not support case insensitive queries.</p>" +
|
||||
"<p>You can check this by looking for the following two settings in your my.ini file in your MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
|
||||
"<p>Note: Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
else
|
||||
{
|
||||
var configuredVersion = new Version(GlobalSettings.ConfigurationStatus);
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider.GetType() == typeof(MySqlSyntaxProvider))
|
||||
{
|
||||
message = "<p> </p><p>Congratulations, the database step ran successfully!</p>" +
|
||||
"<p>Note: You're using MySQL and the database instance you're connecting to seems to support case insensitive queries.</p>" +
|
||||
"<p>However, your hosting provider may not support this option. Umbraco does not currently support MySQL installs that do not support case insensitive queries</p>" +
|
||||
"<p>Make sure to check with your hosting provider if they support case insensitive queries as well.</p>" +
|
||||
"<p>They can check this by looking for the following two settings in the my.ini file in their MySQL installation directory:</p>" +
|
||||
"<pre>lower_case_table_names=1\nlower_case_file_system=1</pre><br />" +
|
||||
"<p>For more technical information on case sensitivity in MySQL, have a look at " +
|
||||
"<a href='http://dev.mysql.com/doc/refman/5.0/en/identifier-case-sensitivity.html'>the documentation on the subject</a></p>";
|
||||
}
|
||||
}
|
||||
|
||||
var schemaResult = ValidateDatabaseSchema();
|
||||
var installedVersion = schemaResult.DetermineInstalledVersion();
|
||||
|
||||
|
||||
//If Configuration Status is empty and the determined version is "empty" its a new install - otherwise upgrade the existing
|
||||
if (string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus) && installedVersion.Equals(new Version(0, 0, 0)))
|
||||
{
|
||||
database.CreateDatabaseSchema();
|
||||
message = message + "<p>Installation completed!</p>";
|
||||
}
|
||||
else
|
||||
{
|
||||
var configuredVersion = string.IsNullOrEmpty(GlobalSettings.ConfigurationStatus)
|
||||
? installedVersion
|
||||
: new Version(GlobalSettings.ConfigurationStatus);
|
||||
var targetVersion = UmbracoVersion.Current;
|
||||
var runner = new MigrationRunner(configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName);
|
||||
var upgraded = runner.Execute(database, true);
|
||||
message = message + "<p>Upgrade completed!</p>";
|
||||
}
|
||||
|
||||
return new Result { Message = "Installation completed!", Success = true, Percentage = "100" };
|
||||
|
||||
LogHelper.Info<DatabaseContext>("Database configuration status: " + message);
|
||||
|
||||
return new Result { Message = message, Success = true, Percentage = "100" };
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new Result { Message = ex.Message, Success = false, Percentage = "90" };
|
||||
LogHelper.Info<DatabaseContext>("Database configuration failed with the following error and stack trace: " + ex.Message + "\n" + ex.StackTrace);
|
||||
|
||||
if (_result != null)
|
||||
{
|
||||
LogHelper.Info<DatabaseContext>("The database schema validation produced the following summary: \n" + _result.GetSummary());
|
||||
}
|
||||
|
||||
return new Result
|
||||
{
|
||||
Message =
|
||||
"The database configuration failed with the following message: " + ex.Message +
|
||||
"\n Please check log file for additional information (can be found in '/App_Data/Logs/UmbracoTraceLog.txt')",
|
||||
Success = false,
|
||||
Percentage = "90"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Dictionary
|
||||
/// <summary>
|
||||
/// Resolves the current CultureDictionaryFactory
|
||||
/// </summary>
|
||||
internal class CultureDictionaryFactoryResolver : SingleObjectResolverBase<CultureDictionaryFactoryResolver, ICultureDictionaryFactory>
|
||||
internal sealed class CultureDictionaryFactoryResolver : SingleObjectResolverBase<CultureDictionaryFactoryResolver, ICultureDictionaryFactory>
|
||||
{
|
||||
internal CultureDictionaryFactoryResolver(ICultureDictionaryFactory factory)
|
||||
: base(factory)
|
||||
|
||||
@@ -9,35 +9,106 @@ using System.Xml.XPath;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
[TypeConverter(typeof(DynamicXmlConverter))]
|
||||
public class DynamicXml : DynamicObject, IEnumerable<DynamicXml>, IEnumerable<XElement>
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns the XElement used to create the DynamicXml structure
|
||||
/// </summary>
|
||||
public XElement BaseElement { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the raw XElement used to create the DynamicXml structure if one was specified otherwise returns the
|
||||
/// same value as BaseElement.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is purely used for when an instance of DynamicXml is created with the overload that supports
|
||||
/// passing in both a raw xml version and a dash-stripped xml version. Otherwise this value is exactly the
|
||||
/// same as BaseElement.
|
||||
/// </remarks>
|
||||
public XElement RawXmlElement { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="baseElement"></param>
|
||||
public DynamicXml(XElement baseElement)
|
||||
{
|
||||
this.BaseElement = baseElement;
|
||||
if (baseElement == null) return;
|
||||
|
||||
//same
|
||||
RawXmlElement = baseElement;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
public DynamicXml(string xml)
|
||||
|
||||
/// <summary>
|
||||
/// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure
|
||||
/// </summary>
|
||||
/// <param name="strippedXml"></param>
|
||||
/// <param name="rawXml"></param>
|
||||
internal DynamicXml(XElement strippedXml, XElement rawXml)
|
||||
{
|
||||
var baseElement = XElement.Parse(xml);
|
||||
this.BaseElement = baseElement;
|
||||
if (rawXml == null) return;
|
||||
if (strippedXml == null) return;
|
||||
|
||||
RawXmlElement = rawXml;
|
||||
BaseElement = strippedXml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// When this constructor is used the BaseElement becomes equivalent to the strippedXml structure
|
||||
/// </summary>
|
||||
/// <param name="strippedXml"></param>
|
||||
/// <param name="rawXml"></param>
|
||||
internal DynamicXml(string strippedXml, string rawXml)
|
||||
{
|
||||
if (rawXml == null) return;
|
||||
if (strippedXml == null) return;
|
||||
|
||||
RawXmlElement = XElement.Parse(rawXml);
|
||||
BaseElement = XElement.Parse(strippedXml);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="xml"></param>
|
||||
public DynamicXml(string xml)
|
||||
{
|
||||
if (xml.IsNullOrWhiteSpace()) return;
|
||||
|
||||
var baseElement = XElement.Parse(xml);
|
||||
|
||||
//same
|
||||
RawXmlElement = baseElement;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="xpni"></param>
|
||||
public DynamicXml(XPathNodeIterator xpni)
|
||||
{
|
||||
if (xpni != null)
|
||||
{
|
||||
if (xpni.Current != null)
|
||||
{
|
||||
var xml = xpni.Current.OuterXml;
|
||||
var baseElement = XElement.Parse(xml);
|
||||
this.BaseElement = baseElement;
|
||||
}
|
||||
}
|
||||
if (xpni == null) return;
|
||||
if (xpni.Current == null) return;
|
||||
|
||||
//TODO: OuterXml is really bad for performance! Should actually use the XPathNodeIterator api
|
||||
var xml = xpni.Current.OuterXml;
|
||||
var baseElement = XElement.Parse(xml);
|
||||
|
||||
//same
|
||||
RawXmlElement = baseElement;
|
||||
BaseElement = baseElement;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the InnertText based on the BaseElement object
|
||||
/// </summary>
|
||||
public string InnerText
|
||||
{
|
||||
get
|
||||
@@ -45,17 +116,34 @@ namespace Umbraco.Core.Dynamics
|
||||
return BaseElement.Value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string representation of the BaseElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ToXml()
|
||||
{
|
||||
return BaseElement.ToString(SaveOptions.DisableFormatting);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string representation of the RawXmlElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string ToRawXml()
|
||||
{
|
||||
return RawXmlElement.ToString(SaveOptions.DisableFormatting);
|
||||
}
|
||||
|
||||
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
|
||||
{
|
||||
int index = 0;
|
||||
if (indexes.Length > 0)
|
||||
{
|
||||
index = (int)indexes[0];
|
||||
result = new DynamicXml(this.BaseElement.Elements().ToList()[index]);
|
||||
result = new DynamicXml(
|
||||
RawXmlElement.Elements().ElementAt(index),
|
||||
BaseElement.Elements().ElementAt(index));
|
||||
return true;
|
||||
}
|
||||
return base.TryGetIndex(binder, indexes, out result);
|
||||
@@ -64,12 +152,12 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
if (args.Length == 0 && binder.Name == "ToXml")
|
||||
{
|
||||
result = this.BaseElement.ToString();
|
||||
result = BaseElement.ToString();
|
||||
return true;
|
||||
}
|
||||
if (args.Length == 1 && binder.Name == "XPath")
|
||||
{
|
||||
var elements = this.BaseElement.XPathSelectElements(args[0].ToString());
|
||||
var elements = BaseElement.XPathSelectElements(args[0].ToString());
|
||||
HandleIEnumerableXElement(elements, out result);
|
||||
return true; //anyway
|
||||
}
|
||||
@@ -102,7 +190,9 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
else if (attempt.Result.ObjectResult is IEnumerable<DynamicXml>)
|
||||
{
|
||||
result = ((IEnumerable<DynamicXml>)attempt.Result.ObjectResult).Select(x => new DynamicXml(x.BaseElement));
|
||||
result = ((IEnumerable<DynamicXml>) attempt.Result.ObjectResult).Select(x => new DynamicXml(
|
||||
x.RawXmlElement,
|
||||
x.BaseElement));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -123,55 +213,102 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
if (BaseElement == null || binder == null)
|
||||
if (RawXmlElement == null || binder == null)
|
||||
{
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
//Go ahead and try to fetch all of the elements matching the member name, and wrap them
|
||||
var elements = BaseElement.Elements(binder.Name);
|
||||
if (!elements.Any() && BaseElement.Name == "root" && BaseElement.Elements().Count() == 1)
|
||||
{
|
||||
//no elements matched, lets try first child
|
||||
elements = BaseElement.Elements().ElementAt(0).Elements(binder.Name);
|
||||
}
|
||||
if (HandleIEnumerableXElement(elements, out result))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
//Ok, so no elements matched, so lets try attributes
|
||||
IEnumerable<string> attributes = BaseElement.Attributes(binder.Name).Select(attr => attr.Value);
|
||||
int count = attributes.Count();
|
||||
|
||||
if (count > 0)
|
||||
//Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped)
|
||||
var elementByNameAttempt = CheckNodeNameMatch(binder.Name, BaseElement);
|
||||
if (elementByNameAttempt.Success)
|
||||
{
|
||||
if (HandleIEnumerableXElement(elementByNameAttempt.Result, out result))
|
||||
{
|
||||
if (count > 1)
|
||||
result = attributes; //more than one attribute matched, lets return the collection
|
||||
else
|
||||
result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // return true because we matched
|
||||
//Check if the name matches a node based on the BaseElement (which if the correct ctor is used, will be dash stripped)
|
||||
var attributeByNameAttempt = CheckAttributeNameMatch(binder.Name, BaseElement);
|
||||
if (attributeByNameAttempt.Success)
|
||||
{
|
||||
if (attributeByNameAttempt.Result.Count() > 1)
|
||||
{
|
||||
//more than one attribute matched, lets return the collection
|
||||
result = attributeByNameAttempt.Result;
|
||||
}
|
||||
else
|
||||
{
|
||||
//no attributes matched, lets try first child
|
||||
if (BaseElement.Name == "root" && BaseElement.Elements().Count() == 1)
|
||||
{
|
||||
attributes = BaseElement.Elements().ElementAt(0).Attributes(binder.Name).Select(attr => attr.Value);
|
||||
count = attributes.Count();
|
||||
if (count > 1)
|
||||
result = attributes; //more than one attribute matched, lets return the collection
|
||||
else
|
||||
result = attributes.FirstOrDefault(); //only one attribute matched, lets just return it
|
||||
//only one attribute matched, lets just return it
|
||||
result = attributeByNameAttempt.Result.FirstOrDefault();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return true; // return true because we matched
|
||||
}
|
||||
return base.TryGetMember(binder, out result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the 'name' matches any attributes of xmlElement
|
||||
/// </summary>
|
||||
/// <param name="name">The name to match</param>
|
||||
/// <param name="xmlElement">The xml element to check against</param>
|
||||
/// <returns></returns>
|
||||
private static Attempt<IEnumerable<string>> CheckAttributeNameMatch(string name, XElement xmlElement)
|
||||
{
|
||||
var attributes = xmlElement.Attributes(name).Select(attr => attr.Value).ToArray();
|
||||
if (attributes.Any())
|
||||
{
|
||||
return new Attempt<IEnumerable<string>>(true, attributes);
|
||||
}
|
||||
|
||||
if (!attributes.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
|
||||
{
|
||||
//no elements matched and this node is called 'root' and only has one child... lets see if it matches.
|
||||
var childElements = xmlElement.Elements().ElementAt(0).Attributes(name).Select(attr => attr.Value).ToArray();
|
||||
if (childElements.Any())
|
||||
{
|
||||
//we've found a match by the first child of an element called 'root' (strange, but sure)
|
||||
return new Attempt<IEnumerable<string>>(true, childElements);
|
||||
}
|
||||
}
|
||||
|
||||
//no deal
|
||||
return Attempt<IEnumerable<string>>.False;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the 'name' matches any elements of xmlElement
|
||||
/// </summary>
|
||||
/// <param name="name">The name to match</param>
|
||||
/// <param name="xmlElement">The xml element to check against</param>
|
||||
/// <returns></returns>
|
||||
private Attempt<IEnumerable<XElement>> CheckNodeNameMatch(string name, XElement xmlElement)
|
||||
{
|
||||
//Go ahead and try to fetch all of the elements matching the member name, and wrap them
|
||||
var elements = xmlElement.Elements(name).ToArray();
|
||||
|
||||
//Check if we've got any matches, if so then return true
|
||||
if (elements.Any())
|
||||
{
|
||||
return new Attempt<IEnumerable<XElement>>(true, elements);
|
||||
}
|
||||
|
||||
if (!elements.Any() && xmlElement.Name == "root" && xmlElement.Elements().Count() == 1)
|
||||
{
|
||||
//no elements matched and this node is called 'root' and only has one child... lets see if it matches.
|
||||
var childElements = xmlElement.Elements().ElementAt(0).Elements(name).ToArray();
|
||||
if (childElements.Any())
|
||||
{
|
||||
//we've found a match by the first child of an element called 'root' (strange, but sure)
|
||||
return new Attempt<IEnumerable<XElement>>(true, childElements);
|
||||
}
|
||||
}
|
||||
return base.TryGetMember(binder, out result);
|
||||
|
||||
//no deal
|
||||
return Attempt<IEnumerable<XElement>>.False;
|
||||
}
|
||||
|
||||
private bool HandleIEnumerableXElement(IEnumerable<XElement> elements, out object result)
|
||||
@@ -193,7 +330,7 @@ namespace Umbraco.Core.Dynamics
|
||||
//We have more than one matching element, so let's return the collection
|
||||
//elements is IEnumerable<DynamicXml>
|
||||
//but we want to be able to re-enter this code
|
||||
XElement root = new XElement(XName.Get("root"));
|
||||
var root = new XElement(XName.Get("root"));
|
||||
root.Add(elements);
|
||||
result = new DynamicXml(root);
|
||||
|
||||
@@ -205,10 +342,16 @@ namespace Umbraco.Core.Dynamics
|
||||
result = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes an XPath expression over the BaseElement object
|
||||
/// </summary>
|
||||
/// <param name="expression"></param>
|
||||
/// <returns></returns>
|
||||
public DynamicXml XPath(string expression)
|
||||
{
|
||||
var matched = this.BaseElement.XPathSelectElements(expression);
|
||||
DynamicXml root = new DynamicXml("<results/>");
|
||||
var matched = BaseElement.XPathSelectElements(expression);
|
||||
var root = new DynamicXml("<results/>");
|
||||
foreach (var element in matched)
|
||||
{
|
||||
root.BaseElement.Add(element);
|
||||
@@ -217,7 +360,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the string version of Xml
|
||||
/// Return the string version of the BaseElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
@@ -231,23 +374,23 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public DynamicXml Find(string expression)
|
||||
{
|
||||
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
}
|
||||
|
||||
public DynamicXml Find(string attributeName, object value)
|
||||
{
|
||||
string expression = string.Format("//*[{0}='{1}']", attributeName, value);
|
||||
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
return new DynamicXml(BaseElement.XPathSelectElements(expression).FirstOrDefault());
|
||||
}
|
||||
|
||||
IEnumerator<XElement> IEnumerable<XElement>.GetEnumerator()
|
||||
{
|
||||
return this.BaseElement.Elements().GetEnumerator();
|
||||
return BaseElement.Elements().GetEnumerator();
|
||||
}
|
||||
|
||||
public IEnumerator<DynamicXml> GetEnumerator()
|
||||
{
|
||||
return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
|
||||
return BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
@@ -310,7 +453,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public bool IsPosition(int index)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -318,7 +461,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsPosition(int index, string valueIfTrue)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
@@ -326,7 +469,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsPosition(int index, string valueIfTrue, string valueIfFalse)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(valueIfFalse);
|
||||
}
|
||||
@@ -334,7 +477,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public bool IsModZero(int modulus)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -342,7 +485,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsModZero(int modulus, string valueIfTrue)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
@@ -350,7 +493,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsModZero(int modulus, string valueIfTrue, string valueIfFalse)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(valueIfFalse);
|
||||
}
|
||||
@@ -359,7 +502,7 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
public bool IsNotModZero(int modulus)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || BaseElement.Parent == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -367,7 +510,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public HtmlString IsNotModZero(int modulus, string valueIfTrue)
|
||||
{
|
||||
if (this.BaseElement == null || this.BaseElement.Parent == null)
|
||||
if (BaseElement == null || this.BaseElement.Parent == null)
|
||||
{
|
||||
return new HtmlString(string.Empty);
|
||||
}
|
||||
@@ -573,7 +716,8 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public IEnumerable<DynamicXml> Descendants(Func<XElement, bool> func)
|
||||
{
|
||||
var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); });
|
||||
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
|
||||
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
|
||||
return flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n));
|
||||
}
|
||||
public IEnumerable<DynamicXml> DescendantsOrSelf()
|
||||
@@ -582,7 +726,8 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
public IEnumerable<DynamicXml> DescendantsOrSelf(Func<XElement, bool> func)
|
||||
{
|
||||
var flattenedNodes = this.BaseElement.Elements().Map(func, (XElement n) => { return n.Elements(); });
|
||||
//var flattenedNodes = this.BaseElement.Elements().Map(func, n => n.Elements());
|
||||
var flattenedNodes = this.BaseElement.Elements().SelectMany(n => n.Elements()).Where(func);
|
||||
var list = new List<DynamicXml>();
|
||||
list.Add(this);
|
||||
list.AddRange(flattenedNodes.ToList().ConvertAll(n => new DynamicXml(n)));
|
||||
@@ -689,57 +834,10 @@ namespace Umbraco.Core.Dynamics
|
||||
return test(this) ? new HtmlString(valueIfTrue) : new HtmlString(valueIfFalse);
|
||||
}
|
||||
|
||||
[Obsolete("Use XmlHelper.StripDashesInElementOrAttributeNames instead")]
|
||||
public static string StripDashesInElementOrAttributeNames(string xml)
|
||||
{
|
||||
using (MemoryStream outputms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter outputtw = new StreamWriter(outputms))
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
using (TextWriter tw = new StreamWriter(ms))
|
||||
{
|
||||
tw.Write(xml);
|
||||
tw.Flush();
|
||||
ms.Position = 0;
|
||||
using (TextReader tr = new StreamReader(ms))
|
||||
{
|
||||
bool IsInsideElement = false, IsInsideQuotes = false;
|
||||
int ic = 0;
|
||||
while ((ic = tr.Read()) != -1)
|
||||
{
|
||||
if (ic == (int)'<' && !IsInsideQuotes)
|
||||
{
|
||||
if (tr.Peek() != (int)'!')
|
||||
{
|
||||
IsInsideElement = true;
|
||||
}
|
||||
}
|
||||
if (ic == (int)'>' && !IsInsideQuotes)
|
||||
{
|
||||
IsInsideElement = false;
|
||||
}
|
||||
if (ic == (int)'"')
|
||||
{
|
||||
IsInsideQuotes = !IsInsideQuotes;
|
||||
}
|
||||
if (!IsInsideElement || ic != (int)'-' || IsInsideQuotes)
|
||||
{
|
||||
outputtw.Write((char)ic);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
outputtw.Flush();
|
||||
outputms.Position = 0;
|
||||
using (TextReader outputtr = new StreamReader(outputms))
|
||||
{
|
||||
return outputtr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
return XmlHelper.StripDashesInElementOrAttributeNames(xml);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,58 @@ using System.Xml.Linq;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to return the raw xml string value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXmlString
|
||||
{
|
||||
public string Value { get; private set; }
|
||||
|
||||
public RawXmlString(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to return the raw xml XElement value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXElement
|
||||
{
|
||||
public XElement Value { get; private set; }
|
||||
|
||||
public RawXElement(XElement value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to return the raw xml XElement value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXmlElement
|
||||
{
|
||||
public XmlElement Value { get; private set; }
|
||||
|
||||
public RawXmlElement(XmlElement value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to return the raw xml XmlDocument value from DynamicXml when using type converters
|
||||
/// </summary>
|
||||
public class RawXmlDocument
|
||||
{
|
||||
public XmlDocument Value { get; private set; }
|
||||
|
||||
public RawXmlDocument(XmlDocument value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom type converter for DynamicXml
|
||||
/// </summary>
|
||||
@@ -14,7 +66,17 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
var convertableTypes = new[] {typeof(string), typeof(XElement), typeof(XmlElement), typeof(XmlDocument)};
|
||||
var convertableTypes = new[]
|
||||
{
|
||||
typeof(string),
|
||||
typeof(XElement),
|
||||
typeof(XmlElement),
|
||||
typeof(XmlDocument),
|
||||
typeof(RawXmlString),
|
||||
typeof(RawXElement),
|
||||
typeof(RawXmlElement),
|
||||
typeof(RawXmlDocument)
|
||||
};
|
||||
|
||||
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType))
|
||||
|| base.CanConvertFrom(context, sourceType);
|
||||
@@ -34,6 +96,7 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
//XElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<XElement>(destinationType))
|
||||
{
|
||||
@@ -53,6 +116,34 @@ namespace Umbraco.Core.Dynamics
|
||||
xDoc.LoadXml(dxml.ToString());
|
||||
return xDoc;
|
||||
}
|
||||
|
||||
//RAW values:
|
||||
//string
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXmlString>(destinationType))
|
||||
{
|
||||
return new RawXmlString(dxml.ToRawXml());
|
||||
}
|
||||
//XElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXElement>(destinationType))
|
||||
{
|
||||
return new RawXElement(dxml.RawXmlElement);
|
||||
}
|
||||
//XmlElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXmlElement>(destinationType))
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
xDoc.LoadXml(dxml.ToRawXml());
|
||||
return new RawXmlElement(xDoc.DocumentElement);
|
||||
}
|
||||
//XmlDocument
|
||||
if (TypeHelper.IsTypeAssignableFrom<RawXmlDocument>(destinationType))
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
xDoc.LoadXml(dxml.ToRawXml());
|
||||
return new RawXmlDocument(xDoc);
|
||||
}
|
||||
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,36 +5,35 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
[Obsolete("This class should not be used, it is just referenced by already obsoleted code and will be removed in the future")]
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
public static IEnumerable<TSource> Map<TSource>(
|
||||
this IEnumerable<TSource> source,
|
||||
Func<TSource, bool> selectorFunction,
|
||||
Func<TSource, IEnumerable<TSource>> getChildrenFunction)
|
||||
{
|
||||
if (!source.Any())
|
||||
{
|
||||
return source;
|
||||
}
|
||||
// Add what we have to the stack
|
||||
var flattenedList = source.Where(selectorFunction);
|
||||
// Go through the input enumerable looking for children,
|
||||
// and add those if we have them
|
||||
foreach (TSource element in source)
|
||||
{
|
||||
var secondInner = getChildrenFunction(element);
|
||||
if (secondInner.Any())
|
||||
{
|
||||
secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
|
||||
}
|
||||
flattenedList = flattenedList.Concat(secondInner);
|
||||
}
|
||||
return flattenedList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//public static IEnumerable<TSource> Map<TSource>(
|
||||
// this IEnumerable<TSource> source,
|
||||
// Func<TSource, bool> selectorFunction,
|
||||
// Func<TSource, IEnumerable<TSource>> getChildrenFunction)
|
||||
//{
|
||||
// if (!source.Any())
|
||||
// {
|
||||
// return source;
|
||||
// }
|
||||
// // Add what we have to the stack
|
||||
// var flattenedList = source.Where(selectorFunction);
|
||||
// // Go through the input enumerable looking for children,
|
||||
// // and add those if we have them
|
||||
// foreach (TSource element in source)
|
||||
// {
|
||||
// var secondInner = getChildrenFunction(element);
|
||||
// if (secondInner.Any())
|
||||
// {
|
||||
// secondInner = secondInner.Map(selectorFunction, getChildrenFunction);
|
||||
// }
|
||||
// flattenedList = flattenedList.Concat(secondInner);
|
||||
// }
|
||||
// return flattenedList;
|
||||
//}
|
||||
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, IEnumerable<string> needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -44,6 +43,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, params string[] needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -53,6 +53,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, StringComparison comparison, IEnumerable<string> needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -62,6 +63,7 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsAny(this string haystack, StringComparison comparison, params string[] needles)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
@@ -71,12 +73,13 @@ namespace Umbraco.Core.Dynamics
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool ContainsInsensitive(this string haystack, string needle)
|
||||
{
|
||||
if (haystack == null) throw new ArgumentNullException("haystack");
|
||||
return haystack.IndexOf(needle, StringComparison.CurrentCultureIgnoreCase) >= 0;
|
||||
}
|
||||
|
||||
[Obsolete("This method should not be used and will be removed in the future")]
|
||||
public static bool HasValue(this string s)
|
||||
{
|
||||
return !string.IsNullOrWhiteSpace(s);
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
internal class DatabaseCreationEventArgs : System.ComponentModel.CancelEventArgs{}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
// Provides information on the macro that caused an error
|
||||
public class MacroErrorEventArgs : System.EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the faulting macro.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Alias of the faulting macro.
|
||||
/// </summary>
|
||||
public string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Filename, file path, fully qualified class name, or other key used by the macro engine to do it's processing of the faulting macro.
|
||||
/// </summary>
|
||||
public string ItemKey { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Exception raised.
|
||||
/// </summary>
|
||||
public Exception Exception { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the desired behaviour when a matching macro causes an error. See
|
||||
/// <see cref="MacroErrorBehaviour"/> for definitions. By setting this in your event
|
||||
/// you can override the default behaviour defined in UmbracoSettings.config.
|
||||
/// </summary>
|
||||
/// <value>Macro error behaviour enum.</value>
|
||||
public MacroErrorBehaviour Behaviour { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
public class NewEventArgs<TEntity> : CancellableObjectEventArgs<TEntity>
|
||||
@@ -8,12 +10,26 @@ namespace Umbraco.Core.Events
|
||||
ParentId = parentId;
|
||||
}
|
||||
|
||||
public NewEventArgs(TEntity eventObject, bool canCancel, string @alias, TEntity parent)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
Alias = alias;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public NewEventArgs(TEntity eventObject, string @alias, int parentId) : base(eventObject)
|
||||
{
|
||||
Alias = alias;
|
||||
ParentId = parentId;
|
||||
}
|
||||
|
||||
public NewEventArgs(TEntity eventObject, string @alias, TEntity parent)
|
||||
: base(eventObject)
|
||||
{
|
||||
Alias = alias;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The entity being created
|
||||
/// </summary>
|
||||
@@ -31,5 +47,10 @@ namespace Umbraco.Core.Events
|
||||
/// Gets or Sets the Id of the parent.
|
||||
/// </summary>
|
||||
public int ParentId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the parent IContent object.
|
||||
/// </summary>
|
||||
public TEntity Parent { get; private set; }
|
||||
}
|
||||
}
|
||||
+8
-9
@@ -1,9 +1,8 @@
|
||||
using Umbraco.Core;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// <summary>
|
||||
/// Custom IApplicationStartupHandler that auto subscribes to the applications events
|
||||
/// </summary>
|
||||
public interface IApplicationEventHandler : IApplicationStartupHandler
|
||||
@@ -11,23 +10,23 @@ namespace Umbraco.Web
|
||||
/// <summary>
|
||||
/// ApplicationContext is created and other static objects that require initialization have been setup
|
||||
/// </summary>
|
||||
/// <param name="httpApplication"></param>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationInitialized(UmbracoApplication httpApplication, ApplicationContext applicationContext);
|
||||
void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
|
||||
/// <summary>
|
||||
/// All resolvers have been initialized but resolution is not frozen so they can be modified in this method
|
||||
/// </summary>
|
||||
/// <param name="httpApplication"></param>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationStarting(UmbracoApplication httpApplication, ApplicationContext applicationContext);
|
||||
void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
|
||||
/// <summary>
|
||||
/// Bootup is completed, this allows you to perform any other bootup logic required for the application.
|
||||
/// Resolution is frozen so now they can be used to resolve instances.
|
||||
/// </summary>
|
||||
/// <param name="httpApplication"></param>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationStarted(UmbracoApplication httpApplication, ApplicationContext applicationContext);
|
||||
void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ using System.IO;
|
||||
using System.Configuration;
|
||||
using System.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -136,25 +137,42 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates if the current filepath matches a directory where the user is allowed to edit a file
|
||||
/// Verifies that the current filepath matches a directory where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">filepath </param>
|
||||
/// <param name="validDir"></param>
|
||||
/// <returns>true if valid, throws a FileSecurityException if not</returns>
|
||||
internal static bool ValidateEditPath(string filePath, string validDir)
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDir">The valid directory.</param>
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
internal static bool VerifyEditPath(string filePath, string validDir)
|
||||
{
|
||||
if (!filePath.StartsWith(MapPath(SystemDirectories.Root)))
|
||||
filePath = MapPath(filePath);
|
||||
if (!validDir.StartsWith(MapPath(SystemDirectories.Root)))
|
||||
validDir = MapPath(validDir);
|
||||
|
||||
if (!filePath.StartsWith(validDir))
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return filePath.StartsWith(validDir);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates that the current filepath matches a directory where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDir">The valid directory.</param>
|
||||
/// <returns>True, if the filepath is valid, else an exception is thrown.</returns>
|
||||
/// <exception cref="FileSecurityException">The filepath is invalid.</exception>
|
||||
internal static bool ValidateEditPath(string filePath, string validDir)
|
||||
{
|
||||
if (!VerifyEditPath(filePath, validDir))
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static bool ValidateEditPath(string filePath, IEnumerable<string> validDirs)
|
||||
/// <summary>
|
||||
/// Verifies that the current filepath matches one of several directories where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDirs">The valid directories.</param>
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
internal static bool VerifyEditPath(string filePath, IEnumerable<string> validDirs)
|
||||
{
|
||||
foreach (var dir in validDirs)
|
||||
{
|
||||
@@ -168,19 +186,49 @@ namespace Umbraco.Core.IO
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool ValidateFileExtension(string filePath, List<string> validFileExtensions)
|
||||
/// <summary>
|
||||
/// Validates that the current filepath matches one of several directories where the user is allowed to edit a file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validDirs">The valid directories.</param>
|
||||
/// <returns>True, if the filepath is valid, else an exception is thrown.</returns>
|
||||
/// <exception cref="FileSecurityException">The filepath is invalid.</exception>
|
||||
internal static bool ValidateEditPath(string filePath, IEnumerable<string> validDirs)
|
||||
{
|
||||
if (!VerifyEditPath(filePath, validDirs))
|
||||
throw new FileSecurityException(String.Format("The filepath '{0}' is not within an allowed directory for this type of files", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies that the current filepath has one of several authorized extensions.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validFileExtensions">The valid extensions.</param>
|
||||
/// <returns>A value indicating whether the filepath is valid.</returns>
|
||||
internal static bool VerifyFileExtension(string filePath, List<string> validFileExtensions)
|
||||
{
|
||||
if (!filePath.StartsWith(MapPath(SystemDirectories.Root)))
|
||||
filePath = MapPath(filePath);
|
||||
var f = new FileInfo(filePath);
|
||||
|
||||
return validFileExtensions.Contains(f.Extension.Substring(1));
|
||||
}
|
||||
|
||||
|
||||
if (!validFileExtensions.Contains(f.Extension.Substring(1)))
|
||||
/// <summary>
|
||||
/// Validates that the current filepath has one of several authorized extensions.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The filepath to validate.</param>
|
||||
/// <param name="validFileExtensions">The valid extensions.</param>
|
||||
/// <returns>True, if the filepath is valid, else an exception is thrown.</returns>
|
||||
/// <exception cref="FileSecurityException">The filepath is invalid.</exception>
|
||||
internal static bool ValidateFileExtension(string filePath, List<string> validFileExtensions)
|
||||
{
|
||||
if (!VerifyFileExtension(filePath, validFileExtensions))
|
||||
throw new FileSecurityException(String.Format("The extension for the current file '{0}' is not of an allowed type for this editor. This is typically controlled from either the installed MacroEngines or based on configuration in /config/umbracoSettings.config", filePath.Replace(MapPath(SystemDirectories.Root), "")));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -215,41 +263,8 @@ namespace Umbraco.Core.IO
|
||||
/// <returns>A safe filename without any path specific chars.</returns>
|
||||
internal static string SafeFileName(string filePath)
|
||||
{
|
||||
if (String.IsNullOrEmpty(filePath))
|
||||
return String.Empty;
|
||||
|
||||
if (!String.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
foreach (var character in Path.GetInvalidFileNameChars())
|
||||
{
|
||||
filePath = filePath.Replace(character, '-');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
filePath = String.Empty;
|
||||
}
|
||||
|
||||
// Adapted from: http://stackoverflow.com/a/4827510/5018
|
||||
// Combined both Reserved Characters and Character Data
|
||||
// from http://en.wikipedia.org/wiki/Percent-encoding
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
const string reservedCharacters = "!*'();:@&=+$,/?%#[]-~{}\"<>\\^`| ";
|
||||
|
||||
foreach (var character in filePath)
|
||||
{
|
||||
if (reservedCharacters.IndexOf(character) == -1)
|
||||
stringBuilder.Append(character);
|
||||
else
|
||||
stringBuilder.Append("-");
|
||||
}
|
||||
|
||||
// Remove repeating dashes
|
||||
// From: http://stackoverflow.com/questions/5111967/regex-to-remove-a-specific-repeated-character
|
||||
var reducedString = Regex.Replace(stringBuilder.ToString(), "-+", "-");
|
||||
|
||||
return reducedString;
|
||||
// use string extensions
|
||||
return filePath.ToSafeFileName();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.CodeAnnotations;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
@@ -27,6 +25,15 @@ namespace Umbraco.Core.IO
|
||||
return propertyId.ToString() + seperator + fileName;
|
||||
}
|
||||
|
||||
public string GetRelativePath(string subfolder, string fileName)
|
||||
{
|
||||
var seperator = UmbracoSettings.UploadAllowDirectories
|
||||
? Path.DirectorySeparatorChar
|
||||
: '-';
|
||||
|
||||
return subfolder + seperator + fileName;
|
||||
}
|
||||
|
||||
public IEnumerable<string> GetThumbnails(string path)
|
||||
{
|
||||
var parentDirectory = System.IO.Path.GetDirectoryName(path);
|
||||
|
||||
@@ -183,16 +183,26 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
}
|
||||
|
||||
private static string _root;
|
||||
/// <summary>
|
||||
/// Gets the root path of the application
|
||||
/// </summary>
|
||||
public static string Root
|
||||
{
|
||||
get
|
||||
{
|
||||
string appPath = HttpRuntime.AppDomainAppVirtualPath ?? string.Empty;
|
||||
if (appPath == "/")
|
||||
appPath = string.Empty;
|
||||
if (_root == null)
|
||||
{
|
||||
string appPath = HttpRuntime.AppDomainAppVirtualPath ?? string.Empty;
|
||||
if (appPath == "/")
|
||||
appPath = string.Empty;
|
||||
|
||||
return appPath;
|
||||
_root = appPath;
|
||||
}
|
||||
return _root;
|
||||
}
|
||||
//Only required for unit tests
|
||||
internal set { _root = value; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public enum IconPickerBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Default umbraco behavior - show duplicates in files and sprites
|
||||
/// </summary>
|
||||
ShowDuplicates,
|
||||
|
||||
/// <summary>
|
||||
/// If a file exists on disk with the same name as one in the sprite
|
||||
/// then the file on disk overrules the one in the sprite, the
|
||||
/// sprite icon will not be shown
|
||||
/// </summary>
|
||||
HideSpriteDuplicates,
|
||||
|
||||
/// <summary>
|
||||
/// If a file exists on disk with the same name as one in the sprite
|
||||
/// then the file in the sprite overrules the one on disk, the file
|
||||
/// on disk will be shown
|
||||
/// </summary>
|
||||
HideFileDuplicates
|
||||
}
|
||||
}
|
||||
@@ -64,23 +64,28 @@ namespace Umbraco.Core.Logging
|
||||
{
|
||||
_forceStop = true;
|
||||
var windowsIdentity = WindowsIdentity.GetCurrent();
|
||||
base.Append(new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = Level.Error,
|
||||
Message =
|
||||
"Unable to clear out the AsynchronousRollingFileAppender buffer in the allotted time, forcing a shutdown",
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = "",
|
||||
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo =
|
||||
new LocationInfo(this.GetType().Name, "OnClose", "AsynchronousRollingFileAppender.cs", "59"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
})
|
||||
);
|
||||
|
||||
var logEvent = new LoggingEvent(new LoggingEventData
|
||||
{
|
||||
Level = global::log4net.Core.Level.Error,
|
||||
Message =
|
||||
"Unable to clear out the AsynchronousRollingFileAppender buffer in the allotted time, forcing a shutdown",
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Identity = "",
|
||||
ExceptionString = "",
|
||||
UserName = windowsIdentity != null ? windowsIdentity.Name : "",
|
||||
Domain = AppDomain.CurrentDomain.FriendlyName,
|
||||
ThreadName = Thread.CurrentThread.ManagedThreadId.ToString(),
|
||||
LocationInfo =
|
||||
new LocationInfo(this.GetType().Name, "OnClose", "AsynchronousRollingFileAppender.cs", "59"),
|
||||
LoggerName = this.GetType().FullName,
|
||||
Properties = new PropertiesDictionary(),
|
||||
});
|
||||
|
||||
if (this.DateTimeStrategy != null)
|
||||
{
|
||||
base.Append(logEvent);
|
||||
}
|
||||
}
|
||||
|
||||
base.OnClose();
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
public enum MacroErrorBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Default umbraco behavior - show an inline error within the
|
||||
/// macro but allow the page to continue rendering.
|
||||
/// </summary>
|
||||
Inline,
|
||||
|
||||
/// <summary>
|
||||
/// Silently eat the error and do not display the offending macro.
|
||||
/// </summary>
|
||||
Silent,
|
||||
|
||||
/// <summary>
|
||||
/// Throw an exception which can be caught by the global error handler
|
||||
/// defined in Application_OnError. If no such error handler is defined
|
||||
/// then you'll see the Yellow Screen Of Death (YSOD) error page.
|
||||
/// </summary>
|
||||
Throw
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Macros;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
namespace Umbraco.Core.Macros
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to return all IMacroGuiRendering objects
|
||||
@@ -14,18 +16,16 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Much of this classes methods are based on legacy code from umbraco.editorControls.macrocontainer.MacroControlFactory
|
||||
/// this code should probably be reviewed and cleaned up if necessary.
|
||||
/// </remarks>
|
||||
internal sealed class MacroFieldEditorsResolver : ManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
internal sealed class MacroFieldEditorsResolver : LazyManyObjectsResolverBase<MacroFieldEditorsResolver, IMacroGuiRendering>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="macroEditors"></param>
|
||||
internal MacroFieldEditorsResolver(IEnumerable<Type> macroEditors)
|
||||
internal MacroFieldEditorsResolver(Func<IEnumerable<Type>> macroEditors)
|
||||
: base(macroEditors, ObjectLifetimeScope.Transient)
|
||||
{
|
||||
|
||||
}
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IMacroGuiRendering"/> implementations.
|
||||
@@ -56,7 +56,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </remarks>
|
||||
internal List<Type> MacroControlTypes
|
||||
{
|
||||
get { return InstanceTypes; }
|
||||
get { return InstanceTypes.ToList(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Core.Media
|
||||
{
|
||||
/// <summary>
|
||||
/// Internal singleton to handle the numbering of subfolders within the Media-folder.
|
||||
/// When this class is initiated it will look for numbered subfolders and select the highest number,
|
||||
/// which will be the start point for the naming of the next subfolders. If no subfolders exists
|
||||
/// then the starting point will be 1000, ie. /media/1000/koala.jpg
|
||||
/// </summary>
|
||||
internal class MediaSubfolderCounter
|
||||
{
|
||||
#region Singleton
|
||||
|
||||
private long _numberedFolder = 1000;//Default starting point
|
||||
private static readonly ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
|
||||
private static readonly Lazy<MediaSubfolderCounter> Lazy = new Lazy<MediaSubfolderCounter>(() => new MediaSubfolderCounter());
|
||||
|
||||
public static MediaSubfolderCounter Current { get { return Lazy.Value; } }
|
||||
|
||||
private MediaSubfolderCounter()
|
||||
{
|
||||
var folders = new List<long>();
|
||||
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
|
||||
var directories = fs.GetDirectories("");
|
||||
foreach (var directory in directories)
|
||||
{
|
||||
long dirNum;
|
||||
if (long.TryParse(directory, out dirNum))
|
||||
{
|
||||
folders.Add(dirNum);
|
||||
}
|
||||
}
|
||||
var last = folders.OrderBy(x => x).LastOrDefault();
|
||||
if(last != default(long))
|
||||
_numberedFolder = last;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns an increment of the numbered media subfolders.
|
||||
/// </summary>
|
||||
/// <returns>A <see cref="System.Int64"/> value</returns>
|
||||
public long Increment()
|
||||
{
|
||||
using (new ReadLock(ClearLock))
|
||||
{
|
||||
_numberedFolder = _numberedFolder + 1;
|
||||
return _numberedFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -101,8 +103,11 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
set
|
||||
{
|
||||
_template = value;
|
||||
OnPropertyChanged(TemplateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_template = value;
|
||||
return _template;
|
||||
}, _template, TemplateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +145,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _published; }
|
||||
internal set
|
||||
{
|
||||
_published = value;
|
||||
OnPropertyChanged(PublishedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_published = value;
|
||||
return _published;
|
||||
}, _published, PublishedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,8 +165,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _language; }
|
||||
set
|
||||
{
|
||||
_language = value;
|
||||
OnPropertyChanged(LanguageSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_language = value;
|
||||
return _language;
|
||||
}, _language, LanguageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,8 +182,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _releaseDate; }
|
||||
set
|
||||
{
|
||||
_releaseDate = value;
|
||||
OnPropertyChanged(ReleaseDateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_releaseDate = value;
|
||||
return _releaseDate;
|
||||
}, _releaseDate, ReleaseDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,8 +199,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _expireDate; }
|
||||
set
|
||||
{
|
||||
_expireDate = value;
|
||||
OnPropertyChanged(ExpireDateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_expireDate = value;
|
||||
return _expireDate;
|
||||
}, _expireDate, ExpireDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -199,8 +216,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _writer; }
|
||||
set
|
||||
{
|
||||
_writer = value;
|
||||
OnPropertyChanged(WriterSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_writer = value;
|
||||
return _writer;
|
||||
}, _writer, WriterSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +235,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _nodeName; }
|
||||
set
|
||||
{
|
||||
_nodeName = value;
|
||||
OnPropertyChanged(NodeNameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_nodeName = value;
|
||||
return _nodeName;
|
||||
}, _nodeName, NodeNameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,19 +303,10 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
|
||||
/// <param name="parentId"> </param>
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -1)
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
{
|
||||
Trashed = isTrashed;
|
||||
|
||||
//If Content is trashed the parent id should be set to that of the RecycleBin
|
||||
if(isTrashed)
|
||||
{
|
||||
ParentId = -20;
|
||||
}
|
||||
else//otherwise set the parent id to the optional parameter, -1 being the fallback
|
||||
{
|
||||
ParentId = parentId;
|
||||
}
|
||||
ParentId = parentId;
|
||||
|
||||
//If the content is trashed and is published it should be marked as unpublished
|
||||
if (isTrashed && Published)
|
||||
@@ -312,6 +326,12 @@ namespace Umbraco.Core.Models
|
||||
clone.Version = Guid.NewGuid();
|
||||
clone.ResetIdentity();
|
||||
|
||||
foreach (var property in clone.Properties)
|
||||
{
|
||||
property.ResetIdentity();
|
||||
property.Version = clone.Version;
|
||||
}
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@@ -13,6 +14,7 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Represents an abstract class for base Content properties and methods
|
||||
/// </summary>
|
||||
[DebuggerDisplay("Id: {Id}, Name: {Name}, ContentType: {ContentTypeBase.Alias}")]
|
||||
public abstract class ContentBase : Entity, IContentBase
|
||||
{
|
||||
protected IContentTypeComposition ContentTypeBase;
|
||||
@@ -118,8 +120,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -132,8 +137,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +154,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,8 +171,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,8 +188,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
_creatorId = value;
|
||||
OnPropertyChanged(CreatorIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, CreatorIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,8 +207,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,8 +230,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _contentTypeId; }
|
||||
protected set
|
||||
{
|
||||
_contentTypeId = value;
|
||||
OnPropertyChanged(DefaultContentTypeIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_contentTypeId = value;
|
||||
return _contentTypeId;
|
||||
}, _contentTypeId, DefaultContentTypeIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -401,6 +424,6 @@ namespace Umbraco.Core.Models
|
||||
return Properties.Any(property => !property.IsValid()) == false;
|
||||
}
|
||||
|
||||
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -1);
|
||||
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -20);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -10,7 +11,9 @@ using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Media;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Strings;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
|
||||
@@ -18,6 +21,90 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public static class ContentExtensions
|
||||
{
|
||||
#region IContent
|
||||
/// <summary>
|
||||
/// Returns a list of the current contents ancestors, not including the content itself.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public static IEnumerable<IContent> Ancestors(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetAncestors(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current contents children.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public static IEnumerable<IContent> Children(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetChildren(content.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current contents descendants, not including the content itself.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An enumerable list of <see cref="IContent"/> objects</returns>
|
||||
public static IEnumerable<IContent> Descendants(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetDescendants(content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the parent of the current content.
|
||||
/// </summary>
|
||||
/// <param name="content">Current content</param>
|
||||
/// <returns>An <see cref="IContent"/> object</returns>
|
||||
public static IContent Parent(this IContent content)
|
||||
{
|
||||
return ApplicationContext.Current.Services.ContentService.GetById(content.ParentId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IMedia
|
||||
/// <summary>
|
||||
/// Returns a list of the current medias ancestors, not including the media itself.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public static IEnumerable<IMedia> Ancestors(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetAncestors(media);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current medias children.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public static IEnumerable<IMedia> Children(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetChildren(media.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of the current medias descendants, not including the media itself.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An enumerable list of <see cref="IMedia"/> objects</returns>
|
||||
public static IEnumerable<IMedia> Descendants(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetDescendants(media);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the parent of the current media.
|
||||
/// </summary>
|
||||
/// <param name="media">Current media</param>
|
||||
/// <returns>An <see cref="IMedia"/> object</returns>
|
||||
public static IMedia Parent(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.MediaService.GetById(media.ParentId);
|
||||
}
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Set property values by alias with an annonymous object
|
||||
/// </summary>
|
||||
@@ -54,68 +141,25 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
|
||||
/// </summary>
|
||||
/// <param name="media"><see cref="IMedia"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
|
||||
public static void SetPropertyValue(this IMedia media, string propertyTypeAlias, HttpPostedFileBase value)
|
||||
{
|
||||
var name =
|
||||
IOHelper.SafeFileName(
|
||||
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
|
||||
if(string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(media, propertyTypeAlias, name, value.InputStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFile object as the property value
|
||||
/// </summary>
|
||||
/// <param name="media"><see cref="IMedia"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFile"/> containing the file that will be uploaded</param>
|
||||
public static void SetPropertyValue(this IMedia media, string propertyTypeAlias, HttpPostedFile value)
|
||||
{
|
||||
var name =
|
||||
IOHelper.SafeFileName(
|
||||
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(media, propertyTypeAlias, name, value.InputStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileWrapper object as the property value
|
||||
/// </summary>
|
||||
/// <param name="media"><see cref="IMedia"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFileWrapper"/> containing the file that will be uploaded</param>
|
||||
public static void SetPropertyValue(this IMedia media, string propertyTypeAlias, HttpPostedFileWrapper value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value.FileName) == false)
|
||||
SetFileOnContent(media, propertyTypeAlias, value.FileName, value.InputStream);
|
||||
}
|
||||
*/
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileBase object as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to add property value to</param>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFileBase"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value)
|
||||
{
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
|
||||
|
||||
var name =
|
||||
IOHelper.SafeFileName(
|
||||
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
fileName.Substring(fileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
fileName.Length - fileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
|
||||
@@ -124,16 +168,22 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFile object as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to add property value to</param>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFile"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFile value)
|
||||
{
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
|
||||
|
||||
var name =
|
||||
IOHelper.SafeFileName(
|
||||
value.FileName.Substring(value.FileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
value.FileName.Length - value.FileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
fileName.Substring(fileName.LastIndexOf(IOHelper.DirSepChar) + 1,
|
||||
fileName.Length - fileName.LastIndexOf(IOHelper.DirSepChar) - 1)
|
||||
.ToLower());
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
|
||||
@@ -142,26 +192,52 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a HttpPostedFileWrapper object as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to add property value to</param>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="value">The <see cref="HttpPostedFileWrapper"/> containing the file that will be uploaded</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileWrapper value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value.FileName) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, value.FileName, value.InputStream);
|
||||
// Ensure we get the filename without the path in IE in intranet mode
|
||||
// http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie
|
||||
var fileName = value.FileName;
|
||||
if (fileName.LastIndexOf(@"\") > 0)
|
||||
fileName = fileName.Substring(fileName.LastIndexOf(@"\") + 1);
|
||||
|
||||
var name = IOHelper.SafeFileName(fileName);
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false)
|
||||
SetFileOnContent(content, propertyTypeAlias, name, value.InputStream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets and uploads the file from a <see cref="Stream"/> as the property value
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContentBase"/> to add property value to</param>
|
||||
/// <param name="propertyTypeAlias">Alias of the property to save the value on</param>
|
||||
/// <param name="fileName">Name of the file</param>
|
||||
/// <param name="fileStream"><see cref="Stream"/> to save to disk</param>
|
||||
public static void SetValue(this IContentBase content, string propertyTypeAlias, string fileName,
|
||||
Stream fileStream)
|
||||
{
|
||||
var name = IOHelper.SafeFileName(fileName);
|
||||
|
||||
if (string.IsNullOrEmpty(name) == false && fileStream != null)
|
||||
SetFileOnContent(content, propertyTypeAlias, name, fileStream);
|
||||
}
|
||||
|
||||
private static void SetFileOnContent(IContentBase content, string propertyTypeAlias, string name, Stream fileStream)
|
||||
{
|
||||
var property = content.Properties.FirstOrDefault(x => x.Alias == propertyTypeAlias);
|
||||
if(property == null)
|
||||
if (property == null)
|
||||
return;
|
||||
|
||||
bool supportsResizing = false;
|
||||
var numberedFolder = MediaSubfolderCounter.Current.Increment();
|
||||
string fileName = UmbracoSettings.UploadAllowDirectories
|
||||
? Path.Combine(property.Id.ToString(), name)
|
||||
: property.Id + "-" + name;
|
||||
string extension = Path.GetExtension(name);
|
||||
? Path.Combine(numberedFolder.ToString(CultureInfo.InvariantCulture), name)
|
||||
: numberedFolder + "-" + name;
|
||||
|
||||
string extension = Path.GetExtension(name).Substring(1).ToLowerInvariant();
|
||||
|
||||
var fs = FileSystemProviderManager.Current.GetFileSystemProvider<MediaFileSystem>();
|
||||
fs.AddFile(fileName, fileStream);
|
||||
@@ -175,7 +251,7 @@ namespace Umbraco.Core.Models
|
||||
var thumbUrl = Resize(fs, fileName, extension, 100, "thumb");
|
||||
|
||||
//Look up Prevalues for this upload datatype - if it is an upload datatype
|
||||
var uploadFieldId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c");
|
||||
var uploadFieldId = new Guid(Constants.PropertyEditors.UploadField);
|
||||
if (property.PropertyType.DataTypeId == uploadFieldId)
|
||||
{
|
||||
//Get Prevalues by the DataType's Id: property.PropertyType.DataTypeId
|
||||
@@ -204,7 +280,7 @@ namespace Umbraco.Core.Models
|
||||
XmlNode uploadFieldConfigNode =
|
||||
UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode(
|
||||
string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias));
|
||||
|
||||
|
||||
if (uploadFieldConfigNode != null)
|
||||
{
|
||||
//Only add dimensions to web images
|
||||
@@ -231,12 +307,12 @@ namespace Umbraco.Core.Models
|
||||
private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, string propertyValue)
|
||||
{
|
||||
XmlNode propertyNode = uploadFieldConfigNode.SelectSingleNode(propertyAlias);
|
||||
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false)
|
||||
if (propertyNode != null && string.IsNullOrEmpty(propertyNode.FirstChild.Value) == false && content.HasProperty(propertyNode.FirstChild.Value))
|
||||
{
|
||||
content.SetValue(propertyNode.FirstChild.Value, propertyValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static string Resize(MediaFileSystem fileSystem, string path, string extension, int maxWidthHeight, string fileNameAddition)
|
||||
{
|
||||
var fileNameThumb = DoResize(fileSystem, path, extension, GetDimensions(fileSystem, path).Item1, GetDimensions(fileSystem, path).Item2, maxWidthHeight, fileNameAddition);
|
||||
@@ -347,16 +423,20 @@ namespace Umbraco.Core.Models
|
||||
return new Tuple<int, int, string>(widthTh, heightTh, newFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this media item.
|
||||
/// </summary>
|
||||
public static IProfile GetCreatorProfile(this IMedia media)
|
||||
{
|
||||
return ApplicationContext.Current.Services.UserService.GetProfileById(media.CreatorId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this content.
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this content item.
|
||||
/// </summary>
|
||||
public static IProfile GetCreatorProfile(this IContent content)
|
||||
public static IProfile GetCreatorProfile(this IContentBase content)
|
||||
{
|
||||
using (var repository = RepositoryResolver.Current.Factory.CreateUserRepository(
|
||||
PetaPocoUnitOfWorkProvider.CreateUnitOfWork()))
|
||||
{
|
||||
return repository.GetProfileById(content.CreatorId);
|
||||
}
|
||||
return ApplicationContext.Current.Services.UserService.GetProfileById(content.CreatorId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -364,11 +444,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public static IProfile GetWriterProfile(this IContent content)
|
||||
{
|
||||
using(var repository = RepositoryResolver.Current.Factory.CreateUserRepository(
|
||||
PetaPocoUnitOfWorkProvider.CreateUnitOfWork()))
|
||||
{
|
||||
return repository.GetProfileById(content.WriterId);
|
||||
}
|
||||
return ApplicationContext.Current.Services.UserService.GetProfileById(content.WriterId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -384,6 +460,47 @@ namespace Umbraco.Core.Models
|
||||
return ApplicationContext.Current.Services.ContentService.HasPublishedVersion(content.Id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the full xml representation for the <see cref="IContent"/> object and all of it's descendants
|
||||
/// </summary>
|
||||
/// <param name="content"><see cref="IContent"/> to generate xml for</param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
internal static XElement ToDeepXml(this IContent content)
|
||||
{
|
||||
var xml = content.ToXml();
|
||||
|
||||
var descendants = content.Descendants().ToArray();
|
||||
var currentChildren = descendants.Where(x => x.ParentId == content.Id);
|
||||
AddChildXml(descendants, currentChildren, xml);
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by ToDeepXml to recursively add children
|
||||
/// </summary>
|
||||
/// <param name="originalDescendants"></param>
|
||||
/// <param name="currentChildren"></param>
|
||||
/// <param name="currentXml"></param>
|
||||
private static void AddChildXml(
|
||||
IContent[] originalDescendants,
|
||||
IEnumerable<IContent> currentChildren,
|
||||
XElement currentXml)
|
||||
{
|
||||
foreach (var child in currentChildren)
|
||||
{
|
||||
//add the child's xml
|
||||
var childXml = child.ToXml();
|
||||
currentXml.Add(childXml);
|
||||
//copy local (out of closure)
|
||||
var c = child;
|
||||
//get this item's children
|
||||
var children = originalDescendants.Where(x => x.ParentId == c.Id);
|
||||
//recurse and add it's children to the child xml element
|
||||
AddChildXml(originalDescendants, children, childXml);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
@@ -391,43 +508,77 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
public static XElement ToXml(this IContent content)
|
||||
{
|
||||
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
|
||||
//var nodeName = content.ContentType.Alias.ToUmbracoAlias(StringAliasCaseType.CamelCase, true);
|
||||
var nodeName = content.ContentType.Alias;
|
||||
var niceUrl = content.Name.FormatUrl().ToLower();
|
||||
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
|
||||
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck();
|
||||
|
||||
var xml = new XElement(nodeName,
|
||||
new XAttribute("id", content.Id),
|
||||
new XAttribute("parentID", content.Level > 1 ? content.ParentId : -1),
|
||||
new XAttribute("level", content.Level),
|
||||
new XAttribute("writerID", content.WriterId),
|
||||
new XAttribute("creatorID", content.CreatorId),
|
||||
new XAttribute("nodeType", content.ContentType.Id),
|
||||
new XAttribute("template", content.Template == null ? "0" : content.Template.Id.ToString()),
|
||||
new XAttribute("sortOrder", content.SortOrder),
|
||||
new XAttribute("createDate", content.CreateDate.ToString("s")),
|
||||
new XAttribute("updateDate", content.UpdateDate.ToString("s")),
|
||||
new XAttribute("nodeName", content.Name),
|
||||
new XAttribute("urlName", niceUrl),//Format Url ?
|
||||
new XAttribute("writerName", content.GetWriterProfile().Name),
|
||||
new XAttribute("creatorName", content.GetCreatorProfile().Name),
|
||||
new XAttribute("path", content.Path),
|
||||
new XAttribute("isDoc", ""));
|
||||
|
||||
foreach (var property in content.Properties)
|
||||
var x = content.ToXml(nodeName);
|
||||
x.Add(new XAttribute("nodeType", content.ContentType.Id));
|
||||
x.Add(new XAttribute("creatorName", content.GetCreatorProfile().Name));
|
||||
x.Add(new XAttribute("writerName", content.GetWriterProfile().Name));
|
||||
x.Add(new XAttribute("writerID", content.WriterId));
|
||||
x.Add(new XAttribute("template", content.Template == null ? "0" : content.Template.Id.ToString()));
|
||||
if (UmbracoSettings.UseLegacyXmlSchema)
|
||||
{
|
||||
if (property == null) continue;
|
||||
|
||||
xml.Add(property.ToXml());
|
||||
|
||||
//Check for umbracoUrlName convention
|
||||
if (property.Alias == "umbracoUrlName" && property.Value.ToString().Trim() != string.Empty)
|
||||
xml.SetAttributeValue("urlName", property.Value);
|
||||
x.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias));
|
||||
}
|
||||
|
||||
return xml;
|
||||
return x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IMedia"/> object
|
||||
/// </summary>
|
||||
/// <param name="media"><see cref="IContent"/> to generate xml for</param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
public static XElement ToXml(this IMedia media)
|
||||
{
|
||||
//nodeName should match Casing.SafeAliasWithForcingCheck(content.ContentType.Alias);
|
||||
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : media.ContentType.Alias.ToSafeAliasWithForcingCheck();
|
||||
|
||||
var x = media.ToXml(nodeName);
|
||||
x.Add(new XAttribute("nodeType", media.ContentType.Id));
|
||||
x.Add(new XAttribute("writerName", media.GetCreatorProfile().Name));
|
||||
x.Add(new XAttribute("writerID", media.CreatorId));
|
||||
x.Add(new XAttribute("version", media.Version));
|
||||
x.Add(new XAttribute("template", 0));
|
||||
if (UmbracoSettings.UseLegacyXmlSchema)
|
||||
{
|
||||
x.Add(new XAttribute("nodeTypeAlias", media.ContentType.Alias));
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContentBase"/> object
|
||||
/// </summary>
|
||||
/// <param name="contentBase"><see cref="IContent"/> to generate xml for</param>
|
||||
/// <param name="nodeName"></param>
|
||||
/// <returns>Xml representation of the passed in <see cref="IContent"/></returns>
|
||||
private static XElement ToXml(this IContentBase contentBase, string nodeName)
|
||||
{
|
||||
// note: that one will take care of umbracoUrlName
|
||||
var url = contentBase.GetUrlSegment();
|
||||
|
||||
var xml = new XElement(nodeName,
|
||||
new XAttribute("id", contentBase.Id),
|
||||
new XAttribute("parentID", contentBase.Level > 1 ? contentBase.ParentId : -1),
|
||||
new XAttribute("level", contentBase.Level),
|
||||
new XAttribute("creatorID", contentBase.CreatorId),
|
||||
new XAttribute("sortOrder", contentBase.SortOrder),
|
||||
new XAttribute("createDate", contentBase.CreateDate.ToString("s")),
|
||||
new XAttribute("updateDate", contentBase.UpdateDate.ToString("s")),
|
||||
new XAttribute("nodeName", contentBase.Name),
|
||||
new XAttribute("urlName", url),
|
||||
new XAttribute("path", contentBase.Path),
|
||||
new XAttribute("isDoc", ""));
|
||||
|
||||
foreach (var property in contentBase.Properties.Where(p => p != null))
|
||||
xml.Add(property.ToXml());
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the xml representation for the <see cref="IContent"/> object
|
||||
/// </summary>
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -47,8 +48,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _defaultTemplate; }
|
||||
set
|
||||
{
|
||||
_defaultTemplate = value;
|
||||
OnPropertyChanged(DefaultTemplateSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_defaultTemplate = value;
|
||||
return _defaultTemplate;
|
||||
}, _defaultTemplate, DefaultTemplateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,8 +65,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedTemplates; }
|
||||
set
|
||||
{
|
||||
_allowedTemplates = value;
|
||||
OnPropertyChanged(AllowedTemplatesSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_allowedTemplates = value;
|
||||
return _allowedTemplates;
|
||||
}, _allowedTemplates, AllowedTemplatesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -23,8 +22,8 @@ namespace Umbraco.Core.Models
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _sortOrder;
|
||||
private string _icon;
|
||||
private string _thumbnail;
|
||||
private string _icon = "folder.png";
|
||||
private string _thumbnail = "folder.png";
|
||||
private int _creatorId;
|
||||
private bool _allowedAsRoot;
|
||||
private bool _isContainer;
|
||||
@@ -32,6 +31,8 @@ namespace Umbraco.Core.Models
|
||||
private PropertyGroupCollection _propertyGroups;
|
||||
private PropertyTypeCollection _propertyTypes;
|
||||
private IEnumerable<ContentTypeSort> _allowedContentTypes;
|
||||
private bool _hasPropertyTypeBeenRemoved;
|
||||
|
||||
|
||||
protected ContentTypeBase(int parentId)
|
||||
{
|
||||
@@ -69,6 +70,8 @@ namespace Umbraco.Core.Models
|
||||
private static readonly PropertyInfo AllowedContentTypesSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<ContentTypeSort>>(x => x.AllowedContentTypes);
|
||||
private static readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
private static readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<PropertyType>>(x => x.PropertyTypes);
|
||||
private static readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.HasPropertyTypeBeenRemoved);
|
||||
|
||||
|
||||
protected void PropertyGroupsChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
@@ -112,8 +115,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,8 +132,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -140,8 +149,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,13 +166,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
//Ensures a valid ContentType alias
|
||||
//Would have liked to use .ToUmbracoAlias() but that would break casing upon saving older/upgraded ContentTypes
|
||||
var result = Regex.Replace(value, @"[^a-zA-Z0-9\s\.-]+", "", RegexOptions.Compiled);
|
||||
result = result.Replace(" ", "");
|
||||
|
||||
_alias = result;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value.ToSafeAlias();
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,8 +183,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_description = value;
|
||||
return _description;
|
||||
}, _description, DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,8 +200,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,8 +217,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _icon; }
|
||||
set
|
||||
{
|
||||
_icon = value;
|
||||
OnPropertyChanged(IconSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_icon = value;
|
||||
return _icon;
|
||||
}, _icon, IconSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +234,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _thumbnail; }
|
||||
set
|
||||
{
|
||||
_thumbnail = value;
|
||||
OnPropertyChanged(ThumbnailSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_thumbnail = value;
|
||||
return _thumbnail;
|
||||
}, _thumbnail, ThumbnailSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -229,8 +251,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
_creatorId = value;
|
||||
OnPropertyChanged(CreatorIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, CreatorIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -243,8 +268,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedAsRoot; }
|
||||
set
|
||||
{
|
||||
_allowedAsRoot = value;
|
||||
OnPropertyChanged(AllowedAsRootSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_allowedAsRoot = value;
|
||||
return _allowedAsRoot;
|
||||
}, _allowedAsRoot, AllowedAsRootSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -260,8 +288,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _isContainer; }
|
||||
set
|
||||
{
|
||||
_isContainer = value;
|
||||
OnPropertyChanged(IsContainerSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isContainer = value;
|
||||
return _isContainer;
|
||||
}, _isContainer, IsContainerSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,8 +306,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _trashed; }
|
||||
set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,8 +323,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedContentTypes; }
|
||||
set
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
OnPropertyChanged(AllowedContentTypesSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_allowedContentTypes = value;
|
||||
return _allowedContentTypes;
|
||||
}, _allowedContentTypes, AllowedContentTypesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,16 +365,116 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A boolean flag indicating if a property type has been removed from this instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is currently (specifically) used in order to know that we need to refresh the content cache which
|
||||
/// needs to occur when a property has been removed from a content type
|
||||
/// </remarks>
|
||||
[IgnoreDataMember]
|
||||
internal bool HasPropertyTypeBeenRemoved
|
||||
{
|
||||
get { return _hasPropertyTypeBeenRemoved; }
|
||||
private set
|
||||
{
|
||||
_hasPropertyTypeBeenRemoved = value;
|
||||
OnPropertyChanged(HasPropertyTypeBeenRemovedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
|
||||
public abstract bool PropertyTypeExists(string propertyTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyGroup.
|
||||
/// This method will also check if a group already exists with the same name and link it to the parent.
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the PropertyGroup to add</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
|
||||
public abstract bool AddPropertyGroup(string groupName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType to a specific PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public abstract bool AddPropertyType(PropertyType propertyType, string propertyGroupName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType, which does not belong to a PropertyGroup.
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public bool AddPropertyType(PropertyType propertyType)
|
||||
{
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
_propertyTypes.Add(propertyType);
|
||||
_propertyTypes.CollectionChanged += PropertyTypesChanged;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves a PropertyType to a specified PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType to move</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to move the PropertyType to</param>
|
||||
/// <returns></returns>
|
||||
public bool MovePropertyType(string propertyTypeAlias, string propertyGroupName)
|
||||
{
|
||||
if (PropertyTypes.Any(x => x.Alias == propertyTypeAlias) == false || PropertyGroups.Any(x => x.Name == propertyGroupName) == false)
|
||||
return false;
|
||||
|
||||
var propertyType = PropertyTypes.First(x => x.Alias == propertyTypeAlias);
|
||||
//The PropertyType already belongs to a PropertyGroup, so we have to remove the PropertyType from that group
|
||||
if (PropertyGroups.Any(x => x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias)))
|
||||
{
|
||||
var oldPropertyGroup = PropertyGroups.First(x => x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias));
|
||||
oldPropertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => default(int));
|
||||
propertyType.ResetDirtyProperties();
|
||||
|
||||
var propertyGroup = PropertyGroups.First(x => x.Name == propertyGroupName);
|
||||
propertyGroup.PropertyTypes.Add(propertyType);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a PropertyType from the current ContentType
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the <see cref="PropertyType"/> to remove</param>
|
||||
public void RemovePropertyType(string propertyTypeAlias)
|
||||
{
|
||||
|
||||
//check if the property exist in one of our collections
|
||||
if (PropertyGroups.Any(group => group.PropertyTypes.Any(pt => pt.Alias == propertyTypeAlias))
|
||||
|| _propertyTypes.Any(x => x.Alias == propertyTypeAlias))
|
||||
{
|
||||
//set the flag that a property has been removed
|
||||
HasPropertyTypeBeenRemoved = true;
|
||||
}
|
||||
|
||||
foreach (var propertyGroup in PropertyGroups)
|
||||
{
|
||||
propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
|
||||
if (_propertyTypes.Any(x => x.Alias == propertyTypeAlias))
|
||||
{
|
||||
_propertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -348,9 +485,5 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
_parentId = id;
|
||||
}
|
||||
|
||||
//TODO Implement moving PropertyType between groups.
|
||||
/*public bool MovePropertyTypeToGroup(string propertyTypeAlias, string groupName)
|
||||
{}*/
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ namespace Umbraco.Core.Models
|
||||
public abstract class ContentTypeCompositionBase : ContentTypeBase, IContentTypeComposition
|
||||
{
|
||||
private readonly List<IContentTypeComposition> _contentTypeComposition = new List<IContentTypeComposition>();
|
||||
internal List<int> RemovedContentTypeKeyTracker = new List<int>();
|
||||
|
||||
protected ContentTypeCompositionBase(int parentId) : base(parentId)
|
||||
{
|
||||
@@ -44,7 +45,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var groups = PropertyGroups.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups));
|
||||
var groups = ContentTypeComposition.SelectMany(x => x.CompositionPropertyGroups).Union(PropertyGroups);
|
||||
return groups;
|
||||
}
|
||||
}
|
||||
@@ -57,8 +58,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get
|
||||
{
|
||||
var propertyTypes =
|
||||
PropertyTypes.Union(ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes));
|
||||
var propertyTypes = ContentTypeComposition.SelectMany(x => x.CompositionPropertyTypes).Union(PropertyTypes);
|
||||
return propertyTypes;
|
||||
}
|
||||
}
|
||||
@@ -89,9 +89,11 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>True if ContentType was removed, otherwise returns False</returns>
|
||||
public bool RemoveContentType(string alias)
|
||||
{
|
||||
if (!ContentTypeCompositionExists(alias))
|
||||
if (ContentTypeCompositionExists(alias))
|
||||
{
|
||||
var contentTypeComposition = ContentTypeComposition.First(x => x.Alias == alias);
|
||||
RemovedContentTypeKeyTracker.Add(contentTypeComposition.Id);
|
||||
OnPropertyChanged(ContentTypeCompositionSelector);
|
||||
return _contentTypeComposition.Remove(contentTypeComposition);
|
||||
}
|
||||
return false;
|
||||
@@ -113,6 +115,83 @@ namespace Umbraco.Core.Models
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
|
||||
public override bool PropertyTypeExists(string propertyTypeAlias)
|
||||
{
|
||||
return CompositionPropertyTypes.Any(x => x.Alias == propertyTypeAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyGroup.
|
||||
/// This method will also check if a group already exists with the same name and link it to the parent.
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the PropertyGroup to add</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
|
||||
public override bool AddPropertyGroup(string groupName)
|
||||
{
|
||||
if (PropertyGroups.Any(x => x.Name == groupName))
|
||||
return false;
|
||||
|
||||
var propertyGroup = new PropertyGroup {Name = groupName, SortOrder = 0};
|
||||
|
||||
if (CompositionPropertyGroups.Any(x => x.Name == groupName))
|
||||
{
|
||||
var firstGroup = CompositionPropertyGroups.First(x => x.Name == groupName && x.ParentId.HasValue == false);
|
||||
propertyGroup.SetLazyParentId(new Lazy<int?>(() => firstGroup.Id));
|
||||
}
|
||||
|
||||
if (PropertyGroups.Any())
|
||||
{
|
||||
var last = PropertyGroups.Last();
|
||||
propertyGroup.SortOrder = last.SortOrder + 1;
|
||||
}
|
||||
|
||||
PropertyGroups.Add(propertyGroup);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType to a specific PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
public override bool AddPropertyType(PropertyType propertyType, string propertyGroupName)
|
||||
{
|
||||
if (PropertyTypeExists(propertyType.Alias) == false)
|
||||
{
|
||||
if (PropertyGroups.Contains(propertyGroupName))
|
||||
{
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => PropertyGroups[propertyGroupName].Id);
|
||||
PropertyGroups[propertyGroupName].PropertyTypes.Add(propertyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the PropertyGroup doesn't already exist we create a new one
|
||||
var propertyTypes = new List<PropertyType> { propertyType };
|
||||
var propertyGroup = new PropertyGroup(new PropertyTypeCollection(propertyTypes)) { Name = propertyGroupName, SortOrder = 1 };
|
||||
//and check if its an inherited PropertyGroup, which exists in the composition
|
||||
if (CompositionPropertyGroups.Any(x => x.Name == propertyGroupName))
|
||||
{
|
||||
var parentPropertyGroup = CompositionPropertyGroups.First(x => x.Name == propertyGroupName && x.ParentId.HasValue == false);
|
||||
propertyGroup.SortOrder = parentPropertyGroup.SortOrder;
|
||||
//propertyGroup.ParentId = parentPropertyGroup.Id;
|
||||
propertyGroup.SetLazyParentId(new Lazy<int?>(() => parentPropertyGroup.Id));
|
||||
}
|
||||
|
||||
PropertyGroups.Add(propertyGroup);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of ContentType aliases from the current composition
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal static class ContentTypeExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get all descendant content types
|
||||
/// </summary>
|
||||
/// <param name="contentType"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<IContentTypeBase> Descendants(this IContentTypeBase contentType)
|
||||
{
|
||||
var contentTypeService = ApplicationContext.Current.Services.ContentTypeService;
|
||||
var descendants = contentTypeService.GetContentTypeChildren(contentType.Id)
|
||||
.FlattenList(type => contentTypeService.GetContentTypeChildren(type.Id));
|
||||
return descendants;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get all descendant and self content types
|
||||
/// </summary>
|
||||
/// <param name="contentType"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<IContentTypeBase> DescendantsAndSelf(this IContentTypeBase contentType)
|
||||
{
|
||||
var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants());
|
||||
return descendantsAndSelf;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Returns the descendant content type Ids for the given content type
|
||||
///// </summary>
|
||||
///// <param name="contentType"></param>
|
||||
///// <returns></returns>
|
||||
//public static IEnumerable<int> DescendantIds(this IContentTypeBase contentType)
|
||||
//{
|
||||
// return ((ContentTypeService) ApplicationContext.Current.Services.ContentTypeService)
|
||||
// .GetDescendantContentTypeIds(contentType.Id);
|
||||
//}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,17 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public class ContentTypeSort : IValueObject
|
||||
{
|
||||
public ContentTypeSort()
|
||||
{
|
||||
}
|
||||
|
||||
public ContentTypeSort(Lazy<int> id, int sortOrder, string @alias)
|
||||
{
|
||||
Id = id;
|
||||
SortOrder = sortOrder;
|
||||
Alias = alias;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the ContentType
|
||||
/// </summary>
|
||||
|
||||
@@ -15,12 +15,12 @@ namespace Umbraco.Core.Models
|
||||
public enum DataTypeDatabaseType
|
||||
{
|
||||
[EnumMember]
|
||||
Integer,
|
||||
[EnumMember]
|
||||
Date,
|
||||
Ntext,
|
||||
[EnumMember]
|
||||
Nvarchar,
|
||||
[EnumMember]
|
||||
Ntext /*, Object*/
|
||||
Integer,
|
||||
[EnumMember]
|
||||
Date
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -52,8 +53,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,8 +70,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,8 +87,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +104,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _level; }
|
||||
set
|
||||
{
|
||||
_level = value;
|
||||
OnPropertyChanged(LevelSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_level = value;
|
||||
return _level;
|
||||
}, _level, LevelSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +121,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
_path = value;
|
||||
OnPropertyChanged(PathSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,8 +138,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _creatorId; }
|
||||
set
|
||||
{
|
||||
_creatorId = value;
|
||||
OnPropertyChanged(UserIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_creatorId = value;
|
||||
return _creatorId;
|
||||
}, _creatorId, UserIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,8 +155,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _trashed; }
|
||||
internal set
|
||||
{
|
||||
_trashed = value;
|
||||
OnPropertyChanged(TrashedSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_trashed = value;
|
||||
return _trashed;
|
||||
}, _trashed, TrashedSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,9 +171,12 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get { return _controlId; }
|
||||
private set
|
||||
{
|
||||
_controlId = value;
|
||||
OnPropertyChanged(ControlIdSelector);
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_controlId = value;
|
||||
return _controlId;
|
||||
}, _controlId, ControlIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,16 +188,21 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
get { return _databaseType; }
|
||||
set
|
||||
{
|
||||
_databaseType = value;
|
||||
OnPropertyChanged(DatabaseTypeSelector);
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_databaseType = value;
|
||||
return _databaseType;
|
||||
}, _databaseType, DatabaseTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
base.AddingEntity();
|
||||
Key = Guid.NewGuid();
|
||||
|
||||
if(Key == default(Guid))
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -41,8 +42,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _parentId; }
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_parentId = value;
|
||||
return _parentId;
|
||||
}, _parentId, ParentIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +59,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _itemKey; }
|
||||
set
|
||||
{
|
||||
_itemKey = value;
|
||||
OnPropertyChanged(ItemKeySelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_itemKey = value;
|
||||
return _itemKey;
|
||||
}, _itemKey, ItemKeySelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +76,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _translations; }
|
||||
set
|
||||
{
|
||||
_translations = value;
|
||||
OnPropertyChanged(TranslationsSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_translations = value;
|
||||
return _translations;
|
||||
}, _translations, TranslationsSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -40,8 +41,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _language; }
|
||||
set
|
||||
{
|
||||
_language = value;
|
||||
OnPropertyChanged(LanguageSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_language = value;
|
||||
return _language;
|
||||
}, _language, LanguageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,8 +58,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _value; }
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
OnPropertyChanged(ValueSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_value = value;
|
||||
return _value;
|
||||
}, _value, ValueSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
@@ -12,12 +10,24 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class Entity : IEntity, ICanBeDirty
|
||||
[DebuggerDisplay("Id: {Id}")]
|
||||
public abstract class Entity : TracksChangesEntityBase, IEntity, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
private bool _hasIdentity;
|
||||
private int? _hash;
|
||||
private int _id;
|
||||
private Guid _key;
|
||||
private DateTime _createDate;
|
||||
private DateTime _updateDate;
|
||||
private bool _wasCancelled;
|
||||
|
||||
private static readonly PropertyInfo IdSelector = ExpressionHelper.GetPropertyInfo<Entity, int>(x => x.Id);
|
||||
private static readonly PropertyInfo KeySelector = ExpressionHelper.GetPropertyInfo<Entity, Guid>(x => x.Key);
|
||||
private static readonly PropertyInfo CreateDateSelector = ExpressionHelper.GetPropertyInfo<Entity, DateTime>(x => x.CreateDate);
|
||||
private static readonly PropertyInfo UpdateDateSelector = ExpressionHelper.GetPropertyInfo<Entity, DateTime>(x => x.UpdateDate);
|
||||
private static readonly PropertyInfo HasIdentitySelector = ExpressionHelper.GetPropertyInfo<Entity, bool>(x => x.HasIdentity);
|
||||
private static readonly PropertyInfo WasCancelledSelector = ExpressionHelper.GetPropertyInfo<Entity, bool>(x => x.WasCancelled);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id
|
||||
@@ -31,8 +41,12 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
}
|
||||
set
|
||||
{
|
||||
_id = value;
|
||||
HasIdentity = true;
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_id = value;
|
||||
HasIdentity = true; //set the has Identity
|
||||
return _id;
|
||||
}, _id, IdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,41 +65,71 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
|
||||
return _key;
|
||||
}
|
||||
set { _key = value; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_key = value;
|
||||
return _key;
|
||||
}, _key, KeySelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Created Date
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public DateTime CreateDate { get; set; }
|
||||
public DateTime CreateDate
|
||||
{
|
||||
get { return _createDate; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_createDate = value;
|
||||
return _createDate;
|
||||
}, _createDate, CreateDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// /// Gets or sets the WasCancelled flag, which is used to track
|
||||
/// whether some action against an entity was cancelled through some event.
|
||||
/// This only exists so we have a way to check if an event was cancelled through
|
||||
/// the new api, which also needs to take effect in the legacy api.
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal bool WasCancelled
|
||||
{
|
||||
get { return _wasCancelled; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_wasCancelled = value;
|
||||
return _wasCancelled;
|
||||
}, _wasCancelled, WasCancelledSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Modified Date
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Method to call on a property setter.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">The property info.</param>
|
||||
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
|
||||
public DateTime UpdateDate
|
||||
{
|
||||
_propertyChangedInfo[propertyInfo.Name] = true;
|
||||
|
||||
if (PropertyChanged != null)
|
||||
get { return _updateDate; }
|
||||
set
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_updateDate = value;
|
||||
return _updateDate;
|
||||
}, _updateDate, UpdateDateSelector);
|
||||
}
|
||||
}
|
||||
|
||||
protected void ResetIdentity()
|
||||
internal virtual void ResetIdentity()
|
||||
{
|
||||
_hasIdentity = false;
|
||||
_id = default(int);
|
||||
@@ -108,42 +152,6 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
UpdateDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the properties that have changed
|
||||
/// </summary>
|
||||
private readonly IDictionary<string, bool> _propertyChangedInfo = new Dictionary<string, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property is dirty, otherwise False</returns>
|
||||
public virtual bool IsPropertyDirty(string propertyName)
|
||||
{
|
||||
return _propertyChangedInfo.Any(x => x.Key == propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is dirty, otherwise False</returns>
|
||||
public virtual bool IsDirty()
|
||||
{
|
||||
return _propertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
public virtual void ResetDirtyProperties()
|
||||
{
|
||||
_propertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity has an identity, eg. Id.
|
||||
/// </summary>
|
||||
@@ -155,7 +163,11 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
}
|
||||
protected set
|
||||
{
|
||||
_hasIdentity = value;
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_hasIdentity = value;
|
||||
return _hasIdentity;
|
||||
}, _hasIdentity, HasIdentitySelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// An interface that defines if the object is tracking property changes and that is is also
|
||||
/// remembering what property changes had been made after the changes were committed.
|
||||
/// </summary>
|
||||
public interface IRememberBeingDirty : ICanBeDirty
|
||||
{
|
||||
bool WasDirty();
|
||||
bool WasPropertyDirty(string propertyName);
|
||||
void ForgetPreviouslyDirtyProperties();
|
||||
}
|
||||
}
|
||||
@@ -3,29 +3,34 @@
|
||||
public interface IUmbracoEntity : IAggregateRoot
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent entity
|
||||
/// Profile of the user who created this Entity
|
||||
/// </summary>
|
||||
int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the sort order of the Entity
|
||||
/// </summary>
|
||||
int SortOrder { get; set; }
|
||||
int CreatorId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the level of the Entity
|
||||
/// </summary>
|
||||
int Level { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the Entity
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Id of the Parent Entity
|
||||
/// </summary>
|
||||
int ParentId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Entity
|
||||
/// </summary>
|
||||
string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Profile of the user who created this Entity
|
||||
/// Gets or sets the sort order of the Entity
|
||||
/// </summary>
|
||||
int CreatorId { get; set; }
|
||||
int SortOrder { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether this Entity is Trashed or not.
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for use to implement IRememberBeingDirty/ICanBeDirty
|
||||
/// </summary>
|
||||
public abstract class TracksChangesEntityBase : IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracks the properties that have changed
|
||||
/// </summary>
|
||||
private readonly IDictionary<string, bool> _propertyChangedInfo = new Dictionary<string, bool>();
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the properties that we're changed before the last commit (or last call to ResetDirtyProperties)
|
||||
/// </summary>
|
||||
private IDictionary<string, bool> _lastPropertyChangedInfo = null;
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Method to call on a property setter.
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo">The property info.</param>
|
||||
protected virtual void OnPropertyChanged(PropertyInfo propertyInfo)
|
||||
{
|
||||
_propertyChangedInfo[propertyInfo.Name] = true;
|
||||
|
||||
if (PropertyChanged != null)
|
||||
{
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property is dirty, otherwise False</returns>
|
||||
public virtual bool IsPropertyDirty(string propertyName)
|
||||
{
|
||||
return _propertyChangedInfo.Any(x => x.Key == propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity is dirty.
|
||||
/// </summary>
|
||||
/// <returns>True if entity is dirty, otherwise False</returns>
|
||||
public virtual bool IsDirty()
|
||||
{
|
||||
return _propertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates that the entity had been changed and the changes were committed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool WasDirty()
|
||||
{
|
||||
return _lastPropertyChangedInfo != null && _lastPropertyChangedInfo.Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a specific property on the current entity was changed and the changes were committed
|
||||
/// </summary>
|
||||
/// <param name="propertyName">Name of the property to check</param>
|
||||
/// <returns>True if Property was changed, otherwise False. Returns false if the entity had not been previously changed.</returns>
|
||||
public virtual bool WasPropertyDirty(string propertyName)
|
||||
{
|
||||
return WasDirty() && _lastPropertyChangedInfo.Any(x => x.Key == propertyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets the remembered dirty properties from before the last commit
|
||||
/// </summary>
|
||||
public void ForgetPreviouslyDirtyProperties()
|
||||
{
|
||||
_lastPropertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
public virtual void ResetDirtyProperties()
|
||||
{
|
||||
ResetDirtyProperties(true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties by clearing the dictionary used to track changes.
|
||||
/// </summary>
|
||||
/// <param name="rememberPreviouslyChangedProperties">
|
||||
/// true if we are to remember the last changes made after resetting
|
||||
/// </param>
|
||||
/// <remarks>
|
||||
/// Please note that resetting the dirty properties could potentially
|
||||
/// obstruct the saving of a new or updated entity.
|
||||
/// </remarks>
|
||||
internal void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
if (rememberPreviouslyChangedProperties)
|
||||
{
|
||||
//copy the changed properties to the last changed properties
|
||||
_lastPropertyChangedInfo = _propertyChangedInfo.ToDictionary(v => v.Key, v => v.Value);
|
||||
}
|
||||
|
||||
_propertyChangedInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by inheritors to set the value of properties, this will detect if the property value actually changed and if it did
|
||||
/// it will ensure that the property has a dirty flag set.
|
||||
/// </summary>
|
||||
/// <param name="setValue"></param>
|
||||
/// <param name="value"></param>
|
||||
/// <param name="propertySelector"></param>
|
||||
/// <returns>returns true if the value changed</returns>
|
||||
/// <remarks>
|
||||
/// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we
|
||||
/// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set
|
||||
/// to the same value, so it's really not dirty.
|
||||
/// </remarks>
|
||||
internal bool SetPropertyValueAndDetectChanges<T>(Func<T, T> setValue, T value, PropertyInfo propertySelector)
|
||||
{
|
||||
var initVal = value;
|
||||
var newVal = setValue(value);
|
||||
if (!Equals(initVal, newVal))
|
||||
{
|
||||
OnPropertyChanged(propertySelector);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -12,11 +13,17 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
public abstract class File : Entity, IFile
|
||||
{
|
||||
private string _path;
|
||||
private string _content = string.Empty; //initialize to empty string, not null
|
||||
|
||||
protected File(string path)
|
||||
{
|
||||
Path = path;
|
||||
_path = path;
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo ContentSelector = ExpressionHelper.GetPropertyInfo<File, string>(x => x.Content);
|
||||
private static readonly PropertyInfo PathSelector = ExpressionHelper.GetPropertyInfo<File, string>(x => x.Path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the File including extension
|
||||
/// </summary>
|
||||
@@ -48,29 +55,40 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or sets the Path to the File from the root of the site
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string Path { get; set; }
|
||||
public virtual string Path
|
||||
{
|
||||
get { return _path; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_path = value;
|
||||
return _path;
|
||||
}, _path, PathSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Content of a File
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public virtual string Content { get; set; }
|
||||
public virtual string Content
|
||||
{
|
||||
get { return _content; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_content = value;
|
||||
return _content;
|
||||
}, _content, ContentSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Boolean indicating whether the file could be validated
|
||||
/// </summary>
|
||||
/// <returns>True if file is valid, otherwise false</returns>
|
||||
public abstract bool IsValid();
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether the current entity has an identity, which in this case is a path/name.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Overrides the default Entity identity check.
|
||||
/// </remarks>
|
||||
public override bool HasIdentity
|
||||
{
|
||||
get { return string.IsNullOrEmpty(Path) == false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,12 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a Content object
|
||||
/// </summary>
|
||||
/// </summary>
|
||||
public interface IContent : IContentBase
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -10,11 +10,6 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
public interface IContentBase : IUmbracoEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the Content
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Integer Id of the default ContentType
|
||||
/// </summary>
|
||||
@@ -83,6 +78,6 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
|
||||
/// <param name="parentId"> </param>
|
||||
void ChangeTrashedState(bool isTrashed, int parentId = -1);
|
||||
void ChangeTrashedState(bool isTrashed, int parentId = -20);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -15,11 +15,6 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Name of the ContentType
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the Description for the ContentType
|
||||
/// </summary>
|
||||
@@ -74,5 +69,43 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
void SetLazyParentId(Lazy<int> id);
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a PropertyType with a given alias already exists
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyType with the passed in alias exists, otherwise <c>False</c></returns>
|
||||
bool PropertyTypeExists(string propertyTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType to a specific PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to add the PropertyType to</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
bool AddPropertyType(PropertyType propertyType, string propertyGroupName);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyType, which does not belong to a PropertyGroup.
|
||||
/// </summary>
|
||||
/// <param name="propertyType"><see cref="PropertyType"/> to add</param>
|
||||
/// <returns>Returns <c>True</c> if PropertyType was added, otherwise <c>False</c></returns>
|
||||
bool AddPropertyType(PropertyType propertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Adds a PropertyGroup.
|
||||
/// This method will also check if a group already exists with the same name and link it to the parent.
|
||||
/// </summary>
|
||||
/// <param name="groupName">Name of the PropertyGroup to add</param>
|
||||
/// <returns>Returns <c>True</c> if a PropertyGroup with the passed in name was added, otherwise <c>False</c></returns>
|
||||
bool AddPropertyGroup(string groupName);
|
||||
|
||||
/// <summary>
|
||||
/// Moves a PropertyType to a specified PropertyGroup
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType to move</param>
|
||||
/// <param name="propertyGroupName">Name of the PropertyGroup to move the PropertyType to</param>
|
||||
/// <returns></returns>
|
||||
bool MovePropertyType(string propertyTypeAlias, string propertyGroupName);
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IDataTypeDefinition : IUmbracoEntity
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the current entity
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Id of the DataType control
|
||||
/// </summary>
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
namespace Umbraco.Core.Models
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IMedia : IContentBase
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
namespace Umbraco.Core.Models
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines a ContentType, which Media is based on
|
||||
/// </summary>
|
||||
/// </summary
|
||||
public interface IMediaType : IContentTypeComposition
|
||||
{
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -33,8 +34,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _isoCode; }
|
||||
set
|
||||
{
|
||||
_isoCode = value;
|
||||
OnPropertyChanged(IsoCodeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_isoCode = value;
|
||||
return _isoCode;
|
||||
}, _isoCode, IsoCodeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,8 +51,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _cultureName; }
|
||||
set
|
||||
{
|
||||
_cultureName = value;
|
||||
OnPropertyChanged(CultureNameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cultureName = value;
|
||||
return _cultureName;
|
||||
}, _cultureName, CultureNameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
@@ -12,81 +13,240 @@ namespace Umbraco.Core.Models
|
||||
[DataContract(IsReference = true)]
|
||||
internal class Macro : Entity, IMacro
|
||||
{
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private bool _useInEditor;
|
||||
private int _cacheDuration;
|
||||
private bool _cacheByPage;
|
||||
private bool _cacheByMember;
|
||||
private bool _dontRender;
|
||||
private string _scriptFile;
|
||||
private string _scriptAssembly;
|
||||
private string _python;
|
||||
private string _xslt;
|
||||
private List<IMacroProperty> _properties;
|
||||
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Name);
|
||||
private static readonly PropertyInfo UseInEditorSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.UseInEditor);
|
||||
private static readonly PropertyInfo CacheDurationSelector = ExpressionHelper.GetPropertyInfo<Macro, int>(x => x.CacheDuration);
|
||||
private static readonly PropertyInfo CacheByPageSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.CacheByPage);
|
||||
private static readonly PropertyInfo CacheByMemberSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.CacheByMember);
|
||||
private static readonly PropertyInfo DontRenderSelector = ExpressionHelper.GetPropertyInfo<Macro, bool>(x => x.DontRender);
|
||||
private static readonly PropertyInfo ScriptFileSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.ScriptFile);
|
||||
private static readonly PropertyInfo ScriptAssemblySelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.ScriptAssembly);
|
||||
private static readonly PropertyInfo PythonSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Python);
|
||||
private static readonly PropertyInfo XsltSelector = ExpressionHelper.GetPropertyInfo<Macro, string>(x => x.Xslt);
|
||||
private static readonly PropertyInfo PropertiesSelector = ExpressionHelper.GetPropertyInfo<Macro, List<IMacroProperty>>(x => x.Properties);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias of the Macro
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias { get; set; }
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the Macro
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro can be used in an Editor
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool UseInEditor { get; set; }
|
||||
public bool UseInEditor
|
||||
{
|
||||
get { return _useInEditor; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_useInEditor = value;
|
||||
return _useInEditor;
|
||||
}, _useInEditor, UseInEditorSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Cache Duration for the Macro
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int CacheDuration { get; set; }
|
||||
public int CacheDuration
|
||||
{
|
||||
get { return _cacheDuration; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cacheDuration = value;
|
||||
return _cacheDuration;
|
||||
}, _cacheDuration, CacheDurationSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro should be Cached by Page
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool CacheByPage { get; set; }
|
||||
public bool CacheByPage
|
||||
{
|
||||
get { return _cacheByPage; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cacheByPage = value;
|
||||
return _cacheByPage;
|
||||
}, _cacheByPage, CacheByPageSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro should be Cached Personally
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool CacheByMember { get; set; }
|
||||
public bool CacheByMember
|
||||
{
|
||||
get { return _cacheByMember; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_cacheByMember = value;
|
||||
return _cacheByMember;
|
||||
}, _cacheByMember, CacheByMemberSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether the Macro should be rendered in an Editor
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public bool DontRender { get; set; }
|
||||
public bool DontRender
|
||||
{
|
||||
get { return _dontRender; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dontRender = value;
|
||||
return _dontRender;
|
||||
}, _dontRender, DontRenderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the script file in use
|
||||
/// </summary>
|
||||
/// <remarks>Optional: Can only be one of three Script, Python or Xslt</remarks>
|
||||
[DataMember]
|
||||
public string ScriptFile { get; set; }
|
||||
public string ScriptFile
|
||||
{
|
||||
get { return _scriptFile; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_scriptFile = value;
|
||||
return _scriptFile;
|
||||
}, _scriptFile, ScriptFileSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the name of the assembly, which should be used by the Macro
|
||||
/// </summary>
|
||||
/// <remarks>Will usually only be filled if the ScriptFile is a Usercontrol</remarks>
|
||||
[DataMember]
|
||||
public string ScriptAssembly { get; set; }
|
||||
public string ScriptAssembly
|
||||
{
|
||||
get { return _scriptAssembly; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_scriptAssembly = value;
|
||||
return _scriptAssembly;
|
||||
}, _scriptAssembly, ScriptAssemblySelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or set the path to the Python file in use
|
||||
/// </summary>
|
||||
/// <remarks>Optional: Can only be one of three Script, Python or Xslt</remarks>
|
||||
[DataMember]
|
||||
public string Python { get; set; }
|
||||
public string Python
|
||||
{
|
||||
get { return _python; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_python = value;
|
||||
return _python;
|
||||
}, _python, PythonSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path to the Xslt file in use
|
||||
/// </summary>
|
||||
/// <remarks>Optional: Can only be one of three Script, Python or Xslt</remarks>
|
||||
[DataMember]
|
||||
public string Xslt { get; set; }
|
||||
public string Xslt
|
||||
{
|
||||
get { return _xslt; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_xslt = value;
|
||||
return _xslt;
|
||||
}, _xslt, XsltSelector);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: This needs to be changed to a custom collection class so we can track the dirtyness of each property!
|
||||
/// <summary>
|
||||
/// Gets or sets a list of Macro Properties
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public List<IMacroProperty> Properties { get; set; }
|
||||
public List<IMacroProperty> Properties
|
||||
{
|
||||
get { return _properties; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_properties = value;
|
||||
return _properties;
|
||||
}, _properties, PropertiesSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overridden this method in order to set a random Id
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -8,25 +10,68 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class MacroProperty : IMacroProperty
|
||||
internal class MacroProperty : TracksChangesEntityBase, IMacroProperty, IRememberBeingDirty
|
||||
{
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private int _sortOrder;
|
||||
private IMacroPropertyType _propertyType;
|
||||
|
||||
private static readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, string>(x => x.Alias);
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, string>(x => x.Name);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo PropertyTypeSelector = ExpressionHelper.GetPropertyInfo<MacroProperty, IMacroPropertyType>(x => x.PropertyType);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Alias of the Property
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias { get; set; }
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the Property
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Name { get; set; }
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Sort Order of the Property
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public int SortOrder { get; set; }
|
||||
public int SortOrder
|
||||
{
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Type for this Property
|
||||
@@ -36,6 +81,18 @@ namespace Umbraco.Core.Models
|
||||
/// All types was previously contained in the database, but has been ported to code.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public IMacroPropertyType PropertyType { get; set; }
|
||||
public IMacroPropertyType PropertyType
|
||||
|
||||
{
|
||||
get { return _propertyType; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_propertyType = value;
|
||||
return _propertyType;
|
||||
}, _propertyType, PropertyTypeSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -111,19 +112,11 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <param name="isTrashed">Boolean indicating whether content is trashed (true) or not trashed (false)</param>
|
||||
/// <param name="parentId"> </param>
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -1)
|
||||
public override void ChangeTrashedState(bool isTrashed, int parentId = -20)
|
||||
{
|
||||
Trashed = isTrashed;
|
||||
|
||||
//If Content is trashed the parent id should be set to that of the RecycleBin
|
||||
if (isTrashed)
|
||||
{
|
||||
ParentId = -21;
|
||||
}
|
||||
else//otherwise set the parent id to the optional parameter, -1 being the fallback
|
||||
{
|
||||
ParentId = parentId;
|
||||
}
|
||||
//The Media Recycle Bin Id is -21 so we correct that here
|
||||
ParentId = parentId == -20 ? -21 : parentId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
@@ -12,7 +13,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
int SessionTimeout { get; set; }
|
||||
int StartContentId { get; set; }
|
||||
int StartMediaId { get; set; }
|
||||
string Lanuguage { get; set; }
|
||||
string Language { get; set; }
|
||||
bool DefaultToLiveEditing { get; set; }
|
||||
IEnumerable<string> Applications { get; set; }
|
||||
bool NoConsole { get; set; }
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
internal interface IUserType : IAggregateRoot
|
||||
{
|
||||
string Alias { get; set; }
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
@@ -88,7 +89,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
#region Implementation of IUser
|
||||
|
||||
[DataMember]
|
||||
public string Lanuguage { get; set; }
|
||||
public string Language { get; set; }
|
||||
[DataMember]
|
||||
public string Permissions { get; set; }
|
||||
[DataMember]
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -82,8 +83,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _version; }
|
||||
set
|
||||
{
|
||||
_version = value;
|
||||
OnPropertyChanged(VersionSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_version = value;
|
||||
return _version;
|
||||
}, _version, VersionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,8 +112,11 @@ namespace Umbraco.Core.Models
|
||||
"Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'",
|
||||
value == null ? "null" : value.GetType().Name, Alias));
|
||||
|
||||
_value = value;
|
||||
OnPropertyChanged(ValueSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_value = value;
|
||||
return _value;
|
||||
}, _value, ValueSelector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -13,11 +14,19 @@ namespace Umbraco.Core.Models
|
||||
/// <returns>Xml of the property and its value</returns>
|
||||
public static XElement ToXml(this Property property)
|
||||
{
|
||||
string nodeName = property.Alias.ToUmbracoAlias(StringAliasCaseType.CamelCase, true);
|
||||
string nodeName = UmbracoSettings.UseLegacyXmlSchema ? "data" : property.Alias.ToSafeAlias();
|
||||
|
||||
var xd = new XmlDocument();
|
||||
XmlNode xmlNode = xd.CreateNode(XmlNodeType.Element, nodeName, "");
|
||||
|
||||
//Add the property alias to the legacy schema
|
||||
if (UmbracoSettings.UseLegacyXmlSchema)
|
||||
{
|
||||
var alias = xd.CreateAttribute("alias");
|
||||
alias.Value = property.Alias.ToSafeAlias();
|
||||
xmlNode.Attributes.Append(alias);
|
||||
}
|
||||
|
||||
//This seems to fail during testing
|
||||
xmlNode.AppendChild(property.PropertyType.DataType(property.Id).Data.ToXMl(xd));
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Specialized;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -14,7 +15,7 @@ namespace Umbraco.Core.Models
|
||||
public class PropertyGroup : Entity, IEquatable<PropertyGroup>
|
||||
{
|
||||
private string _name;
|
||||
private int? _parentId;
|
||||
private Lazy<int?> _parentId;
|
||||
private int _sortOrder;
|
||||
private PropertyTypeCollection _propertyTypes;
|
||||
|
||||
@@ -45,21 +46,33 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the Name of the Group, which corresponds to the Tab-name in the UI
|
||||
/// Gets or sets the Id of the Parent PropertyGroup.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A Parent PropertyGroup corresponds to an inherited PropertyGroup from a composition.
|
||||
/// If a PropertyType is inserted into an inherited group then a new group will be created with an Id reference to the parent.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public int? ParentId
|
||||
{
|
||||
get { return _parentId; }
|
||||
get
|
||||
{
|
||||
if (_parentId == null)
|
||||
return default(int?);
|
||||
return _parentId.Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
_parentId = value;
|
||||
_parentId = new Lazy<int?>(() => value);
|
||||
OnPropertyChanged(ParentIdSelector);
|
||||
}
|
||||
}
|
||||
@@ -73,8 +86,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +108,15 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the ParentId from the lazy integer id
|
||||
/// </summary>
|
||||
/// <param name="id">Id of the Parent</param>
|
||||
internal void SetLazyParentId(Lazy<int?> id)
|
||||
{
|
||||
_parentId = id;
|
||||
}
|
||||
|
||||
public bool Equals(PropertyGroup other)
|
||||
{
|
||||
//Check whether the compared object is null.
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -18,7 +19,7 @@ namespace Umbraco.Core.Models
|
||||
private string _alias;
|
||||
private string _description;
|
||||
private int _dataTypeDefinitionId;
|
||||
private int _propertyGroupId;
|
||||
private Lazy<int> _propertyGroupId;
|
||||
private Guid _dataTypeId;
|
||||
private DataTypeDatabaseType _dataTypeDatabaseType;
|
||||
private bool _mandatory;
|
||||
@@ -61,7 +62,7 @@ namespace Umbraco.Core.Models
|
||||
private static readonly PropertyInfo HelpTextSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.HelpText);
|
||||
private static readonly PropertyInfo SortOrderSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.SortOrder);
|
||||
private static readonly PropertyInfo ValidationRegExpSelector = ExpressionHelper.GetPropertyInfo<PropertyType, string>(x => x.ValidationRegExp);
|
||||
private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, int>(x => x.PropertyGroupId);
|
||||
private static readonly PropertyInfo PropertyGroupIdSelector = ExpressionHelper.GetPropertyInfo<PropertyType, Lazy<int>>(x => x.PropertyGroupId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets of Sets the Name of the PropertyType
|
||||
@@ -72,8 +73,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _name; }
|
||||
set
|
||||
{
|
||||
_name = value;
|
||||
OnPropertyChanged(NameSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_name = value;
|
||||
return _name;
|
||||
}, _name, NameSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +90,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
OnPropertyChanged(AliasSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_alias = value;
|
||||
return _alias;
|
||||
}, _alias, AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +107,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _description; }
|
||||
set
|
||||
{
|
||||
_description = value;
|
||||
OnPropertyChanged(DescriptionSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_description = value;
|
||||
return _description;
|
||||
}, _description, DescriptionSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,8 +125,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _dataTypeDefinitionId; }
|
||||
set
|
||||
{
|
||||
_dataTypeDefinitionId = value;
|
||||
OnPropertyChanged(DataTypeDefinitionIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dataTypeDefinitionId = value;
|
||||
return _dataTypeDefinitionId;
|
||||
}, _dataTypeDefinitionId, DataTypeDefinitionIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,8 +143,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _dataTypeId; }
|
||||
internal set
|
||||
{
|
||||
_dataTypeId = value;
|
||||
OnPropertyChanged(DataTypeControlIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dataTypeId = value;
|
||||
return _dataTypeId;
|
||||
}, _dataTypeId, DataTypeControlIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,8 +160,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _dataTypeDatabaseType; }
|
||||
set
|
||||
{
|
||||
_dataTypeDatabaseType = value;
|
||||
OnPropertyChanged(DataTypeDatabaseTypeSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_dataTypeDatabaseType = value;
|
||||
return _dataTypeDatabaseType;
|
||||
}, _dataTypeDatabaseType, DataTypeDatabaseTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,13 +172,16 @@ namespace Umbraco.Core.Models
|
||||
/// Gets or Sets the PropertyGroup's Id for which this PropertyType belongs
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
internal int PropertyGroupId
|
||||
internal Lazy<int> PropertyGroupId
|
||||
{
|
||||
get { return _propertyGroupId; }
|
||||
set
|
||||
{
|
||||
_propertyGroupId = value;
|
||||
OnPropertyChanged(PropertyGroupIdSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_propertyGroupId = value;
|
||||
return _propertyGroupId;
|
||||
}, _propertyGroupId, PropertyGroupIdSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,8 +194,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _mandatory; }
|
||||
set
|
||||
{
|
||||
_mandatory = value;
|
||||
OnPropertyChanged(MandatorySelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_mandatory = value;
|
||||
return _mandatory;
|
||||
}, _mandatory, MandatorySelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,8 +211,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _helpText; }
|
||||
set
|
||||
{
|
||||
_helpText = value;
|
||||
OnPropertyChanged(HelpTextSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_helpText = value;
|
||||
return _helpText;
|
||||
}, _helpText, HelpTextSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,8 +228,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _sortOrder; }
|
||||
set
|
||||
{
|
||||
_sortOrder = value;
|
||||
OnPropertyChanged(SortOrderSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_sortOrder = value;
|
||||
return _sortOrder;
|
||||
}, _sortOrder, SortOrderSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,8 +245,11 @@ namespace Umbraco.Core.Models
|
||||
get { return _validationRegExp; }
|
||||
set
|
||||
{
|
||||
_validationRegExp = value;
|
||||
OnPropertyChanged(ValidationRegExpSelector);
|
||||
SetPropertyValueAndDetectChanges(o =>
|
||||
{
|
||||
_validationRegExp = value;
|
||||
return _validationRegExp;
|
||||
}, _validationRegExp, ValidationRegExpSelector);
|
||||
}
|
||||
}
|
||||
//Note that Validation should eventually come from PropertyEditors like in v5
|
||||
@@ -335,8 +369,8 @@ namespace Umbraco.Core.Models
|
||||
if (Mandatory && (value == null || string.IsNullOrEmpty(value.ToString())))
|
||||
return false;
|
||||
|
||||
//Check against Regular Expression for Legacy DataTypes
|
||||
if(!string.IsNullOrEmpty(ValidationRegExp))
|
||||
//Check against Regular Expression for Legacy DataTypes - Validation exists and value is not null:
|
||||
if(string.IsNullOrEmpty(ValidationRegExp) == false && (value != null && string.IsNullOrEmpty(value.ToString()) == false))
|
||||
{
|
||||
var regexPattern = new Regex(ValidationRegExp);
|
||||
return regexPattern.IsMatch(value.ToString());
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoServer")]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class ServerRegistrationDto
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(AutoIncrement = true)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("address")]
|
||||
[Length(500)]
|
||||
public string Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A unique column in the database, a computer name must always be unique!
|
||||
/// </summary>
|
||||
[Column("computerName")]
|
||||
[Length(255)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_computerName")]
|
||||
public string ComputerName { get; set; }
|
||||
|
||||
[Column("registeredDate")]
|
||||
[Constraint(Default = "getdate()")]
|
||||
public DateTime DateRegistered { get; set; }
|
||||
|
||||
[Column("lastNotifiedDate")]
|
||||
[Constraint(Default = "getdate()")]
|
||||
public DateTime LastNotified { get; set; }
|
||||
|
||||
[Column("isActive")]
|
||||
[Index(IndexTypes.NonClustered)]
|
||||
public bool IsActive { get; set; }
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user