Compare commits
704 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 75c2b07ad3 | |||
| 969fe30f6e | |||
| 0f90d357cf | |||
| d955daab0f | |||
| 617b17ca9e | |||
| 9e3d7a1cce | |||
| f04071d7c7 | |||
| 2cce9395da | |||
| 6ad56863d4 | |||
| 2703fa7ea2 | |||
| b3c6654d41 | |||
| 0071651621 | |||
| 4dbc27f1fe | |||
| 3f8bbc2f02 | |||
| 999be9c578 | |||
| b36b1693dd | |||
| 99b2192ab7 | |||
| 5230f55f44 | |||
| f93fee28dd | |||
| fc7cfea4ad | |||
| bc5f651c64 | |||
| ecdca378c6 | |||
| 4628c1f858 | |||
| 5af4d02f44 | |||
| 2f9b526465 | |||
| 800e02bccf | |||
| 693b0dba24 | |||
| 2004f6a51e | |||
| f650b6238c | |||
| 7c179a7868 | |||
| 7a7e0edfa7 | |||
| 69adec1d68 | |||
| 0cf6548f86 | |||
| 111ee66b60 | |||
| fedcd6f970 | |||
| 8e82ff5450 | |||
| 81459c3659 | |||
| 8907c9855b | |||
| e1bf30ec26 | |||
| 6bb9c5b81c | |||
| 6aafbfb245 | |||
| d5fe8c11c8 | |||
| 3fdb122e91 | |||
| 710dda164f | |||
| 07d0d82bd1 | |||
| 91eb3ea59e | |||
| 096f1b6ff9 | |||
| f24c0d3e7a | |||
| 104338c817 | |||
| 568f098445 | |||
| f46d595f00 | |||
| 46826ad590 | |||
| a8bd34b77e | |||
| 40774cfff2 | |||
| 5dde898205 | |||
| 249287e101 | |||
| 3e458e2ba6 | |||
| 4f293a8be1 | |||
| 3b9d9ab8c4 | |||
| 83f875dadd | |||
| 89df81d3df | |||
| 2e4ee42c90 | |||
| a03858a726 | |||
| 253174d4b3 | |||
| 947889fae6 | |||
| 7ee0b582dd | |||
| 7bec4efc60 | |||
| 571d8086c8 | |||
| 8abeefe6bb | |||
| 0aaf3eea02 | |||
| 8fc84f9b09 | |||
| 493b98a771 | |||
| 114a9b4d33 | |||
| 824b1e7c08 | |||
| dfa9b297db | |||
| adceb24651 | |||
| c7f1a1419a | |||
| 8878b5e21c | |||
| 6ebb1d1b4b | |||
| 583cd2d1e9 | |||
| 86c6b01e73 | |||
| 1170e222e3 | |||
| fe004db7d5 | |||
| 9e75ffb332 | |||
| d0bb6b7aa4 | |||
| c306f94a6a | |||
| 11b2ec89fd | |||
| 89596f00f1 | |||
| 4fa6e70e72 | |||
| a5a0a84d46 | |||
| 839431e6fa | |||
| 5369a6fc56 | |||
| 8a078e258f | |||
| fb42574c34 | |||
| 9ad3b6a337 | |||
| 91da14b0c6 | |||
| f361e286ed | |||
| 65b16fbfe5 | |||
| 6ad2853bce | |||
| e60e4e52fc | |||
| b2407eab98 | |||
| 778c7a836b | |||
| 11f9cdead0 | |||
| a1076d5443 | |||
| 4a11bf68f3 | |||
| fa64e73a43 | |||
| adf3e2dfe0 | |||
| c4c86cf5ce | |||
| 479aba8e1d | |||
| 0c474e2aba | |||
| 4f5b34cdfe | |||
| 0cb7f220ea | |||
| 0995b2cb5a | |||
| af1fe425a2 | |||
| 22385d40db | |||
| 1b37475144 | |||
| be0bacd895 | |||
| a2564bd0c3 | |||
| 402a5c9d56 | |||
| 2a2f22c7d9 | |||
| 372a768dca | |||
| f6e48243a6 | |||
| 94ea677ec0 | |||
| 55e7159f7d | |||
| 390a94e323 | |||
| 19fb920aa1 | |||
| f35e1604ca | |||
| b9765c3bec | |||
| d5a57c505c | |||
| 5f365241a8 | |||
| 9c121f0044 | |||
| f13bc07ddc | |||
| a707d23692 | |||
| 0929b7d42c | |||
| 35a9272b68 | |||
| 112453a032 | |||
| bba7367ba6 | |||
| 367073e02e | |||
| 83e679ba5e | |||
| 05c35b22bd | |||
| 1a4322eb48 | |||
| 4d950fb4d4 | |||
| 0d191fb8bd | |||
| f6318fb6f3 | |||
| c7a3efadb1 | |||
| 956425dfbf | |||
| c616354522 | |||
| 17b29357d4 | |||
| 36246b96d4 | |||
| 7d8791ec86 | |||
| f349a9ae3e | |||
| 2719e2c231 | |||
| 57a766098d | |||
| dafde545b0 | |||
| 610538261e | |||
| f78cb8a970 | |||
| e8f84cfec0 | |||
| def276de01 | |||
| 293b170a56 | |||
| 9f7b82e20f | |||
| 6ba4efc416 | |||
| 981fb39af6 | |||
| c64f6f894e | |||
| 3e73c2da43 | |||
| 26a8d23039 | |||
| 2632ef740c | |||
| f024dba864 | |||
| 9758851a4b | |||
| 04b3532e9d | |||
| 38e56f0fea | |||
| 462baf91e4 | |||
| 01bcd3b623 | |||
| 64fd95bd22 | |||
| f1366c7d29 | |||
| baaa9340e4 | |||
| 183a5b5c43 | |||
| 1a0c095f40 | |||
| ffada74aa4 | |||
| f2fc70f731 | |||
| 866b0113e7 | |||
| 06c49daca7 | |||
| 9293008b94 | |||
| dbb9386d22 | |||
| 51ed441b85 | |||
| f566fec665 | |||
| 9d92781a97 | |||
| 123bfe5afe | |||
| 3383d2a2ac | |||
| d9f38a20af | |||
| a91669abc0 | |||
| cc6dfd0c55 | |||
| d4802fcef6 | |||
| 35c3208b77 | |||
| 3b9db8a92f | |||
| 7debe17c58 | |||
| 1bfc1229bd | |||
| f941456af6 | |||
| 828e88e6f2 | |||
| 3d6fd2d785 | |||
| e56881abc6 | |||
| d32991c30a | |||
| 8758f9649b | |||
| 07902e840f | |||
| e807ee7d64 | |||
| 6f0f1ab2c3 | |||
| cd28240172 | |||
| 85ca85fd42 | |||
| 4a10178697 | |||
| ccba7f14a0 | |||
| b797e0d0c5 | |||
| 8220b033f3 | |||
| 6fffc8b45e | |||
| b550b3dde3 | |||
| 7002291c41 | |||
| 51bbf7ceb5 | |||
| 93d9f09fcc | |||
| 42a68cb770 | |||
| 1c2dec00fc | |||
| fcea4c7fdd | |||
| b6ef4bf6b5 | |||
| 82297a6ff1 | |||
| 3bf79f0a23 | |||
| 3f5aa3aa2b | |||
| cc5ac1a84c | |||
| 6373add383 | |||
| 180099b718 | |||
| 65f15125e1 | |||
| f026201c68 | |||
| 640b2c0ee0 | |||
| bef7ad1196 | |||
| 33c6c8b473 | |||
| 0a26e482aa | |||
| d0de54e2d3 | |||
| 6effcdfce9 | |||
| cbdabaa3b1 | |||
| 65c97040b3 | |||
| a33d7da211 | |||
| f31b6d9c2c | |||
| 367c945b42 | |||
| b962fcdbc3 | |||
| 0f8a13d60a | |||
| 5c1502c806 | |||
| 3cdebf4427 | |||
| e4e7c18460 | |||
| 5f246c533c | |||
| 5323543ec0 | |||
| d44542694b | |||
| 016a14e5c7 | |||
| 52f4dfec80 | |||
| 4f6e023d77 | |||
| 5e46750cc4 | |||
| d028b133f5 | |||
| ca6821104b | |||
| 1ea8c8280c | |||
| 17ff952b52 | |||
| b4f64975a2 | |||
| 1d8a5cf795 | |||
| dccee93700 | |||
| efeafb4471 | |||
| 496efde5b3 | |||
| 2b56854652 | |||
| 04e1d8c2bd | |||
| c7a7dd6ed5 | |||
| 1eedbba97a | |||
| d6b46e7e78 | |||
| 1b03a8f06c | |||
| 726bef1edf | |||
| 33aa04bb2f | |||
| a79333080a | |||
| d1f513df69 | |||
| 54ddbc264d | |||
| 89f6089f8e | |||
| cf0b72fd77 | |||
| 2c32530701 | |||
| d6d945a96e | |||
| 4b6aee7fd9 | |||
| 8bbeeb2eaf | |||
| 5648617809 | |||
| 0a33b37f2d | |||
| 157bf0d1eb | |||
| 2721c5cb12 | |||
| fd984bd613 | |||
| fe0ed2ceea | |||
| 0829bae5b2 | |||
| c3c1567c2e | |||
| 4a8b59bdfa | |||
| af543c56ec | |||
| 4113def0b6 | |||
| c346e62176 | |||
| 94fdbb1983 | |||
| f32e688c1a | |||
| 0303196f42 | |||
| c8faf17017 | |||
| b2cba310b9 | |||
| 95522afda8 | |||
| 1b84e33392 | |||
| 065ed5ed78 | |||
| 9e931b84db | |||
| be449a96f7 | |||
| a22bfb927a | |||
| 5b92b30f64 | |||
| 5e8200ecb2 | |||
| 9b5ea3da21 | |||
| d495b96434 | |||
| 79edf81434 | |||
| b3620f1ca4 | |||
| b6a9734755 | |||
| c4cedaddd2 | |||
| b5a2b3dbbd | |||
| dc4266852f | |||
| 881e8daafd | |||
| 5176b68935 | |||
| 0bfc5f1272 | |||
| 54c1d25296 | |||
| 624d3a9b82 | |||
| d46d23b372 | |||
| aeba68782c | |||
| ac60c63104 | |||
| 6e0e48b6e4 | |||
| 0ea15ae22e | |||
| 54548ffc68 | |||
| 39c18d4201 | |||
| fdc50f0635 | |||
| 66ea8ae604 | |||
| 44f2a9e96f | |||
| 11743ea322 | |||
| 4d74ec7785 | |||
| aa704a2065 | |||
| 08844ea098 | |||
| 3449b1efd3 | |||
| 00d012162f | |||
| 966be0f342 | |||
| 0347a93dcf | |||
| 25482f53ef | |||
| 7e762d9114 | |||
| 82699a8ac9 | |||
| 0ea68f4f42 | |||
| 2cd4e9aa99 | |||
| 8e3454d24f | |||
| e352c65420 | |||
| 04a12567bc | |||
| 16caeb96bd | |||
| fbd5bdbd1d | |||
| e3983bb427 | |||
| c4389a3820 | |||
| 1f8274e807 | |||
| 9978b0d8ea | |||
| 0d9fef5457 | |||
| 7449e3bf1d | |||
| e6550b543d | |||
| 1552a08b46 | |||
| c9d2d574f8 | |||
| 4807bc4f2f | |||
| 87a2589853 | |||
| 6f400df775 | |||
| 68eaca6f66 | |||
| 166429cf68 | |||
| 48adc259d9 | |||
| 42c23dadc9 | |||
| fb9471359c | |||
| 4e0b018a8b | |||
| f94b5cc462 | |||
| fee98f8144 | |||
| aa31e293ec | |||
| f8045840ee | |||
| e2985d74e5 | |||
| 7d15b26a8f | |||
| a77ebb1160 | |||
| 6a1e54b221 | |||
| 864ca4e40e | |||
| 24d42e6bd1 | |||
| 6fc794ca2e | |||
| 8b4d34a1e8 | |||
| 65c3f8c513 | |||
| 1d326a76a3 | |||
| 625f976f14 | |||
| 67c3ea7c00 | |||
| 797eb34f36 | |||
| 5f2150ddf7 | |||
| c4981b50e5 | |||
| 00a7c97c5e | |||
| eb7fa9528a | |||
| 27d2b631a9 | |||
| bf1086ca39 | |||
| e423864781 | |||
| aed4649ff5 | |||
| 36119848e7 | |||
| 8080746004 | |||
| edaa335b18 | |||
| ae9fba87b5 | |||
| 076efad616 | |||
| df3aaf43d3 | |||
| 75fe61f134 | |||
| 5d5c6ed33a | |||
| d01bd5bd40 | |||
| 03f88b3866 | |||
| 78c2708116 | |||
| e22c6d9c04 | |||
| 08e9579481 | |||
| 61ba602b4b | |||
| bd393dffd4 | |||
| 573890b7ce | |||
| 7d4fbe4267 | |||
| cb978e2fee | |||
| 4e75575b40 | |||
| d7174146e3 | |||
| 325f92f6ca | |||
| 856c345905 | |||
| b2cd5dfb85 | |||
| 462f7a59b5 | |||
| 22689d24ec | |||
| ee303957b8 | |||
| 4055afdf05 | |||
| a1c70a219a | |||
| 3f23b06e24 | |||
| 3151515855 | |||
| 25df9da715 | |||
| 9c2f438476 | |||
| a763602aeb | |||
| 0de3be42cf | |||
| 1545e0eed7 | |||
| 42a7ed6877 | |||
| 98b8aedc4d | |||
| 4812f1d603 | |||
| 137de20cef | |||
| 8ce8199820 | |||
| bb52467f90 | |||
| 8791f7ee97 | |||
| e9af8bfee1 | |||
| c7a2b54d1c | |||
| 6583ff4439 | |||
| 7b08b3e936 | |||
| bd2fc71dc5 | |||
| 4360d49531 | |||
| ae26a19d4a | |||
| 0af97f63e2 | |||
| da732359af | |||
| c659e1ff8f | |||
| fd92884ce5 | |||
| 1db635f24c | |||
| 6e27b3d6d4 | |||
| 1dea0edcf1 | |||
| 1abab41955 | |||
| b22ae28acc | |||
| 2718d895fa | |||
| f4e6913e6e | |||
| 647fbea066 | |||
| b69bd8617f | |||
| 924d2a0d88 | |||
| 17fdc7d246 | |||
| 10fc60def3 | |||
| 1362df8e64 | |||
| b6962296c3 | |||
| cf022ca6a4 | |||
| e2bf27e53f | |||
| d1be38be64 | |||
| 8916c68a0c | |||
| 6faa7e2fc9 | |||
| db6f492aac | |||
| a6093f41bd | |||
| a1dcd2739b | |||
| ef4bb3e341 | |||
| 8c90e2fd58 | |||
| a1156472fb | |||
| d526ff43f2 | |||
| dc6c15e150 | |||
| 0bc6b600a5 | |||
| fb4cf18873 | |||
| edd47814ee | |||
| 107e66e4da | |||
| ec0a9493e2 | |||
| 549a8380c3 | |||
| e0ba030b1f | |||
| 256849f8a6 | |||
| c9c451be65 | |||
| 1fcea083e7 | |||
| 85d6ee5713 | |||
| ec81583741 | |||
| 332da9bf2d | |||
| a0036d925e | |||
| 81a99d6f7d | |||
| e912238574 | |||
| 2d17603703 | |||
| 5d3e580cda | |||
| 93aadc196f | |||
| 9a830e5de6 | |||
| 5f43b360ec | |||
| 7d9ba0e36e | |||
| 6c5e09fd84 | |||
| 5d96534678 | |||
| 5a2ebec473 | |||
| 0cefdcbc20 | |||
| 02b74a5059 | |||
| 2913a0f624 | |||
| 1c58360891 | |||
| 49fc068b38 | |||
| b671595608 | |||
| 4bc51feccd | |||
| 1d5696a08b | |||
| bd2b6e0f93 | |||
| 98c65ff8f4 | |||
| 3addffbd34 | |||
| dbb7e3825d | |||
| 1d1dd87d44 | |||
| 592ccd29e3 | |||
| 0ea9ce1363 | |||
| cc4c7b0d88 | |||
| 800df325a9 | |||
| 1c04aa377c | |||
| 1f1aeaf446 | |||
| 38e9193573 | |||
| 409d6dd71c | |||
| 9c5d5f4318 | |||
| e8dfa056b0 | |||
| 81754b37a4 | |||
| 02e5056987 | |||
| c33b488006 | |||
| 43e49b75de | |||
| e050090f0f | |||
| 5e88fbfad0 | |||
| c9f71ce067 | |||
| 21190bc0c6 | |||
| 2f8c43c689 | |||
| 7a25cb52b2 | |||
| 19bc97a7fd | |||
| df958223b0 | |||
| 72900ef3b3 | |||
| 74ddd09c5d | |||
| fd58c3b3c6 | |||
| e461cb92da | |||
| ba2fd96e88 | |||
| 7cdaacf149 | |||
| 7cfdc81555 | |||
| aeb6babad0 | |||
| 24f38e0c0e | |||
| 8cb9d6858e | |||
| 17629ea1b5 | |||
| 779e7d7667 | |||
| 7117c6f085 | |||
| ba9ebd394b | |||
| 3ed340bde1 | |||
| 7d616cf937 | |||
| fa1c227136 | |||
| 738f24d6c9 | |||
| c33ad3eed7 | |||
| 3e5050ee9a | |||
| 7dce1ee39a | |||
| f30c05b37f | |||
| 7fce8583c8 | |||
| 3a17dd06d8 | |||
| 9d10362e7a | |||
| 3712a80031 | |||
| 930bada737 | |||
| 95eb5f88f3 | |||
| 56f0d67639 | |||
| 0be5c31d4a | |||
| ca03967662 | |||
| 91413c2a89 | |||
| bd109d3700 | |||
| d9de5e5f29 | |||
| 63635ec9fb | |||
| d32380294a | |||
| 8ea6f1168e | |||
| 7595da7645 | |||
| f33af2930e | |||
| 08cfececd9 | |||
| 1aab6c217f | |||
| 396194ae01 | |||
| baea34b6a4 | |||
| 742ee57835 | |||
| 2e4941053c | |||
| 1118d95773 | |||
| e91b53e66d | |||
| f981fe60ff | |||
| 1217d9f0b3 | |||
| bbb187f2c8 | |||
| 10617d1bd5 | |||
| 7ac1c8ab6f | |||
| 4372c9df40 | |||
| c4e8e20f02 | |||
| 09d038fcde | |||
| b5e8cb29dd | |||
| 20dc4f5bc4 | |||
| 1301897f39 | |||
| 2c399860ca | |||
| c7185dcef0 | |||
| 5ab61e7638 | |||
| 4dc4c36581 | |||
| fe774f557c | |||
| 3ecb9d0f86 | |||
| f78a425985 | |||
| 291d92bfc9 | |||
| ffce67e4fd | |||
| 4f85985a09 | |||
| 5efbec1a2e | |||
| 4bb6b2e230 | |||
| c365b1569b | |||
| b38edd1921 | |||
| dfa45e70f4 | |||
| 1f29d85f83 | |||
| 2a6b559b6e | |||
| 6d34fe416d | |||
| c7805f0af1 | |||
| 07d50464cc | |||
| 8373955bf0 | |||
| ca5f317a90 | |||
| d86db6b2cd | |||
| a884ece8b1 | |||
| b15f0a9c54 | |||
| 48667bb50a | |||
| ad5043295f | |||
| 0c0518ff7b | |||
| 52b1a09de0 | |||
| e456761bb9 | |||
| be1b770df8 | |||
| a8e43a3908 | |||
| 47ea3828a1 | |||
| 504235d6db | |||
| 0ffcc9b889 | |||
| 177e61834c | |||
| 2d0f198f58 | |||
| 6ad568c81a | |||
| 25dd891938 | |||
| 2ef673bc84 | |||
| adc3c1e927 | |||
| e2eaf7d58e | |||
| 38a6f8c4a9 | |||
| 8fc44699bc | |||
| 277b67ac84 | |||
| fda3111e43 | |||
| 5c2bd5748d | |||
| 348bee885e | |||
| dd5523de42 | |||
| 4bb9dfb4c9 | |||
| 5440353fb3 | |||
| 9f365727e0 | |||
| df3e96e86a | |||
| 74d73cfe94 | |||
| 1fd76731cd | |||
| 4e1e240f54 | |||
| 85207b3d5c | |||
| 8b80a22018 | |||
| 9c58e82169 | |||
| 42fbcb6f41 | |||
| 2571e5c683 | |||
| c16aa5bbf0 | |||
| dad0cf20eb | |||
| fe563b0828 | |||
| 9e8821594a | |||
| 7fb9d430a9 | |||
| 76dd7f8909 | |||
| 7cd8ba13c0 | |||
| 9a0e85af10 | |||
| ee3131b63d | |||
| 00aed2b33d | |||
| 4fd7182388 | |||
| 173f3cb32a | |||
| d0df31be8b | |||
| e857b0a5f4 | |||
| e5f5e16f9a | |||
| e51ef64b66 | |||
| 76ff12f681 | |||
| 068a08cfcd | |||
| 329636abab | |||
| caef155805 | |||
| ff876266cf | |||
| 9f360c2b9b | |||
| 0621019918 | |||
| 28aa928655 | |||
| cff6a74f16 | |||
| 853bd3947b | |||
| 9ea492f5b7 | |||
| 05044dc871 | |||
| 19fae702a9 | |||
| 994ded8518 | |||
| 1888888650 | |||
| db26eac99b | |||
| a1b98b6e31 | |||
| 698617dc60 | |||
| a6b7e26606 | |||
| 2074df58fb | |||
| e6ab111f4d | |||
| c9936da37f | |||
| 4ce4bd25c4 | |||
| ce3028446b | |||
| 73f1458190 | |||
| 684788cb62 | |||
| 6a1b8f00eb | |||
| 4574e4291b | |||
| aae15bf0b4 | |||
| ae85b7bf2b | |||
| 9dbdae3b90 | |||
| 9649e6d9bf | |||
| 0d7363af23 | |||
| b52c480da3 | |||
| dada91f006 | |||
| 348694d9d4 | |||
| 855e3b3dcc | |||
| 5a8ea4aa41 | |||
| 4bd465f666 | |||
| ad591c07cf | |||
| 1cd00cb6f6 | |||
| cd3aaa47ca | |||
| a05cc03254 |
@@ -15,11 +15,11 @@ If you're interested in making changes to Belle make sure to read the [Belle Rea
|
||||
|
||||
**More than 177,000 sites trust Umbraco**
|
||||
|
||||
For the first time on the Microsoft platform a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developers dream and your users will love it too.
|
||||
For the first time on the Microsoft platform, there is a free user and developer friendly CMS that makes it quick and easy to create websites - or a breeze to build complex web applications. Umbraco has award-winning integration capabilities and supports ASP.NET MVC or Web Forms, including User and Custom Controls, out of the box. It's a developer's dream and your users will love it too.
|
||||
|
||||
Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)) you can be sure that the technology is proven, stable and scales.
|
||||
Used by more than 177,000 active websites including [http://daviscup.com](http://daviscup.com), [http://heinz.com](http://heinz.com), [http://peugeot.com](http://peugeot.com), [http://www.hersheys.com/](http://www.hersheys.com/) and **The Official ASP.NET and IIS.NET website from Microsoft** ([http://asp.net](http://asp.net) / [http://iis.net](http://iis.net)), you can be sure that the technology is proven, stable and scales.
|
||||
|
||||
To view more examples please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies)
|
||||
To view more examples, please visit [http://umbraco.com/why-umbraco/#caseStudies](http://umbraco.com/why-umbraco/#caseStudies)
|
||||
|
||||
## Downloading ##
|
||||
|
||||
@@ -35,6 +35,6 @@ If you want to contribute back to Umbraco you should check out our [guide to con
|
||||
|
||||
## Found a bug? ##
|
||||
|
||||
Another way you can contribute to Umbraco is by providing issue reports, for information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature).
|
||||
Another way you can contribute to Umbraco is by providing issue reports. For information on how to submit an issue report refer to our [online guide for reporting issues](http://our.umbraco.org/contribute/report-an-issue-or-request-a-feature).
|
||||
|
||||
To view existing issues please visit [http://issues.umbraco.org](http://issues.umbraco.org)
|
||||
To view existing issues, please visit [http://issues.umbraco.org](http://issues.umbraco.org).
|
||||
|
||||
@@ -21,14 +21,6 @@ ECHO Building Umbraco %version%
|
||||
|
||||
ReplaceIISExpressPortNumber.exe ..\src\Umbraco.Web.UI\Umbraco.Web.UI.csproj %release%
|
||||
|
||||
ECHO Installing the Microsoft.Bcl.Build package before anything else, otherwise you'd have to run build.cmd twice
|
||||
SET nuGetFolder=%CD%\..\src\packages\
|
||||
..\src\.nuget\NuGet.exe sources Remove -Name MyGetUmbracoCore >NUL
|
||||
..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet
|
||||
|
||||
ECHO Removing the belle build folder and bower_components folder to make sure everything is clean as a whistle
|
||||
RD ..\src\Umbraco.Web.UI.Client\build /Q /S
|
||||
RD ..\src\Umbraco.Web.UI.Client\bower_components /Q /S
|
||||
|
||||
+2
-2
@@ -175,8 +175,8 @@
|
||||
<!-- Copy SQL CE -->
|
||||
<ItemGroup>
|
||||
<SQLCE4Files
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.0\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.0\lib\**\*;..\src\packages\SqlServerCE.4.0.0.0\**\*.nu*"
|
||||
Include="..\src\packages\SqlServerCE.4.0.0.1\**\*.*"
|
||||
Exclude="..\src\packages\SqlServerCE.4.0.0.1\lib\**\*;..\src\packages\SqlServerCE.4.0.0.1\**\*.nu*"
|
||||
/>
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -17,11 +17,10 @@
|
||||
<dependencies>
|
||||
<dependency id="Microsoft.AspNet.Mvc" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebApi" version="[5.2.3,6.0.0)" />
|
||||
<dependency id="Microsoft.Net.Http" version="[2.2.29, 3.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.Identity.Owin" 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.Host.SystemWeb" version="[3.0.1, 4.0.0)" />
|
||||
<dependency id="MiniProfiler" version="[2.1.0, 3.0.0)" />
|
||||
<dependency id="HtmlAgilityPack" version="[1.4.9, 2.0.0)" />
|
||||
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
|
||||
@@ -31,14 +30,13 @@
|
||||
<dependency id="ClientDependency" version="[1.8.4, 2.0.0)" />
|
||||
<dependency id="ClientDependency-Mvc5" version="[1.8.0, 2.0.0)" />
|
||||
<dependency id="AutoMapper" version="[3.0.0, 3.1.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 7.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 9.0.0)" />
|
||||
<dependency id="Examine" version="[0.1.68, 1.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.3.2, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.5.0, 5.0.0)" />
|
||||
<dependency id="ImageProcessor" version="[2.3.3, 3.0.0)" />
|
||||
<dependency id="ImageProcessor.Web" version="[4.5.3, 5.0.0)" />
|
||||
<dependency id="semver" version="[1.1.2, 2.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebHelpers" version="[3.2.3, 4.0.0)" />
|
||||
<dependency id="Microsoft.AspNet.WebPages.Data" version="[3.2.3, 4.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder.AspNet" version="[2.2.0-beta003, 3.0.0)" />
|
||||
<dependency id="UrlRewritingNet" version="[2.0.7, 3.0.0)" />
|
||||
<dependency id="Markdown" version="[1.14.4, 2.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
@@ -73,35 +71,34 @@
|
||||
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
|
||||
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
|
||||
<file src="tools\install.core.ps1" target="tools\install.ps1" />
|
||||
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.pdb" target="lib" />
|
||||
<!-- Added to be able to produce a symbols package -->
|
||||
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.pdb" target="lib" />
|
||||
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
|
||||
<file src="..\_BuildOutput\bin\businesslogic.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\businesslogic.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
|
||||
<file src="..\_BuildOutput\bin\cms.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\cms.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
|
||||
<file src="..\_BuildOutput\bin\controls.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\controls.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
|
||||
<file src="..\_BuildOutput\bin\interfaces.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\interfaces.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Core.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.DataLayer.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.DataLayer.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.editorControls.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.editorControls.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.providers.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.providers.pdb" target="lib" />
|
||||
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\umbraco.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.pdb" target="lib" />
|
||||
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.pdb" target="lib" />
|
||||
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
|
||||
<file src="..\_BuildOutput\bin\UmbracoExamine.pdb" target="lib" />
|
||||
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
|
||||
<file src="..\_BuildOutput\bin\UmbracoExamine.pdb" target="lib" />
|
||||
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
|
||||
</files>
|
||||
</package>
|
||||
@@ -16,7 +16,8 @@
|
||||
<tags>umbraco</tags>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="[$version$]" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
|
||||
<dependency id="Newtonsoft.Json" version="[6.0.8, 9.0.0)" />
|
||||
<dependency id="Umbraco.ModelsBuilder" version="[3.0.2, 4.0.0)" />
|
||||
</dependencies>
|
||||
</metadata>
|
||||
<files>
|
||||
|
||||
@@ -77,4 +77,8 @@
|
||||
<section alias="uGoLiveDashboardSection" xdt:Locator="Match(alias)" xdt:Transform="Remove" />
|
||||
|
||||
<section alias="ExamineManagement" xdt:Locator="Match(alias)" xdt:Transform="Remove" />
|
||||
|
||||
<section alias="StartupDashboardSection">
|
||||
<tab caption="Change Password" xdt:Locator="Match(caption)" xdt:Transform="Remove" />
|
||||
</section>
|
||||
</dashBoard>
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
When upgrading your website using NuGet you should answer "No" to the questions to overwrite the Web.config
|
||||
file (and config files in the config folder).
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
We've done our best to transform your configuration files but in case something is not quite right: remember we
|
||||
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
<section name="ExamineLuceneIndexSets" type="Examine.LuceneEngine.Config.IndexSets, Examine" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="SetAttributes(type,requirePermission)" />
|
||||
|
||||
<sectionGroup name="applicationSettings" xdt:Locator="Match(name)">
|
||||
<section name="umbraco.presentation.Properties.Settings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</sectionGroup>
|
||||
<section name="umbraco.presentation.Properties.Settings" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
</sectionGroup>
|
||||
<sectionGroup name="system.web.webPages.razor" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<sectionGroup name="umbracoConfiguration" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing">
|
||||
<section name="settings" type="Umbraco.Core.Configuration.UmbracoSettings.UmbracoSettingsSection, Umbraco.Core" requirePermission="false" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
@@ -21,8 +21,10 @@
|
||||
<appSettings xdt:Transform="InsertIfMissing" />
|
||||
<appSettings>
|
||||
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
<add key="Umbraco.ModelsBuilder.Enable" value="false" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
<add key="Umbraco.ModelsBuilder.ModelsMode" value="Nothing" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
|
||||
</appSettings>
|
||||
|
||||
|
||||
<umbracoConfiguration xdt:Transform="InsertIfMissing">
|
||||
<settings configSource="config\umbracoSettings.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
<BaseRestExtensions configSource="config\BaseRestExtensions.config" xdt:Locator="Match(configSource)" xdt:Transform="InsertIfMissing" />
|
||||
@@ -37,7 +39,7 @@
|
||||
<DbProviderFactories xdt:Transform="InsertIfMissing">
|
||||
<remove invariant="System.Data.SqlServerCe.4.0" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
|
||||
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="Remove" />
|
||||
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
|
||||
<add invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(type)" />
|
||||
@@ -48,13 +50,15 @@
|
||||
<system.web xdt:Transform="InsertIfMissing" />
|
||||
<system.web>
|
||||
<siteMap xdt:Transform="Remove" />
|
||||
<siteMap xdt:Transform="InsertIfMissing">
|
||||
<siteMap xdt:Transform="InsertIfMissing">
|
||||
<providers xdt:Transform="InsertIfMissing">
|
||||
<remove name="MySqlSiteMapProvider" xdt:Transform="InsertIfMissing" />
|
||||
</providers>
|
||||
</siteMap>
|
||||
</siteMap>
|
||||
<httpRuntime xdt:Transform="InsertIfMissing" />
|
||||
<httpRuntime targetFramework="4.5" maxRequestLength="1048576" fcnMode="Single" xdt:Transform="SetAttributes(targetFramework,fcnMode,maxRequestLength)" />
|
||||
<httpRuntime maxRequestLength="51200" fcnMode="Single" xdt:Transform="SetAttributes(fcnMode,maxRequestLength)" />
|
||||
<httpRuntime targetFramework="4.5" xdt:Locator="Condition(count(@targetFramework) != 1)" xdt:Transform="SetAttributes(targetFramework)" />
|
||||
|
||||
<membership defaultProvider="DefaultMembershipProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove" />
|
||||
<roleManager defaultProvider="DefaultRoleProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>
|
||||
<profile defaultProvider="DefaultProfileProvider" xdt:Locator="Match(defaultProvider)" xdt:Transform="Remove"/>>
|
||||
@@ -63,8 +67,7 @@
|
||||
<compilation>
|
||||
<assemblies xdt:Transform="InsertIfMissing" />
|
||||
<assemblies>
|
||||
<add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)"
|
||||
xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Web.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
@@ -78,6 +81,56 @@
|
||||
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<add assembly="System.Web.WebPages, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<add assembly="System.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Collections.Concurrent, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ComponentModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ComponentModel.Annotations, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ComponentModel.EventBasedAsync, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Contracts, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Debug, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Tools, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Diagnostics.Tracing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Dynamic.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Globalization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.IO, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq.Expressions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Linq.Queryable, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.NetworkInformation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Net.Requests, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ObjectModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Emit, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Emit.ILGeneration, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Emit.Lightweight, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Reflection.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Resources.ResourceManager, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.InteropServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.InteropServices.WindowsRuntime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Serialization.Json, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Serialization.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Runtime.Serialization.Xml, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Security.Principal, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Duplex, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Http, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.NetTcp, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Primitives, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.ServiceModel.Security, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Text.Encoding, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Text.Encoding.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Text.RegularExpressions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Threading, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Threading.Tasks, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Threading.Tasks.Parallel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Xml.ReaderWriter, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Xml.XDocument, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
<add assembly="System.Xml.XmlSerializer, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" xdt:Locator="Match(assembly)" xdt:Transform="InsertIfMissing" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
|
||||
@@ -86,11 +139,113 @@
|
||||
<remove assembly="System.Web.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Collections" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Collections.Concurrent" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ComponentModel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ComponentModel.Annotations" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ComponentModel.EventBasedAsync" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Contracts" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Debug" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Tools" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Diagnostics.Tracing" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Dynamic.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Globalization" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.IO" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq.Expressions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Linq.Queryable" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.NetworkInformation" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Net.Requests" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ObjectModel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Emit" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Emit.ILGeneration" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Emit.Lightweight" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Reflection.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Resources.ResourceManager" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.InteropServices" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.InteropServices.WindowsRuntime" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Numerics" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Serialization.Json" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Serialization.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Runtime.Serialization.Xml" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Security.Principal" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Duplex" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Http" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.NetTcp" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.ServiceModel.Security" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Text.Encoding" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Text.Encoding.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Text.RegularExpressions" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Threading" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Threading.Tasks" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Threading.Tasks.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Xml.ReaderWriter" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Xml.XDocument" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
<remove assembly="System.Xml.XmlSerializer" xdt:Locator="Match(assembly)" xdt:Transform="Remove" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
<compilation>
|
||||
<assemblies>
|
||||
<remove assembly="System.Web.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Collections" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Collections.Concurrent" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ComponentModel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ComponentModel.Annotations" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ComponentModel.EventBasedAsync" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Contracts" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Debug" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Tools" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Diagnostics.Tracing" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Dynamic.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Globalization" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.IO" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq.Expressions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Linq.Queryable" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.NetworkInformation" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Net.Requests" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ObjectModel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Emit" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Emit.ILGeneration" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Emit.Lightweight" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Reflection.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Resources.ResourceManager" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.InteropServices" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.InteropServices.WindowsRuntime" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Numerics" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Serialization.Json" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Serialization.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Runtime.Serialization.Xml" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Security.Principal" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Duplex" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Http" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.NetTcp" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Primitives" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.ServiceModel.Security" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Text.Encoding" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Text.Encoding.Extensions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Text.RegularExpressions" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Threading" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Threading.Tasks" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Threading.Tasks.Parallel" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Xml.ReaderWriter" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Xml.XDocument" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
<remove assembly="System.Xml.XmlSerializer" xdt:Locator="Match(assembly)" xdt:Transform="InsertBefore(/configuration/system.web/compilation/assemblies/add)" />
|
||||
</assemblies>
|
||||
</compilation>
|
||||
|
||||
@@ -125,6 +280,8 @@
|
||||
<add name="umbracoRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="viewstateMoverModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="umbracoBaseRequestModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<!-- Note, we're removing the one that starts with a space here, don't correct it -->
|
||||
<!-- This to fix a quirk we for a lot of releases where we added it with the space by default -->
|
||||
<add name=" UmbracoModule" xdt:Locator="Match(name)" xdt:Transform="Remove" />
|
||||
<add name="UmbracoModule" type="Umbraco.Web.UmbracoModule,umbraco" xdt:Locator="Match(name)" xdt:Transform="InsertIfMissing" />
|
||||
</modules>
|
||||
@@ -146,19 +303,17 @@
|
||||
|
||||
<security xdt:Transform="InsertIfMissing">
|
||||
<requestFiltering xdt:Transform="InsertIfMissing">
|
||||
<requestLimits maxAllowedContentLength="1073741824" xdt:Transform="InsertIfMissing" />
|
||||
<requestLimits maxAllowedContentLength="52428800" xdt:Transform="InsertIfMissing" />
|
||||
</requestFiltering>
|
||||
</security>
|
||||
|
||||
</system.webServer>
|
||||
|
||||
<system.codedom xdt:Transform="Remove" />
|
||||
</system.webServer>
|
||||
|
||||
<runtime xdt:Transform="InsertIfMissing" />
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1" xdt:Transform="InsertIfMissing" />
|
||||
</runtime>
|
||||
|
||||
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='HtmlAgilityPack')" xdt:Transform="Remove" />
|
||||
@@ -171,7 +326,7 @@
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.OAuth')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='Microsoft.Owin.Security.Cookies')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
|
||||
<dependentAssembly xdt:Locator="Condition(./_defaultNamespace:assemblyIdentity/@name='System.Net.Http.Formatting')" xdt:Transform="Remove" />
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
|
||||
@@ -180,7 +335,7 @@
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="HtmlAgilityPack" publicKeyToken="bd319b19eaf3b43a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.4.9.0" newVersion="1.4.9.0" />
|
||||
</dependentAssembly>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0"/>
|
||||
@@ -191,12 +346,12 @@
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.0.1" newVersion="4.0.0.1" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.WebPages.Razor" publicKeyToken="31bf3856ad364e35" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
@@ -208,16 +363,16 @@
|
||||
<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" />
|
||||
</dependentAssembly>
|
||||
</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" />
|
||||
</dependentAssembly>
|
||||
</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" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
</dependentAssembly>
|
||||
<dependentAssembly xdt:Transform="Insert">
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
|
||||
</dependentAssembly>
|
||||
@@ -225,19 +380,19 @@
|
||||
</runtime>
|
||||
|
||||
<system.web.webPages.razor xdt:Transform="Remove" />
|
||||
|
||||
|
||||
<location path="umbraco" xdt:Locator="Match(path)" xdt:Transform="InsertIfMissing" />
|
||||
<location path="umbraco" xdt:Locator="Match(path)">
|
||||
<system.webServer xdt:Transform="InsertIfMissing">
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
</system.webServer>
|
||||
</location>
|
||||
|
||||
|
||||
<location path="App_Plugins" xdt:Locator="Match(path)" xdt:Transform="InsertIfMissing" />
|
||||
<location path="App_Plugins" xdt:Locator="Match(path)">
|
||||
<system.webServer xdt:Transform="InsertIfMissing">
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
<urlCompression doStaticCompression="false" doDynamicCompression="false" dynamicCompressionBeforeCache="false" xdt:Transform="SetAttributes(doStaticCompression,doDynamicCompression,dynamicCompressionBeforeCache)" />
|
||||
</system.webServer>
|
||||
</location>
|
||||
|
||||
|
||||
</configuration>
|
||||
@@ -1,18 +1,30 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
|
||||
Write-Host "copyLogsPath:" "${copyLogsPath}"
|
||||
$umbracoBinFolder = Join-Path $projectPath "bin"
|
||||
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# After backing up, remove all umbraco dlls from bin folder in case dll files are included in the VS project
|
||||
# See: http://issues.umbraco.org/issue/U4-4930
|
||||
$umbracoBinFolder = Join-Path $projectDestinationPath "bin"
|
||||
|
||||
if(Test-Path $umbracoBinFolder) {
|
||||
$umbracoBinBackupPath = Join-Path $backupPath "bin"
|
||||
|
||||
@@ -20,7 +32,7 @@ if ($project) {
|
||||
|
||||
robocopy $umbracoBinFolder $umbracoBinBackupPath /e /LOG:$copyLogsPath\UmbracoBinBackup.log
|
||||
|
||||
# Delete files Umbraco brings in
|
||||
# Delete files Umbraco ships with
|
||||
if(Test-Path $umbracoBinFolder\businesslogic.dll) { Remove-Item $umbracoBinFolder\businesslogic.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\cms.dll) { Remove-Item $umbracoBinFolder\cms.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\controls.dll) { Remove-Item $umbracoBinFolder\controls.dll -Force -Confirm:$false }
|
||||
@@ -36,16 +48,18 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\umbraco.DataLayer.dll) { Remove-Item $umbracoBinFolder\umbraco.DataLayer.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.editorControls.dll) { Remove-Item $umbracoBinFolder\umbraco.editorControls.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.MacroEngines.dll) { Remove-Item $umbracoBinFolder\umbraco.MacroEngines.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll) { Remove-Item $umbracoBinFolder\Umbraco.ModelsBuilder.AspNet.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll) { Remove-Item $umbracoBinFolder\UrlRewritingNet.UrlRewriter.dll -Force -Confirm:$false }
|
||||
|
||||
# Delete files Umbraco depends upon
|
||||
$amd64Folder = Join-Path $projectDestinationPath "bin\amd64"
|
||||
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
|
||||
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $projectDestinationPath "bin\x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
$x86Folder = Join-Path $umbracoBinFolder "x86"
|
||||
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\AutoMapper.dll) { Remove-Item $umbracoBinFolder\AutoMapper.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\AutoMapper.Net4.dll) { Remove-Item $umbracoBinFolder\AutoMapper.Net4.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\ClientDependency.Core.dll) { Remove-Item $umbracoBinFolder\ClientDependency.Core.dll -Force -Confirm:$false }
|
||||
@@ -59,6 +73,8 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\Lucene.Net.dll) { Remove-Item $umbracoBinFolder\Lucene.Net.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Core.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.AspNet.Identity.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.CSharp.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.CodeAnalysis.dll) { Remove-Item $umbracoBinFolder\Microsoft.CodeAnalysis.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Host.SystemWeb.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Microsoft.Owin.Security.dll) { Remove-Item $umbracoBinFolder\Microsoft.Owin.Security.dll -Force -Confirm:$false }
|
||||
@@ -72,6 +88,8 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\Newtonsoft.Json.dll) { Remove-Item $umbracoBinFolder\Newtonsoft.Json.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Owin.dll) { Remove-Item $umbracoBinFolder\Owin.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\Semver.dll) { Remove-Item $umbracoBinFolder\Semver.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Collections.Immutable.dll) { Remove-Item $umbracoBinFolder\System.Collections.Immutable.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Reflection.Metadata.dll) { Remove-Item $umbracoBinFolder\System.Reflection.Metadata.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Extensions.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Extensions.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Formatting.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Formatting.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Net.Http.Primitives.dll) { Remove-Item $umbracoBinFolder\System.Net.Http.Primitives.dll -Force -Confirm:$false }
|
||||
@@ -82,6 +100,6 @@ if ($project) {
|
||||
if(Test-Path $umbracoBinFolder\System.Web.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.Razor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Deployment.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Deployment.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
|
||||
if(Test-Path $umbracoBinFolder\System.Web.WebPages.Razor.dll) { Remove-Item $umbracoBinFolder\System.Web.WebPages.Razor.dll -Force -Confirm:$false }
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,33 @@
|
||||
param($rootPath, $toolsPath, $package, $project)
|
||||
param($installPath, $toolsPath, $package, $project)
|
||||
|
||||
Write-Host "installPath:" "${installPath}"
|
||||
Write-Host "toolsPath:" "${toolsPath}"
|
||||
|
||||
Write-Host " "
|
||||
|
||||
if ($project) {
|
||||
$dateTime = Get-Date -Format yyyyMMdd-HHmmss
|
||||
$backupPath = Join-Path (Split-Path $project.FullName -Parent) "\App_Data\NuGetBackup\$dateTime"
|
||||
|
||||
# Create paths and list them
|
||||
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
|
||||
Write-Host "projectPath:" "${projectPath}"
|
||||
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup\$dateTime"
|
||||
Write-Host "backupPath:" "${backupPath}"
|
||||
$copyLogsPath = Join-Path $backupPath "CopyLogs"
|
||||
$projectDestinationPath = Split-Path $project.FullName -Parent
|
||||
Write-Host "copyLogsPath:" "${copyLogsPath}"
|
||||
$webConfigSource = Join-Path $projectPath "Web.config"
|
||||
Write-Host "webConfigSource:" "${webConfigSource}"
|
||||
$configFolder = Join-Path $projectPath "Config"
|
||||
Write-Host "configFolder:" "${configFolder}"
|
||||
|
||||
# Create backup folder and logs folder if it doesn't exist yet
|
||||
New-Item -ItemType Directory -Force -Path $backupPath
|
||||
New-Item -ItemType Directory -Force -Path $copyLogsPath
|
||||
|
||||
# Create a backup of original web.config
|
||||
$webConfigSource = Join-Path $projectDestinationPath "Web.config"
|
||||
Copy-Item $webConfigSource $backupPath -Force
|
||||
|
||||
# Backup config files folder
|
||||
$configFolder = Join-Path $projectDestinationPath "Config"
|
||||
# Backup config files folder
|
||||
if(Test-Path $configFolder) {
|
||||
$umbracoBackupPath = Join-Path $backupPath "Config"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
@@ -24,32 +36,24 @@ if ($project) {
|
||||
}
|
||||
|
||||
# Copy umbraco and umbraco_files from package to project folder
|
||||
# This is only done when these folders already exist because we
|
||||
# only want to do this for upgrades
|
||||
$umbracoFolder = Join-Path $projectDestinationPath "Umbraco"
|
||||
if(Test-Path $umbracoFolder) {
|
||||
$umbracoFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco"
|
||||
|
||||
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
}
|
||||
$umbracoFolder = Join-Path $projectPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoFolder
|
||||
$umbracoFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco"
|
||||
$umbracoBackupPath = Join-Path $backupPath "Umbraco"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoBackupPath
|
||||
robocopy $umbracoFolder $umbracoBackupPath /e /LOG:$copyLogsPath\UmbracoBackup.log
|
||||
robocopy $umbracoFolderSource $umbracoFolder /is /it /e /xf UI.xml /LOG:$copyLogsPath\UmbracoCopy.log
|
||||
|
||||
$umbracoClientFolder = Join-Path $projectDestinationPath "Umbraco_Client"
|
||||
if(Test-Path $umbracoClientFolder) {
|
||||
$umbracoClientFolderSource = Join-Path $rootPath "UmbracoFiles\Umbraco_Client"
|
||||
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
}
|
||||
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientFolder
|
||||
$umbracoClientFolderSource = Join-Path $installPath "UmbracoFiles\Umbraco_Client"
|
||||
$umbracoClientBackupPath = Join-Path $backupPath "Umbraco_Client"
|
||||
New-Item -ItemType Directory -Force -Path $umbracoClientBackupPath
|
||||
robocopy $umbracoClientFolder $umbracoClientBackupPath /e /LOG:$copyLogsPath\UmbracoClientBackup.log
|
||||
robocopy $umbracoClientFolderSource $umbracoClientFolder /is /it /e /LOG:$copyLogsPath\UmbracoClientCopy.log
|
||||
|
||||
$copyWebconfig = $true
|
||||
$destinationWebConfig = Join-Path $projectDestinationPath "Web.config"
|
||||
$destinationWebConfig = Join-Path $projectPath "Web.config"
|
||||
|
||||
if(Test-Path $destinationWebConfig)
|
||||
{
|
||||
@@ -71,11 +75,11 @@ if ($project) {
|
||||
|
||||
if($copyWebconfig -eq $true)
|
||||
{
|
||||
$packageWebConfigSource = Join-Path $rootPath "UmbracoFiles\Web.config"
|
||||
$packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config"
|
||||
Copy-Item $packageWebConfigSource $destinationWebConfig -Force
|
||||
}
|
||||
|
||||
$installFolder = Join-Path $projectDestinationPath "Install"
|
||||
$installFolder = Join-Path $projectPath "Install"
|
||||
if(Test-Path $installFolder) {
|
||||
Remove-Item $installFolder -Force -Recurse -Confirm:$false
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.4.0
|
||||
beta2
|
||||
7.4.2
|
||||
@@ -47,13 +47,15 @@
|
||||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>True</Private>
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.0\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
|
||||
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
|
||||
</packages>
|
||||
+2
-2
@@ -11,5 +11,5 @@ using System.Resources;
|
||||
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.4.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.4.0-beta2")]
|
||||
[assembly: AssemblyFileVersion("7.4.2")]
|
||||
[assembly: AssemblyInformationalVersion("7.4.2")]
|
||||
@@ -7,14 +7,22 @@ using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
/// <summary>
|
||||
/// Interface describing this cache provider as a wrapper for another
|
||||
/// </summary>
|
||||
internal interface IRuntimeCacheProviderWrapper
|
||||
{
|
||||
IRuntimeCacheProvider InnerProvider { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A wrapper for any IRuntimeCacheProvider that ensures that all inserts and returns
|
||||
/// are a deep cloned copy of the item when the item is IDeepCloneable and that tracks changes are
|
||||
/// reset if the object is TracksChangesEntityBase
|
||||
/// </summary>
|
||||
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider
|
||||
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider, IRuntimeCacheProviderWrapper
|
||||
{
|
||||
internal IRuntimeCacheProvider InnerProvider { get; private set; }
|
||||
public IRuntimeCacheProvider InnerProvider { get; private set; }
|
||||
|
||||
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
|
||||
{
|
||||
|
||||
@@ -11,35 +11,35 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
internal class DefaultRepositoryCachePolicy<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
|
||||
/// <remarks>
|
||||
/// This cache policy uses sliding expiration and caches instances for 5 minutes. However if allow zero count is true, then we use the
|
||||
/// default policy with no expiry.
|
||||
/// </remarks>
|
||||
internal class DefaultRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private readonly RepositoryCachePolicyOptions _options;
|
||||
protected IRuntimeCacheProvider Cache { get; private set; }
|
||||
private Action _action;
|
||||
|
||||
public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
: base(cache)
|
||||
{
|
||||
if (options == null) throw new ArgumentNullException("options");
|
||||
|
||||
_options = options;
|
||||
Cache = cache;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
public string GetCacheIdKey(object id)
|
||||
protected string GetCacheIdKey(object id)
|
||||
{
|
||||
if (id == null) throw new ArgumentNullException("id");
|
||||
|
||||
return string.Format("{0}{1}", GetCacheTypeKey(), id);
|
||||
}
|
||||
|
||||
public string GetCacheTypeKey()
|
||||
protected string GetCacheTypeKey()
|
||||
{
|
||||
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
|
||||
}
|
||||
|
||||
public void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
@@ -54,7 +54,9 @@ namespace Umbraco.Core.Cache
|
||||
//just to be safe, we cannot cache an item without an identity
|
||||
if (entity.HasIdentity)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity);
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => entity,
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
@@ -79,24 +81,29 @@ namespace Umbraco.Core.Cache
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
persistMethod(entity);
|
||||
|
||||
//set the disposal action
|
||||
var cacheKey = GetCacheIdKey(entity.Id);
|
||||
SetCacheAction(() =>
|
||||
try
|
||||
{
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
persistMethod(entity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//set the disposal action
|
||||
var cacheKey = GetCacheIdKey(entity.Id);
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
Cache.ClearCacheItem(cacheKey);
|
||||
//If there's a GetAllCacheAllowZeroCount cache, ensure it is cleared
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -113,13 +120,13 @@ namespace Umbraco.Core.Cache
|
||||
return entity;
|
||||
}
|
||||
|
||||
public TEntity Get(TId id)
|
||||
public override TEntity Get(TId id)
|
||||
{
|
||||
var cacheKey = GetCacheIdKey(id);
|
||||
return Cache.GetCacheItem<TEntity>(cacheKey);
|
||||
}
|
||||
|
||||
public bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -128,7 +135,7 @@ namespace Umbraco.Core.Cache
|
||||
return fromCache != null || getFromRepo(id);
|
||||
}
|
||||
|
||||
public virtual TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
if (getFromRepo == null) throw new ArgumentNullException("getFromRepo");
|
||||
|
||||
@@ -158,8 +165,7 @@ namespace Umbraco.Core.Cache
|
||||
else if (_options.GetAllCacheAllowZeroCount)
|
||||
{
|
||||
//if the repository allows caching a zero count, then check the zero count cache
|
||||
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
|
||||
if (zeroCount != null && zeroCount.Any() == false)
|
||||
if (HasZeroCountCache())
|
||||
{
|
||||
//there is a zero count cache so return an empty list
|
||||
return new TEntity[] {};
|
||||
@@ -179,28 +185,27 @@ namespace Umbraco.Core.Cache
|
||||
return entityCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up the zero count cache, must return null if it doesn't exist
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected bool HasZeroCountCache()
|
||||
{
|
||||
var zeroCount = Cache.GetCacheItem<TEntity[]>(GetCacheTypeKey());
|
||||
return (zeroCount != null && zeroCount.Any() == false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the lookup for all entities of this type from the cache
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected virtual TEntity[] GetAllFromCache()
|
||||
protected TEntity[] GetAllFromCache()
|
||||
{
|
||||
var allEntities = Cache.GetCacheItemsByKeySearch<TEntity>(GetCacheTypeKey())
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
return allEntities.Any() ? allEntities : new TEntity[] {};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The disposal performs the caching
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal for a single entity
|
||||
@@ -216,7 +221,9 @@ namespace Umbraco.Core.Cache
|
||||
//just to be safe, we cannot cache an item without an identity
|
||||
if (entity.HasIdentity)
|
||||
{
|
||||
Cache.InsertCacheItem(cacheKey, () => entity);
|
||||
Cache.InsertCacheItem(cacheKey, () => entity,
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -235,6 +242,7 @@ namespace Umbraco.Core.Cache
|
||||
{
|
||||
//there was nothing returned but we want to cache a zero count result so add an TEntity[] to the cache
|
||||
// to signify that there is a zero count cache
|
||||
//NOTE: Don't set expiry/sliding for a zero count
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new TEntity[] {});
|
||||
}
|
||||
else
|
||||
@@ -247,20 +255,14 @@ namespace Umbraco.Core.Cache
|
||||
//just to be safe, we cannot cache an item without an identity
|
||||
if (localCopy.HasIdentity)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy);
|
||||
Cache.InsertCacheItem(GetCacheIdKey(entity.Id), () => localCopy,
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
protected void SetCacheAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Collections;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -9,11 +11,157 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <typeparam name="TEntity"></typeparam>
|
||||
/// <typeparam name="TId"></typeparam>
|
||||
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : DefaultRepositoryCachePolicy<TEntity, TId>
|
||||
internal class FullDataSetRepositoryCachePolicy<TEntity, TId> : RepositoryCachePolicyBase<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache) : base(cache, new RepositoryCachePolicyOptions())
|
||||
private readonly Func<TEntity, TId> _getEntityId;
|
||||
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
|
||||
private readonly bool _expires;
|
||||
|
||||
public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
|
||||
: base(cache)
|
||||
{
|
||||
_getEntityId = getEntityId;
|
||||
_getAllFromRepo = getAllFromRepo;
|
||||
_expires = expires;
|
||||
}
|
||||
|
||||
private bool? _hasZeroCountCache;
|
||||
|
||||
|
||||
protected string GetCacheTypeKey()
|
||||
{
|
||||
return string.Format("uRepo_{0}_", typeof(TEntity).Name);
|
||||
}
|
||||
|
||||
public override void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
try
|
||||
{
|
||||
persistMethod(entity);
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Remove(TEntity entity, Action<TEntity> persistMethod)
|
||||
{
|
||||
if (entity == null) throw new ArgumentNullException("entity");
|
||||
if (persistMethod == null) throw new ArgumentNullException("persistMethod");
|
||||
|
||||
try
|
||||
{
|
||||
persistMethod(entity);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//Clear all
|
||||
Cache.ClearCacheItem(GetCacheTypeKey());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public override TEntity Get(TId id, Func<TId, TEntity> getFromRepo)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return from the repo
|
||||
if (found == null) return getFromRepo(id);
|
||||
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
|
||||
if (entity == null) return null;
|
||||
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
return (TEntity)entity.DeepClone();
|
||||
}
|
||||
|
||||
public override TEntity Get(TId id)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return null
|
||||
if (found == null) return null;
|
||||
var entity = found.FirstOrDefault(x => _getEntityId(x).Equals(id));
|
||||
if (entity == null) return null;
|
||||
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
return (TEntity)entity.DeepClone();
|
||||
}
|
||||
|
||||
public override bool Exists(TId id, Func<TId, bool> getFromRepo)
|
||||
{
|
||||
//Force get all with cache
|
||||
var found = GetAll(new TId[] { }, ids => _getAllFromRepo().WhereNotNull());
|
||||
|
||||
//we don't have anything in cache (this should never happen), just return from the repo
|
||||
return found == null
|
||||
? getFromRepo(id)
|
||||
: found.Any(x => _getEntityId(x).Equals(id));
|
||||
}
|
||||
|
||||
public override TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
//process getting all including setting the cache callback
|
||||
var result = PerformGetAll(getFromRepo);
|
||||
|
||||
//now that the base result has been calculated, they will all be cached.
|
||||
// Now we can just filter by ids if they have been supplied
|
||||
|
||||
return (ids.Any()
|
||||
? result.Where(x => ids.Contains(_getEntityId(x))).ToArray()
|
||||
: result)
|
||||
//We must ensure to deep clone each one out manually since the deep clone list only clones one way
|
||||
.Select(x => (TEntity)x.DeepClone())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private TEntity[] PerformGetAll(Func<TId[], IEnumerable<TEntity>> getFromRepo)
|
||||
{
|
||||
var allEntities = GetAllFromCache();
|
||||
if (allEntities.Any())
|
||||
{
|
||||
return allEntities;
|
||||
}
|
||||
|
||||
//check the zero count cache
|
||||
if (HasZeroCountCache())
|
||||
{
|
||||
//there is a zero count cache so return an empty list
|
||||
return new TEntity[] { };
|
||||
}
|
||||
|
||||
//we need to do the lookup from the repo
|
||||
var entityCollection = getFromRepo(new TId[] { })
|
||||
//ensure we don't include any null refs in the returned collection!
|
||||
.WhereNotNull()
|
||||
.ToArray();
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(entityCollection);
|
||||
|
||||
return entityCollection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -21,37 +169,61 @@ namespace Umbraco.Core.Cache
|
||||
/// </summary>
|
||||
/// <param name="cacheKey"></param>
|
||||
/// <param name="entity"></param>
|
||||
protected override void SetCacheAction(string cacheKey, TEntity entity)
|
||||
protected void SetCacheAction(string cacheKey, TEntity entity)
|
||||
{
|
||||
//do nothing
|
||||
//No-op
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal for an entity collection
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <param name="entityCollection"></param>
|
||||
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
|
||||
protected void SetCacheAction(TEntity[] entityCollection)
|
||||
{
|
||||
//for this type of caching policy, we don't want to cache any GetAll request containing specific Ids
|
||||
if (ids.Any()) return;
|
||||
|
||||
//set the disposal action
|
||||
SetCacheAction(() =>
|
||||
{
|
||||
//We want to cache the result as a single collection
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
|
||||
|
||||
if (_expires)
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection),
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
isSliding: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
Cache.InsertCacheItem(GetCacheTypeKey(), () => new DeepCloneableList<TEntity>(entityCollection));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up the zero count cache, must return null if it doesn't exist
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected bool HasZeroCountCache()
|
||||
{
|
||||
if (_hasZeroCountCache.HasValue)
|
||||
return _hasZeroCountCache.Value;
|
||||
|
||||
_hasZeroCountCache = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey()) != null;
|
||||
return _hasZeroCountCache.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This policy will cache the full data set as a single collection
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override TEntity[] GetAllFromCache()
|
||||
protected TEntity[] GetAllFromCache()
|
||||
{
|
||||
var found = Cache.GetCacheItem<DeepCloneableList<TEntity>>(GetCacheTypeKey());
|
||||
|
||||
//This method will get called before checking for zero count cache, so we'll just set the flag here
|
||||
_hasZeroCountCache = found != null;
|
||||
|
||||
return found == null ? new TEntity[] { } : found.WhereNotNull().ToArray();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
@@ -11,15 +13,21 @@ namespace Umbraco.Core.Cache
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
|
||||
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache)
|
||||
private readonly Func<TEntity, TId> _getEntityId;
|
||||
private readonly Func<IEnumerable<TEntity>> _getAllFromRepo;
|
||||
private readonly bool _expires;
|
||||
|
||||
public FullDataSetRepositoryCachePolicyFactory(IRuntimeCacheProvider runtimeCache, Func<TEntity, TId> getEntityId, Func<IEnumerable<TEntity>> getAllFromRepo, bool expires)
|
||||
{
|
||||
_runtimeCache = runtimeCache;
|
||||
_getEntityId = getEntityId;
|
||||
_getAllFromRepo = getAllFromRepo;
|
||||
_expires = expires;
|
||||
}
|
||||
|
||||
public virtual IRepositoryCachePolicy<TEntity, TId> CreatePolicy()
|
||||
{
|
||||
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache);
|
||||
return new FullDataSetRepositoryCachePolicy<TEntity, TId>(_runtimeCache, _getEntityId, _getAllFromRepo, _expires);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,9 +10,7 @@ namespace Umbraco.Core.Cache
|
||||
TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
|
||||
TEntity Get(TId id);
|
||||
bool Exists(TId id, Func<TId, bool> getFromRepo);
|
||||
|
||||
string GetCacheIdKey(object id);
|
||||
string GetCacheTypeKey();
|
||||
|
||||
void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
|
||||
void Remove(TEntity entity, Action<TEntity> persistMethod);
|
||||
TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Cache
|
||||
/// </remarks>
|
||||
public class IsolatedRuntimeCache
|
||||
{
|
||||
private readonly Func<Type, IRuntimeCacheProvider> _cacheFactory;
|
||||
internal Func<Type, IRuntimeCacheProvider> CacheFactory { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor that allows specifying a factory for the type of runtime isolated cache to create
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <param name="cacheFactory"></param>
|
||||
public IsolatedRuntimeCache(Func<Type, IRuntimeCacheProvider> cacheFactory)
|
||||
{
|
||||
_cacheFactory = cacheFactory;
|
||||
CacheFactory = cacheFactory;
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<Type, IRuntimeCacheProvider> _isolatedCache = new ConcurrentDictionary<Type, IRuntimeCacheProvider>();
|
||||
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <returns></returns>
|
||||
public IRuntimeCacheProvider GetOrCreateCache<T>()
|
||||
{
|
||||
return _isolatedCache.GetOrAdd(typeof(T), type => _cacheFactory(type));
|
||||
return _isolatedCache.GetOrAdd(typeof(T), type => CacheFactory(type));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -41,7 +41,7 @@ namespace Umbraco.Core.Cache
|
||||
/// <returns></returns>
|
||||
public IRuntimeCacheProvider GetOrCreateCache(Type type)
|
||||
{
|
||||
return _isolatedCache.GetOrAdd(type, t => _cacheFactory(t));
|
||||
return _isolatedCache.GetOrAdd(type, t => CacheFactory(t));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
|
||||
namespace Umbraco.Core.Cache
|
||||
{
|
||||
internal abstract class RepositoryCachePolicyBase<TEntity, TId> : DisposableObject, IRepositoryCachePolicy<TEntity, TId>
|
||||
where TEntity : class, IAggregateRoot
|
||||
{
|
||||
private Action _action;
|
||||
|
||||
protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache)
|
||||
{
|
||||
if (cache == null) throw new ArgumentNullException("cache");
|
||||
|
||||
Cache = cache;
|
||||
}
|
||||
|
||||
protected IRuntimeCacheProvider Cache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The disposal performs the caching
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
if (_action != null)
|
||||
{
|
||||
_action();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the action to execute on disposal
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
protected void SetCacheAction(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public abstract TEntity Get(TId id, Func<TId, TEntity> getFromRepo);
|
||||
public abstract TEntity Get(TId id);
|
||||
public abstract bool Exists(TId id, Func<TId, bool> getFromRepo);
|
||||
public abstract void CreateOrUpdate(TEntity entity, Action<TEntity> persistMethod);
|
||||
public abstract void Remove(TEntity entity, Action<TEntity> persistMethod);
|
||||
public abstract TEntity[] GetAll(TId[] ids, Func<TId[], IEnumerable<TEntity>> getFromRepo);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Core.Cache
|
||||
|
||||
protected override void SetCacheAction(TId[] ids, TEntity[] entityCollection)
|
||||
{
|
||||
//do nothing
|
||||
//no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,8 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public class CacheHelper
|
||||
{
|
||||
private readonly IsolatedRuntimeCache _isolatedCacheManager;
|
||||
private readonly ICacheProvider _requestCache;
|
||||
private static readonly ICacheProvider NullRequestCache = new NullCacheProvider();
|
||||
private readonly ICacheProvider _staticCache;
|
||||
private static readonly ICacheProvider NullStaticCache = new NullCacheProvider();
|
||||
private readonly IRuntimeCacheProvider _runtimeCache;
|
||||
private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider();
|
||||
|
||||
/// <summary>
|
||||
@@ -90,45 +86,33 @@ namespace Umbraco.Core
|
||||
if (staticCacheProvider == null) throw new ArgumentNullException("staticCacheProvider");
|
||||
if (requestCacheProvider == null) throw new ArgumentNullException("requestCacheProvider");
|
||||
if (isolatedCacheManager == null) throw new ArgumentNullException("isolatedCacheManager");
|
||||
_runtimeCache = httpCacheProvider;
|
||||
_staticCache = staticCacheProvider;
|
||||
_requestCache = requestCacheProvider;
|
||||
_isolatedCacheManager = isolatedCacheManager;
|
||||
RuntimeCache = httpCacheProvider;
|
||||
StaticCache = staticCacheProvider;
|
||||
RequestCache = requestCacheProvider;
|
||||
IsolatedRuntimeCache = isolatedCacheManager;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Request cache
|
||||
/// </summary>
|
||||
public ICacheProvider RequestCache
|
||||
{
|
||||
get { return _requestCache; }
|
||||
}
|
||||
public ICacheProvider RequestCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Runtime cache
|
||||
/// </summary>
|
||||
public ICacheProvider StaticCache
|
||||
{
|
||||
get { return _staticCache; }
|
||||
}
|
||||
public ICacheProvider StaticCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Runtime cache
|
||||
/// </summary>
|
||||
public IRuntimeCacheProvider RuntimeCache
|
||||
{
|
||||
get { return _runtimeCache; }
|
||||
}
|
||||
public IRuntimeCacheProvider RuntimeCache { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the current Isolated Runtime cache manager
|
||||
/// </summary>
|
||||
public IsolatedRuntimeCache IsolatedRuntimeCache
|
||||
{
|
||||
get { return _isolatedCacheManager; }
|
||||
}
|
||||
|
||||
#region Legacy Runtime/Http Cache accessors
|
||||
public IsolatedRuntimeCache IsolatedRuntimeCache { get; internal set; }
|
||||
|
||||
#region Legacy Runtime/Http Cache accessors
|
||||
|
||||
/// <summary>
|
||||
/// Clears the item in umbraco's runtime cache
|
||||
@@ -137,8 +121,8 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearAllCache()
|
||||
{
|
||||
_runtimeCache.ClearAllCache();
|
||||
_isolatedCacheManager.ClearAllCaches();
|
||||
RuntimeCache.ClearAllCache();
|
||||
IsolatedRuntimeCache.ClearAllCaches();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -149,7 +133,7 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheItem(string key)
|
||||
{
|
||||
_runtimeCache.ClearCacheItem(key);
|
||||
RuntimeCache.ClearCacheItem(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,7 +145,7 @@ namespace Umbraco.Core
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
public void ClearCacheObjectTypes(string typeName)
|
||||
{
|
||||
_runtimeCache.ClearCacheObjectTypes(typeName);
|
||||
RuntimeCache.ClearCacheObjectTypes(typeName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -171,7 +155,7 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheObjectTypes<T>()
|
||||
{
|
||||
_runtimeCache.ClearCacheObjectTypes<T>();
|
||||
RuntimeCache.ClearCacheObjectTypes<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +166,7 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheByKeySearch(string keyStartsWith)
|
||||
{
|
||||
_runtimeCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
RuntimeCache.ClearCacheByKeySearch(keyStartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -193,14 +177,14 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public void ClearCacheByKeyExpression(string regexString)
|
||||
{
|
||||
_runtimeCache.ClearCacheByKeyExpression(regexString);
|
||||
RuntimeCache.ClearCacheByKeyExpression(regexString);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method, access the runtime cache from the RuntimeCache property")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public IEnumerable<T> GetCacheItemsByKeySearch<T>(string keyStartsWith)
|
||||
{
|
||||
return _runtimeCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
return RuntimeCache.GetCacheItemsByKeySearch<T>(keyStartsWith);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -213,7 +197,7 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey)
|
||||
{
|
||||
return _runtimeCache.GetCacheItem<TT>(cacheKey);
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -227,7 +211,7 @@ namespace Umbraco.Core
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TT GetCacheItem<TT>(string cacheKey, Func<TT> getCacheItem)
|
||||
{
|
||||
return _runtimeCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem);
|
||||
|
||||
}
|
||||
|
||||
@@ -244,7 +228,7 @@ namespace Umbraco.Core
|
||||
public TT GetCacheItem<TT>(string cacheKey,
|
||||
TimeSpan timeout, Func<TT> getCacheItem)
|
||||
{
|
||||
return _runtimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout);
|
||||
|
||||
}
|
||||
|
||||
@@ -263,7 +247,7 @@ namespace Umbraco.Core
|
||||
CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return _runtimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, removedCallback: refreshAction);
|
||||
|
||||
}
|
||||
|
||||
@@ -283,7 +267,7 @@ namespace Umbraco.Core
|
||||
CacheItemPriority priority, CacheItemRemovedCallback refreshAction, TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
return _runtimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
|
||||
return RuntimeCache.GetCacheItem<TT>(cacheKey, getCacheItem, timeout, false, priority, refreshAction);
|
||||
|
||||
}
|
||||
|
||||
@@ -306,7 +290,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = _runtimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
@@ -330,7 +314,7 @@ namespace Umbraco.Core
|
||||
CacheDependency cacheDependency,
|
||||
Func<TT> getCacheItem)
|
||||
{
|
||||
var cache = _runtimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
var result = cache.GetCacheItem(cacheKey, () => getCacheItem(), null, false, priority, null, cacheDependency);
|
||||
@@ -352,7 +336,7 @@ namespace Umbraco.Core
|
||||
CacheItemPriority priority,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
_runtimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
|
||||
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, priority: priority);
|
||||
|
||||
}
|
||||
|
||||
@@ -371,7 +355,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
_runtimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
|
||||
RuntimeCache.InsertCacheItem<T>(cacheKey, getCacheItem, timeout, priority: priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -390,7 +374,7 @@ namespace Umbraco.Core
|
||||
TimeSpan timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = _runtimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, null, cacheDependency);
|
||||
@@ -416,7 +400,7 @@ namespace Umbraco.Core
|
||||
TimeSpan? timeout,
|
||||
Func<T> getCacheItem)
|
||||
{
|
||||
var cache = _runtimeCache as HttpRuntimeCacheProvider;
|
||||
var cache = GetHttpRuntimeCacheProvider(RuntimeCache);
|
||||
if (cache != null)
|
||||
{
|
||||
cache.InsertCacheItem(cacheKey, () => getCacheItem(), timeout, false, priority, refreshAction, cacheDependency);
|
||||
@@ -425,6 +409,20 @@ namespace Umbraco.Core
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
private HttpRuntimeCacheProvider GetHttpRuntimeCacheProvider(IRuntimeCacheProvider runtimeCache)
|
||||
{
|
||||
HttpRuntimeCacheProvider cache;
|
||||
var wrapper = RuntimeCache as IRuntimeCacheProviderWrapper;
|
||||
if (wrapper != null)
|
||||
{
|
||||
cache = wrapper.InnerProvider as HttpRuntimeCacheProvider;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache = RuntimeCache as HttpRuntimeCacheProvider;
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,18 +14,24 @@ namespace Umbraco.Core.Collections
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class DeepCloneableList<T> : List<T>, IDeepCloneable, IRememberBeingDirty
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that is empty and has the default initial capacity.
|
||||
/// </summary>
|
||||
public DeepCloneableList()
|
||||
private readonly ListCloneBehavior _listCloneBehavior;
|
||||
|
||||
public DeepCloneableList(ListCloneBehavior listCloneBehavior)
|
||||
{
|
||||
_listCloneBehavior = listCloneBehavior;
|
||||
}
|
||||
|
||||
public DeepCloneableList(IEnumerable<T> collection, ListCloneBehavior listCloneBehavior) : base(collection)
|
||||
{
|
||||
_listCloneBehavior = listCloneBehavior;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="T:System.Collections.Generic.List`1"/> class that contains elements copied from the specified collection and has sufficient capacity to accommodate the number of elements copied.
|
||||
/// Default behavior is CloneOnce
|
||||
/// </summary>
|
||||
/// <param name="collection">The collection whose elements are copied to the new list.</param><exception cref="T:System.ArgumentNullException"><paramref name="collection"/> is null.</exception>
|
||||
public DeepCloneableList(IEnumerable<T> collection) : base(collection)
|
||||
/// <param name="collection"></param>
|
||||
public DeepCloneableList(IEnumerable<T> collection)
|
||||
: this(collection, ListCloneBehavior.CloneOnce)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -35,20 +41,47 @@ namespace Umbraco.Core.Collections
|
||||
/// <returns></returns>
|
||||
public object DeepClone()
|
||||
{
|
||||
var newList = new DeepCloneableList<T>();
|
||||
foreach (var item in this)
|
||||
switch (_listCloneBehavior)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add((T) dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(item);
|
||||
}
|
||||
case ListCloneBehavior.CloneOnce:
|
||||
//we are cloning once, so create a new list in none mode
|
||||
// and deep clone all items into it
|
||||
var newList = new DeepCloneableList<T>(ListCloneBehavior.None);
|
||||
foreach (var item in this)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList.Add((T)dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList.Add(item);
|
||||
}
|
||||
}
|
||||
return newList;
|
||||
case ListCloneBehavior.None:
|
||||
//we are in none mode, so just return a new list with the same items
|
||||
return new DeepCloneableList<T>(this, ListCloneBehavior.None);
|
||||
case ListCloneBehavior.Always:
|
||||
//always clone to new list
|
||||
var newList2 = new DeepCloneableList<T>(ListCloneBehavior.Always);
|
||||
foreach (var item in this)
|
||||
{
|
||||
var dc = item as IDeepCloneable;
|
||||
if (dc != null)
|
||||
{
|
||||
newList2.Add((T)dc.DeepClone());
|
||||
}
|
||||
else
|
||||
{
|
||||
newList2.Add(item);
|
||||
}
|
||||
}
|
||||
return newList2;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
return newList;
|
||||
}
|
||||
|
||||
public bool IsDirty()
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Umbraco.Core.Collections
|
||||
{
|
||||
internal enum ListCloneBehavior
|
||||
{
|
||||
/// <summary>
|
||||
/// When set, DeepClone will clone the items one time and the result list behavior will be None
|
||||
/// </summary>
|
||||
CloneOnce,
|
||||
|
||||
/// <summary>
|
||||
/// When set, DeepClone will not clone any items
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// When set, DeepClone will always clone all items
|
||||
/// </summary>
|
||||
Always
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.4.0");
|
||||
private static readonly Version Version = new Version("7.4.2");
|
||||
|
||||
/// <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 "beta2"; } }
|
||||
public static string CurrentComment { get { return ""; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -10,6 +10,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public static class Web
|
||||
{
|
||||
public const string UmbracoContextDataToken = "umbraco-context";
|
||||
public const string UmbracoDataToken = "umbraco";
|
||||
public const string PublishedDocumentRequestDataToken = "umbraco-doc-request";
|
||||
public const string CustomRouteDataToken = "umbraco-custom-route";
|
||||
public const string UmbracoRouteDefinitionDataToken = "umbraco-route-def";
|
||||
|
||||
/// <summary>
|
||||
/// The preview cookie name
|
||||
/// </summary>
|
||||
|
||||
@@ -136,7 +136,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationInitialized", x.GetType())))
|
||||
{
|
||||
x.OnApplicationInitialized(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -299,7 +302,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarting", x.GetType())))
|
||||
{
|
||||
x.OnApplicationStarting(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -350,7 +356,10 @@ namespace Umbraco.Core
|
||||
{
|
||||
try
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
using (ProfilingLogger.DebugDuration<CoreBootManager>(string.Format("Executing {0} in ApplicationStarted", x.GetType())))
|
||||
{
|
||||
x.OnApplicationStarted(UmbracoApplication, ApplicationContext);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Web;
|
||||
@@ -12,6 +13,12 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public class DisposableTimer : DisposableObject
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly LogType? _logType;
|
||||
private readonly IProfiler _profiler;
|
||||
private readonly Type _loggerType;
|
||||
private readonly string _endMessage;
|
||||
private readonly IDisposable _profilerStep;
|
||||
private readonly Stopwatch _stopwatch = Stopwatch.StartNew();
|
||||
private readonly Action<long> _callback;
|
||||
|
||||
@@ -25,25 +32,12 @@ namespace Umbraco.Core
|
||||
if (logger == null) throw new ArgumentNullException("logger");
|
||||
if (loggerType == null) throw new ArgumentNullException("loggerType");
|
||||
|
||||
_callback = x =>
|
||||
{
|
||||
if (profiler != null)
|
||||
{
|
||||
profiler.DisposeIfDisposable();
|
||||
}
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
logger.Debug(loggerType, () => endMessage + " (took " + x + "ms)");
|
||||
break;
|
||||
case LogType.Info:
|
||||
logger.Info(loggerType, () => endMessage + " (took " + x + "ms)");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("logType");
|
||||
}
|
||||
|
||||
};
|
||||
_logger = logger;
|
||||
_logType = logType;
|
||||
_profiler = profiler;
|
||||
_loggerType = loggerType;
|
||||
_endMessage = endMessage;
|
||||
|
||||
switch (logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
@@ -58,7 +52,7 @@ namespace Umbraco.Core
|
||||
|
||||
if (profiler != null)
|
||||
{
|
||||
profiler.Step(loggerType, startMessage);
|
||||
_profilerStep = profiler.Step(loggerType, startMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,7 +217,36 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
protected override void DisposeResources()
|
||||
{
|
||||
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
|
||||
if (_profiler != null)
|
||||
{
|
||||
_profiler.DisposeIfDisposable();
|
||||
}
|
||||
|
||||
if (_profilerStep != null)
|
||||
{
|
||||
_profilerStep.Dispose();
|
||||
}
|
||||
|
||||
if (_logType.HasValue && _endMessage.IsNullOrWhiteSpace() == false && _loggerType != null && _logger != null)
|
||||
{
|
||||
switch (_logType)
|
||||
{
|
||||
case LogType.Debug:
|
||||
_logger.Debug(_loggerType, () => _endMessage + " (took " + Stopwatch.ElapsedMilliseconds + "ms)");
|
||||
break;
|
||||
case LogType.Info:
|
||||
_logger.Info(_loggerType, () => _endMessage + " (took " + Stopwatch.ElapsedMilliseconds + "ms)");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException("logType");
|
||||
}
|
||||
}
|
||||
|
||||
if (_callback != null)
|
||||
{
|
||||
_callback.Invoke(Stopwatch.ElapsedMilliseconds);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Dynamic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
/// <summary>
|
||||
/// This will check enable dynamic access to properties and methods in a case insensitive manner
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// This works by using reflection on the type - the reflection lookup is lazy so it will not execute unless a dynamic method needs to be accessed
|
||||
/// </remarks>
|
||||
public abstract class CaseInsensitiveDynamicObject<T> : DynamicObject
|
||||
where T: class
|
||||
{
|
||||
/// <summary>
|
||||
/// Used for dynamic access for case insensitive property access
|
||||
/// </summary>`
|
||||
private static readonly Lazy<IDictionary<string, Func<T, object>>> CaseInsensitivePropertyAccess = new Lazy<IDictionary<string, Func<T, object>>>(() =>
|
||||
{
|
||||
var props = typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.DistinctBy(x => x.Name);
|
||||
return props.Select(propInfo =>
|
||||
{
|
||||
var name = propInfo.Name.ToLowerInvariant();
|
||||
Func<T, object> getVal = propInfo.GetValue;
|
||||
return new KeyValuePair<string, Func<T, object>>(name, getVal);
|
||||
|
||||
}).ToDictionary(x => x.Key, x => x.Value);
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// Used for dynamic access for case insensitive property access
|
||||
/// </summary>
|
||||
private static readonly Lazy<IDictionary<string, Tuple<ParameterInfo[], Func<T, object[], object>>>> CaseInsensitiveMethodAccess
|
||||
= new Lazy<IDictionary<string, Tuple<ParameterInfo[], Func<T, object[], object>>>>(() =>
|
||||
{
|
||||
var props = typeof(T).GetMethods(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(x => x.IsSpecialName == false && x.IsVirtual == false)
|
||||
.DistinctBy(x => x.Name);
|
||||
return props.Select(methodInfo =>
|
||||
{
|
||||
var name = methodInfo.Name.ToLowerInvariant();
|
||||
Func<T, object[], object> getVal = methodInfo.Invoke;
|
||||
var val = new Tuple<ParameterInfo[], Func<T, object[], object>>(methodInfo.GetParameters(), getVal);
|
||||
return new KeyValuePair<string, Tuple<ParameterInfo[], Func<T, object[], object>>>(name, val);
|
||||
|
||||
}).ToDictionary(x => x.Key, x => x.Value);
|
||||
});
|
||||
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
var name = binder.Name.ToLowerInvariant();
|
||||
if (CaseInsensitiveMethodAccess.Value.ContainsKey(name) == false)
|
||||
return base.TryInvokeMember(binder, args, out result);
|
||||
|
||||
var val = CaseInsensitiveMethodAccess.Value[name];
|
||||
var parameters = val.Item1;
|
||||
var callback = val.Item2;
|
||||
var fullArgs = new List<object>(args);
|
||||
if (args.Length <= parameters.Length)
|
||||
{
|
||||
//need to fill them up if they're optional
|
||||
for (var i = args.Length; i < parameters.Length; i++)
|
||||
{
|
||||
if (parameters[i].IsOptional)
|
||||
{
|
||||
fullArgs.Add(parameters[i].DefaultValue);
|
||||
}
|
||||
}
|
||||
if (fullArgs.Count == parameters.Length)
|
||||
{
|
||||
result = callback((T)(object)this, fullArgs.ToArray());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return base.TryInvokeMember(binder, args, out result);
|
||||
}
|
||||
|
||||
public override bool TryGetMember(GetMemberBinder binder, out object result)
|
||||
{
|
||||
var name = binder.Name.ToLowerInvariant();
|
||||
if (CaseInsensitivePropertyAccess.Value.ContainsKey(name) == false)
|
||||
return base.TryGetMember(binder, out result);
|
||||
|
||||
result = CaseInsensitivePropertyAccess.Value[name]((T)(object)this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace Umbraco.Core.Dynamics
|
||||
/// </summary>
|
||||
public class DynamicXmlConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type sourceType)
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
var convertableTypes = new[]
|
||||
{
|
||||
@@ -78,8 +78,8 @@ namespace Umbraco.Core.Dynamics
|
||||
typeof(RawXmlDocument)
|
||||
};
|
||||
|
||||
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, sourceType))
|
||||
|| base.CanConvertFrom(context, sourceType);
|
||||
return convertableTypes.Any(x => TypeHelper.IsTypeAssignableFrom(x, destinationType))
|
||||
|| base.CanConvertFrom(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(
|
||||
|
||||
@@ -5,8 +5,10 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using System.Web.Services.Description;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
@@ -20,6 +22,20 @@ namespace Umbraco.Core.Dynamics
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]> MethodCache = new ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]>();
|
||||
|
||||
private static IEnumerable<Type> GetTypes(Assembly a)
|
||||
{
|
||||
try
|
||||
{
|
||||
return TypeFinder.GetTypesWithFormattedException(a);
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
// is this going to flood the log?
|
||||
LogHelper.Error(typeof (ExtensionMethodFinder), "Failed to get types.", ex);
|
||||
return Enumerable.Empty<Type>();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the enumerable of all extension method info's in the app domain = USE SPARINGLY!!!
|
||||
/// </summary>
|
||||
@@ -36,7 +52,7 @@ namespace Umbraco.Core.Dynamics
|
||||
// assemblies that contain extension methods
|
||||
.Where(a => a.IsDefined(typeof (ExtensionAttribute), false))
|
||||
// types that contain extension methods
|
||||
.SelectMany(a => a.GetTypes()
|
||||
.SelectMany(a => GetTypes(a)
|
||||
.Where(t => t.IsDefined(typeof (ExtensionAttribute), false) && t.IsSealed && t.IsGenericType == false && t.IsNested == false))
|
||||
// actual extension methods
|
||||
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public)
|
||||
@@ -45,9 +61,9 @@ namespace Umbraco.Core.Dynamics
|
||||
.Concat(typeof (Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public))
|
||||
//If we don't do this then we'll be scanning all assemblies each time!
|
||||
.ToArray(),
|
||||
|
||||
|
||||
//only cache for 5 minutes
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
timeout: TimeSpan.FromMinutes(5),
|
||||
|
||||
//each time this is accessed it will be for 5 minutes longer
|
||||
isSliding:true);
|
||||
@@ -57,7 +73,7 @@ namespace Umbraco.Core.Dynamics
|
||||
/// Returns all extension methods found matching the definition
|
||||
/// </summary>
|
||||
/// <param name="runtimeCache">
|
||||
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
|
||||
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
|
||||
/// while we search for individual extension methods, the process will be reasonably 'quick'. We then statically
|
||||
/// cache the MethodInfo's that we are looking for and then the runtime cache will expire and give back all that memory.
|
||||
/// </param>
|
||||
@@ -78,7 +94,7 @@ namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
var candidates = GetAllExtensionMethodsInAppDomain(runtimeCache);
|
||||
|
||||
// filter by name
|
||||
// filter by name
|
||||
var filtr1 = candidates.Where(m => m.Name == name);
|
||||
|
||||
// filter by args count
|
||||
@@ -102,7 +118,7 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
return filtr3.ToArray();
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
|
||||
@@ -123,12 +139,12 @@ namespace Umbraco.Core.Dynamics
|
||||
types = method.GetParameters().Select(pi => pi.ParameterType).Skip(1)
|
||||
});
|
||||
|
||||
//This type comparer will check
|
||||
//This type comparer will check
|
||||
var typeComparer = new DelegateEqualityComparer<Type>(
|
||||
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
|
||||
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
|
||||
// example, if the argument type is HtmlHelper<MyModel> but the method parameter type is HtmlHelper then
|
||||
// it will match because the argument is assignable to that parameter type and will be able to execute
|
||||
TypeHelper.IsTypeAssignableFrom,
|
||||
TypeHelper.IsTypeAssignableFrom,
|
||||
//This will not ever execute but if it does we need to get the hash code of the string because the hash
|
||||
// code of a type is random
|
||||
type => type.FullName.GetHashCode());
|
||||
@@ -159,7 +175,7 @@ namespace Umbraco.Core.Dynamics
|
||||
.ToArray();
|
||||
|
||||
var methods = GetAllExtensionMethods(runtimeCache, thisType, name, args.Length).ToArray();
|
||||
|
||||
|
||||
return DetermineMethodFromParams(methods, genericType, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Security.Permissions;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
{
|
||||
@@ -11,11 +14,19 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
private bool _cancel;
|
||||
|
||||
public CancellableEventArgs(bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
|
||||
{
|
||||
CanCancel = canCancel;
|
||||
Messages = messages;
|
||||
AdditionalData = new ReadOnlyDictionary<string, object>(additionalData);
|
||||
}
|
||||
|
||||
public CancellableEventArgs(bool canCancel, EventMessages eventMessages)
|
||||
{
|
||||
if (eventMessages == null) throw new ArgumentNullException("eventMessages");
|
||||
CanCancel = canCancel;
|
||||
Messages = eventMessages;
|
||||
AdditionalData = new ReadOnlyDictionary<string, object>(new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
public CancellableEventArgs(bool canCancel)
|
||||
@@ -23,6 +34,7 @@ namespace Umbraco.Core.Events
|
||||
CanCancel = canCancel;
|
||||
//create a standalone messages
|
||||
Messages = new EventMessages();
|
||||
AdditionalData = new ReadOnlyDictionary<string, object>(new Dictionary<string, object>());
|
||||
}
|
||||
|
||||
public CancellableEventArgs(EventMessages eventMessages)
|
||||
@@ -78,5 +90,14 @@ namespace Umbraco.Core.Events
|
||||
/// Returns the EventMessages object which is used to add messages to the message collection for this event
|
||||
/// </summary>
|
||||
public EventMessages Messages { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// In some cases raised evens might need to contain additional arbitrary readonly data which can be read by event subscribers
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This allows for a bit of flexibility in our event raising - it's not pretty but we need to maintain backwards compatibility
|
||||
/// so we cannot change the strongly typed nature for some events.
|
||||
/// </remarks>
|
||||
public ReadOnlyDictionary<string, object> AdditionalData { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Permissions;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
@@ -11,8 +12,13 @@ namespace Umbraco.Core.Events
|
||||
[HostProtection(SecurityAction.LinkDemand, SharedState = true)]
|
||||
public class CancellableObjectEventArgs<T> : CancellableEventArgs
|
||||
{
|
||||
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
|
||||
: base(canCancel, messages, additionalData)
|
||||
{
|
||||
EventObject = eventObject;
|
||||
}
|
||||
|
||||
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages eventMessages)
|
||||
public CancellableObjectEventArgs(T eventObject, bool canCancel, EventMessages eventMessages)
|
||||
: base(canCancel, eventMessages)
|
||||
{
|
||||
EventObject = eventObject;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Semver;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Persistence.Migrations;
|
||||
|
||||
namespace Umbraco.Core.Events
|
||||
@@ -13,23 +14,49 @@ namespace Umbraco.Core.Events
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="productName"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, string productName, bool canCancel)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, productName, canCancel)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
[Obsolete("Use constructor accepting a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName, canCancel)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting SemVersion instances and a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
ConfiguredSemVersion = new SemVersion(configuredVersion);
|
||||
TargetSemVersion = new SemVersion(targetVersion);
|
||||
}
|
||||
: this(eventObject, null, new SemVersion(configuredVersion), new SemVersion(targetVersion), GlobalSettings.UmbracoMigrationName, canCancel)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="migrationContext"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="productName"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, string productName, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
MigrationContext = migrationContext;
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
ProductName = productName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
@@ -39,12 +66,15 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="targetVersion"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
[Obsolete("Use constructor accepting a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
|
||||
: base(eventObject, canCancel)
|
||||
{
|
||||
MigrationContext = migrationContext;
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
ProductName = GlobalSettings.UmbracoMigrationName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -53,21 +83,28 @@ namespace Umbraco.Core.Events
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
|
||||
: base(eventObject)
|
||||
{
|
||||
ConfiguredSemVersion = configuredVersion;
|
||||
TargetSemVersion = targetVersion;
|
||||
}
|
||||
/// <param name="productName"></param>
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, string productName)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, productName, false)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple migrations that are used in the migration runner
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="configuredVersion"></param>
|
||||
/// <param name="targetVersion"></param>
|
||||
[Obsolete("Use constructor accepting a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
|
||||
: this(eventObject, null, configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName, false)
|
||||
{ }
|
||||
|
||||
[Obsolete("Use constructor accepting SemVersion instances and a product name instead.")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion)
|
||||
: base(eventObject)
|
||||
{
|
||||
ConfiguredSemVersion = new SemVersion(configuredVersion);
|
||||
TargetSemVersion = new SemVersion(targetVersion);
|
||||
}
|
||||
: this(eventObject, null, new SemVersion(configuredVersion), new SemVersion(targetVersion), GlobalSettings.UmbracoMigrationName, false)
|
||||
{ }
|
||||
|
||||
/// <summary>
|
||||
/// Returns all migrations that were used in the migration runner
|
||||
@@ -95,6 +132,8 @@ namespace Umbraco.Core.Events
|
||||
|
||||
public SemVersion TargetSemVersion { get; private set; }
|
||||
|
||||
public string ProductName { get; private set; }
|
||||
|
||||
internal MigrationContext MigrationContext { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,18 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
public class SaveEventArgs<TEntity> : CancellableObjectEventArgs<IEnumerable<TEntity>>
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the saving operation
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="messages"></param>
|
||||
/// <param name="additionalData"></param>
|
||||
public SaveEventArgs(IEnumerable<TEntity> eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
|
||||
: base(eventObject, canCancel, messages, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting multiple entities that are used in the saving operation
|
||||
/// </summary>
|
||||
@@ -25,12 +37,24 @@ namespace Umbraco.Core.Events
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public SaveEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="canCancel"></param>
|
||||
/// <param name="messages"></param>
|
||||
/// <param name="additionalData"></param>
|
||||
public SaveEventArgs(TEntity eventObject, bool canCancel, EventMessages messages, IDictionary<string, object> additionalData)
|
||||
: base(new List<TEntity> { eventObject }, canCancel, messages, additionalData)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a single entity instance
|
||||
/// </summary>
|
||||
/// <param name="eventObject"></param>
|
||||
/// <param name="eventMessages"></param>
|
||||
public SaveEventArgs(TEntity eventObject, EventMessages eventMessages)
|
||||
: base(new List<TEntity> { eventObject }, eventMessages)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.IO
|
||||
{
|
||||
internal class ViewHelper
|
||||
public class ViewHelper
|
||||
{
|
||||
private readonly IFileSystem _viewFileSystem;
|
||||
|
||||
@@ -66,21 +66,58 @@ namespace Umbraco.Core.IO
|
||||
return viewContent;
|
||||
}
|
||||
|
||||
internal static string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null)
|
||||
public static string GetDefaultFileContent(string layoutPageAlias = null, string modelClassName = null, string modelNamespace = null, string modelNamespaceAlias = null)
|
||||
{
|
||||
var design = @"@inherits Umbraco.Web.Mvc.UmbracoTemplatePage
|
||||
@{
|
||||
Layout = null;
|
||||
}";
|
||||
var content = new StringBuilder();
|
||||
|
||||
if (layoutPageAlias.IsNullOrWhiteSpace() == false)
|
||||
design = design.Replace("null", string.Format("\"{0}.cshtml\"", layoutPageAlias));
|
||||
if (string.IsNullOrWhiteSpace(modelNamespaceAlias))
|
||||
modelNamespaceAlias = "ContentModels";
|
||||
|
||||
// either
|
||||
// @inherits Umbraco.Web.Mvc.UmbracoTemplatePage
|
||||
// @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<ModelClass>
|
||||
// @inherits Umbraco.Web.Mvc.UmbracoTemplatePage<ContentModels.ModelClass>
|
||||
content.Append("@inherits Umbraco.Web.Mvc.UmbracoTemplatePage");
|
||||
if (modelClassName.IsNullOrWhiteSpace() == false)
|
||||
design = design.Replace(".UmbracoTemplatePage", string.Format(".UmbracoTemplatePage<{0}>", modelClassName));
|
||||
{
|
||||
content.Append("<");
|
||||
if (modelNamespace.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
content.Append(modelNamespaceAlias);
|
||||
content.Append(".");
|
||||
}
|
||||
content.Append(modelClassName);
|
||||
content.Append(">");
|
||||
}
|
||||
content.Append("\r\n");
|
||||
|
||||
// if required, add
|
||||
// @using ContentModels = ModelNamespace;
|
||||
if (modelClassName.IsNullOrWhiteSpace() == false && modelNamespace.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
content.Append("@using ");
|
||||
content.Append(modelNamespaceAlias);
|
||||
content.Append(" = ");
|
||||
content.Append(modelNamespace);
|
||||
content.Append(";\r\n");
|
||||
}
|
||||
|
||||
return design;
|
||||
// either
|
||||
// Layout = null;
|
||||
// Layout = "layoutPage.cshtml";
|
||||
content.Append("@{\r\n\tLayout = ");
|
||||
if (layoutPageAlias.IsNullOrWhiteSpace())
|
||||
{
|
||||
content.Append("null");
|
||||
}
|
||||
else
|
||||
{
|
||||
content.Append("\"");
|
||||
content.Append(layoutPageAlias);
|
||||
content.Append(".cshtml\"");
|
||||
}
|
||||
content.Append(";\r\n}");
|
||||
return content.ToString();
|
||||
}
|
||||
|
||||
private string SaveTemplateToFile(ITemplate template)
|
||||
|
||||
@@ -367,8 +367,27 @@ namespace Umbraco.Core.Models
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, long value)
|
||||
{
|
||||
string val = value.ToString();
|
||||
SetValueOnProperty(propertyTypeAlias, val);
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Decimal"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, decimal value)
|
||||
{
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the <see cref="System.Double"/> value of a Property
|
||||
/// </summary>
|
||||
/// <param name="propertyTypeAlias">Alias of the PropertyType</param>
|
||||
/// <param name="value">Value to set for the Property</param>
|
||||
public virtual void SetPropertyValue(string propertyTypeAlias, double value)
|
||||
{
|
||||
SetValueOnProperty(propertyTypeAlias, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the alias of the default Template.
|
||||
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
|
||||
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
|
||||
/// we should not store direct entity
|
||||
/// </summary>
|
||||
[IgnoreDataMember]
|
||||
public ITemplate DefaultTemplate
|
||||
@@ -79,6 +82,9 @@ namespace Umbraco.Core.Models
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets a list of Templates which are allowed for the ContentType
|
||||
/// TODO: This should be ignored from cloning!!!!!!!!!!!!!!
|
||||
/// - but to do that we have to implement callback hacks, this needs to be fixed in v8,
|
||||
/// we should not store direct entity
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public IEnumerable<ITemplate> AllowedTemplates
|
||||
|
||||
@@ -487,11 +487,8 @@ namespace Umbraco.Core.Models
|
||||
var oldPropertyGroup = PropertyGroups.FirstOrDefault(x =>
|
||||
x.PropertyTypes.Any(y => y.Alias == propertyTypeAlias));
|
||||
|
||||
// reset PropertyGroupId, which will be re-evaluated when the content type
|
||||
// is saved - what is important is group.PropertyTypes - see code in
|
||||
// ContentTypeBaseRepository.PersistUpdatedBaseContentType
|
||||
propertyType.PropertyGroupId = new Lazy<int>(() => default(int));
|
||||
propertyType.ResetDirtyProperties(); // PropertyGroupId must not be dirty
|
||||
// set new group
|
||||
propertyType.PropertyGroupId = newPropertyGroup == null ? null : new Lazy<int>(() => newPropertyGroup.Id, false);
|
||||
|
||||
// remove from old group, if any - add to new group, if any
|
||||
if (oldPropertyGroup != null)
|
||||
@@ -540,7 +537,7 @@ namespace Umbraco.Core.Models
|
||||
// re-assign the group's properties to no group
|
||||
foreach (var property in group.PropertyTypes)
|
||||
{
|
||||
property.PropertyGroupId = new Lazy<int>(() => 0);
|
||||
property.PropertyGroupId = null;
|
||||
_propertyTypes.Add(property);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,10 +9,30 @@ namespace Umbraco.Core.Models
|
||||
{
|
||||
public static class DeepCloneHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores the metadata for the properties for a given type so we know how to create them
|
||||
/// </summary>
|
||||
private struct ClonePropertyInfo
|
||||
{
|
||||
public ClonePropertyInfo(PropertyInfo propertyInfo) : this()
|
||||
{
|
||||
if (propertyInfo == null) throw new ArgumentNullException("propertyInfo");
|
||||
PropertyInfo = propertyInfo;
|
||||
}
|
||||
|
||||
public PropertyInfo PropertyInfo { get; private set; }
|
||||
public bool IsDeepCloneable { get; set; }
|
||||
public Type GenericListType { get; set; }
|
||||
public bool IsList
|
||||
{
|
||||
get { return GenericListType != null; }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to avoid constant reflection (perf)
|
||||
/// </summary>
|
||||
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropCache = new ConcurrentDictionary<Type, PropertyInfo[]>();
|
||||
private static readonly ConcurrentDictionary<Type, ClonePropertyInfo[]> PropCache = new ConcurrentDictionary<Type, ClonePropertyInfo[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Used to deep clone any reference properties on the object (should be done after a MemberwiseClone for which the outcome is 'output')
|
||||
@@ -30,81 +50,99 @@ namespace Umbraco.Core.Models
|
||||
throw new InvalidOperationException("Both the input and output types must be the same");
|
||||
}
|
||||
|
||||
//get the property metadata from cache so we only have to figure this out once per type
|
||||
var refProperties = PropCache.GetOrAdd(inputType, type =>
|
||||
inputType.GetProperties()
|
||||
.Where(x =>
|
||||
//is not attributed with the ignore clone attribute
|
||||
x.GetCustomAttribute<DoNotCloneAttribute>() == null
|
||||
.Select<PropertyInfo, ClonePropertyInfo?>(propertyInfo =>
|
||||
{
|
||||
if (
|
||||
//is not attributed with the ignore clone attribute
|
||||
propertyInfo.GetCustomAttribute<DoNotCloneAttribute>() != null
|
||||
//reference type but not string
|
||||
&& x.PropertyType.IsValueType == false && x.PropertyType != typeof (string)
|
||||
|| propertyInfo.PropertyType.IsValueType || propertyInfo.PropertyType == typeof (string)
|
||||
//settable
|
||||
&& x.CanWrite
|
||||
|| propertyInfo.CanWrite == false
|
||||
//non-indexed
|
||||
&& x.GetIndexParameters().Any() == false)
|
||||
|| propertyInfo.GetIndexParameters().Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
{
|
||||
return new ClonePropertyInfo(propertyInfo) { IsDeepCloneable = true };
|
||||
}
|
||||
|
||||
if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
{
|
||||
if (propertyInfo.PropertyType.IsGenericType
|
||||
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
|
||||
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
|
||||
return new ClonePropertyInfo(propertyInfo) { GenericListType = genericType };
|
||||
}
|
||||
if (propertyInfo.PropertyType.IsArray
|
||||
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
|
||||
{
|
||||
//if its an array, we'll create a list to work with first and then convert to array later
|
||||
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
|
||||
return new ClonePropertyInfo(propertyInfo) { GenericListType = typeof(List<object>) };
|
||||
}
|
||||
//skip instead of trying to create instance of abstract or interface
|
||||
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
//its a custom IEnumerable, we'll try to create it
|
||||
try
|
||||
{
|
||||
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
//if it's an IList we can work with it, otherwise we cannot
|
||||
var newList = custom as IList;
|
||||
if (newList == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return new ClonePropertyInfo(propertyInfo) {GenericListType = propertyInfo.PropertyType};
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//could not create this type so we'll skip it
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return new ClonePropertyInfo(propertyInfo);
|
||||
})
|
||||
.Where(x => x.HasValue)
|
||||
.Select(x => x.Value)
|
||||
.ToArray());
|
||||
|
||||
foreach (var propertyInfo in refProperties)
|
||||
foreach (var clonePropertyInfo in refProperties)
|
||||
{
|
||||
if (TypeHelper.IsTypeAssignableFrom<IDeepCloneable>(propertyInfo.PropertyType))
|
||||
if (clonePropertyInfo.IsDeepCloneable)
|
||||
{
|
||||
//this ref property is also deep cloneable so clone it
|
||||
var result = (IDeepCloneable)propertyInfo.GetValue(input, null);
|
||||
var result = (IDeepCloneable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
//set the cloned value to the property
|
||||
propertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, result.DeepClone(), null);
|
||||
}
|
||||
}
|
||||
else if (TypeHelper.IsTypeAssignableFrom<IEnumerable>(propertyInfo.PropertyType)
|
||||
&& TypeHelper.IsTypeAssignableFrom<string>(propertyInfo.PropertyType) == false)
|
||||
else if (clonePropertyInfo.IsList)
|
||||
{
|
||||
IList newList;
|
||||
if (propertyInfo.PropertyType.IsGenericType
|
||||
&& (propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>)
|
||||
|| propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList<>)))
|
||||
{
|
||||
//if it is a IEnumerable<>, IList<T> or ICollection<> we'll use a List<>
|
||||
var genericType = typeof(List<>).MakeGenericType(propertyInfo.PropertyType.GetGenericArguments());
|
||||
newList = (IList)Activator.CreateInstance(genericType);
|
||||
}
|
||||
else if (propertyInfo.PropertyType.IsArray
|
||||
|| (propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.IsGenericType == false))
|
||||
{
|
||||
//if its an array, we'll create a list to work with first and then convert to array later
|
||||
//otherwise if its just a regular derivitave of IEnumerable, we can use a list too
|
||||
newList = new List<object>();
|
||||
}
|
||||
else
|
||||
{
|
||||
//skip instead of trying to create instance of abstract or interface
|
||||
if (propertyInfo.PropertyType.IsAbstract || propertyInfo.PropertyType.IsInterface)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//its a custom IEnumerable, we'll try to create it
|
||||
try
|
||||
{
|
||||
var custom = Activator.CreateInstance(propertyInfo.PropertyType);
|
||||
//if it's an IList we can work with it, otherwise we cannot
|
||||
newList = custom as IList;
|
||||
if (newList == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
//could not create this type so we'll skip it
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
var enumerable = (IEnumerable)propertyInfo.GetValue(input, null);
|
||||
var enumerable = (IEnumerable)clonePropertyInfo.PropertyInfo.GetValue(input, null);
|
||||
if (enumerable == null) continue;
|
||||
|
||||
var newList = (IList)Activator.CreateInstance(clonePropertyInfo.GenericListType);
|
||||
|
||||
var isUsableType = true;
|
||||
|
||||
//now clone each item
|
||||
@@ -136,21 +174,21 @@ namespace Umbraco.Core.Models
|
||||
continue;
|
||||
}
|
||||
|
||||
if (propertyInfo.PropertyType.IsArray)
|
||||
if (clonePropertyInfo.PropertyInfo.PropertyType.IsArray)
|
||||
{
|
||||
//need to convert to array
|
||||
var arr = (object[])Activator.CreateInstance(propertyInfo.PropertyType, newList.Count);
|
||||
var arr = (object[])Activator.CreateInstance(clonePropertyInfo.PropertyInfo.PropertyType, newList.Count);
|
||||
for (int i = 0; i < newList.Count; i++)
|
||||
{
|
||||
arr[i] = newList[i];
|
||||
}
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, arr, null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, arr, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
//set the cloned collection
|
||||
propertyInfo.SetValue(output, newList, null);
|
||||
clonePropertyInfo.PropertyInfo.SetValue(output, newList, null);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,12 @@ namespace Umbraco.Core.Models
|
||||
/// </summary
|
||||
public interface IMediaType : IContentTypeComposition
|
||||
{
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <param name="newAlias"></param>
|
||||
/// <returns></returns>
|
||||
IMediaType DeepCloneWithResetIdentities(string newAlias);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration.UmbracoSettings;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.PropertyEditors.ValueConverters;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
internal static class MediaExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Hack: we need to put this in a real place, this is currently just used to render the urls for a media item in the back office
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetUrl(this IMedia media, string propertyAlias, ILogger logger)
|
||||
{
|
||||
var propertyType = media.PropertyTypes.FirstOrDefault(x => x.Alias.InvariantEquals(propertyAlias));
|
||||
if (propertyType != null)
|
||||
{
|
||||
var val = media.Properties[propertyType];
|
||||
if (val != null)
|
||||
{
|
||||
var jsonString = val.Value as string;
|
||||
if (jsonString != null)
|
||||
{
|
||||
if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.ImageCropperAlias)
|
||||
{
|
||||
if (jsonString.DetectIsJson())
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonConvert.DeserializeObject<JObject>(jsonString);
|
||||
if (json["src"] != null)
|
||||
{
|
||||
return json["src"].Value<string>();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error<ImageCropperValueConverter>("Could not parse the string " + jsonString + " to a json object", ex);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return jsonString;
|
||||
}
|
||||
}
|
||||
else if (propertyType.PropertyEditorAlias == Constants.PropertyEditors.UploadFieldAlias)
|
||||
{
|
||||
return jsonString;
|
||||
}
|
||||
//hrm, without knowing what it is, just adding a string here might not be very nice
|
||||
}
|
||||
}
|
||||
}
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hack: we need to put this in a real place, this is currently just used to render the urls for a media item in the back office
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string[] GetUrls(this IMedia media, IContentSection contentSection, ILogger logger)
|
||||
{
|
||||
var links = new List<string>();
|
||||
var autoFillProperties = contentSection.ImageAutoFillProperties.ToArray();
|
||||
if (autoFillProperties.Any())
|
||||
{
|
||||
links.AddRange(
|
||||
autoFillProperties
|
||||
.Select(field => media.GetUrl(field.Alias, logger))
|
||||
.Where(link => link.IsNullOrWhiteSpace() == false));
|
||||
}
|
||||
return links.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,5 +38,30 @@ namespace Umbraco.Core.Models
|
||||
: base(parent, alias)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public IMediaType DeepCloneWithResetIdentities(string alias)
|
||||
{
|
||||
var clone = (MediaType)DeepClone();
|
||||
clone.Alias = alias;
|
||||
clone.Key = Guid.Empty;
|
||||
foreach (var propertyGroup in clone.PropertyGroups)
|
||||
{
|
||||
propertyGroup.ResetIdentity();
|
||||
propertyGroup.ResetDirtyProperties(false);
|
||||
}
|
||||
foreach (var propertyType in clone.PropertyTypes)
|
||||
{
|
||||
propertyType.ResetIdentity();
|
||||
propertyType.ResetDirtyProperties(false);
|
||||
}
|
||||
|
||||
clone.ResetIdentity();
|
||||
clone.ResetDirtyProperties(false);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -221,8 +221,9 @@ namespace Umbraco.Core.Models
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or Sets the PropertyGroup's Id for which this PropertyType belongs
|
||||
/// Gets or sets the identifier of the PropertyGroup this PropertyType belongs to.
|
||||
/// </summary>
|
||||
/// <remarks>For generic properties, the value is <c>null</c>.</remarks>
|
||||
[DataMember]
|
||||
internal Lazy<int> PropertyGroupId
|
||||
{
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Web.Caching;
|
||||
using System.Web.UI;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
@@ -16,6 +13,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public class PublishedContentType
|
||||
{
|
||||
private readonly PublishedPropertyType[] _propertyTypes;
|
||||
private readonly HashSet<string> _compositionAliases;
|
||||
|
||||
// fast alias-to-index xref containing both the raw alias and its lowercase version
|
||||
private readonly Dictionary<string, int> _indexes = new Dictionary<string, int>();
|
||||
@@ -27,6 +25,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
Id = contentType.Id;
|
||||
Alias = contentType.Alias;
|
||||
_compositionAliases = new HashSet<string>(contentType.CompositionAliases(), StringComparer.InvariantCultureIgnoreCase);
|
||||
_propertyTypes = contentType.CompositionPropertyTypes
|
||||
.Select(x => new PublishedPropertyType(this, x))
|
||||
.ToArray();
|
||||
@@ -34,10 +33,11 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
// internal so it can be used for unit tests
|
||||
internal PublishedContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
internal PublishedContentType(int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
{
|
||||
Id = id;
|
||||
Alias = alias;
|
||||
_compositionAliases = new HashSet<string>(compositionAliases, StringComparer.InvariantCultureIgnoreCase);
|
||||
_propertyTypes = propertyTypes.ToArray();
|
||||
foreach (var propertyType in _propertyTypes)
|
||||
propertyType.ContentType = this;
|
||||
@@ -45,8 +45,8 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
}
|
||||
|
||||
// create detached content type - ie does not match anything in the DB
|
||||
internal PublishedContentType(string alias, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
: this (0, alias, propertyTypes)
|
||||
internal PublishedContentType(string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
|
||||
: this(0, alias, compositionAliases, propertyTypes)
|
||||
{ }
|
||||
|
||||
private void InitializeIndexes()
|
||||
@@ -63,6 +63,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
public int Id { get; private set; }
|
||||
public string Alias { get; private set; }
|
||||
public HashSet<string> CompositionAliases { get { return _compositionAliases; } }
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -113,10 +114,25 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
internal static void ClearContentType(int id)
|
||||
{
|
||||
Logging.LogHelper.Debug<PublishedContentType>("Clear content type w/id {0}.", () => id);
|
||||
// requires a predicate because the key does not contain the ID
|
||||
// faster than key strings comparisons anyway
|
||||
|
||||
// we don't support "get all" at the moment - so, cheating
|
||||
var all = ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItemsByKeySearch<PublishedContentType>("PublishedContentType_").ToArray();
|
||||
|
||||
// the one we want to clear
|
||||
var clr = all.FirstOrDefault(x => x.Id == id);
|
||||
if (clr == null) return;
|
||||
|
||||
// those that have that one in their composition aliases
|
||||
// note: CompositionAliases contains all recursive aliases
|
||||
var oth = all.Where(x => x.CompositionAliases.InvariantContains(clr.Alias)).Select(x => x.Id);
|
||||
|
||||
// merge ids
|
||||
var ids = oth.Concat(new[] { clr.Id }).ToArray();
|
||||
|
||||
// clear them all at once
|
||||
// we don't support "clear many at once" at the moment - so, cheating
|
||||
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
|
||||
(key, value) => value.Id == id);
|
||||
(key, value) => ids.Contains(value.Id));
|
||||
}
|
||||
|
||||
internal static void ClearDataType(int id)
|
||||
|
||||
@@ -164,6 +164,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
|
||||
private void InitializeConverters()
|
||||
{
|
||||
//TODO: Look at optimizing this method, it gets run for every property type for the document being rendered at startup,
|
||||
// every precious second counts!
|
||||
|
||||
var converters = PropertyValueConvertersResolver.Current.Converters.ToArray();
|
||||
var defaultConvertersWithAttributes = PropertyValueConvertersResolver.Current.DefaultConverters;
|
||||
|
||||
@@ -230,13 +233,13 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
_sourceCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
_xpathCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
|
||||
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
_xpathCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
|
||||
}
|
||||
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
|
||||
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Umbraco.Core.Persistence.Factories
|
||||
Name = typeDto.Name,
|
||||
SortOrder = typeDto.SortOrder,
|
||||
ValidationRegExp = typeDto.ValidationRegExp,
|
||||
PropertyGroupId = new Lazy<int>(() => default(int)),
|
||||
PropertyGroupId = null,
|
||||
CreateDate = dto.CreateDate,
|
||||
UpdateDate = dto.CreateDate
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -27,18 +28,21 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
private readonly IMigration[] _migrations;
|
||||
|
||||
[Obsolete("Use the ctor that specifies all dependencies instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationRunner(Version currentVersion, Version targetVersion, string productName)
|
||||
: this(LoggerResolver.Current.Logger, currentVersion, targetVersion, productName)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the ctor that specifies all dependencies instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationRunner(ILogger logger, Version currentVersion, Version targetVersion, string productName)
|
||||
: this(logger, currentVersion, targetVersion, productName, null)
|
||||
{
|
||||
}
|
||||
|
||||
[Obsolete("Use the ctor that specifies all dependencies instead")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public MigrationRunner(ILogger logger, Version currentVersion, Version targetVersion, string productName, params IMigration[] migrations)
|
||||
: this(ApplicationContext.Current.Services.MigrationEntryService, logger, new SemVersion(currentVersion), new SemVersion(targetVersion), productName, migrations)
|
||||
{
|
||||
@@ -92,7 +96,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
: OrderedDowngradeMigrations(foundMigrations).ToList();
|
||||
|
||||
|
||||
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, true), this))
|
||||
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, _productName, true), this))
|
||||
{
|
||||
_logger.Warn<MigrationRunner>("Migration was cancelled by an event");
|
||||
return false;
|
||||
@@ -121,7 +125,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
throw;
|
||||
}
|
||||
|
||||
Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, false), this);
|
||||
Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, _productName, false), this);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -289,7 +293,7 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
//NOTE: We CANNOT do this as part of the transaction!!! This is because when upgrading to 7.3, we cannot
|
||||
// create the migrations table and then add data to it in the same transaction without issuing things like GO
|
||||
// commands and since we need to support all Dbs, we need to just do this after the fact.
|
||||
var exists = _migrationEntryService.FindEntry(GlobalSettings.UmbracoMigrationName, _targetVersion);
|
||||
var exists = _migrationEntryService.FindEntry(_productName, _targetVersion);
|
||||
if (exists == null)
|
||||
{
|
||||
_migrationEntryService.CreateEntry(_productName, _targetVersion);
|
||||
@@ -308,4 +312,4 @@ namespace Umbraco.Core.Persistence.Migrations
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<MigrationRunner, MigrationEventArgs> Migrated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+15
-12
@@ -37,9 +37,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
|
||||
if (!dataTypeIds.Any()) return string.Empty;
|
||||
|
||||
var propertyData =
|
||||
database.Fetch<PropertyDataDto>(
|
||||
"WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds });
|
||||
// need to use dynamic, as PropertyDataDto has new properties
|
||||
var propertyData = database.Fetch<dynamic>("SELECT * FROM cmsPropertyData"
|
||||
+ " WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds });
|
||||
if (!propertyData.Any()) return string.Empty;
|
||||
|
||||
var nodesIdsWithProperty = propertyData.Select(x => x.NodeId).Distinct().ToArray();
|
||||
@@ -71,13 +71,16 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
xml = new XmlDocument();
|
||||
xml.LoadXml(data.Text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error<UpdateRelatedLinksData>("The data stored for property id " + data.Id + " on document " + data.NodeId +
|
||||
" is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + data.Text, ex);
|
||||
int dataId = data.id;
|
||||
int dataNodeId = data.nodeId;
|
||||
string dataText = data.dataNText;
|
||||
Logger.Error<UpdateRelatedLinksData>("The data stored for property id " + dataId + " on document " + dataNodeId +
|
||||
" is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + dataText, ex);
|
||||
|
||||
data.Text = "";
|
||||
database.Update(data);
|
||||
data.dataNText = "";
|
||||
database.Update("cmsPropertyData", "id", data, new[] { "dataNText" });
|
||||
|
||||
UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database);
|
||||
|
||||
@@ -91,11 +94,11 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
{
|
||||
var title = node.Attributes["title"].Value;
|
||||
var type = node.Attributes["type"].Value;
|
||||
var newwindow = node.Attributes["newwindow"].Value.Equals("1") ? true : false;
|
||||
var newwindow = node.Attributes["newwindow"].Value.Equals("1");
|
||||
var lnk = node.Attributes["link"].Value;
|
||||
|
||||
//create the links in the format the new prop editor expects it to be
|
||||
var link = new ExpandoObject() as IDictionary<string, Object>;
|
||||
var link = new ExpandoObject() as IDictionary<string, object>;
|
||||
link.Add("title", title);
|
||||
link.Add("caption", title);
|
||||
link.Add("link", lnk);
|
||||
@@ -110,9 +113,9 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven
|
||||
}
|
||||
|
||||
//store the serialized data
|
||||
data.Text = JsonConvert.SerializeObject(links);
|
||||
data.dataNText = JsonConvert.SerializeObject(links);
|
||||
|
||||
database.Update(data);
|
||||
database.Update("cmsPropertyData", "id", data, new[] { "dataNText" });
|
||||
|
||||
UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database);
|
||||
|
||||
|
||||
+43
-29
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -33,45 +35,57 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourZer
|
||||
|
||||
// fill in the data in a way that is consistent over all environments
|
||||
// (ie cannot use random guids, http://issues.umbraco.org/issue/U4-6942)
|
||||
Execute.Code(UpdateGuids);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var data in Context.Database.Query<dynamic>(@"
|
||||
private static string UpdateGuids(Database database)
|
||||
{
|
||||
var updates = new List<Tuple<Guid, int>>();
|
||||
|
||||
foreach (var data in database.Query<dynamic>(@"
|
||||
SELECT cmsPropertyTypeGroup.id grId, cmsPropertyTypeGroup.text grName, cmsContentType.alias ctAlias, umbracoNode.nodeObjectType nObjType
|
||||
FROM cmsPropertyTypeGroup
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsPropertyTypeGroup.contentTypeNodeId = cmsContentType.nodeId
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id"))
|
||||
{
|
||||
Guid guid;
|
||||
// see BaseDataCreation... built-in groups have their own guids
|
||||
if (data.grId == 3)
|
||||
{
|
||||
Guid guid;
|
||||
// see BaseDataCreation... built-in groups have their own guids
|
||||
if (data.grId == 3)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Image);
|
||||
}
|
||||
else if (data.grId == 4)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.File);
|
||||
}
|
||||
else if (data.grId == 5)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Contents);
|
||||
}
|
||||
else if (data.grId == 11)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Membership);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a consistent guid from
|
||||
// group name + content type alias + object type
|
||||
string guidSource = data.grName + data.ctAlias + data.nObjType;
|
||||
guid = guidSource.ToGuid();
|
||||
}
|
||||
|
||||
// set the Unique Id to the one we've generated
|
||||
Update.Table("cmsPropertyTypeGroup").Set(new { uniqueID = guid }).Where(new { id = data.grId });
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Image);
|
||||
}
|
||||
else if (data.grId == 4)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.File);
|
||||
}
|
||||
else if (data.grId == 5)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Contents);
|
||||
}
|
||||
else if (data.grId == 11)
|
||||
{
|
||||
guid = new Guid(Constants.PropertyTypeGroups.Membership);
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a consistent guid from
|
||||
// group name + content type alias + object type
|
||||
string guidSource = data.grName + data.ctAlias + data.nObjType;
|
||||
guid = guidSource.ToGuid();
|
||||
}
|
||||
|
||||
// set the Unique Id to the one we've generated
|
||||
// but not within the foreach loop (as we already have a data reader open)
|
||||
updates.Add(Tuple.Create(guid, data.grId));
|
||||
}
|
||||
|
||||
foreach (var update in updates)
|
||||
database.Execute("UPDATE cmsPropertyTypeGroup SET uniqueID=@uid WHERE id=@id", new { uid = update.Item1, id = update.Item2 });
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override void Down()
|
||||
|
||||
+11
-1
@@ -20,7 +20,17 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourZer
|
||||
if (columns.Any(x => x.TableName.InvariantEquals("cmsPropertyTypeGroup") && x.ColumnName.InvariantEquals("parentGroupId")) == false)
|
||||
return;
|
||||
|
||||
Delete.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id").OnTable("cmsPropertyTypeGroup");
|
||||
//This constraing can be based on old aliases, before removing them, check they exist
|
||||
var constraints = SqlSyntax.GetConstraintsPerColumn(Context.Database).Distinct().ToArray();
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("cmsPropertyTypeGroup") && x.Item3.InvariantEquals("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id")))
|
||||
{
|
||||
Delete.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup_id").OnTable("cmsPropertyTypeGroup");
|
||||
}
|
||||
if (constraints.Any(x => x.Item1.InvariantEquals("cmsPropertyTypeGroup") && x.Item3.InvariantEquals("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup")))
|
||||
{
|
||||
Delete.ForeignKey("FK_cmsPropertyTypeGroup_cmsPropertyTypeGroup").OnTable("cmsPropertyTypeGroup");
|
||||
}
|
||||
|
||||
Delete.Column("parentGroupId").FromTable("cmsPropertyTypeGroup");
|
||||
}
|
||||
|
||||
|
||||
+25
-13
@@ -33,36 +33,40 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
// won't exist yet
|
||||
var propertyTypes = database.Fetch<dynamic>("SELECT * FROM cmsPropertyType WHERE propertyTypeGroupId > 0");
|
||||
|
||||
var propertyGroups = database.Fetch<PropertyTypeGroupDto>("WHERE id > 0");
|
||||
// need to use dynamic, as PropertyTypeGroupDto has new properties
|
||||
var propertyGroups = database.Fetch<dynamic>("SELECT * FROM cmsPropertyTypeGroup WHERE id > 0");
|
||||
|
||||
foreach (var propertyType in propertyTypes)
|
||||
{
|
||||
// get the PropertyTypeGroup of the current PropertyType, skip if not found
|
||||
var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.Id == propertyType.propertyTypeGroupId);
|
||||
var propertyTypeGroup = propertyGroups.FirstOrDefault(x => x.id == propertyType.propertyTypeGroupId);
|
||||
if (propertyTypeGroup == null) continue;
|
||||
|
||||
// if the PropretyTypeGroup belongs to the same content type as the PropertyType, then fine
|
||||
if (propertyTypeGroup.ContentTypeNodeId == propertyType.contentTypeId) continue;
|
||||
if (propertyTypeGroup.contenttypeNodeId == propertyType.contentTypeId) continue;
|
||||
|
||||
// else we want to assign the PropertyType to a proper PropertyTypeGroup
|
||||
// ie one that does belong to the same content - look for it
|
||||
var okPropertyTypeGroup = propertyGroups.FirstOrDefault(x =>
|
||||
x.Text == propertyTypeGroup.Text && // same name
|
||||
x.ContentTypeNodeId == propertyType.contentTypeId); // but for proper content type
|
||||
x.text == propertyTypeGroup.text && // same name
|
||||
x.contenttypeNodeId == propertyType.contentTypeId); // but for proper content type
|
||||
|
||||
if (okPropertyTypeGroup == null)
|
||||
{
|
||||
// does not exist, create a new PropertyTypeGroup,
|
||||
var propertyGroup = new PropertyTypeGroupDto
|
||||
// does not exist, create a new PropertyTypeGroup
|
||||
// cannot use a PropertyTypeGroupDto because of the new (not-yet-existing) uniqueID property
|
||||
// cannot use a dynamic because database.Insert fails to set the value of property
|
||||
var propertyGroup = new PropertyTypeGroupDtoTemp
|
||||
{
|
||||
ContentTypeNodeId = propertyType.contentTypeId,
|
||||
Text = propertyTypeGroup.Text,
|
||||
SortOrder = propertyTypeGroup.SortOrder
|
||||
id = 0,
|
||||
contenttypeNodeId = propertyType.contentTypeId,
|
||||
text = propertyTypeGroup.text,
|
||||
sortorder = propertyTypeGroup.sortorder
|
||||
};
|
||||
|
||||
// save + add to list of groups
|
||||
int id = Convert.ToInt16(database.Insert(propertyGroup));
|
||||
propertyGroup.Id = id;
|
||||
int id = Convert.ToInt16(database.Insert("cmsPropertyTypeGroup", "id", propertyGroup));
|
||||
propertyGroup.id = id;
|
||||
propertyGroups.Add(propertyGroup);
|
||||
|
||||
// update the PropertyType to use the new PropertyTypeGroup
|
||||
@@ -71,7 +75,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
else
|
||||
{
|
||||
// exists, update PropertyType to use the PropertyTypeGroup
|
||||
propertyType.propertyTypeGroupId = okPropertyTypeGroup.Id;
|
||||
propertyType.propertyTypeGroupId = okPropertyTypeGroup.id;
|
||||
}
|
||||
database.Update("cmsPropertyType", "id", propertyType);
|
||||
}
|
||||
@@ -79,5 +83,13 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSixZeroOne
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
private class PropertyTypeGroupDtoTemp
|
||||
{
|
||||
public int id { get; set; }
|
||||
public int contenttypeNodeId { get; set; }
|
||||
public string text { get; set; }
|
||||
public int sortorder { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -834,7 +834,7 @@ namespace Umbraco.Core.Persistence
|
||||
var pd = PocoData.ForType(typeof(T));
|
||||
try
|
||||
{
|
||||
r = cmd.ExecuteReader();
|
||||
r = cmd.ExecuteReaderWithRetry();
|
||||
OnExecutedCommand(cmd);
|
||||
}
|
||||
catch (Exception x)
|
||||
|
||||
@@ -128,6 +128,34 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
right = Visit(b.Right);
|
||||
}
|
||||
}
|
||||
else if (operand == "=")
|
||||
{
|
||||
// deal with (x == true|false) - most common
|
||||
var constRight = b.Right as ConstantExpression;
|
||||
if (constRight != null && constRight.Type == typeof (bool))
|
||||
return ((bool) constRight.Value) ? VisitNotNot(b.Left) : VisitNot(b.Left);
|
||||
right = Visit(b.Right);
|
||||
|
||||
// deal with (true|false == x) - why not
|
||||
var constLeft = b.Left as ConstantExpression;
|
||||
if (constLeft != null && constLeft.Type == typeof (bool))
|
||||
return ((bool) constLeft.Value) ? VisitNotNot(b.Right) : VisitNot(b.Right);
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
else if (operand == "<>")
|
||||
{
|
||||
// deal with (x != true|false) - most common
|
||||
var constRight = b.Right as ConstantExpression;
|
||||
if (constRight != null && constRight.Type == typeof(bool))
|
||||
return ((bool) constRight.Value) ? VisitNot(b.Left) : VisitNotNot(b.Left);
|
||||
right = Visit(b.Right);
|
||||
|
||||
// deal with (true|false != x) - why not
|
||||
var constLeft = b.Left as ConstantExpression;
|
||||
if (constLeft != null && constLeft.Type == typeof(bool))
|
||||
return ((bool) constLeft.Value) ? VisitNot(b.Right) : VisitNotNot(b.Right);
|
||||
left = Visit(b.Left);
|
||||
}
|
||||
else
|
||||
{
|
||||
left = Visit(b.Left);
|
||||
@@ -152,7 +180,7 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
case "COALESCE":
|
||||
return string.Format("{0}({1},{2})", operand, left, right);
|
||||
default:
|
||||
return left + " " + operand + " " + right;
|
||||
return "(" + left + " " + operand + " " + right + ")";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -231,25 +259,47 @@ namespace Umbraco.Core.Persistence.Querying
|
||||
switch (u.NodeType)
|
||||
{
|
||||
case ExpressionType.Not:
|
||||
var o = Visit(u.Operand);
|
||||
|
||||
//use a Not equal operator instead of <> since we don't know that <> works in all sql servers
|
||||
|
||||
switch (u.Operand.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
//In this case it wil be a false property , i.e. x => !Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("NOT ({0} = @0)", o);
|
||||
default:
|
||||
//In this case it could be anything else, such as: x => !x.Path.StartsWith("-20")
|
||||
return string.Format("NOT ({0})", o);
|
||||
}
|
||||
return VisitNot(u.Operand);
|
||||
default:
|
||||
return Visit(u.Operand);
|
||||
}
|
||||
}
|
||||
|
||||
private string VisitNot(Expression exp)
|
||||
{
|
||||
var o = Visit(exp);
|
||||
|
||||
// use a "NOT (...)" syntax instead of "<>" since we don't know whether "<>" works in all sql servers
|
||||
// also, x.StartsWith(...) translates to "x LIKE '...%'" which we cannot "<>" and have to "NOT (...")
|
||||
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
// false property , i.e. x => !Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("NOT ({0} = @{1})", o, SqlParameters.Count - 1);
|
||||
default:
|
||||
// could be anything else, such as: x => !x.Path.StartsWith("-20")
|
||||
return "NOT (" + o + ")";
|
||||
}
|
||||
}
|
||||
|
||||
private string VisitNotNot(Expression exp)
|
||||
{
|
||||
var o = Visit(exp);
|
||||
|
||||
switch (exp.NodeType)
|
||||
{
|
||||
case ExpressionType.MemberAccess:
|
||||
// true property, i.e. x => Trashed
|
||||
SqlParameters.Add(true);
|
||||
return string.Format("({0} = @{1})", o, SqlParameters.Count - 1);
|
||||
default:
|
||||
// could be anything else, such as: x => x.Path.StartsWith("-20")
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string VisitNewArray(NewArrayExpression na)
|
||||
{
|
||||
|
||||
|
||||
@@ -18,8 +18,11 @@ namespace Umbraco.Core.Persistence.Relators
|
||||
// Is this the same DictionaryItem as the current one we're processing
|
||||
if (Current != null && Current.Id == a.Id)
|
||||
{
|
||||
// Yes, just add this User2AppDto to the current item's collection
|
||||
Current.User2AppDtos.Add(p);
|
||||
if (p.AppAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
// Yes, just add this User2AppDto to the current item's collection
|
||||
Current.User2AppDtos.Add(p);
|
||||
}
|
||||
|
||||
// Return null to indicate we're not done with this User yet
|
||||
return null;
|
||||
@@ -35,7 +38,7 @@ namespace Umbraco.Core.Persistence.Relators
|
||||
Current = a;
|
||||
Current.User2AppDtos = new List<User2AppDto>();
|
||||
//this can be null since we are doing a left join
|
||||
if (p.AppAlias != null)
|
||||
if (p.AppAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
Current.User2AppDtos.Add(p);
|
||||
}
|
||||
|
||||
@@ -155,8 +155,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
"DELETE FROM cmsContentVersion WHERE ContentId = @Id",
|
||||
"DELETE FROM cmsContentXml WHERE nodeId = @Id",
|
||||
"DELETE FROM cmsContent WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id",
|
||||
"DELETE FROM umbracoAccess WHERE nodeId = @Id"
|
||||
"DELETE FROM umbracoAccess WHERE nodeId = @Id",
|
||||
"DELETE FROM umbracoNode WHERE id = @Id"
|
||||
};
|
||||
return list;
|
||||
}
|
||||
@@ -689,8 +689,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
public int CountPublished()
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<NodeDto>(x => x.Trashed == false)
|
||||
.Where<DocumentDto>(x => x.Published == true)
|
||||
.Where<DocumentDto>(x => x.Newest == true);
|
||||
.Where<DocumentDto>(x => x.Published == true);
|
||||
return Database.ExecuteScalar<int>(sql);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,14 +33,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
protected ContentTypeBaseRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
_guidRepo = new GuidReadOnlyContentTypeBaseRepository(this, work, cache, logger, sqlSyntax);
|
||||
}
|
||||
|
||||
private readonly GuidReadOnlyContentTypeBaseRepository _guidRepo;
|
||||
|
||||
public IEnumerable<MoveEventInfo<TEntity>> Move(TEntity toMove, EntityContainer container)
|
||||
{
|
||||
var parentId = -1;
|
||||
var parentId = Constants.System.Root;
|
||||
if (container != null)
|
||||
{
|
||||
// Check on paths
|
||||
@@ -57,27 +54,36 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
new MoveEventInfo<TEntity>(toMove, toMove.Path, parentId)
|
||||
};
|
||||
|
||||
//do the move to a new parent
|
||||
|
||||
// get the level delta (old pos to new pos)
|
||||
var levelDelta = container == null
|
||||
? 1 - toMove.Level
|
||||
: container.Level + 1 - toMove.Level;
|
||||
|
||||
// move to parent (or -1), update path, save
|
||||
toMove.ParentId = parentId;
|
||||
//schedule it for updating in the transaction
|
||||
var toMovePath = toMove.Path + ","; // save before changing
|
||||
toMove.Path = (container == null ? Constants.System.Root.ToString() : container.Path) + "," + toMove.Id;
|
||||
toMove.Level = container == null ? 1 : container.Level + 1;
|
||||
AddOrUpdate(toMove);
|
||||
|
||||
//update all descendants
|
||||
var descendants = this.GetByQuery(
|
||||
new Query<TEntity>().Where(type => type.Path.StartsWith(toMove.Path + ",")));
|
||||
foreach (var descendant in descendants)
|
||||
//update all descendants, update in order of level
|
||||
var descendants = GetByQuery(new Query<TEntity>().Where(type => type.Path.StartsWith(toMovePath)));
|
||||
var paths = new Dictionary<int, string>();
|
||||
paths[toMove.Id] = toMove.Path;
|
||||
|
||||
foreach (var descendant in descendants.OrderBy(x => x.Level))
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<TEntity>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
//all we're doing here is setting the parent Id to be dirty so that it resets the path/level/etc...
|
||||
descendant.ParentId = descendant.ParentId;
|
||||
//schedule it for updating in the transaction
|
||||
descendant.Path = paths[descendant.Id] = paths[descendant.ParentId] + "," + descendant.Id;
|
||||
descendant.Level += levelDelta;
|
||||
|
||||
AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
return moveInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the content type ids that match the query
|
||||
/// </summary>
|
||||
@@ -279,7 +285,7 @@ AND umbracoNode.id <> @id",
|
||||
{
|
||||
//Find PropertyTypes for the removed ContentType
|
||||
var propertyTypes = Database.Fetch<PropertyTypeDto>("WHERE contentTypeId = @Id", new { Id = key });
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//Loop through the Content that is based on the current ContentType in order to remove the Properties that are
|
||||
//based on the PropertyTypes that belong to the removed ContentType.
|
||||
foreach (var contentDto in contentDtos)
|
||||
{
|
||||
@@ -403,7 +409,7 @@ AND umbracoNode.id <> @id",
|
||||
AssignDataTypeFromPropertyEditor(propertyType);
|
||||
}
|
||||
|
||||
//validate the alias!
|
||||
//validate the alias!
|
||||
ValidateAlias(propertyType);
|
||||
|
||||
var propertyTypeDto = propertyGroupFactory.BuildPropertyTypeDto(tabId, propertyType);
|
||||
@@ -577,14 +583,13 @@ AND umbracoNode.id <> @id",
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<IMediaType> GetMediaTypes<TRepo, TId>(
|
||||
TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
public static IEnumerable<IMediaType> GetMediaTypes<TRepo>(
|
||||
Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
TRepo contentTypeRepository)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId: struct
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
IDictionary<TId, IEnumerable<TId>> allParentMediaTypeIds;
|
||||
var mediaTypes = MapMediaTypes(mediaTypeIds, db, sqlSyntax, out allParentMediaTypeIds)
|
||||
IDictionary<int, List<int>> allParentMediaTypeIds;
|
||||
var mediaTypes = MapMediaTypes(db, sqlSyntax, out allParentMediaTypeIds)
|
||||
.ToArray();
|
||||
|
||||
MapContentTypeChildren(mediaTypes, db, sqlSyntax, contentTypeRepository, allParentMediaTypeIds);
|
||||
@@ -592,16 +597,15 @@ AND umbracoNode.id <> @id",
|
||||
return mediaTypes;
|
||||
}
|
||||
|
||||
public static IEnumerable<IContentType> GetContentTypes<TRepo, TId>(
|
||||
TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
public static IEnumerable<IContentType> GetContentTypes<TRepo>(
|
||||
Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
TRepo contentTypeRepository,
|
||||
ITemplateRepository templateRepository)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId : struct
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
IDictionary<TId, IEnumerable<AssociatedTemplate>> allAssociatedTemplates;
|
||||
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds;
|
||||
var contentTypes = MapContentTypes(contentTypeIds, db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
|
||||
IDictionary<int, List<AssociatedTemplate>> allAssociatedTemplates;
|
||||
IDictionary<int, List<int>> allParentContentTypeIds;
|
||||
var contentTypes = MapContentTypes(db, sqlSyntax, out allAssociatedTemplates, out allParentContentTypeIds)
|
||||
.ToArray();
|
||||
|
||||
if (contentTypes.Any())
|
||||
@@ -616,12 +620,11 @@ AND umbracoNode.id <> @id",
|
||||
return contentTypes;
|
||||
}
|
||||
|
||||
internal static void MapContentTypeChildren<TRepo, TId>(IContentTypeComposition[] contentTypes,
|
||||
internal static void MapContentTypeChildren<TRepo>(IContentTypeComposition[] contentTypes,
|
||||
Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
TRepo contentTypeRepository,
|
||||
IDictionary<TId, IEnumerable<TId>> allParentContentTypeIds)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId : struct
|
||||
IDictionary<int, List<int>> allParentContentTypeIds)
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
//NOTE: SQL call #2
|
||||
|
||||
@@ -643,25 +646,22 @@ AND umbracoNode.id <> @id",
|
||||
var allParentIdsAsArray = allParentContentTypeIds.SelectMany(x => x.Value).Distinct().ToArray();
|
||||
if (allParentIdsAsArray.Any())
|
||||
{
|
||||
var allParentContentTypes = contentTypeRepository.GetAll(allParentIdsAsArray).ToArray();
|
||||
var allParentContentTypes = contentTypes.Where(x => allParentIdsAsArray.Contains(x.Id)).ToArray();
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
|
||||
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
|
||||
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
|
||||
{
|
||||
var entityId = contentType.Id;
|
||||
|
||||
var parentContentTypes = allParentContentTypes.Where(x =>
|
||||
{
|
||||
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
|
||||
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
|
||||
var parentEntityId = typeof(TId) == typeof(int) ? x.Id : (object)x.Key;
|
||||
var parentEntityId = x.Id;
|
||||
|
||||
return allParentContentTypeIds[(TId)entityId].Contains((TId)parentEntityId);
|
||||
return allParentContentTypeIds[entityId].Contains(parentEntityId);
|
||||
});
|
||||
foreach (var parentContentType in parentContentTypes)
|
||||
{
|
||||
var result = contentType.AddContentType(parentContentType);
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
|
||||
//Do something if adding fails? (Should hopefully not be possible unless someone created a circular reference)
|
||||
}
|
||||
|
||||
//on initial construction we don't want to have dirty properties tracked
|
||||
@@ -674,13 +674,12 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
}
|
||||
|
||||
internal static void MapContentTypeTemplates<TRepo, TId>(IContentType[] contentTypes,
|
||||
internal static void MapContentTypeTemplates<TRepo>(IContentType[] contentTypes,
|
||||
Database db,
|
||||
TRepo contentTypeRepository,
|
||||
ITemplateRepository templateRepository,
|
||||
IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates)
|
||||
where TRepo : IReadRepository<TId, TEntity>
|
||||
where TId: struct
|
||||
IDictionary<int, List<AssociatedTemplate>> associatedTemplates)
|
||||
where TRepo : IReadRepository<int, TEntity>
|
||||
{
|
||||
if (associatedTemplates == null || associatedTemplates.Any() == false) return;
|
||||
|
||||
@@ -697,11 +696,9 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
foreach (var contentType in contentTypes)
|
||||
{
|
||||
//TODO: this is pretty hacky right now but i don't have time to refactor/fix running queries based on ints and Guids
|
||||
// (i.e. for v8) but we need queries by GUIDs now so this is how it's gonna have to be
|
||||
var entityId = typeof(TId) == typeof(int) ? contentType.Id : (object)contentType.Key;
|
||||
|
||||
var associatedTemplateIds = associatedTemplates[(TId)entityId].Select(x => x.TemplateId)
|
||||
var entityId = contentType.Id;
|
||||
|
||||
var associatedTemplateIds = associatedTemplates[entityId].Select(x => x.TemplateId)
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
|
||||
@@ -713,19 +710,14 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
}
|
||||
|
||||
internal static IEnumerable<IMediaType> MapMediaTypes<TId>(TId[] mediaTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<TId, IEnumerable<TId>> parentMediaTypeIds)
|
||||
where TId : struct
|
||||
internal static IEnumerable<IMediaType> MapMediaTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<int, List<int>> parentMediaTypeIds)
|
||||
{
|
||||
Mandate.That(mediaTypeIds.Any(), () => new InvalidOperationException("must be at least one content type id specified"));
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
//ensure they are unique
|
||||
mediaTypeIds = mediaTypeIds.Distinct().ToArray();
|
||||
|
||||
|
||||
var sql = @"SELECT cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId, ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
@@ -734,40 +726,23 @@ AND umbracoNode.id <> @id",
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType.nodeId = umbracoNode.id
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
ON AllowedTypes.Id = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
|
||||
|
||||
if (mediaTypeIds.Any())
|
||||
{
|
||||
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
|
||||
// work for the time being.
|
||||
if (typeof(TId) == typeof(int))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
|
||||
}
|
||||
else if (typeof(TId) == typeof(Guid))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
|
||||
}
|
||||
}
|
||||
|
||||
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
|
||||
if ((mediaTypeIds.Length - 1) > 2000)
|
||||
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType), contentTypeIds = mediaTypeIds });
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.MediaType) });
|
||||
|
||||
if (result.Any() == false)
|
||||
{
|
||||
@@ -775,95 +750,118 @@ AND umbracoNode.id <> @id",
|
||||
return Enumerable.Empty<IMediaType>();
|
||||
}
|
||||
|
||||
parentMediaTypeIds = new Dictionary<TId, IEnumerable<TId>>();
|
||||
parentMediaTypeIds = new Dictionary<int, List<int>>();
|
||||
var mappedMediaTypes = new List<IMediaType>();
|
||||
|
||||
foreach (var contentTypeId in mediaTypeIds)
|
||||
//loop through each result and fill in our required values, each row will contain different requried data than the rest.
|
||||
// it is much quicker to iterate each result and populate instead of looking up the values over and over in the result like
|
||||
// we used to do.
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
//the current content type id that we're working with
|
||||
var ct = queue.Dequeue();
|
||||
|
||||
var currentCtId = contentTypeId;
|
||||
|
||||
//first we want to get the main content type data this is 1 : 1 with umbraco node data
|
||||
|
||||
var ct = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof (TId) == typeof (int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
|
||||
.DistinctBy(x => (int)x.ctId)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (ct == null)
|
||||
//check for allowed content types
|
||||
int? allowedCtId = ct.ctaAllowedId;
|
||||
int? allowedCtSort = ct.ctaSortOrder;
|
||||
string allowedCtAlias = ct.ctaAlias;
|
||||
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
|
||||
{
|
||||
continue;
|
||||
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
|
||||
if (currAllowedContentTypes.Contains(ctSort) == false)
|
||||
{
|
||||
currAllowedContentTypes.Add(ctSort);
|
||||
}
|
||||
}
|
||||
|
||||
var contentTypeDto = new ContentTypeDto
|
||||
//always ensure there's a list for this content type
|
||||
if (parentMediaTypeIds.ContainsKey(ct.ctId) == false)
|
||||
parentMediaTypeIds[ct.ctId] = new List<int>();
|
||||
|
||||
//check for parent ids and assign to the outgoing collection
|
||||
int? parentId = ct.chtParentId;
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
Alias = ct.ctAlias,
|
||||
AllowAtRoot = ct.ctAllowAtRoot,
|
||||
Description = ct.ctDesc,
|
||||
Icon = ct.ctIcon,
|
||||
IsContainer = ct.ctIsContainer,
|
||||
NodeId = ct.ctId,
|
||||
PrimaryKey = ct.ctPk,
|
||||
Thumbnail = ct.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = ct.nCreateDate,
|
||||
Level = (short)ct.nLevel,
|
||||
NodeId = ct.ctId,
|
||||
NodeObjectType = ct.nObjectType,
|
||||
ParentId = ct.nParentId,
|
||||
Path = ct.nPath,
|
||||
SortOrder = ct.nSortOrder,
|
||||
Text = ct.nName,
|
||||
Trashed = ct.nTrashed,
|
||||
UniqueId = ct.nUniqueId,
|
||||
UserId = ct.nUser
|
||||
}
|
||||
};
|
||||
var associatedParentIds = parentMediaTypeIds[ct.ctId];
|
||||
if (associatedParentIds.Contains(parentId.Value) == false)
|
||||
associatedParentIds.Add(parentId.Value);
|
||||
}
|
||||
|
||||
//now create the media type object
|
||||
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
|
||||
{
|
||||
//it's the last in the queue or the content type is changing (moving to the next one)
|
||||
var mediaType = CreateForMapping(ct, currAllowedContentTypes);
|
||||
mappedMediaTypes.Add(mediaType);
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var mediaType = factory.BuildMediaTypeEntity(contentTypeDto);
|
||||
|
||||
//map the allowed content types
|
||||
//map the child content type ids
|
||||
MapCommonContentTypeObjects(mediaType, currentCtId, result, parentMediaTypeIds);
|
||||
|
||||
mappedMediaTypes.Add(mediaType);
|
||||
//Here we need to reset the current variables, we're now collecting data for a different content type
|
||||
currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
}
|
||||
}
|
||||
|
||||
return mappedMediaTypes;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IContentType> MapContentTypes<TId>(TId[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<TId, IEnumerable<AssociatedTemplate>> associatedTemplates,
|
||||
out IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
|
||||
where TId : struct
|
||||
private static IMediaType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes)
|
||||
{
|
||||
// * create the DTO object
|
||||
// * create the content type object
|
||||
// * map the allowed content types
|
||||
// * add to the outgoing list
|
||||
|
||||
var contentTypeDto = new ContentTypeDto
|
||||
{
|
||||
Alias = currCt.ctAlias,
|
||||
AllowAtRoot = currCt.ctAllowAtRoot,
|
||||
Description = currCt.ctDesc,
|
||||
Icon = currCt.ctIcon,
|
||||
IsContainer = currCt.ctIsContainer,
|
||||
NodeId = currCt.ctId,
|
||||
PrimaryKey = currCt.ctPk,
|
||||
Thumbnail = currCt.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = currCt.nCreateDate,
|
||||
Level = (short)currCt.nLevel,
|
||||
NodeId = currCt.ctId,
|
||||
NodeObjectType = currCt.nObjectType,
|
||||
ParentId = currCt.nParentId,
|
||||
Path = currCt.nPath,
|
||||
SortOrder = currCt.nSortOrder,
|
||||
Text = currCt.nName,
|
||||
Trashed = currCt.nTrashed,
|
||||
UniqueId = currCt.nUniqueId,
|
||||
UserId = currCt.nUser
|
||||
}
|
||||
};
|
||||
|
||||
//now create the content type object
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var mediaType = factory.BuildMediaTypeEntity(contentTypeDto);
|
||||
|
||||
//map the allowed content types
|
||||
mediaType.AllowedContentTypes = currAllowedContentTypes;
|
||||
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
internal static IEnumerable<IContentType> MapContentTypes(Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
out IDictionary<int, List<AssociatedTemplate>> associatedTemplates,
|
||||
out IDictionary<int, List<int>> parentContentTypeIds)
|
||||
{
|
||||
Mandate.ParameterNotNull(db, "db");
|
||||
|
||||
//ensure they are unique
|
||||
contentTypeIds = contentTypeIds.Distinct().ToArray();
|
||||
|
||||
|
||||
var sql = @"SELECT cmsDocumentType.IsDefault as dtIsDefault, cmsDocumentType.templateNodeId as dtTemplateId,
|
||||
cmsContentType.pk as ctPk, cmsContentType.alias as ctAlias, cmsContentType.allowAtRoot as ctAllowAtRoot, cmsContentType.description as ctDesc,
|
||||
cmsContentType.icon as ctIcon, cmsContentType.isContainer as ctIsContainer, cmsContentType.nodeId as ctId, cmsContentType.thumbnail as ctThumb,
|
||||
AllowedTypes.allowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
AllowedTypes.AllowedId as ctaAllowedId, AllowedTypes.SortOrder as ctaSortOrder, AllowedTypes.alias as ctaAlias,
|
||||
ParentTypes.parentContentTypeId as chtParentId,ParentTypes.parentContentTypeKey as chtParentKey,
|
||||
umbracoNode.createDate as nCreateDate, umbracoNode." + sqlSyntax.GetQuotedColumnName("level") + @" as nLevel, umbracoNode.nodeObjectType as nObjectType, umbracoNode.nodeUser as nUser,
|
||||
umbracoNode.parentID as nParentId, umbracoNode." + sqlSyntax.GetQuotedColumnName("path") + @" as nPath, umbracoNode.sortOrder as nSortOrder, umbracoNode." + sqlSyntax.GetQuotedColumnName("text") + @" as nName, umbracoNode.trashed as nTrashed,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
umbracoNode.uniqueID as nUniqueId,
|
||||
Template.alias as tAlias, Template.nodeId as tId,Template.text as tText
|
||||
FROM cmsContentType
|
||||
INNER JOIN umbracoNode
|
||||
@@ -871,8 +869,8 @@ AND umbracoNode.id <> @id",
|
||||
LEFT JOIN cmsDocumentType
|
||||
ON cmsDocumentType.contentTypeNodeId = cmsContentType.nodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
SELECT cmsContentTypeAllowedContentType.Id, cmsContentTypeAllowedContentType.AllowedId, cmsContentType.alias, cmsContentTypeAllowedContentType.SortOrder
|
||||
FROM cmsContentTypeAllowedContentType
|
||||
INNER JOIN cmsContentType
|
||||
ON cmsContentTypeAllowedContentType.AllowedId = cmsContentType.nodeId
|
||||
) AllowedTypes
|
||||
@@ -885,33 +883,15 @@ AND umbracoNode.id <> @id",
|
||||
ON Template.nodeId = cmsDocumentType.templateNodeId
|
||||
LEFT JOIN (
|
||||
SELECT cmsContentType2ContentType.parentContentTypeId, umbracoNode.uniqueID AS parentContentTypeKey, cmsContentType2ContentType.childContentTypeId
|
||||
FROM cmsContentType2ContentType
|
||||
FROM cmsContentType2ContentType
|
||||
INNER JOIN umbracoNode
|
||||
ON cmsContentType2ContentType.parentContentTypeId = umbracoNode." + sqlSyntax.GetQuotedColumnName("id") + @"
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)";
|
||||
|
||||
if (contentTypeIds.Any())
|
||||
{
|
||||
//TODO: This is all sorts of hacky but i don't have time to refactor a lot to get both ints and guids working nicely... this will
|
||||
// work for the time being.
|
||||
if (typeof(TId) == typeof(int))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.id IN (@contentTypeIds))";
|
||||
}
|
||||
else if (typeof(TId) == typeof(Guid))
|
||||
{
|
||||
sql = sql + " AND (umbracoNode.uniqueID IN (@contentTypeIds))";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//NOTE: we are going to assume there's not going to be more than 2100 content type ids since that is the max SQL param count!
|
||||
if ((contentTypeIds.Length - 1) > 2000)
|
||||
throw new InvalidOperationException("Cannot perform this lookup, too many sql parameters");
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType), contentTypeIds = contentTypeIds });
|
||||
) ParentTypes
|
||||
ON ParentTypes.childContentTypeId = cmsContentType.nodeId
|
||||
WHERE (umbracoNode.nodeObjectType = @nodeObjectType)
|
||||
ORDER BY ctId";
|
||||
|
||||
var result = db.Fetch<dynamic>(sql, new { nodeObjectType = new Guid(Constants.ObjectTypes.DocumentType)});
|
||||
|
||||
if (result.Any() == false)
|
||||
{
|
||||
@@ -920,170 +900,139 @@ AND umbracoNode.id <> @id",
|
||||
return Enumerable.Empty<IContentType>();
|
||||
}
|
||||
|
||||
parentContentTypeIds = new Dictionary<TId, IEnumerable<TId>>();
|
||||
associatedTemplates = new Dictionary<TId, IEnumerable<AssociatedTemplate>>();
|
||||
parentContentTypeIds = new Dictionary<int, List<int>>();
|
||||
associatedTemplates = new Dictionary<int, List<AssociatedTemplate>>();
|
||||
var mappedContentTypes = new List<IContentType>();
|
||||
|
||||
foreach (var contentTypeId in contentTypeIds)
|
||||
var queue = new Queue<dynamic>(result);
|
||||
var currDefaultTemplate = -1;
|
||||
var currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
//the current content type id that we're working with
|
||||
var ct = queue.Dequeue();
|
||||
|
||||
var currentCtId = contentTypeId;
|
||||
|
||||
//first we want to get the main content type data this is 1 : 1 with umbraco node data
|
||||
|
||||
var ct = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x => new { x.ctPk, x.ctId, x.ctAlias, x.ctAllowAtRoot, x.ctDesc, x.ctIcon, x.ctIsContainer, x.ctThumb, x.nName, x.nCreateDate, x.nLevel, x.nObjectType, x.nUser, x.nParentId, x.nPath, x.nSortOrder, x.nTrashed, x.nUniqueId })
|
||||
.DistinctBy(x => (int)x.ctId)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (ct == null)
|
||||
//check for default templates
|
||||
bool? isDefaultTemplate = Convert.ToBoolean(ct.dtIsDefault);
|
||||
int? templateId = ct.dtTemplateId;
|
||||
if (currDefaultTemplate == -1 && isDefaultTemplate.HasValue && isDefaultTemplate.Value && templateId.HasValue)
|
||||
{
|
||||
continue;
|
||||
currDefaultTemplate = templateId.Value;
|
||||
}
|
||||
|
||||
//get the unique list of associated templates
|
||||
var defaultTemplates = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
//use a tuple so that distinct checks both values (in some rare cases the dtIsDefault will not compute as bool?, so we force it with Convert.ToBoolean)
|
||||
.Select(x => new Tuple<bool?, int?>(Convert.ToBoolean(x.dtIsDefault), x.dtTemplateId))
|
||||
.Where(x => x.Item1.HasValue && x.Item2.HasValue)
|
||||
.Distinct()
|
||||
.OrderByDescending(x => x.Item1.Value)
|
||||
.ToArray();
|
||||
//if there isn't one set to default explicitly, we'll pick the first one
|
||||
var defaultTemplate = defaultTemplates.FirstOrDefault(x => x.Item1.Value)
|
||||
?? defaultTemplates.FirstOrDefault();
|
||||
//always ensure there's a list for this content type
|
||||
if (associatedTemplates.ContainsKey(ct.ctId) == false)
|
||||
associatedTemplates[ct.ctId] = new List<AssociatedTemplate>();
|
||||
|
||||
var dtDto = new ContentTypeTemplateDto
|
||||
//check for associated templates and assign to the outgoing collection
|
||||
if (ct.tId != null)
|
||||
{
|
||||
//create the content type dto
|
||||
ContentTypeDto = new ContentTypeDto
|
||||
var associatedTemplate = new AssociatedTemplate(ct.tId, ct.tAlias, ct.tText);
|
||||
var associatedList = associatedTemplates[ct.ctId];
|
||||
|
||||
if (associatedList.Contains(associatedTemplate) == false)
|
||||
associatedList.Add(associatedTemplate);
|
||||
}
|
||||
|
||||
//check for allowed content types
|
||||
int? allowedCtId = ct.ctaAllowedId;
|
||||
int? allowedCtSort = ct.ctaSortOrder;
|
||||
string allowedCtAlias = ct.ctaAlias;
|
||||
if (allowedCtId.HasValue && allowedCtSort.HasValue && allowedCtAlias != null)
|
||||
{
|
||||
var ctSort = new ContentTypeSort(new Lazy<int>(() => allowedCtId.Value), allowedCtSort.Value, allowedCtAlias);
|
||||
if (currAllowedContentTypes.Contains(ctSort) == false)
|
||||
{
|
||||
Alias = ct.ctAlias,
|
||||
AllowAtRoot = ct.ctAllowAtRoot,
|
||||
Description = ct.ctDesc,
|
||||
Icon = ct.ctIcon,
|
||||
IsContainer = ct.ctIsContainer,
|
||||
NodeId = ct.ctId,
|
||||
PrimaryKey = ct.ctPk,
|
||||
Thumbnail = ct.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = ct.nCreateDate,
|
||||
Level = (short)ct.nLevel,
|
||||
NodeId = ct.ctId,
|
||||
NodeObjectType = ct.nObjectType,
|
||||
ParentId = ct.nParentId,
|
||||
Path = ct.nPath,
|
||||
SortOrder = ct.nSortOrder,
|
||||
Text = ct.nName,
|
||||
Trashed = ct.nTrashed,
|
||||
UniqueId = ct.nUniqueId,
|
||||
UserId = ct.nUser
|
||||
}
|
||||
},
|
||||
ContentTypeNodeId = ct.ctId,
|
||||
IsDefault = defaultTemplate != null,
|
||||
TemplateNodeId = defaultTemplate != null ? defaultTemplate.Item2.Value : 0,
|
||||
};
|
||||
currAllowedContentTypes.Add(ctSort);
|
||||
}
|
||||
}
|
||||
|
||||
// We will map a subset of the associated template - alias, id, name
|
||||
//always ensure there's a list for this content type
|
||||
if (parentContentTypeIds.ContainsKey(ct.ctId) == false)
|
||||
parentContentTypeIds[ct.ctId] = new List<int>();
|
||||
|
||||
associatedTemplates.Add(currentCtId, result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Where(x => x.tId != null)
|
||||
.Select(x => new AssociatedTemplate(x.tId, x.tAlias, x.tText))
|
||||
.Distinct()
|
||||
.ToArray());
|
||||
//check for parent ids and assign to the outgoing collection
|
||||
int? parentId = ct.chtParentId;
|
||||
if (parentId.HasValue)
|
||||
{
|
||||
var associatedParentIds = parentContentTypeIds[ct.ctId];
|
||||
|
||||
//now create the content type object
|
||||
if (associatedParentIds.Contains(parentId.Value) == false)
|
||||
associatedParentIds.Add(parentId.Value);
|
||||
}
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var contentType = factory.BuildContentTypeEntity(dtDto.ContentTypeDto);
|
||||
|
||||
// NOTE
|
||||
// that was done by the factory but makes little sense, moved here, so
|
||||
// now we have to reset dirty props again (as the factory does it) and yet,
|
||||
// we are not managing allowed templates... the whole thing is weird.
|
||||
((ContentType) contentType).DefaultTemplateId = dtDto.TemplateNodeId;
|
||||
contentType.ResetDirtyProperties(false);
|
||||
if (queue.Count == 0 || queue.Peek().ctId != ct.ctId)
|
||||
{
|
||||
//it's the last in the queue or the content type is changing (moving to the next one)
|
||||
var contentType = CreateForMapping(ct, currAllowedContentTypes, currDefaultTemplate);
|
||||
mappedContentTypes.Add(contentType);
|
||||
|
||||
//map the allowed content types
|
||||
//map the child content type ids
|
||||
MapCommonContentTypeObjects(contentType, currentCtId, result, parentContentTypeIds);
|
||||
|
||||
mappedContentTypes.Add(contentType);
|
||||
//Here we need to reset the current variables, we're now collecting data for a different content type
|
||||
currDefaultTemplate = -1;
|
||||
currAllowedContentTypes = new List<ContentTypeSort>();
|
||||
}
|
||||
}
|
||||
|
||||
return mappedContentTypes;
|
||||
}
|
||||
|
||||
private static void MapCommonContentTypeObjects<T, TId>(T contentType, TId currentCtId, List<dynamic> result, IDictionary<TId, IEnumerable<TId>> parentContentTypeIds)
|
||||
where T : IContentTypeBase
|
||||
where TId : struct
|
||||
private static IContentType CreateForMapping(dynamic currCt, List<ContentTypeSort> currAllowedContentTypes, int currDefaultTemplate)
|
||||
{
|
||||
//map the allowed content types
|
||||
contentType.AllowedContentTypes = result
|
||||
.Where(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
//use tuple so we can use distinct on all vals
|
||||
.Select(x => new Tuple<int?, int?, string>(x.ctaAllowedId, x.ctaSortOrder, x.ctaAlias))
|
||||
.Where(x => x.Item1.HasValue && x.Item2.HasValue && x.Item3 != null)
|
||||
.Distinct()
|
||||
.Select(x => new ContentTypeSort(new Lazy<int>(() => x.Item1.Value), x.Item2.Value, x.Item3))
|
||||
.ToList();
|
||||
// * set the default template to the first one if a default isn't found
|
||||
// * create the DTO object
|
||||
// * create the content type object
|
||||
// * map the allowed content types
|
||||
// * add to the outgoing list
|
||||
|
||||
//map the child content type ids
|
||||
parentContentTypeIds.Add(currentCtId, result
|
||||
.Where(x =>
|
||||
var dtDto = new ContentTypeTemplateDto
|
||||
{
|
||||
//create the content type dto
|
||||
ContentTypeDto = new ContentTypeDto
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? x.ctId == currentCtId
|
||||
: x.nUniqueId == currentCtId;
|
||||
})
|
||||
.Select(x =>
|
||||
{
|
||||
//TODO: This is a bit hacky right now but don't have time to do a nice refactor to support both GUID and Int queries, so this is
|
||||
// how it is for now.
|
||||
return (typeof(TId) == typeof(int))
|
||||
? (TId?)x.chtParentId
|
||||
: (TId?)x.chtParentKey;
|
||||
})
|
||||
.Where(x => x.HasValue)
|
||||
.Distinct()
|
||||
.Select(x => x.Value).ToList());
|
||||
Alias = currCt.ctAlias,
|
||||
AllowAtRoot = currCt.ctAllowAtRoot,
|
||||
Description = currCt.ctDesc,
|
||||
Icon = currCt.ctIcon,
|
||||
IsContainer = currCt.ctIsContainer,
|
||||
NodeId = currCt.ctId,
|
||||
PrimaryKey = currCt.ctPk,
|
||||
Thumbnail = currCt.ctThumb,
|
||||
//map the underlying node dto
|
||||
NodeDto = new NodeDto
|
||||
{
|
||||
CreateDate = currCt.nCreateDate,
|
||||
Level = (short)currCt.nLevel,
|
||||
NodeId = currCt.ctId,
|
||||
NodeObjectType = currCt.nObjectType,
|
||||
ParentId = currCt.nParentId,
|
||||
Path = currCt.nPath,
|
||||
SortOrder = currCt.nSortOrder,
|
||||
Text = currCt.nName,
|
||||
Trashed = currCt.nTrashed,
|
||||
UniqueId = currCt.nUniqueId,
|
||||
UserId = currCt.nUser
|
||||
}
|
||||
},
|
||||
ContentTypeNodeId = currCt.ctId,
|
||||
IsDefault = currDefaultTemplate != -1,
|
||||
TemplateNodeId = currDefaultTemplate != -1 ? currDefaultTemplate : 0,
|
||||
};
|
||||
|
||||
//now create the content type object
|
||||
|
||||
var factory = new ContentTypeFactory();
|
||||
var contentType = factory.BuildContentTypeEntity(dtDto.ContentTypeDto);
|
||||
|
||||
// NOTE
|
||||
// that was done by the factory but makes little sense, moved here, so
|
||||
// now we have to reset dirty props again (as the factory does it) and yet,
|
||||
// we are not managing allowed templates... the whole thing is weird.
|
||||
((ContentType)contentType).DefaultTemplateId = dtDto.TemplateNodeId;
|
||||
contentType.ResetDirtyProperties(false);
|
||||
|
||||
//map the allowed content types
|
||||
contentType.AllowedContentTypes = currAllowedContentTypes;
|
||||
|
||||
return contentType;
|
||||
}
|
||||
|
||||
internal static void MapGroupsAndProperties(int[] contentTypeIds, Database db, ISqlSyntaxProvider sqlSyntax,
|
||||
@@ -1101,14 +1050,14 @@ AND umbracoNode.id <> @id",
|
||||
// therefore the union of the two contains all of the property type and property group information we need
|
||||
// NOTE: MySQL requires a SELECT * FROM the inner union in order to be able to sort . lame.
|
||||
|
||||
var sqlBuilder = new StringBuilder(@"SELECT PG.contenttypeNodeId as contentTypeId,
|
||||
PT.ptUniqueId as ptUniqueID, PT.ptId, PT.ptAlias, PT.ptDesc,PT.ptMandatory,PT.ptName,PT.ptSortOrder,PT.ptRegExp,
|
||||
var sqlBuilder = new StringBuilder(@"SELECT PG.contenttypeNodeId as contentTypeId,
|
||||
PT.ptUniqueId as ptUniqueID, PT.ptId, PT.ptAlias, PT.ptDesc,PT.ptMandatory,PT.ptName,PT.ptSortOrder,PT.ptRegExp,
|
||||
PT.dtId,PT.dtDbType,PT.dtPropEdAlias,
|
||||
PG.id as pgId, PG.uniqueID as pgKey, PG.sortorder as pgSortOrder, PG." + sqlSyntax.GetQuotedColumnName("text") + @" as pgText
|
||||
FROM cmsPropertyTypeGroup as PG
|
||||
LEFT JOIN
|
||||
(
|
||||
SELECT PT.uniqueID as ptUniqueId, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
SELECT PT.uniqueID as ptUniqueId, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.mandatory as ptMandatory, PT.Name as ptName, PT.sortOrder as ptSortOrder, PT.validationRegExp as ptRegExp,
|
||||
PT.propertyTypeGroupId as ptGroupId,
|
||||
DT.dbType as dtDbType, DT.nodeId as dtId, DT.propertyEditorAlias as dtPropEdAlias
|
||||
@@ -1118,11 +1067,11 @@ AND umbracoNode.id <> @id",
|
||||
) as PT
|
||||
ON PT.ptGroupId = PG.id
|
||||
WHERE (PG.contenttypeNodeId in (@contentTypeIds))
|
||||
|
||||
|
||||
UNION
|
||||
|
||||
SELECT PT.contentTypeId as contentTypeId,
|
||||
PT.uniqueID as ptUniqueID, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.uniqueID as ptUniqueID, PT.id as ptId, PT.Alias as ptAlias, PT." + sqlSyntax.GetQuotedColumnName("Description") + @" as ptDesc,
|
||||
PT.mandatory as ptMandatory, PT.Name as ptName, PT.sortOrder as ptSortOrder, PT.validationRegExp as ptRegExp,
|
||||
DT.nodeId as dtId, DT.dbType as dtDbType, DT.propertyEditorAlias as dtPropEdAlias,
|
||||
PG.id as pgId, PG.uniqueID as pgKey, PG.sortorder as pgSortOrder, PG." + sqlSyntax.GetQuotedColumnName("text") + @" as pgText
|
||||
@@ -1216,71 +1165,20 @@ AND umbracoNode.id <> @id",
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Inner repository to support the GUID lookups and keep the caching consistent
|
||||
/// </summary>
|
||||
internal class GuidReadOnlyContentTypeBaseRepository : PetaPocoRepositoryBase<Guid, TEntity>
|
||||
{
|
||||
private readonly ContentTypeBaseRepository<TEntity> _parentRepo;
|
||||
|
||||
public GuidReadOnlyContentTypeBaseRepository(
|
||||
ContentTypeBaseRepository<TEntity> parentRepo,
|
||||
IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
_parentRepo = parentRepo;
|
||||
}
|
||||
|
||||
protected override TEntity PerformGet(Guid id)
|
||||
{
|
||||
return _parentRepo.PerformGet(id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<TEntity> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
return _parentRepo.PerformGetAll(ids);
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
return _parentRepo.GetBaseQuery(isCount);
|
||||
}
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
return "umbracoNode.uniqueID = @Id";
|
||||
}
|
||||
|
||||
#region No implementation required
|
||||
protected override IEnumerable<TEntity> PerformGetByQuery(IQuery<TEntity> query)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
}
|
||||
|
||||
protected override void PersistNewItem(TEntity entity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void PersistUpdatedItem(TEntity entity)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
protected abstract TEntity PerformGet(Guid id);
|
||||
protected abstract TEntity PerformGet(string alias);
|
||||
protected abstract IEnumerable<TEntity> PerformGetAll(params Guid[] ids);
|
||||
protected abstract bool PerformExists(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Gets an Entity by alias
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <returns></returns>
|
||||
public TEntity Get(string alias)
|
||||
{
|
||||
return PerformGet(alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an Entity by Id
|
||||
@@ -1289,7 +1187,7 @@ AND umbracoNode.id <> @id",
|
||||
/// <returns></returns>
|
||||
public TEntity Get(Guid id)
|
||||
{
|
||||
return _guidRepo.Get(id);
|
||||
return PerformGet(id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1297,9 +1195,12 @@ AND umbracoNode.id <> @id",
|
||||
/// </summary>
|
||||
/// <param name="ids"></param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<TEntity> GetAll(params Guid[] ids)
|
||||
/// <remarks>
|
||||
/// Ensure explicit implementation, we don't want to have any accidental calls to this since it is essentially the same signature as the main GetAll when there are no parameters
|
||||
/// </remarks>
|
||||
IEnumerable<TEntity> IReadRepository<Guid, TEntity>.GetAll(params Guid[] ids)
|
||||
{
|
||||
return _guidRepo.GetAll(ids);
|
||||
return PerformGetAll(ids);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1309,7 +1210,21 @@ AND umbracoNode.id <> @id",
|
||||
/// <returns></returns>
|
||||
public bool Exists(Guid id)
|
||||
{
|
||||
return _guidRepo.Exists(id);
|
||||
return PerformExists(id);
|
||||
}
|
||||
|
||||
public string GetUniqueAlias(string alias)
|
||||
{
|
||||
// alias is unique accross ALL content types!
|
||||
var aliasColumn = SqlSyntax.GetQuotedColumnName("alias");
|
||||
var aliases = Database.Fetch<string>(@"SELECT cmsContentType." + aliasColumn + @" FROM cmsContentType
|
||||
INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id
|
||||
WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
|
||||
new { pattern = alias + "%", objectType = NodeObjectTypeId });
|
||||
var i = 1;
|
||||
string test;
|
||||
while (aliases.Contains(test = alias + i)) i++;
|
||||
return test;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -28,42 +29,54 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
_templateRepository = templateRepository;
|
||||
}
|
||||
}
|
||||
|
||||
private FullDataSetRepositoryCachePolicyFactory<IContentType, int> _cachePolicyFactory;
|
||||
protected override IRepositoryCachePolicyFactory<IContentType, int> CachePolicyFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IContentType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires:true));
|
||||
}
|
||||
}
|
||||
|
||||
protected override IContentType PerformGet(int id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetContentTypes(
|
||||
new[] {id}, Database, SqlSyntax, this, _templateRepository);
|
||||
|
||||
var contentType = contentTypes.SingleOrDefault();
|
||||
return contentType;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetAll(params int[] ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
return ContentTypeQueryMapper.GetContentTypes(ids, Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
//NOTE: This logic should never be executed according to our cache policy
|
||||
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository)
|
||||
.Where(x => ids.Contains(x.Id));
|
||||
}
|
||||
|
||||
return ContentTypeQueryMapper.GetContentTypes(Database, SqlSyntax, this, _templateRepository);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetByQuery(IQuery<IContentType> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IContentType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeTemplateDto, ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>();
|
||||
|
||||
return
|
||||
//This returns a lookup from the GetAll cached looup
|
||||
(dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.ContentTypeDto.NodeId).Select(x => x.ContentTypeDto.NodeId).ToArray())
|
||||
: Enumerable.Empty<IContentType>())
|
||||
//order the result by name
|
||||
.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -87,7 +100,30 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
return Database.Fetch<string>("SELECT DISTINCT Alias FROM cmsPropertyType ORDER BY Alias");
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets all content type aliases
|
||||
/// </summary>
|
||||
/// <param name="objectTypes">
|
||||
/// If this list is empty, it will return all content type aliases for media, members and content, otherwise
|
||||
/// it will only return content type aliases for the object types specified
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes)
|
||||
{
|
||||
var sql = new Sql().Select("cmsContentType.alias")
|
||||
.From<ContentTypeDto>(SqlSyntax)
|
||||
.InnerJoin<NodeDto>(SqlSyntax)
|
||||
.On<ContentTypeDto, NodeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.NodeId);
|
||||
|
||||
if (objectTypes.Any())
|
||||
{
|
||||
sql = sql.Where("umbracoNode.nodeObjectType IN (@objectTypes)", objectTypes);
|
||||
}
|
||||
|
||||
return Database.Fetch<string>(sql);
|
||||
}
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
@@ -151,6 +187,22 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
PersistDeletedItem((IEntity)child);
|
||||
}
|
||||
|
||||
//Before we call the base class methods to run all delete clauses, we need to first
|
||||
// delete all of the property data associated with this document type. Normally this will
|
||||
// be done in the ContentTypeService by deleting all associated content first, but in some cases
|
||||
// like when we switch a document type, there is property data left over that is linked
|
||||
// to the previous document type. So we need to ensure it's removed.
|
||||
var sql = new Sql().Select("DISTINCT cmsPropertyData.propertytypeid")
|
||||
.From<PropertyDataDto>(SqlSyntax)
|
||||
.InnerJoin<PropertyTypeDto>(SqlSyntax)
|
||||
.On<PropertyDataDto, PropertyTypeDto>(SqlSyntax, dto => dto.PropertyTypeId, dto => dto.Id)
|
||||
.InnerJoin<ContentTypeDto>(SqlSyntax)
|
||||
.On<ContentTypeDto, PropertyTypeDto>(SqlSyntax, dto => dto.NodeId, dto => dto.ContentTypeId)
|
||||
.Where<ContentTypeDto>(dto => dto.NodeId == entity.Id);
|
||||
|
||||
//Delete all cmsPropertyData where propertytypeid EXISTS in the subquery above
|
||||
Database.Execute(SqlSyntax.GetDeleteSubquery("cmsPropertyData", "propertytypeid", sql));
|
||||
|
||||
base.PersistDeletedItem(entity);
|
||||
}
|
||||
|
||||
@@ -232,25 +284,33 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IContentType PerformGet(Guid id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetContentTypes(
|
||||
new[] { id }, Database, SqlSyntax, this, _templateRepository);
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
var contentType = contentTypes.SingleOrDefault();
|
||||
return contentType;
|
||||
protected override IContentType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
protected override IEnumerable<IContentType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return ContentTypeQueryMapper.GetContentTypes(ids, Database, SqlSyntax, this, _templateRepository);
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetContentTypes(allIds, Database, SqlSyntax, this, _templateRepository);
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,21 +348,29 @@ AND umbracoNode.id <> @id",
|
||||
new MoveEventInfo<IDataTypeDefinition>(toMove, toMove.Path, parentId)
|
||||
};
|
||||
|
||||
var origPath = toMove.Path;
|
||||
|
||||
//do the move to a new parent
|
||||
toMove.ParentId = parentId;
|
||||
|
||||
//set the updated path
|
||||
toMove.Path = string.Concat(container == null ? parentId.ToInvariantString() : container.Path, ",", toMove.Id);
|
||||
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(toMove);
|
||||
|
||||
//update all descendants
|
||||
//update all descendants from the original path, update in order of level
|
||||
var descendants = this.GetByQuery(
|
||||
new Query<IDataTypeDefinition>().Where(type => type.Path.StartsWith(toMove.Path + ",")));
|
||||
foreach (var descendant in descendants)
|
||||
new Query<IDataTypeDefinition>().Where(type => type.Path.StartsWith(origPath + ",")));
|
||||
|
||||
var lastParent = toMove;
|
||||
foreach (var descendant in descendants.OrderBy(x => x.Level))
|
||||
{
|
||||
moveInfo.Add(new MoveEventInfo<IDataTypeDefinition>(descendant, descendant.Path, descendant.ParentId));
|
||||
|
||||
//all we're doing here is setting the parent Id to be dirty so that it resets the path/level/etc...
|
||||
descendant.ParentId = descendant.ParentId + 1;
|
||||
descendant.ParentId = descendant.ParentId - 1;
|
||||
descendant.ParentId = lastParent.Id;
|
||||
descendant.Path = string.Concat(lastParent.Path, ",", descendant.Id);
|
||||
|
||||
//schedule it for updating in the transaction
|
||||
AddOrUpdate(descendant);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IDomain, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,16 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
/// </summary>
|
||||
internal class EntityContainerRepository : PetaPocoRepositoryBase<int, EntityContainer>
|
||||
{
|
||||
public EntityContainerRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax)
|
||||
private readonly Guid _containerObjectType;
|
||||
|
||||
public EntityContainerRepository(IDatabaseUnitOfWork work, CacheHelper cache, ILogger logger, ISqlSyntaxProvider sqlSyntax, Guid containerObjectType)
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{ }
|
||||
{
|
||||
var allowedContainers = new[] {Constants.ObjectTypes.DocumentTypeContainerGuid, Constants.ObjectTypes.MediaTypeContainerGuid, Constants.ObjectTypes.DataTypeContainerGuid};
|
||||
_containerObjectType = containerObjectType;
|
||||
if (allowedContainers.Contains(_containerObjectType) == false)
|
||||
throw new InvalidOperationException("No container type exists with ID: " + _containerObjectType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Do not cache anything
|
||||
@@ -32,7 +39,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override EntityContainer PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where(GetBaseWhereClause(), new { id });
|
||||
var sql = GetBaseQuery(false).Where(GetBaseWhereClause(), new { id = id, NodeObjectType = NodeObjectTypeId });
|
||||
|
||||
var nodeDto = Database.Fetch<NodeDto>(sql).FirstOrDefault();
|
||||
return nodeDto == null ? null : CreateEntity(nodeDto);
|
||||
@@ -47,15 +54,25 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
return nodeDto == null ? null : CreateEntity(nodeDto);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> Get(string name, int level, Guid umbracoObjectTypeId)
|
||||
public IEnumerable<EntityContainer> Get(string name, int level)
|
||||
{
|
||||
var sql = GetBaseQuery(false).Where("text=@name AND level=@level AND nodeObjectType=@umbracoObjectTypeId", new { name, level, umbracoObjectTypeId });
|
||||
var sql = GetBaseQuery(false).Where("text=@name AND level=@level AND nodeObjectType=@umbracoObjectTypeId", new { name, level, umbracoObjectTypeId = NodeObjectTypeId });
|
||||
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
|
||||
}
|
||||
|
||||
protected override IEnumerable<EntityContainer> PerformGetAll(params int[] ids)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
//we need to batch these in groups of 2000 so we don't exceed the max 2100 limit
|
||||
return ids.InGroupsOf(2000).SelectMany(@group =>
|
||||
{
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where("nodeObjectType=@umbracoObjectTypeId", new { umbracoObjectTypeId = NodeObjectTypeId })
|
||||
.Where(string.Format("{0} IN (@ids)", SqlSyntax.GetQuotedColumnName("id")), new { ids = @group });
|
||||
|
||||
sql.OrderBy<NodeDto>(x => x.Level, SqlSyntax);
|
||||
|
||||
return Database.Fetch<NodeDto>(sql).Select(CreateEntity);
|
||||
});
|
||||
}
|
||||
|
||||
protected override IEnumerable<EntityContainer> PerformGetByQuery(IQuery<EntityContainer> query)
|
||||
@@ -99,7 +116,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override string GetBaseWhereClause()
|
||||
{
|
||||
return "umbracoNode.id = @id"; //" and nodeObjectType = @NodeObjectType";
|
||||
return "umbracoNode.id = @id and nodeObjectType = @NodeObjectType";
|
||||
}
|
||||
|
||||
protected override IEnumerable<string> GetDeleteClauses()
|
||||
@@ -109,11 +126,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override Guid NodeObjectTypeId
|
||||
{
|
||||
get { throw new NotImplementedException(); }
|
||||
get { return _containerObjectType; }
|
||||
}
|
||||
|
||||
protected override void PersistDeletedItem(EntityContainer entity)
|
||||
{
|
||||
EnsureContainerType(entity);
|
||||
|
||||
var nodeDto = Database.FirstOrDefault<NodeDto>(new Sql().Select("*")
|
||||
.From<NodeDto>(SqlSyntax)
|
||||
.Where<NodeDto>(dto => dto.NodeId == entity.Id && dto.NodeObjectType == entity.ContainerObjectType));
|
||||
@@ -143,6 +162,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override void PersistNewItem(EntityContainer entity)
|
||||
{
|
||||
EnsureContainerType(entity);
|
||||
|
||||
entity.Name = entity.Name.Trim();
|
||||
Mandate.ParameterNotNullOrEmpty(entity.Name, "entity.Name");
|
||||
|
||||
@@ -202,6 +223,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//
|
||||
protected override void PersistUpdatedItem(EntityContainer entity)
|
||||
{
|
||||
EnsureContainerType(entity);
|
||||
|
||||
entity.Name = entity.Name.Trim();
|
||||
Mandate.ParameterNotNullOrEmpty(entity.Name, "entity.Name");
|
||||
|
||||
@@ -251,5 +274,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
entity.SortOrder = 0;
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
private void EnsureContainerType(EntityContainer entity)
|
||||
{
|
||||
if (entity.ContainerObjectType != NodeObjectTypeId)
|
||||
{
|
||||
throw new InvalidOperationException("The container type does not match the repository object type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeCompositionRepository<TEntity> : IRepositoryQueryable<int, TEntity>, IReadRepository<Guid, TEntity>
|
||||
where TEntity : IContentTypeComposition
|
||||
{
|
||||
TEntity Get(string alias);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IContentTypeRepository : IRepositoryQueryable<int, IContentType>, IReadRepository<Guid, IContentType>
|
||||
public interface IContentTypeRepository : IContentTypeCompositionRepository<IContentType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
@@ -22,5 +22,23 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<string> GetAllPropertyTypeAliases();
|
||||
|
||||
IEnumerable<MoveEventInfo<IContentType>> Move(IContentType toMove, EntityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all content type aliases
|
||||
/// </summary>
|
||||
/// <param name="objectTypes">
|
||||
/// If this list is empty, it will return all content type aliases for media, members and content, otherwise
|
||||
/// it will only return content type aliases for the object types specified
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Derives a unique alias from an existing alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The original alias.</param>
|
||||
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
|
||||
/// /// <remarks>Unique accross all content, media and member types.</remarks>
|
||||
string GetUniqueAlias(string alias);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IMediaTypeRepository : IRepositoryQueryable<int, IMediaType>, IReadRepository<Guid, IMediaType>
|
||||
public interface IMediaTypeRepository : IContentTypeCompositionRepository<IMediaType>
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets all entities of the specified <see cref="PropertyType"/> query
|
||||
@@ -16,5 +15,13 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
|
||||
|
||||
IEnumerable<MoveEventInfo<IMediaType>> Move(IMediaType toMove, EntityContainer container);
|
||||
|
||||
/// <summary>
|
||||
/// Derives a unique alias from an existing alias.
|
||||
/// </summary>
|
||||
/// <param name="alias">The original alias.</param>
|
||||
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
|
||||
/// <remarks>Unique accross all content, media and member types.</remarks>
|
||||
string GetUniqueAlias(string alias);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
public interface IMemberTypeRepository : IRepositoryQueryable<int, IMemberType>, IReadRepository<Guid, IMemberType>
|
||||
public interface IMemberTypeRepository : IContentTypeCompositionRepository<IMemberType>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ILanguage, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Exceptions;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -26,41 +27,53 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
: base(work, cache, logger, sqlSyntax)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private FullDataSetRepositoryCachePolicyFactory<IMediaType, int> _cachePolicyFactory;
|
||||
protected override IRepositoryCachePolicyFactory<IMediaType, int> CachePolicyFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMediaType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires: true));
|
||||
}
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(int id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
|
||||
new[] { id }, Database, SqlSyntax, this);
|
||||
|
||||
var contentType = contentTypes.SingleOrDefault();
|
||||
return contentType;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetAll(params int[] ids)
|
||||
{
|
||||
if (ids.Any())
|
||||
{
|
||||
return ContentTypeQueryMapper.GetMediaTypes(ids, Database, SqlSyntax, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
|
||||
//NOTE: This logic should never be executed according to our cache policy
|
||||
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this)
|
||||
.Where(x => ids.Contains(x.Id));
|
||||
}
|
||||
|
||||
return ContentTypeQueryMapper.GetMediaTypes(Database, SqlSyntax, this);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetByQuery(IQuery<IMediaType> query)
|
||||
{
|
||||
var sqlClause = GetBaseQuery(false);
|
||||
var translator = new SqlTranslator<IMediaType>(sqlClause, query);
|
||||
var sql = translator.Translate()
|
||||
.OrderBy<NodeDto>(x => x.Text, SqlSyntax);
|
||||
var sql = translator.Translate();
|
||||
|
||||
var dtos = Database.Fetch<ContentTypeDto, NodeDto>(sql);
|
||||
return dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>();
|
||||
|
||||
return
|
||||
//This returns a lookup from the GetAll cached looup
|
||||
(dtos.Any()
|
||||
? GetAll(dtos.DistinctBy(x => x.NodeId).Select(x => x.NodeId).ToArray())
|
||||
: Enumerable.Empty<IMediaType>())
|
||||
//order the result by name
|
||||
.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -149,28 +162,36 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
|
||||
protected override IMediaType PerformGet(Guid id)
|
||||
{
|
||||
var contentTypes = ContentTypeQueryMapper.GetMediaTypes(
|
||||
new[] { id }, Database, SqlSyntax, this);
|
||||
|
||||
var contentType = contentTypes.SingleOrDefault();
|
||||
return contentType;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMediaType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
return ContentTypeQueryMapper.GetMediaTypes(ids, Database, SqlSyntax, this);
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
var sql = new Sql().Select("id").From<NodeDto>(SqlSyntax).Where<NodeDto>(dto => dto.NodeObjectType == NodeObjectTypeId);
|
||||
var allIds = Database.Fetch<int>(sql).ToArray();
|
||||
return ContentTypeQueryMapper.GetMediaTypes(allIds, Database, SqlSyntax, this);
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
protected override IMediaType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using log4net;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -26,25 +27,23 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
}
|
||||
|
||||
#region Overrides of RepositoryBase<int, IMemberType>
|
||||
|
||||
private FullDataSetRepositoryCachePolicyFactory<IMemberType, int> _cachePolicyFactory;
|
||||
protected override IRepositoryCachePolicyFactory<IMemberType, int> CachePolicyFactory
|
||||
{
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<IMemberType, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(),
|
||||
//allow this cache to expire
|
||||
expires: true));
|
||||
}
|
||||
}
|
||||
|
||||
protected override IMemberType PerformGet(int id)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where(GetBaseWhereClause(), new { Id = id });
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
new PropertyTypePropertyGroupRelator().Map, sql);
|
||||
|
||||
if (dtos == null || dtos.Any() == false)
|
||||
return null;
|
||||
|
||||
var factory = new MemberTypeReadOnlyFactory();
|
||||
var member = factory.BuildEntity(dtos.First());
|
||||
|
||||
return member;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Id == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMemberType> PerformGetAll(params int[] ids)
|
||||
@@ -52,10 +51,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var sql = GetBaseQuery(false);
|
||||
if (ids.Any())
|
||||
{
|
||||
//NOTE: This logic should never be executed according to our cache policy
|
||||
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.id='{0}'", x)));
|
||||
sql.Where(statement);
|
||||
}
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId);
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
@@ -71,7 +71,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var subquery = translator.Translate();
|
||||
var sql = GetBaseQuery(false)
|
||||
.Append(new Sql("WHERE umbracoNode.id IN (" + subquery.SQL + ")", subquery.Arguments))
|
||||
.OrderBy<NodeDto>(x => x.SortOrder);
|
||||
.OrderBy<NodeDto>(x => x.SortOrder, SqlSyntax);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
@@ -79,11 +79,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
return BuildFromDtos(dtos);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides of PetaPocoRepositoryBase<int, IMemberType>
|
||||
|
||||
|
||||
protected override Sql GetBaseQuery(bool isCount)
|
||||
{
|
||||
var sql = new Sql();
|
||||
@@ -157,11 +153,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
get { return new Guid(Constants.ObjectTypes.MemberType); }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Unit of Work Implementation
|
||||
|
||||
|
||||
protected override void PersistNewItem(IMemberType entity)
|
||||
{
|
||||
ValidateAlias(entity);
|
||||
@@ -232,8 +224,6 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Override so we can specify explicit db type's on any property types that are built-in.
|
||||
@@ -256,38 +246,33 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
protected override IMemberType PerformGet(Guid id)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
sql.Where("umbracoNode.uniqueID = @Id", new { Id = id });
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId);
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
new PropertyTypePropertyGroupRelator().Map, sql);
|
||||
|
||||
if (dtos == null || dtos.Any() == false)
|
||||
return null;
|
||||
|
||||
var factory = new MemberTypeReadOnlyFactory();
|
||||
var member = factory.BuildEntity(dtos.First());
|
||||
|
||||
return member;
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Key == id);
|
||||
}
|
||||
|
||||
protected override IEnumerable<IMemberType> PerformGetAll(params Guid[] ids)
|
||||
{
|
||||
var sql = GetBaseQuery(false);
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
|
||||
if (ids.Any())
|
||||
{
|
||||
var statement = string.Join(" OR ", ids.Select(x => string.Format("umbracoNode.uniqueID='{0}'", x)));
|
||||
sql.Where(statement);
|
||||
return GetAll().Where(x => ids.Contains(x.Key));
|
||||
}
|
||||
sql.OrderByDescending<NodeDto>(x => x.NodeId, SqlSyntax);
|
||||
else
|
||||
{
|
||||
return GetAll();
|
||||
}
|
||||
}
|
||||
|
||||
var dtos =
|
||||
Database.Fetch<MemberTypeReadOnlyDto, PropertyTypeReadOnlyDto, PropertyTypeGroupReadOnlyDto, MemberTypeReadOnlyDto>(
|
||||
new PropertyTypePropertyGroupRelator().Map, sql);
|
||||
protected override bool PerformExists(Guid id)
|
||||
{
|
||||
return GetAll().FirstOrDefault(x => x.Key == id) != null;
|
||||
}
|
||||
|
||||
return BuildFromDtos(dtos);
|
||||
protected override IMemberType PerformGet(string alias)
|
||||
{
|
||||
//use the underlying GetAll which will force cache all content types
|
||||
return GetAll().FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -26,7 +26,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<PublicAccessEntry, Guid>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected virtual TId GetEntityId(TEntity entity)
|
||||
{
|
||||
return (TId)(object)entity.Id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The runtime cache used for this repo by default is the isolated cache for this type
|
||||
@@ -179,7 +183,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
using (var p = CachePolicyFactory.CreatePolicy())
|
||||
{
|
||||
return p.GetAll(ids, PerformGetAll);
|
||||
var result = p.GetAll(ids, PerformGetAll);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
get
|
||||
{
|
||||
//Use a FullDataSet cache policy - this will cache the entire GetAll result in a single collection
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(RuntimeCache));
|
||||
return _cachePolicyFactory ?? (_cachePolicyFactory = new FullDataSetRepositoryCachePolicyFactory<ITemplate, int>(
|
||||
RuntimeCache, GetEntityId, () => PerformGetAll(), false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,7 +476,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
if (aliases.Any() == false) return base.GetAll();
|
||||
|
||||
//return from base.GetAll, this is all cached
|
||||
return base.GetAll().Where(x => aliases.Contains(x.Alias));
|
||||
return base.GetAll().Where(x => aliases.InvariantContains(x.Alias));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetChildren(int masterTemplateId)
|
||||
@@ -488,7 +489,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var parent = all.FirstOrDefault(x => x.Id == masterTemplateId);
|
||||
if (parent == null) return Enumerable.Empty<ITemplate>();
|
||||
|
||||
var children = all.Where(x => x.MasterTemplateAlias == parent.Alias);
|
||||
var children = all.Where(x => x.MasterTemplateAlias.InvariantEquals(parent.Alias));
|
||||
return children;
|
||||
}
|
||||
|
||||
@@ -497,7 +498,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//return from base.GetAll, this is all cached
|
||||
return base.GetAll().Where(x => alias.IsNullOrWhiteSpace()
|
||||
? x.MasterTemplateAlias.IsNullOrWhiteSpace()
|
||||
: x.MasterTemplateAlias == alias);
|
||||
: x.MasterTemplateAlias.InvariantEquals(alias));
|
||||
}
|
||||
|
||||
public IEnumerable<ITemplate> GetDescendants(int masterTemplateId)
|
||||
@@ -532,7 +533,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var descendants = new List<ITemplate>();
|
||||
if (alias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
var parent = all.FirstOrDefault(x => x.Alias == alias);
|
||||
var parent = all.FirstOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
if (parent == null) return Enumerable.Empty<ITemplate>();
|
||||
//recursively add all children
|
||||
AddChildren(all, descendants, parent.Alias);
|
||||
@@ -552,7 +553,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private void AddChildren(ITemplate[] all, List<ITemplate> descendants, string masterAlias)
|
||||
{
|
||||
var c = all.Where(x => x.MasterTemplateAlias == masterAlias).ToArray();
|
||||
var c = all.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray();
|
||||
descendants.AddRange(c);
|
||||
if (c.Any() == false) return;
|
||||
//recurse through all children
|
||||
@@ -573,7 +574,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
//first get all template objects
|
||||
var allTemplates = base.GetAll().ToArray();
|
||||
|
||||
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias == alias);
|
||||
var selfTemplate = allTemplates.SingleOrDefault(x => x.Alias.InvariantEquals(alias));
|
||||
if (selfTemplate == null)
|
||||
{
|
||||
return null;
|
||||
@@ -582,11 +583,11 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
var top = selfTemplate;
|
||||
while (top.MasterTemplateAlias.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
top = allTemplates.Single(x => x.Alias == top.MasterTemplateAlias);
|
||||
top = allTemplates.Single(x => x.Alias.InvariantEquals(top.MasterTemplateAlias));
|
||||
}
|
||||
|
||||
var topNode = new TemplateNode(allTemplates.Single(x => x.Id == top.Id));
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias == top.Alias);
|
||||
var childTemplates = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(top.Alias));
|
||||
//This now creates the hierarchy recursively
|
||||
topNode.Children = CreateChildren(topNode, childTemplates, allTemplates);
|
||||
|
||||
@@ -598,7 +599,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
private static TemplateNode WalkTree(TemplateNode current, string alias)
|
||||
{
|
||||
//now walk the tree to find the node
|
||||
if (current.Template.Alias == alias)
|
||||
if (current.Template.Alias.InvariantEquals(alias))
|
||||
{
|
||||
return current;
|
||||
}
|
||||
@@ -730,7 +731,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//get this node's children
|
||||
var local = childTemplate;
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias == local.Alias);
|
||||
var kids = allTemplates.Where(x => x.MasterTemplateAlias.InvariantEquals(local.Alias));
|
||||
|
||||
//recurse
|
||||
child.Children = CreateChildren(child, kids, allTemplates);
|
||||
@@ -760,7 +761,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
private bool AliasAlreadExists(ITemplate template)
|
||||
{
|
||||
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias == template.Alias && x.NodeId != template.Id);
|
||||
var sql = GetBaseQuery(true).Where<TemplateDto>(x => x.Alias.InvariantEquals(template.Alias) && x.NodeId != template.Id);
|
||||
var count = Database.ExecuteScalar<int>(sql);
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
@@ -31,29 +31,27 @@ namespace Umbraco.Core.Persistence
|
||||
//if (sqlSyntax == null) throw new ArgumentNullException("sqlSyntax");
|
||||
if (settings == null) throw new ArgumentNullException("settings");
|
||||
|
||||
_cacheHelper = cacheHelper;
|
||||
_cacheHelper = cacheHelper;
|
||||
|
||||
//IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying
|
||||
// runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks
|
||||
// changes entities are reset.
|
||||
if ((_cacheHelper.RuntimeCache is DeepCloneRuntimeCacheProvider) == false)
|
||||
{
|
||||
var originalHelper = cacheHelper;
|
||||
|
||||
_cacheHelper = new CacheHelper(
|
||||
new DeepCloneRuntimeCacheProvider(originalHelper.RuntimeCache),
|
||||
originalHelper.StaticCache,
|
||||
originalHelper.RequestCache,
|
||||
new IsolatedRuntimeCache(type =>
|
||||
{
|
||||
var cache = originalHelper.IsolatedRuntimeCache.GetOrCreateCache(type);
|
||||
return (cache is DeepCloneRuntimeCacheProvider) == false
|
||||
//wrap the original if it's not DeepCloneRuntimeCacheProvider
|
||||
? new DeepCloneRuntimeCacheProvider(cache)
|
||||
: cache;
|
||||
}));
|
||||
var origRuntimeCache = cacheHelper.RuntimeCache;
|
||||
_cacheHelper.RuntimeCache = new DeepCloneRuntimeCacheProvider(origRuntimeCache);
|
||||
}
|
||||
|
||||
//If the factory for isolated cache doesn't return DeepCloneRuntimeCacheProvider, then ensure it does
|
||||
if (_cacheHelper.IsolatedRuntimeCache.CacheFactory.Method.ReturnType != typeof (DeepCloneRuntimeCacheProvider))
|
||||
{
|
||||
var origFactory = cacheHelper.IsolatedRuntimeCache.CacheFactory;
|
||||
_cacheHelper.IsolatedRuntimeCache.CacheFactory = type =>
|
||||
{
|
||||
var cache = origFactory(type);
|
||||
return new DeepCloneRuntimeCacheProvider(cache);
|
||||
};
|
||||
}
|
||||
|
||||
_noCache = CacheHelper.CreateDisabledCacheHelper();
|
||||
_logger = logger;
|
||||
_sqlSyntax = sqlSyntax;
|
||||
@@ -327,12 +325,13 @@ namespace Umbraco.Core.Persistence
|
||||
_logger, _sqlSyntax);
|
||||
}
|
||||
|
||||
internal virtual EntityContainerRepository CreateEntityContainerRepository(IDatabaseUnitOfWork uow)
|
||||
internal virtual EntityContainerRepository CreateEntityContainerRepository(IDatabaseUnitOfWork uow, Guid containerObjectType)
|
||||
{
|
||||
return new EntityContainerRepository(
|
||||
uow,
|
||||
_cacheHelper,
|
||||
_logger, _sqlSyntax);
|
||||
_logger, _sqlSyntax,
|
||||
containerObjectType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
|
||||
GuidColumnDefinition = "char(36)";
|
||||
|
||||
DefaultValueFormat = "DEFAULT {0}";
|
||||
|
||||
InitColumnTypeMap();
|
||||
}
|
||||
|
||||
public override IEnumerable<string> GetTablesInSchema(Database db)
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Umbraco.Core.Persistence
|
||||
/// Represents the Umbraco implementation of the PetaPoco Database object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently this object exists for 'future proofing' our implementation. By having our own inheritied implementation we
|
||||
/// Currently this object exists for 'future proofing' our implementation. By having our own inheritied implementation we
|
||||
/// can then override any additional execution (such as additional loggging, functionality, etc...) that we need to without breaking compatibility since we'll always be exposing
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// this object instead of the base PetaPoco database object.
|
||||
/// </remarks>
|
||||
public class UmbracoDatabase : Database, IDisposeOnRequestEnd
|
||||
{
|
||||
@@ -111,7 +111,9 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
public override IDbConnection OnConnectionOpened(IDbConnection connection)
|
||||
{
|
||||
// wrap the connection with a profiling connection that tracks timings
|
||||
// propagate timeout if none yet
|
||||
|
||||
// wrap the connection with a profiling connection that tracks timings
|
||||
return new StackExchange.Profiling.Data.ProfiledDbConnection(connection as DbConnection, MiniProfiler.Current);
|
||||
}
|
||||
|
||||
@@ -121,6 +123,14 @@ namespace Umbraco.Core.Persistence
|
||||
base.OnException(x);
|
||||
}
|
||||
|
||||
public override void OnExecutingCommand(IDbCommand cmd)
|
||||
{
|
||||
// if no timeout is specified, and the connection has a longer timeout, use it
|
||||
if (OneTimeCommandTimeout == 0 && CommandTimeout == 0 && cmd.Connection.ConnectionTimeout > 30)
|
||||
cmd.CommandTimeout = cmd.Connection.ConnectionTimeout;
|
||||
base.OnExecutingCommand(cmd);
|
||||
}
|
||||
|
||||
public override void OnExecutedCommand(IDbCommand cmd)
|
||||
{
|
||||
if (EnableSqlTrace)
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <summary>
|
||||
/// Manages the list of IPropertyEditorValueConverter's
|
||||
/// </summary>
|
||||
[Obsolete("IPropertyEditorValueConverter is obsolete, but we need to support them until v8, to resolve the correct converter types use: PropertyValueConvertersResolver")]
|
||||
internal sealed class PropertyEditorValueConvertersResolver : ManyObjectsResolverBase<PropertyEditorValueConvertersResolver, IPropertyEditorValueConverter>
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -12,6 +12,9 @@ using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// This ensures that the grid config is merged in with the front-end value
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
|
||||
[PropertyValueType(typeof(JToken))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
@@ -90,7 +93,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<JsonValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
|
||||
LogHelper.Error<GridValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// This ensures that the cropper config (pre-values/crops) are merged in with the front-end value.
|
||||
/// </summary>
|
||||
[DefaultPropertyValueConverter(typeof (JsonValueConverter))] //this shadows the JsonValueConverter
|
||||
[PropertyValueType(typeof (JToken))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
public class ImageCropperValueConverter : JsonValueConverter
|
||||
{
|
||||
private readonly IDataTypeService _dataTypeService;
|
||||
|
||||
public ImageCropperValueConverter()
|
||||
{
|
||||
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
|
||||
}
|
||||
|
||||
public ImageCropperValueConverter(IDataTypeService dataTypeService)
|
||||
{
|
||||
if (dataTypeService == null) throw new ArgumentNullException("dataTypeService");
|
||||
_dataTypeService = dataTypeService;
|
||||
}
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ImageCropperAlias);
|
||||
}
|
||||
|
||||
internal static void MergePreValues(JObject currentValue, IDataTypeService dataTypeService, int dataTypeId)
|
||||
{
|
||||
//need to lookup the pre-values for this data type
|
||||
//TODO: Change all singleton access to use ctor injection in v8!!!
|
||||
var dt = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeId);
|
||||
|
||||
if (dt != null && dt.IsDictionaryBased && dt.PreValuesAsDictionary.ContainsKey("crops"))
|
||||
{
|
||||
var cropsString = dt.PreValuesAsDictionary["crops"].Value;
|
||||
JArray preValueCrops;
|
||||
try
|
||||
{
|
||||
preValueCrops = JsonConvert.DeserializeObject<JArray>(cropsString);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ImageCropperValueConverter>("Could not parse the string " + cropsString + " to a json object", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
//now we need to merge the crop values - the alias + width + height comes from pre-configured pre-values,
|
||||
// however, each crop can store it's own coordinates
|
||||
|
||||
JArray existingCropsArray;
|
||||
if (currentValue["crops"] != null)
|
||||
{
|
||||
existingCropsArray = (JArray)currentValue["crops"];
|
||||
}
|
||||
else
|
||||
{
|
||||
currentValue["crops"] = existingCropsArray = new JArray();
|
||||
}
|
||||
|
||||
foreach (var preValueCrop in preValueCrops.Where(x => x.HasValues))
|
||||
{
|
||||
var found = existingCropsArray.FirstOrDefault(x =>
|
||||
{
|
||||
if (x.HasValues && x["alias"] != null)
|
||||
{
|
||||
return x["alias"].Value<string>() == preValueCrop["alias"].Value<string>();
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (found != null)
|
||||
{
|
||||
found["width"] = preValueCrop["width"];
|
||||
found["height"] = preValueCrop["height"];
|
||||
}
|
||||
else
|
||||
{
|
||||
existingCropsArray.Add(preValueCrop);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
var sourceString = source.ToString();
|
||||
|
||||
if (sourceString.DetectIsJson())
|
||||
{
|
||||
JObject obj;
|
||||
try
|
||||
{
|
||||
obj = JsonConvert.DeserializeObject<JObject>(sourceString, new JsonSerializerSettings
|
||||
{
|
||||
Culture = CultureInfo.InvariantCulture,
|
||||
FloatParseHandling = FloatParseHandling.Decimal
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ImageCropperValueConverter>("Could not parse the string " + sourceString + " to a json object", ex);
|
||||
return sourceString;
|
||||
}
|
||||
|
||||
MergePreValues(obj, _dataTypeService, propertyType.DataTypeId);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
//it's not json, just return the string
|
||||
return sourceString;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// We need this property converter so that we always force the value of a label to be a string
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Without a property converter defined for the label type, the value will be converted with
|
||||
/// the `ConvertUsingDarkMagic` method which will try to parse the value into it's correct type, but this
|
||||
/// can cause issues if the string is detected as a number and then strips leading zeros.
|
||||
/// Example: http://issues.umbraco.org/issue/U4-7929
|
||||
/// </remarks>
|
||||
[DefaultPropertyValueConverter]
|
||||
[PropertyValueType(typeof (string))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
public class LabelValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias);
|
||||
}
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
return source == null ? string.Empty : source.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,10 +103,18 @@ namespace Umbraco.Core.Security
|
||||
var backOfficeIdentity = http.User.Identity as UmbracoBackOfficeIdentity;
|
||||
if (backOfficeIdentity != null) return backOfficeIdentity;
|
||||
|
||||
//Check if there's more than one identity assigned and see if it's a UmbracoBackOfficeIdentity and use that
|
||||
var claimsPrincipal = http.User as ClaimsPrincipal;
|
||||
if (claimsPrincipal != null)
|
||||
{
|
||||
backOfficeIdentity = claimsPrincipal.Identities.OfType<UmbracoBackOfficeIdentity>().FirstOrDefault();
|
||||
if (backOfficeIdentity != null) return backOfficeIdentity;
|
||||
}
|
||||
|
||||
//Otherwise convert to a UmbracoBackOfficeIdentity if it's auth'd and has the back office session
|
||||
var claimsIdentity = http.User.Identity as ClaimsIdentity;
|
||||
if (claimsIdentity != null && claimsIdentity.IsAuthenticated)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
return UmbracoBackOfficeIdentity.FromClaimsIdentity(claimsIdentity);
|
||||
@@ -167,74 +175,18 @@ namespace Umbraco.Core.Security
|
||||
/// This clears the forms authentication cookie for webapi since cookies are handled differently
|
||||
/// </summary>
|
||||
/// <param name="response"></param>
|
||||
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead")]
|
||||
[Obsolete("Use OWIN IAuthenticationManager.SignOut instead", true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static void UmbracoLogoutWebApi(this HttpResponseMessage response)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException("response");
|
||||
//remove the cookie
|
||||
var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
//remove the preview cookie too
|
||||
var prevCookie = new CookieHeaderValue(Constants.Web.PreviewCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
//remove the external login cookie too
|
||||
var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
|
||||
response.Headers.AddCookies(new[] { authCookie, prevCookie, extLoginCookie });
|
||||
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
||||
}
|
||||
|
||||
[Obsolete("Use WebSecurity.SetPrincipalForRequest")]
|
||||
[Obsolete("Use WebSecurity.SetPrincipalForRequest", true)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static FormsAuthenticationTicket UmbracoLoginWebApi(this HttpResponseMessage response, IUser user)
|
||||
{
|
||||
if (response == null) throw new ArgumentNullException("response");
|
||||
|
||||
//remove the external login cookie
|
||||
var extLoginCookie = new CookieHeaderValue(Constants.Security.BackOfficeExternalCookieName, "")
|
||||
{
|
||||
Expires = DateTime.Now.AddYears(-1),
|
||||
Path = "/"
|
||||
};
|
||||
|
||||
var userDataString = JsonConvert.SerializeObject(Mapper.Map<UserData>(user));
|
||||
|
||||
var ticket = new FormsAuthenticationTicket(
|
||||
4,
|
||||
user.Username,
|
||||
DateTime.Now,
|
||||
DateTime.Now.AddMinutes(GlobalSettings.TimeOutInMinutes),
|
||||
true,
|
||||
userDataString,
|
||||
"/"
|
||||
);
|
||||
|
||||
// Encrypt the cookie using the machine key for secure transport
|
||||
var encrypted = FormsAuthentication.Encrypt(ticket);
|
||||
|
||||
//add the cookie
|
||||
var authCookie = new CookieHeaderValue(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, encrypted)
|
||||
{
|
||||
//Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way
|
||||
Expires = DateTime.Now.AddMinutes(1440),
|
||||
Path = "/",
|
||||
Secure = GlobalSettings.UseSSL,
|
||||
HttpOnly = true
|
||||
};
|
||||
|
||||
response.Headers.AddCookies(new[] { authCookie, extLoginCookie });
|
||||
|
||||
return ticket;
|
||||
throw new NotSupportedException("This method is not supported and should not be used, it has been removed in Umbraco 7.4");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -9,6 +9,12 @@ namespace Umbraco.Core.Security
|
||||
{
|
||||
public class BackOfficeClaimsIdentityFactory : ClaimsIdentityFactory<BackOfficeIdentityUser, int>
|
||||
{
|
||||
public BackOfficeClaimsIdentityFactory()
|
||||
{
|
||||
SecurityStampClaimType = Constants.Security.SessionIdClaimType;
|
||||
UserNameClaimType = ClaimTypes.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a ClaimsIdentity from a user
|
||||
/// </summary>
|
||||
@@ -20,7 +26,7 @@ namespace Umbraco.Core.Security
|
||||
|
||||
var umbracoIdentity = new UmbracoBackOfficeIdentity(baseIdentity,
|
||||
//set a new session id
|
||||
new UserData(Guid.NewGuid().ToString("N"))
|
||||
new UserData
|
||||
{
|
||||
Id = user.Id,
|
||||
Username = user.UserName,
|
||||
@@ -29,7 +35,8 @@ namespace Umbraco.Core.Security
|
||||
Culture = user.Culture,
|
||||
Roles = user.Roles.Select(x => x.RoleId).ToArray(),
|
||||
StartContentNode = user.StartContentId,
|
||||
StartMediaNode = user.StartMediaId
|
||||
StartMediaNode = user.StartMediaId,
|
||||
SessionId = user.SecurityStamp
|
||||
});
|
||||
|
||||
return umbracoIdentity;
|
||||
|
||||
@@ -759,12 +759,13 @@ namespace Umbraco.Core.Security
|
||||
|
||||
//This is the correct way to implement this (as per the sql membership provider)
|
||||
|
||||
switch ((int)PasswordFormat)
|
||||
switch (PasswordFormat)
|
||||
{
|
||||
case 0:
|
||||
case MembershipPasswordFormat.Clear:
|
||||
return pass;
|
||||
case 1:
|
||||
case MembershipPasswordFormat.Hashed:
|
||||
throw new ProviderException("Provider can not decrypt hashed password");
|
||||
case MembershipPasswordFormat.Encrypted:
|
||||
default:
|
||||
var bytes = DecryptPassword(Convert.FromBase64String(pass));
|
||||
return bytes == null ? null : Encoding.Unicode.GetString(bytes, 16, bytes.Length - 16);
|
||||
|
||||
@@ -209,17 +209,19 @@ namespace Umbraco.Core.Security
|
||||
|
||||
if (HasClaim(x => x.Type == ClaimTypes.Locality) == false)
|
||||
AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
|
||||
////TODO: Not sure why this is null sometimes, it shouldn't be. Somewhere it's not being set
|
||||
/// I think it's due to some bug I had in chrome, we'll see
|
||||
//if (UserData.SessionId.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// UserData.SessionId = Guid.NewGuid().ToString();
|
||||
//}
|
||||
|
||||
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false)
|
||||
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
|
||||
//The security stamp claim is also required... this is because this claim type is hard coded
|
||||
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
|
||||
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
|
||||
{
|
||||
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
|
||||
}
|
||||
}
|
||||
|
||||
//Add each app as a separate claim
|
||||
if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false)
|
||||
{
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace Umbraco.Core.Security
|
||||
/// Use this constructor to create/assign new UserData to the ticket
|
||||
/// </summary>
|
||||
/// <param name="sessionId">
|
||||
/// A unique id that is assigned to this ticket
|
||||
/// The security stamp for the user
|
||||
/// </param>
|
||||
public UserData(string sessionId)
|
||||
{
|
||||
@@ -30,8 +30,7 @@ namespace Umbraco.Core.Security
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used to Id the current ticket which we can then use to mitigate csrf attacks
|
||||
/// and other things that require request validation.
|
||||
/// This is the 'security stamp' for validation
|
||||
/// </summary>
|
||||
[DataMember(Name = "sessionId")]
|
||||
public string SessionId { get; set; }
|
||||
@@ -42,8 +41,6 @@ namespace Umbraco.Core.Security
|
||||
[DataMember(Name = "roles")]
|
||||
public string[] Roles { get; set; }
|
||||
|
||||
//public int SessionTimeout { get; set; }
|
||||
|
||||
[DataMember(Name = "username")]
|
||||
public string Username { get; set; }
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Serialization
|
||||
{
|
||||
/// <summary>
|
||||
/// This is required if we want to force JSON.Net to not use .Net TypeConverters during serialization/deserialization
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <remarks>
|
||||
/// In some cases thsi is required if your model has an explicit type converter, see: http://stackoverflow.com/a/31328131/694494
|
||||
///
|
||||
/// NOTE: I was going to use this for the ImageCropDataSetConverter to convert to String, which would have worked by putting this attribute:
|
||||
/// [JsonConverter(typeof(NoTypeConverterJsonConverter{ImageCropDataSet}))] on top of the ImageCropDataSet class, however it turns out we
|
||||
/// don't require this because to convert to string, we just override ToString().
|
||||
/// I'll leave this class here for the future though.
|
||||
/// </remarks>
|
||||
internal class NoTypeConverterJsonConverter<T> : JsonConverter
|
||||
{
|
||||
static readonly IContractResolver resolver = new NoTypeConverterContractResolver();
|
||||
|
||||
private class NoTypeConverterContractResolver : DefaultContractResolver
|
||||
{
|
||||
protected override JsonContract CreateContract(Type objectType)
|
||||
{
|
||||
if (typeof(T).IsAssignableFrom(objectType))
|
||||
{
|
||||
var contract = this.CreateObjectContract(objectType);
|
||||
contract.Converter = null; // Also null out the converter to prevent infinite recursion.
|
||||
return contract;
|
||||
}
|
||||
return base.CreateContract(objectType);
|
||||
}
|
||||
}
|
||||
|
||||
public override bool CanConvert(Type objectType)
|
||||
{
|
||||
return typeof(T).IsAssignableFrom(objectType);
|
||||
}
|
||||
|
||||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||
{
|
||||
return JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Deserialize(reader, objectType);
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||
{
|
||||
JsonSerializer.CreateDefault(new JsonSerializerSettings { ContractResolver = resolver }).Serialize(writer, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Cache;
|
||||
using File = System.IO.File;
|
||||
|
||||
namespace Umbraco.Core.Services
|
||||
@@ -84,7 +83,7 @@ namespace Umbraco.Core.Services
|
||||
// based on the ApplicationTreeRegistrar - and as noted there this is not an ideal way to do things but were stuck like this
|
||||
// currently because of the legacy assemblies and types not in the Core.
|
||||
|
||||
//Get all the trees not registered in the config
|
||||
//Get all the trees not registered in the config (those not matching by alias casing will be detected as "unregistered")
|
||||
var unregistered = _allAvailableTrees
|
||||
.Where(x => list.Any(l => l.Alias == x.Alias) == false)
|
||||
.ToArray();
|
||||
@@ -93,19 +92,46 @@ namespace Umbraco.Core.Services
|
||||
|
||||
if (hasChanges == false) return false;
|
||||
|
||||
//add the unregistered ones to the list and re-save the file if any changes were found
|
||||
//add or edit the unregistered ones and re-save the file if any changes were found
|
||||
var count = 0;
|
||||
foreach (var tree in unregistered)
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("initialize", tree.Initialize),
|
||||
new XAttribute("sortOrder", tree.SortOrder),
|
||||
new XAttribute("alias", tree.Alias),
|
||||
new XAttribute("application", tree.ApplicationAlias),
|
||||
new XAttribute("title", tree.Title),
|
||||
new XAttribute("iconClosed", tree.IconClosed),
|
||||
new XAttribute("iconOpen", tree.IconOpened),
|
||||
new XAttribute("type", tree.Type)));
|
||||
var existingElement = doc.Root.Elements("add").SingleOrDefault(x =>
|
||||
string.Equals(x.Attribute("alias").Value, tree.Alias,
|
||||
StringComparison.InvariantCultureIgnoreCase) &&
|
||||
string.Equals(x.Attribute("application").Value, tree.ApplicationAlias,
|
||||
StringComparison.InvariantCultureIgnoreCase));
|
||||
if (existingElement != null)
|
||||
{
|
||||
existingElement.SetAttributeValue("alias", tree.Alias);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tree.Title.IsNullOrWhiteSpace())
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("initialize", tree.Initialize),
|
||||
new XAttribute("sortOrder", tree.SortOrder),
|
||||
new XAttribute("alias", tree.Alias),
|
||||
new XAttribute("application", tree.ApplicationAlias),
|
||||
new XAttribute("iconClosed", tree.IconClosed),
|
||||
new XAttribute("iconOpen", tree.IconOpened),
|
||||
new XAttribute("type", tree.Type)));
|
||||
}
|
||||
else
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("initialize", tree.Initialize),
|
||||
new XAttribute("sortOrder", tree.SortOrder),
|
||||
new XAttribute("alias", tree.Alias),
|
||||
new XAttribute("application", tree.ApplicationAlias),
|
||||
new XAttribute("title", tree.Title),
|
||||
new XAttribute("iconClosed", tree.IconClosed),
|
||||
new XAttribute("iconOpen", tree.IconOpened),
|
||||
new XAttribute("type", tree.Type)));
|
||||
}
|
||||
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -124,11 +150,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
|
||||
|
||||
}, new TimeSpan(0, 10, 0));
|
||||
}
|
||||
|
||||
@@ -351,13 +373,15 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
list.Add(new ApplicationTree(
|
||||
addElement.Attribute("initialize") == null || Convert.ToBoolean(addElement.Attribute("initialize").Value),
|
||||
addElement.Attribute("sortOrder") != null ? Convert.ToByte(addElement.Attribute("sortOrder").Value) : (byte)0,
|
||||
addElement.Attribute("application").Value,
|
||||
addElement.Attribute("alias").Value,
|
||||
addElement.Attribute("title").Value,
|
||||
addElement.Attribute("iconClosed").Value,
|
||||
addElement.Attribute("iconOpen").Value,
|
||||
addElement.Attribute("type").Value));
|
||||
addElement.Attribute("sortOrder") != null
|
||||
? Convert.ToByte(addElement.Attribute("sortOrder").Value)
|
||||
: (byte)0,
|
||||
(string)addElement.Attribute("application"),
|
||||
(string)addElement.Attribute("alias"),
|
||||
(string)addElement.Attribute("title"),
|
||||
(string)addElement.Attribute("iconClosed"),
|
||||
(string)addElement.Attribute("iconOpen"),
|
||||
(string)addElement.Attribute("type")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -910,7 +910,7 @@ namespace Umbraco.Core.Services
|
||||
new MoveEventArgs<IContent>(evtMsgs, new MoveEventInfo<IContent>(content, originalPath, Constants.System.RecycleBinContent)),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContent>>
|
||||
@@ -957,7 +957,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1080,7 +1080,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IContent>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
using (new WriteLock(Locker))
|
||||
@@ -1124,7 +1124,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1147,7 +1147,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<IContent>(content, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
//Make sure that published content is unpublished before being deleted
|
||||
@@ -1178,7 +1178,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1227,6 +1227,13 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user issueing the delete operation</param>
|
||||
public void DeleteContentOfType(int contentTypeId, int userId = 0)
|
||||
{
|
||||
//TODO: This currently this is called from the ContentTypeService but that needs to change,
|
||||
// if we are deleting a content type, we should just delete the data and do this operation slightly differently.
|
||||
// This method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
using (var uow = UowProvider.GetUnitOfWork())
|
||||
@@ -1709,6 +1716,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: All of this needs to be moved to the repository
|
||||
private void PerformMove(IContent content, int parentId, int userId, ICollection<MoveEventInfo<IContent>> moveInfo)
|
||||
{
|
||||
//add a tracking item to use in the Moved event
|
||||
@@ -2042,7 +2050,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IContent>(content, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2074,7 +2082,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Save Content performed by user", userId, content.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Umbraco.Core.Services
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IMediaService _mediaService;
|
||||
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//Support recursive locks because some of the methods that require locking call other methods that require locking.
|
||||
//for example, the Move method needs to be locked but this calls the Save method which also needs to be locked.
|
||||
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
|
||||
|
||||
@@ -44,10 +44,11 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Containers
|
||||
|
||||
public Attempt<int> CreateContentTypeContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContentTypeContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -57,22 +58,34 @@ namespace Umbraco.Core.Services
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingContentTypeContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
|
||||
SavedContentTypeContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<int> CreateMediaTypeContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateMediaTypeContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -82,130 +95,239 @@ namespace Umbraco.Core.Services
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingMediaTypeContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
|
||||
SavedMediaTypeContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveContentTypeContainer(EntityContainer container, int userId = 0)
|
||||
public Attempt<OperationStatus> SaveContentTypeContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
SaveContainer(container, Constants.ObjectTypes.DocumentTypeGuid, "document type", userId);
|
||||
return SaveContainer(
|
||||
SavingContentTypeContainer, SavedContentTypeContainer,
|
||||
container, Constants.ObjectTypes.DocumentTypeContainerGuid, "document type", userId);
|
||||
}
|
||||
|
||||
public void SaveMediaTypeContainer(EntityContainer container, int userId = 0)
|
||||
public Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
SaveContainer(container, Constants.ObjectTypes.MediaTypeGuid, "media type", userId);
|
||||
return SaveContainer(
|
||||
SavingMediaTypeContainer, SavedMediaTypeContainer,
|
||||
container, Constants.ObjectTypes.MediaTypeContainerGuid, "media type", userId);
|
||||
}
|
||||
|
||||
private void SaveContainer(EntityContainer container, Guid containedObjectType, string objectTypeName, int userId)
|
||||
private Attempt<OperationStatus> SaveContainer(
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savingEvent,
|
||||
TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> savedEvent,
|
||||
EntityContainer container,
|
||||
Guid containerObjectType,
|
||||
string objectTypeName, int userId)
|
||||
{
|
||||
if (container.ContainedObjectType != containedObjectType)
|
||||
throw new InvalidOperationException("Not a " + objectTypeName + " container.");
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (container.ContainedObjectType != containerObjectType)
|
||||
{
|
||||
var ex = new InvalidOperationException("Not a " + objectTypeName + " container.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (container.HasIdentity && container.IsPropertyDirty("ParentId"))
|
||||
throw new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
{
|
||||
var ex = new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (savingEvent.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType))
|
||||
{
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
|
||||
savedEvent.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
public EntityContainer GetContentTypeContainer(int containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeGuid);
|
||||
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeContainerGuid);
|
||||
}
|
||||
|
||||
public EntityContainer GetMediaTypeContainer(int containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeGuid);
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeContainerGuid);
|
||||
}
|
||||
|
||||
private EntityContainer GetContainer(int containerId, Guid containedObjectType)
|
||||
private EntityContainer GetContainer(int containerId, Guid containerObjectType)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
return container != null && container.ContainedObjectType == containedObjectType
|
||||
? container
|
||||
: null;
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetMediaTypeContainers(int[] containerIds)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
{
|
||||
return repo.GetAll(containerIds);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetMediaTypeContainers(string name, int level)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
{
|
||||
return repo.Get(name, level, Constants.ObjectTypes.MediaTypeContainerGuid);
|
||||
return repo.Get(name, level);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetMediaTypeContainers(IMediaType mediaType)
|
||||
{
|
||||
var ancestorIds = mediaType.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x =>
|
||||
{
|
||||
var asInt = x.TryConvertTo<int>();
|
||||
if (asInt) return asInt.Result;
|
||||
return int.MinValue;
|
||||
})
|
||||
.Where(x => x != int.MinValue && x != mediaType.Id)
|
||||
.ToArray();
|
||||
|
||||
return GetMediaTypeContainers(ancestorIds);
|
||||
}
|
||||
|
||||
public EntityContainer GetContentTypeContainer(Guid containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeGuid);
|
||||
return GetContainer(containerId, Constants.ObjectTypes.DocumentTypeContainerGuid);
|
||||
}
|
||||
|
||||
public EntityContainer GetMediaTypeContainer(Guid containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeGuid);
|
||||
}
|
||||
|
||||
private EntityContainer GetContainer(Guid containerId, Guid containedObjectType)
|
||||
|
||||
public IEnumerable<EntityContainer> GetContentTypeContainers(int[] containerIds)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
return repo.GetAll(containerIds);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContentTypeContainers(IContentType contentType)
|
||||
{
|
||||
var ancestorIds = contentType.Path.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x =>
|
||||
{
|
||||
var asInt = x.TryConvertTo<int>();
|
||||
if (asInt) return asInt.Result;
|
||||
return int.MinValue;
|
||||
})
|
||||
.Where(x => x != int.MinValue && x != contentType.Id)
|
||||
.ToArray();
|
||||
|
||||
return GetContentTypeContainers(ancestorIds);
|
||||
}
|
||||
|
||||
public EntityContainer GetMediaTypeContainer(Guid containerId)
|
||||
{
|
||||
return GetContainer(containerId, Constants.ObjectTypes.MediaTypeContainerGuid);
|
||||
}
|
||||
|
||||
private EntityContainer GetContainer(Guid containerId, Guid containerObjectType)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
return container != null && container.ContainedObjectType == containedObjectType
|
||||
? container
|
||||
: null;
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContentTypeContainers(string name, int level)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
return repo.Get(name, level, Constants.ObjectTypes.DocumentTypeContainerGuid);
|
||||
return repo.Get(name, level);
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteContentTypeContainer(int containerId, int userId = 0)
|
||||
public Attempt<OperationStatus> DeleteContentTypeContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return;
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DocumentTypeGuid) return;
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingContentTypeContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
DeletedContentTypeContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteMediaTypeContainer(int containerId, int userId = 0)
|
||||
public Attempt<OperationStatus> DeleteMediaTypeContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return;
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.MediaTypeGuid) return;
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingMediaTypeContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
DeletedMediaTypeContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
@@ -224,6 +346,22 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all content type aliases
|
||||
/// </summary>
|
||||
/// <param name="objectTypes">
|
||||
/// If this list is empty, it will return all content type aliases for media, members and content, otherwise
|
||||
/// it will only return content type aliases for the object types specified
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
public IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes)
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetAllContentTypeAliases(objectTypes);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
|
||||
/// </summary>
|
||||
@@ -242,7 +380,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IContentType Copy(IContentType original, string alias, string name, int parentId = -1)
|
||||
{
|
||||
IContentType parent = null;
|
||||
IContentType parent = null;
|
||||
if (parentId > 0)
|
||||
{
|
||||
parent = GetContentType(parentId);
|
||||
@@ -276,7 +414,7 @@ namespace Umbraco.Core.Services
|
||||
Mandate.ParameterNotNullOrEmpty(alias, "alias");
|
||||
if (parent != null)
|
||||
{
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
|
||||
Mandate.That(parent.HasIdentity, () => new InvalidOperationException("The parent content type must have an identity"));
|
||||
}
|
||||
|
||||
var clone = original.DeepCloneWithResetIdentities(alias);
|
||||
@@ -302,7 +440,7 @@ namespace Umbraco.Core.Services
|
||||
//set to root
|
||||
clone.ParentId = -1;
|
||||
}
|
||||
|
||||
|
||||
Save(clone);
|
||||
return clone;
|
||||
}
|
||||
@@ -329,10 +467,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IContentType>.Builder.Where(x => x.Alias == alias);
|
||||
var contentTypes = repository.GetByQuery(query);
|
||||
|
||||
return contentTypes.FirstOrDefault();
|
||||
return repository.Get(alias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -370,7 +505,7 @@ namespace Umbraco.Core.Services
|
||||
public IEnumerable<IContentType> GetAllContentTypes(IEnumerable<Guid> ids)
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
{
|
||||
return repository.GetAll(ids.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -464,7 +599,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
//this should never occur, the content service should always be typed but we'll check anyways.
|
||||
_contentService.RePublishAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (firstType is IMediaType)
|
||||
{
|
||||
@@ -473,10 +608,10 @@ namespace Umbraco.Core.Services
|
||||
if (typedContentService != null)
|
||||
{
|
||||
typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int CountContentTypes()
|
||||
@@ -526,14 +661,17 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var contentType = compositionContentType as IContentType;
|
||||
var mediaType = compositionContentType as IMediaType;
|
||||
var memberType = compositionContentType as IMemberType; // should NOT do it here but... v8!
|
||||
|
||||
IContentTypeComposition[] allContentTypes;
|
||||
if (contentType != null)
|
||||
allContentTypes = GetAllContentTypes().Cast<IContentTypeComposition>().ToArray();
|
||||
else if (mediaType != null)
|
||||
allContentTypes = GetAllMediaTypes().Cast<IContentTypeComposition>().ToArray();
|
||||
else if (memberType != null)
|
||||
return; // no compositions on members, always validate
|
||||
else
|
||||
throw new Exception("Composition is neither IContentType nor IMediaType?");
|
||||
throw new Exception("Composition is neither IContentType nor IMediaType nor IMemberType?");
|
||||
|
||||
var compositionAliases = compositionContentType.CompositionAliases();
|
||||
var compositions = allContentTypes.Where(x => compositionAliases.Any(y => x.Alias.Equals(y)));
|
||||
@@ -549,7 +687,7 @@ namespace Umbraco.Core.Services
|
||||
dependencies.Add(indirectReference);
|
||||
//Get all compositions for the current indirect reference
|
||||
var directReferences = indirectReference.ContentTypeComposition;
|
||||
|
||||
|
||||
foreach (var directReference in directReferences)
|
||||
{
|
||||
if (directReference.Id == compositionContentType.Id || directReference.Alias.Equals(compositionContentType.Alias)) continue;
|
||||
@@ -569,7 +707,7 @@ namespace Umbraco.Core.Services
|
||||
if (contentTypeDependency == null) continue;
|
||||
var intersect = contentTypeDependency.PropertyTypes.Select(x => x.Alias.ToLowerInvariant()).Intersect(propertyTypeAliases).ToArray();
|
||||
if (intersect.Length == 0) continue;
|
||||
|
||||
|
||||
throw new InvalidCompositionException(compositionContentType.Alias, intersect.ToArray());
|
||||
}
|
||||
}
|
||||
@@ -581,7 +719,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user saving the ContentType</param>
|
||||
public void Save(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -611,7 +749,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = contentTypes.ToArray();
|
||||
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
|
||||
if (SavingContentType.IsRaisedEventCancelled(new SaveEventArgs<IContentType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -647,12 +785,19 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user issueing the delete</param>
|
||||
/// <remarks>Deleting a <see cref="IContentType"/> will delete all the <see cref="IContent"/> objects based on this <see cref="IContentType"/></remarks>
|
||||
public void Delete(IContentType contentType, int userId = 0)
|
||||
{
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
|
||||
{
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(contentType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
|
||||
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
|
||||
// this method will recursively go lookup every content item, check if any of it's descendants are
|
||||
// of a different type, move them to the recycle bin, then permanently delete the content items.
|
||||
// The main problem with this is that for every content item being deleted, events are raised...
|
||||
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
|
||||
|
||||
_contentService.DeleteContentOfType(contentType.Id);
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -680,7 +825,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = contentTypes.ToArray();
|
||||
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
|
||||
if (DeletingContentType.IsRaisedEventCancelled(new DeleteEventArgs<IContentType>(asArray), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -706,7 +851,7 @@ namespace Umbraco.Core.Services
|
||||
Audit(AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets an <see cref="IMediaType"/> object by its Id
|
||||
/// </summary>
|
||||
@@ -729,10 +874,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateMediaTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IMediaType>.Builder.Where(x => x.Alias == alias);
|
||||
var contentTypes = repository.GetByQuery(query);
|
||||
|
||||
return contentTypes.FirstOrDefault();
|
||||
return repository.Get(alias);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -842,7 +984,7 @@ namespace Umbraco.Core.Services
|
||||
public Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
|
||||
if (MovingMediaType.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMediaType>(evtMsgs, new MoveEventInfo<IMediaType>(toMove, toMove.Path, containerId)),
|
||||
this))
|
||||
@@ -854,7 +996,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMediaType>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateMediaTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
@@ -863,7 +1005,7 @@ namespace Umbraco.Core.Services
|
||||
if (containerId > 0)
|
||||
{
|
||||
container = containerRepository.Get(containerId);
|
||||
if (container == null || container.ContainedObjectType != Constants.ObjectTypes.MediaTypeGuid)
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
moveInfo.AddRange(repository.Move(toMove, container));
|
||||
@@ -897,7 +1039,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IContentType>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
@@ -906,7 +1048,7 @@ namespace Umbraco.Core.Services
|
||||
if (containerId > 0)
|
||||
{
|
||||
container = containerRepository.Get(containerId);
|
||||
if (container == null || container.ContainedObjectType != Constants.ObjectTypes.DocumentTypeGuid)
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
moveInfo.AddRange(repository.Move(toMove, container));
|
||||
@@ -925,6 +1067,92 @@ namespace Umbraco.Core.Services
|
||||
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
IMediaType copy;
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateMediaTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (containerId > 0)
|
||||
{
|
||||
var container = containerRepository.Get(containerId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
var alias = repository.GetUniqueAlias(toCopy.Alias);
|
||||
copy = toCopy.DeepCloneWithResetIdentities(alias);
|
||||
copy.Name = copy.Name + " (copy)"; // might not be unique
|
||||
|
||||
// if it has a parent, and the parent is a content type, unplug composition
|
||||
// all other compositions remain in place in the copied content type
|
||||
if (copy.ParentId > 0)
|
||||
{
|
||||
var parent = repository.Get(copy.ParentId);
|
||||
if (parent != null)
|
||||
copy.RemoveContentType(parent.Alias);
|
||||
}
|
||||
|
||||
copy.ParentId = containerId;
|
||||
repository.AddOrUpdate(copy);
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<IMediaType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<IMediaType, MoveOperationStatusType>(copy, MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
IContentType copy;
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (containerId > 0)
|
||||
{
|
||||
var container = containerRepository.Get(containerId);
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
var alias = repository.GetUniqueAlias(toCopy.Alias);
|
||||
copy = toCopy.DeepCloneWithResetIdentities(alias);
|
||||
copy.Name = copy.Name + " (copy)"; // might not be unique
|
||||
|
||||
// if it has a parent, and the parent is a content type, unplug composition
|
||||
// all other compositions remain in place in the copied content type
|
||||
if (copy.ParentId > 0)
|
||||
{
|
||||
var parent = repository.Get(copy.ParentId);
|
||||
if (parent != null)
|
||||
copy.RemoveContentType(parent.Alias);
|
||||
}
|
||||
|
||||
copy.ParentId = containerId;
|
||||
repository.AddOrUpdate(copy);
|
||||
}
|
||||
catch (DataOperationException<MoveOperationStatusType> ex)
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<IContentType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
|
||||
}
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<IContentType, MoveOperationStatusType>(copy, MoveOperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single <see cref="IMediaType"/> object
|
||||
/// </summary>
|
||||
@@ -932,7 +1160,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional Id of the user saving the MediaType</param>
|
||||
public void Save(IMediaType mediaType, int userId = 0)
|
||||
{
|
||||
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
|
||||
if (SavingMediaType.IsRaisedEventCancelled(new SaveEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
|
||||
using (new WriteLock(Locker))
|
||||
@@ -944,7 +1172,7 @@ namespace Umbraco.Core.Services
|
||||
mediaType.CreatorId = userId;
|
||||
repository.AddOrUpdate(mediaType);
|
||||
uow.Commit();
|
||||
|
||||
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(mediaType);
|
||||
@@ -983,7 +1211,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
//save it all in one go
|
||||
uow.Commit();
|
||||
uow.Commit();
|
||||
}
|
||||
|
||||
UpdateContentXmlStructure(asArray.Cast<IContentTypeBase>().ToArray());
|
||||
@@ -1001,7 +1229,7 @@ namespace Umbraco.Core.Services
|
||||
/// <remarks>Deleting a <see cref="IMediaType"/> will delete all the <see cref="IMedia"/> objects based on this <see cref="IMediaType"/></remarks>
|
||||
public void Delete(IMediaType mediaType, int userId = 0)
|
||||
{
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(mediaType), this))
|
||||
return;
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
@@ -1031,7 +1259,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
var asArray = mediaTypes.ToArray();
|
||||
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
|
||||
if (DeletingMediaType.IsRaisedEventCancelled(new DeleteEventArgs<IMediaType>(asArray), this))
|
||||
return;
|
||||
using (new WriteLock(Locker))
|
||||
{
|
||||
@@ -1053,7 +1281,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Audit(AuditType.Delete, string.Format("Delete MediaTypes performed by user"), userId, -1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1120,19 +1348,29 @@ namespace Umbraco.Core.Services
|
||||
uow.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletingContentType;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavingContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavedContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletingContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletedContentTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavingMediaTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, SaveEventArgs<EntityContainer>> SavedMediaTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletingMediaTypeContainer;
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<EntityContainer>> DeletedMediaTypeContainer;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletingContentType;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IContentType>> DeletedContentType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
@@ -1142,7 +1380,7 @@ namespace Umbraco.Core.Services
|
||||
/// Occurs after Delete
|
||||
/// </summary>
|
||||
public static event TypedEventHandler<IContentTypeService, DeleteEventArgs<IMediaType>> DeletedMediaType;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Save
|
||||
/// </summary>
|
||||
|
||||
@@ -29,10 +29,11 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Containers
|
||||
|
||||
public Attempt<int> CreateContainer(int parentId, string name, int userId = 0)
|
||||
public Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContainer(int parentId, string name, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -42,77 +43,141 @@ namespace Umbraco.Core.Services
|
||||
ParentId = parentId,
|
||||
CreatorId = userId
|
||||
};
|
||||
|
||||
if (SavingContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
return Attempt.Succeed(container.Id);
|
||||
|
||||
SavedContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<EntityContainer, OperationStatusType>(container, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Attempt<int>.Fail(ex);
|
||||
return Attempt.Fail(new OperationStatus<EntityContainer, OperationStatusType>(null, OperationStatusType.FailedExceptionThrown, evtMsgs), ex);
|
||||
}
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
|
||||
public EntityContainer GetContainer(int containerId)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
return container != null && container.ContainedObjectType == Constants.ObjectTypes.DataTypeGuid
|
||||
? container
|
||||
: null;
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public EntityContainer GetContainer(Guid containerId)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
return container != null && container.ContainedObjectType == Constants.ObjectTypes.DataTypeGuid
|
||||
? container
|
||||
: null;
|
||||
return container;
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContainers(string name, int level)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
return repo.Get(name, level, Constants.ObjectTypes.DataTypeContainerGuid);
|
||||
return repo.Get(name, level);
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveContainer(EntityContainer container, int userId = 0)
|
||||
public IEnumerable<EntityContainer> GetContainers(IDataTypeDefinition dataTypeDefinition)
|
||||
{
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)
|
||||
throw new InvalidOperationException("Not a data type container.");
|
||||
var ancestorIds = dataTypeDefinition.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(x =>
|
||||
{
|
||||
var asInt = x.TryConvertTo<int>();
|
||||
if (asInt) return asInt.Result;
|
||||
return int.MinValue;
|
||||
})
|
||||
.Where(x => x != int.MinValue && x != dataTypeDefinition.Id)
|
||||
.ToArray();
|
||||
|
||||
return GetContainers(ancestorIds);
|
||||
}
|
||||
|
||||
public IEnumerable<EntityContainer> GetContainers(int[] containerIds)
|
||||
{
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
return repo.GetAll(containerIds);
|
||||
}
|
||||
}
|
||||
|
||||
public Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)
|
||||
{
|
||||
var ex = new InvalidOperationException("Not a " + Constants.ObjectTypes.DataTypeGuid + " container.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (container.HasIdentity && container.IsPropertyDirty("ParentId"))
|
||||
throw new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
{
|
||||
var ex = new InvalidOperationException("Cannot save a container with a modified parent, move the container instead.");
|
||||
return OperationStatus.Exception(evtMsgs, ex);
|
||||
}
|
||||
|
||||
if (SavingContainer.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
repo.AddOrUpdate(container);
|
||||
uow.Commit();
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
|
||||
SavedContainer.RaiseEvent(new SaveEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
//TODO: Audit trail ?
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
public void DeleteContainer(int containerId, int userId = 0)
|
||||
public Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0)
|
||||
{
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
{
|
||||
var container = repo.Get(containerId);
|
||||
if (container == null) return;
|
||||
if (container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid) return;
|
||||
if (container == null) return OperationStatus.NoOperation(evtMsgs);
|
||||
|
||||
if (DeletingContainer.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<EntityContainer>(container, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus(OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
repo.Delete(container);
|
||||
uow.Commit();
|
||||
|
||||
DeletedContainer.RaiseEvent(new DeleteEventArgs<EntityContainer>(container, evtMsgs), this);
|
||||
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
//TODO: Audit trail ?
|
||||
}
|
||||
}
|
||||
@@ -261,7 +326,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IDataTypeDefinition>>();
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow))
|
||||
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid))
|
||||
using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow))
|
||||
{
|
||||
try
|
||||
@@ -270,7 +335,7 @@ namespace Umbraco.Core.Services
|
||||
if (parentId > 0)
|
||||
{
|
||||
container = containerRepository.Get(parentId);
|
||||
if (container == null || container.ContainedObjectType != Constants.ObjectTypes.DataTypeGuid)
|
||||
if (container == null)
|
||||
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
|
||||
}
|
||||
moveInfo.AddRange(repository.Move(toMove, container));
|
||||
@@ -518,6 +583,12 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
public static event TypedEventHandler<IDataTypeService, SaveEventArgs<EntityContainer>> SavingContainer;
|
||||
public static event TypedEventHandler<IDataTypeService, SaveEventArgs<EntityContainer>> SavedContainer;
|
||||
public static event TypedEventHandler<IDataTypeService, DeleteEventArgs<EntityContainer>> DeletingContainer;
|
||||
public static event TypedEventHandler<IDataTypeService, DeleteEventArgs<EntityContainer>> DeletedContainer;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before Delete
|
||||
/// </summary>
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Umbraco.Core.Services
|
||||
new DeleteEventArgs<IDomain>(domain, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -45,7 +45,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
var args = new DeleteEventArgs<IDomain>(domain, false, evtMsgs);
|
||||
Deleted.RaiseEvent(args, this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
public IDomain GetByName(string name)
|
||||
@@ -91,7 +91,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IDomain>(domainEntity, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
@@ -102,7 +102,7 @@ namespace Umbraco.Core.Services
|
||||
}
|
||||
|
||||
Saved.RaiseEvent(new SaveEventArgs<IDomain>(domainEntity, false, evtMsgs), this);
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
@@ -2,7 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Web;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
@@ -140,18 +140,6 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="dataTypeDefinition">IDataTypeDefinition type to export</param>
|
||||
/// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition object</returns>
|
||||
public XElement Serialize(IDataTypeService dataTypeService, IDataTypeDefinition dataTypeDefinition)
|
||||
{
|
||||
return Serialize(dataTypeService, dataTypeDefinition, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports an <see cref="IDataTypeDefinition"/> item to xml as an <see cref="XElement"/>
|
||||
/// </summary>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="dataTypeDefinition">IDataTypeDefinition type to export</param>
|
||||
/// <param name="folders">The path of folders for this data type separated by a backslash, for example: `SEO/Meta`</param>
|
||||
/// <returns><see cref="XElement"/> containing the xml representation of the IDataTypeDefinition object</returns>
|
||||
public XElement Serialize(IDataTypeService dataTypeService, IDataTypeDefinition dataTypeDefinition, string folders)
|
||||
{
|
||||
var prevalues = new XElement("PreValues");
|
||||
var prevalueList = dataTypeService.GetPreValuesCollectionByDataTypeId(dataTypeDefinition.Id)
|
||||
@@ -175,8 +163,20 @@ namespace Umbraco.Core.Services
|
||||
xml.Add(new XAttribute("Id", dataTypeDefinition.PropertyEditorAlias));
|
||||
xml.Add(new XAttribute("Definition", dataTypeDefinition.Key));
|
||||
xml.Add(new XAttribute("DatabaseType", dataTypeDefinition.DatabaseType.ToString()));
|
||||
if(string.IsNullOrWhiteSpace(folders) == false)
|
||||
xml.Add(new XAttribute("Folders", folders));
|
||||
|
||||
var folderNames = string.Empty;
|
||||
if (dataTypeDefinition.Level != 1)
|
||||
{
|
||||
//get url encoded folder names
|
||||
var folders = dataTypeService.GetContainers(dataTypeDefinition)
|
||||
.OrderBy(x => x.Level)
|
||||
.Select(x => HttpUtility.UrlEncode(x.Name));
|
||||
|
||||
folderNames = string.Join("/", folders.ToArray());
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(folderNames) == false)
|
||||
xml.Add(new XAttribute("Folders", folderNames));
|
||||
|
||||
return xml;
|
||||
}
|
||||
@@ -267,11 +267,15 @@ namespace Umbraco.Core.Services
|
||||
structure.Add(new XElement("MediaType", allowedType.Alias));
|
||||
}
|
||||
|
||||
var genericProperties = new XElement("GenericProperties");
|
||||
var genericProperties = new XElement("GenericProperties"); // actually, all of them
|
||||
foreach (var propertyType in mediaType.PropertyTypes)
|
||||
{
|
||||
var definition = dataTypeService.GetDataTypeDefinitionById(propertyType.DataTypeDefinitionId);
|
||||
var propertyGroup = mediaType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
|
||||
var propertyGroup = propertyType.PropertyGroupId == null // true generic property
|
||||
? null
|
||||
: mediaType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
|
||||
var genericProperty = new XElement("GenericProperty",
|
||||
new XElement("Name", propertyType.Name),
|
||||
new XElement("Alias", propertyType.Alias),
|
||||
@@ -337,21 +341,10 @@ namespace Umbraco.Core.Services
|
||||
/// Exports an <see cref="IContentType"/> item to xml as an <see cref="XElement"/>
|
||||
/// </summary>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="contentTypeService"></param>
|
||||
/// <param name="contentType">Content type to export</param>
|
||||
/// <returns><see cref="XElement"/> containing the xml representation of the IContentType object</returns>
|
||||
public XElement Serialize(IDataTypeService dataTypeService, IContentType contentType)
|
||||
{
|
||||
return Serialize(dataTypeService, contentType, string.Empty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Exports an <see cref="IContentType"/> item to xml as an <see cref="XElement"/>
|
||||
/// </summary>
|
||||
/// <param name="dataTypeService"></param>
|
||||
/// <param name="contentType">Content type to export</param>
|
||||
/// <param name="folders">The path of folders for this content type separated by a backslash, for example: `SEO/Meta`</param>
|
||||
/// <returns><see cref="XElement"/> containing the xml representation of the IContentType object</returns>
|
||||
public XElement Serialize(IDataTypeService dataTypeService, IContentType contentType, string folders)
|
||||
public XElement Serialize(IDataTypeService dataTypeService, IContentTypeService contentTypeService, IContentType contentType)
|
||||
{
|
||||
var info = new XElement("Info",
|
||||
new XElement("Name", contentType.Name),
|
||||
@@ -392,14 +385,14 @@ namespace Umbraco.Core.Services
|
||||
structure.Add(new XElement("DocumentType", allowedType.Alias));
|
||||
}
|
||||
|
||||
var genericProperties = new XElement("GenericProperties");
|
||||
var genericProperties = new XElement("GenericProperties"); // actually, all of them
|
||||
foreach (var propertyType in contentType.PropertyTypes)
|
||||
{
|
||||
var definition = dataTypeService.GetDataTypeDefinitionById(propertyType.DataTypeDefinitionId);
|
||||
|
||||
var propertyGroup = propertyType.PropertyGroupId == null
|
||||
? null
|
||||
: contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
var propertyGroup = propertyType.PropertyGroupId == null // true generic property
|
||||
? null
|
||||
: contentType.PropertyGroups.FirstOrDefault(x => x.Id == propertyType.PropertyGroupId.Value);
|
||||
|
||||
var genericProperty = new XElement("GenericProperty",
|
||||
new XElement("Name", propertyType.Name),
|
||||
@@ -431,8 +424,20 @@ namespace Umbraco.Core.Services
|
||||
genericProperties,
|
||||
tabs);
|
||||
|
||||
if(string.IsNullOrWhiteSpace(folders) == false)
|
||||
xml.Add(new XAttribute("Folders", folders));
|
||||
var folderNames = string.Empty;
|
||||
//don't add folders if this is a child doc type
|
||||
if (contentType.Level != 1 && masterContentType == null)
|
||||
{
|
||||
//get url encoded folder names
|
||||
var folders = contentTypeService.GetContentTypeContainers(contentType)
|
||||
.OrderBy(x => x.Level)
|
||||
.Select(x => HttpUtility.UrlEncode(x.Name));
|
||||
|
||||
folderNames = string.Join("/", folders.ToArray());
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(folderNames) == false)
|
||||
xml.Add(new XAttribute("Folders", folderNames));
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
@@ -23,34 +23,22 @@ namespace Umbraco.Core.Services
|
||||
/// <summary>
|
||||
/// Represents the File Service, which is an easy access to operations involving <see cref="IFile"/> objects like Scripts, Stylesheets and Templates
|
||||
/// </summary>
|
||||
public class FileService : IFileService
|
||||
public class FileService : RepositoryService, IFileService
|
||||
{
|
||||
private readonly RepositoryFactory _repositoryFactory;
|
||||
private readonly IUnitOfWorkProvider _fileUowProvider;
|
||||
private readonly IDatabaseUnitOfWorkProvider _dataUowProvider;
|
||||
|
||||
private const string PartialViewHeader = "@inherits Umbraco.Web.Mvc.UmbracoTemplatePage";
|
||||
private const string PartialViewMacroHeader = "@inherits Umbraco.Web.Macros.PartialViewMacroPage";
|
||||
|
||||
[Obsolete("Use the constructors that specify all dependencies instead")]
|
||||
public FileService()
|
||||
: this(new RepositoryFactory())
|
||||
{ }
|
||||
|
||||
[Obsolete("Use the constructors that specify all dependencies instead")]
|
||||
public FileService(RepositoryFactory repositoryFactory)
|
||||
: this(new FileUnitOfWorkProvider(), new PetaPocoUnitOfWorkProvider(), repositoryFactory)
|
||||
public FileService(
|
||||
IUnitOfWorkProvider fileProvider,
|
||||
IDatabaseUnitOfWorkProvider dataProvider,
|
||||
RepositoryFactory repositoryFactory,
|
||||
ILogger logger,
|
||||
IEventMessagesFactory eventMessagesFactory)
|
||||
: base(dataProvider, repositoryFactory, logger, eventMessagesFactory)
|
||||
{
|
||||
}
|
||||
|
||||
public FileService(IUnitOfWorkProvider fileProvider, IDatabaseUnitOfWorkProvider dataProvider, RepositoryFactory repositoryFactory)
|
||||
{
|
||||
if (fileProvider == null) throw new ArgumentNullException("fileProvider");
|
||||
if (dataProvider == null) throw new ArgumentNullException("dataProvider");
|
||||
if (repositoryFactory == null) throw new ArgumentNullException("repositoryFactory");
|
||||
_repositoryFactory = repositoryFactory;
|
||||
_fileUowProvider = fileProvider;
|
||||
_dataUowProvider = dataProvider;
|
||||
_fileUowProvider = fileProvider;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +50,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="Stylesheet"/> objects</returns>
|
||||
public IEnumerable<Stylesheet> GetStylesheets(params string[] names)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateStylesheetRepository(_fileUowProvider.GetUnitOfWork(), _dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateStylesheetRepository(_fileUowProvider.GetUnitOfWork(), UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetAll(names);
|
||||
}
|
||||
@@ -75,7 +63,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>A <see cref="Stylesheet"/> object</returns>
|
||||
public Stylesheet GetStylesheetByName(string name)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateStylesheetRepository(_fileUowProvider.GetUnitOfWork(), _dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateStylesheetRepository(_fileUowProvider.GetUnitOfWork(), UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.Get(name);
|
||||
}
|
||||
@@ -92,7 +80,7 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateStylesheetRepository(uow, _dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateStylesheetRepository(uow, UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
repository.AddOrUpdate(stylesheet);
|
||||
uow.Commit();
|
||||
@@ -111,7 +99,7 @@ namespace Umbraco.Core.Services
|
||||
public void DeleteStylesheet(string path, int userId = 0)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateStylesheetRepository(uow, _dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateStylesheetRepository(uow, UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var stylesheet = repository.Get(path);
|
||||
if (stylesheet == null) return;
|
||||
@@ -137,7 +125,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateStylesheetRepository(uow, _dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateStylesheetRepository(uow, UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.ValidateStylesheet(stylesheet);
|
||||
}
|
||||
@@ -152,7 +140,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="Script"/> objects</returns>
|
||||
public IEnumerable<Script> GetScripts(params string[] names)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetAll(names);
|
||||
}
|
||||
@@ -165,7 +153,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>A <see cref="Script"/> object</returns>
|
||||
public Script GetScriptByName(string name)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.Get(name);
|
||||
}
|
||||
@@ -182,7 +170,7 @@ namespace Umbraco.Core.Services
|
||||
return;
|
||||
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(script);
|
||||
uow.Commit();
|
||||
@@ -201,7 +189,7 @@ namespace Umbraco.Core.Services
|
||||
public void DeleteScript(string path, int userId = 0)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(uow))
|
||||
{
|
||||
var script = repository.Get(path);
|
||||
if (script == null) return;
|
||||
@@ -226,7 +214,7 @@ namespace Umbraco.Core.Services
|
||||
public bool ValidateScript(Script script)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(uow))
|
||||
{
|
||||
return repository.ValidateScript(script);
|
||||
}
|
||||
@@ -235,7 +223,7 @@ namespace Umbraco.Core.Services
|
||||
public void CreateScriptFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(uow))
|
||||
{
|
||||
((ScriptRepository)repository).AddFolder(folderPath);
|
||||
uow.Commit();
|
||||
@@ -245,7 +233,7 @@ namespace Umbraco.Core.Services
|
||||
public void DeleteScriptFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateScriptRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreateScriptRepository(uow))
|
||||
{
|
||||
((ScriptRepository)repository).DeleteFolder(folderPath);
|
||||
uow.Commit();
|
||||
@@ -256,6 +244,56 @@ namespace Umbraco.Core.Services
|
||||
|
||||
#region Templates
|
||||
|
||||
/// <summary>
|
||||
/// Creates a template for a content type
|
||||
/// </summary>
|
||||
/// <param name="contentTypeAlias"></param>
|
||||
/// <param name="contentTypeName"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns>
|
||||
/// The template created
|
||||
/// </returns>
|
||||
public Attempt<OperationStatus<ITemplate, OperationStatusType>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0)
|
||||
{
|
||||
var template = new Template(contentTypeName,
|
||||
//NOTE: We are NOT passing in the content type alias here, we want to use it's name since we don't
|
||||
// want to save template file names as camelCase, the Template ctor will clean the alias as
|
||||
// `alias.ToCleanString(CleanStringType.UnderscoreAlias)` which has been the default.
|
||||
// This fixes: http://issues.umbraco.org/issue/U4-7953
|
||||
contentTypeName);
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
//NOTE: This isn't pretty but we need to maintain backwards compatibility so we cannot change
|
||||
// the event args here. The other option is to create a different event with different event
|
||||
// args specifically for this method... which also isn't pretty. So for now, we'll use this
|
||||
// dictionary approach to store 'additional data' in.
|
||||
var additionalData = new Dictionary<string, object>
|
||||
{
|
||||
{"CreateTemplateForContentType", true},
|
||||
{"ContentTypeAlias", contentTypeAlias},
|
||||
};
|
||||
if (SavingTemplate.IsRaisedEventCancelled(
|
||||
new SaveEventArgs<ITemplate>(template, true, evtMsgs, additionalData),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(new OperationStatus<ITemplate, OperationStatusType>(template, OperationStatusType.FailedCancelledByEvent, evtMsgs));
|
||||
}
|
||||
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(template);
|
||||
uow.Commit();
|
||||
|
||||
SavedTemplate.RaiseEvent(new SaveEventArgs<ITemplate>(template, false, evtMsgs), this);
|
||||
}
|
||||
|
||||
Audit(AuditType.Save, string.Format("Save Template performed by user"), userId, template.Id);
|
||||
|
||||
return Attempt.Succeed(new OperationStatus<ITemplate, OperationStatusType>(template, OperationStatusType.Success, evtMsgs));
|
||||
}
|
||||
|
||||
public ITemplate CreateTemplateWithIdentity(string name, string content, ITemplate masterTemplate = null, int userId = 0)
|
||||
{
|
||||
var template = new Template(name, name)
|
||||
@@ -276,7 +314,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="ITemplate"/> objects</returns>
|
||||
public IEnumerable<ITemplate> GetTemplates(params string[] aliases)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetAll(aliases).OrderBy(x => x.Name);
|
||||
}
|
||||
@@ -288,7 +326,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>An enumerable list of <see cref="ITemplate"/> objects</returns>
|
||||
public IEnumerable<ITemplate> GetTemplates(int masterTemplateId)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetChildren(masterTemplateId).OrderBy(x => x.Name);
|
||||
}
|
||||
@@ -301,7 +339,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>The <see cref="ITemplate"/> object matching the alias, or null.</returns>
|
||||
public ITemplate GetTemplate(string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.Get(alias);
|
||||
}
|
||||
@@ -314,7 +352,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>The <see cref="ITemplate"/> object matching the identifier, or null.</returns>
|
||||
public ITemplate GetTemplate(int id)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.Get(id);
|
||||
}
|
||||
@@ -327,7 +365,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>The <see cref="ITemplate"/> object matching the identifier, or null.</returns>
|
||||
public ITemplate GetTemplate(Guid id)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<ITemplate>.Builder.Where(x => x.Key == id);
|
||||
return repository.GetByQuery(query).SingleOrDefault();
|
||||
@@ -336,7 +374,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public IEnumerable<ITemplate> GetTemplateDescendants(string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetDescendants(alias);
|
||||
}
|
||||
@@ -349,7 +387,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IEnumerable<ITemplate> GetTemplateDescendants(int masterTemplateId)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetDescendants(masterTemplateId);
|
||||
}
|
||||
@@ -362,7 +400,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IEnumerable<ITemplate> GetTemplateChildren(string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetChildren(alias);
|
||||
}
|
||||
@@ -375,7 +413,7 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
public IEnumerable<ITemplate> GetTemplateChildren(int masterTemplateId)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetChildren(masterTemplateId);
|
||||
}
|
||||
@@ -390,7 +428,7 @@ namespace Umbraco.Core.Services
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TemplateNode GetTemplateNode(string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.GetTemplateNode(alias);
|
||||
}
|
||||
@@ -406,7 +444,7 @@ namespace Umbraco.Core.Services
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public TemplateNode FindTemplateInTree(TemplateNode anyNode, string alias)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(_dataUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.FindTemplateInTree(anyNode, alias);
|
||||
}
|
||||
@@ -422,8 +460,8 @@ namespace Umbraco.Core.Services
|
||||
if (SavingTemplate.IsRaisedEventCancelled(new SaveEventArgs<ITemplate>(template), this))
|
||||
return;
|
||||
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(uow))
|
||||
{
|
||||
repository.AddOrUpdate(template);
|
||||
uow.Commit();
|
||||
@@ -444,8 +482,8 @@ namespace Umbraco.Core.Services
|
||||
if (SavingTemplate.IsRaisedEventCancelled(new SaveEventArgs<ITemplate>(templates), this))
|
||||
return;
|
||||
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(uow))
|
||||
{
|
||||
foreach (var template in templates)
|
||||
{
|
||||
@@ -474,8 +512,8 @@ namespace Umbraco.Core.Services
|
||||
/// </remarks>
|
||||
public RenderingEngine DetermineTemplateRenderingEngine(ITemplate template)
|
||||
{
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(uow))
|
||||
{
|
||||
return repository.DetermineTemplateRenderingEngine(template);
|
||||
}
|
||||
@@ -488,8 +526,8 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId"></param>
|
||||
public void DeleteTemplate(string alias, int userId = 0)
|
||||
{
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(uow))
|
||||
{
|
||||
var template = repository.Get(alias);
|
||||
if (template == null) return;
|
||||
@@ -513,8 +551,8 @@ namespace Umbraco.Core.Services
|
||||
/// <returns>True if Script is valid, otherwise false</returns>
|
||||
public bool ValidateTemplate(ITemplate template)
|
||||
{
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreateTemplateRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreateTemplateRepository(uow))
|
||||
{
|
||||
return repository.ValidateTemplate(template);
|
||||
}
|
||||
@@ -543,7 +581,7 @@ namespace Umbraco.Core.Services
|
||||
public void DeletePartialViewFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreatePartialViewRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreatePartialViewRepository(uow))
|
||||
{
|
||||
((PartialViewRepository)repository).DeleteFolder(folderPath);
|
||||
uow.Commit();
|
||||
@@ -553,7 +591,7 @@ namespace Umbraco.Core.Services
|
||||
public void DeletePartialViewMacroFolder(string folderPath)
|
||||
{
|
||||
var uow = _fileUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreatePartialViewMacroRepository(uow))
|
||||
using (var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow))
|
||||
{
|
||||
((PartialViewMacroRepository)repository).DeleteFolder(folderPath);
|
||||
uow.Commit();
|
||||
@@ -562,7 +600,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public IPartialView GetPartialView(string path)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreatePartialViewRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreatePartialViewRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.Get(path);
|
||||
}
|
||||
@@ -570,7 +608,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public IPartialView GetPartialViewMacro(string path)
|
||||
{
|
||||
using (var repository = _repositoryFactory.CreatePartialViewMacroRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
using (var repository = RepositoryFactory.CreatePartialViewMacroRepository(_fileUowProvider.GetUnitOfWork()))
|
||||
{
|
||||
return repository.Get(path);
|
||||
}
|
||||
@@ -706,8 +744,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public bool ValidatePartialView(PartialView partialView)
|
||||
{
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreatePartialViewRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreatePartialViewRepository(uow))
|
||||
{
|
||||
return repository.ValidatePartialView(partialView);
|
||||
}
|
||||
@@ -715,8 +753,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
public bool ValidatePartialViewMacro(PartialView partialView)
|
||||
{
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var repository = _repositoryFactory.CreatePartialViewMacroRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var repository = RepositoryFactory.CreatePartialViewMacroRepository(uow))
|
||||
{
|
||||
return repository.ValidatePartialView(partialView);
|
||||
}
|
||||
@@ -746,9 +784,9 @@ namespace Umbraco.Core.Services
|
||||
switch (partialViewType)
|
||||
{
|
||||
case PartialViewType.PartialView:
|
||||
return _repositoryFactory.CreatePartialViewRepository(uow);
|
||||
return RepositoryFactory.CreatePartialViewRepository(uow);
|
||||
case PartialViewType.PartialViewMacro:
|
||||
return _repositoryFactory.CreatePartialViewMacroRepository(uow);
|
||||
return RepositoryFactory.CreatePartialViewMacroRepository(uow);
|
||||
}
|
||||
throw new ArgumentOutOfRangeException("partialViewType");
|
||||
}
|
||||
@@ -757,8 +795,8 @@ namespace Umbraco.Core.Services
|
||||
|
||||
private void Audit(AuditType type, string message, int userId, int objectId)
|
||||
{
|
||||
var uow = _dataUowProvider.GetUnitOfWork();
|
||||
using (var auditRepo = _repositoryFactory.CreateAuditRepository(uow))
|
||||
var uow = UowProvider.GetUnitOfWork();
|
||||
using (var auditRepo = RepositoryFactory.CreateAuditRepository(uow))
|
||||
{
|
||||
auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId));
|
||||
uow.Commit();
|
||||
|
||||
@@ -21,18 +21,23 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
Attempt<string[]> ValidateComposition(IContentTypeComposition compo);
|
||||
|
||||
Attempt<int> CreateContentTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<int> CreateMediaTypeContainer(int parentId, string name, int userId = 0);
|
||||
void SaveContentTypeContainer(EntityContainer container, int userId = 0);
|
||||
void SaveMediaTypeContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContentTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateMediaTypeContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContentTypeContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus> SaveMediaTypeContainer(EntityContainer container, int userId = 0);
|
||||
|
||||
EntityContainer GetContentTypeContainer(int containerId);
|
||||
EntityContainer GetContentTypeContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(int[] containerIds);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(IContentType contentType);
|
||||
IEnumerable<EntityContainer> GetContentTypeContainers(string folderName, int level);
|
||||
EntityContainer GetMediaTypeContainer(int containerId);
|
||||
EntityContainer GetMediaTypeContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(int[] containerIds);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(string folderName, int level);
|
||||
void DeleteMediaTypeContainer(int folderId, int userId = 0);
|
||||
void DeleteContentTypeContainer(int containerId, int userId = 0);
|
||||
IEnumerable<EntityContainer> GetMediaTypeContainers(IMediaType mediaType);
|
||||
Attempt<OperationStatus> DeleteMediaTypeContainer(int folderId, int userId = 0);
|
||||
Attempt<OperationStatus> DeleteContentTypeContainer(int containerId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all property type aliases.
|
||||
@@ -40,6 +45,16 @@ namespace Umbraco.Core.Services
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllPropertyTypeAliases();
|
||||
|
||||
/// <summary>
|
||||
/// Gets all content type aliases
|
||||
/// </summary>
|
||||
/// <param name="objectTypes">
|
||||
/// If this list is empty, it will return all content type aliases for media, members and content, otherwise
|
||||
/// it will only return content type aliases for the object types specified
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes);
|
||||
|
||||
/// <summary>
|
||||
/// Copies a content type as a child under the specified parent if specified (otherwise to the root)
|
||||
/// </summary>
|
||||
@@ -276,5 +291,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId);
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int containerId);
|
||||
Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId);
|
||||
Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId);
|
||||
}
|
||||
}
|
||||
@@ -10,12 +10,14 @@ namespace Umbraco.Core.Services
|
||||
/// </summary>
|
||||
public interface IDataTypeService : IService
|
||||
{
|
||||
Attempt<int> CreateContainer(int parentId, string name, int userId = 0);
|
||||
void SaveContainer(EntityContainer container, int userId = 0);
|
||||
Attempt<OperationStatus<EntityContainer, OperationStatusType>> CreateContainer(int parentId, string name, int userId = 0);
|
||||
Attempt<OperationStatus> SaveContainer(EntityContainer container, int userId = 0);
|
||||
EntityContainer GetContainer(int containerId);
|
||||
EntityContainer GetContainer(Guid containerId);
|
||||
IEnumerable<EntityContainer> GetContainers(string folderName, int level);
|
||||
void DeleteContainer(int containerId, int userId = 0);
|
||||
IEnumerable<EntityContainer> GetContainers(IDataTypeDefinition dataTypeDefinition);
|
||||
IEnumerable<EntityContainer> GetContainers(int[] containerIds);
|
||||
Attempt<OperationStatus> DeleteContainer(int containerId, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a <see cref="IDataTypeDefinition"/> by its Name
|
||||
@@ -160,5 +162,6 @@ namespace Umbraco.Core.Services
|
||||
string GetPreValueAsString(int id);
|
||||
|
||||
Attempt<OperationStatus<MoveOperationStatusType>> Move(IDataTypeDefinition toMove, int parentId);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -187,6 +187,17 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="userId">Optional id of the user saving the template</param>
|
||||
void SaveTemplate(ITemplate template, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a template for a content type
|
||||
/// </summary>
|
||||
/// <param name="contentTypeAlias"></param>
|
||||
/// <param name="contentTypeName"></param>
|
||||
/// <param name="userId"></param>
|
||||
/// <returns>
|
||||
/// The template created
|
||||
/// </returns>
|
||||
Attempt<OperationStatus<ITemplate, OperationStatusType>> CreateTemplateForContentType(string contentTypeAlias, string contentTypeName, int userId = 0);
|
||||
|
||||
ITemplate CreateTemplateWithIdentity(string name, string content, ITemplate masterTemplate = null, int userId = 0);
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
|
||||
|
||||
@@ -747,7 +747,7 @@ namespace Umbraco.Core.Services
|
||||
if (Deleting.IsRaisedEventCancelled(
|
||||
new DeleteEventArgs<IMedia>(media, evtMsgs), this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
//Delete children before deleting the 'possible parent'
|
||||
@@ -772,7 +772,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Delete, "Delete Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -791,7 +791,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IMedia>(media, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -816,7 +816,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Save Media performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -836,7 +836,7 @@ namespace Umbraco.Core.Services
|
||||
new SaveEventArgs<IMedia>(asArray, evtMsgs),
|
||||
this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -864,7 +864,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Save, "Save Media items performed by user", userId, -1);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -966,7 +966,7 @@ namespace Umbraco.Core.Services
|
||||
if (Trashing.IsRaisedEventCancelled(
|
||||
new MoveEventArgs<IMedia>(new MoveEventInfo<IMedia>(media, originalPath, Constants.System.RecycleBinMedia)), this))
|
||||
{
|
||||
return Attempt.Fail(OperationStatus.Cancelled(evtMsgs));
|
||||
return OperationStatus.Cancelled(evtMsgs);
|
||||
}
|
||||
|
||||
var moveInfo = new List<MoveEventInfo<IMedia>>
|
||||
@@ -1008,7 +1008,7 @@ namespace Umbraco.Core.Services
|
||||
|
||||
Audit(AuditType.Move, "Move Media to Recycle Bin performed by user", userId, media.Id);
|
||||
|
||||
return Attempt.Succeed(OperationStatus.Success(evtMsgs));
|
||||
return OperationStatus.Success(evtMsgs);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -69,10 +69,7 @@ namespace Umbraco.Core.Services
|
||||
{
|
||||
using (var repository = RepositoryFactory.CreateMemberTypeRepository(UowProvider.GetUnitOfWork()))
|
||||
{
|
||||
var query = Query<IMemberType>.Builder.Where(x => x.Alias == alias);
|
||||
var contentTypes = repository.GetByQuery(query);
|
||||
|
||||
return contentTypes.FirstOrDefault();
|
||||
return repository.Get(alias);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user