Compare commits
712 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a0651f4383 | |||
| 9452d5fd09 | |||
| 1f40d726de | |||
| 2699611ba3 | |||
| 43795f0007 | |||
| b1fa06bfe8 | |||
| 4dc22b6ce4 | |||
| d4ab60f8af | |||
| 883277125a | |||
| 8edfc0ffdd | |||
| ff961abaab | |||
| b2414c1ab8 | |||
| 9dde86d591 | |||
| b4ce4fbdef | |||
| 4285484c1b | |||
| 2fd299ebfc | |||
| f545f293b1 | |||
| b745c0ae90 | |||
| f2efff5411 | |||
| 9ef5890636 | |||
| bc9fd04a36 | |||
| 185c5d78f1 | |||
| 3ea9963166 | |||
| ab40822a98 | |||
| dffce76e29 | |||
| d1e02f506c | |||
| 5e18d13178 | |||
| 1dfca6836d | |||
| dbbdd16bb9 | |||
| 74362fba23 | |||
| 112502cf18 | |||
| 1db7f808c9 | |||
| 762cca145f | |||
| 65dc5eaeee | |||
| 4f81e06d3d | |||
| 6b74b75b6f | |||
| 98e53b3d74 | |||
| a1f01f9d5c | |||
| f5d8cb0275 | |||
| 0d8b65caea | |||
| 70285991bb | |||
| a336eaa4a1 | |||
| fdefe993b7 | |||
| ba0e72a1c1 | |||
| c5710277a5 | |||
| 5cd2d568e3 | |||
| 9c89a56d8d | |||
| 9ba7664f78 | |||
| 4b87a5c2d3 | |||
| f0699afb6e | |||
| b4d5658d45 | |||
| d485c3da97 | |||
| 1214082997 | |||
| 1a56e6693a | |||
| c6b7f20dab | |||
| 5cc55ad6e2 | |||
| a55fedab0a | |||
| 0e12f14a4a | |||
| 3e25b71d9e | |||
| 63de9e6691 | |||
| b9ea85d29d | |||
| d0787e92fe | |||
| ffe9953c43 | |||
| 99a9f1ab87 | |||
| 7def26a489 | |||
| a76ffe8daf | |||
| 259fbcb8f0 | |||
| ee9f91b5cf | |||
| db3f21429e | |||
| 033692d7ee | |||
| 23146cb12a | |||
| 04b9607741 | |||
| 0e392b398c | |||
| 5914690ad8 | |||
| c4aa9095f2 | |||
| 79ce586c8b | |||
| 8fba03c05d | |||
| 2fdcb9164a | |||
| 7404a1f93d | |||
| c8b8b28e9b | |||
| 5bd2571395 | |||
| c0cd157e60 | |||
| ac2f9b172c | |||
| b8e4a73c3b | |||
| 63192f3a65 | |||
| 727f62d418 | |||
| 68c4255a51 | |||
| 187af3e361 | |||
| c6f29a50d6 | |||
| d07212c89b | |||
| 28c55320a1 | |||
| cb0dd70434 | |||
| fd58017e97 | |||
| 928d92fce4 | |||
| 09408b898e | |||
| d1b05332c5 | |||
| 836b0f39c2 | |||
| 1b01386673 | |||
| 2a09f02afb | |||
| ee95434cea | |||
| caad0afed8 | |||
| fe08e7fc2f | |||
| 4ad96b49e7 | |||
| 9a1bb4a2dd | |||
| c39f902ed5 | |||
| b7dc052cb2 | |||
| 0c77114cd5 | |||
| 222a5237b0 | |||
| de55cb8392 | |||
| df164ee618 | |||
| 21b0687a57 | |||
| 9310efa280 | |||
| a41b55a9e6 | |||
| af2d8a4755 | |||
| d48e339b81 | |||
| 9b6d498cf7 | |||
| 62d365573f | |||
| 04bf011fcd | |||
| f3b7a8a581 | |||
| 5d62902684 | |||
| 82d645a0f7 | |||
| a8936de638 | |||
| a765f36d24 | |||
| 6b691eb461 | |||
| 046da1a8ce | |||
| ca7abd6c78 | |||
| 452688b2bb | |||
| 7cc0f2a514 | |||
| a2251fe062 | |||
| 3d0684eac0 | |||
| a8fafaa194 | |||
| 2b8a6e532e | |||
| d497659f1f | |||
| 0cafeac6eb | |||
| 4516305f3c | |||
| 04c8390a4f | |||
| fc94d92b37 | |||
| 84171c6b98 | |||
| 3ff88bc4fa | |||
| 4b54edf660 | |||
| 1bc9d1d9c3 | |||
| b5cbe63a4e | |||
| 4882df43bd | |||
| cb03178d99 | |||
| 361fa8836b | |||
| 194ebb57b9 | |||
| 5effe5015e | |||
| ee2943b9fb | |||
| a3b03988b3 | |||
| 6d5f7c4293 | |||
| cc32e73235 | |||
| 92ef4d8055 | |||
| e57e2f5b5f | |||
| 0b4efe4eeb | |||
| c250fa560e | |||
| 6eeae52333 | |||
| c38c18fed8 | |||
| 0af47963c6 | |||
| b017e8690a | |||
| 916e442ee4 | |||
| ecae9c47b7 | |||
| 836a99128f | |||
| abefbc7581 | |||
| 365addedf4 | |||
| 44f5439a2c | |||
| 8a9680e75c | |||
| ae0991bc67 | |||
| 0caaaa500c | |||
| 36c66e676a | |||
| a14baeb111 | |||
| 5b4d8ed6f3 | |||
| 25ea4003f9 | |||
| 30cef671dc | |||
| 250e627b1d | |||
| 5b00501d21 | |||
| 06e5350c43 | |||
| ba530061a0 | |||
| 89ae3bc143 | |||
| 484afccf89 | |||
| 3951f59d09 | |||
| 2589ec8367 | |||
| a6aeada197 | |||
| cd8c998ebf | |||
| 2a9e32e8fd | |||
| 603724ddd6 | |||
| 902cfc5a22 | |||
| 2cb544591b | |||
| db7aa99b85 | |||
| 031ceccf5d | |||
| 7127706c43 | |||
| d078ef8f5e | |||
| 289b9743c5 | |||
| eda9ba07f4 | |||
| 1b1b5c047c | |||
| fa5b9e5689 | |||
| 6948d70b75 | |||
| 3f9b022ae4 | |||
| 990ab7f87f | |||
| 861198eec9 | |||
| c26df8da6f | |||
| b5aefdce04 | |||
| adfb7cfaa4 | |||
| 0a88ba05c8 | |||
| 9ee295d49e | |||
| 1e02d85fca | |||
| 7173b44b4f | |||
| 69f6edadb3 | |||
| d1dc2331f8 | |||
| bb2f3a1732 | |||
| 4b29d7ba2e | |||
| d503deb8c5 | |||
| 0859b92aaf | |||
| b409740da5 | |||
| a888e0564c | |||
| fef96e8b43 | |||
| 429522a0bc | |||
| e9b2261aab | |||
| 02adb6e112 | |||
| 695d26434c | |||
| 00d408e6bc | |||
| 0498161367 | |||
| 0d3d4693b4 | |||
| a19de645e4 | |||
| f0a53ea9c0 | |||
| fbcabc94f2 | |||
| de9a27db10 | |||
| d494b061f3 | |||
| ebc8443e70 | |||
| 48ee59b94e | |||
| 560dcad90a | |||
| 7498b2f994 | |||
| df4f92197a | |||
| 13b1191aad | |||
| adaec42982 | |||
| b6d5b7d603 | |||
| 93d7cf4dc3 | |||
| e9f2546c2a | |||
| 007c4d5862 | |||
| f3621aa743 | |||
| 46cf4398a0 | |||
| 1599f493fa | |||
| b5d79ebb74 | |||
| 1cc8367fa9 | |||
| 7e5087ae7d | |||
| d6f9909bec | |||
| 0c42596dc8 | |||
| 9b4da4c8f8 | |||
| cfc81d0e84 | |||
| 00e10deecb | |||
| 46e67e4a92 | |||
| 520a7f238d | |||
| 3c41871e59 | |||
| 8cf9c1ba97 | |||
| e2d806f5d9 | |||
| 7a47d63b48 | |||
| 596c4ac329 | |||
| 8ad8a3239a | |||
| c0fa011cc3 | |||
| 4648a8c103 | |||
| 2df05da7fc | |||
| 87947871d1 | |||
| 87fee572ff | |||
| e00c0fc447 | |||
| 7137c57ac9 | |||
| d68b4d97f6 | |||
| 89f7a3ec63 | |||
| 96a62b57fb | |||
| 7092a9ccbb | |||
| e9ea9b5e1b | |||
| fd1efb29ec | |||
| cf4781153e | |||
| 46687429fb | |||
| ce7aa43aa7 | |||
| ebed142cd5 | |||
| 76e5304233 | |||
| d162aba14a | |||
| 387398b044 | |||
| 635b8bd82e | |||
| f2071379fc | |||
| ec075f5807 | |||
| eb8875066c | |||
| dca90e6316 | |||
| 2a47b384d2 | |||
| 29e5872a0f | |||
| df31fafec5 | |||
| 5f28f279e0 | |||
| 828dc64035 | |||
| 1d9e445a42 | |||
| 1aa137e9da | |||
| 042eb47c17 | |||
| a6556d0195 | |||
| 0b74164a8e | |||
| 807b32fb0d | |||
| 62be1b1267 | |||
| bda3fbc698 | |||
| 85ae7e764f | |||
| c744e47665 | |||
| 3daa624627 | |||
| 9a7894df76 | |||
| d8af1aaf7b | |||
| f2d105d8b9 | |||
| c93193c5c8 | |||
| 6734420c6f | |||
| fd795e14c6 | |||
| d622f76393 | |||
| d4fc82dae1 | |||
| d4058bd81f | |||
| bc824ba66a | |||
| 4201286038 | |||
| e333ad2b23 | |||
| a8eeabb73d | |||
| b06620f56e | |||
| e8524963dd | |||
| 5b0a8c0668 | |||
| 5d931d1146 | |||
| 879c77c68d | |||
| e71dd3008d | |||
| 597c888d36 | |||
| ef4c02f759 | |||
| 452a0a43b0 | |||
| c3ccf3a609 | |||
| 60bbede408 | |||
| 0751aff31f | |||
| a2ea20de70 | |||
| 3bfa1be60c | |||
| 8d38cf3c44 | |||
| a3a9ab069a | |||
| da908501e5 | |||
| 995ed22401 | |||
| c9cd4c721c | |||
| c059c14d7a | |||
| 04c9771978 | |||
| 9c8b5cd97e | |||
| 8bb447065c | |||
| 1d0299af89 | |||
| 5b8beceea8 | |||
| e4568520a9 | |||
| cbba628eaf | |||
| c2d0e255df | |||
| e096890400 | |||
| ec4b1c8f70 | |||
| 1af904435a | |||
| 7b2f03ba50 | |||
| 005d3e7d64 | |||
| 12f8638223 | |||
| 137b0754d6 | |||
| 7d1e9cfd72 | |||
| d01a39e0c6 | |||
| 73bd0137e3 | |||
| e3f9e8c842 | |||
| 7a38726b26 | |||
| a475f72d50 | |||
| 36cadf39e9 | |||
| a559ef9f90 | |||
| b45f6e0393 | |||
| b99ff6c981 | |||
| 81021f5821 | |||
| 29724b352b | |||
| be83302b14 | |||
| 83d7ea9ef1 | |||
| 95024442de | |||
| 69f54b5f22 | |||
| 3404f95b2e | |||
| e56738481b | |||
| cb59dc353b | |||
| d1b75eac08 | |||
| 1f7651d0e3 | |||
| 8fabd4e4ed | |||
| 564d92bed7 | |||
| d73dd47e7b | |||
| 95f103ccc2 | |||
| c21b232a33 | |||
| 0ace2fdae7 | |||
| dfb2a31f26 | |||
| 5da3541584 | |||
| ef86d2f1f1 | |||
| be98425956 | |||
| 61d1f87611 | |||
| 598d66ac7f | |||
| a10a6d1af8 | |||
| 7640908781 | |||
| b101e25e7a | |||
| 319f257ee5 | |||
| 14d40697b2 | |||
| 6e6b1beffd | |||
| e22de5c9a0 | |||
| 1eea4dab33 | |||
| 83518de981 | |||
| 6d87174cc1 | |||
| 2da18d4500 | |||
| 9af9c3fe77 | |||
| 9cedf5da4c | |||
| d50396ce68 | |||
| f7d4080472 | |||
| e24ff1b92b | |||
| 0c05cbc9db | |||
| 906d675dca | |||
| 860ef73fab | |||
| ec6158792a | |||
| f1b3105202 | |||
| 3ebb213916 | |||
| 97536086c0 | |||
| 0853f8da85 | |||
| 32d36d66c9 | |||
| 2aef75a70a | |||
| fc21d10192 | |||
| c6bd94532d | |||
| a65ca205de | |||
| c8e08b8ef8 | |||
| 683d793460 | |||
| d430efa7ab | |||
| c828c6ede3 | |||
| 3e1120612b | |||
| 8d06d39a62 | |||
| f64d4c9272 | |||
| b2f6620d80 | |||
| 812d38878c | |||
| da7fea47c6 | |||
| 71ddaf04b9 | |||
| 6e1316cb95 | |||
| f2442b25f6 | |||
| bfb8912518 | |||
| 300d3ff09b | |||
| e6337b8f14 | |||
| 39d45ba4b0 | |||
| 2be785ace3 | |||
| 5e2d991fab | |||
| 536cb4caf1 | |||
| 27745ea141 | |||
| 5289c55740 | |||
| 791773fc8a | |||
| 3179b2794b | |||
| 1da27e6c2b | |||
| bea6031de1 | |||
| 3608242b25 | |||
| 5602701645 | |||
| a909b7904e | |||
| 6e0af6827e | |||
| 51ff861e44 | |||
| aa092ab3f3 | |||
| aaaace8dd3 | |||
| 44012398bf | |||
| f18c557fb4 | |||
| 1249761ecd | |||
| db6da95421 | |||
| 8473601f03 | |||
| ac2c3ff321 | |||
| 7300686f34 | |||
| 7e288f657b | |||
| ca44094a37 | |||
| c72b6d7ae5 | |||
| 99c880a4c9 | |||
| 1b1abce7da | |||
| fbc10be381 | |||
| 61f2647b62 | |||
| a5bea7fc59 | |||
| 00cf20a8d0 | |||
| b20bb7a5a2 | |||
| b9be5c2561 | |||
| a82c5c332a | |||
| 19869e6d5f | |||
| 861d4a1b22 | |||
| b722bce2ed | |||
| 0c19307fa3 | |||
| 97556de447 | |||
| bd12cb3ae5 | |||
| ceb561c113 | |||
| 14c0e9e149 | |||
| 1d6587bb6b | |||
| a2a925fd7a | |||
| 29ef529c57 | |||
| 30fe0ecaf4 | |||
| ea805a7af8 | |||
| 350bea7798 | |||
| f9977a9fd8 | |||
| ea4f89701c | |||
| f3bfe0177d | |||
| 5dc80c55b2 | |||
| 14d5c9bee5 | |||
| 1c08921f55 | |||
| 01bd247831 | |||
| a1c39171a5 | |||
| bb430ddacd | |||
| 2fdb485203 | |||
| 1e8b82f5df | |||
| c63f8bc3bd | |||
| c9d55a4a5e | |||
| 9ae962492a | |||
| d404970c74 | |||
| 66bf667100 | |||
| 65980e8c76 | |||
| a2b5b13432 | |||
| c5d1439422 | |||
| 7ffb3cfb7f | |||
| df1cfaba28 | |||
| 5e9f4559b6 | |||
| 4bbb0441a6 | |||
| 4cf1d7d9a4 | |||
| a6a3ddca75 | |||
| 27cfa85d3a | |||
| a9e1e7b634 | |||
| 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 | |||
| e485c471cb | |||
| f00e8b4efc | |||
| d45ba48b37 | |||
| c8807c3798 | |||
| 82c2560822 | |||
| f467b8cb6c | |||
| aea1a03453 | |||
| 1568e5f19c | |||
| 8dff47db78 | |||
| 987e48733a | |||
| a95c129116 | |||
| 72ff03f142 | |||
| f4574b6014 | |||
| 2dde71abb3 | |||
| e55593fc34 | |||
| 1c6346233e | |||
| 00e316b5bd | |||
| 652abe3838 | |||
| 9c8c1d405b | |||
| 4bf9cf270d | |||
| f547e21f0b | |||
| 675cc0b850 | |||
| 07a8b1de79 | |||
| d3bdb8b743 | |||
| 04d1bf3604 | |||
| 46a83e553b | |||
| 801eb2c3d3 | |||
| cac1c4a296 | |||
| 84e4727ef5 | |||
| e2b86cf2df | |||
| 362e98ebe7 | |||
| 3e28376ae7 | |||
| e1902a54f0 | |||
| 5cb865f4c4 | |||
| 480bd39687 | |||
| 1bd4cbdb99 | |||
| efba265730 | |||
| f6ceb937a1 | |||
| 62bd1ce4fa | |||
| caea28afd0 | |||
| 035a09afba | |||
| e8361c2ab5 | |||
| 0292ca9bf3 | |||
| 9ef07ed2eb | |||
| 307a7fa77b | |||
| 53ddda9f59 | |||
| 98b8db7e3d | |||
| b5a140945a | |||
| f5ce9dc9d0 | |||
| 1304a9d791 | |||
| 9106438317 | |||
| c0b5525dd7 | |||
| ad62cf0123 | |||
| d64bdc089d | |||
| 36f8a8e1dd | |||
| 88e2690717 | |||
| 16f73b56ab | |||
| 47dc2e6214 | |||
| c6483f0380 | |||
| 168b38b2a3 | |||
| 5f1e327e4a | |||
| 70ca4ac913 | |||
| 816afe5abc | |||
| 7e460005da | |||
| 03a9e5507f | |||
| f947d05582 | |||
| 72099192b5 | |||
| ea48128869 | |||
| f0b22146c8 | |||
| fe0d94687a | |||
| 238c3d38e8 | |||
| 6af4f1f2c6 | |||
| e215fb056f | |||
| ac5142443a | |||
| 44360d83aa | |||
| 021cb817d4 | |||
| f4f91fba78 | |||
| dec5e8ad6c | |||
| a6b2196c10 | |||
| 4321c8d24e | |||
| 03070c3882 | |||
| 6293af2654 | |||
| 468af78d38 | |||
| c103f93004 | |||
| 3403b168f2 | |||
| 8cf8503d56 | |||
| 4cff3a3c28 | |||
| cbebe0141f | |||
| 371b539058 | |||
| fc3681a930 | |||
| 35052c626a | |||
| ef9b0b6433 | |||
| e29c48d2ef | |||
| d3c10d6033 | |||
| 84635631cb | |||
| 6efb15fef8 | |||
| 32ae861662 | |||
| 5458c9a310 | |||
| 0045ec353f | |||
| 04f351b287 | |||
| d0cccb5be6 | |||
| dfb6953792 | |||
| 716d3e95f1 | |||
| beeb28f390 | |||
| f32b8e31a2 | |||
| a75fe0ed7a | |||
| e738ec9437 | |||
| 864d840d41 | |||
| 080e8816a5 | |||
| a3338a5e22 | |||
| 7cf0bd670e | |||
| 81adf3f746 | |||
| d922b0dc90 | |||
| bfa9cdd9e6 | |||
| ac35d6ccbf | |||
| fb66d87ae8 | |||
| bc23495632 | |||
| f7eb323bd5 | |||
| 886678786b | |||
| 014bebd38f | |||
| afc41b4e70 | |||
| 4ec192d2dd | |||
| 0466a8ce13 | |||
| 537a9c0ad2 | |||
| ac0f304680 | |||
| fa862e9a33 | |||
| 03e3b37272 | |||
| 749a872fec | |||
| 0f484fdf49 | |||
| d779422bf4 | |||
| 98a171266e | |||
| 9ddf5dbbb8 | |||
| 880cafb0a9 | |||
| c00f0b9811 | |||
| 67f9f14e83 | |||
| c96891ad62 | |||
| 50589c0911 | |||
| e61ae618e8 | |||
| 930e6a0989 | |||
| 7c50b32684 | |||
| 0f7daf7ebd | |||
| 12cbc2a9c5 | |||
| 959d263619 | |||
| fc2d801a3a | |||
| 64c05cb50e | |||
| 6a1fb52b25 | |||
| 18cd043421 | |||
| 11ea698969 | |||
| 0e0e6b5c41 | |||
| 4c218621c6 | |||
| c150a91e50 | |||
| 7be9a0a987 | |||
| 2f482bdf53 | |||
| ddb2f82aba | |||
| 6c99e7951f | |||
| 7fa0c91faf | |||
| e44e745761 | |||
| 30c11439e4 | |||
| 0883f621f6 | |||
| 2d0784d1e5 | |||
| af0011f32a | |||
| 6cb3fcf9ad | |||
| e5878554bd | |||
| 44c8c4b5b8 |
@@ -4,7 +4,6 @@ web.Template.[a-zA-Z0-9]*.Debug.config
|
||||
|
||||
syntax: glob
|
||||
*.obj
|
||||
*.exe
|
||||
*.pdb
|
||||
*.user
|
||||
*.aps
|
||||
@@ -15,6 +14,7 @@ syntax: glob
|
||||
obj/
|
||||
[Rr]elease*/
|
||||
_ReSharper*/
|
||||
_NCrunch_*/
|
||||
*.ncrunchsolution
|
||||
*.ncrunchsolution.user
|
||||
*.ncrunchproject
|
||||
@@ -44,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
|
||||
@@ -63,6 +64,7 @@ src/Umbraco.Web.UI/Views/*.vbhtml
|
||||
src/Umbraco.Tests/config/umbracoSettings.config
|
||||
src/Umbraco.Web.UI/App_Plugins/*
|
||||
src/Umbraco.Web.UI/Views/*
|
||||
src/packages/
|
||||
|
||||
src\Umbraco.Web.UI\[Ww]eb.config
|
||||
*.transformed
|
||||
src\Umbraco.Web.UI\[W]eb.config
|
||||
*.transformed
|
||||
@@ -20,3 +20,10 @@ f6da531fbb4c251ff61d314e2a7effb13c71e74a Release-4.10.0
|
||||
73711b806a4044dbf0d7d7c095ddfdda23b09932 4.11.2
|
||||
0000000000000000000000000000000000000000 4.11.2
|
||||
73711b806a4044dbf0d7d7c095ddfdda23b09932 Release-4.11.2
|
||||
77db220b89e166b3c0736ed321ecfd6416cddbcd Release-4.11.2.1
|
||||
54cde33b809dcb3a1f7e7ae0d5375f6dd0d89c8d Release-4.11.2.2
|
||||
ff3bb24ea0c915878396a6ae27f1ff164e8ac150 Release-6.0.0-beta
|
||||
56015ac26f5ab60e3c61b1d09075297b660afa07 Release-6.0.0-RC
|
||||
1719fbd857f28b376639ac2aa0abada0ef2e7560 Release-6.0.0
|
||||
e02f5aebb87e3f07d27376647756caa9762931d8 Release-4.11.4
|
||||
b247b35d821144849f551e02da8ba719f91d5fb0 Release-6.0.2
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
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\App_Code\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\App_Data\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\App_Plugins\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\css\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\macroScripts\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\masterpages\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\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\xslt\dummy.txt
|
||||
|
||||
set version=6.0.0-beta
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
|
||||
if ERRORLEVEL 1 goto :showerror
|
||||
|
||||
goto :EOF
|
||||
|
||||
:showerror
|
||||
pause
|
||||
@@ -1,25 +0,0 @@
|
||||
@ECHO OFF
|
||||
set version=6.0.0-beta
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_NUMBER=%version%
|
||||
|
||||
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\App_Code\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\App_Data\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\App_Plugins\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\css\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\macroScripts\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\masterpages\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\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\xslt\dummy.txt
|
||||
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
|
||||
|
||||
if ERRORLEVEL 1 goto :showerror
|
||||
|
||||
goto :EOF
|
||||
|
||||
:showerror
|
||||
pause
|
||||
+26
-4
@@ -1,9 +1,31 @@
|
||||
@ECHO OFF
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj"
|
||||
SET release=6.0.3
|
||||
SET comment=
|
||||
SET version=%release%
|
||||
|
||||
if ERRORLEVEL 1 goto :showerror
|
||||
IF [%comment%] EQU [] (SET version=%release%) ELSE (SET version=%release%-%comment%)
|
||||
|
||||
goto :EOF
|
||||
%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.proj" /p:BUILD_RELEASE=%release% /p:BUILD_COMMENT=%comment%
|
||||
|
||||
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\App_Code\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\App_Data\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\App_Plugins\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\css\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\macroScripts\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\masterpages\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\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%
|
||||
..\src\.nuget\NuGet.exe pack NuSpecs\UmbracoCms.nuspec -Version %version%
|
||||
|
||||
IF ERRORLEVEL 1 GOTO :showerror
|
||||
|
||||
GOTO :EOF
|
||||
|
||||
:showerror
|
||||
pause
|
||||
PAUSE
|
||||
+81
-4
@@ -1,3 +1,4 @@
|
||||
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
|
||||
<!--
|
||||
@@ -13,7 +14,45 @@
|
||||
|
||||
<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
|
||||
@@ -23,6 +62,12 @@
|
||||
<!-- 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>
|
||||
@@ -65,10 +110,18 @@
|
||||
*****************************************************
|
||||
-->
|
||||
|
||||
<Target Name="Build" DependsOnTargets="ZipWebPiApp">
|
||||
<Target Name="Build" DependsOnTargets="GenerateWebPiHash">
|
||||
<Message Text="Build finished" />
|
||||
</Target>
|
||||
|
||||
<Target Name="GenerateWebPiHash" DependsOnTargets="ZipWebPiApp">
|
||||
<ItemGroup>
|
||||
<WebPiFile Include="$(BuildZipFileNameWebPi)" />
|
||||
</ItemGroup>
|
||||
<Message Text="Calculating hash for $(BuildZipFileNameWebPi)" />
|
||||
<GenerateHash InputFiles="@(WebPiFile)" OutputFile="webpihash.txt" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CleanUp" DependsOnTargets="ZipWebPiApp">
|
||||
<Message Text="Deleting $(BuildFolder)" Importance="high" />
|
||||
<RemoveDir Directories="$(BuildFolder)" />
|
||||
@@ -141,7 +194,7 @@
|
||||
</Target>
|
||||
|
||||
<!-- Copy the transformed web.config file to the root -->
|
||||
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CompileProjects">
|
||||
<Target Name="CopyTransformedWebConfig" DependsOnTargets="CopyXmlDocumentation">
|
||||
<ItemGroup>
|
||||
<WebConfigFile Include="..\src\Umbraco.Web.UI\web.$(BuildConfiguration).Config.transformed" />
|
||||
</ItemGroup>
|
||||
@@ -152,7 +205,20 @@
|
||||
SkipUnchangedFiles="false" />
|
||||
</Target>
|
||||
|
||||
<Target Name="CompileProjects">
|
||||
<!-- 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">
|
||||
@@ -161,5 +227,16 @@
|
||||
<!-- DONE -->
|
||||
<Message Text="Finished compiling projects" Importance="high" />
|
||||
</Target>
|
||||
|
||||
|
||||
<Target Name="SetVersionNumber" Condition="'$(BUILD_RELEASE)'!=''">
|
||||
<!-- Match & replace 3 and 4 digit version numbers and -beta (if it's there) -->
|
||||
<FileUpdate
|
||||
Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="(\d+)\.(\d+)\.(\d+)(.(\d+))?"
|
||||
ReplacementText="$(BUILD_RELEASE)"/>
|
||||
|
||||
<FileUpdate Files="..\src\Umbraco.Core\Configuration\UmbracoVersion.cs"
|
||||
Regex="CurrentComment { get { return "([a-zA-Z]+)?""
|
||||
ReplacementText="CurrentComment { get { return "$(BUILD_COMMENT)""/>
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -22,17 +22,22 @@
|
||||
</metadata>
|
||||
<files>
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.dll" target="lib\businesslogic.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\businesslogic.xml" target="lib\businesslogic.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\ClientDependency.Core.dll" target="lib\ClientDependency.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\ClientDependency.Core.Mvc.dll" target="lib\ClientDependency.Core.Mvc.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.dll" target="lib\cms.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\cms.xml" target="lib\cms.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.dll" target="lib\controls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\controls.xml" target="lib\controls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\CookComputing.XmlRpcV2.dll" target="lib\CookComputing.XmlRpcV2.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Examine.dll" target="lib\Examine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\HtmlAgilityPack.dll" target="lib\HtmlAgilityPack.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\ICSharpCode.SharpZipLib.dll" target="lib\ICSharpCode.SharpZipLib.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.dll" target="lib\interfaces.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\interfaces.xml" target="lib\interfaces.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Lucene.Net.dll" target="lib\Lucene.Net.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Lucene.Net.xml" target="lib\Lucene.Net.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Microsoft.Web.Helpers.dll" target="lib\Microsoft.Web.Helpers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\MySql.Data.dll" target="lib\MySql.Data.dll" />
|
||||
@@ -44,18 +49,24 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Core.xml" target="lib\Umbraco.Core.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.DataLayer.xml" target="lib\umbraco.DataLayer.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.dll" target="lib\umbraco.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.xml" target="lib\umbraco.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.editorControls.xml" target="lib\umbraco.editorControls.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.MacroEngines.xml" target="lib\umbraco.MacroEngines.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.dll" target="lib\umbraco.macroRenderings.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.macroRenderings.xml" target="lib\umbraco.macroRenderings.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.webservices.dll" target="lib\umbraco.webservices.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\umbraco.webservices.xml" target="lib\umbraco.webservices.xml" />
|
||||
<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,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
|
||||
|
||||
@@ -39,6 +39,7 @@
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<DocumentationFile>bin\Release\SQLCE4Umbraco.XML</DocumentationFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -28,24 +28,49 @@ 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 for unit tests
|
||||
/// </summary>
|
||||
internal static void ResetCache()
|
||||
{
|
||||
_reservedUrlsCache = null;
|
||||
_reservedPaths = null;
|
||||
_reservedUrls = null;
|
||||
}
|
||||
|
||||
/// <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 +81,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 +154,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 +166,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 +213,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
if (value.ToLower().Contains("SQLCE4Umbraco.SqlCEHelper".ToLower()))
|
||||
{
|
||||
ApplicationContext.Current.DatabaseContext.ConfigureDatabaseConnection();
|
||||
ApplicationContext.Current.DatabaseContext.ConfigureEmbeddedDatabaseConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -201,6 +244,7 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a setting into the configuration file.
|
||||
/// </summary>
|
||||
@@ -622,38 +666,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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,31 @@ namespace Umbraco.Core.Configuration
|
||||
/// </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()
|
||||
@@ -35,6 +59,7 @@ namespace Umbraco.Core.Configuration
|
||||
_useLegacySchema = null;
|
||||
_useDomainPrefixes = null;
|
||||
_umbracoLibraryCacheDuration = null;
|
||||
_trySkipIisCustomErrors = null;
|
||||
SettingsFilePath = null;
|
||||
}
|
||||
|
||||
@@ -126,11 +151,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 +249,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 +398,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 +418,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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -623,31 +642,34 @@ 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;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool? _trySkipIisCustomErrors;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating where to try to skip IIS custom errors.
|
||||
/// </summary>
|
||||
public static bool TrySkipIisCustomErrors
|
||||
{
|
||||
get
|
||||
{
|
||||
// default: false
|
||||
return _trySkipIisCustomErrors ?? GetKeyValue("/settings/web.routing/@trySkipIisCustomErrors", false);
|
||||
}
|
||||
internal set
|
||||
{
|
||||
// used for unit testing
|
||||
_trySkipIisCustomErrors = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the allowed image file types.
|
||||
@@ -677,26 +699,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 +1062,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;
|
||||
}
|
||||
}
|
||||
@@ -1221,6 +1216,40 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration regarding webservices
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
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.0.3");
|
||||
|
||||
/// <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 "Beta"; } }
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
|
||||
// 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
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
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.Services;
|
||||
using MigrationsVersionSixth = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixth;
|
||||
using MigrationsVersionFourNineZero = Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourNineZero;
|
||||
|
||||
namespace Umbraco.Core
|
||||
@@ -30,10 +30,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 +60,57 @@ 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
|
||||
};
|
||||
}
|
||||
|
||||
/// <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 +119,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,22 +143,39 @@ 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>
|
||||
@@ -117,47 +184,58 @@ namespace Umbraco.Core
|
||||
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(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),
|
||||
typeof (UpdatePropertyTypesAndGroups)
|
||||
});
|
||||
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
//add the internal ones, these are not public currently so need to add them manually
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<DatePickerPropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<TinyMcePropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<YesNoPropertyEditorValueConverter>();
|
||||
|
||||
//the database migration objects
|
||||
MigrationResolver.Current = new MigrationResolver(new List<Type>
|
||||
{
|
||||
typeof (MigrationsVersionFourNineZero.RemoveUmbracoAppConstraints),
|
||||
typeof (MigrationsVersionSixth.DeleteAppTables),
|
||||
typeof (MigrationsVersionSixth.EnsureAppsTreesUpdated),
|
||||
typeof (MigrationsVersionSixth.MoveMasterContentTypeData),
|
||||
typeof (MigrationsVersionSixth.NewCmsContentType2ContentTypeTable),
|
||||
typeof (MigrationsVersionSixth.RemoveMasterContentTypeColumn),
|
||||
typeof (MigrationsVersionSixth.RenameCmsTabTable),
|
||||
typeof (MigrationsVersionSixth.RenameTabIdColumn),
|
||||
typeof (MigrationsVersionSixth.UpdateCmsContentTypeAllowedContentTypeTable),
|
||||
typeof (MigrationsVersionSixth.UpdateCmsContentTypeTable),
|
||||
typeof (MigrationsVersionSixth.UpdateCmsContentVersionTable),
|
||||
typeof (MigrationsVersionSixth.UpdateCmsPropertyTypeGroupTable)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web.Mvc;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
@@ -158,7 +159,7 @@ namespace Umbraco.Core
|
||||
var builder = new StringBuilder();
|
||||
foreach (var i in d)
|
||||
{
|
||||
builder.Append(String.Format("{0}={1}&", i.Key, i.Value));
|
||||
builder.Append(String.Format("{0}={1}&", HttpUtility.UrlEncode(i.Key), i.Value == null ? string.Empty : HttpUtility.UrlEncode(i.Value.ToString())));
|
||||
}
|
||||
return builder.ToString().TrimEnd('&');
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Dynamic;
|
||||
using System.Reflection;
|
||||
@@ -8,34 +9,106 @@ using System.Xml.XPath;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
public class DynamicXml : DynamicObject, IEnumerable<DynamicXml>, IEnumerable<XElement>
|
||||
[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
|
||||
@@ -43,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);
|
||||
@@ -62,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
|
||||
}
|
||||
@@ -100,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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -121,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)
|
||||
@@ -191,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);
|
||||
|
||||
@@ -203,39 +342,55 @@ 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);
|
||||
}
|
||||
return root;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the string version of the BaseElement object
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override string ToString()
|
||||
{
|
||||
return ToXml();
|
||||
}
|
||||
|
||||
public IHtmlString ToHtml()
|
||||
{
|
||||
return new HtmlString(this.ToXml());
|
||||
}
|
||||
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()
|
||||
@@ -298,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;
|
||||
}
|
||||
@@ -306,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);
|
||||
}
|
||||
@@ -314,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);
|
||||
}
|
||||
@@ -322,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;
|
||||
}
|
||||
@@ -330,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);
|
||||
}
|
||||
@@ -338,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);
|
||||
}
|
||||
@@ -347,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;
|
||||
}
|
||||
@@ -355,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);
|
||||
}
|
||||
@@ -561,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()
|
||||
@@ -570,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)));
|
||||
@@ -677,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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
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>
|
||||
public class DynamicXmlConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
public override object ConvertTo(
|
||||
ITypeDescriptorContext context,
|
||||
CultureInfo culture,
|
||||
object value,
|
||||
Type destinationType)
|
||||
{
|
||||
var dxml = value as DynamicXml;
|
||||
if (dxml == null)
|
||||
return null;
|
||||
//string
|
||||
if (TypeHelper.IsTypeAssignableFrom<string>(destinationType))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
//XElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<XElement>(destinationType))
|
||||
{
|
||||
return dxml.BaseElement;
|
||||
}
|
||||
//XmlElement
|
||||
if (TypeHelper.IsTypeAssignableFrom<XmlElement>(destinationType))
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
xDoc.LoadXml(dxml.ToString());
|
||||
return xDoc.DocumentElement;
|
||||
}
|
||||
//XmlDocument
|
||||
if (TypeHelper.IsTypeAssignableFrom<XmlDocument>(destinationType))
|
||||
{
|
||||
var xDoc = new XmlDocument();
|
||||
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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom IApplicationStartupHandler that auto subscribes to the applications events
|
||||
/// </summary>
|
||||
public interface IApplicationEventHandler : IApplicationStartupHandler
|
||||
{
|
||||
/// <summary>
|
||||
/// ApplicationContext is created and other static objects that require initialization have been setup
|
||||
/// </summary>
|
||||
/// <param name="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
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="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
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="umbracoApplication"></param>
|
||||
/// <param name="applicationContext"></param>
|
||||
void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext);
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,7 @@ namespace Umbraco.Core.IO
|
||||
///
|
||||
/// This abstract class just wraps the 'real' IFileSystem object passed in to its constructor.
|
||||
/// </remarks>
|
||||
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
|
||||
internal abstract class FileSystemWrapper : IFileSystem
|
||||
public abstract class FileSystemWrapper : IFileSystem
|
||||
{
|
||||
private readonly IFileSystem _wrapped;
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ using Umbraco.Core.CodeAnnotations;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
|
||||
internal interface IFileSystem
|
||||
public interface IFileSystem
|
||||
{
|
||||
IEnumerable<string> GetDirectories(string path);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -230,6 +231,20 @@ namespace Umbraco.Core.IO
|
||||
filePath = String.Empty;
|
||||
}
|
||||
|
||||
//Break up the file in name and extension before applying the UrlReplaceCharacters
|
||||
var fileNamePart = filePath.Substring(0, filePath.LastIndexOf('.'));
|
||||
var ext = filePath.Substring(filePath.LastIndexOf('.'));
|
||||
|
||||
//Because the file usually is downloadable as well we check characters against 'UmbracoSettings.UrlReplaceCharacters'
|
||||
XmlNode replaceChars = UmbracoSettings.UrlReplaceCharacters;
|
||||
foreach (XmlNode n in replaceChars.SelectNodes("char"))
|
||||
{
|
||||
if (n.Attributes.GetNamedItem("org") != null && n.Attributes.GetNamedItem("org").Value != "")
|
||||
fileNamePart = fileNamePart.Replace(n.Attributes.GetNamedItem("org").Value, XmlHelper.GetNodeValue(n));
|
||||
}
|
||||
|
||||
filePath = string.Concat(fileNamePart, ext);
|
||||
|
||||
// Adapted from: http://stackoverflow.com/a/4827510/5018
|
||||
// Combined both Reserved Characters and Character Data
|
||||
// from http://en.wikipedia.org/wiki/Percent-encoding
|
||||
|
||||
@@ -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
|
||||
@@ -11,8 +9,7 @@ namespace Umbraco.Core.IO
|
||||
/// A custom file system provider for media
|
||||
/// </summary>
|
||||
[FileSystemProvider("media")]
|
||||
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
|
||||
internal class MediaFileSystem : FileSystemWrapper
|
||||
public class MediaFileSystem : FileSystemWrapper
|
||||
{
|
||||
public MediaFileSystem(IFileSystem wrapped)
|
||||
: base(wrapped)
|
||||
@@ -28,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);
|
||||
|
||||
@@ -10,16 +10,19 @@ using Umbraco.Core.Publishing;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
[UmbracoExperimentalFeature("http://issues.umbraco.org/issue/U4-1156", "Will be declared public after 4.10")]
|
||||
internal class PhysicalFileSystem : IFileSystem
|
||||
public class PhysicalFileSystem : IFileSystem
|
||||
{
|
||||
internal string RootPath { get; private set; }
|
||||
private readonly string _rootUrl;
|
||||
|
||||
public PhysicalFileSystem(string virtualRoot)
|
||||
{
|
||||
RootPath = System.Web.Hosting.HostingEnvironment.MapPath(virtualRoot);
|
||||
_rootUrl = VirtualPathUtility.ToAbsolute(virtualRoot);
|
||||
if (virtualRoot == null) throw new ArgumentNullException("virtualRoot");
|
||||
if (!virtualRoot.StartsWith("~/"))
|
||||
throw new ArgumentException("The virtualRoot argument must be a virtual path and start with '~/'");
|
||||
|
||||
RootPath = IOHelper.MapPath(virtualRoot);
|
||||
_rootUrl = IOHelper.ResolveUrl(virtualRoot);
|
||||
}
|
||||
|
||||
public PhysicalFileSystem(string rootPath, string rootUrl)
|
||||
@@ -30,6 +33,9 @@ namespace Umbraco.Core.IO
|
||||
if (string.IsNullOrEmpty(rootUrl))
|
||||
throw new ArgumentException("The argument 'rootUrl' cannot be null or empty.");
|
||||
|
||||
if (rootPath.StartsWith("~/"))
|
||||
throw new ArgumentException("The rootPath argument cannot be a virtual path and cannot start with '~/'");
|
||||
|
||||
RootPath = rootPath;
|
||||
_rootUrl = rootUrl;
|
||||
}
|
||||
@@ -141,7 +147,7 @@ namespace Umbraco.Core.IO
|
||||
}
|
||||
catch (FileNotFoundException ex)
|
||||
{
|
||||
LogHelper.Info<PublishingStrategy>(string.Format("DeleteFile failed with FileNotFoundException: {0}", ex.InnerException));
|
||||
LogHelper.Info<PhysicalFileSystem>(string.Format("DeleteFile failed with FileNotFoundException: {0}", ex.InnerException));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,25 +19,28 @@ namespace Umbraco.Core.Models
|
||||
private DateTime? _releaseDate;
|
||||
private DateTime? _expireDate;
|
||||
private int _writer;
|
||||
private string _nodeName;
|
||||
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
/// </summary>
|
||||
/// <param name="parentId">Id of the Parent content</param>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="parent">Parent <see cref="IContent"/> object</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Content(int parentId, IContentType contentType)
|
||||
: this(parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
|
||||
public Content(IContent parent, IContentType contentType)
|
||||
: this(parent, contentType, new PropertyCollection())
|
||||
public Content(string name, IContent parent, IContentType contentType)
|
||||
: this(name, parent, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
|
||||
public Content(IContent parent, IContentType contentType, PropertyCollection properties)
|
||||
: base(parent, contentType, properties)
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="parent">Parent <see cref="IContent"/> object</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
/// <param name="properties">Collection of properties</param>
|
||||
public Content(string name, IContent parent, IContentType contentType, PropertyCollection properties)
|
||||
: base(name, parent, contentType, properties)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
@@ -47,11 +50,23 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="parentId">Id of the Parent content</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Content(string name, int parentId, IContentType contentType)
|
||||
: this(name, parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the content</param>
|
||||
/// <param name="parentId">Id of the Parent content</param>
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
/// <param name="properties">Collection of properties</param>
|
||||
public Content(int parentId, IContentType contentType, PropertyCollection properties)
|
||||
: base(parentId, contentType, properties)
|
||||
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
|
||||
: base(name, parentId, contentType, properties)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
@@ -189,6 +204,12 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the Node (non-localized).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This Property is kept internal until localization is introduced.
|
||||
/// </remarks>
|
||||
internal string NodeName
|
||||
{
|
||||
get { return _nodeName; }
|
||||
@@ -259,19 +280,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)
|
||||
@@ -291,6 +303,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -16,7 +17,7 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
protected IContentTypeComposition ContentTypeBase;
|
||||
private Lazy<int> _parentId;
|
||||
private string _name;
|
||||
private string _name;//NOTE Once localization is introduced this will be the localized Name of the Content/Media.
|
||||
private int _sortOrder;
|
||||
private int _level;
|
||||
private string _path;
|
||||
@@ -25,34 +26,50 @@ namespace Umbraco.Core.Models
|
||||
private int _contentTypeId;
|
||||
private PropertyCollection _properties;
|
||||
|
||||
protected ContentBase(int parentId, IContentTypeComposition contentType, PropertyCollection properties)
|
||||
/// <summary>
|
||||
/// Protected constructor for ContentBase (Base for Content and Media)
|
||||
/// </summary>
|
||||
/// <param name="name">Localized Name of the entity</param>
|
||||
/// <param name="parentId"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="properties"></param>
|
||||
protected ContentBase(string name, int parentId, IContentTypeComposition contentType, PropertyCollection properties)
|
||||
{
|
||||
Mandate.ParameterCondition(parentId != 0, "parentId");
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
Mandate.ParameterNotNull(properties, "properties");
|
||||
|
||||
_parentId = new Lazy<int>(() => parentId);
|
||||
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
ContentTypeBase = contentType;
|
||||
Version = Guid.NewGuid();
|
||||
|
||||
_parentId = new Lazy<int>(() => parentId);
|
||||
_name = name;
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Version = Guid.NewGuid();
|
||||
}
|
||||
|
||||
protected ContentBase(IContentBase parent, IContentTypeComposition contentType, PropertyCollection properties)
|
||||
/// <summary>
|
||||
/// Protected constructor for ContentBase (Base for Content and Media)
|
||||
/// </summary>
|
||||
/// <param name="name">Localized Name of the entity</param>
|
||||
/// <param name="parent"></param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="properties"></param>
|
||||
protected ContentBase(string name, IContentBase parent, IContentTypeComposition contentType, PropertyCollection properties)
|
||||
{
|
||||
Mandate.ParameterNotNull(parent, "parent");
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
Mandate.ParameterNotNull(properties, "properties");
|
||||
|
||||
_parentId = new Lazy<int>(() => parent.Id);
|
||||
ContentTypeBase = contentType;
|
||||
Version = Guid.NewGuid();
|
||||
|
||||
_parentId = new Lazy<int>(() => parent.Id);
|
||||
_name = name;
|
||||
_contentTypeId = int.Parse(contentType.Id.ToString(CultureInfo.InvariantCulture));
|
||||
ContentTypeBase = contentType;
|
||||
_properties = properties;
|
||||
_properties.EnsurePropertyTypes(PropertyTypes);
|
||||
Version = Guid.NewGuid();
|
||||
}
|
||||
|
||||
private static readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<ContentBase, string>(x => x.Name);
|
||||
@@ -256,11 +273,110 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a Property
|
||||
/// Sets the <see cref="System.Object"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetValue(string propertyTypeAlias, object value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// .NET magic to call one of the 'SetPropertyValue' handlers with matching signature
|
||||
((dynamic)this).SetPropertyValue(propertyTypeAlias, (dynamic)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.String"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, string value)
|
||||
{
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Int32"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, int value)
|
||||
{
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Int64"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, long value)
|
||||
{
|
||||
string val = value.ToString();
|
||||
SetValueOnProperty(propertyTypeAlias, val);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Boolean"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, bool value)
|
||||
{
|
||||
int val = Convert.ToInt32(value);
|
||||
SetValueOnProperty(propertyTypeAlias, val);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.DateTime"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, DateTime value)
|
||||
{
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Web.HttpPostedFile"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, HttpPostedFile value)
|
||||
{
|
||||
ContentExtensions.SetValue(this, propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Web.HttpPostedFileBase"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, HttpPostedFileBase value)
|
||||
{
|
||||
ContentExtensions.SetValue(this, propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Web.HttpPostedFileWrapper"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, HttpPostedFileWrapper value)
|
||||
{
|
||||
ContentExtensions.SetValue(this, propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private method to set the value of a property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias"></param>
|
||||
/// <param name="value"></param>
|
||||
private void SetValueOnProperty(string propertyTypeAlias, object value)
|
||||
{
|
||||
if (Properties.Contains(propertyTypeAlias))
|
||||
{
|
||||
@@ -285,6 +401,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);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
@@ -9,6 +10,7 @@ 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.Persistence;
|
||||
using Umbraco.Core.Persistence.UnitOfWork;
|
||||
@@ -56,64 +58,22 @@ 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="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 IMedia media, string propertyTypeAlias, HttpPostedFileBase value)
|
||||
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());
|
||||
|
||||
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 SetValue(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 SetValue(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="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 IContent content, 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());
|
||||
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);
|
||||
@@ -122,16 +82,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 IContent content, string propertyTypeAlias, HttpPostedFile value)
|
||||
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);
|
||||
@@ -140,26 +106,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 IContent content, string propertyTypeAlias, HttpPostedFileWrapper value)
|
||||
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);
|
||||
@@ -202,14 +194,14 @@ namespace Umbraco.Core.Models
|
||||
XmlNode uploadFieldConfigNode =
|
||||
UmbracoSettings.ImageAutoFillImageProperties.SelectSingleNode(
|
||||
string.Format("uploadField [@alias = \"{0}\"]", propertyTypeAlias));
|
||||
|
||||
|
||||
if (uploadFieldConfigNode != null)
|
||||
{
|
||||
//Only add dimensions to web images
|
||||
if (supportsResizing)
|
||||
{
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "widthFieldAlias", GetDimensions(fs, fileName).Item1);
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", GetDimensions(fs, fileName).Item2);
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "widthFieldAlias", GetDimensions(fs, fileName).Item1.ToString(CultureInfo.InvariantCulture));
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", GetDimensions(fs, fileName).Item2.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -217,7 +209,7 @@ namespace Umbraco.Core.Models
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "heightFieldAlias", string.Empty);
|
||||
}
|
||||
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "lengthFieldAlias", fs.GetSize(fileName));
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "lengthFieldAlias", fs.GetSize(fileName).ToString(CultureInfo.InvariantCulture));
|
||||
SetPropertyValue(content, uploadFieldConfigNode, "extensionFieldAlias", extension);
|
||||
}
|
||||
}
|
||||
@@ -226,15 +218,15 @@ namespace Umbraco.Core.Models
|
||||
property.Value = fs.GetUrl(fileName);
|
||||
}
|
||||
|
||||
private static void SetPropertyValue(IContentBase content, XmlNode uploadFieldConfigNode, string propertyAlias, object propertyValue)
|
||||
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);
|
||||
@@ -346,15 +338,11 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this content.
|
||||
/// Gets the <see cref="IProfile"/> for the Creator of this content/media 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>
|
||||
@@ -362,11 +350,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>
|
||||
@@ -390,37 +374,79 @@ namespace Umbraco.Core.Models
|
||||
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();
|
||||
var nodeName = UmbracoSettings.UseLegacyXmlSchema ? "node" : content.ContentType.Alias.ToSafeAliasWithForcingCheck();
|
||||
|
||||
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)
|
||||
{
|
||||
x.Add(new XAttribute("nodeTypeAlias", content.ContentType.Alias));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
var niceUrl = contentBase.Name.FormatUrl().ToLower();
|
||||
|
||||
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("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", niceUrl),//Format Url ?
|
||||
new XAttribute("path", contentBase.Path),
|
||||
new XAttribute("isDoc", ""));
|
||||
|
||||
foreach (var property in content.Properties)
|
||||
foreach (var property in contentBase.Properties)
|
||||
{
|
||||
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);
|
||||
if (property.Alias == "umbracoUrlName" && property.Value != null &&
|
||||
property.Value.ToString().Trim() != string.Empty)
|
||||
xml.SetAttributeValue("urlName", property.Value.ToString().FormatUrl().ToLower());
|
||||
}
|
||||
|
||||
return xml;
|
||||
|
||||
@@ -153,7 +153,7 @@ namespace Umbraco.Core.Models
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
_alias = value;
|
||||
_alias = value.ToSafeAlias();
|
||||
OnPropertyChanged(AliasSelector);
|
||||
}
|
||||
}
|
||||
@@ -322,6 +322,74 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
/// <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>
|
||||
@@ -332,6 +400,11 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
propertyGroup.PropertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
|
||||
if (_propertyTypes.Any(x => x.Alias == propertyTypeAlias))
|
||||
{
|
||||
_propertyTypes.RemoveItem(propertyTypeAlias);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -342,9 +415,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>
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -172,7 +172,9 @@ namespace Umbraco.Core.Models
|
||||
internal override void AddingEntity()
|
||||
{
|
||||
base.AddingEntity();
|
||||
Key = Guid.NewGuid();
|
||||
|
||||
if(Key == default(Guid))
|
||||
Key = Guid.NewGuid();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,15 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
[DataMember]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
/// <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; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Property changed event
|
||||
/// </summary>
|
||||
@@ -85,7 +94,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
}
|
||||
}
|
||||
|
||||
protected void ResetIdentity()
|
||||
internal virtual void ResetIdentity()
|
||||
{
|
||||
_hasIdentity = false;
|
||||
_id = default(int);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -61,16 +61,5 @@ namespace Umbraco.Core.Models
|
||||
/// </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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -66,7 +61,7 @@ namespace Umbraco.Core.Models
|
||||
TPassType GetValue<TPassType>(string propertyTypeAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value of a Property
|
||||
/// Sets the <see cref="System.Object"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,6 @@ 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>
|
||||
|
||||
@@ -15,20 +15,23 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Constructor for creating a Media object
|
||||
/// </summary>
|
||||
/// <param name="parentId"> </param>
|
||||
/// <param name="name">ame of the Media object</param>
|
||||
/// <param name="parent">Parent <see cref="IMedia"/> object</param>
|
||||
/// <param name="contentType">MediaType for the current Media object</param>
|
||||
public Media(int parentId, IMediaType contentType)
|
||||
: this(parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
|
||||
public Media(IMedia parent, IMediaType contentType)
|
||||
: this(parent, contentType, new PropertyCollection())
|
||||
public Media(string name, IMedia parent, IMediaType contentType)
|
||||
: this(name, parent, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
|
||||
public Media(IMedia parent, IMediaType contentType, PropertyCollection properties)
|
||||
: base(parent, contentType, properties)
|
||||
/// <summary>
|
||||
/// Constructor for creating a Media object
|
||||
/// </summary>
|
||||
/// <param name="name">ame of the Media object</param>
|
||||
/// <param name="parent">Parent <see cref="IMedia"/> object</param>
|
||||
/// <param name="contentType">MediaType for the current Media object</param>
|
||||
/// <param name="properties">Collection of properties</param>
|
||||
public Media(string name, IMedia parent, IMediaType contentType, PropertyCollection properties)
|
||||
: base(name, parent, contentType, properties)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
_contentType = contentType;
|
||||
@@ -37,10 +40,23 @@ namespace Umbraco.Core.Models
|
||||
/// <summary>
|
||||
/// Constructor for creating a Media object
|
||||
/// </summary>
|
||||
/// <param name="parentId"> </param>
|
||||
/// <param name="name">ame of the Media object</param>
|
||||
/// <param name="parentId">Id of the Parent IMedia</param>
|
||||
/// <param name="contentType">MediaType for the current Media object</param>
|
||||
public Media(string name, int parentId, IMediaType contentType)
|
||||
: this(name, parentId, contentType, new PropertyCollection())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Media object
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the Media object</param>
|
||||
/// <param name="parentId">Id of the Parent IMedia</param>
|
||||
/// <param name="contentType">MediaType for the current Media object</param>
|
||||
/// <param name="properties">Collection of properties</param>
|
||||
public Media(int parentId, IMediaType contentType, PropertyCollection properties) : base(parentId, contentType, properties)
|
||||
public Media(string name, int parentId, IMediaType contentType, PropertyCollection properties)
|
||||
: base(name, parentId, contentType, properties)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
_contentType = contentType;
|
||||
@@ -95,19 +111,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>
|
||||
|
||||
@@ -12,7 +12,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; }
|
||||
|
||||
@@ -88,7 +88,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.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));
|
||||
|
||||
|
||||
@@ -14,7 +14,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;
|
||||
|
||||
@@ -51,15 +51,24 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
@@ -92,6 +101,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.
|
||||
|
||||
@@ -18,7 +18,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 +61,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
|
||||
@@ -153,7 +153,7 @@ 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
|
||||
@@ -335,8 +335,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());
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public int ContentTypeNodeId { get; set; }
|
||||
|
||||
[Column("templateNodeId")]
|
||||
/*[ForeignKey(typeof(TemplateDto))]*/
|
||||
[ForeignKey(typeof(TemplateDto), Column = "nodeId")]
|
||||
public int TemplateNodeId { get; set; }
|
||||
|
||||
[Column("IsDefault")]
|
||||
|
||||
@@ -52,5 +52,16 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return validFile && validExtension;
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +147,17 @@ namespace Umbraco.Core.Models
|
||||
|
||||
return !parser.Errors.Any();
|
||||
}
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace Umbraco.Core.Models
|
||||
base.Path = path;
|
||||
ParentId = -1;
|
||||
Key = name.EncodeAsGuid();
|
||||
_name = name;
|
||||
_alias = alias;
|
||||
_name = name.Replace("/", ".").Replace("\\", "");
|
||||
_alias = alias.ToSafeAlias();
|
||||
|
||||
CreateDate = DateTime.Now;
|
||||
UpdateDate = DateTime.Now;
|
||||
@@ -52,7 +52,7 @@ namespace Umbraco.Core.Models
|
||||
internal string NodePath { get; set; }
|
||||
|
||||
[DataMember]
|
||||
internal int MasterTemplateId { get; set; }
|
||||
internal Lazy<int> MasterTemplateId { get; set; }
|
||||
|
||||
[DataMember]
|
||||
internal string MasterTemplateAlias { get; set; }
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A resolver to return all IApplicationEvents objects
|
||||
/// </summary>
|
||||
internal sealed class ApplicationEventsResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationEventHandler>
|
||||
{
|
||||
|
||||
private readonly LegacyStartupHandlerResolver _legacyResolver;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="applicationEventHandlers"></param>
|
||||
internal ApplicationEventsResolver(IEnumerable<Type> applicationEventHandlers)
|
||||
: base(applicationEventHandlers)
|
||||
{
|
||||
//create the legacy resolver and only include the legacy types
|
||||
_legacyResolver = new LegacyStartupHandlerResolver(
|
||||
applicationEventHandlers.Where(x => !TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>(x)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override in order to only return types of IApplicationEventHandler and above,
|
||||
/// do not include the legacy types of IApplicationStartupHandler
|
||||
/// </summary>
|
||||
protected override IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get { return base.InstanceTypes.Where(TypeHelper.IsTypeAssignableFrom<IApplicationEventHandler>); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IApplicationEventHandler"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<IApplicationEventHandler> ApplicationEventHandlers
|
||||
{
|
||||
get { return Values; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create instances of all of the legacy startup handlers
|
||||
/// </summary>
|
||||
public void InstantiateLegacyStartupHanlders()
|
||||
{
|
||||
//this will instantiate them all
|
||||
var handlers = _legacyResolver.LegacyStartupHandlers;
|
||||
}
|
||||
|
||||
protected override bool SupportsClear
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override bool SupportsInsert
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
protected override bool SupportsRemove
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
private class LegacyStartupHandlerResolver : ManyObjectsResolverBase<ApplicationEventsResolver, IApplicationStartupHandler>
|
||||
{
|
||||
internal LegacyStartupHandlerResolver(IEnumerable<Type> legacyStartupHandlers)
|
||||
: base(legacyStartupHandlers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public IEnumerable<IApplicationStartupHandler> LegacyStartupHandlers
|
||||
{
|
||||
get { return Values; }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
/// <summary>
|
||||
/// A base class for lazily resolving types for a resolver
|
||||
/// </summary>
|
||||
/// <typeparam name="TResolver"></typeparam>
|
||||
/// <typeparam name="TResolved"></typeparam>
|
||||
/// <remarks>
|
||||
/// This is a special case resolver for when types get lazily resolved in order to resolve the actual types. This is useful
|
||||
/// for when there is some processing overhead (i.e. Type finding in assemblies) to return the Types used to instantiate the instances.
|
||||
/// In some these cases we don't want to have to type find during application startup, only when we need to resolve the instances.
|
||||
///
|
||||
/// Important notes about this resolver: This does not support Insert or Remove and therefore does not support any ordering unless
|
||||
/// the types are marked with the WeightedPluginAttribute.
|
||||
/// </remarks>
|
||||
internal abstract class LazyManyObjectsResolverBase<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
protected LazyManyObjectsResolverBase(ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: base(scope)
|
||||
{
|
||||
}
|
||||
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext)
|
||||
: base(httpContext)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of lazy types
|
||||
/// </summary>
|
||||
/// <param name="listOfLazyTypes"></param>
|
||||
/// <param name="scope"></param>
|
||||
protected LazyManyObjectsResolverBase(IEnumerable<Lazy<Type>> listOfLazyTypes, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
AddTypes(listOfLazyTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a delegate to return a list of types
|
||||
/// </summary>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
/// <param name="scope"></param>
|
||||
protected LazyManyObjectsResolverBase(Func<IEnumerable<Type>> typeListDelegate, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of lazy types
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="listOfLazyTypes"></param>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Lazy<Type>> listOfLazyTypes)
|
||||
: this(httpContext)
|
||||
{
|
||||
AddTypes(listOfLazyTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a delegate to return a list of types
|
||||
/// </summary>
|
||||
/// <param name="httpContext"></param>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
protected LazyManyObjectsResolverBase(HttpContextBase httpContext, Func<IEnumerable<Type>> typeListDelegate)
|
||||
: this(httpContext)
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private readonly List<Lazy<Type>> _lazyTypeList = new List<Lazy<Type>>();
|
||||
private readonly List<Func<IEnumerable<Type>>> _listOfTypeListDelegates = new List<Func<IEnumerable<Type>>>();
|
||||
private List<Type> _resolvedTypes = null;
|
||||
private readonly ReaderWriterLockSlim _typeResolutionLock = new ReaderWriterLockSlim();
|
||||
|
||||
/// <summary>
|
||||
/// Used for unit tests
|
||||
/// </summary>
|
||||
internal bool HasResolvedTypes
|
||||
{
|
||||
get { return _resolvedTypes != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Once this is called this will resolve all types registered in the lazy list
|
||||
/// </summary>
|
||||
protected override IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get
|
||||
{
|
||||
using (var lck = new UpgradeableReadLock(_typeResolutionLock))
|
||||
{
|
||||
var lazyTypeList = _lazyTypeList.Select(x => x.Value).ToArray();
|
||||
var listofTypeListDelegates = _listOfTypeListDelegates.SelectMany(x => x()).ToArray();
|
||||
|
||||
//we need to validate each resolved type now since we could not do it before when inserting the lazy delegates
|
||||
if (!HasResolvedTypes)
|
||||
{
|
||||
lck.UpgradeToWriteLock();
|
||||
|
||||
_resolvedTypes = new List<Type>();
|
||||
|
||||
//first iterate the lazy type list
|
||||
foreach (var l in lazyTypeList)
|
||||
{
|
||||
UpdateUniqueList(_resolvedTypes, l);
|
||||
}
|
||||
|
||||
//next iterate the list of list type delegates
|
||||
foreach (var l in listofTypeListDelegates)
|
||||
{
|
||||
UpdateUniqueList(_resolvedTypes, l);
|
||||
}
|
||||
}
|
||||
|
||||
return _resolvedTypes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateUniqueList(List<Type> uniqueList, Type toAdd)
|
||||
{
|
||||
EnsureCorrectType(toAdd);
|
||||
if (uniqueList.Contains(toAdd))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + toAdd + " already exists in the collection");
|
||||
}
|
||||
uniqueList.Add(toAdd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows adding of multiple lazy types at once
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
protected void AddTypes(IEnumerable<Lazy<Type>> types)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
foreach (var t in types)
|
||||
{
|
||||
_lazyTypeList.Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a type list delegate to the collection
|
||||
/// </summary>
|
||||
/// <param name="typeListDelegate"></param>
|
||||
public void AddTypeListDelegate(Func<IEnumerable<Type>> typeListDelegate)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_listOfTypeListDelegates.Add(typeListDelegate);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a lazy type to the list
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void AddType(Lazy<Type> value)
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_lazyTypeList.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the static type added to a lazy type and adds it to the internal list
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public override void AddType(Type value)
|
||||
{
|
||||
AddType(new Lazy<Type>(() => value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all lazy types
|
||||
/// </summary>
|
||||
public override void Clear()
|
||||
{
|
||||
EnsureClearSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
_lazyTypeList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support removal
|
||||
/// </summary>
|
||||
protected override bool SupportsRemove
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does not support insert
|
||||
/// </summary>
|
||||
protected override bool SupportsInsert
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// these old classes don't contain metadata, the objects need to be instantiated first to get their metadata, we then store this
|
||||
/// for use in the GetById method.
|
||||
/// </remarks>
|
||||
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : ManyObjectsResolverBase<TResolver, TResolved>
|
||||
internal abstract class LegacyTransientObjectsResolver<TResolver, TResolved> : LazyManyObjectsResolverBase<TResolver, TResolved>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
@@ -27,16 +27,15 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="refreshers"></param>
|
||||
/// <param name="types"></param>
|
||||
/// <remarks>
|
||||
/// We are creating Transient instances (new instances each time) because this is how the legacy code worked and
|
||||
/// I don't want to muck anything up by changing them to application based instances.
|
||||
/// TODO: However, it would make much more sense to do this and would speed up the application plus this would make the GetById method much easier.
|
||||
/// </remarks>
|
||||
protected LegacyTransientObjectsResolver(IEnumerable<Type> refreshers)
|
||||
: base(ObjectLifetimeScope.Transient) // new objects every time
|
||||
{
|
||||
AddTypes(refreshers);
|
||||
protected LegacyTransientObjectsResolver(Func<IEnumerable<Type>> types)
|
||||
: base(types, ObjectLifetimeScope.Transient) // new objects every time
|
||||
{
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -55,7 +54,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
protected abstract Guid GetUniqueIdentifier(TResolved obj);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a new ICacheRefresher instance by id
|
||||
/// Returns a new TResolved instance by id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Macros;
|
||||
@@ -14,14 +15,14 @@ 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)
|
||||
{
|
||||
|
||||
@@ -56,7 +57,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </remarks>
|
||||
internal List<Type> MacroControlTypes
|
||||
{
|
||||
get { return InstanceTypes; }
|
||||
get { return InstanceTypes.ToList(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -6,14 +6,14 @@ using System.Web;
|
||||
|
||||
namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
|
||||
internal abstract class ManyObjectsResolverBase<TResolver, TResolved> : ResolverBase<TResolver>
|
||||
where TResolved : class
|
||||
where TResolver : class
|
||||
{
|
||||
private List<TResolved> _applicationInstances = null;
|
||||
private readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim();
|
||||
|
||||
private readonly List<Type> _instanceTypes = new List<Type>();
|
||||
|
||||
#region Constructors
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
}
|
||||
|
||||
LifetimeScope = scope;
|
||||
InstanceTypes = new List<Type>();
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
if (httpContext == null) throw new ArgumentNullException("httpContext");
|
||||
LifetimeScope = ObjectLifetimeScope.HttpRequest;
|
||||
CurrentHttpContext = httpContext;
|
||||
InstanceTypes = new List<Type>();
|
||||
_instanceTypes = new List<Type>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -58,8 +58,8 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <param name="scope">If set to true will resolve singleton objects which will be created once for the lifetime of the application</param>
|
||||
protected ManyObjectsResolverBase(IEnumerable<Type> value, ObjectLifetimeScope scope = ObjectLifetimeScope.Application)
|
||||
: this(scope)
|
||||
{
|
||||
InstanceTypes = new List<Type>(value);
|
||||
{
|
||||
_instanceTypes = new List<Type>(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
protected ManyObjectsResolverBase(HttpContextBase httpContext, IEnumerable<Type> value)
|
||||
: this(httpContext)
|
||||
{
|
||||
InstanceTypes = new List<Type>(value);
|
||||
_instanceTypes = new List<Type>(value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
@@ -83,7 +83,10 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Returns the list of Types registered that instances will be created from
|
||||
/// </summary>
|
||||
protected List<Type> InstanceTypes { get; private set; }
|
||||
protected virtual IEnumerable<Type> InstanceTypes
|
||||
{
|
||||
get { return _instanceTypes; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Current HttpContextBase used to construct this object if one exists.
|
||||
@@ -97,11 +100,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
protected ObjectLifetimeScope LifetimeScope { get; private set; }
|
||||
|
||||
private int _defaultPluginWeight = 10;
|
||||
private bool _supportsAdd = true;
|
||||
private bool _supportsInsert = true;
|
||||
private bool _supportsClear = true;
|
||||
private bool _supportsRemove = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used in conjunction with GetSortedValues and WeightedPluginAttribute, if any of the objects
|
||||
/// being resolved do not contain the WeightedPluginAttribute then this will be the default weight applied
|
||||
@@ -189,15 +188,16 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Removes a type.
|
||||
/// </summary>
|
||||
/// <param name="value">The type to remove.</param>
|
||||
public void RemoveType(Type value)
|
||||
public virtual void RemoveType(Type value)
|
||||
{
|
||||
if (!SupportsRemove)
|
||||
throw new InvalidOperationException("This resolver does not support Removing types");
|
||||
EnsureRemoveSupport();
|
||||
|
||||
using (new WriteLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
InstanceTypes.Remove(value);
|
||||
_instanceTypes.Remove(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,8 +215,12 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="types"></param>
|
||||
protected void AddTypes(IEnumerable<Type> types)
|
||||
{
|
||||
using (var l = new WriteLock(_lock))
|
||||
{
|
||||
EnsureAddSupport();
|
||||
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
foreach(var t in types)
|
||||
{
|
||||
@@ -225,7 +229,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + t + " already exists in the collection");
|
||||
};
|
||||
InstanceTypes.Add(t);
|
||||
_instanceTypes.Add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,19 +238,20 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// Adds a Type to the end of the list.
|
||||
/// </summary>
|
||||
/// <param name="value">The object to be added.</param>
|
||||
public void AddType(Type value)
|
||||
public virtual void AddType(Type value)
|
||||
{
|
||||
if (!SupportsAdd)
|
||||
throw new InvalidOperationException("This resolver does not support Adding new types");
|
||||
EnsureAddSupport();
|
||||
|
||||
using (var l = new WriteLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (InstanceTypes.Contains(value))
|
||||
{
|
||||
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
|
||||
};
|
||||
InstanceTypes.Add(value);
|
||||
_instanceTypes.Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,14 +267,15 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// <summary>
|
||||
/// Clears the list.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
public virtual void Clear()
|
||||
{
|
||||
if (!SupportsClear)
|
||||
throw new InvalidOperationException("This resolver does not support Clearing types");
|
||||
EnsureClearSupport();
|
||||
|
||||
using (new WriteLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (GetWriteLock())
|
||||
{
|
||||
InstanceTypes.Clear();
|
||||
_instanceTypes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -278,12 +284,13 @@ namespace Umbraco.Core.ObjectResolution
|
||||
/// </summary>
|
||||
/// <param name="index">The zero-based index at which the object should be inserted.</param>
|
||||
/// <param name="value">The object to insert.</param>
|
||||
public void InsertType(int index, Type value)
|
||||
public virtual void InsertType(int index, Type value)
|
||||
{
|
||||
if (!SupportsInsert)
|
||||
throw new InvalidOperationException("This resolver does not support Inserting new types");
|
||||
EnsureInsertSupport();
|
||||
|
||||
using (var l = new UpgradeableReadLock(_lock))
|
||||
EnsureResolutionNotFrozen();
|
||||
|
||||
using (var l = GetWriteLock())
|
||||
{
|
||||
EnsureCorrectType(value);
|
||||
if (InstanceTypes.Contains(value))
|
||||
@@ -291,8 +298,7 @@ namespace Umbraco.Core.ObjectResolution
|
||||
throw new InvalidOperationException("The Type " + value + " already exists in the collection");
|
||||
};
|
||||
|
||||
l.UpgradeToWriteLock();
|
||||
InstanceTypes.Insert(index, value);
|
||||
_instanceTypes.Insert(index, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,7 +312,65 @@ namespace Umbraco.Core.ObjectResolution
|
||||
InsertType(index, typeof (T));
|
||||
}
|
||||
|
||||
private void EnsureCorrectType(Type t)
|
||||
/// <summary>
|
||||
/// Returns a WriteLock to use when modifying collections
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected WriteLock GetWriteLock()
|
||||
{
|
||||
return new WriteLock(_lock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if resolution is frozen
|
||||
/// </summary>
|
||||
protected void EnsureResolutionNotFrozen()
|
||||
{
|
||||
if (Resolution.IsFrozen)
|
||||
throw new InvalidOperationException("The type list cannot be modified after resolution has been frozen");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Remove
|
||||
/// </summary>
|
||||
protected void EnsureRemoveSupport()
|
||||
{
|
||||
if (!SupportsRemove)
|
||||
throw new InvalidOperationException("This resolver does not support Removing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Clear
|
||||
/// </summary>
|
||||
protected void EnsureClearSupport()
|
||||
{
|
||||
if (!SupportsClear)
|
||||
throw new InvalidOperationException("This resolver does not support Clearing types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support Add
|
||||
/// </summary>
|
||||
protected void EnsureAddSupport()
|
||||
{
|
||||
if (!SupportsAdd)
|
||||
throw new InvalidOperationException("This resolver does not support Adding new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if this does not support insert
|
||||
/// </summary>
|
||||
protected void EnsureInsertSupport()
|
||||
{
|
||||
if (!SupportsInsert)
|
||||
throw new InvalidOperationException("This resolver does not support Inserting new types");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws an exception if the type is not of the TResolved type
|
||||
/// </summary>
|
||||
/// <param name="t"></param>
|
||||
protected void EnsureCorrectType(Type t)
|
||||
{
|
||||
if (!TypeHelper.IsTypeAssignableFrom<TResolved>(t))
|
||||
throw new InvalidOperationException("The resolver " + this.GetType() + " can only accept types of " + typeof(TResolved) + ". The Type passed in to this method is " + t);
|
||||
@@ -314,22 +378,22 @@ namespace Umbraco.Core.ObjectResolution
|
||||
|
||||
protected virtual bool SupportsAdd
|
||||
{
|
||||
get { return _supportsAdd; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsInsert
|
||||
{
|
||||
get { return _supportsInsert; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsClear
|
||||
{
|
||||
get { return _supportsClear; }
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
protected virtual bool SupportsRemove
|
||||
{
|
||||
get { return _supportsRemove; }
|
||||
get { return true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,14 +8,14 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// A resolver to return all IPackageAction objects
|
||||
/// </summary>
|
||||
internal sealed class PackageActionsResolver : ManyObjectsResolverBase<PackageActionsResolver, IPackageAction>
|
||||
internal sealed class PackageActionsResolver : LazyManyObjectsResolverBase<PackageActionsResolver, IPackageAction>
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="packageActions"></param>
|
||||
internal PackageActionsResolver(IEnumerable<Type> packageActions)
|
||||
internal PackageActionsResolver(Func<IEnumerable<Type>> packageActions)
|
||||
: base(packageActions)
|
||||
{
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Umbraco.Core.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Persistence
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to the PetaPoco database as Singleton, so the database is created once in app lifecycle.
|
||||
/// This is necessary for transactions to work properly
|
||||
/// </summary>
|
||||
public sealed class DatabaseFactory
|
||||
{
|
||||
#region Singleton
|
||||
|
||||
private static readonly Database _database = new Database(GlobalSettings.DbDsn);
|
||||
private static readonly Lazy<DatabaseFactory> lazy = new Lazy<DatabaseFactory>(() => new DatabaseFactory());
|
||||
|
||||
public static DatabaseFactory Current { get { return lazy.Value; } }
|
||||
|
||||
private DatabaseFactory()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of the PetaPoco database
|
||||
/// </summary>
|
||||
public Database Database
|
||||
{
|
||||
get { return _database; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -84,10 +84,14 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
var primaryKeyColumnAttribute = propertyInfo.FirstAttribute<PrimaryKeyColumnAttribute>();
|
||||
if (primaryKeyColumnAttribute != null)
|
||||
{
|
||||
string primaryKeyName = string.IsNullOrEmpty(primaryKeyColumnAttribute.Name)
|
||||
? string.Format("PK_{0}", tableName)
|
||||
: primaryKeyColumnAttribute.Name;
|
||||
|
||||
definition.IsPrimaryKey = true;
|
||||
definition.IsIdentity = primaryKeyColumnAttribute.AutoIncrement;
|
||||
definition.IsIndexed = primaryKeyColumnAttribute.Clustered;
|
||||
definition.PrimaryKeyName = primaryKeyColumnAttribute.Name ?? string.Empty;
|
||||
definition.PrimaryKeyName = primaryKeyName;
|
||||
definition.PrimaryKeyColumns = primaryKeyColumnAttribute.OnColumns ?? string.Empty;
|
||||
definition.Seeding = primaryKeyColumnAttribute.IdentitySeed;
|
||||
}
|
||||
@@ -120,9 +124,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
? referencedPrimaryKey.Value
|
||||
: attribute.Column;
|
||||
|
||||
string foreignKeyName = string.IsNullOrEmpty(attribute.Name)
|
||||
? string.Format("FK_{0}_{1}_{2}", tableName, referencedTable.Value, referencedColumn)
|
||||
: attribute.Name;
|
||||
|
||||
var definition = new ForeignKeyDefinition
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Name = foreignKeyName,
|
||||
ForeignTable = tableName,
|
||||
PrimaryTable = referencedTable.Value
|
||||
};
|
||||
@@ -134,9 +142,13 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
|
||||
|
||||
public static IndexDefinition GetIndexDefinition(Type modelType, PropertyInfo propertyInfo, IndexAttribute attribute, string columnName, string tableName)
|
||||
{
|
||||
string indexName = string.IsNullOrEmpty(attribute.Name)
|
||||
? string.Format("IX_{0}_{1}", tableName, columnName)
|
||||
: attribute.Name;
|
||||
|
||||
var definition = new IndexDefinition
|
||||
{
|
||||
Name = attribute.Name,
|
||||
Name = indexName,
|
||||
IndexType = attribute.IndexType,
|
||||
ColumnName = columnName,
|
||||
TableName = tableName,
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public IContent BuildEntity(DocumentDto dto)
|
||||
{
|
||||
return new Content(dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType)
|
||||
return new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType)
|
||||
{
|
||||
Id = _id,
|
||||
Key =
|
||||
@@ -57,20 +57,23 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public DocumentDto BuildDto(IContent entity)
|
||||
{
|
||||
//NOTE Currently doesn't add Alias and templateId (legacy stuff that eventually will go away)
|
||||
//NOTE Currently doesn't add Alias (legacy that eventually will go away)
|
||||
var documentDto = new DocumentDto
|
||||
{
|
||||
Newest = true,
|
||||
NodeId = entity.Id,
|
||||
Published = entity.Published,
|
||||
Text = entity.Name,
|
||||
UpdateDate = entity.UpdateDate,
|
||||
WriterUserId = entity.WriterId,
|
||||
VersionId = entity.Version,
|
||||
ExpiresDate = null,
|
||||
ReleaseDate = null,
|
||||
ContentVersionDto = BuildContentVersionDto(entity)
|
||||
};
|
||||
{
|
||||
Newest = true,
|
||||
NodeId = entity.Id,
|
||||
Published = entity.Published,
|
||||
Text = entity.Name,
|
||||
UpdateDate = entity.UpdateDate,
|
||||
WriterUserId = entity.WriterId,
|
||||
VersionId = entity.Version,
|
||||
ExpiresDate = null,
|
||||
ReleaseDate = null,
|
||||
ContentVersionDto = BuildContentVersionDto(entity)
|
||||
};
|
||||
|
||||
if (entity.Template != null && entity.Template.Id > 0)
|
||||
documentDto.TemplateId = entity.Template.Id;
|
||||
|
||||
if (entity.ExpireDate.HasValue)
|
||||
documentDto.ExpiresDate = entity.ExpireDate.Value;
|
||||
@@ -124,9 +127,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
private NodeDto BuildNodeDto(IContent entity)
|
||||
{
|
||||
//TODO: Change this once the Language property is public on IContent
|
||||
var content = entity as Content;
|
||||
var nodeName = content != null && string.IsNullOrEmpty(content.NodeName) == false ? content.NodeName : entity.Name;
|
||||
//TODO: Change this once the Language property is public on IContent
|
||||
var nodeName = entity.Name;
|
||||
|
||||
var nodeDto = new NodeDto
|
||||
{
|
||||
|
||||
@@ -29,14 +29,13 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public IMedia BuildEntity(ContentVersionDto dto)
|
||||
{
|
||||
return new Models.Media(dto.ContentDto.NodeDto.ParentId, _contentType)
|
||||
return new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, _contentType)
|
||||
{
|
||||
Id = _id,
|
||||
Key =
|
||||
dto.ContentDto.NodeDto.UniqueId.HasValue
|
||||
? dto.ContentDto.NodeDto.UniqueId.Value
|
||||
: _id.ToGuid(),
|
||||
Name = dto.ContentDto.NodeDto.Text,
|
||||
Path = dto.ContentDto.NodeDto.Path,
|
||||
CreatorId = dto.ContentDto.NodeDto.UserId.Value,
|
||||
Level = dto.ContentDto.NodeDto.Level,
|
||||
|
||||
@@ -8,41 +8,34 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
internal class PropertyFactory : IEntityFactory<IEnumerable<Property>, IEnumerable<PropertyDataDto>>
|
||||
{
|
||||
private readonly IContentType _contentType;
|
||||
private readonly IMediaType _mediaType;
|
||||
private readonly IContentTypeComposition _contentType;
|
||||
private readonly Guid _version;
|
||||
private readonly int _id;
|
||||
|
||||
public PropertyFactory(IContentType contentType, Guid version, int id)
|
||||
public PropertyFactory(IContentTypeComposition contentType, Guid version, int id)
|
||||
{
|
||||
_contentType = contentType;
|
||||
_version = version;
|
||||
_id = id;
|
||||
}
|
||||
|
||||
public PropertyFactory(IMediaType mediaType, Guid version, int id)
|
||||
{
|
||||
_mediaType = mediaType;
|
||||
_version = version;
|
||||
_id = id;
|
||||
}
|
||||
|
||||
#region Implementation of IEntityFactory<IContent,PropertyDataDto>
|
||||
|
||||
public IEnumerable<Property> BuildEntity(IEnumerable<PropertyDataDto> dtos)
|
||||
{
|
||||
var properties = new List<Property>();
|
||||
|
||||
foreach (var dto in dtos)
|
||||
foreach (var propertyType in _contentType.CompositionPropertyTypes)
|
||||
{
|
||||
if (_contentType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
|
||||
{
|
||||
var propertyType = _contentType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
|
||||
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
|
||||
var propertyDataDto = dtos.LastOrDefault(x => x.PropertyTypeId == propertyType.Id);
|
||||
var property = propertyDataDto == null
|
||||
? propertyType.CreatePropertyFromValue(null)
|
||||
: propertyType.CreatePropertyFromRawValue(propertyDataDto.GetValue,
|
||||
propertyDataDto.VersionId.Value,
|
||||
propertyDataDto.Id);
|
||||
|
||||
property.ResetDirtyProperties();
|
||||
properties.Add(property);
|
||||
}
|
||||
property.ResetDirtyProperties();
|
||||
properties.Add(property);
|
||||
}
|
||||
|
||||
return properties;
|
||||
@@ -78,7 +71,9 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
}
|
||||
else if (property.DataTypeDatabaseType == DataTypeDatabaseType.Date && property.Value != null && string.IsNullOrWhiteSpace(property.Value.ToString()) == false)
|
||||
{
|
||||
dto.Date = DateTime.Parse(property.Value.ToString());
|
||||
DateTime date;
|
||||
if(DateTime.TryParse(property.Value.ToString(), out date))
|
||||
dto.Date = date;
|
||||
}
|
||||
else if (property.DataTypeDatabaseType == DataTypeDatabaseType.Ntext && property.Value != null)
|
||||
{
|
||||
@@ -95,22 +90,5 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public IEnumerable<Property> BuildMediaEntity(IEnumerable<PropertyDataDto> dtos)
|
||||
{
|
||||
var properties = new List<Property>();
|
||||
foreach (var dto in dtos)
|
||||
{
|
||||
if (_mediaType.CompositionPropertyTypes.Any(x => x.Id == dto.PropertyTypeId))
|
||||
{
|
||||
var propertyType = _mediaType.CompositionPropertyTypes.First(x => x.Id == dto.PropertyTypeId);
|
||||
var property = propertyType.CreatePropertyFromRawValue(dto.GetValue, dto.VersionId.Value, dto.Id);
|
||||
|
||||
property.ResetDirtyProperties();
|
||||
properties.Add(property);
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
@@ -22,9 +23,21 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
foreach (var groupDto in dto)
|
||||
{
|
||||
var group = new PropertyGroup();
|
||||
group.Id = groupDto.Id;
|
||||
//Only assign an Id if the PropertyGroup belongs to this ContentType
|
||||
if (groupDto.ContentTypeNodeId == _id)
|
||||
{
|
||||
group.Id = groupDto.Id;
|
||||
|
||||
if (groupDto.ParentGroupId.HasValue)
|
||||
group.ParentId = groupDto.ParentGroupId.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
//If the PropertyGroup is inherited, we add a reference to the group as a Parent.
|
||||
group.ParentId = groupDto.Id;
|
||||
}
|
||||
|
||||
group.Name = groupDto.Text;
|
||||
group.ParentId = groupDto.ParentGroupId;
|
||||
group.SortOrder = groupDto.SortOrder;
|
||||
group.PropertyTypes = new PropertyTypeCollection();
|
||||
|
||||
@@ -32,7 +45,8 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0);
|
||||
foreach (var typeDto in typeDtos)
|
||||
{
|
||||
group.PropertyTypes.Add(new PropertyType(typeDto.DataTypeDto.ControlId,
|
||||
var tempGroupDto = groupDto;
|
||||
var propertyType = new PropertyType(typeDto.DataTypeDto.ControlId,
|
||||
typeDto.DataTypeDto.DbType.EnumParse<DataTypeDatabaseType>(true))
|
||||
{
|
||||
Alias = typeDto.Alias,
|
||||
@@ -43,9 +57,12 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
HelpText = typeDto.HelpText,
|
||||
Mandatory = typeDto.Mandatory,
|
||||
SortOrder = typeDto.SortOrder,
|
||||
PropertyGroupId = groupDto.Id
|
||||
});
|
||||
|
||||
ValidationRegExp = typeDto.ValidationRegExp,
|
||||
PropertyGroupId = new Lazy<int>(() => tempGroupDto.Id)
|
||||
};
|
||||
|
||||
propertyType.ResetDirtyProperties();
|
||||
group.PropertyTypes.Add(propertyType);
|
||||
}
|
||||
group.ResetDirtyProperties();
|
||||
propertyGroups.Add(group);
|
||||
@@ -67,10 +84,12 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
ContentTypeNodeId = _id,
|
||||
SortOrder = propertyGroup.SortOrder,
|
||||
Text = propertyGroup.Name,
|
||||
ParentGroupId = propertyGroup.ParentId
|
||||
Text = propertyGroup.Name
|
||||
};
|
||||
|
||||
if (propertyGroup.ParentId.HasValue)
|
||||
dto.ParentGroupId = propertyGroup.ParentId.Value;
|
||||
|
||||
if (propertyGroup.HasIdentity)
|
||||
dto.Id = propertyGroup.Id;
|
||||
|
||||
@@ -90,11 +109,18 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
HelpText = propertyType.HelpText,
|
||||
Mandatory = propertyType.Mandatory,
|
||||
Name = propertyType.Name,
|
||||
SortOrder = propertyType.SortOrder
|
||||
SortOrder = propertyType.SortOrder,
|
||||
ValidationRegExp = propertyType.ValidationRegExp
|
||||
};
|
||||
|
||||
if (tabId != default(int))
|
||||
{
|
||||
propertyTypeDto.PropertyTypeGroupId = tabId;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyTypeDto.PropertyTypeGroupId = null;
|
||||
}
|
||||
|
||||
if (propertyType.HasIdentity)
|
||||
propertyTypeDto.Id = propertyType.Id;
|
||||
|
||||
@@ -28,17 +28,22 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
|
||||
public Template BuildEntity(TemplateDto dto)
|
||||
{
|
||||
return new Template(string.Empty, dto.NodeDto.Text, dto.Alias)
|
||||
{
|
||||
CreateDate = dto.NodeDto.CreateDate,
|
||||
Id = dto.NodeId,
|
||||
Key = dto.NodeDto.UniqueId.Value,
|
||||
CreatorId = dto.NodeDto.UserId.Value,
|
||||
Level = dto.NodeDto.Level,
|
||||
ParentId = dto.NodeDto.ParentId,
|
||||
SortOrder = dto.NodeDto.SortOrder,
|
||||
NodePath = dto.NodeDto.Path
|
||||
};
|
||||
var template = new Template(string.Empty, dto.NodeDto.Text, dto.Alias)
|
||||
{
|
||||
CreateDate = dto.NodeDto.CreateDate,
|
||||
Id = dto.NodeId,
|
||||
Key = dto.NodeDto.UniqueId.Value,
|
||||
CreatorId = dto.NodeDto.UserId.Value,
|
||||
Level = dto.NodeDto.Level,
|
||||
ParentId = dto.NodeDto.ParentId,
|
||||
SortOrder = dto.NodeDto.SortOrder,
|
||||
NodePath = dto.NodeDto.Path
|
||||
};
|
||||
|
||||
if(dto.Master.HasValue)
|
||||
template.MasterTemplateId = new Lazy<int>(() => dto.Master.Value);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
public TemplateDto BuildDto(Template entity)
|
||||
@@ -50,6 +55,11 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
NodeDto = BuildNodeDto(entity)
|
||||
};
|
||||
|
||||
if (entity.MasterTemplateId != null && entity.MasterTemplateId.Value != default(int))
|
||||
{
|
||||
dto.Master = entity.MasterTemplateId.Value;
|
||||
}
|
||||
|
||||
if (entity.HasIdentity)
|
||||
{
|
||||
dto.NodeId = entity.Id;
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
IsLockedOut = dto.Disabled,
|
||||
IsApproved = dto.Disabled == false,
|
||||
Email = dto.Email,
|
||||
Lanuguage = dto.UserLanguage,
|
||||
Language = dto.UserLanguage,
|
||||
DefaultToLiveEditing = dto.DefaultToLiveEditing,
|
||||
NoConsole = dto.NoConsole,
|
||||
Permissions = dto.DefaultPermissions
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Login = entity.Username,
|
||||
NoConsole = entity.NoConsole,
|
||||
Password = entity.Password,
|
||||
UserLanguage = entity.Lanuguage,
|
||||
UserLanguage = entity.Language,
|
||||
UserName = entity.Name,
|
||||
Type = short.Parse(entity.UserType.Id.ToString()),
|
||||
DefaultPermissions = entity.Permissions
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
string columnName = columnAttribute.Name;
|
||||
|
||||
string columnMap = string.Format("{0}.{1}",
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(tableName),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(tableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
|
||||
return columnMap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Mappers
|
||||
{
|
||||
internal class ModelDtoMapper : IMapper
|
||||
{
|
||||
public void GetTableInfo(Type t, TableInfo ti)
|
||||
{ }
|
||||
|
||||
public bool MapPropertyToColumn(PropertyInfo pi, ref string columnName, ref bool resultColumn)
|
||||
{
|
||||
if (pi.DeclaringType == typeof(Content) || pi.DeclaringType == typeof(IContent))
|
||||
{
|
||||
switch (pi.Name)
|
||||
{
|
||||
case "Trashed":
|
||||
columnName = "[umbracoNode].[trashed]";
|
||||
return true;
|
||||
case "ParentId":
|
||||
columnName = "[umbracoNode].[parentID]";
|
||||
return true;
|
||||
case "UserId":
|
||||
columnName = "[umbracoNode].[nodeUser]";
|
||||
return true;
|
||||
case "Level":
|
||||
columnName = "[umbracoNode].[level]";
|
||||
return true;
|
||||
case "Path":
|
||||
columnName = "[umbracoNode].[path]";
|
||||
return true;
|
||||
case "SortOrder":
|
||||
columnName = "[umbracoNode].[sortOrder]";
|
||||
return true;
|
||||
case "NodeId":
|
||||
columnName = "[umbracoNode].[id]";
|
||||
return true;
|
||||
case "Published":
|
||||
columnName = "[cmsDocument].[published]";
|
||||
return true;
|
||||
case "Key":
|
||||
columnName = "[umbracoNode].[uniqueID]";
|
||||
return true;
|
||||
case "CreateDate":
|
||||
columnName = "[umbracoNode].[createDate]";
|
||||
return true;
|
||||
case "Name":
|
||||
columnName = "[umbracoNode].[text]";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pi.DeclaringType == typeof(ContentType) || pi.DeclaringType == typeof(IContentType))
|
||||
{
|
||||
switch (pi.Name)
|
||||
{
|
||||
case "Alias":
|
||||
columnName = "[cmsContentType].[alias]";
|
||||
return true;
|
||||
case "Icon":
|
||||
columnName = "[cmsContentType].[icon]";
|
||||
return true;
|
||||
case "Thumbnail":
|
||||
columnName = "[cmsContentType].[thumbnail]";
|
||||
return true;
|
||||
case "Description":
|
||||
columnName = "[cmsContentType].[description]";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public Func<object, object> GetFromDbConverter(PropertyInfo pi, Type sourceType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public Func<object, object> GetToDbConverter(Type sourceType)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Persistence.Mappers
|
||||
CacheMap<User, UserDto>(src => src.IsApproved, dto => dto.Disabled);
|
||||
CacheMap<User, UserDto>(src => src.NoConsole, dto => dto.NoConsole);
|
||||
CacheMap<User, UserDto>(src => src.UserType, dto => dto.Type);
|
||||
CacheMap<User, UserDto>(src => src.Lanuguage, dto => dto.UserLanguage);
|
||||
CacheMap<User, UserDto>(src => src.Language, dto => dto.UserLanguage);
|
||||
}
|
||||
|
||||
internal override string Map(string propertyName)
|
||||
|
||||
@@ -6,5 +6,6 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
{
|
||||
ICollection<IMigrationExpression> Expressions { get; set; }
|
||||
DatabaseProviders CurrentDatabaseProvider { get; }
|
||||
Database Database { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,10 @@
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
@@ -7,13 +13,193 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
/// </summary>
|
||||
internal class DatabaseSchemaCreation
|
||||
{
|
||||
#region Private Members
|
||||
private readonly Database _database;
|
||||
private static readonly Dictionary<int, Type> OrderedTables = new Dictionary<int, Type>
|
||||
{
|
||||
{0, typeof (NodeDto)},
|
||||
{1, typeof (TemplateDto)},
|
||||
{2, typeof (ContentDto)},
|
||||
{3, typeof (ContentVersionDto)},
|
||||
{4, typeof (DocumentDto)},
|
||||
{5, typeof (ContentTypeDto)},
|
||||
{6, typeof (DocumentTypeDto)},
|
||||
{7, typeof (DataTypeDto)},
|
||||
{8, typeof (DataTypePreValueDto)},
|
||||
{9, typeof (DictionaryDto)},
|
||||
{10, typeof (LanguageTextDto)},
|
||||
{11, typeof (LanguageDto)},
|
||||
{12, typeof (DomainDto)},
|
||||
{13, typeof (LogDto)},
|
||||
{14, typeof (MacroDto)},
|
||||
{15, typeof (MacroPropertyTypeDto)},
|
||||
{16, typeof (MacroPropertyDto)},
|
||||
{17, typeof (MemberTypeDto)},
|
||||
{18, typeof (MemberDto)},
|
||||
{19, typeof (Member2MemberGroupDto)},
|
||||
{20, typeof (ContentXmlDto)},
|
||||
{21, typeof (PreviewXmlDto)},
|
||||
{22, typeof (PropertyTypeGroupDto)},
|
||||
{23, typeof (PropertyTypeDto)},
|
||||
{24, typeof (PropertyDataDto)},
|
||||
{25, typeof (RelationTypeDto)},
|
||||
{26, typeof (RelationDto)},
|
||||
{27, typeof (StylesheetDto)},
|
||||
{28, typeof (StylesheetPropertyDto)},
|
||||
{29, typeof (TagDto)},
|
||||
{30, typeof (TagRelationshipDto)},
|
||||
{31, typeof (UserLoginDto)},
|
||||
{32, typeof (UserTypeDto)},
|
||||
{33, typeof (UserDto)},
|
||||
{34, typeof (TaskTypeDto)},
|
||||
{35, typeof (TaskDto)},
|
||||
{36, typeof (ContentType2ContentTypeDto)},
|
||||
{
|
||||
37,
|
||||
typeof (ContentTypeAllowedContentTypeDto)
|
||||
},
|
||||
{38, typeof (User2AppDto)},
|
||||
{39, typeof (User2NodeNotifyDto)},
|
||||
{40, typeof (User2NodePermissionDto)}
|
||||
};
|
||||
#endregion
|
||||
|
||||
public DatabaseSchemaCreation(Database database)
|
||||
{
|
||||
_database = database;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the database by creating the umbraco db schema
|
||||
/// </summary>
|
||||
public void InitializeDatabaseSchema()
|
||||
{
|
||||
var e = new DatabaseCreationEventArgs();
|
||||
FireBeforeCreation(e);
|
||||
|
||||
if (!e.Cancel)
|
||||
{
|
||||
foreach (var item in OrderedTables.OrderBy(x => x.Key))
|
||||
{
|
||||
_database.CreateTable(false, item.Value);
|
||||
}
|
||||
}
|
||||
|
||||
FireAfterCreation(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Validates the schema of the current database
|
||||
/// </summary>
|
||||
public DatabaseSchemaResult ValidateSchema()
|
||||
{
|
||||
var result = new DatabaseSchemaResult();
|
||||
|
||||
foreach (var item in OrderedTables.OrderBy(x => x.Key))
|
||||
{
|
||||
var tableDefinition = DefinitionFactory.GetTableDefinition(item.Value);
|
||||
result.TableDefinitions.Add(tableDefinition);
|
||||
}
|
||||
|
||||
//Check tables in configured database against tables in schema
|
||||
var tablesInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetTablesInSchema(_database).ToList();
|
||||
var tablesInSchema = result.TableDefinitions.Select(x => x.Name).ToList();
|
||||
//Add valid and invalid table differences to the result object
|
||||
var validTableDifferences = tablesInDatabase.Intersect(tablesInSchema);
|
||||
foreach (var tableName in validTableDifferences)
|
||||
{
|
||||
result.ValidTables.Add(tableName);
|
||||
}
|
||||
var invalidTableDifferences = tablesInDatabase.Except(tablesInSchema);
|
||||
foreach (var tableName in invalidTableDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Table", tableName));
|
||||
}
|
||||
|
||||
//Check columns in configured database against columns in schema
|
||||
var columnsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetColumnsInSchema(_database);
|
||||
var columnsPerTableInDatabase = columnsInDatabase.Select(x => string.Concat(x.TableName, ",", x.ColumnName)).ToList();
|
||||
var columnsPerTableInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => string.Concat(y.TableName, ",", y.Name))).ToList();
|
||||
//Add valid and invalid column differences to the result object
|
||||
var validColumnDifferences = columnsPerTableInDatabase.Intersect(columnsPerTableInSchema);
|
||||
foreach (var column in validColumnDifferences)
|
||||
{
|
||||
result.ValidColumns.Add(column);
|
||||
}
|
||||
var invalidColumnDifferences = columnsPerTableInDatabase.Except(columnsPerTableInSchema);
|
||||
foreach (var column in invalidColumnDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Column", column));
|
||||
}
|
||||
|
||||
//MySql doesn't conform to the "normal" naming of constraints, so there is currently no point in doing these checks.
|
||||
//NOTE: At a later point we do other checks for MySql, but ideally it should be necessary to do special checks for different providers.
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider)
|
||||
return result;
|
||||
|
||||
//Check constraints in configured database against constraints in schema
|
||||
var constraintsInDatabase = SqlSyntaxContext.SqlSyntaxProvider.GetConstraintsPerColumn(_database).DistinctBy(x => x.Item3).ToList();
|
||||
var foreignKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("FK_")).Select(x => x.Item3).ToList();
|
||||
var primaryKeysInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("PK_")).Select(x => x.Item3).ToList();
|
||||
var indexesInDatabase = constraintsInDatabase.Where(x => x.Item3.StartsWith("IX_")).Select(x => x.Item3).ToList();
|
||||
var unknownConstraintsInDatabase =
|
||||
constraintsInDatabase.Where(
|
||||
x =>
|
||||
x.Item3.StartsWith("FK_") == false && x.Item3.StartsWith("PK_") == false &&
|
||||
x.Item3.StartsWith("IX_") == false).Select(x => x.Item3).ToList();
|
||||
var foreignKeysInSchema = result.TableDefinitions.SelectMany(x => x.ForeignKeys.Select(y => y.Name)).ToList();
|
||||
var primaryKeysInSchema = result.TableDefinitions.SelectMany(x => x.Columns.Select(y => y.PrimaryKeyName)).ToList();
|
||||
var indexesInSchema = result.TableDefinitions.SelectMany(x => x.Indexes.Select(y => y.Name)).ToList();
|
||||
//Add valid and invalid foreign key differences to the result object
|
||||
foreach (var unknown in unknownConstraintsInDatabase)
|
||||
{
|
||||
if (foreignKeysInSchema.Contains(unknown) || primaryKeysInSchema.Contains(unknown) || indexesInSchema.Contains(unknown))
|
||||
{
|
||||
result.ValidConstraints.Add(unknown);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Unknown", unknown));
|
||||
}
|
||||
}
|
||||
var validForeignKeyDifferences = foreignKeysInDatabase.Intersect(foreignKeysInSchema);
|
||||
foreach (var foreignKey in validForeignKeyDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(foreignKey);
|
||||
}
|
||||
var invalidForeignKeyDifferences = foreignKeysInDatabase.Except(foreignKeysInSchema);
|
||||
foreach (var foreignKey in invalidForeignKeyDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", foreignKey));
|
||||
}
|
||||
//Add valid and invalid primary key differences to the result object
|
||||
var validPrimaryKeyDifferences = primaryKeysInDatabase.Intersect(primaryKeysInSchema);
|
||||
foreach (var primaryKey in validPrimaryKeyDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(primaryKey);
|
||||
}
|
||||
var invalidPrimaryKeyDifferences = primaryKeysInDatabase.Except(primaryKeysInSchema);
|
||||
foreach (var primaryKey in invalidPrimaryKeyDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", primaryKey));
|
||||
}
|
||||
//Add valid and invalid index differences to the result object
|
||||
var validIndexDifferences = indexesInDatabase.Intersect(indexesInSchema);
|
||||
foreach (var index in validIndexDifferences)
|
||||
{
|
||||
result.ValidConstraints.Add(index);
|
||||
}
|
||||
var invalidIndexDifferences = indexesInDatabase.Except(indexesInSchema);
|
||||
foreach (var index in invalidIndexDifferences)
|
||||
{
|
||||
result.Errors.Add(new Tuple<string, string>("Constraint", index));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// The save event handler
|
||||
/// </summary>
|
||||
@@ -51,83 +237,6 @@ namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the database by creating the umbraco db schema
|
||||
/// </summary>
|
||||
public void InitializeDatabaseSchema()
|
||||
{
|
||||
var e = new DatabaseCreationEventArgs();
|
||||
FireBeforeCreation(e);
|
||||
|
||||
if (!e.Cancel)
|
||||
{
|
||||
_database.CreateTable<NodeDto>();
|
||||
|
||||
_database.CreateTable<TemplateDto>();
|
||||
|
||||
_database.CreateTable<ContentDto>();
|
||||
_database.CreateTable<ContentVersionDto>();
|
||||
_database.CreateTable<DocumentDto>();
|
||||
|
||||
_database.CreateTable<ContentTypeDto>();
|
||||
_database.CreateTable<DocumentTypeDto>();
|
||||
|
||||
//_database.CreateTable<AppDto>();
|
||||
//_database.CreateTable<AppTreeDto>();
|
||||
|
||||
_database.CreateTable<DataTypeDto>();
|
||||
_database.CreateTable<DataTypePreValueDto>();
|
||||
|
||||
_database.CreateTable<DictionaryDto>();
|
||||
_database.CreateTable<LanguageTextDto>();
|
||||
|
||||
_database.CreateTable<LanguageDto>();
|
||||
_database.CreateTable<DomainDto>();
|
||||
|
||||
_database.CreateTable<LogDto>();
|
||||
|
||||
_database.CreateTable<MacroDto>();
|
||||
_database.CreateTable<MacroPropertyTypeDto>();
|
||||
_database.CreateTable<MacroPropertyDto>();
|
||||
|
||||
_database.CreateTable<MemberTypeDto>();
|
||||
_database.CreateTable<MemberDto>();
|
||||
_database.CreateTable<Member2MemberGroupDto>();
|
||||
|
||||
_database.CreateTable<ContentXmlDto>();
|
||||
_database.CreateTable<PreviewXmlDto>();
|
||||
|
||||
_database.CreateTable<PropertyTypeGroupDto>();
|
||||
_database.CreateTable<PropertyTypeDto>();
|
||||
_database.CreateTable<PropertyDataDto>();
|
||||
|
||||
_database.CreateTable<RelationTypeDto>();
|
||||
_database.CreateTable<RelationDto>();
|
||||
|
||||
_database.CreateTable<StylesheetDto>();
|
||||
_database.CreateTable<StylesheetPropertyDto>();
|
||||
|
||||
_database.CreateTable<TagDto>();
|
||||
_database.CreateTable<TagRelationshipDto>();
|
||||
|
||||
_database.CreateTable<UserLoginDto>();
|
||||
_database.CreateTable<UserTypeDto>();
|
||||
_database.CreateTable<UserDto>();
|
||||
|
||||
_database.CreateTable<TaskTypeDto>();
|
||||
_database.CreateTable<TaskDto>();
|
||||
|
||||
_database.CreateTable<ContentType2ContentTypeDto>();
|
||||
_database.CreateTable<ContentTypeAllowedContentTypeDto>();
|
||||
|
||||
_database.CreateTable<User2AppDto>();
|
||||
_database.CreateTable<User2NodeNotifyDto>();
|
||||
_database.CreateTable<User2NodePermissionDto>();
|
||||
}
|
||||
|
||||
FireAfterCreation(e);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
internal class DatabaseCreationEventArgs : System.ComponentModel.CancelEventArgs{}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Initial
|
||||
{
|
||||
public class DatabaseSchemaResult
|
||||
{
|
||||
public DatabaseSchemaResult()
|
||||
{
|
||||
Errors = new List<Tuple<string, string>>();
|
||||
TableDefinitions = new List<TableDefinition>();
|
||||
ValidTables = new List<string>();
|
||||
ValidColumns = new List<string>();
|
||||
ValidConstraints = new List<string>();
|
||||
}
|
||||
|
||||
public List<Tuple<string, string>> Errors { get; set; }
|
||||
|
||||
public List<TableDefinition> TableDefinitions { get; set; }
|
||||
|
||||
public List<string> ValidTables { get; set; }
|
||||
|
||||
public List<string> ValidColumns { get; set; }
|
||||
|
||||
public List<string> ValidConstraints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines the version of the currently installed database.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="Version"/> with Major and Minor values for
|
||||
/// non-empty database, otherwise "0.0.0" for empty databases.
|
||||
/// </returns>
|
||||
public Version DetermineInstalledVersion()
|
||||
{
|
||||
//If (ValidTables.Count == 0) database is empty and we return -> new Version(0, 0, 0);
|
||||
if(ValidTables.Count == 0)
|
||||
return new Version(0, 0, 0);
|
||||
|
||||
//If Errors is empty or if TableDefinitions tables + columns correspond to valid tables + columns then we're at current version
|
||||
if (Errors.Any() == false ||
|
||||
TableDefinitions.Any(x => ValidTables.Contains(x.Name) == false) == false &&
|
||||
TableDefinitions.SelectMany(definition => definition.Columns).Any(x => ValidColumns.Contains(x.Name) == false) == false)
|
||||
return UmbracoVersion.Current;
|
||||
|
||||
//If Errors contains umbracoApp or umbracoAppTree its pre-6.0.0 -> new Version(4, 10, 0);
|
||||
if (
|
||||
Errors.Any(
|
||||
x => x.Item1.Equals("Table") && (x.Item2.Equals("umbracoApp") || x.Item2.Equals("umbracoAppTree"))))
|
||||
{
|
||||
//If Errors contains umbracoUser2app or umbracoAppTree foreignkey to umbracoApp exists its pre-4.8.0 -> new Version(4, 7, 0);
|
||||
if (
|
||||
Errors.Any(
|
||||
x =>
|
||||
x.Item1.Equals("Constraint") &&
|
||||
(x.Item2.Contains("umbracoUser2app_umbracoApp") || x.Item2.Contains("umbracoAppTree_umbracoApp"))))
|
||||
{
|
||||
return new Version(4, 7, 0);
|
||||
}
|
||||
|
||||
return new Version(4, 9, 0);
|
||||
}
|
||||
|
||||
return UmbracoVersion.Current;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a summary of the schema validation result
|
||||
/// </summary>
|
||||
/// <returns>A string containing a human readable string with a summary message</returns>
|
||||
public string GetSummary()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
if (Errors.Any() == false)
|
||||
{
|
||||
sb.AppendLine("The database schema validation didn't find any errors.");
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
//Table error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Table")))
|
||||
{
|
||||
sb.AppendLine("The following tables were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Table")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
//Column error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Column")))
|
||||
{
|
||||
sb.AppendLine("The following columns were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Column")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
//Constraint error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Constraint")))
|
||||
{
|
||||
sb.AppendLine("The following constraints (Primary Keys, Foreign Keys and Indexes) were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Constraint")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
//Unknown constraint error summary
|
||||
if (Errors.Any(x => x.Item1.Equals("Unknown")))
|
||||
{
|
||||
sb.AppendLine("The following unknown constraints (Primary Keys, Foreign Keys and Indexes) were found in the database, but are not in the current schema:");
|
||||
sb.AppendLine(string.Join(",", Errors.Where(x => x.Item1.Equals("Unknown")).Select(x => x.Item2)));
|
||||
sb.AppendLine(" ");
|
||||
}
|
||||
|
||||
if (SqlSyntaxContext.SqlSyntaxProvider is MySqlSyntaxProvider)
|
||||
{
|
||||
sb.AppendLine("Please note that the constraints could not be validated because the current dataprovider is MySql.");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,61 +11,61 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
{
|
||||
public abstract class MigrationBase : IMigration
|
||||
{
|
||||
internal IMigrationContext _context;
|
||||
internal IMigrationContext Context;
|
||||
|
||||
public abstract void Up();
|
||||
public abstract void Down();
|
||||
|
||||
public virtual void GetUpExpressions(IMigrationContext context)
|
||||
{
|
||||
_context = context;
|
||||
Context = context;
|
||||
Up();
|
||||
}
|
||||
|
||||
public virtual void GetDownExpressions(IMigrationContext context)
|
||||
{
|
||||
_context = context;
|
||||
Context = context;
|
||||
Down();
|
||||
}
|
||||
|
||||
public IAlterSyntaxBuilder Alter
|
||||
{
|
||||
get { return new AlterSyntaxBuilder(_context); }
|
||||
get { return new AlterSyntaxBuilder(Context); }
|
||||
}
|
||||
|
||||
public ICreateBuilder Create
|
||||
{
|
||||
get { return new CreateBuilder(_context); }
|
||||
get { return new CreateBuilder(Context); }
|
||||
}
|
||||
|
||||
public IDeleteBuilder Delete
|
||||
{
|
||||
get { return new DeleteBuilder(_context); }
|
||||
get { return new DeleteBuilder(Context); }
|
||||
}
|
||||
|
||||
public IExecuteBuilder Execute
|
||||
{
|
||||
get { return new ExecuteBuilder(_context); }
|
||||
get { return new ExecuteBuilder(Context); }
|
||||
}
|
||||
|
||||
public IInsertBuilder Insert
|
||||
{
|
||||
get { return new InsertBuilder(_context); }
|
||||
get { return new InsertBuilder(Context); }
|
||||
}
|
||||
|
||||
public IRenameBuilder Rename
|
||||
{
|
||||
get { return new RenameBuilder(_context); }
|
||||
get { return new RenameBuilder(Context); }
|
||||
}
|
||||
|
||||
public IUpdateBuilder Update
|
||||
{
|
||||
get { return new UpdateBuilder(_context); }
|
||||
get { return new UpdateBuilder(Context); }
|
||||
}
|
||||
|
||||
public IIfDatabaseBuilder IfDatabase(params DatabaseProviders[] databaseProviders)
|
||||
{
|
||||
return new IfDatabaseBuilder(_context, databaseProviders);
|
||||
return new IfDatabaseBuilder(Context, databaseProviders);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,17 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
{
|
||||
internal class MigrationContext : IMigrationContext
|
||||
{
|
||||
public MigrationContext(DatabaseProviders databaseProvider)
|
||||
public MigrationContext(DatabaseProviders databaseProvider, Database database)
|
||||
{
|
||||
Expressions = new Collection<IMigrationExpression>();
|
||||
CurrentDatabaseProvider = databaseProvider;
|
||||
Database = database;
|
||||
}
|
||||
|
||||
public ICollection<IMigrationExpression> Expressions { get; set; }
|
||||
|
||||
public DatabaseProviders CurrentDatabaseProvider { get; private set; }
|
||||
|
||||
public Database Database { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -12,12 +12,12 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
/// <param name="surfaceControllers"></param>
|
||||
/// <param name="migrations"></param>
|
||||
/// <remarks>
|
||||
/// Use transient objects as we don't want these as singletons and take up memory that is not required
|
||||
/// </remarks>
|
||||
public MigrationResolver(IEnumerable<Type> surfaceControllers)
|
||||
: base(surfaceControllers, ObjectLifetimeScope.Transient)
|
||||
public MigrationResolver(IEnumerable<Type> migrations)
|
||||
: base(migrations, ObjectLifetimeScope.Transient)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -43,28 +43,30 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
/// <returns><c>True</c> if migrations were applied, otherwise <c>False</c></returns>
|
||||
public bool Execute(Database database, DatabaseProviders databaseProvider, bool isUpgrade = true)
|
||||
{
|
||||
LogHelper.Info<MigrationRunner>("Initializing database migration");
|
||||
LogHelper.Info<MigrationRunner>("Initializing database migrations");
|
||||
|
||||
var foundMigrations = MigrationResolver.Current.Migrations;
|
||||
|
||||
var migrations = isUpgrade
|
||||
? OrderedUpgradeMigrations(foundMigrations)
|
||||
: OrderedDowngradeMigrations(foundMigrations);
|
||||
|
||||
? OrderedUpgradeMigrations(foundMigrations).ToList()
|
||||
: OrderedDowngradeMigrations(foundMigrations).ToList();
|
||||
|
||||
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _configuredVersion, _targetVersion, true), this))
|
||||
return false;
|
||||
|
||||
//Loop through migrations to generate sql
|
||||
var context = new MigrationContext(databaseProvider);
|
||||
var context = new MigrationContext(databaseProvider, database);
|
||||
foreach (MigrationBase migration in migrations)
|
||||
{
|
||||
if (isUpgrade)
|
||||
{
|
||||
migration.GetUpExpressions(context);
|
||||
LogHelper.Info<MigrationRunner>(string.Format("Added UPGRADE migration '{0}' to context", migration.GetType().Name));
|
||||
}
|
||||
else
|
||||
{
|
||||
migration.GetDownExpressions(context);
|
||||
LogHelper.Info<MigrationRunner>(string.Format("Added DOWNGRADE migration '{0}' to context", migration.GetType().Name));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,7 +105,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
migrationAttribute.TargetVersion > _configuredVersion &&
|
||||
migrationAttribute.TargetVersion <= _targetVersion &&
|
||||
migrationAttribute.ProductName == _productName
|
||||
orderby migrationAttribute.SortOrder ascending
|
||||
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder ascending
|
||||
select migration);
|
||||
return migrations;
|
||||
}
|
||||
@@ -117,7 +119,8 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
migrationAttribute.TargetVersion > _configuredVersion &&
|
||||
migrationAttribute.TargetVersion <= _targetVersion &&
|
||||
migrationAttribute.ProductName == _productName
|
||||
orderby migrationAttribute.SortOrder descending
|
||||
orderby migrationAttribute.TargetVersion, migrationAttribute.SortOrder descending
|
||||
|
||||
select migration);
|
||||
return migrations;
|
||||
}
|
||||
|
||||
+3
-3
@@ -21,9 +21,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.AlterColumn,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(Column.Name));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.AlterColumn,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Column.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Alter.Expressions
|
||||
{
|
||||
//NOTE Should probably investigate if Deleting a Default Constraint is different from deleting a 'regular' constraint
|
||||
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ConstraintName));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ConstraintName));
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
|
||||
{
|
||||
var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE";
|
||||
|
||||
if (Constraint.IsPrimaryKeyConstraint && SyntaxConfig.SqlSyntaxProvider.SupportsClustered())
|
||||
if (Constraint.IsPrimaryKeyConstraint && SqlSyntaxContext.SqlSyntaxProvider.SupportsClustered())
|
||||
constraintType += " CLUSTERED";
|
||||
|
||||
if (Constraint.IsNonUniqueConstraint)
|
||||
@@ -27,12 +27,12 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
|
||||
|
||||
for (int i = 0; i < Constraint.Columns.Count; i++)
|
||||
{
|
||||
columns[i] = SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(Constraint.Columns.ElementAt(i));
|
||||
columns[i] = SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(Constraint.Columns.ElementAt(i));
|
||||
}
|
||||
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.CreateConstraint,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName),
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.CreateConstraint,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName),
|
||||
constraintType,
|
||||
string.Join(", ", columns));
|
||||
}
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Create.Expressions
|
||||
{
|
||||
var table = new TableDefinition{Name = TableName, SchemaName = SchemaName, Columns = Columns};
|
||||
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.Format(table));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.Format(table));
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -31,9 +31,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
foreach (string columnName in ColumnNames)
|
||||
{
|
||||
if (ColumnNames.First() != columnName) sb.AppendLine(";");
|
||||
sb.AppendFormat(SyntaxConfig.SqlSyntaxProvider.DropColumn,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(columnName));
|
||||
sb.AppendFormat(SqlSyntaxContext.SqlSyntaxProvider.DropColumn,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(columnName));
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
|
||||
+3
-3
@@ -14,9 +14,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Constraint.TableName),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Constraint.ConstraintName));
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
-5
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
|
||||
if (IsAllRows)
|
||||
{
|
||||
deleteItems.Add(string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteData, SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName), "1 = 1"));
|
||||
deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData, SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName), "1 = 1"));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -42,13 +42,13 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
foreach (KeyValuePair<string, object> item in row)
|
||||
{
|
||||
whereClauses.Add(string.Format("{0} {1} {2}",
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(item.Key),
|
||||
item.Value == null ? "IS" : "=",
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedValue(item.Value.ToString())));
|
||||
}
|
||||
|
||||
deleteItems.Add(string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteData,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
deleteItems.Add(string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteData,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName),
|
||||
String.Join(" AND ", whereClauses.ToArray())));
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
if (IsExpressionSupported() == false)
|
||||
return string.Empty;
|
||||
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteDefaultConstraint,
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteDefaultConstraint,
|
||||
TableName,
|
||||
ColumnName);
|
||||
}
|
||||
|
||||
+6
-6
@@ -33,10 +33,10 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
if (string.IsNullOrEmpty(ForeignKey.Name))
|
||||
ForeignKey.Name = string.Format("{0}_ibfk_1", ForeignKey.ForeignTable.ToLower());
|
||||
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
|
||||
"FOREIGN KEY ",
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(ForeignKey.Name))
|
||||
@@ -44,9 +44,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
ForeignKey.Name = string.Format("FK_{0}_{1}", ForeignKey.ForeignTable, ForeignKey.PrimaryTable);
|
||||
}
|
||||
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DeleteConstraint,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DeleteConstraint,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(ForeignKey.ForeignTable),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(ForeignKey.Name));
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -19,9 +19,9 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DropIndex,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedName(Index.Name),
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(Index.TableName));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DropIndex,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedName(Index.Name),
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(Index.TableName));
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -17,8 +17,8 @@ namespace Umbraco.Core.Persistence.Migrations.Syntax.Delete.Expressions
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format(SyntaxConfig.SqlSyntaxProvider.DropTable,
|
||||
SyntaxConfig.SqlSyntaxProvider.GetQuotedTableName(TableName));
|
||||
return string.Format(SqlSyntaxContext.SqlSyntaxProvider.DropTable,
|
||||
SqlSyntaxContext.SqlSyntaxProvider.GetQuotedTableName(TableName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,34 @@
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
|
||||
using System;
|
||||
using Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute
|
||||
{
|
||||
public class ExecuteBuilder : IExecuteBuilder
|
||||
{
|
||||
private readonly IMigrationContext _context;
|
||||
private readonly DatabaseProviders[] _databaseProviders;
|
||||
|
||||
public ExecuteBuilder(IMigrationContext context)
|
||||
public ExecuteBuilder(IMigrationContext context, params DatabaseProviders[] databaseProviders)
|
||||
{
|
||||
_context = context;
|
||||
_databaseProviders = databaseProviders;
|
||||
}
|
||||
|
||||
public void Sql(string sqlStatement)
|
||||
{
|
||||
var expression = new ExecuteSqlStatementExpression {SqlStatement = sqlStatement};
|
||||
var expression = _databaseProviders == null
|
||||
? new ExecuteSqlStatementExpression {SqlStatement = sqlStatement}
|
||||
: new ExecuteSqlStatementExpression(_context.CurrentDatabaseProvider,
|
||||
_databaseProviders) {SqlStatement = sqlStatement};
|
||||
_context.Expressions.Add(expression);
|
||||
}
|
||||
|
||||
public void Code(Func<Database, string> codeStatement)
|
||||
{
|
||||
var expression = _databaseProviders == null
|
||||
? new ExecuteCodeStatementExpression { CodeStatement = codeStatement }
|
||||
: new ExecuteCodeStatementExpression(_context.CurrentDatabaseProvider,
|
||||
_databaseProviders) { CodeStatement = codeStatement };
|
||||
_context.Expressions.Add(expression);
|
||||
}
|
||||
}
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Migrations.Syntax.Execute.Expressions
|
||||
{
|
||||
public class ExecuteCodeStatementExpression : MigrationExpressionBase
|
||||
{
|
||||
public ExecuteCodeStatementExpression()
|
||||
{
|
||||
}
|
||||
|
||||
public ExecuteCodeStatementExpression(DatabaseProviders current, DatabaseProviders[] databaseProviders)
|
||||
: base(current, databaseProviders)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual Func<Database, string> CodeStatement { get; set; }
|
||||
|
||||
public override string Process(Database database)
|
||||
{
|
||||
if(CodeStatement != null)
|
||||
return CodeStatement(database);
|
||||
|
||||
return base.Process(database);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
@@ -14,6 +14,9 @@
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (IsExpressionSupported() == false)
|
||||
return string.Empty;
|
||||
|
||||
return SqlStatement;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user