Compare commits
1014 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d7d6b7f128 | |||
| 62e467d860 | |||
| 021010d7ea | |||
| 4a21675a0a | |||
| 73bc5c6ec9 | |||
| 98a545bdc6 | |||
| 08150c05e9 | |||
| 688f8c4170 | |||
| 31cbb79ede | |||
| 305ce84ef5 | |||
| c27e9e9c77 | |||
| c6d7056a64 | |||
| cbf5e25e1f | |||
| 41e555881f | |||
| b60c700e05 | |||
| 60ffd20e20 | |||
| 7db1055a0d | |||
| fb4af74916 | |||
| 8b962cff0c | |||
| d625388786 | |||
| fa1663ed51 | |||
| fc8c750fb0 | |||
| 4d7fa64a6c | |||
| bbe8271c35 | |||
| 2d42a6ca16 | |||
| 4879215146 | |||
| 48a6929077 | |||
| efc52e26e5 | |||
| 1258148e37 | |||
| 2c7f0c54bb | |||
| ca0de5acd3 | |||
| 405d8e8253 | |||
| b335ca0a10 | |||
| 27168722ab | |||
| 6658ecf6e3 | |||
| cfee55d0db | |||
| 80d49f9bc8 | |||
| 6efc6dfe6a | |||
| 51624cee57 | |||
| 701082a909 | |||
| 81b2e4e050 | |||
| be9fbf14f1 | |||
| e31ec37c9e | |||
| 6dbeba0763 | |||
| 00e0f83c8e | |||
| 3ba3d8977f | |||
| 19af28dd93 | |||
| 91cda667a2 | |||
| 1c59c0b164 | |||
| 9fc87a3986 | |||
| 3a44f70cee | |||
| 74b9a43685 | |||
| 23e16a9182 | |||
| a3cf41284b | |||
| 2907b0dd1a | |||
| c89f44bb3d | |||
| 3a13cd82ed | |||
| 90e6815164 | |||
| f59bd481f4 | |||
| d459246519 | |||
| efbfef74c2 | |||
| 1ee131db81 | |||
| cb9e631d7b | |||
| 9ced53c9a9 | |||
| df287f291e | |||
| fc861fecbc | |||
| 6aeb1a8845 | |||
| 8c493a1ff9 | |||
| 9b7b0d8923 | |||
| 51f51c1762 | |||
| b6e377a560 | |||
| 4534581b29 | |||
| b915f723f5 | |||
| 36768a19c1 | |||
| bf5a48c5f5 | |||
| 040aae2429 | |||
| c7f6416a0b | |||
| 8259024e20 | |||
| 31ea03a7cc | |||
| 150e2b12e8 | |||
| e29ac4d17c | |||
| ae30245a9b | |||
| 595e26e41f | |||
| dda19e292a | |||
| 08f07ff3b7 | |||
| e9e8d0d4b1 | |||
| 9d3a1fe529 | |||
| 4f396222dc | |||
| 68f5a141c5 | |||
| 9c0ca85c41 | |||
| 5cd314335c | |||
| 241d486e97 | |||
| b0f1b19385 | |||
| b6de92167b | |||
| 136b3db098 | |||
| 7e49cc0f25 | |||
| 1c5bcbc5bb | |||
| 5fab5102d9 | |||
| 6655be5f5e | |||
| 60cd82884f | |||
| eb93c0de11 | |||
| 8cb29182f4 | |||
| 0786d0849c | |||
| 005bee7650 | |||
| 39ce2067ef | |||
| 21f46d0a3c | |||
| 59db5b0081 | |||
| 44b90e2ce6 | |||
| 6829660720 | |||
| 67a69d2e11 | |||
| 80364fc4d2 | |||
| e02c6591d9 | |||
| 2e6fb8e3e5 | |||
| cee3f456d1 | |||
| 46bb0cca2d | |||
| 2beba8067e | |||
| 175da06d60 | |||
| 7769a0ba42 | |||
| fd65380367 | |||
| 9880e9b6a5 | |||
| 134033bc3d | |||
| 8bf3835212 | |||
| 6782e71841 | |||
| 7b449b4bad | |||
| 7fafea2370 | |||
| 86c37c7f6d | |||
| 7dd9f3e766 | |||
| c539db39ec | |||
| 2cc881883b | |||
| bcf4a84725 | |||
| 164f1e253e | |||
| 5c0af42d00 | |||
| 38ae9d6d52 | |||
| b8971f0dd1 | |||
| 939d429b8b | |||
| d103151159 | |||
| 796708075c | |||
| cfd473bfe5 | |||
| b20e3c7435 | |||
| 6de2cea9c5 | |||
| 9db9112407 | |||
| cc8adae593 | |||
| 19d55c8df0 | |||
| 7707bfe700 | |||
| 47290cd801 | |||
| b10d370b16 | |||
| 71a640de74 | |||
| 9c27a6c69a | |||
| adac29c655 | |||
| e52adfdd07 | |||
| 43bb9ab69b | |||
| 239a7632b0 | |||
| 04a7e2e04e | |||
| 27d7bc2ae1 | |||
| 5ba07d56e7 | |||
| 0ffd02fc61 | |||
| 2eabcef69b | |||
| 960cc32da1 | |||
| ef20deb9cb | |||
| fdf206038a | |||
| 6faadce477 | |||
| 2d5f56cbff | |||
| 4569a52806 | |||
| ca2896aaaa | |||
| 0b77e604f6 | |||
| f50153728d | |||
| 52a46a2fe0 | |||
| da9fd1a9e8 | |||
| 1692000117 | |||
| 9972f95a10 | |||
| 964a8b400f | |||
| 0762bd7e76 | |||
| 15c5900a24 | |||
| 1ec63c3f85 | |||
| fad090658f | |||
| 61c3816bb9 | |||
| b8e2e49a44 | |||
| 6d9190bdb3 | |||
| 72998e1a6e | |||
| ff87d8b414 | |||
| a8c29644d4 | |||
| bb9ec82060 | |||
| 6e055f0d03 | |||
| 9b1f2352bd | |||
| abbee60c9c | |||
| 97ec0ecd08 | |||
| d232aa1f00 | |||
| 1ccc8cc161 | |||
| 56b1e0902e | |||
| 17d17cfb82 | |||
| fa89bef11a | |||
| 39e4bf4579 | |||
| 5ade95d797 | |||
| f043a2e4ee | |||
| c5e7e1e39e | |||
| db2a35dbce | |||
| 3d006f1e08 | |||
| e0c891719f | |||
| 89a14c13e5 | |||
| ca9aa21c7b | |||
| c0eaeb3168 | |||
| 74e16c0f8d | |||
| fedd9e2897 | |||
| c456c0a396 | |||
| 525254efd4 | |||
| a92288cd61 | |||
| 97471f667d | |||
| 7aca656919 | |||
| c309e5edaf | |||
| e76ad837b9 | |||
| 0b6ed42201 | |||
| a875ede3da | |||
| f8fac9f84e | |||
| 83ce359234 | |||
| 69fc7c4b7c | |||
| e9e2a86e2e | |||
| 540c338967 | |||
| b58799eb3d | |||
| 85e5b023b7 | |||
| 63befa55d5 | |||
| 2c64f91b25 | |||
| 964f3bae60 | |||
| e702fe2877 | |||
| 9d55656ae9 | |||
| d57de05453 | |||
| 11e4bf5de8 | |||
| 5c75285543 | |||
| 82661d9af4 | |||
| ee3f977565 | |||
| 8f984c8dc8 | |||
| 8df00d5525 | |||
| 05d9eca904 | |||
| 2851216b88 | |||
| 92dc70fc0c | |||
| 38cd3dcf94 | |||
| ba46430ad1 | |||
| db957c8eaa | |||
| b32325bbaa | |||
| 56cff6bba8 | |||
| f28136de91 | |||
| 8c3f6dfc25 | |||
| 6b289e1a7d | |||
| 73b107ee2a | |||
| 945050858e | |||
| 32dc9bd275 | |||
| f87245f73d | |||
| 0008afb455 | |||
| 6f74fcf24a | |||
| a0d3c18acc | |||
| bd848b00ff | |||
| 50d7114209 | |||
| 91fa583f62 | |||
| 23d91fd350 | |||
| d4714e1580 | |||
| 2b22e6a784 | |||
| 59840926c8 | |||
| 338c7cc5a6 | |||
| 77850aea18 | |||
| 895f0a9dfe | |||
| ec03a3dc42 | |||
| 5a4dbba21b | |||
| 04546dd827 | |||
| 4ecf1f919e | |||
| bdc4e1ae6a | |||
| 3cb05870af | |||
| 95b0c342bb | |||
| 3a5584a1c1 | |||
| b425edbb45 | |||
| b403283368 | |||
| cb1d347769 | |||
| 3ac64f18d2 | |||
| 193682cd4c | |||
| d99f7b6ff6 | |||
| d1d74203ea | |||
| 4d0a2c85b7 | |||
| e135291980 | |||
| e1957b895f | |||
| 04daaef7b7 | |||
| 29aaa26022 | |||
| 3f6ec6e36f | |||
| 8347d8f23b | |||
| db863a4592 | |||
| ca104347b3 | |||
| 9fbf1aedac | |||
| dfbd064de6 | |||
| c696c62185 | |||
| 0dfbb95033 | |||
| 2bff1bfbb6 | |||
| 17969e4537 | |||
| ab1dade468 | |||
| 374fdcf29e | |||
| 1643eec62c | |||
| 6a48c1646d | |||
| 6e89202002 | |||
| 69a6a80ffd | |||
| c472463f37 | |||
| 76f9e2c22a | |||
| df18cdc7f7 | |||
| 87dcdc596e | |||
| 044120ffd2 | |||
| bcb19eea35 | |||
| 0acb0d48a1 | |||
| da00ad1444 | |||
| 7bc52b3948 | |||
| a77aec4156 | |||
| f7f3dccfc8 | |||
| ab3469d703 | |||
| c78ea90cf5 | |||
| c8828b968c | |||
| 2e28ff3ccf | |||
| 3de0b85ae3 | |||
| f18b7110c9 | |||
| 44bb7e84db | |||
| 06f68b1417 | |||
| 7115d85440 | |||
| d9937fb276 | |||
| 87b51d1418 | |||
| 8ea1af56ab | |||
| 219eb61194 | |||
| 7f98f99eaa | |||
| 53bce239c3 | |||
| 1d3279fe07 | |||
| 88bb796f4d | |||
| 97878ac25a | |||
| c87e880b64 | |||
| 50a896a6cc | |||
| 3c31e33000 | |||
| 9462f8ad85 | |||
| cb4e1d324d | |||
| 13d26eb435 | |||
| 6a06a9e400 | |||
| 1149129c6f | |||
| ad886efa62 | |||
| 79df75c415 | |||
| c0a6c58a07 | |||
| deaece7cfc | |||
| a3bb11e4b0 | |||
| f2b52585e1 | |||
| 8b308fa1ea | |||
| e28ba446a0 | |||
| c645a2cf15 | |||
| 5fb8d990f8 | |||
| 8626e4337f | |||
| 0f22c41eee | |||
| e73fda14b5 | |||
| a04df8070a | |||
| 60c1052db1 | |||
| dd041a6f09 | |||
| 733aab6eb5 | |||
| 1e6d50a86b | |||
| 0445588c6b | |||
| e9072aa6c9 | |||
| 779306d90f | |||
| 4d316cf0ce | |||
| 7540f49a5e | |||
| 2e29d112e5 | |||
| fe451154d1 | |||
| 864650193a | |||
| 271056f997 | |||
| 9b0f2145d0 | |||
| cfa7b0a092 | |||
| 5726420848 | |||
| f355b27d1f | |||
| 8e861eab43 | |||
| 7e9afe7720 | |||
| a050a73c31 | |||
| 403a210c1c | |||
| 03c7429653 | |||
| bba7b15125 | |||
| ca752f74bc | |||
| b840a0992c | |||
| 51997d0651 | |||
| 1d9e33dadf | |||
| 316ec5d20f | |||
| 9482104ec5 | |||
| 7053c175f8 | |||
| 82bd11e66d | |||
| b2116480fc | |||
| 94b0cb04da | |||
| caef6cc623 | |||
| ff02b28d26 | |||
| 247ca906aa | |||
| bcffc37287 | |||
| 280ad246ab | |||
| 8d2a9d1d81 | |||
| 43e0ef2472 | |||
| 2aaf104856 | |||
| 44cfe5da84 | |||
| 224d1bcf6e | |||
| 6ebacf118e | |||
| d5fd266b19 | |||
| e4edd8f692 | |||
| 8fe904cea7 | |||
| 3a17002ec4 | |||
| 804c60653e | |||
| 29c6d547db | |||
| 546999e470 | |||
| 0da75f4e78 | |||
| e69957e580 | |||
| a072d4edb3 | |||
| 5768992ccc | |||
| 968f93f769 | |||
| 0c6c3f6d51 | |||
| 81aae79b42 | |||
| 9edbb3fc26 | |||
| 7fdd2bcdfc | |||
| ba90fdeb56 | |||
| d6bae1b58f | |||
| ef53db52f7 | |||
| 863b97039c | |||
| 1a1adbf647 | |||
| 5c745565da | |||
| 5dec54badb | |||
| e5e725b376 | |||
| a082b72f50 | |||
| 69791a3616 | |||
| 72bdc0f070 | |||
| 4f28cb1917 | |||
| 6cb104cd4f | |||
| af3665c0f9 | |||
| ed78082693 | |||
| f0f25c67c6 | |||
| 91e15d4b64 | |||
| da8c0726b1 | |||
| 2fbb9721fa | |||
| de6ffd456c | |||
| 5b3ff58ad8 | |||
| 5dec4a4a94 | |||
| 5d5b852e5a | |||
| 454684e108 | |||
| 4fc5279a78 | |||
| abb393c335 | |||
| 225cf8f8f5 | |||
| 0bc2e93230 | |||
| 7ca7b6f922 | |||
| 923ceadd02 | |||
| c5111f9ba8 | |||
| 85d988e75e | |||
| 49f2892ff1 | |||
| c7c0793a0a | |||
| 3d847b0ea9 | |||
| 3cd39fee94 | |||
| 8023a89b10 | |||
| 4f6ecf5e91 | |||
| eb4588780e | |||
| 9a4c1972b2 | |||
| b993ce953b | |||
| dde0f1aa36 | |||
| 3fd6754057 | |||
| 8fbb459233 | |||
| de00b2ef00 | |||
| 2294940038 | |||
| e8e2e2c91d | |||
| d78dcb51c0 | |||
| cb6f934792 | |||
| 8eb4d2ed20 | |||
| bc19c8358d | |||
| ce38320c6a | |||
| 439df3b52c | |||
| ab71fa3101 | |||
| 8e21bc3c74 | |||
| 7adbecf9a1 | |||
| 3083f185d0 | |||
| 07356db30e | |||
| f615125c24 | |||
| 29da5ed843 | |||
| 587ce8fc4f | |||
| 833c787414 | |||
| 1f2e1e4e93 | |||
| d7bd711d9a | |||
| 2fdf148610 | |||
| 9d9e5e8274 | |||
| 89895dd592 | |||
| f309e3587b | |||
| f9252372ea | |||
| 02a2178029 | |||
| ee775a2fde | |||
| 22af206626 | |||
| 493873a8d0 | |||
| 7beec02a3f | |||
| 86cb750ca1 | |||
| f92e119060 | |||
| 13a0621f89 | |||
| 67e109c0e6 | |||
| 8a4d85771b | |||
| 0cd871241f | |||
| 3eba5e5c19 | |||
| 4688ac104e | |||
| 754dbc9621 | |||
| d936105cfe | |||
| ea2f808c1e | |||
| 3ece9175a0 | |||
| 692dc66684 | |||
| 25a79bc2fa | |||
| 8cd413ba8f | |||
| 1eeae770b4 | |||
| 032dbe5bf5 | |||
| a7695163b9 | |||
| cb4569677e | |||
| 4be704b968 | |||
| b7a5cb046a | |||
| 0e2c94c079 | |||
| 99da2e923d | |||
| c9200d54b5 | |||
| eb52dafb33 | |||
| af382c171b | |||
| 54fdfdd639 | |||
| c4c99ef0b8 | |||
| 0bd233815e | |||
| 8f51f574ae | |||
| 90d4153e87 | |||
| 6380d1d538 | |||
| b43ca64ac7 | |||
| 4c9fd4029f | |||
| 7825040e4d | |||
| f27b456eb4 | |||
| 3d65afabbf | |||
| ef9bf155ef | |||
| e947f661a9 | |||
| 0eb8ebd82e | |||
| bc76fa8687 | |||
| 8681d535f2 | |||
| bd7aba5ea2 | |||
| 6d81705ece | |||
| b433af8611 | |||
| b0f4d0e16b | |||
| 2f24dfb8f0 | |||
| ad63050078 | |||
| 552c2ed4dc | |||
| d7e522132e | |||
| ca7c43d944 | |||
| c35e842391 | |||
| dae20cc986 | |||
| c466514e7f | |||
| 5e2aa7fa68 | |||
| 11ccc88bc8 | |||
| c83009c879 | |||
| d6b9b41776 | |||
| 508a4c32b4 | |||
| dbf2538aae | |||
| 5293b3bcc7 | |||
| 940caba2c4 | |||
| e31daef4fa | |||
| 7984626433 | |||
| ffa557b097 | |||
| 9236bcbcd8 | |||
| 1b875b0c67 | |||
| ecce68da0a | |||
| e27a882d2b | |||
| c7ae379fd1 | |||
| 8ad13f6853 | |||
| e4ae40c2fe | |||
| be61270e42 | |||
| bd00b532eb | |||
| ebc9478f2d | |||
| ab72808a10 | |||
| 068e82172a | |||
| 45988d4f0c | |||
| db330b3223 | |||
| 03fd06cfa7 | |||
| 775148d241 | |||
| 8e65ecdc4a | |||
| 6a43dd41c6 | |||
| 82ae6a1aef | |||
| a127683d92 | |||
| 06f3f4b191 | |||
| a2f45a38f7 | |||
| 4b966ebe91 | |||
| da9e87d0ab | |||
| 84a206ce5e | |||
| 3c3c31c36e | |||
| 585f8e07f7 | |||
| f7c0e02bfd | |||
| e767eaa08b | |||
| 9786ae8428 | |||
| f28c4cdaa5 | |||
| cc41447ff7 | |||
| 2e239939fc | |||
| 4cdb30fed0 | |||
| ef32eda874 | |||
| 01ccf8a6a6 | |||
| 9dc34f0c98 | |||
| c27ca1fb0d | |||
| 68e287cf12 | |||
| ad6946aa26 | |||
| cec829774e | |||
| 94e958bd7a | |||
| 42d7c83a6d | |||
| 1a435148d8 | |||
| 957c8e917f | |||
| de348a9946 | |||
| d7e65dd088 | |||
| 4e1e2c5332 | |||
| 7689ee73d4 | |||
| af7a5187f2 | |||
| e276c7a1bf | |||
| 7797ad4130 | |||
| 78bfc087fb | |||
| 146a865882 | |||
| 791e6a5f92 | |||
| 1f6f8df5b5 | |||
| 7f5eff6e53 | |||
| d885265818 | |||
| be6140a38b | |||
| 8ee05063a2 | |||
| 7920383904 | |||
| 1a3d9e27f4 | |||
| b0827b75b2 | |||
| 824eee80b3 | |||
| 0638786075 | |||
| 2654f9189f | |||
| 79e9394b62 | |||
| ebef6b5d42 | |||
| 054fd46555 | |||
| 9ab9007821 | |||
| a7a7909a25 | |||
| ac1aa719b6 | |||
| d7453b5a6e | |||
| 5ed8ceb85e | |||
| b7ea0840a9 | |||
| 6b65f1c197 | |||
| 9f68bd4e52 | |||
| bc7dc8629e | |||
| d3c2b0a247 | |||
| 41ee187637 | |||
| 3ec9c9a348 | |||
| 464711d3c8 | |||
| efaa24fb51 | |||
| 00659711d9 | |||
| 021e083b75 | |||
| 0f89b1dea7 | |||
| b15fd4496a | |||
| b3ea0c83f9 | |||
| c1aefe0686 | |||
| 907dd8092a | |||
| 5b8d314a29 | |||
| f33d21b8f6 | |||
| 7b5568ecb4 | |||
| 2361d7878e | |||
| 613a9de858 | |||
| 9f234f1669 | |||
| 7353591f4c | |||
| 439c30e2fd | |||
| 0858e04345 | |||
| 6d22f7f86f | |||
| c13b2fae4b | |||
| 2fd383960d | |||
| 51b19bedc8 | |||
| 582e36c517 | |||
| a62426a763 | |||
| 33f76d25f7 | |||
| 898f00cbf1 | |||
| 12de575dfb | |||
| cd8418a8c0 | |||
| 89dcb6a0e2 | |||
| a2c5c35394 | |||
| cd1e88d151 | |||
| c0616a37bf | |||
| da4be3be65 | |||
| e757868d09 | |||
| f09f17e496 | |||
| 3fac1b05ae | |||
| 716629235e | |||
| e40a904896 | |||
| 5aeb8ed74d | |||
| 5273644a7e | |||
| 08c4a75af7 | |||
| 047eb893eb | |||
| 308c381e17 | |||
| 56e6722880 | |||
| fb3ac86d8c | |||
| e99309aa2f | |||
| 917a2b78dd | |||
| e559a6d485 | |||
| 160518e977 | |||
| f985725118 | |||
| 01a2ba8ad6 | |||
| 36a659f3da | |||
| 5ec67ab3fd | |||
| 993513b138 | |||
| 7f75802e4e | |||
| f6cc06356c | |||
| 7929b460c3 | |||
| 379b8c3719 | |||
| 174e336512 | |||
| 9bf61bb487 | |||
| 5a5bdb6328 | |||
| 7f03a97a78 | |||
| 7533b0e704 | |||
| d72af87790 | |||
| 1eba16579a | |||
| 1c373ca771 | |||
| f907385ac8 | |||
| fbda8fe4a3 | |||
| e8ceb2756d | |||
| cfe90999d3 | |||
| bbda93a06b | |||
| a041fc47e0 | |||
| 6da5fe6b3a | |||
| 869f75af4a | |||
| 76032cf5f7 | |||
| c03e1420e0 | |||
| 64975166e7 | |||
| 2ee34d5c48 | |||
| 44018b976a | |||
| 1293730dd3 | |||
| fc30cdee31 | |||
| ca8e25f465 | |||
| f55d1328d0 | |||
| 685f7bcde8 | |||
| 5eb330b7d7 | |||
| 6c78b8b60a | |||
| 8602aab6f7 | |||
| 88702f7e18 | |||
| ce618d289b | |||
| 2191d33844 | |||
| 92a507bc87 | |||
| 57bb47a78b | |||
| 57b037fda0 | |||
| 7aad660ebf | |||
| 181a5b847c | |||
| 7a7f24ed78 | |||
| 0c8e5a2cc2 | |||
| c43dda468c | |||
| 9edc20b1b1 | |||
| 28247add3c | |||
| e4d96997d5 | |||
| dd84164ac5 | |||
| 8bc033efde | |||
| a407f9aa19 | |||
| 1e90015253 | |||
| 7f63919ba6 | |||
| 57ce6d7f64 | |||
| 0fff051cf6 | |||
| 0a997ae04e | |||
| bf194a819a | |||
| a102a7c094 | |||
| 346b29b827 | |||
| 1bedc6a444 | |||
| 826f916960 | |||
| d30b70ea12 | |||
| 0f7165dada | |||
| 31f8213460 | |||
| 6b419f4260 | |||
| ddd693e120 | |||
| 7047d3ebaa | |||
| 84d131e7f7 | |||
| f75b66dda8 | |||
| 1abec65f03 | |||
| ac0a5bfe5d | |||
| 6e4ffcc068 | |||
| 121036ebb9 | |||
| e2f9c90dc6 | |||
| 439d52e358 | |||
| 7d1aedc0d3 | |||
| 48864e3fa4 | |||
| 474dcf0779 | |||
| 0366fa73c3 | |||
| 9b6cad7d82 | |||
| 3a990d9cf0 | |||
| 832ee47564 | |||
| dc3f96a292 | |||
| 7806246a52 | |||
| e136780947 | |||
| b9ac5a365a | |||
| 942d010264 | |||
| 643dab0238 | |||
| 1445ff7a83 | |||
| b70241e807 | |||
| 10761a2211 | |||
| f392c32d63 | |||
| 95cfb6c56b | |||
| d59e3d34f9 | |||
| 1a03c7f068 | |||
| f52e82296f | |||
| 16868d7b51 | |||
| 59df08f956 | |||
| 3c9041b00e | |||
| 09a39c1fe4 | |||
| 7377b7614e | |||
| e2137c9a43 | |||
| f2b9963385 | |||
| f5ad4a35cd | |||
| b55aa7c16d | |||
| ee577da48e | |||
| affe3d688b | |||
| addd8946e8 | |||
| d2fe3e7406 | |||
| 1b844421fc | |||
| 6b0ef0e289 | |||
| 7c0acff9f8 | |||
| b2279a30f7 | |||
| df9c6baed7 | |||
| 22758c6e12 | |||
| f8ed2a3db4 | |||
| c9f6778e31 | |||
| 494a7d54b8 | |||
| 6dd9fc2780 | |||
| b99b9b7a6b | |||
| c06ac51b48 | |||
| abcd6e69f0 | |||
| 5fe22a2231 | |||
| 03cb5bf9e5 | |||
| 79fa7db631 | |||
| 4574bf2de2 | |||
| 3351a3e112 | |||
| 584c3e4c19 | |||
| 479f6a1525 | |||
| 6f55515f11 | |||
| 9f0639ba24 | |||
| 028903c306 | |||
| adb02c96a7 | |||
| 53357b0582 | |||
| 1164f1cdbb | |||
| f4d0de6665 | |||
| 7f05b80a22 | |||
| 20239a9b71 | |||
| 70a0bbbe61 | |||
| c4b07cc3ae | |||
| 771935b8a5 | |||
| 73bb401f81 | |||
| 8ccbe4c1e4 | |||
| cf3343749f | |||
| 079df4a8b7 | |||
| 7612884705 | |||
| 74dc2d80fd | |||
| 647ebee34d | |||
| bc444847f4 | |||
| 24d9c60bdf | |||
| b5c2fc82bb | |||
| a50256d381 | |||
| 290f34f034 | |||
| 92f609ff71 | |||
| 7e6f7f8a2b | |||
| c5419e700b | |||
| cb09094632 | |||
| 618c50f9da | |||
| 72404e68a0 | |||
| 2c451c5cfe | |||
| af7f83f0f6 | |||
| 5b3c2178a2 | |||
| 145f789631 | |||
| 106a06be2a | |||
| a70c9226fc | |||
| e27e95cb1a | |||
| cdbc3fa8cd | |||
| 6feb7b222f | |||
| f3763dffe5 | |||
| be939b48f9 | |||
| b678eff484 | |||
| 01ff16d00d | |||
| a50f1e22c0 | |||
| 3ae16e717c | |||
| 06aaa9718f | |||
| d3eeb45651 | |||
| 6cd52bbc3c | |||
| 273c934e26 | |||
| 2087125d95 | |||
| 7f27745d27 | |||
| f493c254e8 | |||
| 362b98509b | |||
| 4337036358 | |||
| 271c771f1c | |||
| 7934ea14a3 | |||
| 8aabb3e3d0 | |||
| 528be48437 | |||
| a8220e0f62 | |||
| cb097f11a1 | |||
| 911fdf20a4 | |||
| 939d128662 | |||
| b95ba2e9a7 | |||
| e9c917e60b | |||
| 2cd23cb24f | |||
| 59872b0e17 | |||
| 6e9ae485ea | |||
| dec9422531 | |||
| 8b299a070f | |||
| 633bd847ea | |||
| 38837049f0 | |||
| 1a637961b7 | |||
| f792be9495 | |||
| 41460d5500 | |||
| d56bee8761 | |||
| 4c852eab0b | |||
| 0cca342b83 | |||
| 45fa106c42 | |||
| 6e9e2b99a4 | |||
| 1be3f06bc4 | |||
| 86e4acef86 | |||
| 782193b17a | |||
| b3118f742d | |||
| 83d26fd91a | |||
| 16c6fc70bf | |||
| 517dc3abe3 | |||
| 48432179be | |||
| f3d925b509 | |||
| e590b20e75 | |||
| 048112dcea | |||
| fce7adcc8e | |||
| fcc71958e3 | |||
| bb431c7681 | |||
| 4b945f355a | |||
| 3cf8ef9513 | |||
| aeabca87d7 | |||
| fbed82219d | |||
| d57a273c65 | |||
| d90ef2865b | |||
| 29177974eb | |||
| b130ccf9c1 | |||
| 4c61cac9a8 | |||
| 57bd5178f7 | |||
| ef51336a7e | |||
| d3dd84671f | |||
| 5e3e9cce12 | |||
| 9bb880f195 | |||
| 65654de06a | |||
| 2334596bf3 | |||
| 1d664bce52 | |||
| 9a515de43f | |||
| c299edfe5a | |||
| 73d7915fb5 | |||
| 225f657154 | |||
| 4f80902ac2 | |||
| 26b8236eea | |||
| ffd63a9103 | |||
| bb436426a4 | |||
| faa6a229e6 | |||
| b55d065d45 | |||
| 0e8b8e3aef | |||
| 7cf3f10afb | |||
| 9b50d6d251 | |||
| 83db63c5a8 | |||
| 6a4a84d8aa | |||
| 1fb0b95428 | |||
| 89c4f7dffd | |||
| 4e76b61251 | |||
| 03cce6e8f6 | |||
| 956250004e | |||
| 536be45bbf | |||
| e5240575bd | |||
| 84c7f5046e | |||
| d2d6b6654a | |||
| 53e23f09dc | |||
| 9e781173fc | |||
| fead30db38 | |||
| d8811d6b46 | |||
| dd40dd964c | |||
| bc51a98cfd | |||
| 1dc30214cc | |||
| a84159a1ba | |||
| 7bfe736e5e | |||
| 1ea06930f4 | |||
| 512f3237f0 | |||
| f594006b95 | |||
| fc58c4f546 | |||
| 645e28eefe | |||
| 71fdd1df85 | |||
| aa99657dea | |||
| dfd240bd25 | |||
| ff68f18a26 | |||
| b0b0f0056e | |||
| f044c4dde1 | |||
| 205a83dd3c | |||
| 350bd75310 | |||
| b92eb9dcdd | |||
| c0c1e2bc06 | |||
| 75e375ff54 | |||
| 1a29a3237d | |||
| 971f92301f | |||
| e7137e9cce | |||
| 7001e791f7 | |||
| e327a971c2 | |||
| c8813c8584 | |||
| 0bbef8cf94 | |||
| 8f69efe331 | |||
| 24e2547656 | |||
| 53ef2e356a | |||
| 11b97c5291 | |||
| ece73578c8 | |||
| 8d8bb4e237 | |||
| 6772b1de35 | |||
| ea13989b7e | |||
| 78bc38fe1b | |||
| edb0a934a1 | |||
| f726dd59bf | |||
| 9589500412 | |||
| 1c3b870ad2 | |||
| f266c78915 | |||
| 6a5002495c | |||
| b3938cd7b2 | |||
| 8664d3cd35 | |||
| 2363cdd17b | |||
| 1e73bb12ac | |||
| 662bf16a4f | |||
| 26d450ad9a | |||
| bab4c7715d | |||
| d7aba9ce4a | |||
| ece61a45d8 | |||
| 8bb3685e5d | |||
| 6560f38cb0 | |||
| f316b3f694 | |||
| 311401d119 | |||
| 93c400a005 | |||
| 92010adce6 | |||
| b1800305b8 | |||
| 14a0e3cca7 | |||
| ebbbf11903 | |||
| 2d9aeb3aa1 | |||
| cbb36a900a | |||
| 27f121f25c | |||
| b199f4072c | |||
| 53928c02f8 | |||
| 756d554b47 | |||
| fb4de621c0 |
+1
-1
@@ -3,7 +3,7 @@ root=true
|
||||
[*]
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
indent_size = 4
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{cs,cshtml,csx,vb,vbx,vbhtml,fs,fsx,txt,ps1,sql}]
|
||||
|
||||
@@ -143,5 +143,6 @@ build/csharp-docs.zip
|
||||
build/msbuild.log
|
||||
.vs/
|
||||
src/packages/
|
||||
src/PrecompiledWeb/*
|
||||
build/tools/
|
||||
src/PrecompiledWeb/*
|
||||
|
||||
@@ -125,22 +125,12 @@ IF NOT EXIST "%nuGetExecutable%" (
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', '%nuGetExecutable%')"
|
||||
)
|
||||
|
||||
:: We need 7za.exe for BuildBelle.bat
|
||||
IF NOT EXIST "%toolsFolder%7za.exe" (
|
||||
ECHO 7zip not found - fetching now
|
||||
"%nuGetExecutable%" install 7-Zip.CommandLine -OutputDirectory tools -Verbosity quiet
|
||||
)
|
||||
|
||||
:: We need vswhere.exe for VS2017+
|
||||
IF NOT EXIST "%toolsFolder%vswhere.exe" (
|
||||
ECHO vswhere not found - fetching now
|
||||
"%nuGetExecutable%" install vswhere -OutputDirectory tools -Verbosity quiet
|
||||
)
|
||||
|
||||
:: Put 7za.exe and vswhere.exe in a predictable path (not version specific)
|
||||
FOR /f "delims=" %%A in ('dir "%toolsFolder%7-Zip.CommandLine.*" /b') DO SET "sevenZipExePath=%toolsFolder%%%A\"
|
||||
MOVE "%sevenZipExePath%tools\7za.exe" "%toolsFolder%7za.exe"
|
||||
|
||||
FOR /f "delims=" %%A in ('dir "%toolsFolder%vswhere.*" /b') DO SET "vswhereExePath=%toolsFolder%%%A\"
|
||||
MOVE "%vswhereExePath%tools\vswhere.exe" "%toolsFolder%vswhere.exe"
|
||||
|
||||
|
||||
+16
-7
@@ -8,6 +8,22 @@ ECHO Current folder: %CD%
|
||||
SET nodeFileName=node-v6.9.1-win-x86.7z
|
||||
SET nodeExtractFolder=%toolsFolder%node.js.691
|
||||
|
||||
SET nuGetExecutable=%CD%\tools\nuget.exe
|
||||
IF NOT EXIST "%nuGetExecutable%" (
|
||||
ECHO Downloading https://dist.nuget.org/win-x86-commandline/latest/nuget.exe to %nuGetExecutable%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', '%nuGetExecutable%')"
|
||||
)
|
||||
|
||||
:: We need 7za.exe for BuildBelle.bat
|
||||
IF NOT EXIST "%toolsFolder%7za.exe" (
|
||||
ECHO 7zip not found - fetching now
|
||||
"%nuGetExecutable%" install 7-Zip.CommandLine -OutputDirectory tools -Verbosity quiet
|
||||
)
|
||||
|
||||
:: Put 7za.exe and vswhere.exe in a predictable path (not version specific)
|
||||
FOR /f "delims=" %%A in ('dir "%toolsFolder%7-Zip.CommandLine.*" /b') DO SET "sevenZipExePath=%toolsFolder%%%A\"
|
||||
MOVE "%sevenZipExePath%tools\7za.exe" "%toolsFolder%7za.exe"
|
||||
|
||||
IF NOT EXIST "%nodeExtractFolder%" (
|
||||
ECHO Downloading http://nodejs.org/dist/v6.9.1/%nodeFileName% to %toolsFolder%%nodeFileName%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('http://nodejs.org/dist/v6.9.1/%nodeFileName%', '%toolsFolder%%nodeFileName%')"
|
||||
@@ -16,13 +32,6 @@ IF NOT EXIST "%nodeExtractFolder%" (
|
||||
)
|
||||
FOR /f "delims=" %%A in ('dir "%nodeExtractFolder%\node*" /b') DO SET "nodePath=%nodeExtractFolder%\%%A"
|
||||
|
||||
|
||||
SET nuGetExecutable=%CD%\tools\nuget.exe
|
||||
IF NOT EXIST "%nuGetExecutable%" (
|
||||
ECHO Downloading https://dist.nuget.org/win-x86-commandline/latest/nuget.exe to %nuGetExecutable%
|
||||
powershell -Command "(New-Object Net.WebClient).DownloadFile('https://dist.nuget.org/win-x86-commandline/latest/nuget.exe', '%nuGetExecutable%')"
|
||||
)
|
||||
|
||||
SET drive=%CD:~0,2%
|
||||
SET nuGetFolder=%drive%\packages\
|
||||
FOR /f "delims=" %%A in ('dir "%nuGetFolder%npm.*" /b') DO SET "npmPath=%nuGetFolder%%%A\"
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.Cookies" version="[3.1.0, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Security.OAuth" version="[3.1.0, 4.0.0)" />
|
||||
<dependency id="Microsoft.Owin.Host.SystemWeb" version="[3.1.0, 4.0.0)" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.9.5, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
@@ -34,13 +34,13 @@
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.82, 1.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.83, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.5.3, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.8.3, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 3.0.0)" />
|
||||
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
|
||||
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
|
||||
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
<section name="BaseRestExtensions" type="Umbraco.Core.Configuration.BaseRest.BaseRestSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
<section name="FileSystemProviders" type="Umbraco.Core.Configuration.FileSystemProvidersSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
<section name="dashBoard" type="Umbraco.Core.Configuration.Dashboard.DashboardSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
<section name="HealthChecks" type="Umbraco.Core.Configuration.HealthChecks.HealthChecksSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
|
||||
@@ -30,6 +31,7 @@
|
||||
<BaseRestExtensions configSource="config\BaseRestExtensions.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
<FileSystemProviders configSource="config\FileSystemProviders.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
<dashBoard configSource="config\Dashboard.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
<HealthChecks configSource="config\HealthChecks.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
</umbracoConfiguration>
|
||||
|
||||
<FileSystemProviders xdt:Transform="Remove" />
|
||||
@@ -368,19 +370,19 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
|
||||
@@ -102,15 +102,16 @@
|
||||
xdt:Transform="Remove" />
|
||||
|
||||
<!--Users-->
|
||||
<add application="users" alias="users" title="Users" type="umbraco.loadUsers, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="0"
|
||||
<add initialize="true" sortOrder="0" alias="users" application="users" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.UserTreeController, umbraco"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
|
||||
<add application="users" alias="userTypes"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="users" alias="userTypes" title="User Types" type="umbraco.cms.presentation.Trees.UserTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="1"
|
||||
xdt:Transform="Remove" />
|
||||
<add application="users" alias="userPermissions"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
<add application="users" alias="userPermissions" title="User Permissions" type="umbraco.cms.presentation.Trees.UserPermissions, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2"
|
||||
xdt:Locator="Match(application,alias)"
|
||||
xdt:Transform="SetAttributes()" />
|
||||
xdt:Transform="Remove" />
|
||||
|
||||
<!--Members-->
|
||||
<add initialize="true" sortOrder="0" alias="member" application="member" title="Members" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MemberTreeController, umbraco"
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.2
|
||||
7.7.0
|
||||
beta
|
||||
@@ -16,19 +16,19 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.OAuth" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.1.0.0" newVersion="3.1.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
|
||||
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.2")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.2")]
|
||||
[assembly: AssemblyFileVersion("7.7.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.7.0-beta")]
|
||||
@@ -23,12 +23,12 @@ namespace Umbraco.Core
|
||||
: base(serviceProvider, logger, packageActions)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IPackageAction"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<IAction> Actions
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="IAction"/> implementations.
|
||||
/// </summary>
|
||||
public IEnumerable<IAction> Actions
|
||||
{
|
||||
get
|
||||
{
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace Umbraco.Core
|
||||
/// <param name="cache"></param>
|
||||
[Obsolete("Use the other constructor specifying a ProfilingLogger instead")]
|
||||
public ApplicationContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache)
|
||||
: this(dbContext, serviceContext, cache,
|
||||
: this(dbContext, serviceContext, cache,
|
||||
new ProfilingLogger(LoggerResolver.Current.Logger, ProfilerResolver.Current.Profiler))
|
||||
{
|
||||
}
|
||||
@@ -89,7 +89,7 @@ namespace Umbraco.Core
|
||||
/// <param name="replaceContext">If set to true and the singleton is already set, it will be replaced</param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(ApplicationContext appContext, bool replaceContext)
|
||||
{
|
||||
@@ -107,14 +107,14 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="replaceContext">
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// startup if for some reason the boot manager is not the umbraco boot manager.
|
||||
/// </param>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
[Obsolete("Use the other method specifying an ProfilingLogger instead")]
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, bool replaceContext)
|
||||
@@ -135,14 +135,14 @@ namespace Umbraco.Core
|
||||
/// <param name="cache"></param>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="replaceContext">
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// If set to true will replace the current singleton instance - This should only be used for unit tests or on app
|
||||
/// startup if for some reason the boot manager is not the umbraco boot manager.
|
||||
/// </param>
|
||||
/// <param name="dbContext"></param>
|
||||
/// <param name="serviceContext"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This is NOT thread safe
|
||||
/// This is NOT thread safe
|
||||
/// </remarks>
|
||||
public static ApplicationContext EnsureContext(DatabaseContext dbContext, ServiceContext serviceContext, CacheHelper cache, ProfilingLogger logger, bool replaceContext)
|
||||
{
|
||||
@@ -175,7 +175,7 @@ namespace Umbraco.Core
|
||||
public CacheHelper ApplicationCache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the global ProfilingLogger - this should generally not be accessed via the UmbracoContext and should normally just be exposed
|
||||
/// Exposes the global ProfilingLogger - this should generally not be accessed via the UmbracoContext and should normally just be exposed
|
||||
/// on most base classes or injected with IoC
|
||||
/// </summary>
|
||||
public ProfilingLogger ProfilingLogger { get; private set; }
|
||||
@@ -213,7 +213,7 @@ namespace Umbraco.Core
|
||||
// GlobalSettings.CurrentVersion returns the hard-coded "current version"
|
||||
// the system is configured if they match
|
||||
// if they don't, install runs, updates web.config (presumably) and updates GlobalSettings.ConfiguredStatus
|
||||
|
||||
|
||||
public bool IsConfigured
|
||||
{
|
||||
get { return _configured.Value; }
|
||||
@@ -226,8 +226,8 @@ namespace Umbraco.Core
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsConfigured == false
|
||||
&& DatabaseContext != null
|
||||
if (IsConfigured == false
|
||||
&& DatabaseContext != null
|
||||
&& DatabaseContext.IsDatabaseConfigured)
|
||||
{
|
||||
var schemaresult = DatabaseContext.ValidateDatabaseSchema();
|
||||
@@ -274,12 +274,12 @@ namespace Umbraco.Core
|
||||
|
||||
private Lazy<bool> _configured;
|
||||
internal MainDom MainDom { get; private set; }
|
||||
|
||||
|
||||
private void Init()
|
||||
{
|
||||
MainDom = new MainDom(ProfilingLogger.Logger);
|
||||
MainDom.Acquire();
|
||||
|
||||
|
||||
//Create the lazy value to resolve whether or not the application is 'configured'
|
||||
_configured = new Lazy<bool>(() =>
|
||||
{
|
||||
@@ -289,7 +289,7 @@ namespace Umbraco.Core
|
||||
var currentVersion = UmbracoVersion.GetSemanticVersion();
|
||||
|
||||
var ok =
|
||||
//we are not configured if this is null
|
||||
//we are not configured if this is null
|
||||
string.IsNullOrWhiteSpace(configStatus) == false
|
||||
//they must match
|
||||
&& configStatus == currentVersion;
|
||||
@@ -303,7 +303,7 @@ namespace Umbraco.Core
|
||||
var found = Services.MigrationEntryService.FindEntry(Constants.System.UmbracoMigrationName, UmbracoVersion.GetSemanticVersion());
|
||||
if (found == null)
|
||||
{
|
||||
//we haven't executed this migration in this environment, so even though the config versions match,
|
||||
//we haven't executed this migration in this environment, so even though the config versions match,
|
||||
// this db has not been updated.
|
||||
ProfilingLogger.Logger.Debug<ApplicationContext>(string.Format("The migration for version: '{0} has not been executed, there is no record in the database", currentVersion.ToSemanticString()));
|
||||
ok = false;
|
||||
@@ -323,7 +323,7 @@ namespace Umbraco.Core
|
||||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private string ConfigurationStatus
|
||||
@@ -338,7 +338,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AssertIsNotReady()
|
||||
@@ -363,7 +363,7 @@ namespace Umbraco.Core
|
||||
}
|
||||
internal set { _databaseContext = value; }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current ServiceContext
|
||||
/// </summary>
|
||||
@@ -417,7 +417,7 @@ namespace Umbraco.Core
|
||||
ResolverCollection.ResetAll();
|
||||
//reset resolution itself (though this should be taken care of by resetting any of the resolvers above)
|
||||
Resolution.Reset();
|
||||
|
||||
|
||||
//reset the instance objects
|
||||
this.ApplicationCache = null;
|
||||
if (_databaseContext != null) //need to check the internal field here
|
||||
@@ -430,14 +430,14 @@ namespace Umbraco.Core
|
||||
/*
|
||||
if (DatabaseContext.IsDatabaseConfigured && DatabaseContext.Database != null)
|
||||
{
|
||||
DatabaseContext.Database.Dispose();
|
||||
}
|
||||
*/
|
||||
DatabaseContext.Database.Dispose();
|
||||
}
|
||||
*/
|
||||
}
|
||||
this.DatabaseContext = null;
|
||||
this.Services = null;
|
||||
this._isReady = false; //set the internal field
|
||||
|
||||
|
||||
// Indicate that the instance has been disposed.
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
@@ -55,8 +55,10 @@ namespace Umbraco.Core.Cache
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public const string UserCacheKey = "UmbracoUser";
|
||||
|
||||
public const string UserPermissionsCacheKey = "UmbracoUserPermissions";
|
||||
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public const string UserGroupPermissionsCacheKey = "UmbracoUserGroupPermissions";
|
||||
|
||||
[UmbracoWillObsolete("This cache key is only used for legacy business logic caching, remove in v8")]
|
||||
public const string ContentTypeCacheKey = "UmbracoContentType";
|
||||
@@ -89,7 +91,7 @@ namespace Umbraco.Core.Cache
|
||||
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
|
||||
public const string DataTypePreValuesCacheKey = "UmbracoPreVal";
|
||||
|
||||
public const string IdToKeyCacheKey = "UI2K";
|
||||
public const string KeyToIdCacheKey = "UK2I";
|
||||
public const string IdToKeyCacheKey = "UI2K__";
|
||||
public const string KeyToIdCacheKey = "UK2I__";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.CodeAnnotations
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
|
||||
internal class ActionMetadataAttribute : Attribute
|
||||
{
|
||||
public string Category { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor used to assign a Category, since no name is assigned it will try to be translated from the language files based on the action's alias
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
public ActionMetadataAttribute(string category)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentException("Value cannot be null or whitespace.", "category");
|
||||
Category = category;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor used to assign an explicit name and category
|
||||
/// </summary>
|
||||
/// <param name="category"></param>
|
||||
/// <param name="name"></param>
|
||||
public ActionMetadataAttribute(string category, string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(category)) throw new ArgumentException("Value cannot be null or whitespace.", "category");
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
|
||||
Category = category;
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net.Configuration;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Hosting;
|
||||
@@ -42,7 +43,6 @@ namespace Umbraco.Core.Configuration
|
||||
//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,~/config/splashes/noNodes.aspx,~/VSEnterpriseHelper.axd,";
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
@@ -53,6 +53,7 @@ namespace Umbraco.Core.Configuration
|
||||
_reservedUrlsCache = null;
|
||||
_reservedPaths = null;
|
||||
_reservedUrls = null;
|
||||
HasSmtpServer = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -64,7 +65,26 @@ namespace Umbraco.Core.Configuration
|
||||
ResetInternal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
public static bool HasSmtpServerConfigured(string appPath)
|
||||
{
|
||||
if (HasSmtpServer.HasValue) return HasSmtpServer.Value;
|
||||
|
||||
var config = WebConfigurationManager.OpenWebConfiguration(appPath);
|
||||
var settings = (MailSettingsSectionGroup)config.GetSectionGroup("system.net/mailSettings");
|
||||
if (settings == null || settings.Smtp == null) return false;
|
||||
if (settings.Smtp.SpecifiedPickupDirectory != null && string.IsNullOrEmpty(settings.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation) == false)
|
||||
return true;
|
||||
if (settings.Smtp.Network != null && string.IsNullOrEmpty(settings.Smtp.Network.Host) == false)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// For testing only
|
||||
/// </summary>
|
||||
internal static bool? HasSmtpServer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the reserved urls from web.config.
|
||||
/// </summary>
|
||||
/// <value>The reserved urls.</value>
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public class DisabledHealthCheckElement : ConfigurationElement, IDisabledHealthCheck
|
||||
{
|
||||
private const string IdKey = "id";
|
||||
private const string DisabledOnKey = "disabledOn";
|
||||
private const string DisabledByKey = "disabledBy";
|
||||
|
||||
[ConfigurationProperty(IdKey, IsKey = true, IsRequired = true)]
|
||||
public Guid Id
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((Guid)(base[IdKey]));
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(DisabledOnKey, IsKey = false, IsRequired = false)]
|
||||
public DateTime DisabledOn
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((DateTime)(base[DisabledOnKey]));
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(DisabledByKey, IsKey = false, IsRequired = false)]
|
||||
public int DisabledBy
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((int)(base[DisabledByKey]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
[ConfigurationCollection(typeof(DisabledHealthCheckElement), AddItemName = "check")]
|
||||
public class DisabledHealthChecksElementCollection : ConfigurationElementCollection, IEnumerable<IDisabledHealthCheck>
|
||||
{
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new DisabledHealthCheckElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((DisabledHealthCheckElement)(element)).Id;
|
||||
}
|
||||
|
||||
public new DisabledHealthCheckElement this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DisabledHealthCheckElement)BaseGet(key);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator<IDisabledHealthCheck> IEnumerable<IDisabledHealthCheck>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return BaseGet(i) as DisabledHealthCheckElement;
|
||||
}
|
||||
}
|
||||
|
||||
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public class HealthCheckNotificationSettingsElement : ConfigurationElement, IHealthCheckNotificationSettings
|
||||
{
|
||||
private const string EnabledKey = "enabled";
|
||||
private const string FirstRunTimeKey = "firstRunTime";
|
||||
private const string PeriodKey = "periodInHours";
|
||||
private const string NotificationMethodsKey = "notificationMethods";
|
||||
private const string DisabledChecksKey = "disabledChecks";
|
||||
|
||||
[ConfigurationProperty(EnabledKey, IsRequired = true)]
|
||||
public bool Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)base[EnabledKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(FirstRunTimeKey, IsRequired = false)]
|
||||
public string FirstRunTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base[FirstRunTimeKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(PeriodKey, IsRequired = true)]
|
||||
public int PeriodInHours
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)base[PeriodKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(NotificationMethodsKey, IsDefaultCollection = true, IsRequired = false)]
|
||||
public NotificationMethodsElementCollection NotificationMethods
|
||||
{
|
||||
get
|
||||
{
|
||||
return (NotificationMethodsElementCollection)base[NotificationMethodsKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(DisabledChecksKey, IsDefaultCollection = false, IsRequired = false)]
|
||||
public DisabledHealthChecksElementCollection DisabledChecks
|
||||
{
|
||||
get
|
||||
{
|
||||
return (DisabledHealthChecksElementCollection)base[DisabledChecksKey];
|
||||
}
|
||||
}
|
||||
|
||||
bool IHealthCheckNotificationSettings.Enabled
|
||||
{
|
||||
get { return Enabled; }
|
||||
}
|
||||
|
||||
string IHealthCheckNotificationSettings.FirstRunTime
|
||||
{
|
||||
get { return FirstRunTime; }
|
||||
}
|
||||
|
||||
int IHealthCheckNotificationSettings.PeriodInHours
|
||||
{
|
||||
get { return PeriodInHours; }
|
||||
}
|
||||
|
||||
IReadOnlyDictionary<string, INotificationMethod> IHealthCheckNotificationSettings.NotificationMethods
|
||||
{
|
||||
get { return NotificationMethods; }
|
||||
}
|
||||
|
||||
IEnumerable<IDisabledHealthCheck> IHealthCheckNotificationSettings.DisabledChecks
|
||||
{
|
||||
get { return DisabledChecks; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public enum HealthCheckNotificationVerbosity
|
||||
{
|
||||
Summary,
|
||||
Detailed
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public class HealthChecksSection : ConfigurationSection, IHealthChecks
|
||||
{
|
||||
private const string DisabledChecksKey = "disabledChecks";
|
||||
private const string NotificationSettingsKey = "notificationSettings";
|
||||
|
||||
[ConfigurationProperty(DisabledChecksKey)]
|
||||
public DisabledHealthChecksElementCollection DisabledChecks
|
||||
{
|
||||
get { return ((DisabledHealthChecksElementCollection)(base[DisabledChecksKey])); }
|
||||
}
|
||||
|
||||
[ConfigurationProperty(NotificationSettingsKey, IsRequired = true)]
|
||||
public HealthCheckNotificationSettingsElement NotificationSettings
|
||||
{
|
||||
get { return ((HealthCheckNotificationSettingsElement)(base[NotificationSettingsKey])); }
|
||||
}
|
||||
|
||||
IEnumerable<IDisabledHealthCheck> IHealthChecks.DisabledChecks
|
||||
{
|
||||
get { return DisabledChecks; }
|
||||
}
|
||||
|
||||
IHealthCheckNotificationSettings IHealthChecks.NotificationSettings
|
||||
{
|
||||
get { return NotificationSettings; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public interface IDisabledHealthCheck
|
||||
{
|
||||
Guid Id { get; }
|
||||
DateTime DisabledOn { get; }
|
||||
int DisabledBy { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public interface IHealthCheckNotificationSettings
|
||||
{
|
||||
bool Enabled { get; }
|
||||
string FirstRunTime { get; }
|
||||
int PeriodInHours { get; }
|
||||
IReadOnlyDictionary<string, INotificationMethod> NotificationMethods { get; }
|
||||
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public interface IHealthChecks
|
||||
{
|
||||
IEnumerable<IDisabledHealthCheck> DisabledChecks { get; }
|
||||
IHealthCheckNotificationSettings NotificationSettings { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public interface INotificationMethod
|
||||
{
|
||||
string Alias { get; }
|
||||
bool Enabled { get; }
|
||||
HealthCheckNotificationVerbosity Verbosity { get; }
|
||||
bool FailureOnly { get; }
|
||||
IReadOnlyDictionary<string, INotificationMethodSettings> Settings { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public interface INotificationMethodSettings
|
||||
{
|
||||
string Key { get; }
|
||||
string Value { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public class NotificationMethodElement : ConfigurationElement, INotificationMethod
|
||||
{
|
||||
private const string AliasKey = "alias";
|
||||
private const string EnabledKey = "enabled";
|
||||
private const string VerbosityKey = "verbosity";
|
||||
private const string FailureonlyKey = "failureOnly";
|
||||
private const string SettingsKey = "settings";
|
||||
|
||||
[ConfigurationProperty(AliasKey, IsKey = true, IsRequired = true)]
|
||||
public string Alias
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base[AliasKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(EnabledKey, IsKey = true, IsRequired = true)]
|
||||
public bool Enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)base[EnabledKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(VerbosityKey, IsRequired = true)]
|
||||
public HealthCheckNotificationVerbosity Verbosity
|
||||
{
|
||||
get
|
||||
{
|
||||
return (HealthCheckNotificationVerbosity)base[VerbosityKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(FailureonlyKey, IsRequired = false)]
|
||||
public bool FailureOnly
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)base[FailureonlyKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(SettingsKey, IsDefaultCollection = true, IsRequired = false)]
|
||||
public NotificationMethodSettingsElementCollection Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
return (NotificationMethodSettingsElementCollection)base[SettingsKey];
|
||||
}
|
||||
}
|
||||
|
||||
string INotificationMethod.Alias
|
||||
{
|
||||
get { return Alias; }
|
||||
}
|
||||
|
||||
bool INotificationMethod.Enabled
|
||||
{
|
||||
get { return Enabled; }
|
||||
}
|
||||
|
||||
HealthCheckNotificationVerbosity INotificationMethod.Verbosity
|
||||
{
|
||||
get { return Verbosity; }
|
||||
}
|
||||
|
||||
bool INotificationMethod.FailureOnly
|
||||
{
|
||||
get { return FailureOnly; }
|
||||
}
|
||||
|
||||
IReadOnlyDictionary<string, INotificationMethodSettings> INotificationMethod.Settings
|
||||
{
|
||||
get { return Settings; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
public class NotificationMethodSettingsElement : ConfigurationElement, INotificationMethodSettings
|
||||
{
|
||||
private const string KeyKey = "key";
|
||||
private const string ValueKey = "value";
|
||||
|
||||
[ConfigurationProperty(KeyKey, IsKey = true, IsRequired = true)]
|
||||
public string Key
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base[KeyKey];
|
||||
}
|
||||
}
|
||||
|
||||
[ConfigurationProperty(ValueKey, IsRequired = true)]
|
||||
public string Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string)base[ValueKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
[ConfigurationCollection(typeof(NotificationMethodSettingsElement), AddItemName = "add")]
|
||||
public class NotificationMethodSettingsElementCollection : ConfigurationElementCollection, IEnumerable<INotificationMethodSettings>, IReadOnlyDictionary<string, INotificationMethodSettings>
|
||||
{
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new NotificationMethodSettingsElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((NotificationMethodSettingsElement)(element)).Key;
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<string, INotificationMethodSettings>> IEnumerable<KeyValuePair<string, INotificationMethodSettings>>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
var val = (NotificationMethodSettingsElement)BaseGet(i);
|
||||
var key = (string)BaseGetKey(i);
|
||||
yield return new KeyValuePair<string, INotificationMethodSettings>(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator<INotificationMethodSettings> IEnumerable<INotificationMethodSettings>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return (NotificationMethodSettingsElement)BaseGet(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool IReadOnlyDictionary<string, INotificationMethodSettings>.ContainsKey(string key)
|
||||
{
|
||||
return ((IReadOnlyDictionary<string, INotificationMethodSettings>)this).Keys.Any(x => x == key);
|
||||
}
|
||||
|
||||
bool IReadOnlyDictionary<string, INotificationMethodSettings>.TryGetValue(string key, out INotificationMethodSettings value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var val = (NotificationMethodSettingsElement)BaseGet(key);
|
||||
value = val;
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
INotificationMethodSettings IReadOnlyDictionary<string, INotificationMethodSettings>.this[string key]
|
||||
{
|
||||
get { return (NotificationMethodSettingsElement)BaseGet(key); }
|
||||
}
|
||||
|
||||
IEnumerable<string> IReadOnlyDictionary<string, INotificationMethodSettings>.Keys
|
||||
{
|
||||
get { return BaseGetAllKeys().Cast<string>(); }
|
||||
}
|
||||
|
||||
IEnumerable<INotificationMethodSettings> IReadOnlyDictionary<string, INotificationMethodSettings>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return (NotificationMethodSettingsElement)BaseGet(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Configuration.HealthChecks
|
||||
{
|
||||
[ConfigurationCollection(typeof(NotificationMethodElement), AddItemName = "notificationMethod")]
|
||||
public class NotificationMethodsElementCollection : ConfigurationElementCollection, IEnumerable<INotificationMethod>, IReadOnlyDictionary<string, INotificationMethod>
|
||||
{
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
{
|
||||
return new NotificationMethodElement();
|
||||
}
|
||||
|
||||
protected override object GetElementKey(ConfigurationElement element)
|
||||
{
|
||||
return ((NotificationMethodElement)(element)).Alias;
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<string, INotificationMethod>> IEnumerable<KeyValuePair<string, INotificationMethod>>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
var val = (NotificationMethodElement)BaseGet(i);
|
||||
var key = (string)BaseGetKey(i);
|
||||
yield return new KeyValuePair<string, INotificationMethod>(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerator<INotificationMethod> IEnumerable<INotificationMethod>.GetEnumerator()
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return (NotificationMethodElement)BaseGet(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool IReadOnlyDictionary<string, INotificationMethod>.ContainsKey(string key)
|
||||
{
|
||||
return ((IReadOnlyDictionary<string, INotificationMethod>) this).Keys.Any(x => x == key);
|
||||
}
|
||||
|
||||
bool IReadOnlyDictionary<string, INotificationMethod>.TryGetValue(string key, out INotificationMethod value)
|
||||
{
|
||||
try
|
||||
{
|
||||
var val = (NotificationMethodElement)BaseGet(key);
|
||||
value = val;
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
INotificationMethod IReadOnlyDictionary<string, INotificationMethod>.this[string key]
|
||||
{
|
||||
get { return (NotificationMethodElement)BaseGet(key); }
|
||||
}
|
||||
|
||||
IEnumerable<string> IReadOnlyDictionary<string, INotificationMethod>.Keys
|
||||
{
|
||||
get { return BaseGetAllKeys().Cast<string>(); }
|
||||
}
|
||||
|
||||
IEnumerable<INotificationMethod> IReadOnlyDictionary<string, INotificationMethod>.Values
|
||||
{
|
||||
get
|
||||
{
|
||||
for (var i = 0; i < Count; i++)
|
||||
{
|
||||
yield return (NotificationMethodElement)BaseGet(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration.BaseRest;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.Configuration.HealthChecks;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
@@ -52,6 +53,12 @@ namespace Umbraco.Core.Configuration
|
||||
var dashboardConfig = ConfigurationManager.GetSection("umbracoConfiguration/dashBoard") as IDashboardSection;
|
||||
SetDashboardSettings(dashboardConfig);
|
||||
}
|
||||
|
||||
if (_healthChecks == null)
|
||||
{
|
||||
var healthCheckConfig = ConfigurationManager.GetSection("umbracoConfiguration/HealthChecks") as IHealthChecks;
|
||||
SetHealthCheckSettings(healthCheckConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -60,18 +67,36 @@ namespace Umbraco.Core.Configuration
|
||||
/// <param name="umbracoSettings"></param>
|
||||
/// <param name="baseRestSettings"></param>
|
||||
/// <param name="dashboardSettings"></param>
|
||||
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings)
|
||||
/// <param name="healthChecks"></param>
|
||||
public UmbracoConfig(IUmbracoSettingsSection umbracoSettings, IBaseRestSection baseRestSettings, IDashboardSection dashboardSettings, IHealthChecks healthChecks)
|
||||
{
|
||||
SetHealthCheckSettings(healthChecks);
|
||||
SetUmbracoSettings(umbracoSettings);
|
||||
SetBaseRestExtensions(baseRestSettings);
|
||||
SetDashboardSettings(dashboardSettings);
|
||||
}
|
||||
|
||||
private IHealthChecks _healthChecks;
|
||||
private IDashboardSection _dashboardSection;
|
||||
private IUmbracoSettingsSection _umbracoSettings;
|
||||
private IBaseRestSection _baseRestExtensions;
|
||||
private IGridConfig _gridConfig;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IHealthCheck config
|
||||
/// </summary>
|
||||
public IHealthChecks HealthCheck()
|
||||
{
|
||||
if (_healthChecks == null)
|
||||
{
|
||||
var ex = new ConfigurationErrorsException("Could not load the " + typeof(IHealthChecks) + " from config file, ensure the web.config and healthchecks.config files are formatted correctly");
|
||||
LogHelper.Error<UmbracoConfig>("Config error", ex);
|
||||
throw ex;
|
||||
}
|
||||
|
||||
return _healthChecks;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IDashboardSection
|
||||
/// </summary>
|
||||
@@ -86,14 +111,23 @@ namespace Umbraco.Core.Configuration
|
||||
|
||||
return _dashboardSection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetDashboardSettings(IDashboardSection value)
|
||||
{
|
||||
_dashboardSection = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Only for testing
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
internal void SetDashboardSettings(IDashboardSection value)
|
||||
public void SetHealthCheckSettings(IHealthChecks value)
|
||||
{
|
||||
_dashboardSection = value;
|
||||
_healthChecks = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
internal class HelpElement : ConfigurationElement, IHelpSection
|
||||
{
|
||||
[ConfigurationProperty("defaultUrl", DefaultValue = "http://our.umbraco.org/wiki/umbraco-help/{0}/{1}")]
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
public interface IHelpSection : IUmbracoConfigurationSection
|
||||
{
|
||||
string DefaultUrl { get; }
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
public interface ILink
|
||||
{
|
||||
string Application { get; }
|
||||
|
||||
@@ -12,6 +12,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
bool ConvertUrlsToAscii { get; }
|
||||
|
||||
bool TryConvertUrlsToAscii { get; }
|
||||
|
||||
IEnumerable<IChar> CharCollection { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
public interface IUmbracoSettingsSection : IUmbracoConfigurationSection
|
||||
{
|
||||
@@ -24,6 +27,8 @@
|
||||
|
||||
IProvidersSection Providers { get; }
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
IHelpSection Help { get; }
|
||||
|
||||
IWebRoutingSection WebRouting { get; }
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Configuration;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
internal class LinkElement : ConfigurationElement, ILink
|
||||
{
|
||||
[ConfigurationProperty("application")]
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration;
|
||||
|
||||
namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
internal class LinksCollection : ConfigurationElementCollection, IEnumerable<ILink>
|
||||
{
|
||||
protected override ConfigurationElement CreateNewElement()
|
||||
|
||||
@@ -111,7 +111,12 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
|
||||
bool IRequestHandlerSection.ConvertUrlsToAscii
|
||||
{
|
||||
get { return UrlReplacing.ConvertUrlsToAscii; }
|
||||
get { return UrlReplacing.ConvertUrlsToAscii.InvariantEquals("true"); }
|
||||
}
|
||||
|
||||
bool IRequestHandlerSection.TryConvertUrlsToAscii
|
||||
{
|
||||
get { return UrlReplacing.ConvertUrlsToAscii.InvariantEquals("try"); }
|
||||
}
|
||||
|
||||
IEnumerable<IChar> IRequestHandlerSection.CharCollection
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
|
||||
@@ -183,6 +184,8 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return Providers; }
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This is no longer used and will be removed in future versions")]
|
||||
IHelpSection IUmbracoSettingsSection.Help
|
||||
{
|
||||
get { return Help; }
|
||||
|
||||
@@ -11,10 +11,10 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
get { return (bool) base["removeDoubleDashes"]; }
|
||||
}
|
||||
|
||||
[ConfigurationProperty("toAscii", DefaultValue = false)]
|
||||
internal bool ConvertUrlsToAscii
|
||||
[ConfigurationProperty("toAscii", DefaultValue = "false")]
|
||||
internal string ConvertUrlsToAscii
|
||||
{
|
||||
get { return (bool)base["toAscii"]; }
|
||||
get { return (string) base["toAscii"]; }
|
||||
}
|
||||
|
||||
[ConfigurationCollection(typeof(CharCollection), AddItemName = "char")]
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.6.2");
|
||||
private static readonly Version Version = new Version("7.7.0");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
@@ -24,7 +24,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 ""; } }
|
||||
public static string CurrentComment { get { return "beta"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
@@ -33,9 +33,9 @@ namespace Umbraco.Core.Configuration
|
||||
public static SemVersion GetSemanticVersion()
|
||||
{
|
||||
return new SemVersion(
|
||||
Current.Major,
|
||||
Current.Major,
|
||||
Current.Minor,
|
||||
Current.Build,
|
||||
Current.Build,
|
||||
CurrentComment.IsNullOrWhiteSpace() ? null : CurrentComment,
|
||||
Current.Revision > 0 ? Current.Revision.ToInvariantString() : null);
|
||||
}
|
||||
|
||||
@@ -56,7 +56,12 @@
|
||||
/// <summary>
|
||||
/// alias for the content tree.
|
||||
/// </summary>
|
||||
public const string Content = "content";
|
||||
public const string Content = "content";
|
||||
|
||||
/// <summary>
|
||||
/// alias for the content blueprint tree.
|
||||
/// </summary>
|
||||
public const string ContentBlueprints = "contentBlueprints";
|
||||
|
||||
/// <summary>
|
||||
/// alias for the member tree.
|
||||
@@ -118,6 +123,8 @@
|
||||
|
||||
public const string Scripts = "scripts";
|
||||
|
||||
public const string Users = "users";
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,14 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class Conventions
|
||||
{
|
||||
internal static class PermissionCategories
|
||||
{
|
||||
public const string ContentCategory = "content";
|
||||
public const string AdministrationCategory = "administration";
|
||||
public const string StructureCategory = "structure";
|
||||
public const string OtherCategory = "other";
|
||||
}
|
||||
|
||||
public static class PublicAccess
|
||||
{
|
||||
public const string MemberUsernameRuleType = "MemberUsername";
|
||||
|
||||
@@ -68,12 +68,22 @@ namespace Umbraco.Core
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public const string Document = "C66BA18E-EAF3-4CFF-8A22-41B16D66A972";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public static readonly Guid DocumentGuid = new Guid(Document);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document Blueprint object.
|
||||
/// </summary>
|
||||
public const string DocumentBlueprint = "6EBEF410-03AA-48CF-A792-E1C1CB087ACA";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document object.
|
||||
/// </summary>
|
||||
public static readonly Guid DocumentBlueprintGuid = new Guid(DocumentBlueprint);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Document Type object.
|
||||
/// </summary>
|
||||
@@ -212,6 +222,16 @@ namespace Umbraco.Core
|
||||
/// Guid for a Forms DataSource.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsDataSourceGuid = new Guid(FormsDataSource);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Language.
|
||||
/// </summary>
|
||||
public const string Language = "6B05D05B-EC78-49BE-A4E4-79E274F07A77";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms DataSource.
|
||||
/// </summary>
|
||||
public static readonly Guid LanguageGuid = new Guid(Language);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -437,6 +437,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string EmailAddressAlias = "Umbraco.EmailAddress";
|
||||
|
||||
/// <summary>
|
||||
/// Alias for the nested content property editor.
|
||||
/// </summary>
|
||||
public const string NestedContentAlias = "Umbraco.NestedContent";
|
||||
|
||||
public static class PreValueKeys
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -8,12 +8,17 @@ namespace Umbraco.Core
|
||||
public static class Security
|
||||
{
|
||||
|
||||
public const string AdminGroupAlias = "admin";
|
||||
|
||||
public const string BackOfficeAuthenticationType = "UmbracoBackOffice";
|
||||
public const string BackOfficeExternalAuthenticationType = "UmbracoExternalCookie";
|
||||
public const string BackOfficeExternalCookieName = "UMB_EXTLOGIN";
|
||||
public const string BackOfficeTokenAuthenticationType = "UmbracoBackOfficeToken";
|
||||
public const string BackOfficeTwoFactorAuthenticationType = "UmbracoTwoFactorCookie";
|
||||
|
||||
internal const string EmptyPasswordPrefix = "___UIDEMPTYPWORD__";
|
||||
internal const string ForceReAuthFlag = "umbraco-force-auth";
|
||||
|
||||
/// <summary>
|
||||
/// The prefix used for external identity providers for their authentication type
|
||||
/// </summary>
|
||||
|
||||
@@ -41,7 +41,43 @@ namespace Umbraco.Core
|
||||
Hour,
|
||||
Minute,
|
||||
Second
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
|
||||
/// date time is before the time, calculate onto next day)
|
||||
/// </summary>
|
||||
/// <param name="fromDateTime">Date to start from</param>
|
||||
/// <param name="scheduledTime">Time to compare against (in Hmm form, e.g. 330, 2200)</param>
|
||||
/// <returns></returns>
|
||||
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
|
||||
{
|
||||
// Ensure time provided is 4 digits long
|
||||
if (scheduledTime.Length == 3)
|
||||
{
|
||||
scheduledTime = "0" + scheduledTime;
|
||||
}
|
||||
|
||||
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
|
||||
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
|
||||
|
||||
DateTime scheduledDateTime;
|
||||
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
|
||||
{
|
||||
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var nextDay = fromDateTime.AddDays(1);
|
||||
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
|
||||
}
|
||||
|
||||
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
|
||||
}
|
||||
|
||||
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
|
||||
{
|
||||
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,9 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static bool ContainsAll<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> other)
|
||||
{
|
||||
if (source == null) throw new ArgumentNullException("source");
|
||||
if (other == null) throw new ArgumentNullException("other");
|
||||
|
||||
return other.Except(source).Any() == false;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Packaging.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
internal class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
|
||||
public class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
|
||||
{
|
||||
private readonly MetaData _packageMetaData;
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Events
|
||||
public bool Equals(ImportPackageEventArgs<TEntity> other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
//TODO: MetaData for package metadata has no equality operators :/
|
||||
return base.Equals(other) && _packageMetaData.Equals(other._packageMetaData);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Packaging.Models;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
internal class UninstallPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
public class UninstallPackageEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
private readonly MetaData _packageMetaData;
|
||||
|
||||
|
||||
@@ -217,8 +217,21 @@ namespace Umbraco.Core
|
||||
public static MemberInfo GetMemberInfo<T, TReturn>(Expression<Func<T, TReturn>> fromExpression)
|
||||
{
|
||||
if (fromExpression == null) return null;
|
||||
var body = fromExpression.Body as MemberExpression;
|
||||
return body != null ? body.Member : null;
|
||||
|
||||
MemberExpression me;
|
||||
switch (fromExpression.Body.NodeType)
|
||||
{
|
||||
case ExpressionType.Convert:
|
||||
case ExpressionType.ConvertChecked:
|
||||
var ue = fromExpression.Body as UnaryExpression;
|
||||
me = ((ue != null) ? ue.Operand : null) as MemberExpression;
|
||||
break;
|
||||
default:
|
||||
me = fromExpression.Body as MemberExpression;
|
||||
break;
|
||||
}
|
||||
|
||||
return me != null ? me.Member : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
private ShadowWrapper _macroPartialFileSystem;
|
||||
private ShadowWrapper _partialViewsFileSystem;
|
||||
private ShadowWrapper _macroScriptsFileSystem;
|
||||
private ShadowWrapper _userControlsFileSystem;
|
||||
private ShadowWrapper _stylesheetsFileSystem;
|
||||
private ShadowWrapper _scriptsFileSystem;
|
||||
private ShadowWrapper _xsltFileSystem;
|
||||
@@ -61,6 +63,8 @@ namespace Umbraco.Core.IO
|
||||
{
|
||||
var macroPartialFileSystem = new PhysicalFileSystem(SystemDirectories.MacroPartials);
|
||||
var partialViewsFileSystem = new PhysicalFileSystem(SystemDirectories.PartialViews);
|
||||
var macroScriptsFileSystem = new PhysicalFileSystem(SystemDirectories.MacroScripts);
|
||||
var userControlsFileSystem = new PhysicalFileSystem(SystemDirectories.UserControls);
|
||||
var stylesheetsFileSystem = new PhysicalFileSystem(SystemDirectories.Css);
|
||||
var scriptsFileSystem = new PhysicalFileSystem(SystemDirectories.Scripts);
|
||||
var xsltFileSystem = new PhysicalFileSystem(SystemDirectories.Xslt);
|
||||
@@ -69,6 +73,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
_macroPartialFileSystem = new ShadowWrapper(macroPartialFileSystem, "Views/MacroPartials", ScopeProvider);
|
||||
_partialViewsFileSystem = new ShadowWrapper(partialViewsFileSystem, "Views/Partials", ScopeProvider);
|
||||
_macroScriptsFileSystem = new ShadowWrapper(macroScriptsFileSystem, "macroScripts", ScopeProvider);
|
||||
_userControlsFileSystem = new ShadowWrapper(userControlsFileSystem, "usercontrols", ScopeProvider);
|
||||
_stylesheetsFileSystem = new ShadowWrapper(stylesheetsFileSystem, "css", ScopeProvider);
|
||||
_scriptsFileSystem = new ShadowWrapper(scriptsFileSystem, "scripts", ScopeProvider);
|
||||
_xsltFileSystem = new ShadowWrapper(xsltFileSystem, "xslt", ScopeProvider);
|
||||
@@ -85,6 +91,10 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public IFileSystem2 MacroPartialsFileSystem { get { return _macroPartialFileSystem; } }
|
||||
public IFileSystem2 PartialViewsFileSystem { get { return _partialViewsFileSystem; } }
|
||||
// Legacy /macroScripts folder
|
||||
public IFileSystem2 MacroScriptsFileSystem { get { return _macroScriptsFileSystem; } }
|
||||
// Legacy /usercontrols folder
|
||||
public IFileSystem2 UserControlsFileSystem { get { return _userControlsFileSystem; } }
|
||||
public IFileSystem2 StylesheetsFileSystem { get { return _stylesheetsFileSystem; } }
|
||||
public IFileSystem2 ScriptsFileSystem { get { return _scriptsFileSystem; } }
|
||||
public IFileSystem2 XsltFileSystem { get { return _xsltFileSystem; } }
|
||||
@@ -252,13 +262,15 @@ namespace Umbraco.Core.IO
|
||||
internal ICompletable Shadow(Guid id)
|
||||
{
|
||||
var typed = _wrappers.ToArray();
|
||||
var wrappers = new ShadowWrapper[typed.Length + 7];
|
||||
var wrappers = new ShadowWrapper[typed.Length + 9];
|
||||
var i = 0;
|
||||
while (i < typed.Length) wrappers[i] = typed[i++];
|
||||
wrappers[i++] = _macroPartialFileSystem;
|
||||
wrappers[i++] = _macroScriptsFileSystem;
|
||||
wrappers[i++] = _partialViewsFileSystem;
|
||||
wrappers[i++] = _stylesheetsFileSystem;
|
||||
wrappers[i++] = _scriptsFileSystem;
|
||||
wrappers[i++] = _userControlsFileSystem;
|
||||
wrappers[i++] = _xsltFileSystem;
|
||||
wrappers[i++] = _masterPagesFileSystem;
|
||||
wrappers[i] = _mvcViewsFileSystem;
|
||||
|
||||
@@ -97,6 +97,8 @@ namespace Umbraco.Core.IO
|
||||
|
||||
public static string MapPath(string path, bool useHttpContext)
|
||||
{
|
||||
if (path == null) throw new ArgumentNullException("path");
|
||||
|
||||
// Check if the path is already mapped
|
||||
if ((path.Length >= 2 && path[1] == Path.VolumeSeparatorChar)
|
||||
|| path.StartsWith(@"\\")) //UNC Paths start with "\\". If the site is running off a network drive mapped paths will look like "\\Whatever\Boo\Bar"
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
@@ -23,7 +20,7 @@ namespace Umbraco.Core.Models
|
||||
private DateTime? _expireDate;
|
||||
private int _writer;
|
||||
private string _nodeName;//NOTE Once localization is introduced this will be the non-localized Node Name.
|
||||
private bool _permissionsChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Content object
|
||||
/// </summary>
|
||||
@@ -32,7 +29,7 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="contentType">ContentType for the current Content object</param>
|
||||
public Content(string name, IContent parent, IContentType contentType)
|
||||
: this(name, parent, contentType, new PropertyCollection())
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -68,7 +65,7 @@ namespace Umbraco.Core.Models
|
||||
/// <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(string name, int parentId, IContentType contentType, PropertyCollection properties)
|
||||
public Content(string name, int parentId, IContentType contentType, PropertyCollection properties)
|
||||
: base(name, parentId, contentType, properties)
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
@@ -87,7 +84,6 @@ namespace Umbraco.Core.Models
|
||||
public readonly PropertyInfo ExpireDateSelector = ExpressionHelper.GetPropertyInfo<Content, DateTime?>(x => x.ExpireDate);
|
||||
public readonly PropertyInfo WriterSelector = ExpressionHelper.GetPropertyInfo<Content, int>(x => x.WriterId);
|
||||
public readonly PropertyInfo NodeNameSelector = ExpressionHelper.GetPropertyInfo<Content, string>(x => x.NodeName);
|
||||
public readonly PropertyInfo PermissionsChangedSelector = ExpressionHelper.GetPropertyInfo<Content, bool>(x => x.PermissionsChanged);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -95,7 +91,7 @@ namespace Umbraco.Core.Models
|
||||
/// This is used to override the default one from the ContentType.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If no template is explicitly set on the Content object,
|
||||
/// If no template is explicitly set on the Content object,
|
||||
/// the Default template from the ContentType will be returned.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
@@ -197,15 +193,6 @@ namespace Umbraco.Core.Models
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _nodeName, Ps.Value.NodeNameSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally to track if permissions have been changed during the saving process for this entity
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
internal bool PermissionsChanged
|
||||
{
|
||||
get { return _permissionsChanged; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _permissionsChanged, Ps.Value.PermissionsChangedSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the ContentType used by this content object
|
||||
@@ -277,6 +264,9 @@ namespace Umbraco.Core.Models
|
||||
[IgnoreDataMember]
|
||||
internal DateTime PublishedDate { get; set; }
|
||||
|
||||
[DataMember]
|
||||
public bool IsBlueprint { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the Trashed state of the content object
|
||||
/// </summary>
|
||||
@@ -293,7 +283,7 @@ namespace Umbraco.Core.Models
|
||||
ChangePublishedState(PublishedState.Unpublished);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Method to call when Entity is being updated
|
||||
/// </summary>
|
||||
|
||||
@@ -264,7 +264,7 @@ namespace Umbraco.Core.Models
|
||||
/// <returns><see cref="Property"/> Value as an <see cref="object"/></returns>
|
||||
public virtual object GetValue(string propertyTypeAlias)
|
||||
{
|
||||
return Properties[propertyTypeAlias].Value;
|
||||
return Properties.Contains(propertyTypeAlias) ? Properties[propertyTypeAlias].Value : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -275,8 +275,13 @@ namespace Umbraco.Core.Models
|
||||
/// <returns><see cref="Property"/> Value as a <see cref="TPassType"/></returns>
|
||||
public virtual TPassType GetValue<TPassType>(string propertyTypeAlias)
|
||||
{
|
||||
if (Properties.Contains(propertyTypeAlias) == false)
|
||||
{
|
||||
return default(TPassType);
|
||||
}
|
||||
|
||||
var convertAttempt = Properties[propertyTypeAlias].Value.TryConvertTo<TPassType>();
|
||||
return convertAttempt.Success ? convertAttempt.Result : default(TPassType);
|
||||
return convertAttempt.Success ? convertAttempt.Result : default(TPassType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -54,6 +54,11 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public readonly PropertyInfo DefaultTemplateSelector = ExpressionHelper.GetPropertyInfo<ContentType, int>(x => x.DefaultTemplateId);
|
||||
public readonly PropertyInfo AllowedTemplatesSelector = ExpressionHelper.GetPropertyInfo<ContentType, IEnumerable<ITemplate>>(x => x.AllowedTemplates);
|
||||
|
||||
//Custom comparer for enumerable
|
||||
public readonly DelegateEqualityComparer<IEnumerable<ITemplate>> TemplateComparer = new DelegateEqualityComparer<IEnumerable<ITemplate>>(
|
||||
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
|
||||
templates => templates.GetHashCode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -91,10 +96,7 @@ namespace Umbraco.Core.Models
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<ITemplate>>(
|
||||
(templates, enumerable) => templates.UnsortedSequenceEqual(enumerable),
|
||||
templates => templates.GetHashCode()));
|
||||
Ps.Value.TemplateComparer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -88,6 +88,12 @@ namespace Umbraco.Core.Models
|
||||
public readonly PropertyInfo PropertyGroupCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, PropertyGroupCollection>(x => x.PropertyGroups);
|
||||
public readonly PropertyInfo PropertyTypeCollectionSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, IEnumerable<PropertyType>>(x => x.PropertyTypes);
|
||||
public readonly PropertyInfo HasPropertyTypeBeenRemovedSelector = ExpressionHelper.GetPropertyInfo<ContentTypeBase, bool>(x => x.HasPropertyTypeBeenRemoved);
|
||||
|
||||
//Custom comparer for enumerable
|
||||
public readonly DelegateEqualityComparer<IEnumerable<ContentTypeSort>> ContentTypeSortComparer =
|
||||
new DelegateEqualityComparer<IEnumerable<ContentTypeSort>>(
|
||||
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
|
||||
sorts => sorts.GetHashCode());
|
||||
}
|
||||
|
||||
|
||||
@@ -254,7 +260,7 @@ namespace Umbraco.Core.Models
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _trashed, Ps.Value.TrashedSelector); }
|
||||
}
|
||||
|
||||
private IDictionary<string, object> _additionalData;
|
||||
private readonly IDictionary<string, object> _additionalData;
|
||||
/// <summary>
|
||||
/// Some entities may expose additional data that other's might not, this custom data will be available in this collection
|
||||
/// </summary>
|
||||
@@ -273,11 +279,8 @@ namespace Umbraco.Core.Models
|
||||
get { return _allowedContentTypes; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, Ps.Value.AllowedContentTypesSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<ContentTypeSort>>(
|
||||
(sorts, enumerable) => sorts.UnsortedSequenceEqual(enumerable),
|
||||
sorts => sorts.GetHashCode()));
|
||||
SetPropertyValueAndDetectChanges(value, ref _allowedContentTypes, Ps.Value.AllowedContentTypesSelector,
|
||||
Ps.Value.ContentTypeSortComparer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,12 @@ namespace Umbraco.Core.Models
|
||||
public readonly PropertyInfo ParentIdSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, Guid?>(x => x.ParentId);
|
||||
public readonly PropertyInfo ItemKeySelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, string>(x => x.ItemKey);
|
||||
public readonly PropertyInfo TranslationsSelector = ExpressionHelper.GetPropertyInfo<DictionaryItem, IEnumerable<IDictionaryTranslation>>(x => x.Translations);
|
||||
|
||||
//Custom comparer for enumerable
|
||||
public readonly DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>> DictionaryTranslationComparer =
|
||||
new DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>>(
|
||||
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
|
||||
enumerable => enumerable.GetHashCode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -79,10 +85,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
SetPropertyValueAndDetectChanges(asArray, ref _translations, Ps.Value.TranslationsSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<IDictionaryTranslation>>(
|
||||
(enumerable, translations) => enumerable.UnsortedSequenceEqual(translations),
|
||||
enumerable => enumerable.GetHashCode()));
|
||||
Ps.Value.DictionaryTranslationComparer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
if (IsPropertyDirty("CreateDate") == false || _createDate == default(DateTime))
|
||||
CreateDate = DateTime.Now;
|
||||
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default(DateTime))
|
||||
UpdateDate = CreateDate;
|
||||
UpdateDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -129,6 +129,10 @@ namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
if (IsPropertyDirty("UpdateDate") == false || _updateDate == default(DateTime))
|
||||
UpdateDate = DateTime.Now;
|
||||
|
||||
//this is just in case
|
||||
if (_createDate == default(DateTime))
|
||||
CreateDate = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Umbraco.Core.Models.EntityBase
|
||||
{
|
||||
public class EntityPath
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
@@ -85,5 +83,10 @@ namespace Umbraco.Core.Models
|
||||
/// Gets the unique identifier of the published version, if any.
|
||||
/// </summary>
|
||||
Guid PublishedVersionGuid { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the content item is a blueprint.
|
||||
/// </summary>
|
||||
bool IsBlueprint { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
public interface IUserControl : IFile
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -2,23 +2,69 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
|
||||
namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>
|
||||
public class BackOfficeIdentityUser : IdentityUser<int, IIdentityUserLogin, IdentityUserRole<string>, IdentityUserClaim<int>>, IRememberBeingDirty
|
||||
{
|
||||
|
||||
public BackOfficeIdentityUser()
|
||||
/// <summary>
|
||||
/// Used to construct a new instance without an identity
|
||||
/// </summary>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="email">This is allowed to be null (but would need to be filled in if trying to persist this instance)</param>
|
||||
/// <param name="culture"></param>
|
||||
/// <returns></returns>
|
||||
public static BackOfficeIdentityUser CreateNew(string username, string email, string culture)
|
||||
{
|
||||
StartMediaId = -1;
|
||||
StartContentId = -1;
|
||||
Culture = Configuration.GlobalSettings.DefaultUILanguage;
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
|
||||
if (string.IsNullOrWhiteSpace(culture)) throw new ArgumentException("Value cannot be null or whitespace.", "culture");
|
||||
|
||||
var user = new BackOfficeIdentityUser();
|
||||
user.DisableChangeTracking();
|
||||
user._userName = username;
|
||||
user._email = email;
|
||||
//we are setting minvalue here because the default is "0" which is the id of the admin user
|
||||
//which we cannot allow because the admin user will always exist
|
||||
user._id = int.MinValue;
|
||||
user._hasIdentity = false;
|
||||
user._culture = culture;
|
||||
user.EnableChangeTracking();
|
||||
return user;
|
||||
}
|
||||
|
||||
private BackOfficeIdentityUser()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an existing user with the specified groups
|
||||
/// </summary>
|
||||
/// <param name="userId"></param>
|
||||
/// <param name="groups"></param>
|
||||
public BackOfficeIdentityUser(int userId, IEnumerable<IReadOnlyUserGroup> groups)
|
||||
{
|
||||
_startMediaIds = new int[] { };
|
||||
_startContentIds = new int[] { };
|
||||
_groups = new IReadOnlyUserGroup[] { };
|
||||
_allowedSections = new string[] { };
|
||||
_culture = Configuration.GlobalSettings.DefaultUILanguage;
|
||||
_groups = groups.ToArray();
|
||||
_roles = new ObservableCollection<IdentityUserRole<string>>(_groups.Select(x => new IdentityUserRole<string>
|
||||
{
|
||||
RoleId = x.Alias,
|
||||
UserId = userId.ToString()
|
||||
}));
|
||||
_roles.CollectionChanged += _roles_CollectionChanged;
|
||||
}
|
||||
|
||||
public virtual async Task<ClaimsIdentity> GenerateUserIdentityAsync(BackOfficeUserManager<BackOfficeIdentityUser> manager)
|
||||
{
|
||||
// NOTE the authenticationType must match the umbraco one
|
||||
@@ -27,16 +73,155 @@ namespace Umbraco.Core.Models.Identity
|
||||
return userIdentity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if an Id has been set on this object this will be false if the object is new and not peristed to the database
|
||||
/// </summary>
|
||||
public bool HasIdentity
|
||||
{
|
||||
get { return _hasIdentity; }
|
||||
}
|
||||
|
||||
public int[] CalculatedMediaStartNodeIds { get; internal set; }
|
||||
public int[] CalculatedContentStartNodeIds { get; internal set; }
|
||||
|
||||
public override int Id
|
||||
{
|
||||
get { return _id; }
|
||||
set
|
||||
{
|
||||
_id = value;
|
||||
_hasIdentity = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override Email so we can track changes to it
|
||||
/// </summary>
|
||||
public override string Email
|
||||
{
|
||||
get { return _email; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _email, Ps.Value.EmailSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override UserName so we can track changes to it
|
||||
/// </summary>
|
||||
public override string UserName
|
||||
{
|
||||
get { return _userName; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _userName, Ps.Value.UserNameSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override LastLoginDateUtc so we can track changes to it
|
||||
/// </summary>
|
||||
public override DateTime? LastLoginDateUtc
|
||||
{
|
||||
get { return _lastLoginDateUtc; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _lastLoginDateUtc, Ps.Value.LastLoginDateUtcSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override EmailConfirmed so we can track changes to it
|
||||
/// </summary>
|
||||
public override bool EmailConfirmed
|
||||
{
|
||||
get { return _emailConfirmed; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _emailConfirmed, Ps.Value.EmailConfirmedSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the user's real name
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
public int StartContentId { get; set; }
|
||||
public int StartMediaId { get; set; }
|
||||
public string[] AllowedSections { get; set; }
|
||||
public string Culture { get; set; }
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
|
||||
}
|
||||
|
||||
public string UserTypeAlias { get; set; }
|
||||
/// <summary>
|
||||
/// Override AccessFailedCount so we can track changes to it
|
||||
/// </summary>
|
||||
public override int AccessFailedCount
|
||||
{
|
||||
get { return _accessFailedCount; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _accessFailedCount, Ps.Value.AccessFailedCountSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override PasswordHash so we can track changes to it
|
||||
/// </summary>
|
||||
public override string PasswordHash
|
||||
{
|
||||
get { return _passwordHash; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _passwordHash, Ps.Value.PasswordHashSelector); }
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Content start nodes assigned to the User (not ones assigned to the user's groups)
|
||||
/// </summary>
|
||||
public int[] StartContentIds
|
||||
{
|
||||
get { return _startContentIds; }
|
||||
set
|
||||
{
|
||||
if (value == null) value = new int[0];
|
||||
_tracker.SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdsSelector, Ps.Value.StartIdsComparer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Media start nodes assigned to the User (not ones assigned to the user's groups)
|
||||
/// </summary>
|
||||
public int[] StartMediaIds
|
||||
{
|
||||
get { return _startMediaIds; }
|
||||
set
|
||||
{
|
||||
if (value == null) value = new int[0];
|
||||
_tracker.SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdsSelector, Ps.Value.StartIdsComparer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is a readonly list of the user's allowed sections which are based on it's user groups
|
||||
/// </summary>
|
||||
public string[] AllowedSections
|
||||
{
|
||||
get { return _allowedSections ?? (_allowedSections = _groups.SelectMany(x => x.AllowedSections).Distinct().ToArray()); }
|
||||
}
|
||||
|
||||
public string Culture
|
||||
{
|
||||
get { return _culture; }
|
||||
set { _tracker.SetPropertyValueAndDetectChanges(value, ref _culture, Ps.Value.CultureSelector); }
|
||||
}
|
||||
|
||||
public IReadOnlyUserGroup[] Groups
|
||||
{
|
||||
get { return _groups; }
|
||||
set
|
||||
{
|
||||
//so they recalculate
|
||||
_allowedSections = null;
|
||||
|
||||
//now clear all roles and re-add them
|
||||
_roles.CollectionChanged -= _roles_CollectionChanged;
|
||||
_roles.Clear();
|
||||
foreach (var identityUserRole in _groups.Select(x => new IdentityUserRole<string>
|
||||
{
|
||||
RoleId = x.Alias,
|
||||
UserId = Id.ToString()
|
||||
}))
|
||||
{
|
||||
_roles.Add(identityUserRole);
|
||||
}
|
||||
_roles.CollectionChanged += _roles_CollectionChanged;
|
||||
|
||||
_tracker.SetPropertyValueAndDetectChanges(value, ref _groups, Ps.Value.GroupsSelector, Ps.Value.GroupsComparer);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lockout is always enabled
|
||||
@@ -44,7 +229,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
public override bool LockoutEnabled
|
||||
{
|
||||
get { return true; }
|
||||
set
|
||||
set
|
||||
{
|
||||
//do nothing
|
||||
}
|
||||
@@ -82,16 +267,42 @@ namespace Umbraco.Core.Models.Identity
|
||||
return _logins;
|
||||
}
|
||||
}
|
||||
|
||||
public bool LoginsChanged { get; private set; }
|
||||
|
||||
|
||||
void Logins_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
LoginsChanged = true;
|
||||
_tracker.OnPropertyChanged(Ps.Value.LoginsSelector);
|
||||
}
|
||||
|
||||
private ObservableCollection<IIdentityUserLogin> _logins;
|
||||
private Lazy<IEnumerable<IIdentityUserLogin>> _getLogins;
|
||||
private void _roles_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
_tracker.OnPropertyChanged(Ps.Value.RolesSelector);
|
||||
}
|
||||
|
||||
private readonly ObservableCollection<IdentityUserRole<string>> _roles;
|
||||
|
||||
/// <summary>
|
||||
/// helper method to easily add a role without having to deal with IdentityUserRole{T}
|
||||
/// </summary>
|
||||
/// <param name="role"></param>
|
||||
/// <remarks>
|
||||
/// Adding a role this way will not reflect on the user's group's collection or it's allowed sections until the user is persisted
|
||||
/// </remarks>
|
||||
public void AddRole(string role)
|
||||
{
|
||||
Roles.Add(new IdentityUserRole<string>
|
||||
{
|
||||
UserId = this.Id.ToString(),
|
||||
RoleId = role
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override Roles because the value of these are the user's group aliases
|
||||
/// </summary>
|
||||
public override ICollection<IdentityUserRole<string>> Roles
|
||||
{
|
||||
get { return _roles; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to set a lazy call back to populate the user's Login list
|
||||
@@ -101,6 +312,128 @@ namespace Umbraco.Core.Models.Identity
|
||||
{
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
_getLogins = callback;
|
||||
}
|
||||
|
||||
#region Change tracking
|
||||
|
||||
public void DisableChangeTracking()
|
||||
{
|
||||
_tracker.DisableChangeTracking();
|
||||
}
|
||||
|
||||
public void EnableChangeTracking()
|
||||
{
|
||||
_tracker.EnableChangeTracking();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Since this class only has change tracking turned on for Email/Username this will return true if either of those have changed
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public bool IsDirty()
|
||||
{
|
||||
return _tracker.IsDirty();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if the specified property is dirty
|
||||
/// </summary>
|
||||
/// <param name="propName"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsPropertyDirty(string propName)
|
||||
{
|
||||
return _tracker.IsPropertyDirty(propName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets dirty properties
|
||||
/// </summary>
|
||||
void ICanBeDirty.ResetDirtyProperties()
|
||||
{
|
||||
_tracker.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
bool IRememberBeingDirty.WasDirty()
|
||||
{
|
||||
return _tracker.WasDirty();
|
||||
}
|
||||
|
||||
bool IRememberBeingDirty.WasPropertyDirty(string propertyName)
|
||||
{
|
||||
return _tracker.WasPropertyDirty(propertyName);
|
||||
}
|
||||
|
||||
void IRememberBeingDirty.ForgetPreviouslyDirtyProperties()
|
||||
{
|
||||
_tracker.ForgetPreviouslyDirtyProperties();
|
||||
}
|
||||
|
||||
public void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
{
|
||||
_tracker.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
}
|
||||
|
||||
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
|
||||
private class PropertySelectors
|
||||
{
|
||||
public readonly PropertyInfo EmailSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.Email);
|
||||
public readonly PropertyInfo UserNameSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.UserName);
|
||||
public readonly PropertyInfo LastLoginDateUtcSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, DateTime?>(x => x.LastLoginDateUtc);
|
||||
public readonly PropertyInfo EmailConfirmedSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, bool>(x => x.EmailConfirmed);
|
||||
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.Name);
|
||||
public readonly PropertyInfo AccessFailedCountSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, int>(x => x.AccessFailedCount);
|
||||
public readonly PropertyInfo PasswordHashSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.PasswordHash);
|
||||
public readonly PropertyInfo CultureSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, string>(x => x.Culture);
|
||||
public readonly PropertyInfo StartMediaIdsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, int[]>(x => x.StartMediaIds);
|
||||
public readonly PropertyInfo StartContentIdsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, int[]>(x => x.StartContentIds);
|
||||
public readonly PropertyInfo GroupsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, IReadOnlyUserGroup[]>(x => x.Groups);
|
||||
public readonly PropertyInfo LoginsSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, IEnumerable<IIdentityUserLogin>>(x => x.Logins);
|
||||
public readonly PropertyInfo RolesSelector = ExpressionHelper.GetPropertyInfo<BackOfficeIdentityUser, IEnumerable<IdentityUserRole<string>>>(x => x.Roles);
|
||||
|
||||
//Custom comparer for enumerables
|
||||
public readonly DelegateEqualityComparer<IReadOnlyUserGroup[]> GroupsComparer = new DelegateEqualityComparer<IReadOnlyUserGroup[]>(
|
||||
(groups, enumerable) => groups.Select(x => x.Alias).UnsortedSequenceEqual(enumerable.Select(x => x.Alias)),
|
||||
groups => groups.GetHashCode());
|
||||
public readonly DelegateEqualityComparer<int[]> StartIdsComparer = new DelegateEqualityComparer<int[]>(
|
||||
(groups, enumerable) => groups.UnsortedSequenceEqual(enumerable),
|
||||
groups => groups.GetHashCode());
|
||||
|
||||
}
|
||||
|
||||
private readonly ChangeTracker _tracker = new ChangeTracker();
|
||||
private string _email;
|
||||
private string _userName;
|
||||
private int _id;
|
||||
private bool _hasIdentity = false;
|
||||
private DateTime? _lastLoginDateUtc;
|
||||
private bool _emailConfirmed;
|
||||
private string _name;
|
||||
private int _accessFailedCount;
|
||||
private string _passwordHash;
|
||||
private string _culture;
|
||||
private ObservableCollection<IIdentityUserLogin> _logins;
|
||||
private Lazy<IEnumerable<IIdentityUserLogin>> _getLogins;
|
||||
private IReadOnlyUserGroup[] _groups;
|
||||
private string[] _allowedSections;
|
||||
private int[] _startMediaIds;
|
||||
private int[] _startContentIds;
|
||||
|
||||
/// <summary>
|
||||
/// internal class used to track changes for properties that have it enabled
|
||||
/// </summary>
|
||||
private class ChangeTracker : TracksChangesEntityBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Make this public so that it's usable
|
||||
/// </summary>
|
||||
/// <param name="propertyInfo"></param>
|
||||
public new void OnPropertyChanged(PropertyInfo propertyInfo)
|
||||
{
|
||||
base.OnPropertyChanged(propertyInfo);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Security;
|
||||
@@ -13,28 +13,42 @@ namespace Umbraco.Core.Models.Identity
|
||||
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
|
||||
{
|
||||
config.CreateMap<IUser, BackOfficeIdentityUser>()
|
||||
.BeforeMap((user, identityUser) =>
|
||||
{
|
||||
identityUser.DisableChangeTracking();
|
||||
})
|
||||
.ConstructUsing(user => new BackOfficeIdentityUser(user.Id, user.Groups))
|
||||
.ForMember(user => user.LastLoginDateUtc, expression => expression.MapFrom(user => user.LastLoginDate.ToUniversalTime()))
|
||||
.ForMember(user => user.Email, expression => expression.MapFrom(user => user.Email))
|
||||
.ForMember(user => user.EmailConfirmed, expression => expression.MapFrom(user => user.EmailConfirmedDate.HasValue))
|
||||
.ForMember(user => user.Id, expression => expression.MapFrom(user => user.Id))
|
||||
.ForMember(user => user.LockoutEndDateUtc, expression => expression.MapFrom(user => user.IsLockedOut ? DateTime.MaxValue.ToUniversalTime() : (DateTime?)null))
|
||||
.ForMember(user => user.UserName, expression => expression.MapFrom(user => user.Username))
|
||||
.ForMember(user => user.PasswordHash, expression => expression.MapFrom(user => GetPasswordHash(user.RawPasswordValue)))
|
||||
.ForMember(user => user.Culture, expression => expression.MapFrom(user => user.GetUserCulture(applicationContext.Services.TextService)))
|
||||
.ForMember(user => user.Name, expression => expression.MapFrom(user => user.Name))
|
||||
.ForMember(user => user.StartMediaId, expression => expression.MapFrom(user => user.StartMediaId))
|
||||
.ForMember(user => user.StartContentId, expression => expression.MapFrom(user => user.StartContentId))
|
||||
.ForMember(user => user.UserTypeAlias, expression => expression.MapFrom(user => user.UserType.Alias))
|
||||
.ForMember(user => user.StartMediaIds, expression => expression.MapFrom(user => user.StartMediaIds))
|
||||
.ForMember(user => user.StartContentIds, expression => expression.MapFrom(user => user.StartContentIds))
|
||||
.ForMember(user => user.AccessFailedCount, expression => expression.MapFrom(user => user.FailedPasswordAttempts))
|
||||
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()));
|
||||
|
||||
.ForMember(user => user.CalculatedContentStartNodeIds, expression => expression.MapFrom(user => user.CalculateContentStartNodeIds(applicationContext.Services.EntityService)))
|
||||
.ForMember(user => user.CalculatedMediaStartNodeIds, expression => expression.MapFrom(user => user.CalculateMediaStartNodeIds(applicationContext.Services.EntityService)))
|
||||
.ForMember(user => user.AllowedSections, expression => expression.MapFrom(user => user.AllowedSections.ToArray()))
|
||||
.AfterMap((user, identityUser) =>
|
||||
{
|
||||
identityUser.ResetDirtyProperties(true);
|
||||
identityUser.EnableChangeTracking();
|
||||
});
|
||||
|
||||
config.CreateMap<BackOfficeIdentityUser, UserData>()
|
||||
.ConstructUsing((BackOfficeIdentityUser user) => new UserData(Guid.NewGuid().ToString("N"))) //this is the 'session id'
|
||||
.ForMember(detail => detail.Id, opt => opt.MapFrom(user => user.Id))
|
||||
.ForMember(detail => detail.AllowedApplications, opt => opt.MapFrom(user => user.AllowedSections))
|
||||
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => user.Roles.Select(x => x.RoleId).ToArray()))
|
||||
.ForMember(detail => detail.RealName, opt => opt.MapFrom(user => user.Name))
|
||||
.ForMember(detail => detail.Roles, opt => opt.MapFrom(user => new[] { user.UserTypeAlias }))
|
||||
.ForMember(detail => detail.StartContentNode, opt => opt.MapFrom(user => user.StartContentId))
|
||||
.ForMember(detail => detail.StartMediaNode, opt => opt.MapFrom(user => user.StartMediaId))
|
||||
//When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups
|
||||
.ForMember(detail => detail.StartContentNodes, opt => opt.MapFrom(user => user.CalculatedContentStartNodeIds))
|
||||
//When mapping to UserData which is used in the authcookie we want ALL start nodes including ones defined on the groups
|
||||
.ForMember(detail => detail.StartMediaNodes, opt => opt.MapFrom(user => user.CalculatedMediaStartNodeIds))
|
||||
.ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.UserName))
|
||||
.ForMember(detail => detail.Culture, opt => opt.MapFrom(user => user.Culture))
|
||||
.ForMember(detail => detail.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
|
||||
@@ -42,7 +56,7 @@ namespace Umbraco.Core.Models.Identity
|
||||
|
||||
private string GetPasswordHash(string storedPass)
|
||||
{
|
||||
return storedPass.StartsWith("___UIDEMPTYPWORD__") ? null : storedPass;
|
||||
return storedPass.StartsWith(Constants.Security.EmptyPasswordPrefix) ? null : storedPass;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,6 +109,30 @@ namespace Umbraco.Core.Models
|
||||
IsApproved = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a Member object
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="rawPasswordValue">
|
||||
/// The password value passed in to this parameter should be the encoded/encrypted/hashed format of the member's password
|
||||
/// </param>
|
||||
/// <param name="contentType"></param>
|
||||
/// <param name="isApproved"></param>
|
||||
public Member(string name, string email, string username, string rawPasswordValue, IMemberType contentType, bool isApproved)
|
||||
: base(name, -1, contentType, new PropertyCollection())
|
||||
{
|
||||
Mandate.ParameterNotNull(contentType, "contentType");
|
||||
|
||||
_contentTypeAlias = contentType.Alias;
|
||||
_contentType = contentType;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_rawPasswordValue = rawPasswordValue;
|
||||
IsApproved = isApproved;
|
||||
}
|
||||
|
||||
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
|
||||
|
||||
private class PropertySelectors
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an <see cref="IContent"/> -> user group & permission key value pair collection
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This implements <see cref="IAggregateRoot"/> purely so it can be used with the repository layer which is why it's explicitly implemented.
|
||||
/// </remarks>
|
||||
public class ContentPermissionSet : EntityPermissionSet, IAggregateRoot
|
||||
{
|
||||
private readonly IContent _content;
|
||||
|
||||
public ContentPermissionSet(IContent content, EntityPermissionCollection permissionsSet)
|
||||
: base(content.Id, permissionsSet)
|
||||
{
|
||||
_content = content;
|
||||
}
|
||||
|
||||
public override int EntityId
|
||||
{
|
||||
get { return _content.Id; }
|
||||
}
|
||||
|
||||
#region Explicit implementation of IAggregateRoot
|
||||
int IEntity.Id
|
||||
{
|
||||
get { return EntityId; }
|
||||
set { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
bool IEntity.HasIdentity
|
||||
{
|
||||
get { return EntityId > 0; }
|
||||
}
|
||||
|
||||
Guid IEntity.Key { get; set; }
|
||||
|
||||
DateTime IEntity.CreateDate { get; set; }
|
||||
|
||||
DateTime IEntity.UpdateDate { get; set; }
|
||||
|
||||
DateTime? IDeletableEntity.DeletedDate { get; set; }
|
||||
|
||||
object IDeepCloneable.DeepClone()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,66 @@
|
||||
using System.Collections;
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a user -> entity permission
|
||||
/// Represents an entity permission (defined on the user group and derived to retrieve permissions for a given user)
|
||||
/// </summary>
|
||||
public class EntityPermission
|
||||
public class EntityPermission : IEquatable<EntityPermission>
|
||||
{
|
||||
public EntityPermission(int userId, int entityId, string[] assignedPermissions)
|
||||
public EntityPermission(int groupId, int entityId, string[] assignedPermissions)
|
||||
{
|
||||
UserId = userId;
|
||||
UserGroupId = groupId;
|
||||
EntityId = entityId;
|
||||
AssignedPermissions = assignedPermissions;
|
||||
IsDefaultPermissions = false;
|
||||
}
|
||||
|
||||
public EntityPermission(int groupId, int entityId, string[] assignedPermissions, bool isDefaultPermissions)
|
||||
{
|
||||
UserGroupId = groupId;
|
||||
EntityId = entityId;
|
||||
AssignedPermissions = assignedPermissions;
|
||||
IsDefaultPermissions = isDefaultPermissions;
|
||||
}
|
||||
|
||||
public int UserId { get; private set; }
|
||||
public int EntityId { get; private set; }
|
||||
public int UserGroupId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The assigned permissions for the user/entity combo
|
||||
/// </summary>
|
||||
public string[] AssignedPermissions { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// True if the permissions assigned to this object are the group's default permissions and not explicitly defined permissions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will be the case when looking up entity permissions and falling back to the default permissions
|
||||
/// </remarks>
|
||||
public bool IsDefaultPermissions { get; private set; }
|
||||
|
||||
public bool Equals(EntityPermission other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return EntityId == other.EntityId && UserGroupId == other.UserGroupId;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((EntityPermission) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (EntityId * 397) ^ UserGroupId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="HashSet{T}"/> of <see cref="EntityPermission"/>
|
||||
/// </summary>
|
||||
public class EntityPermissionCollection : HashSet<EntityPermission>
|
||||
{
|
||||
public EntityPermissionCollection()
|
||||
{
|
||||
}
|
||||
|
||||
public EntityPermissionCollection(IEnumerable<EntityPermission> collection) : base(collection)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the aggregate permissions in the permission set
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This value is only calculated once
|
||||
/// </remarks>
|
||||
public IEnumerable<string> GetAllPermissions()
|
||||
{
|
||||
return _aggregatePermissions ?? (_aggregatePermissions =
|
||||
this.SelectMany(x => x.AssignedPermissions).Distinct().ToArray());
|
||||
}
|
||||
|
||||
private string[] _aggregatePermissions;
|
||||
}
|
||||
}
|
||||
@@ -1,59 +1,55 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an entity -> user & permission key value pair collection
|
||||
/// </summary>
|
||||
/// Represents an entity -> user group & permission key value pair collection
|
||||
/// </summary>
|
||||
public class EntityPermissionSet
|
||||
{
|
||||
private static readonly Lazy<EntityPermissionSet> EmptyInstance = new Lazy<EntityPermissionSet>(() => new EntityPermissionSet(-1, new EntityPermissionCollection()));
|
||||
/// <summary>
|
||||
/// Returns an empty permission set
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static EntityPermissionSet Empty()
|
||||
{
|
||||
return EmptyInstance.Value;
|
||||
}
|
||||
|
||||
public EntityPermissionSet(int entityId, EntityPermissionCollection permissionsSet)
|
||||
{
|
||||
EntityId = entityId;
|
||||
PermissionsSet = permissionsSet;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The entity id with permissions assigned
|
||||
/// </summary>
|
||||
public int EntityId { get; private set; }
|
||||
public virtual int EntityId { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The key/value pairs of user id & single permission
|
||||
/// The key/value pairs of user group id & single permission
|
||||
/// </summary>
|
||||
public IEnumerable<UserPermission> UserPermissionsSet { get; private set; }
|
||||
public EntityPermissionCollection PermissionsSet { get; private set; }
|
||||
|
||||
public EntityPermissionSet(int entityId, IEnumerable<UserPermission> userPermissionsSet)
|
||||
|
||||
/// <summary>
|
||||
/// Returns the aggregate permissions in the permission set
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// This value is only calculated once
|
||||
/// </remarks>
|
||||
public IEnumerable<string> GetAllPermissions()
|
||||
{
|
||||
EntityId = entityId;
|
||||
UserPermissionsSet = userPermissionsSet;
|
||||
return PermissionsSet.GetAllPermissions();
|
||||
}
|
||||
|
||||
public class UserPermission
|
||||
{
|
||||
public UserPermission(int userId, string permission)
|
||||
{
|
||||
UserId = userId;
|
||||
Permission = permission;
|
||||
}
|
||||
|
||||
public int UserId { get; private set; }
|
||||
public string Permission { get; private set; }
|
||||
|
||||
protected bool Equals(UserPermission other)
|
||||
{
|
||||
return UserId == other.UserId && string.Equals(Permission, other.Permission);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UserPermission) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
return (UserId*397) ^ Permission.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,11 @@
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the the Profile interface
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This interface is pretty useless but has been exposed publicly from 6.x so we're stuck with it. It would make more sense
|
||||
/// if the Id was an int but since it's not people have to cast it to int all of the time!
|
||||
/// </remarks>
|
||||
/// Defines the the User Profile interface
|
||||
/// </summary>
|
||||
public interface IProfile
|
||||
{
|
||||
object Id { get; set; }
|
||||
string Name { get; set; }
|
||||
int Id { get; }
|
||||
string Name { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// A readonly user group providing basic information
|
||||
/// </summary>
|
||||
public interface IReadOnlyUserGroup
|
||||
{
|
||||
string Name { get; }
|
||||
string Icon { get; }
|
||||
int Id { get; }
|
||||
int? StartContentId { get; }
|
||||
int? StartMediaId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The alias
|
||||
/// </summary>
|
||||
string Alias { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
IEnumerable<string> Permissions { get; set; }
|
||||
|
||||
IEnumerable<string> AllowedSections { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
@@ -10,29 +11,39 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// <remarks>Will be left internal until a proper Membership implementation is part of the roadmap</remarks>
|
||||
public interface IUser : IMembershipUser, IRememberBeingDirty, ICanBeDirty
|
||||
{
|
||||
UserState UserState { get; }
|
||||
|
||||
string Name { get; set; }
|
||||
int SessionTimeout { get; set; }
|
||||
int StartContentId { get; set; }
|
||||
int StartMediaId { get; set; }
|
||||
string Language { get; set; }
|
||||
int[] StartContentIds { get; set; }
|
||||
int[] StartMediaIds { get; set; }
|
||||
string Language { get; set; }
|
||||
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IUserType UserType { get; set; }
|
||||
|
||||
DateTime? EmailConfirmedDate { get; set; }
|
||||
DateTime? InvitedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the groups that user is part of
|
||||
/// </summary>
|
||||
IEnumerable<IReadOnlyUserGroup> Groups { get; }
|
||||
|
||||
void RemoveGroup(string group);
|
||||
void ClearGroups();
|
||||
void AddGroup(IReadOnlyUserGroup group);
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the user type for the user
|
||||
/// </summary>
|
||||
IUserType UserType { get; set; }
|
||||
|
||||
//TODO: This should be a private set
|
||||
/// <summary>
|
||||
/// The default permission set for the user
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently in umbraco each permission is a single char but with an Enumerable{string} collection this allows for flexible changes to this in the future
|
||||
/// </remarks>
|
||||
IEnumerable<string> DefaultPermissions { get; set; }
|
||||
|
||||
IEnumerable<string> AllowedSections { get; }
|
||||
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void RemoveAllowedSection(string sectionAlias);
|
||||
void AddAllowedSection(string sectionAlias);
|
||||
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void AddAllowedSection(string sectionAlias);
|
||||
|
||||
/// <summary>
|
||||
/// Exposes the basic profile data
|
||||
@@ -43,5 +54,10 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// The security stamp used by ASP.Net identity
|
||||
/// </summary>
|
||||
string SecurityStamp { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
|
||||
/// </summary>
|
||||
string Avatar { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
public interface IUserGroup : IAggregateRoot
|
||||
{
|
||||
string Alias { get; set; }
|
||||
|
||||
int? StartContentId { get; set; }
|
||||
int? StartMediaId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The icon
|
||||
/// </summary>
|
||||
string Icon { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
IEnumerable<string> Permissions { get; set; }
|
||||
|
||||
IEnumerable<string> AllowedSections { get; }
|
||||
|
||||
void RemoveAllowedSection(string sectionAlias);
|
||||
|
||||
void AddAllowedSection(string sectionAlias);
|
||||
|
||||
void ClearAllowedSections();
|
||||
|
||||
/// <summary>
|
||||
/// Specifies the number of users assigned to this group
|
||||
/// </summary>
|
||||
int UserCount { get; }
|
||||
}
|
||||
}
|
||||
@@ -1,28 +1,17 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
|
||||
public interface IUserType : IAggregateRoot
|
||||
{
|
||||
/// <summary>
|
||||
/// The user type alias
|
||||
/// </summary>
|
||||
string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user type name
|
||||
/// </summary>
|
||||
string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions for the user type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
IEnumerable<string> Permissions { get; set; }
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public interface IUserType : IAggregateRoot
|
||||
{
|
||||
string Alias { get; set; }
|
||||
string Name { get; set; }
|
||||
IEnumerable<string> Permissions { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
public class ReadOnlyUserGroup : IReadOnlyUserGroup, IEquatable<ReadOnlyUserGroup>
|
||||
{
|
||||
public ReadOnlyUserGroup(int id, string name, string icon, int? startContentId, int? startMediaId, string @alias,
|
||||
IEnumerable<string> allowedSections, IEnumerable<string> permissions)
|
||||
{
|
||||
Name = name;
|
||||
Icon = icon;
|
||||
Id = id;
|
||||
Alias = alias;
|
||||
AllowedSections = allowedSections.ToArray();
|
||||
Permissions = permissions.ToArray();
|
||||
|
||||
//Zero is invalid and will be treated as Null
|
||||
StartContentId = startContentId == 0 ? null : startContentId;
|
||||
StartMediaId = startMediaId == 0 ? null : startMediaId;
|
||||
}
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
public string Icon { get; private set; }
|
||||
public int? StartContentId { get; private set; }
|
||||
public int? StartMediaId { get; private set; }
|
||||
public string Alias { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
public IEnumerable<string> Permissions { get; set; }
|
||||
public IEnumerable<string> AllowedSections { get; private set; }
|
||||
|
||||
public bool Equals(ReadOnlyUserGroup other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return string.Equals(Alias, other.Alias);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((ReadOnlyUserGroup) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Alias.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator ==(ReadOnlyUserGroup left, ReadOnlyUserGroup right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(ReadOnlyUserGroup left, ReadOnlyUserGroup right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -34,12 +34,11 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// <param name="lastLockoutDate">The last lockout date.</param>
|
||||
/// <param name="fullName">The full name.</param>
|
||||
/// <param name="language">The language.</param>
|
||||
/// <param name="userType">Type of the user.</param>
|
||||
/// <param name="user"></param>
|
||||
public UmbracoMembershipUser(string providerName, string name, object providerUserKey, string email,
|
||||
string passwordQuestion, string comment, bool isApproved, bool isLockedOut,
|
||||
DateTime creationDate, DateTime lastLoginDate, DateTime lastActivityDate, DateTime lastPasswordChangedDate,
|
||||
DateTime lastLockoutDate, string fullName, string language, IUserType userType, T user)
|
||||
DateTime lastLockoutDate, string fullName, string language, T user)
|
||||
: base( providerName, name, providerUserKey, email, passwordQuestion, comment, isApproved, isLockedOut,
|
||||
creationDate, lastLoginDate, lastActivityDate, lastPasswordChangedDate, lastLockoutDate)
|
||||
{
|
||||
|
||||
@@ -2,13 +2,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
@@ -18,64 +19,107 @@ namespace Umbraco.Core.Models.Membership
|
||||
[DataContract(IsReference = true)]
|
||||
public class User : Entity, IUser
|
||||
{
|
||||
public User(IUserType userType)
|
||||
/// <summary>
|
||||
/// Constructor for creating a new/empty user
|
||||
/// </summary>
|
||||
public User()
|
||||
{
|
||||
if (userType == null) throw new ArgumentNullException("userType");
|
||||
|
||||
_userType = userType;
|
||||
_defaultPermissions = _userType.Permissions == null ? Enumerable.Empty<string>() : new List<string>(_userType.Permissions);
|
||||
//Groups = new List<object> { userType };
|
||||
SessionTimeout = 60;
|
||||
_sectionCollection = new ObservableCollection<string>();
|
||||
_addedSections = new List<string>();
|
||||
_removedSections = new List<string>();
|
||||
_userGroups = new HashSet<IReadOnlyUserGroup>();
|
||||
_language = GlobalSettings.DefaultUILanguage;
|
||||
_sectionCollection.CollectionChanged += SectionCollectionChanged;
|
||||
_isApproved = true;
|
||||
_isLockedOut = false;
|
||||
_startContentId = -1;
|
||||
_startMediaId = -1;
|
||||
_startContentIds = new int[] { };
|
||||
_startMediaIds = new int[] { };
|
||||
//cannot be null
|
||||
_rawPasswordValue = "";
|
||||
}
|
||||
|
||||
public User(string name, string email, string username, string rawPasswordValue, IUserType userType)
|
||||
: this(userType)
|
||||
/// <summary>
|
||||
/// Constructor for creating a new/empty user
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="rawPasswordValue"></param>
|
||||
public User(string name, string email, string username, string rawPasswordValue)
|
||||
: this()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
|
||||
if (string.IsNullOrWhiteSpace(email)) throw new ArgumentException("Value cannot be null or whitespace.", "email");
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
|
||||
if (string.IsNullOrEmpty(rawPasswordValue)) throw new ArgumentException("Value cannot be null or empty.", "rawPasswordValue");
|
||||
|
||||
_name = name;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_rawPasswordValue = rawPasswordValue;
|
||||
_userGroups = new HashSet<IReadOnlyUserGroup>();
|
||||
_isApproved = true;
|
||||
_isLockedOut = false;
|
||||
_startContentId = -1;
|
||||
_startMediaId = -1;
|
||||
_startContentIds = new int[] { };
|
||||
_startMediaIds = new int[] { };
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for creating a new User instance for an existing user
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="email"></param>
|
||||
/// <param name="username"></param>
|
||||
/// <param name="rawPasswordValue"></param>
|
||||
/// <param name="userGroups"></param>
|
||||
/// <param name="startContentIds"></param>
|
||||
/// <param name="startMediaIds"></param>
|
||||
public User(int id, string name, string email, string username, string rawPasswordValue, IEnumerable<IReadOnlyUserGroup> userGroups, int[] startContentIds, int[] startMediaIds)
|
||||
: this()
|
||||
{
|
||||
//we allow whitespace for this value so just check null
|
||||
if (rawPasswordValue == null) throw new ArgumentNullException("rawPasswordValue");
|
||||
if (userGroups == null) throw new ArgumentNullException("userGroups");
|
||||
if (startContentIds == null) throw new ArgumentNullException("startContentIds");
|
||||
if (startMediaIds == null) throw new ArgumentNullException("startMediaIds");
|
||||
if (string.IsNullOrWhiteSpace(name)) throw new ArgumentException("Value cannot be null or whitespace.", "name");
|
||||
if (string.IsNullOrWhiteSpace(username)) throw new ArgumentException("Value cannot be null or whitespace.", "username");
|
||||
|
||||
Id = id;
|
||||
_name = name;
|
||||
_email = email;
|
||||
_username = username;
|
||||
_rawPasswordValue = rawPasswordValue;
|
||||
_userGroups = new HashSet<IReadOnlyUserGroup>(userGroups);
|
||||
_isApproved = true;
|
||||
_isLockedOut = false;
|
||||
_startContentIds = startContentIds;
|
||||
_startMediaIds = startMediaIds;
|
||||
}
|
||||
|
||||
private IUserType _userType;
|
||||
private string _name;
|
||||
private string _securityStamp;
|
||||
private List<string> _addedSections;
|
||||
private List<string> _removedSections;
|
||||
private ObservableCollection<string> _sectionCollection;
|
||||
private string _avatar;
|
||||
private int _sessionTimeout;
|
||||
private int _startContentId;
|
||||
private int _startMediaId;
|
||||
private int[] _startContentIds;
|
||||
private int[] _startMediaIds;
|
||||
private int _failedLoginAttempts;
|
||||
|
||||
private string _username;
|
||||
private DateTime? _emailConfirmedDate;
|
||||
private DateTime? _invitedDate;
|
||||
private string _email;
|
||||
private string _rawPasswordValue;
|
||||
private IEnumerable<string> _allowedSections;
|
||||
private HashSet<IReadOnlyUserGroup> _userGroups;
|
||||
private bool _isApproved;
|
||||
private bool _isLockedOut;
|
||||
private string _language;
|
||||
private DateTime _lastPasswordChangedDate;
|
||||
private DateTime _lastLoginDate;
|
||||
private DateTime _lastLockoutDate;
|
||||
|
||||
private IEnumerable<string> _defaultPermissions;
|
||||
|
||||
private bool _defaultToLiveEditing;
|
||||
private IDictionary<string, object> _additionalData;
|
||||
private object _additionalDataLock = new object();
|
||||
|
||||
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
|
||||
|
||||
@@ -87,10 +131,10 @@ namespace Umbraco.Core.Models.Membership
|
||||
public readonly PropertyInfo LastPasswordChangeDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime>(x => x.LastPasswordChangeDate);
|
||||
|
||||
public readonly PropertyInfo SecurityStampSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.SecurityStamp);
|
||||
public readonly PropertyInfo AvatarSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Avatar);
|
||||
public readonly PropertyInfo SessionTimeoutSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.SessionTimeout);
|
||||
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartContentId);
|
||||
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int>(x => x.StartMediaId);
|
||||
public readonly PropertyInfo AllowedSectionsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<string>>(x => x.AllowedSections);
|
||||
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<User, int[]>(x => x.StartContentIds);
|
||||
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<User, int[]>(x => x.StartMediaIds);
|
||||
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Name);
|
||||
|
||||
public readonly PropertyInfo UsernameSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Username);
|
||||
@@ -99,9 +143,18 @@ namespace Umbraco.Core.Models.Membership
|
||||
public readonly PropertyInfo IsLockedOutSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsLockedOut);
|
||||
public readonly PropertyInfo IsApprovedSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.IsApproved);
|
||||
public readonly PropertyInfo LanguageSelector = ExpressionHelper.GetPropertyInfo<User, string>(x => x.Language);
|
||||
public readonly PropertyInfo EmailConfirmedDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime?>(x => x.EmailConfirmedDate);
|
||||
public readonly PropertyInfo InvitedDateSelector = ExpressionHelper.GetPropertyInfo<User, DateTime?>(x => x.InvitedDate);
|
||||
|
||||
public readonly PropertyInfo DefaultToLiveEditingSelector = ExpressionHelper.GetPropertyInfo<User, bool>(x => x.DefaultToLiveEditing);
|
||||
public readonly PropertyInfo UserTypeSelector = ExpressionHelper.GetPropertyInfo<User, IUserType>(x => x.UserType);
|
||||
|
||||
public readonly PropertyInfo UserGroupsSelector = ExpressionHelper.GetPropertyInfo<User, IEnumerable<IReadOnlyUserGroup>>(x => x.Groups);
|
||||
|
||||
//Custom comparer for enumerable
|
||||
public readonly DelegateEqualityComparer<IEnumerable<int>> IntegerEnumerableComparer =
|
||||
new DelegateEqualityComparer<IEnumerable<int>>(
|
||||
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
|
||||
enum1 => enum1.GetHashCode());
|
||||
}
|
||||
|
||||
#region Implementation of IMembershipUser
|
||||
@@ -112,8 +165,19 @@ namespace Umbraco.Core.Models.Membership
|
||||
get { return Id; }
|
||||
set { throw new NotSupportedException("Cannot set the provider user key for a user"); }
|
||||
}
|
||||
|
||||
|
||||
|
||||
[DataMember]
|
||||
public DateTime? EmailConfirmedDate
|
||||
{
|
||||
get { return _emailConfirmedDate; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _emailConfirmedDate, Ps.Value.EmailConfirmedDateSelector); }
|
||||
}
|
||||
[DataMember]
|
||||
public DateTime? InvitedDate
|
||||
{
|
||||
get { return _invitedDate; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _invitedDate, Ps.Value.InvitedDateSelector); }
|
||||
}
|
||||
[DataMember]
|
||||
public string Username
|
||||
{
|
||||
@@ -189,6 +253,22 @@ namespace Umbraco.Core.Models.Membership
|
||||
|
||||
#region Implementation of IUser
|
||||
|
||||
public UserState UserState
|
||||
{
|
||||
get
|
||||
{
|
||||
if (LastLoginDate == default(DateTime) && IsApproved == false && InvitedDate != null)
|
||||
return UserState.Invited;
|
||||
|
||||
if (IsLockedOut)
|
||||
return UserState.LockedOut;
|
||||
if (IsApproved == false)
|
||||
return UserState.Disabled;
|
||||
|
||||
return UserState.Active;
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
@@ -198,28 +278,171 @@ namespace Umbraco.Core.Models.Membership
|
||||
|
||||
public IEnumerable<string> AllowedSections
|
||||
{
|
||||
get { return _sectionCollection; }
|
||||
get { return _allowedSections ?? (_allowedSections = new List<string>(_userGroups.SelectMany(x => x.AllowedSections).Distinct())); }
|
||||
}
|
||||
|
||||
public void RemoveAllowedSection(string sectionAlias)
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
IUserType IUser.UserType
|
||||
{
|
||||
if (_sectionCollection.Contains(sectionAlias))
|
||||
get
|
||||
{
|
||||
_sectionCollection.Remove(sectionAlias);
|
||||
//the best we can do here is to return the user's first user group as a IUserType object
|
||||
//but we should attempt to return any group that is the built in ones first
|
||||
var groups = Groups.ToArray();
|
||||
if (groups.Length == 0)
|
||||
{
|
||||
//In backwards compatibility land, a user type cannot be null! so we need to return a fake one.
|
||||
return new UserType
|
||||
{
|
||||
Alias = "temp",
|
||||
Id = int.MinValue,
|
||||
Key = Guid.Empty,
|
||||
CreateDate = default(DateTime),
|
||||
DeletedDate = null,
|
||||
Name = "Temp",
|
||||
Permissions = new List<string>(),
|
||||
UpdateDate = default(DateTime)
|
||||
};
|
||||
}
|
||||
var builtIns = new[] { Constants.Security.AdminGroupAlias, "writer", "editor", "translator" };
|
||||
var foundBuiltIn = groups.FirstOrDefault(x => builtIns.Contains(x.Alias));
|
||||
IUserGroup realGroup;
|
||||
if (foundBuiltIn != null)
|
||||
{
|
||||
//if the group isn't IUserGroup we'll need to look it up
|
||||
realGroup = foundBuiltIn as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(foundBuiltIn.Id);
|
||||
|
||||
//return a mapped version of the group
|
||||
return new UserType
|
||||
{
|
||||
Alias = realGroup.Alias,
|
||||
Id = realGroup.Id,
|
||||
Key = realGroup.Key,
|
||||
CreateDate = realGroup.CreateDate,
|
||||
DeletedDate = realGroup.DeletedDate,
|
||||
Name = realGroup.Name,
|
||||
Permissions = realGroup.Permissions,
|
||||
UpdateDate = realGroup.UpdateDate
|
||||
};
|
||||
}
|
||||
|
||||
//otherwise return the first
|
||||
//if the group isn't IUserGroup we'll need to look it up
|
||||
realGroup = groups[0] as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(groups[0].Id);
|
||||
//return a mapped version of the group
|
||||
return new UserType
|
||||
{
|
||||
Alias = realGroup.Alias,
|
||||
Id = realGroup.Id,
|
||||
Key = realGroup.Key,
|
||||
CreateDate = realGroup.CreateDate,
|
||||
DeletedDate = realGroup.DeletedDate,
|
||||
Name = realGroup.Name,
|
||||
Permissions = realGroup.Permissions,
|
||||
UpdateDate = realGroup.UpdateDate
|
||||
};
|
||||
}
|
||||
set
|
||||
{
|
||||
//if old APIs are still using this lets first check if the user is part of the user group with the alias specified
|
||||
if (Groups.Any(x => x.Alias == value.Alias))
|
||||
return;
|
||||
|
||||
//the only other option we have here is to lookup the group (and we'll need to use singletons here :( )
|
||||
var found = ApplicationContext.Current.Services.UserService.GetUserGroupByAlias(value.Alias);
|
||||
if (found == null)
|
||||
throw new InvalidOperationException("No user group was found with the alias " + value.Alias + ", this API (IUser.UserType) is obsolete, use user groups instead");
|
||||
|
||||
//if it's found, all we can do is add it, we can't really replace them
|
||||
AddGroup(found.ToReadOnlyGroup());
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IUser.RemoveAllowedSection(string sectionAlias)
|
||||
{
|
||||
//don't do anything if they aren't allowed it already
|
||||
if (AllowedSections.Contains(sectionAlias) == false)
|
||||
return;
|
||||
|
||||
var groups = Groups.ToArray();
|
||||
//our only option here is to check if a custom group is created for this user, if so we can remove it from that group, otherwise we'll throw
|
||||
//now we'll check if the user has a special 1:1 user group created for itself. This will occur if this method is used and also during an upgrade.
|
||||
//this comes in the alias form of userName + 'Group'
|
||||
var customUserGroup = groups.FirstOrDefault(x => x.Alias == (Username + "Group"));
|
||||
if (customUserGroup != null)
|
||||
{
|
||||
//if the group isn't IUserGroup we'll need to look it up
|
||||
var realGroup = customUserGroup as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(customUserGroup.Id);
|
||||
realGroup.RemoveAllowedSection(sectionAlias);
|
||||
//now we need to flag this for saving (hack!)
|
||||
GroupsToSave.Add(realGroup);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Cannot remove the allowed section using this obsolete API. Modify the user's groups instead");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void AddAllowedSection(string sectionAlias)
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
void IUser.AddAllowedSection(string sectionAlias)
|
||||
{
|
||||
if (_sectionCollection.Contains(sectionAlias) == false)
|
||||
//don't do anything if they are allowed it already
|
||||
if (AllowedSections.Contains(sectionAlias))
|
||||
return;
|
||||
|
||||
//This is here for backwards compat only.
|
||||
//First we'll check if the user is part of the 'admin' group. If so then we can ensure that the admin group has this section available to it.
|
||||
//otherwise, the only thing we can do is create a custom user group for this user and add this section.
|
||||
//We are checking for admin here because if the user is an admin and an allowed section is being added, then it's assumed it's to be added
|
||||
//for the whole admin group (i.e. Forms installer does this for admins)
|
||||
var groups = Groups.ToArray();
|
||||
var admin = groups.FirstOrDefault(x => x.Alias == Constants.Security.AdminGroupAlias);
|
||||
if (admin != null)
|
||||
{
|
||||
//if the group isn't IUserGroup we'll need to look it up
|
||||
var realGroup = admin as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(admin.Id);
|
||||
realGroup.AddAllowedSection(sectionAlias);
|
||||
//now we need to flag this for saving (hack!)
|
||||
GroupsToSave.Add(realGroup);
|
||||
}
|
||||
|
||||
//now we'll check if the user has a special 1:1 user group created for itself. This will occur if this method is used and also during an upgrade.
|
||||
//this comes in the alias form of userName + 'Group'
|
||||
var customUserGroup = groups.FirstOrDefault(x => x.Alias == (Username + "Group"));
|
||||
if (customUserGroup != null)
|
||||
{
|
||||
_sectionCollection.Add(sectionAlias);
|
||||
}
|
||||
}
|
||||
//if the group isn't IUserGroup we'll need to look it up
|
||||
var realGroup = customUserGroup as IUserGroup ?? ApplicationContext.Current.Services.UserService.GetUserGroupById(customUserGroup.Id);
|
||||
realGroup.AddAllowedSection(sectionAlias);
|
||||
//now we need to flag this for saving (hack!)
|
||||
GroupsToSave.Add(realGroup);
|
||||
}
|
||||
|
||||
//ok, so the user doesn't have a 1:1 group, we'll need to flag it for creation
|
||||
var newUserGroup = new UserGroup
|
||||
{
|
||||
Alias = Username + "Group",
|
||||
Name = "Group for " + Username
|
||||
};
|
||||
newUserGroup.AddAllowedSection(sectionAlias);
|
||||
GroupsToSave.Add(newUserGroup);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This used purely for hacking backwards compatibility into this class for < 7.7 compat
|
||||
/// </summary>
|
||||
[DoNotClone]
|
||||
[IgnoreDataMember]
|
||||
internal List<IUserGroup> GroupsToSave = new List<IUserGroup>();
|
||||
|
||||
public IProfile ProfileData
|
||||
{
|
||||
get { return new UserProfile(this); }
|
||||
get { return new WrappedUserProfile(this); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -232,21 +455,12 @@ namespace Umbraco.Core.Models.Membership
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _securityStamp, Ps.Value.SecurityStampSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally to check if we need to add a section in the repository to the db
|
||||
/// </summary>
|
||||
internal IEnumerable<string> AddedSections
|
||||
[DataMember]
|
||||
public string Avatar
|
||||
{
|
||||
get { return _addedSections; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used internally to check if we need to remove a section in the repository to the db
|
||||
/// </summary>
|
||||
internal IEnumerable<string> RemovedSections
|
||||
{
|
||||
get { return _removedSections; }
|
||||
}
|
||||
get { return _avatar; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _avatar, Ps.Value.AvatarSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the session timeout.
|
||||
@@ -268,10 +482,11 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// The start content id.
|
||||
/// </value>
|
||||
[DataMember]
|
||||
public int StartContentId
|
||||
[DoNotClone]
|
||||
public int[] StartContentIds
|
||||
{
|
||||
get { return _startContentId; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _startContentId, Ps.Value.StartContentIdSelector); }
|
||||
get { return _startContentIds; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _startContentIds, Ps.Value.StartContentIdSelector, Ps.Value.IntegerEnumerableComparer); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -281,10 +496,11 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// The start media id.
|
||||
/// </value>
|
||||
[DataMember]
|
||||
public int StartMediaId
|
||||
[DoNotClone]
|
||||
public int[] StartMediaIds
|
||||
{
|
||||
get { return _startMediaId; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _startMediaId, Ps.Value.StartMediaIdSelector); }
|
||||
get { return _startMediaIds; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _startMediaIds, Ps.Value.StartMediaIdSelector, Ps.Value.IntegerEnumerableComparer); }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
@@ -294,14 +510,6 @@ namespace Umbraco.Core.Models.Membership
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _language, Ps.Value.LanguageSelector); }
|
||||
}
|
||||
|
||||
//TODO: This should be a private set
|
||||
[DataMember]
|
||||
public IEnumerable<string> DefaultPermissions
|
||||
{
|
||||
get { return _defaultPermissions;}
|
||||
set { _defaultPermissions = value; }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
internal bool DefaultToLiveEditing
|
||||
{
|
||||
@@ -309,78 +517,107 @@ namespace Umbraco.Core.Models.Membership
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _defaultToLiveEditing, Ps.Value.DefaultToLiveEditingSelector); }
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
public IUserType UserType
|
||||
/// <summary>
|
||||
/// Gets the groups that user is part of
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<IReadOnlyUserGroup> Groups
|
||||
{
|
||||
get { return _userType; }
|
||||
set
|
||||
get { return _userGroups; }
|
||||
}
|
||||
|
||||
public void RemoveGroup(string group)
|
||||
{
|
||||
foreach (var userGroup in _userGroups.ToArray())
|
||||
{
|
||||
if (value.HasIdentity == false)
|
||||
if (userGroup.Alias == group)
|
||||
{
|
||||
throw new InvalidOperationException("Cannot assign a User Type that has not been persisted");
|
||||
_userGroups.Remove(userGroup);
|
||||
//reset this flag so it's rebuilt with the assigned groups
|
||||
_allowedSections = null;
|
||||
OnPropertyChanged(Ps.Value.UserGroupsSelector);
|
||||
}
|
||||
|
||||
SetPropertyValueAndDetectChanges(value, ref _userType, Ps.Value.UserTypeSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearGroups()
|
||||
{
|
||||
if (_userGroups.Count > 0)
|
||||
{
|
||||
_userGroups.Clear();
|
||||
//reset this flag so it's rebuilt with the assigned groups
|
||||
_allowedSections = null;
|
||||
OnPropertyChanged(Ps.Value.UserGroupsSelector);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddGroup(IReadOnlyUserGroup group)
|
||||
{
|
||||
if (_userGroups.Add(group))
|
||||
{
|
||||
//reset this flag so it's rebuilt with the assigned groups
|
||||
_allowedSections = null;
|
||||
OnPropertyChanged(Ps.Value.UserGroupsSelector);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Whenever resetting occurs, clear the remembered add/removed collections, even if
|
||||
/// rememberPreviouslyChangedProperties is true, the AllowedSections property will still
|
||||
/// be flagged as dirty.
|
||||
/// This is used as an internal cache for this entity - specifically for calculating start nodes so we don't re-calculated all of the time
|
||||
/// </summary>
|
||||
/// <param name="rememberPreviouslyChangedProperties"></param>
|
||||
public override void ResetDirtyProperties(bool rememberPreviouslyChangedProperties)
|
||||
[IgnoreDataMember]
|
||||
[DoNotClone]
|
||||
internal IDictionary<string, object> AdditionalData
|
||||
{
|
||||
_addedSections.Clear();
|
||||
_removedSections.Clear();
|
||||
base.ResetDirtyProperties(rememberPreviouslyChangedProperties);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the collection changed event in order for us to flag the AllowedSections property as changed
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
void SectionCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
OnPropertyChanged(Ps.Value.AllowedSectionsSelector);
|
||||
|
||||
if (e.Action == NotifyCollectionChangedAction.Add)
|
||||
get
|
||||
{
|
||||
var item = e.NewItems.Cast<string>().First();
|
||||
|
||||
if (_addedSections.Contains(item) == false)
|
||||
lock (_additionalDataLock)
|
||||
{
|
||||
_addedSections.Add(item);
|
||||
return _additionalData ?? (_additionalData = new Dictionary<string, object>());
|
||||
}
|
||||
}
|
||||
else if (e.Action == NotifyCollectionChangedAction.Remove)
|
||||
{
|
||||
var item = e.OldItems.Cast<string>().First();
|
||||
|
||||
if (_removedSections.Contains(item) == false)
|
||||
{
|
||||
_removedSections.Add(item);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
[IgnoreDataMember]
|
||||
[DoNotClone]
|
||||
internal object AdditionalDataLock { get { return _additionalDataLock; } }
|
||||
|
||||
public override object DeepClone()
|
||||
{
|
||||
var clone = (User)base.DeepClone();
|
||||
//turn off change tracking
|
||||
clone.DisableChangeTracking();
|
||||
//manually clone the start node props
|
||||
clone._startContentIds = _startContentIds.ToArray();
|
||||
clone._startMediaIds = _startMediaIds.ToArray();
|
||||
|
||||
// this value has been cloned and points to the same object
|
||||
// which obviously is bad - needs to point to a new object
|
||||
clone._additionalDataLock = new object();
|
||||
|
||||
if (_additionalData != null)
|
||||
{
|
||||
// clone._additionalData points to the same dictionary, which is bad, because
|
||||
// changing one clone impacts all of them - so we need to reset it with a fresh
|
||||
// dictionary that will contain the same values - and, if some values are deep
|
||||
// cloneable, they should be deep-cloned too
|
||||
var cloneAdditionalData = clone._additionalData = new Dictionary<string, object>();
|
||||
|
||||
lock (_additionalDataLock)
|
||||
{
|
||||
foreach (var kvp in _additionalData)
|
||||
{
|
||||
var deepCloneable = kvp.Value as IDeepCloneable;
|
||||
cloneAdditionalData[kvp.Key] = deepCloneable == null ? kvp.Value : deepCloneable.DeepClone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//need to create new collections otherwise they'll get copied by ref
|
||||
clone._addedSections = new List<string>();
|
||||
clone._removedSections = new List<string>();
|
||||
clone._sectionCollection = new ObservableCollection<string>(_sectionCollection.ToList());
|
||||
clone._defaultPermissions = new List<string>(_defaultPermissions.ToList());
|
||||
clone._userGroups = new HashSet<IReadOnlyUserGroup>(_userGroups);
|
||||
clone._allowedSections = _allowedSections != null ? new List<string>(_allowedSections) : null;
|
||||
//re-create the event handler
|
||||
clone._sectionCollection.CollectionChanged += clone.SectionCollectionChanged;
|
||||
//this shouldn't really be needed since we're not tracking
|
||||
clone.ResetDirtyProperties(false);
|
||||
//re-enable tracking
|
||||
@@ -392,28 +629,26 @@ namespace Umbraco.Core.Models.Membership
|
||||
/// <summary>
|
||||
/// Internal class used to wrap the user in a profile
|
||||
/// </summary>
|
||||
private class UserProfile : IProfile
|
||||
private class WrappedUserProfile : IProfile
|
||||
{
|
||||
private readonly IUser _user;
|
||||
|
||||
public UserProfile(IUser user)
|
||||
public WrappedUserProfile(IUser user)
|
||||
{
|
||||
_user = user;
|
||||
}
|
||||
|
||||
public object Id
|
||||
public int Id
|
||||
{
|
||||
get { return _user.Id; }
|
||||
set { _user.Id = (int)value; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return _user.Name; }
|
||||
set { _user.Name = value; }
|
||||
}
|
||||
|
||||
protected bool Equals(UserProfile other)
|
||||
private bool Equals(WrappedUserProfile other)
|
||||
{
|
||||
return _user.Equals(other._user);
|
||||
}
|
||||
@@ -423,7 +658,7 @@ namespace Umbraco.Core.Models.Membership
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UserProfile) obj);
|
||||
return Equals((WrappedUserProfile) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
|
||||
@@ -1,20 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a Group for a Backoffice User
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should be internal until a proper user/membership implementation
|
||||
/// is part of the roadmap.
|
||||
/// </remarks>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class UserGroup : Entity
|
||||
internal class UserGroup : Entity, IUserGroup, IReadOnlyUserGroup
|
||||
{
|
||||
//Add UserCollection ?
|
||||
private int? _startContentId;
|
||||
private int? _startMediaId;
|
||||
private string _alias;
|
||||
private string _icon;
|
||||
private string _name;
|
||||
private IEnumerable<string> _permissions;
|
||||
private readonly List<string> _sectionCollection;
|
||||
|
||||
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
|
||||
|
||||
private class PropertySelectors
|
||||
{
|
||||
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserGroup, string>(x => x.Name);
|
||||
public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserGroup, string>(x => x.Alias);
|
||||
public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserGroup, IEnumerable<string>>(x => x.Permissions);
|
||||
public readonly PropertyInfo IconSelector = ExpressionHelper.GetPropertyInfo<UserGroup, string>(x => x.Icon);
|
||||
public readonly PropertyInfo StartContentIdSelector = ExpressionHelper.GetPropertyInfo<UserGroup, int?>(x => x.StartContentId);
|
||||
public readonly PropertyInfo StartMediaIdSelector = ExpressionHelper.GetPropertyInfo<UserGroup, int?>(x => x.StartMediaId);
|
||||
|
||||
//Custom comparer for enumerable
|
||||
public readonly DelegateEqualityComparer<IEnumerable<string>> StringEnumerableComparer =
|
||||
new DelegateEqualityComparer<IEnumerable<string>>(
|
||||
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
|
||||
enum1 => enum1.GetHashCode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to create a new user group
|
||||
/// </summary>
|
||||
public UserGroup()
|
||||
{
|
||||
_sectionCollection = new List<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor to create an existing user group
|
||||
/// </summary>
|
||||
/// <param name="userCount"></param>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="permissions"></param>
|
||||
/// <param name="icon"></param>
|
||||
public UserGroup(int userCount, string alias, string name, IEnumerable<string> permissions, string icon)
|
||||
: this()
|
||||
{
|
||||
UserCount = userCount;
|
||||
_alias = alias;
|
||||
_name = name;
|
||||
_permissions = permissions;
|
||||
_icon = icon;
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int? StartMediaId
|
||||
{
|
||||
get { return _startMediaId; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _startMediaId, Ps.Value.StartMediaIdSelector); }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public int? StartContentId
|
||||
{
|
||||
get { return _startContentId; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _startContentId, Ps.Value.StartContentIdSelector); }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Icon
|
||||
{
|
||||
get { return _icon; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _icon, Ps.Value.IconSelector); }
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(
|
||||
value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
|
||||
ref _alias,
|
||||
Ps.Value.AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions for the user group
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public IEnumerable<string> Permissions
|
||||
{
|
||||
get { return _permissions; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector,
|
||||
Ps.Value.StringEnumerableComparer);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<string> AllowedSections
|
||||
{
|
||||
get { return _sectionCollection; }
|
||||
}
|
||||
|
||||
public void RemoveAllowedSection(string sectionAlias)
|
||||
{
|
||||
if (_sectionCollection.Contains(sectionAlias))
|
||||
{
|
||||
_sectionCollection.Remove(sectionAlias);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddAllowedSection(string sectionAlias)
|
||||
{
|
||||
if (_sectionCollection.Contains(sectionAlias) == false)
|
||||
{
|
||||
_sectionCollection.Add(sectionAlias);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAllowedSections()
|
||||
{
|
||||
_sectionCollection.Clear();
|
||||
}
|
||||
|
||||
public int UserCount { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
internal static class UserGroupExtensions
|
||||
{
|
||||
public static IReadOnlyUserGroup ToReadOnlyGroup(this IUserGroup group)
|
||||
{
|
||||
//this will generally always be the case
|
||||
var readonlyGroup = group as IReadOnlyUserGroup;
|
||||
if (readonlyGroup != null) return readonlyGroup;
|
||||
|
||||
//otherwise create one
|
||||
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon, group.StartContentId, group.StartMediaId, group.Alias, group.AllowedSections, group.Permissions);
|
||||
}
|
||||
|
||||
public static IReadOnlyUserGroup ToReadOnlyGroup(this UserGroupDto group)
|
||||
{
|
||||
return new ReadOnlyUserGroup(group.Id, group.Name, group.Icon,
|
||||
group.StartContentId, group.StartMediaId, group.Alias,
|
||||
group.UserGroup2AppDtos.Select(x => x.AppAlias).ToArray(),
|
||||
group.DefaultPermissions == null ? Enumerable.Empty<string>() : group.DefaultPermissions.ToCharArray().Select(x => x.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
internal class UserProfile : IProfile, IEquatable<UserProfile>
|
||||
{
|
||||
public UserProfile(int id, string name)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string Name { get; private set; }
|
||||
|
||||
public bool Equals(UserProfile other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Id == other.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UserProfile) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
public static bool operator ==(UserProfile left, UserProfile right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(UserProfile left, UserProfile right)
|
||||
{
|
||||
return Equals(left, right) == false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// The state of a user
|
||||
/// </summary>
|
||||
public enum UserState
|
||||
{
|
||||
All = -1,
|
||||
Active = 0,
|
||||
Disabled = 1,
|
||||
LockedOut = 2,
|
||||
Invited = 3
|
||||
}
|
||||
}
|
||||
@@ -1,72 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the Type for a Backoffice User
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class UserType : Entity, IUserType
|
||||
{
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private IEnumerable<string> _permissions;
|
||||
|
||||
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
|
||||
|
||||
private class PropertySelectors
|
||||
{
|
||||
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Name);
|
||||
public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Alias);
|
||||
public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserType, IEnumerable<string>>(x => x.Permissions);
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(
|
||||
value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
|
||||
ref _alias,
|
||||
Ps.Value.AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions for the user type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public IEnumerable<string> Permissions
|
||||
{
|
||||
get { return _permissions; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<string>>(
|
||||
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
|
||||
enum1 => enum1.GetHashCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Strings;
|
||||
|
||||
namespace Umbraco.Core.Models.Membership
|
||||
{
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
internal class UserType : Entity, IUserType
|
||||
{
|
||||
private string _alias;
|
||||
private string _name;
|
||||
private IEnumerable<string> _permissions;
|
||||
private static readonly Lazy<PropertySelectors> Ps = new Lazy<PropertySelectors>();
|
||||
private class PropertySelectors
|
||||
{
|
||||
public readonly PropertyInfo NameSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Name);
|
||||
public readonly PropertyInfo AliasSelector = ExpressionHelper.GetPropertyInfo<UserType, string>(x => x.Alias);
|
||||
public readonly PropertyInfo PermissionsSelector = ExpressionHelper.GetPropertyInfo<UserType, IEnumerable<string>>(x => x.Permissions);
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Alias
|
||||
{
|
||||
get { return _alias; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(
|
||||
value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase),
|
||||
ref _alias,
|
||||
Ps.Value.AliasSelector);
|
||||
}
|
||||
}
|
||||
|
||||
[DataMember]
|
||||
public string Name
|
||||
{
|
||||
get { return _name; }
|
||||
set { SetPropertyValueAndDetectChanges(value, ref _name, Ps.Value.NameSelector); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The set of default permissions for the user type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// By default each permission is simply a single char but we've made this an enumerable{string} to support a more flexible permissions structure in the future.
|
||||
/// </remarks>
|
||||
[DataMember]
|
||||
public IEnumerable<string> Permissions
|
||||
{
|
||||
get { return _permissions; }
|
||||
set
|
||||
{
|
||||
SetPropertyValueAndDetectChanges(value, ref _permissions, Ps.Value.PermissionsSelector,
|
||||
//Custom comparer for enumerable
|
||||
new DelegateEqualityComparer<IEnumerable<string>>(
|
||||
(enum1, enum2) => enum1.UnsortedSequenceEqual(enum2),
|
||||
enum1 => enum1.GetHashCode()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@
|
||||
{
|
||||
Unknown = 0, // default
|
||||
PartialView = 1,
|
||||
PartialViewMacro = 2
|
||||
PartialViewMacro = 2,
|
||||
MacroScript = 3
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,36 +49,36 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public readonly PropertyInfo ValueSelector = ExpressionHelper.GetPropertyInfo<Property, object>(x => x.Value);
|
||||
public readonly PropertyInfo VersionSelector = ExpressionHelper.GetPropertyInfo<Property, Guid>(x => x.Version);
|
||||
}
|
||||
|
||||
private static readonly DelegateEqualityComparer<object> ValueComparer = new DelegateEqualityComparer<object>(
|
||||
(o, o1) =>
|
||||
{
|
||||
if (o == null && o1 == null) return true;
|
||||
|
||||
//custom comparer for strings.
|
||||
if (o is string || o1 is string)
|
||||
public readonly DelegateEqualityComparer<object> PropertyValueComparer = new DelegateEqualityComparer<object>(
|
||||
(o, o1) =>
|
||||
{
|
||||
//if one is null and another is empty then they are the same
|
||||
if ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace())
|
||||
if (o == null && o1 == null) return true;
|
||||
|
||||
//custom comparer for strings.
|
||||
if (o is string || o1 is string)
|
||||
{
|
||||
return true;
|
||||
//if one is null and another is empty then they are the same
|
||||
if ((o as string).IsNullOrWhiteSpace() && (o1 as string).IsNullOrWhiteSpace())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (o == null || o1 == null) return false;
|
||||
return o.Equals(o1);
|
||||
}
|
||||
|
||||
if (o == null || o1 == null) return false;
|
||||
|
||||
//Custom comparer for enumerable if it is enumerable
|
||||
var enum1 = o as IEnumerable;
|
||||
var enum2 = o1 as IEnumerable;
|
||||
if (enum1 != null && enum2 != null)
|
||||
{
|
||||
return enum1.Cast<object>().UnsortedSequenceEqual(enum2.Cast<object>());
|
||||
}
|
||||
return o.Equals(o1);
|
||||
}
|
||||
|
||||
if (o == null || o1 == null) return false;
|
||||
|
||||
//Custom comparer for enumerable if it is enumerable
|
||||
var enum1 = o as IEnumerable;
|
||||
var enum2 = o1 as IEnumerable;
|
||||
if (enum1 != null && enum2 != null)
|
||||
{
|
||||
return enum1.Cast<object>().UnsortedSequenceEqual(enum2.Cast<object>());
|
||||
}
|
||||
return o.Equals(o1);
|
||||
}, o => o.GetHashCode());
|
||||
}, o => o.GetHashCode());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the instance of the tag support, by default tags are not enabled
|
||||
@@ -200,7 +200,7 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
}
|
||||
|
||||
SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector, ValueComparer);
|
||||
SetPropertyValueAndDetectChanges(value, ref _value, Ps.Value.ValueSelector, Ps.Value.PropertyValueComparer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
if (_index.HasValue) return _index.Value;
|
||||
|
||||
// slow -- and don't cache, not in a set
|
||||
if (_contentSet == null) return Content.GetIndex();
|
||||
if (_contentSet == null) return WrappedContentInternal.GetIndex();
|
||||
|
||||
// slow -- but cache for next time
|
||||
var index = _contentSet.FindIndex(x => x.Id == Id);
|
||||
@@ -147,7 +147,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
public override IEnumerable<IPublishedContent> ContentSet
|
||||
{
|
||||
get { return _contentSet ?? Content.ContentSet; }
|
||||
get { return _contentSet ?? WrappedContentInternal.ContentSet; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -161,8 +161,8 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
get
|
||||
{
|
||||
return _properties == null
|
||||
? Content.Properties
|
||||
: Content.Properties.Union(_properties).ToList();
|
||||
? WrappedContentInternal.Properties
|
||||
: WrappedContentInternal.Properties.Union(_properties).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,15 +175,15 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
var property = _properties.FirstOrDefault(prop => prop.PropertyTypeAlias.InvariantEquals(alias));
|
||||
if (property != null) return property.HasValue ? property.Value : null;
|
||||
}
|
||||
return Content[alias];
|
||||
return WrappedContentInternal[alias];
|
||||
}
|
||||
}
|
||||
|
||||
public override IPublishedProperty GetProperty(string alias)
|
||||
{
|
||||
return _properties == null
|
||||
? Content.GetProperty(alias)
|
||||
: _properties.FirstOrDefault(prop => prop.PropertyTypeAlias.InvariantEquals(alias)) ?? Content.GetProperty(alias);
|
||||
? WrappedContentInternal.GetProperty(alias)
|
||||
: _properties.FirstOrDefault(prop => prop.PropertyTypeAlias.InvariantEquals(alias)) ?? WrappedContentInternal.GetProperty(alias);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -9,6 +9,6 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
: base(content)
|
||||
{ }
|
||||
|
||||
public Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
|
||||
public Guid Key { get { return ((IPublishedContentWithKey) WrappedContentInternal).Key; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,6 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
: base (content)
|
||||
{ }
|
||||
|
||||
public Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
|
||||
public Guid Key { get { return ((IPublishedContentWithKey) WrappedContentInternal).Key; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,6 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
: base(content)
|
||||
{ }
|
||||
|
||||
public virtual Guid Key { get { return ((IPublishedContentWithKey) Content).Key; } }
|
||||
public virtual Guid Key { get { return ((IPublishedContentWithKey) WrappedContentInternal).Key; } }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// </summary>
|
||||
public abstract class PublishedContentWrapped : IPublishedContent
|
||||
{
|
||||
protected readonly IPublishedContent Content;
|
||||
protected readonly IPublishedContent WrappedContentInternal;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize a new instance of the <see cref="PublishedContentWrapped"/> class
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <param name="content">The content to wrap and extend.</param>
|
||||
protected PublishedContentWrapped(IPublishedContent content)
|
||||
{
|
||||
Content = content;
|
||||
WrappedContentInternal = content;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -45,21 +45,21 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
/// <returns>The wrapped content, that was passed as an argument to the constructor.</returns>
|
||||
public IPublishedContent Unwrap()
|
||||
{
|
||||
return Content;
|
||||
return WrappedContentInternal;
|
||||
}
|
||||
|
||||
#region ContentSet
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> ContentSet
|
||||
{
|
||||
get { return Content.ContentSet; }
|
||||
get { return WrappedContentInternal.ContentSet; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ContentType
|
||||
|
||||
public virtual PublishedContentType ContentType { get { return Content.ContentType; } }
|
||||
public virtual PublishedContentType ContentType { get { return WrappedContentInternal.ContentType; } }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -67,102 +67,102 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
public virtual int Id
|
||||
{
|
||||
get { return Content.Id; }
|
||||
get { return WrappedContentInternal.Id; }
|
||||
}
|
||||
|
||||
public virtual int TemplateId
|
||||
{
|
||||
get { return Content.TemplateId; }
|
||||
get { return WrappedContentInternal.TemplateId; }
|
||||
}
|
||||
|
||||
public virtual int SortOrder
|
||||
{
|
||||
get { return Content.SortOrder; }
|
||||
get { return WrappedContentInternal.SortOrder; }
|
||||
}
|
||||
|
||||
public virtual string Name
|
||||
{
|
||||
get { return Content.Name; }
|
||||
get { return WrappedContentInternal.Name; }
|
||||
}
|
||||
|
||||
public virtual string UrlName
|
||||
{
|
||||
get { return Content.UrlName; }
|
||||
get { return WrappedContentInternal.UrlName; }
|
||||
}
|
||||
|
||||
public virtual string DocumentTypeAlias
|
||||
{
|
||||
get { return Content.DocumentTypeAlias; }
|
||||
get { return WrappedContentInternal.DocumentTypeAlias; }
|
||||
}
|
||||
|
||||
public virtual int DocumentTypeId
|
||||
{
|
||||
get { return Content.DocumentTypeId; }
|
||||
get { return WrappedContentInternal.DocumentTypeId; }
|
||||
}
|
||||
|
||||
public virtual string WriterName
|
||||
{
|
||||
get { return Content.WriterName; }
|
||||
get { return WrappedContentInternal.WriterName; }
|
||||
}
|
||||
|
||||
public virtual string CreatorName
|
||||
{
|
||||
get { return Content.CreatorName; }
|
||||
get { return WrappedContentInternal.CreatorName; }
|
||||
}
|
||||
|
||||
public virtual int WriterId
|
||||
{
|
||||
get { return Content.WriterId; }
|
||||
get { return WrappedContentInternal.WriterId; }
|
||||
}
|
||||
|
||||
public virtual int CreatorId
|
||||
{
|
||||
get { return Content.CreatorId; }
|
||||
get { return WrappedContentInternal.CreatorId; }
|
||||
}
|
||||
|
||||
public virtual string Path
|
||||
{
|
||||
get { return Content.Path; }
|
||||
get { return WrappedContentInternal.Path; }
|
||||
}
|
||||
|
||||
public virtual DateTime CreateDate
|
||||
{
|
||||
get { return Content.CreateDate; }
|
||||
get { return WrappedContentInternal.CreateDate; }
|
||||
}
|
||||
|
||||
public virtual DateTime UpdateDate
|
||||
{
|
||||
get { return Content.UpdateDate; }
|
||||
get { return WrappedContentInternal.UpdateDate; }
|
||||
}
|
||||
|
||||
public virtual Guid Version
|
||||
{
|
||||
get { return Content.Version; }
|
||||
get { return WrappedContentInternal.Version; }
|
||||
}
|
||||
|
||||
public virtual int Level
|
||||
{
|
||||
get { return Content.Level; }
|
||||
get { return WrappedContentInternal.Level; }
|
||||
}
|
||||
|
||||
public virtual string Url
|
||||
{
|
||||
get { return Content.Url; }
|
||||
get { return WrappedContentInternal.Url; }
|
||||
}
|
||||
|
||||
public virtual PublishedItemType ItemType
|
||||
{
|
||||
get { return Content.ItemType; }
|
||||
get { return WrappedContentInternal.ItemType; }
|
||||
}
|
||||
|
||||
public virtual bool IsDraft
|
||||
{
|
||||
get { return Content.IsDraft; }
|
||||
get { return WrappedContentInternal.IsDraft; }
|
||||
}
|
||||
|
||||
public virtual int GetIndex()
|
||||
{
|
||||
return Content.GetIndex();
|
||||
return WrappedContentInternal.GetIndex();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -171,12 +171,12 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
public virtual IPublishedContent Parent
|
||||
{
|
||||
get { return Content.Parent; }
|
||||
get { return WrappedContentInternal.Parent; }
|
||||
}
|
||||
|
||||
public virtual IEnumerable<IPublishedContent> Children
|
||||
{
|
||||
get { return Content.Children; }
|
||||
get { return WrappedContentInternal.Children; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -185,22 +185,22 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
public virtual ICollection<IPublishedProperty> Properties
|
||||
{
|
||||
get { return Content.Properties; }
|
||||
get { return WrappedContentInternal.Properties; }
|
||||
}
|
||||
|
||||
public virtual object this[string alias]
|
||||
{
|
||||
get { return Content[alias]; }
|
||||
get { return WrappedContentInternal[alias]; }
|
||||
}
|
||||
|
||||
public virtual IPublishedProperty GetProperty(string alias)
|
||||
{
|
||||
return Content.GetProperty(alias);
|
||||
return WrappedContentInternal.GetProperty(alias);
|
||||
}
|
||||
|
||||
public virtual IPublishedProperty GetProperty(string alias, bool recurse)
|
||||
{
|
||||
return Content.GetProperty(alias, recurse);
|
||||
return WrappedContentInternal.GetProperty(alias, recurse);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
public Guid? Parent { get; set; }
|
||||
|
||||
[Column("key")]
|
||||
[Length(1000)]
|
||||
[Length(450)]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_cmsDictionary_key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUser2UserGroup")]
|
||||
[ExplicitColumns]
|
||||
internal class User2UserGroupDto
|
||||
{
|
||||
[Column("userId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_user2userGroup", OnColumns = "userId, userGroupId")]
|
||||
[ForeignKey(typeof(UserDto))]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Column("userGroupId")]
|
||||
[ForeignKey(typeof(UserGroupDto))]
|
||||
public int UserGroupId { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
@@ -10,6 +11,12 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[ExplicitColumns]
|
||||
internal class UserDto
|
||||
{
|
||||
public UserDto()
|
||||
{
|
||||
UserGroupDtos = new List<UserGroupDto>();
|
||||
UserStartNodeDtos = new HashSet<UserStartNodeDto>();
|
||||
}
|
||||
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(Name = "PK_user")]
|
||||
public int Id { get; set; }
|
||||
@@ -21,18 +28,7 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[Column("userNoConsole")]
|
||||
[Constraint(Default = "0")]
|
||||
public bool NoConsole { get; set; }
|
||||
|
||||
[Column("userType")]
|
||||
[ForeignKey(typeof(UserTypeDto))]
|
||||
public short Type { get; set; }
|
||||
|
||||
[Column("startStructureID")]
|
||||
public int ContentStartId { get; set; }
|
||||
|
||||
[Column("startMediaID")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public int? MediaStartId { get; set; }
|
||||
|
||||
|
||||
[Column("userName")]
|
||||
public string UserName { get; set; }
|
||||
|
||||
@@ -44,6 +40,14 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[Column("userPassword")]
|
||||
[Length(500)]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This will represent a JSON structure of how the password has been created (i.e hash algorithm, iterations)
|
||||
/// </summary>
|
||||
[Column("passwordConfig")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
[Length(500)]
|
||||
public string PasswordConfig { get; set; }
|
||||
|
||||
[Column("userEmail")]
|
||||
public string Email { get; set; }
|
||||
@@ -73,8 +77,36 @@ namespace Umbraco.Core.Models.Rdbms
|
||||
[Column("lastLoginDate")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public DateTime? LastLoginDate { get; set; }
|
||||
|
||||
|
||||
[Column("emailConfirmedDate")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public DateTime? EmailConfirmedDate { get; set; }
|
||||
|
||||
[Column("invitedDate")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public DateTime? InvitedDate { get; set; }
|
||||
|
||||
[Column("createDate")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Constraint(Default = SystemMethods.CurrentDateTime)]
|
||||
public DateTime CreateDate { get; set; }
|
||||
|
||||
[Column("updateDate")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Constraint(Default = SystemMethods.CurrentDateTime)]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Will hold the media file system relative path of the users custom avatar if they uploaded one
|
||||
/// </summary>
|
||||
[Column("avatar")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Avatar { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public List<User2AppDto> User2AppDtos { get; set; }
|
||||
public List<UserGroupDto> UserGroupDtos { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public HashSet<UserStartNodeDto> UserStartNodeDtos { get; set; }
|
||||
}
|
||||
}
|
||||
+18
-19
@@ -1,20 +1,19 @@
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUser2app")]
|
||||
[PrimaryKey("user", autoIncrement = false)]
|
||||
[ExplicitColumns]
|
||||
internal class User2AppDto
|
||||
{
|
||||
[Column("user")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_user2app", OnColumns = "user, app")]
|
||||
[ForeignKey(typeof(UserDto))]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Column("app")]
|
||||
[Length(50)]
|
||||
public string AppAlias { get; set; }
|
||||
}
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUserGroup2App")]
|
||||
[ExplicitColumns]
|
||||
internal class UserGroup2AppDto
|
||||
{
|
||||
[Column("userGroupId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_userGroup2App", OnColumns = "userGroupId, app")]
|
||||
[ForeignKey(typeof(UserGroupDto))]
|
||||
public int UserGroupId { get; set; }
|
||||
|
||||
[Column("app")]
|
||||
[Length(50)]
|
||||
public string AppAlias { get; set; }
|
||||
}
|
||||
}
|
||||
+6
-7
@@ -3,15 +3,14 @@ using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUser2NodePermission")]
|
||||
[PrimaryKey("userId", autoIncrement = false)]
|
||||
[TableName("umbracoUserGroup2NodePermission")]
|
||||
[ExplicitColumns]
|
||||
internal class User2NodePermissionDto
|
||||
internal class UserGroup2NodePermissionDto
|
||||
{
|
||||
[Column("userId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUser2NodePermission", OnColumns = "userId, nodeId, permission")]
|
||||
[ForeignKey(typeof(UserDto))]
|
||||
public int UserId { get; set; }
|
||||
[Column("userGroupId")]
|
||||
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUserGroup2NodePermission", OnColumns = "userGroupId, nodeId, permission")]
|
||||
[ForeignKey(typeof(UserGroupDto))]
|
||||
public int UserGroupId { get; set; }
|
||||
|
||||
[Column("nodeId")]
|
||||
[ForeignKey(typeof(NodeDto))]
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUserGroup")]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
internal class UserGroupDto
|
||||
{
|
||||
public UserGroupDto()
|
||||
{
|
||||
UserGroup2AppDtos = new List<UserGroup2AppDto>();
|
||||
}
|
||||
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(IdentitySeed = 5)]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("userGroupAlias")]
|
||||
[Length(200)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoUserGroup_userGroupAlias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[Column("userGroupName")]
|
||||
[Length(200)]
|
||||
[Index(IndexTypes.UniqueNonClustered, Name = "IX_umbracoUserGroup_userGroupName")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[Column("userGroupDefaultPermissions")]
|
||||
[Length(50)]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string DefaultPermissions { get; set; }
|
||||
|
||||
[Column("createDate")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Constraint(Default = SystemMethods.CurrentDateTime)]
|
||||
public DateTime CreateDate { get; set; }
|
||||
|
||||
[Column("updateDate")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Constraint(Default = SystemMethods.CurrentDateTime)]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
[Column("icon")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public string Icon { get; set; }
|
||||
|
||||
[Column("startContentId")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public int? StartContentId { get; set; }
|
||||
|
||||
[Column("startMediaId")]
|
||||
[NullSetting(NullSetting = NullSettings.Null)]
|
||||
public int? StartMediaId { get; set; }
|
||||
|
||||
[ResultColumn]
|
||||
public List<UserGroup2AppDto> UserGroup2AppDtos { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// This is only relevant when this column is included in the results (i.e. GetUserGroupsWithUserCounts)
|
||||
/// </summary>
|
||||
[ResultColumn]
|
||||
public int UserCount { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[TableName("umbracoUserStartNode")]
|
||||
[PrimaryKey("id", autoIncrement = true)]
|
||||
[ExplicitColumns]
|
||||
internal class UserStartNodeDto : IEquatable<UserStartNodeDto>
|
||||
{
|
||||
[Column("id")]
|
||||
[PrimaryKeyColumn(Name = "PK_userStartNode")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Column("userId")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[ForeignKey(typeof(UserDto))]
|
||||
public int UserId { get; set; }
|
||||
|
||||
[Column("startNode")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[ForeignKey(typeof(NodeDto))]
|
||||
public int StartNode { get; set; }
|
||||
|
||||
[Column("startNodeType")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Index(IndexTypes.UniqueNonClustered, ForColumns = "startNodeType, startNode, userId", Name = "IX_umbracoUserStartNode_startNodeType")]
|
||||
public int StartNodeType { get; set; }
|
||||
|
||||
public enum StartNodeTypeValue
|
||||
{
|
||||
Content = 1,
|
||||
Media = 2
|
||||
}
|
||||
|
||||
public bool Equals(UserStartNodeDto other)
|
||||
{
|
||||
if (ReferenceEquals(null, other)) return false;
|
||||
if (ReferenceEquals(this, other)) return true;
|
||||
return Id == other.Id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (ReferenceEquals(null, obj)) return false;
|
||||
if (ReferenceEquals(this, obj)) return true;
|
||||
if (obj.GetType() != this.GetType()) return false;
|
||||
return Equals((UserStartNodeDto) obj);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
||||
public static bool operator ==(UserStartNodeDto left, UserStartNodeDto right)
|
||||
{
|
||||
return Equals(left, right);
|
||||
}
|
||||
|
||||
public static bool operator !=(UserStartNodeDto left, UserStartNodeDto right)
|
||||
{
|
||||
return !Equals(left, right);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using Umbraco.Core.Persistence;
|
||||
using System;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
|
||||
namespace Umbraco.Core.Models.Rdbms
|
||||
{
|
||||
[Obsolete("Table no longer exists as of 7.6 - retained only to support migrations from previous versions")]
|
||||
[TableName("umbracoUserType")]
|
||||
[PrimaryKey("id")]
|
||||
[ExplicitColumns]
|
||||
|
||||
@@ -178,6 +178,21 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsDataSource)]
|
||||
[FriendlyName("DataSource")]
|
||||
FormsDataSource
|
||||
FormsDataSource,
|
||||
|
||||
/// <summary>
|
||||
/// Language
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.Language)]
|
||||
[FriendlyName("Language")]
|
||||
Language,
|
||||
|
||||
/// <summary>
|
||||
/// Document
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.DocumentBlueprint, typeof(IContent))]
|
||||
[FriendlyName("DocumentBlueprint")]
|
||||
[UmbracoUdiType(Constants.UdiEntityType.DocumentBluePrint)]
|
||||
DocumentBlueprint
|
||||
}
|
||||
}
|
||||
@@ -68,15 +68,14 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
return UmbracoObjectTypeCache.GetOrAdd(umbracoObjectType, types =>
|
||||
{
|
||||
var type = typeof(UmbracoObjectTypes);
|
||||
var memInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memInfo[0].GetCustomAttributes(typeof(UmbracoObjectTypeAttribute),
|
||||
false);
|
||||
var type = typeof (UmbracoObjectTypes);
|
||||
var memberInfo = type.GetMember(umbracoObjectType.ToString());
|
||||
var attributes = memberInfo[0].GetCustomAttributes(typeof (UmbracoObjectTypeAttribute), false);
|
||||
|
||||
if (attributes.Length == 0)
|
||||
return Guid.Empty;
|
||||
|
||||
var attribute = ((UmbracoObjectTypeAttribute)attributes[0]);
|
||||
var attribute = (UmbracoObjectTypeAttribute) attributes[0];
|
||||
if (attribute == null)
|
||||
return Guid.Empty;
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a UserControl file
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
[DataContract(IsReference = true)]
|
||||
public class UserControl : File, IUserControl
|
||||
{
|
||||
public UserControl(string path)
|
||||
: this(path, (Func<File, string>)null)
|
||||
{ }
|
||||
|
||||
internal UserControl(string path, Func<File, string> getFileContent)
|
||||
: base(path, getFileContent)
|
||||
{ }
|
||||
|
||||
/// <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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user